summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid10
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo53
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-kone8
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus11
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus100
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra9
-rw-r--r--Documentation/cgroups/cpusets.txt17
-rw-r--r--Documentation/cgroups/memory.txt5
-rw-r--r--Documentation/cpu-freq/governors.txt11
-rw-r--r--Documentation/device-mapper/dm-crypt.txt2
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/cache_sram.txt20
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/mpic.txt253
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt9
-rw-r--r--Documentation/filesystems/nfs/pnfs.txt7
-rw-r--r--Documentation/filesystems/romfs.txt3
-rw-r--r--Documentation/filesystems/ubifs.txt4
-rw-r--r--Documentation/filesystems/vfs.txt6
-rw-r--r--Documentation/hwmon/f71882fg16
-rw-r--r--Documentation/hwmon/lineage-pem77
-rw-r--r--Documentation/hwmon/lm8512
-rw-r--r--Documentation/hwmon/ltc415147
-rw-r--r--Documentation/hwmon/max663949
-rw-r--r--Documentation/hwmon/pmbus215
-rw-r--r--Documentation/hwmon/sysfs-interface11
-rw-r--r--Documentation/hwmon/w83627ehf60
-rw-r--r--Documentation/hwspinlock.txt293
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/kbuild/kbuild.txt2
-rw-r--r--Documentation/kbuild/makefiles.txt3
-rw-r--r--Documentation/kernel-parameters.txt12
-rw-r--r--Documentation/kvm/api.txt96
-rw-r--r--Documentation/kvm/locking.txt25
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas23
-rw-r--r--Documentation/scsi/hpsa.txt23
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt14
-rw-r--r--Documentation/sysctl/kernel.txt2
-rw-r--r--Documentation/vm/unevictable-lru.txt3
-rw-r--r--Documentation/x86/x86_64/boot-options.txt14
-rw-r--r--MAINTAINERS40
-rw-r--r--Makefile2
-rw-r--r--README2
-rw-r--r--arch/alpha/include/asm/cacheflush.h2
-rw-r--r--arch/alpha/include/asm/errno.h2
-rw-r--r--arch/arm/Kconfig21
-rw-r--r--arch/arm/Makefile2
-rw-r--r--arch/arm/configs/exynos4_defconfig70
-rw-r--r--arch/arm/configs/kirkwood_defconfig1
-rw-r--r--arch/arm/configs/mx51_defconfig2
-rw-r--r--arch/arm/configs/omap2plus_defconfig1
-rw-r--r--arch/arm/configs/s5p64x0_defconfig2
-rw-r--r--arch/arm/configs/s5pv210_defconfig2
-rw-r--r--arch/arm/configs/u8500_defconfig59
-rw-r--r--arch/arm/configs/vexpress_defconfig140
-rw-r--r--arch/arm/include/asm/kexec.h3
-rw-r--r--arch/arm/include/asm/pmu.h14
-rw-r--r--arch/arm/kernel/etm.c4
-rw-r--r--arch/arm/kernel/machine_kexec.c7
-rw-r--r--arch/arm/kernel/perf_event.c17
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c67
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c96
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c8
-rw-r--r--arch/arm/mach-davinci/board-mityomapl138.c167
-rw-r--r--arch/arm/mach-davinci/board-omapl138-hawk.c284
-rw-r--r--arch/arm/mach-davinci/board-tnetv107x-evm.c57
-rw-r--r--arch/arm/mach-davinci/da830.c6
-rw-r--r--arch/arm/mach-davinci/da850.c99
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c125
-rw-r--r--arch/arm/mach-davinci/devices-tnetv107x.c25
-rw-r--r--arch/arm/mach-davinci/dm355.c5
-rw-r--r--arch/arm/mach-davinci/dm365.c5
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h11
-rw-r--r--arch/arm/mach-davinci/include/mach/edma.h36
-rw-r--r--arch/arm/mach-davinci/include/mach/mux.h4
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/spi.h15
-rw-r--r--arch/arm/mach-davinci/include/mach/tnetv107x.h2
-rw-r--r--arch/arm/mach-davinci/tnetv107x.c2
-rw-r--r--arch/arm/mach-dove/cm-a510.c1
-rw-r--r--arch/arm/mach-dove/common.c8
-rw-r--r--arch/arm/mach-dove/common.h1
-rw-r--r--arch/arm/mach-dove/dove-db-setup.c1
-rw-r--r--arch/arm/mach-dove/include/mach/bridge-regs.h4
-rw-r--r--arch/arm/mach-dove/include/mach/dove.h3
-rw-r--r--arch/arm/mach-dove/include/mach/gpio.h42
-rw-r--r--arch/arm/mach-dove/include/mach/irqs.h7
-rw-r--r--arch/arm/mach-dove/irq.c30
-rw-r--r--arch/arm/mach-exynos4/Kconfig195
-rw-r--r--arch/arm/mach-exynos4/Makefile56
-rw-r--r--arch/arm/mach-exynos4/Makefile.boot (renamed from arch/arm/mach-s5pv310/Makefile.boot)0
-rw-r--r--arch/arm/mach-exynos4/clock.c (renamed from arch/arm/mach-s5pv310/clock.c)286
-rw-r--r--arch/arm/mach-exynos4/cpu.c (renamed from arch/arm/mach-s5pv310/cpu.c)99
-rw-r--r--arch/arm/mach-exynos4/cpufreq.c (renamed from arch/arm/mach-s5pv310/cpufreq.c)111
-rw-r--r--arch/arm/mach-exynos4/dev-ahci.c263
-rw-r--r--arch/arm/mach-exynos4/dev-audio.c (renamed from arch/arm/mach-s5pv310/dev-audio.c)143
-rw-r--r--arch/arm/mach-exynos4/dev-pd.c (renamed from arch/arm/mach-s5pv310/dev-pd.c)40
-rw-r--r--arch/arm/mach-exynos4/dev-sysmmu.c (renamed from arch/arm/mach-s5pv310/dev-sysmmu.c)121
-rw-r--r--arch/arm/mach-exynos4/dma.c (renamed from arch/arm/mach-s5pv310/dma.c)50
-rw-r--r--arch/arm/mach-exynos4/gpiolib.c365
-rw-r--r--arch/arm/mach-exynos4/headsmp.S (renamed from arch/arm/mach-s5pv310/headsmp.S)6
-rw-r--r--arch/arm/mach-exynos4/hotplug.c (renamed from arch/arm/mach-s5pv310/hotplug.c)10
-rw-r--r--arch/arm/mach-exynos4/include/mach/debug-macro.S (renamed from arch/arm/mach-s5pv310/include/mach/debug-macro.S)6
-rw-r--r--arch/arm/mach-exynos4/include/mach/dma.h (renamed from arch/arm/mach-s5pv310/include/mach/dma.h)0
-rw-r--r--arch/arm/mach-exynos4/include/mach/entry-macro.S (renamed from arch/arm/mach-s5pv310/include/mach/entry-macro.S)4
-rw-r--r--arch/arm/mach-exynos4/include/mach/gpio.h156
-rw-r--r--arch/arm/mach-exynos4/include/mach/hardware.h (renamed from arch/arm/mach-s5pv310/include/mach/hardware.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/io.h (renamed from arch/arm/mach-s5pv310/include/mach/io.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/irqs.h (renamed from arch/arm/mach-s5pv310/include/mach/irqs.h)26
-rw-r--r--arch/arm/mach-exynos4/include/mach/map.h162
-rw-r--r--arch/arm/mach-exynos4/include/mach/memory.h (renamed from arch/arm/mach-s5pv310/include/mach/memory.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/pm-core.h49
-rw-r--r--arch/arm/mach-exynos4/include/mach/pwm-clock.h (renamed from arch/arm/mach-s5pv310/include/mach/pwm-clock.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-clock.h (renamed from arch/arm/mach-s5pv310/include/mach/regs-clock.h)41
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-gpio.h42
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-irq.h (renamed from arch/arm/mach-s5pv310/include/mach/regs-irq.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-mct.h52
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-mem.h (renamed from arch/arm/mach-s5pv310/include/mach/regs-mem.h)6
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-pmu.h162
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-sysmmu.h (renamed from arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h)10
-rw-r--r--arch/arm/mach-exynos4/include/mach/smp.h (renamed from arch/arm/mach-s5pv310/include/mach/smp.h)2
-rw-r--r--arch/arm/mach-exynos4/include/mach/sysmmu.h46
-rw-r--r--arch/arm/mach-exynos4/include/mach/system.h (renamed from arch/arm/mach-s5pv310/include/mach/system.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/timex.h (renamed from arch/arm/mach-s5pv310/include/mach/timex.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/uncompress.h (renamed from arch/arm/mach-s5pv310/include/mach/uncompress.h)8
-rw-r--r--arch/arm/mach-exynos4/include/mach/vmalloc.h (renamed from arch/arm/mach-s5pv310/include/mach/vmalloc.h)8
-rw-r--r--arch/arm/mach-exynos4/init.c (renamed from arch/arm/mach-s5pv310/init.c)10
-rw-r--r--arch/arm/mach-exynos4/irq-combiner.c (renamed from arch/arm/mach-s5pv310/irq-combiner.c)4
-rw-r--r--arch/arm/mach-exynos4/irq-eint.c (renamed from arch/arm/mach-s5pv310/irq-eint.c)62
-rw-r--r--arch/arm/mach-exynos4/localtimer.c (renamed from arch/arm/mach-s5pv310/localtimer.c)2
-rw-r--r--arch/arm/mach-exynos4/mach-armlex4210.c215
-rw-r--r--arch/arm/mach-exynos4/mach-nuri.c305
-rw-r--r--arch/arm/mach-exynos4/mach-smdkc210.c (renamed from arch/arm/mach-s5pv310/mach-smdkc210.c)48
-rw-r--r--arch/arm/mach-exynos4/mach-smdkv310.c (renamed from arch/arm/mach-s5pv310/mach-smdkv310.c)72
-rw-r--r--arch/arm/mach-exynos4/mach-universal_c210.c650
-rw-r--r--arch/arm/mach-exynos4/mct.c421
-rw-r--r--arch/arm/mach-exynos4/platsmp.c (renamed from arch/arm/mach-s5pv310/platsmp.c)12
-rw-r--r--arch/arm/mach-exynos4/pm.c420
-rw-r--r--arch/arm/mach-exynos4/setup-fimc.c44
-rw-r--r--arch/arm/mach-exynos4/setup-i2c0.c (renamed from arch/arm/mach-s5pv310/setup-i2c0.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c1.c (renamed from arch/arm/mach-s5pv310/setup-i2c1.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c2.c (renamed from arch/arm/mach-s5pv310/setup-i2c2.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c3.c (renamed from arch/arm/mach-s5pv310/setup-i2c3.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c4.c (renamed from arch/arm/mach-s5pv310/setup-i2c4.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c5.c (renamed from arch/arm/mach-s5pv310/setup-i2c5.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c6.c (renamed from arch/arm/mach-s5pv310/setup-i2c6.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-i2c7.c (renamed from arch/arm/mach-s5pv310/setup-i2c7.c)4
-rw-r--r--arch/arm/mach-exynos4/setup-keypad.c35
-rw-r--r--arch/arm/mach-exynos4/setup-sdhci-gpio.c (renamed from arch/arm/mach-s5pv310/setup-sdhci-gpio.c)52
-rw-r--r--arch/arm/mach-exynos4/setup-sdhci.c (renamed from arch/arm/mach-s5pv310/setup-sdhci.c)12
-rw-r--r--arch/arm/mach-exynos4/sleep.S76
-rw-r--r--arch/arm/mach-exynos4/time.c (renamed from arch/arm/mach-s5pv310/time.c)80
-rw-r--r--arch/arm/mach-imx/Kconfig12
-rw-r--r--arch/arm/mach-imx/Makefile5
-rw-r--r--arch/arm/mach-imx/clock-imx1.c1
-rw-r--r--arch/arm/mach-imx/clock-imx25.c3
-rw-r--r--arch/arm/mach-imx/devices-imx1.h11
-rw-r--r--arch/arm/mach-imx/devices-imx25.h6
-rw-r--r--arch/arm/mach-imx/dma-v1.c2
-rw-r--r--arch/arm/mach-imx/ehci-imx25.c80
-rw-r--r--arch/arm/mach-imx/ehci-imx27.c82
-rw-r--r--arch/arm/mach-imx/eukrea_mbimx27-baseboard.c7
-rw-r--r--arch/arm/mach-imx/mach-cpuimx27.c49
-rw-r--r--arch/arm/mach-imx/mach-eukrea_cpuimx25.c27
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c32
-rw-r--r--arch/arm/mach-imx/mach-imx27ipcam.c78
-rw-r--r--arch/arm/mach-imx/mach-imx27lite.c11
-rw-r--r--arch/arm/mach-imx/mach-mx1ads.c22
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c11
-rw-r--r--arch/arm/mach-imx/mach-mx25_3ds.c32
-rw-r--r--arch/arm/mach-imx/mach-mx27_3ds.c43
-rw-r--r--arch/arm/mach-imx/mach-mx27ads.c11
-rw-r--r--arch/arm/mach-imx/mach-mxt_td60.c12
-rw-r--r--arch/arm/mach-imx/mach-pca100.c49
-rw-r--r--arch/arm/mach-imx/mach-pcm038.c27
-rw-r--r--arch/arm/mach-imx/mach-scb9328.c13
-rw-r--r--arch/arm/mach-imx/mm-imx1.c21
-rw-r--r--arch/arm/mach-imx/mm-imx21.c23
-rw-r--r--arch/arm/mach-imx/mm-imx25.c18
-rw-r--r--arch/arm/mach-imx/mm-imx27.c23
-rw-r--r--arch/arm/mach-kirkwood/common.c16
-rw-r--r--arch/arm/mach-kirkwood/common.h2
-rw-r--r--arch/arm/mach-kirkwood/d2net_v2-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/db88f6281-bp-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/dockstar-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/guruplug-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/include/mach/bridge-regs.h3
-rw-r--r--arch/arm/mach-kirkwood/include/mach/gpio.h29
-rw-r--r--arch/arm/mach-kirkwood/include/mach/kirkwood.h2
-rw-r--r--arch/arm/mach-kirkwood/irq.c22
-rw-r--r--arch/arm/mach-kirkwood/mpp.c3
-rw-r--r--arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/netspace_v2-setup.c3
-rw-r--r--arch/arm/mach-kirkwood/netxbig_v2-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/openrd-setup.c3
-rw-r--r--arch/arm/mach-kirkwood/pcie.c8
-rw-r--r--arch/arm/mach-kirkwood/rd88f6192-nas-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/rd88f6281-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/sheevaplug-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/t5325-setup.c18
-rw-r--r--arch/arm/mach-kirkwood/ts219-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/ts41x-setup.c9
-rw-r--r--arch/arm/mach-loki/common.c9
-rw-r--r--arch/arm/mach-loki/common.h1
-rw-r--r--arch/arm/mach-loki/include/mach/bridge-regs.h5
-rw-r--r--arch/arm/mach-loki/lb88rc8480-setup.c1
-rw-r--r--arch/arm/mach-msm/Kconfig37
-rw-r--r--arch/arm/mach-msm/Makefile29
-rw-r--r--arch/arm/mach-msm/board-halibut.c2
-rw-r--r--arch/arm/mach-msm/board-mahimahi.c2
-rw-r--r--arch/arm/mach-msm/board-msm7x27.c8
-rw-r--r--arch/arm/mach-msm/board-msm7x30.c29
-rw-r--r--arch/arm/mach-msm/board-msm8960.c91
-rw-r--r--arch/arm/mach-msm/board-msm8x60.c4
-rw-r--r--arch/arm/mach-msm/board-qsd8x50.c86
-rw-r--r--arch/arm/mach-msm/board-sapphire.c2
-rw-r--r--arch/arm/mach-msm/board-trout-gpio.c2
-rw-r--r--arch/arm/mach-msm/board-trout.c3
-rw-r--r--arch/arm/mach-msm/clock-7x30.h61
-rw-r--r--arch/arm/mach-msm/clock-debug.c130
-rw-r--r--arch/arm/mach-msm/clock-dummy.c54
-rw-r--r--arch/arm/mach-msm/clock-pcom.c7
-rw-r--r--arch/arm/mach-msm/clock-pcom.h51
-rw-r--r--arch/arm/mach-msm/clock.c192
-rw-r--r--arch/arm/mach-msm/clock.h55
-rw-r--r--arch/arm/mach-msm/devices-iommu.c (renamed from arch/arm/mach-msm/devices-msm8x60-iommu.c)85
-rw-r--r--arch/arm/mach-msm/devices-msm7x00.c36
-rw-r--r--arch/arm/mach-msm/devices-msm7x30.c11
-rw-r--r--arch/arm/mach-msm/devices-msm8960.c85
-rw-r--r--arch/arm/mach-msm/devices-qsd8x50.c213
-rw-r--r--arch/arm/mach-msm/devices.h11
-rw-r--r--arch/arm/mach-msm/gpiomux-7x30.c38
-rw-r--r--arch/arm/mach-msm/gpiomux-8x50.c23
-rw-r--r--arch/arm/mach-msm/headsmp.S2
-rw-r--r--arch/arm/mach-msm/include/mach/board.h4
-rw-r--r--arch/arm/mach-msm/include/mach/clk.h31
-rw-r--r--arch/arm/mach-msm/include/mach/clkdev.h19
-rw-r--r--arch/arm/mach-msm/include/mach/cpu.h54
-rw-r--r--arch/arm/mach-msm/include/mach/io.h1
-rw-r--r--arch/arm/mach-msm/include/mach/iommu.h18
-rw-r--r--arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h32
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-7x30.h31
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-8960.h277
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-8x50.h31
-rw-r--r--arch/arm/mach-msm/include/mach/irqs.h3
-rw-r--r--arch/arm/mach-msm/include/mach/memory.h2
-rw-r--r--arch/arm/mach-msm/include/mach/mmc.h11
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap-7x00.h16
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap-7x30.h14
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap-8960.h48
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap-8x50.h22
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap-8x60.h61
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap.h9
-rw-r--r--arch/arm/mach-msm/include/mach/sirc.h31
-rw-r--r--arch/arm/mach-msm/include/mach/smp.h30
-rw-r--r--arch/arm/mach-msm/io.c41
-rw-r--r--arch/arm/mach-msm/iommu.c72
-rw-r--r--arch/arm/mach-msm/iommu_dev.c230
-rw-r--r--arch/arm/mach-msm/scm-boot.h30
-rw-r--r--arch/arm/mach-msm/scm.c58
-rw-r--r--arch/arm/mach-msm/scm.h30
-rw-r--r--arch/arm/mach-msm/timer.c46
-rw-r--r--arch/arm/mach-mv78xx0/buffalo-wxl-setup.c1
-rw-r--r--arch/arm/mach-mv78xx0/common.c8
-rw-r--r--arch/arm/mach-mv78xx0/common.h1
-rw-r--r--arch/arm/mach-mv78xx0/db78x00-bp-setup.c1
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/bridge-regs.h4
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/gpio.h31
-rw-r--r--arch/arm/mach-mv78xx0/include/mach/mv78xx0.h1
-rw-r--r--arch/arm/mach-mv78xx0/irq.c22
-rw-r--r--arch/arm/mach-mv78xx0/mpp.c3
-rw-r--r--arch/arm/mach-mv78xx0/rd78x00-masa-setup.c1
-rw-r--r--arch/arm/mach-mx3/Kconfig25
-rw-r--r--arch/arm/mach-mx3/Makefile6
-rw-r--r--arch/arm/mach-mx3/devices-imx35.h2
-rw-r--r--arch/arm/mach-mx3/ehci-imx31.c83
-rw-r--r--arch/arm/mach-mx3/ehci-imx35.c80
-rw-r--r--arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c4
-rw-r--r--arch/arm/mach-mx3/iomux-imx31.c12
-rw-r--r--arch/arm/mach-mx3/mach-armadillo5x0.c41
-rw-r--r--arch/arm/mach-mx3/mach-bug.c66
-rw-r--r--arch/arm/mach-mx3/mach-cpuimx35.c31
-rw-r--r--arch/arm/mach-mx3/mach-kzm_arm11_01.c17
-rw-r--r--arch/arm/mach-mx3/mach-mx31_3ds.c462
-rw-r--r--arch/arm/mach-mx3/mach-mx31ads.c57
-rw-r--r--arch/arm/mach-mx3/mach-mx31lilly.c95
-rw-r--r--arch/arm/mach-mx3/mach-mx31lite.c37
-rw-r--r--arch/arm/mach-mx3/mach-mx31moboard.c39
-rw-r--r--arch/arm/mach-mx3/mach-mx35_3ds.c42
-rw-r--r--arch/arm/mach-mx3/mach-pcm037.c46
-rw-r--r--arch/arm/mach-mx3/mach-pcm037_eet.c2
-rw-r--r--arch/arm/mach-mx3/mach-pcm043.c54
-rw-r--r--arch/arm/mach-mx3/mach-qong.c22
-rw-r--r--arch/arm/mach-mx3/mach-vpr200.c328
-rw-r--r--arch/arm/mach-mx3/mm.c43
-rw-r--r--arch/arm/mach-mx3/mx31moboard-devboard.c7
-rw-r--r--arch/arm/mach-mx3/mx31moboard-marxbot.c6
-rw-r--r--arch/arm/mach-mx3/mx31moboard-smartbot.c13
-rw-r--r--arch/arm/mach-mx5/Kconfig27
-rw-r--r--arch/arm/mach-mx5/Makefile4
-rw-r--r--arch/arm/mach-mx5/board-cpuimx51.c20
-rw-r--r--arch/arm/mach-mx5/board-cpuimx51sd.c31
-rw-r--r--arch/arm/mach-mx5/board-mx50_rdp.c34
-rw-r--r--arch/arm/mach-mx5/board-mx51_3ds.c43
-rw-r--r--arch/arm/mach-mx5/board-mx51_babbage.c43
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikamx.c211
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikasb.c283
-rw-r--r--arch/arm/mach-mx5/board-mx53_evk.c40
-rw-r--r--arch/arm/mach-mx5/board-mx53_loco.c178
-rw-r--r--arch/arm/mach-mx5/board-mx53_smd.c40
-rw-r--r--arch/arm/mach-mx5/clock-mx51-mx53.c148
-rw-r--r--arch/arm/mach-mx5/cpu.c11
-rw-r--r--arch/arm/mach-mx5/crm_regs.h7
-rw-r--r--arch/arm/mach-mx5/devices-imx50.h (renamed from arch/arm/mach-mx5/devices-mx50.h)8
-rw-r--r--arch/arm/mach-mx5/devices-imx53.h4
-rw-r--r--arch/arm/mach-mx5/efika.h10
-rw-r--r--arch/arm/mach-mx5/ehci.c156
-rw-r--r--arch/arm/mach-mx5/mm-mx50.c19
-rw-r--r--arch/arm/mach-mx5/mm.c14
-rw-r--r--arch/arm/mach-mx5/mx51_efika.c636
-rw-r--r--arch/arm/mach-mxc91231/iomux.c14
-rw-r--r--arch/arm/mach-mxc91231/magx-zn5.c11
-rw-r--r--arch/arm/mach-mxc91231/mm.c7
-rw-r--r--arch/arm/mach-mxs/Kconfig24
-rw-r--r--arch/arm/mach-mxs/Makefile5
-rw-r--r--arch/arm/mach-mxs/clock-mx23.c11
-rw-r--r--arch/arm/mach-mxs/clock-mx28.c25
-rw-r--r--arch/arm/mach-mxs/devices-mx23.h11
-rw-r--r--arch/arm/mach-mxs/devices-mx28.h23
-rw-r--r--arch/arm/mach-mxs/devices.c2
-rw-r--r--arch/arm/mach-mxs/devices/Kconfig16
-rw-r--r--arch/arm/mach-mxs/devices/Makefile6
-rw-r--r--arch/arm/mach-mxs/devices/platform-auart.c64
-rw-r--r--arch/arm/mach-mxs/devices/platform-dma.c49
-rw-r--r--arch/arm/mach-mxs/devices/platform-fec.c5
-rw-r--r--arch/arm/mach-mxs/devices/platform-flexcan.c51
-rw-r--r--arch/arm/mach-mxs/devices/platform-mxs-i2c.c51
-rw-r--r--arch/arm/mach-mxs/devices/platform-mxs-pwm.c22
-rw-r--r--arch/arm/mach-mxs/devices/platform-mxsfb.c46
-rw-r--r--arch/arm/mach-mxs/gpio.c46
-rw-r--r--arch/arm/mach-mxs/include/mach/common.h1
-rw-r--r--arch/arm/mach-mxs/include/mach/devices-common.h35
-rw-r--r--arch/arm/mach-mxs/include/mach/iomux-mx23.h190
-rw-r--r--arch/arm/mach-mxs/include/mach/iomux.h3
-rw-r--r--arch/arm/mach-mxs/include/mach/mx23.h38
-rw-r--r--arch/arm/mach-mxs/include/mach/mx28.h45
-rw-r--r--arch/arm/mach-mxs/include/mach/mxs.h9
-rw-r--r--arch/arm/mach-mxs/include/mach/mxsfb.h49
-rw-r--r--arch/arm/mach-mxs/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-mxs/mach-mx23evk.c90
-rw-r--r--arch/arm/mach-mxs/mach-mx28evk.c237
-rw-r--r--arch/arm/mach-mxs/mach-tx28.c183
-rw-r--r--arch/arm/mach-mxs/module-tx28.c131
-rw-r--r--arch/arm/mach-mxs/module-tx28.h9
-rw-r--r--arch/arm/mach-mxs/ocotp.c90
-rw-r--r--arch/arm/mach-mxs/pm.c43
-rw-r--r--arch/arm/mach-mxs/regs-clkctrl-mx23.h124
-rw-r--r--arch/arm/mach-mxs/regs-clkctrl-mx28.h177
-rw-r--r--arch/arm/mach-mxs/system.c2
-rw-r--r--arch/arm/mach-omap1/Makefile2
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c16
-rw-r--r--arch/arm/mach-omap1/board-fsample.c4
-rw-r--r--arch/arm/mach-omap1/board-h2.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c2
-rw-r--r--arch/arm/mach-omap1/board-htcherald.c4
-rw-r--r--arch/arm/mach-omap1/board-innovator.c2
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c6
-rw-r--r--arch/arm/mach-omap1/board-palmte.c13
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c107
-rw-r--r--arch/arm/mach-omap1/mcbsp.c333
-rw-r--r--arch/arm/mach-omap1/reset.c25
-rw-r--r--arch/arm/mach-omap2/Kconfig28
-rw-r--r--arch/arm/mach-omap2/Makefile66
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c34
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c215
-rw-r--r--arch/arm/mach-omap2/board-3630sdp.c15
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c190
-rw-r--r--arch/arm/mach-omap2/board-am3517crane.c14
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c41
-rw-r--r--arch/arm/mach-omap2/board-apollon.c12
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c43
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c15
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c27
-rw-r--r--arch/arm/mach-omap2/board-flash.c34
-rw-r--r--arch/arm/mach-omap2/board-flash.h4
-rw-r--r--arch/arm/mach-omap2/board-generic.c12
-rw-r--r--arch/arm/mach-omap2/board-h4.c16
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c34
-rw-r--r--arch/arm/mach-omap2/board-igep0030.c12
-rw-r--r--arch/arm/mach-omap2/board-ldp.c35
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c20
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c73
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c246
-rw-r--r--arch/arm/mach-omap2/board-omap3logic.c9
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c28
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c37
-rw-r--r--arch/arm/mach-omap2/board-omap3touchbook.c20
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c158
-rw-r--r--arch/arm/mach-omap2/board-overo.c16
-rw-r--r--arch/arm/mach-omap2/board-rm680.c10
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c61
-rw-r--r--arch/arm/mach-omap2/board-rx51-video.c15
-rw-r--r--arch/arm/mach-omap2/board-rx51.c14
-rw-r--r--arch/arm/mach-omap2/board-ti8168evm.c62
-rw-r--r--arch/arm/mach-omap2/board-zoom-display.c15
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c6
-rw-r--r--arch/arm/mach-omap2/board-zoom.c21
-rw-r--r--arch/arm/mach-omap2/clkt2xxx_apll.c24
-rw-r--r--arch/arm/mach-omap2/clkt2xxx_dpll.c63
-rw-r--r--arch/arm/mach-omap2/clkt2xxx_osc.c14
-rw-r--r--arch/arm/mach-omap2/clkt_clksel.c2
-rw-r--r--arch/arm/mach-omap2/clkt_dpll.c91
-rw-r--r--arch/arm/mach-omap2/clkt_iclk.c82
-rw-r--r--arch/arm/mach-omap2/clock.c37
-rw-r--r--arch/arm/mach-omap2/clock.h21
-rw-r--r--arch/arm/mach-omap2/clock2420_data.c221
-rw-r--r--arch/arm/mach-omap2/clock2430_data.c244
-rw-r--r--arch/arm/mach-omap2/clock2xxx.h8
-rw-r--r--arch/arm/mach-omap2/clock34xx.c29
-rw-r--r--arch/arm/mach-omap2/clock34xx.h5
-rw-r--r--arch/arm/mach-omap2/clock3517.c4
-rw-r--r--arch/arm/mach-omap2/clock3xxx.c3
-rw-r--r--arch/arm/mach-omap2/clock3xxx_data.c182
-rw-r--r--arch/arm/mach-omap2/clock44xx_data.c77
-rw-r--r--arch/arm/mach-omap2/clock_common_data.c6
-rw-r--r--arch/arm/mach-omap2/clockdomain.c439
-rw-r--r--arch/arm/mach-omap2/clockdomain.h70
-rw-r--r--arch/arm/mach-omap2/clockdomain2xxx_3xxx.c274
-rw-r--r--arch/arm/mach-omap2/clockdomain44xx.c137
-rw-r--r--arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c28
-rw-r--r--arch/arm/mach-omap2/clockdomains44xx_data.c396
-rw-r--r--arch/arm/mach-omap2/cm-regbits-24xx.h3
-rw-r--r--arch/arm/mach-omap2/cm2xxx_3xxx.c69
-rw-r--r--arch/arm/mach-omap2/cm2xxx_3xxx.h8
-rw-r--r--arch/arm/mach-omap2/cm44xx.h1
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c21
-rw-r--r--arch/arm/mach-omap2/cminst44xx.h6
-rw-r--r--arch/arm/mach-omap2/common.c39
-rw-r--r--arch/arm/mach-omap2/control.h6
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c15
-rw-r--r--arch/arm/mach-omap2/devices.c675
-rw-r--r--arch/arm/mach-omap2/display.c45
-rw-r--r--arch/arm/mach-omap2/dpll44xx.c84
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.c7
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c113
-rw-r--r--arch/arm/mach-omap2/gpmc.c56
-rw-r--r--arch/arm/mach-omap2/hsmmc.c421
-rw-r--r--arch/arm/mach-omap2/hwspinlock.c63
-rw-r--r--arch/arm/mach-omap2/id.c77
-rw-r--r--arch/arm/mach-omap2/include/mach/debug-macro.S12
-rw-r--r--arch/arm/mach-omap2/include/mach/entry-macro.S13
-rw-r--r--arch/arm/mach-omap2/include/mach/omap4-common.h4
-rw-r--r--arch/arm/mach-omap2/io.c42
-rw-r--r--arch/arm/mach-omap2/iommu2.c33
-rw-r--r--arch/arm/mach-omap2/irq.c9
-rw-r--r--arch/arm/mach-omap2/mailbox.c74
-rw-r--r--arch/arm/mach-omap2/mcbsp.c231
-rw-r--r--arch/arm/mach-omap2/mux.c85
-rw-r--r--arch/arm/mach-omap2/mux.h7
-rw-r--r--arch/arm/mach-omap2/mux44xx.c282
-rw-r--r--arch/arm/mach-omap2/omap-headsmp.S2
-rw-r--r--arch/arm/mach-omap2/omap44xx-smc.S8
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c333
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420_data.c1316
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430_data.c1798
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c2334
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c3201
-rw-r--r--arch/arm/mach-omap2/omap_l3_noc.c253
-rw-r--r--arch/arm/mach-omap2/omap_l3_noc.h132
-rw-r--r--arch/arm/mach-omap2/omap_l3_smx.c314
-rw-r--r--arch/arm/mach-omap2/omap_l3_smx.h338
-rw-r--r--arch/arm/mach-omap2/omap_opp_data.h24
-rw-r--r--arch/arm/mach-omap2/omap_phy_internal.c93
-rw-r--r--arch/arm/mach-omap2/omap_twl.c62
-rw-r--r--arch/arm/mach-omap2/opp2xxx.h2
-rw-r--r--arch/arm/mach-omap2/opp3xxx_data.c115
-rw-r--r--arch/arm/mach-omap2/opp4xxx_data.c66
-rw-r--r--arch/arm/mach-omap2/pm.c12
-rw-r--r--arch/arm/mach-omap2/pm.h1
-rw-r--r--arch/arm/mach-omap2/pm24xx.c85
-rw-r--r--arch/arm/mach-omap2/pm34xx.c159
-rw-r--r--arch/arm/mach-omap2/powerdomain.c69
-rw-r--r--arch/arm/mach-omap2/powerdomain.h19
-rw-r--r--arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c9
-rw-r--r--arch/arm/mach-omap2/powerdomains2xxx_data.c24
-rw-r--r--arch/arm/mach-omap2/powerdomains3xxx_data.c38
-rw-r--r--arch/arm/mach-omap2/powerdomains44xx_data.c88
-rw-r--r--arch/arm/mach-omap2/prcm-common.h8
-rw-r--r--arch/arm/mach-omap2/prcm.c5
-rw-r--r--arch/arm/mach-omap2/prcm_mpu44xx.h4
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c18
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.h5
-rw-r--r--arch/arm/mach-omap2/serial.c17
-rw-r--r--arch/arm/mach-omap2/sleep34xx.S282
-rw-r--r--arch/arm/mach-omap2/smartreflex-class3.c2
-rw-r--r--arch/arm/mach-omap2/smartreflex.c33
-rw-r--r--arch/arm/mach-omap2/smartreflex.h (renamed from arch/arm/plat-omap/include/plat/smartreflex.h)3
-rw-r--r--arch/arm/mach-omap2/sr_device.c4
-rw-r--r--arch/arm/mach-omap2/sram34xx.S36
-rw-r--r--arch/arm/mach-omap2/timer-gp.c7
-rw-r--r--arch/arm/mach-omap2/usb-musb.c220
-rw-r--r--arch/arm/mach-omap2/vc.h83
-rw-r--r--arch/arm/mach-omap2/vc3xxx_data.c63
-rw-r--r--arch/arm/mach-omap2/vc44xx_data.c75
-rw-r--r--arch/arm/mach-omap2/voltage.c1020
-rw-r--r--arch/arm/mach-omap2/voltage.h (renamed from arch/arm/plat-omap/include/plat/voltage.h)89
-rw-r--r--arch/arm/mach-omap2/voltagedomains3xxx_data.c95
-rw-r--r--arch/arm/mach-omap2/voltagedomains44xx_data.c102
-rw-r--r--arch/arm/mach-omap2/vp.h143
-rw-r--r--arch/arm/mach-omap2/vp3xxx_data.c82
-rw-r--r--arch/arm/mach-omap2/vp44xx_data.c100
-rw-r--r--arch/arm/mach-orion5x/common.c10
-rw-r--r--arch/arm/mach-orion5x/common.h1
-rw-r--r--arch/arm/mach-orion5x/d2net-setup.c2
-rw-r--r--arch/arm/mach-orion5x/db88f5281-setup.c1
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c1
-rw-r--r--arch/arm/mach-orion5x/edmini_v2-setup.c1
-rw-r--r--arch/arm/mach-orion5x/include/mach/bridge-regs.h6
-rw-r--r--arch/arm/mach-orion5x/include/mach/gpio.h28
-rw-r--r--arch/arm/mach-orion5x/include/mach/orion5x.h1
-rw-r--r--arch/arm/mach-orion5x/irq.c19
-rw-r--r--arch/arm/mach-orion5x/kurobox_pro-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ls-chl-setup.c1
-rw-r--r--arch/arm/mach-orion5x/ls_hgl-setup.c1
-rw-r--r--arch/arm/mach-orion5x/lsmini-setup.c1
-rw-r--r--arch/arm/mach-orion5x/mpp.c3
-rw-r--r--arch/arm/mach-orion5x/mss2-setup.c1
-rw-r--r--arch/arm/mach-orion5x/mv2120-setup.c1
-rw-r--r--arch/arm/mach-orion5x/net2big-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f5182-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c1
-rw-r--r--arch/arm/mach-orion5x/terastation_pro2-setup.c1
-rw-r--r--arch/arm/mach-orion5x/ts209-setup.c1
-rw-r--r--arch/arm/mach-orion5x/ts409-setup.c1
-rw-r--r--arch/arm/mach-orion5x/ts78xx-fpga.h15
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c78
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c1
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c1
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c71
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig5
-rw-r--r--arch/arm/mach-s3c64xx/cpufreq.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c46
-rw-r--r--arch/arm/mach-s5p64x0/Kconfig4
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6440.c47
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6450.c47
-rw-r--r--arch/arm/mach-s5pc100/Kconfig1
-rw-r--r--arch/arm/mach-s5pc100/gpiolib.c1
-rw-r--r--arch/arm/mach-s5pc100/mach-smdkc100.c48
-rw-r--r--arch/arm/mach-s5pv210/Kconfig7
-rw-r--r--arch/arm/mach-s5pv210/Makefile1
-rw-r--r--arch/arm/mach-s5pv210/cpufreq.c3
-rw-r--r--arch/arm/mach-s5pv210/gpiolib.c1
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-clock.h5
-rw-r--r--arch/arm/mach-s5pv210/mach-aquila.c56
-rw-r--r--arch/arm/mach-s5pv210/mach-goni.c107
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkc110.c4
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkv210.c47
-rw-r--r--arch/arm/mach-s5pv210/mach-torbreck.c4
-rw-r--r--arch/arm/mach-s5pv210/setup-fimc.c43
-rw-r--r--arch/arm/mach-s5pv310/Kconfig151
-rw-r--r--arch/arm/mach-s5pv310/Makefile43
-rw-r--r--arch/arm/mach-s5pv310/gpiolib.c304
-rw-r--r--arch/arm/mach-s5pv310/include/mach/gpio.h135
-rw-r--r--arch/arm/mach-s5pv310/include/mach/map.h144
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-gpio.h42
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-pmu.h30
-rw-r--r--arch/arm/mach-s5pv310/include/mach/sysmmu.h122
-rw-r--r--arch/arm/mach-s5pv310/mach-universal_c210.c237
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c10
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c13
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c13
-rw-r--r--arch/arm/mach-tcc8k/board-tcc8000-sdk.c19
-rw-r--r--arch/arm/mach-tcc8k/clock.c38
-rw-r--r--arch/arm/mach-u300/core.c179
-rw-r--r--arch/arm/mach-u300/include/mach/coh901318.h7
-rw-r--r--arch/arm/mach-u300/mmc.c160
-rw-r--r--arch/arm/mach-u300/spi.c21
-rw-r--r--arch/arm/mach-ux500/Makefile8
-rw-r--r--arch/arm/mach-ux500/board-mop500-keypads.c229
-rw-r--r--arch/arm/mach-ux500/board-mop500-pins.c241
-rw-r--r--arch/arm/mach-ux500/board-mop500-regulators.c62
-rw-r--r--arch/arm/mach-ux500/board-mop500-sdi.c184
-rw-r--r--arch/arm/mach-ux500/board-mop500-stuib.c205
-rw-r--r--arch/arm/mach-ux500/board-mop500-u8500uib.c111
-rw-r--r--arch/arm/mach-ux500/board-mop500-uib.c135
-rw-r--r--arch/arm/mach-ux500/board-mop500.c328
-rw-r--r--arch/arm/mach-ux500/board-mop500.h25
-rw-r--r--arch/arm/mach-ux500/board-u5500-sdi.c25
-rw-r--r--arch/arm/mach-ux500/board-u5500.c6
-rw-r--r--arch/arm/mach-ux500/clock.c6
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c53
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c76
-rw-r--r--arch/arm/mach-ux500/devices-common.c1
-rw-r--r--arch/arm/mach-ux500/devices-common.h7
-rw-r--r--arch/arm/mach-ux500/devices-db5500.h19
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c67
-rw-r--r--arch/arm/mach-ux500/devices-db8500.h15
-rw-r--r--arch/arm/mach-ux500/dma-db5500.c16
-rw-r--r--arch/arm/mach-ux500/include/mach/uncompress.h6
-rw-r--r--arch/arm/mach-ux500/include/mach/usb.h25
-rw-r--r--arch/arm/mach-ux500/mbox-db5500.c2
-rw-r--r--arch/arm/mach-ux500/usb.c160
-rw-r--r--arch/arm/mm/Kconfig4
-rw-r--r--arch/arm/plat-mxc/Kconfig1
-rw-r--r--arch/arm/plat-mxc/Makefile1
-rw-r--r--arch/arm/plat-mxc/devices.c2
-rw-r--r--arch/arm/plat-mxc/devices/platform-fec.c9
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-dma.c6
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-fb.c5
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-i2c.c10
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx2-wdt.c9
-rw-r--r--arch/arm/plat-mxc/devices/platform-spi_imx.c9
-rw-r--r--arch/arm/plat-mxc/ehci.c369
-rw-r--r--arch/arm/plat-mxc/gpio.c111
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h10
-rw-r--r--arch/arm/plat-mxc/include/mach/gpio.h15
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx3.h8
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx35.h14
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx50.h44
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx51.h44
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx53.h2639
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mxc91231.h8
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-v1.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/irqs.h6
-rw-r--r--arch/arm/plat-mxc/include/mach/mx1.h9
-rw-r--r--arch/arm/plat-mxc/include/mach/mx53.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc.h10
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_ehci.h7
-rw-r--r--arch/arm/plat-mxc/include/mach/ulpi.h9
-rw-r--r--arch/arm/plat-mxc/include/mach/uncompress.h7
-rw-r--r--arch/arm/plat-mxc/iomux-v1.c24
-rw-r--r--arch/arm/plat-mxc/ulpi.c5
-rw-r--r--arch/arm/plat-nomadik/gpio.c487
-rw-r--r--arch/arm/plat-nomadik/include/plat/gpio.h6
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/clock.c99
-rw-r--r--arch/arm/plat-omap/common.c11
-rw-r--r--arch/arm/plat-omap/counter_32k.c4
-rw-r--r--arch/arm/plat-omap/cpu-omap.c2
-rw-r--r--arch/arm/plat-omap/devices.c10
-rw-r--r--arch/arm/plat-omap/dma.c2
-rw-r--r--arch/arm/plat-omap/dmtimer.c4
-rw-r--r--arch/arm/plat-omap/i2c.c2
-rw-r--r--arch/arm/plat-omap/include/plat/board.h4
-rw-r--r--arch/arm/plat-omap/include/plat/clkdev_omap.h1
-rw-r--r--arch/arm/plat-omap/include/plat/clock.h28
-rw-r--r--arch/arm/plat-omap/include/plat/common.h5
-rw-r--r--arch/arm/plat-omap/include/plat/cpu.h44
-rw-r--r--arch/arm/plat-omap/include/plat/display.h11
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h11
-rw-r--r--arch/arm/plat-omap/include/plat/fpga.h92
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc.h18
-rw-r--r--arch/arm/plat-omap/include/plat/hardware.h1
-rw-r--r--arch/arm/plat-omap/include/plat/io.h12
-rw-r--r--arch/arm/plat-omap/include/plat/iommu.h16
-rw-r--r--arch/arm/plat-omap/include/plat/iovmm.h2
-rw-r--r--arch/arm/plat-omap/include/plat/irqs.h11
-rw-r--r--arch/arm/plat-omap/include/plat/l3_2xxx.h20
-rw-r--r--arch/arm/plat-omap/include/plat/l3_3xxx.h20
-rw-r--r--arch/arm/plat-omap/include/plat/l4_2xxx.h24
-rw-r--r--arch/arm/plat-omap/include/plat/l4_3xxx.h10
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h64
-rw-r--r--arch/arm/plat-omap/include/plat/mcspi.h11
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h29
-rw-r--r--arch/arm/plat-omap/include/plat/multi.h4
-rw-r--r--arch/arm/plat-omap/include/plat/nand.h11
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h25
-rw-r--r--arch/arm/plat-omap/include/plat/onenand.h10
-rw-r--r--arch/arm/plat-omap/include/plat/prcm.h1
-rw-r--r--arch/arm/plat-omap/include/plat/sdrc.h8
-rw-r--r--arch/arm/plat-omap/include/plat/serial.h9
-rw-r--r--arch/arm/plat-omap/include/plat/system.h38
-rw-r--r--arch/arm/plat-omap/include/plat/ti816x.h27
-rw-r--r--arch/arm/plat-omap/include/plat/uncompress.h7
-rw-r--r--arch/arm/plat-omap/include/plat/usb.h5
-rw-r--r--arch/arm/plat-omap/io.c5
-rw-r--r--arch/arm/plat-omap/iommu.c69
-rw-r--r--arch/arm/plat-omap/iovmm.c27
-rw-r--r--arch/arm/plat-omap/mcbsp.c203
-rw-r--r--arch/arm/plat-omap/omap_device.c36
-rw-r--r--arch/arm/plat-omap/sram.c20
-rw-r--r--arch/arm/plat-orion/gpio.c456
-rw-r--r--arch/arm/plat-orion/include/plat/gpio.h5
-rw-r--r--arch/arm/plat-orion/include/plat/time.h5
-rw-r--r--arch/arm/plat-orion/time.c119
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig7
-rw-r--r--arch/arm/plat-s3c24xx/cpu-freq.c2
-rw-r--r--arch/arm/plat-s5p/Kconfig23
-rw-r--r--arch/arm/plat-s5p/Makefile3
-rw-r--r--arch/arm/plat-s5p/cpu.c25
-rw-r--r--arch/arm/plat-s5p/dev-csis0.c2
-rw-r--r--arch/arm/plat-s5p/dev-csis1.c2
-rw-r--r--arch/arm/plat-s5p/dev-fimc3.c43
-rw-r--r--arch/arm/plat-s5p/include/plat/camport.h28
-rw-r--r--arch/arm/plat-s5p/include/plat/csis.h28
-rw-r--r--arch/arm/plat-s5p/include/plat/exynos4.h34
-rw-r--r--arch/arm/plat-s5p/include/plat/mipi_csis.h43
-rw-r--r--arch/arm/plat-s5p/include/plat/s5p-time.h40
-rw-r--r--arch/arm/plat-s5p/include/plat/s5pv310.h34
-rw-r--r--arch/arm/plat-s5p/include/plat/sysmmu.h95
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c170
-rw-r--r--arch/arm/plat-s5p/s5p-time.c448
-rw-r--r--arch/arm/plat-s5p/setup-mipiphy.c63
-rw-r--r--arch/arm/plat-s5p/sysmmu.c370
-rw-r--r--arch/arm/plat-samsung/Kconfig13
-rw-r--r--arch/arm/plat-samsung/Makefile1
-rw-r--r--arch/arm/plat-samsung/dev-pwm.c53
-rw-r--r--arch/arm/plat-samsung/include/plat/cpu.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h25
-rw-r--r--arch/arm/plat-samsung/include/plat/fimc-core.h5
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-cfg.h16
-rw-r--r--arch/arm/plat-samsung/include/plat/pd.h4
-rw-r--r--arch/arm/plat-samsung/include/plat/sdhci.h63
-rw-r--r--arch/arm/plat-samsung/pwm.c33
-rw-r--r--arch/avr32/mm/cache.c2
-rw-r--r--arch/cris/Kconfig1
-rw-r--r--arch/cris/arch-v10/kernel/irq.c2
-rw-r--r--arch/cris/arch-v10/mm/init.c2
-rw-r--r--arch/cris/arch-v32/kernel/irq.c8
-rw-r--r--arch/cris/kernel/irq.c39
-rw-r--r--arch/ia64/include/asm/perfmon.h2
-rw-r--r--arch/ia64/kvm/kvm-ia64.c2
-rw-r--r--arch/mips/include/asm/errno.h2
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-rw-r--r--arch/mips/jz4740/platform.c16
-rw-r--r--arch/parisc/include/asm/errno.h2
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts24
-rw-r--r--arch/powerpc/boot/dts/kmeter1.dts69
-rw-r--r--arch/powerpc/boot/dts/mgcoge.dts47
-rw-r--r--arch/powerpc/boot/dts/mgsuvd.dts163
-rw-r--r--arch/powerpc/boot/dts/p1022ds.dts4
-rw-r--r--arch/powerpc/configs/83xx/kmeter1_defconfig7
-rw-r--r--arch/powerpc/configs/mgcoge_defconfig9
-rw-r--r--arch/powerpc/configs/mgsuvd_defconfig81
-rw-r--r--arch/powerpc/include/asm/cputable.h3
-rw-r--r--arch/powerpc/include/asm/hw_irq.h2
-rw-r--r--arch/powerpc/include/asm/mpic.h6
-rw-r--r--arch/powerpc/include/asm/nvram.h3
-rw-r--r--arch/powerpc/include/asm/pgtable.h1
-rw-r--r--arch/powerpc/include/asm/qe_ic.h19
-rw-r--r--arch/powerpc/include/asm/reg.h13
-rw-r--r--arch/powerpc/include/asm/reg_booke.h3
-rw-r--r--arch/powerpc/kernel/cputable.c22
-rw-r--r--arch/powerpc/kernel/irq.c55
-rw-r--r--arch/powerpc/kernel/machine_kexec.c21
-rw-r--r--arch/powerpc/kernel/nvram_64.c31
-rw-r--r--arch/powerpc/kernel/perf_event.c24
-rw-r--r--arch/powerpc/kernel/prom.c2
-rw-r--r--arch/powerpc/kernel/rtasd.c3
-rw-r--r--arch/powerpc/kvm/book3s.c14
-rw-r--r--arch/powerpc/kvm/booke.c14
-rw-r--r--arch/powerpc/math-emu/math_efp.c65
-rw-r--r--arch/powerpc/mm/init_32.c2
-rw-r--r--arch/powerpc/mm/tlb_nohash_low.S35
-rw-r--r--arch/powerpc/platforms/44x/44x.h4
-rw-r--r--arch/powerpc/platforms/44x/Kconfig1
-rw-r--r--arch/powerpc/platforms/44x/Makefile1
-rw-r--r--arch/powerpc/platforms/44x/canyonlands.c134
-rw-r--r--arch/powerpc/platforms/44x/ppc44x_simple.c1
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads_cpld.c14
-rw-r--r--arch/powerpc/platforms/52xx/media5200.c21
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpt.c26
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c80
-rw-r--r--arch/powerpc/platforms/82xx/Makefile2
-rw-r--r--arch/powerpc/platforms/82xx/km82xx.c (renamed from arch/powerpc/platforms/82xx/mgcoge.c)62
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads-pci-pic.c27
-rw-r--r--arch/powerpc/platforms/83xx/Makefile2
-rw-r--r--arch/powerpc/platforms/83xx/km83xx.c (renamed from arch/powerpc/platforms/83xx/kmeter1.c)46
-rw-r--r--arch/powerpc/platforms/85xx/ksi8560.c3
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c3
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c3
-rw-r--r--arch/powerpc/platforms/85xx/sbc8560.c3
-rw-r--r--arch/powerpc/platforms/85xx/smp.c6
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c40
-rw-r--r--arch/powerpc/platforms/85xx/stx_gp3.c3
-rw-r--r--arch/powerpc/platforms/85xx/tqm85xx.c3
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.c22
-rw-r--r--arch/powerpc/platforms/86xx/pic.c5
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig6
-rw-r--r--arch/powerpc/platforms/8xx/Makefile1
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c9
-rw-r--r--arch/powerpc/platforms/8xx/mgsuvd.c92
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c3
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c36
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c30
-rw-r--r--arch/powerpc/platforms/cell/setup.c6
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c43
-rw-r--r--arch/powerpc/platforms/chrp/setup.c5
-rw-r--r--arch/powerpc/platforms/embedded6xx/flipper-pic.c32
-rw-r--r--arch/powerpc/platforms/embedded6xx/hlwd-pic.c41
-rw-r--r--arch/powerpc/platforms/iseries/irq.c43
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c4
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c2
-rw-r--r--arch/powerpc/platforms/powermac/pic.c48
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c40
-rw-r--r--arch/powerpc/platforms/pseries/cmm.c14
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c2
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c587
-rw-r--r--arch/powerpc/platforms/pseries/msi.c14
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c255
-rw-r--r--arch/powerpc/platforms/pseries/setup.c5
-rw-r--r--arch/powerpc/platforms/pseries/xics.c89
-rw-r--r--arch/powerpc/sysdev/cpm1.c18
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c32
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_l2ctlr.c4
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c111
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c15
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h17
-rw-r--r--arch/powerpc/sysdev/i8259.c42
-rw-r--r--arch/powerpc/sysdev/ipic.c54
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c32
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c46
-rw-r--r--arch/powerpc/sysdev/mpic.c137
-rw-r--r--arch/powerpc/sysdev/mpic.h5
-rw-r--r--arch/powerpc/sysdev/mpic_pasemi_msi.c18
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c18
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c2
-rw-r--r--arch/powerpc/sysdev/mv64x60_pic.c46
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c25
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c41
-rw-r--r--arch/powerpc/sysdev/uic.c59
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c48
-rw-r--r--arch/s390/oprofile/Makefile2
-rw-r--r--arch/s390/oprofile/hwsampler.c1256
-rw-r--r--arch/s390/oprofile/hwsampler.h113
-rw-r--r--arch/s390/oprofile/init.c165
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c6
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c6
-rw-r--r--arch/sparc/include/asm/errno.h2
-rw-r--r--arch/tile/Kconfig39
-rw-r--r--arch/tile/include/arch/interrupts_32.h9
-rw-r--r--arch/tile/include/arch/sim.h48
-rw-r--r--arch/tile/include/arch/sim_def.h3
-rw-r--r--arch/tile/include/asm/Kbuild1
-rw-r--r--arch/tile/include/asm/atomic.h2
-rw-r--r--arch/tile/include/asm/bitops_32.h2
-rw-r--r--arch/tile/include/asm/cache.h2
-rw-r--r--arch/tile/include/asm/cacheflush.h55
-rw-r--r--arch/tile/include/asm/edac.h29
-rw-r--r--arch/tile/include/asm/hugetlb.h2
-rw-r--r--arch/tile/include/asm/irqflags.h18
-rw-r--r--arch/tile/include/asm/page.h34
-rw-r--r--arch/tile/include/asm/pgalloc.h7
-rw-r--r--arch/tile/include/asm/pgtable.h31
-rw-r--r--arch/tile/include/asm/pgtable_32.h8
-rw-r--r--arch/tile/include/asm/processor.h1
-rw-r--r--arch/tile/include/asm/ptrace.h3
-rw-r--r--arch/tile/include/asm/spinlock_32.h83
-rw-r--r--arch/tile/include/asm/stack.h3
-rw-r--r--arch/tile/include/asm/system.h19
-rw-r--r--arch/tile/include/asm/thread_info.h1
-rw-r--r--arch/tile/include/asm/timex.h3
-rw-r--r--arch/tile/include/hv/drv_mshim_intf.h50
-rw-r--r--arch/tile/include/hv/hypervisor.h46
-rw-r--r--arch/tile/kernel/entry.S22
-rw-r--r--arch/tile/kernel/head_32.S15
-rw-r--r--arch/tile/kernel/intvec_32.S74
-rw-r--r--arch/tile/kernel/irq.c38
-rw-r--r--arch/tile/kernel/machine_kexec.c7
-rw-r--r--arch/tile/kernel/pci-dma.c38
-rw-r--r--arch/tile/kernel/process.c6
-rw-r--r--arch/tile/kernel/setup.c20
-rw-r--r--arch/tile/kernel/single_step.c21
-rw-r--r--arch/tile/kernel/smp.c33
-rw-r--r--arch/tile/kernel/stack.c28
-rw-r--r--arch/tile/kernel/time.c10
-rw-r--r--arch/tile/kernel/vmlinux.lds.S5
-rw-r--r--arch/tile/lib/Makefile5
-rw-r--r--arch/tile/lib/atomic_32.c5
-rw-r--r--arch/tile/lib/atomic_asm_32.S2
-rw-r--r--arch/tile/lib/cacheflush.c102
-rw-r--r--arch/tile/lib/delay.c21
-rw-r--r--arch/tile/lib/exports.c10
-rw-r--r--arch/tile/lib/mb_incoherent.S34
-rw-r--r--arch/tile/lib/memcpy_tile64.c4
-rw-r--r--arch/tile/lib/spinlock_32.c161
-rw-r--r--arch/tile/mm/fault.c8
-rw-r--r--arch/tile/mm/homecache.c38
-rw-r--r--arch/tile/mm/init.c34
-rw-r--r--arch/tile/mm/migrate_32.S1
-rw-r--r--arch/tile/mm/pgtable.c181
-rw-r--r--arch/x86/Kconfig.cpu4
-rw-r--r--arch/x86/crypto/aesni-intel_asm.S6
-rw-r--r--arch/x86/include/asm/cacheflush.h2
-rw-r--r--arch/x86/include/asm/kdebug.h2
-rw-r--r--arch/x86/include/asm/kvm_emulate.h5
-rw-r--r--arch/x86/include/asm/kvm_host.h12
-rw-r--r--arch/x86/include/asm/msr-index.h1
-rw-r--r--arch/x86/include/asm/nmi.h4
-rw-r--r--arch/x86/include/asm/nops.h2
-rw-r--r--arch/x86/include/asm/olpc.h2
-rw-r--r--arch/x86/include/asm/perf_event_p4.h4
-rw-r--r--arch/x86/include/asm/pgtable-3level.h11
-rw-r--r--arch/x86/include/asm/processor-flags.h2
-rw-r--r--arch/x86/include/asm/ptrace-abi.h2
-rw-r--r--arch/x86/include/asm/ptrace.h4
-rw-r--r--arch/x86/include/asm/stacktrace.h6
-rw-r--r--arch/x86/include/asm/tsc.h2
-rw-r--r--arch/x86/include/asm/xen/interface.h2
-rw-r--r--arch/x86/kernel/alternative.c2
-rw-r--r--arch/x86/kernel/amd_nb.c2
-rw-r--r--arch/x86/kernel/aperture_64.c2
-rw-r--r--arch/x86/kernel/apic/io_apic.c6
-rw-r--r--arch/x86/kernel/apm_32.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/longhaul.c4
-rw-r--r--arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c5
-rw-r--r--arch/x86/kernel/cpu/cpufreq/speedstep-smi.c4
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-inject.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c2
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c6
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c112
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c8
-rw-r--r--arch/x86/kernel/cpu/vmware.c2
-rw-r--r--arch/x86/kernel/dumpstack.c14
-rw-r--r--arch/x86/kernel/dumpstack_32.c15
-rw-r--r--arch/x86/kernel/dumpstack_64.c14
-rw-r--r--arch/x86/kernel/entry_64.S4
-rw-r--r--arch/x86/kernel/i387.c2
-rw-r--r--arch/x86/kernel/irq_32.c2
-rw-r--r--arch/x86/kernel/kgdb.c2
-rw-r--r--arch/x86/kernel/kvm.c2
-rw-r--r--arch/x86/kernel/mca_32.c2
-rw-r--r--arch/x86/kernel/mpparse.c4
-rw-r--r--arch/x86/kernel/pci-calgary_64.c4
-rw-r--r--arch/x86/kernel/process.c2
-rw-r--r--arch/x86/kernel/stacktrace.c6
-rw-r--r--arch/x86/kernel/step.c2
-rw-r--r--arch/x86/kernel/topology.c2
-rw-r--r--arch/x86/kernel/tsc.c4
-rw-r--r--arch/x86/kernel/verify_cpu.S2
-rw-r--r--arch/x86/kernel/xsave.c2
-rw-r--r--arch/x86/kvm/emulate.c52
-rw-r--r--arch/x86/kvm/i8259.c25
-rw-r--r--arch/x86/kvm/lapic.c13
-rw-r--r--arch/x86/kvm/lapic.h1
-rw-r--r--arch/x86/kvm/mmu.c150
-rw-r--r--arch/x86/kvm/paging_tmpl.h19
-rw-r--r--arch/x86/kvm/svm.c27
-rw-r--r--arch/x86/kvm/timer.c2
-rw-r--r--arch/x86/kvm/vmx.c128
-rw-r--r--arch/x86/kvm/x86.c155
-rw-r--r--arch/x86/lguest/boot.c2
-rw-r--r--arch/x86/lib/copy_user_64.S2
-rw-r--r--arch/x86/lib/csum-copy_64.S242
-rw-r--r--arch/x86/lib/csum-partial_64.c2
-rw-r--r--arch/x86/mm/hugetlbpage.c2
-rw-r--r--arch/x86/mm/init_32.c2
-rw-r--r--arch/x86/mm/numa_64.c2
-rw-r--r--arch/x86/mm/pageattr.c2
-rw-r--r--arch/x86/mm/pgtable.c3
-rw-r--r--arch/x86/oprofile/backtrace.c2
-rw-r--r--arch/x86/oprofile/op_model_p4.c2
-rw-r--r--arch/x86/pci/i386.c4
-rw-r--r--arch/x86/pci/xen.c41
-rw-r--r--arch/x86/xen/mmu.c5
-rw-r--r--arch/xtensa/configs/s6105_defconfig2
-rw-r--r--block/blk-core.c23
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/amba/bus.c348
-rw-r--r--drivers/ata/sata_fsl.c25
-rw-r--r--drivers/atm/firestream.c2
-rw-r--r--drivers/block/smart1,2.h2
-rw-r--r--drivers/bluetooth/btusb.c4
-rw-r--r--drivers/char/hw_random/nomadik-rng.c2
-rw-r--r--drivers/cpufreq/cpufreq.c2
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c123
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c122
-rw-r--r--drivers/cpuidle/sysfs.c2
-rw-r--r--drivers/dma/amba-pl08x.c2
-rw-r--r--drivers/dma/coh901318.c4
-rw-r--r--drivers/dma/pl330.c2
-rw-r--r--drivers/dma/shdma.c2
-rw-r--r--drivers/dma/timb_dma.c2
-rw-r--r--drivers/edac/Kconfig10
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/amd64_edac.c1442
-rw-r--r--drivers/edac/amd64_edac.h369
-rw-r--r--drivers/edac/amd64_edac_inj.c8
-rw-r--r--drivers/edac/edac_mc_sysfs.c26
-rw-r--r--drivers/edac/i7300_edac.c2
-rw-r--r--drivers/edac/i82975x_edac.c69
-rw-r--r--drivers/edac/mce_amd.c8
-rw-r--r--drivers/edac/mce_amd.h28
-rw-r--r--drivers/edac/tile_edac.c254
-rw-r--r--drivers/firewire/core-iso.c1
-rw-r--r--drivers/firewire/core.h3
-rw-r--r--drivers/firmware/dcdbas.c4
-rw-r--r--drivers/gpio/pl061.c2
-rw-r--r--drivers/gpu/drm/drm_sman.c4
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c2
-rw-r--r--drivers/gpu/drm/radeon/r100.c10
-rw-r--r--drivers/gpu/drm/radeon/r300.c4
-rw-r--r--drivers/gpu/drm/radeon/r420.c4
-rw-r--r--drivers/gpu/drm/radeon/r520.c4
-rw-r--r--drivers/gpu/drm/radeon/r600.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c2
-rw-r--r--drivers/gpu/drm/radeon/rs400.c4
-rw-r--r--drivers/gpu/drm/radeon/rs600.c4
-rw-r--r--drivers/gpu/drm/radeon/rs690.c4
-rw-r--r--drivers/gpu/drm/radeon/rv515.c4
-rw-r--r--drivers/gpu/drm/radeon/rv770.c2
-rw-r--r--drivers/hid/Kconfig67
-rw-r--r--drivers/hid/Makefile10
-rw-r--r--drivers/hid/hid-axff.c31
-rw-r--r--drivers/hid/hid-core.c43
-rw-r--r--drivers/hid/hid-dr.c (renamed from drivers/hid/hid-drff.c)117
-rw-r--r--drivers/hid/hid-egalax.c279
-rw-r--r--drivers/hid/hid-gyration.c5
-rw-r--r--drivers/hid/hid-ids.h13
-rw-r--r--drivers/hid/hid-input.c31
-rw-r--r--drivers/hid/hid-keytouch.c66
-rw-r--r--drivers/hid/hid-lcpower.c70
-rw-r--r--drivers/hid/hid-lg.c2
-rw-r--r--drivers/hid/hid-magicmouse.c4
-rw-r--r--drivers/hid/hid-multitouch.c76
-rw-r--r--drivers/hid/hid-ntrig.c519
-rw-r--r--drivers/hid/hid-ortek.c6
-rw-r--r--drivers/hid/hid-roccat-arvo.c450
-rw-r--r--drivers/hid/hid-roccat-arvo.h98
-rw-r--r--drivers/hid/hid-roccat-common.c62
-rw-r--r--drivers/hid/hid-roccat-common.h23
-rw-r--r--drivers/hid/hid-roccat-kone.c156
-rw-r--r--drivers/hid/hid-roccat-koneplus.c167
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c715
-rw-r--r--drivers/hid/hid-roccat-kovaplus.h157
-rw-r--r--drivers/hid/hid-roccat-pyra.c174
-rw-r--r--drivers/hid/hid-roccat.c53
-rw-r--r--drivers/hid/hid-sony.c20
-rw-r--r--drivers/hid/hidraw.c112
-rw-r--r--drivers/hid/usbhid/hid-core.c35
-rw-r--r--drivers/hwmon/Kconfig92
-rw-r--r--drivers/hwmon/Makefile10
-rw-r--r--drivers/hwmon/f71882fg.c522
-rw-r--r--drivers/hwmon/lineage-pem.c586
-rw-r--r--drivers/hwmon/lis3lv02d_spi.c19
-rw-r--r--drivers/hwmon/lm85.c136
-rw-r--r--drivers/hwmon/ltc4151.c256
-rw-r--r--drivers/hwmon/max16064.c91
-rw-r--r--drivers/hwmon/max34440.c199
-rw-r--r--drivers/hwmon/max6639.c653
-rw-r--r--drivers/hwmon/max8688.c158
-rw-r--r--drivers/hwmon/pmbus.c203
-rw-r--r--drivers/hwmon/pmbus.h313
-rw-r--r--drivers/hwmon/pmbus_core.c1658
-rw-r--r--drivers/hwmon/w83627ehf.c1351
-rw-r--r--drivers/hwspinlock/Kconfig22
-rw-r--r--drivers/hwspinlock/Makefile6
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c548
-rw-r--r--drivers/hwspinlock/hwspinlock_internal.h61
-rw-r--r--drivers/hwspinlock/omap_hwspinlock.c231
-rw-r--r--drivers/i2c/busses/Kconfig19
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-mxs.c412
-rw-r--r--drivers/i2c/busses/i2c-tegra.c700
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c6
-rw-r--r--drivers/infiniband/hw/qib/qib_user_pages.c6
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c26
-rw-r--r--drivers/input/serio/ambakmi.c3
-rw-r--r--drivers/isdn/mISDN/hwchannel.c6
-rw-r--r--drivers/macintosh/rack-meter.c2
-rw-r--r--drivers/md/dm-mpath.c22
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h1
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h1
-rw-r--r--drivers/message/fusion/mptbase.c7
-rw-r--r--drivers/message/fusion/mptctl.c4
-rw-r--r--drivers/message/fusion/mptsas.c7
-rw-r--r--drivers/message/i2o/i2o_config.c3
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ti-ssp.c476
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/mmci.c348
-rw-r--r--drivers/mmc/host/mmci.h15
-rw-r--r--drivers/mmc/host/msm_sdcc.c40
-rw-r--r--drivers/mmc/host/msm_sdcc.h1
-rw-r--r--drivers/mmc/host/omap_hsmmc.c36
-rw-r--r--drivers/mtd/nand/Kconfig19
-rw-r--r--drivers/mtd/nand/mxc_nand.c5
-rw-r--r--drivers/mtd/nand/omap2.c367
-rw-r--r--drivers/mtd/onenand/Kconfig2
-rw-r--r--drivers/mtd/onenand/omap2.c36
-rw-r--r--drivers/mtd/ubi/Kconfig8
-rw-r--r--drivers/mtd/ubi/Kconfig.debug73
-rw-r--r--drivers/mtd/ubi/build.c34
-rw-r--r--drivers/mtd/ubi/debug.c14
-rw-r--r--drivers/mtd/ubi/debug.h131
-rw-r--r--drivers/mtd/ubi/io.c145
-rw-r--r--drivers/mtd/ubi/kapi.c2
-rw-r--r--drivers/mtd/ubi/scan.c95
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi.h10
-rw-r--r--drivers/mtd/ubi/vmt.c7
-rw-r--r--drivers/mtd/ubi/vtbl.c9
-rw-r--r--drivers/mtd/ubi/wl.c20
-rw-r--r--drivers/net/atl1c/atl1c.h4
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c7
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/sungem.h2
-rw-r--r--drivers/net/tile/tilepro.c965
-rw-r--r--drivers/oprofile/cpu_buffer.c24
-rw-r--r--drivers/oprofile/timer_int.c4
-rw-r--r--drivers/platform/x86/acer-wmi.c1
-rw-r--r--drivers/rtc/rtc-pl030.c2
-rw-r--r--drivers/rtc/rtc-pl031.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c80
-rw-r--r--drivers/s390/scsi/zfcp_def.h15
-rw-r--r--drivers/s390/scsi/zfcp_erp.c4
-rw-r--r--drivers/s390/scsi/zfcp_ext.h9
-rw-r--r--drivers/s390/scsi/zfcp_fc.c333
-rw-r--r--drivers/s390/scsi/zfcp_fc.h124
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c27
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c71
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR5380.c3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c4
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c18
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h4
-rw-r--r--drivers/scsi/be2iscsi/be_main.c3
-rw-r--r--drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h1080
-rw-r--r--drivers/scsi/bnx2fc/Kconfig11
-rw-r--r--drivers/scsi/bnx2fc/Makefile3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h511
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_constants.h206
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_debug.h70
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c515
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c2535
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c1868
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c1833
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c844
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h4
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c125
-rw-r--r--drivers/scsi/bnx2i/bnx2i_init.c29
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c53
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c56
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.h19
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c7
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c66
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h5
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c112
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c18
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c7
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c26
-rw-r--r--drivers/scsi/fcoe/Makefile2
-rw-r--r--drivers/scsi/fcoe/fcoe.c621
-rw-r--r--drivers/scsi/fcoe/fcoe.h50
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c (renamed from drivers/scsi/fcoe/libfcoe.c)40
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c770
-rw-r--r--drivers/scsi/fcoe/libfcoe.h31
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/vnic_dev.c2
-rw-r--r--drivers/scsi/hpsa.c579
-rw-r--r--drivers/scsi/hpsa.h9
-rw-r--r--drivers/scsi/hpsa_cmd.h4
-rw-r--r--drivers/scsi/ipr.c9
-rw-r--r--drivers/scsi/iscsi_tcp.c134
-rw-r--r--drivers/scsi/iscsi_tcp.h4
-rw-r--r--drivers/scsi/libfc/fc_exch.c111
-rw-r--r--drivers/scsi/libfc/fc_fcp.c39
-rw-r--r--drivers/scsi/libfc/fc_libfc.c120
-rw-r--r--drivers/scsi/libfc/fc_libfc.h14
-rw-r--r--drivers/scsi/libfc/fc_lport.c69
-rw-r--r--drivers/scsi/libfc/fc_npiv.c10
-rw-r--r--drivers/scsi/libfc/fc_rport.c191
-rw-r--r--drivers/scsi/libiscsi.c44
-rw-r--r--drivers/scsi/libsas/Kconfig8
-rw-r--r--drivers/scsi/libsas/Makefile4
-rw-r--r--drivers/scsi/libsas/sas_ata.c80
-rw-r--r--drivers/scsi/libsas/sas_dump.c4
-rw-r--r--drivers/scsi/libsas/sas_dump.h12
-rw-r--r--drivers/scsi/libsas/sas_expander.c5
-rw-r--r--drivers/scsi/libsas/sas_internal.h6
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c3
-rw-r--r--drivers/scsi/lpfc/lpfc.h15
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c123
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h9
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c49
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c962
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h60
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c173
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c18
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h104
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c11
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c113
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c217
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c4
-rw-r--r--drivers/scsi/megaraid.c4
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h10
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c149
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c19
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h5
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h6
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt384
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h8
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c128
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h40
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c1
-rw-r--r--drivers/scsi/osd/osd_initiator.c20
-rw-r--r--drivers/scsi/osst.c10
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c37
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c27
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h10
-rw-r--r--drivers/scsi/pmcraid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c21
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c41
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c52
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c45
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c191
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c57
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/scsi_debug.c192
-rw-r--r--drivers/scsi/scsi_devinfo.c85
-rw-r--r--drivers/scsi/scsi_error.c24
-rw-r--r--drivers/scsi/scsi_lib.c36
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c104
-rw-r--r--drivers/scsi/sd.c229
-rw-r--r--drivers/scsi/sd.h25
-rw-r--r--drivers/spi/Kconfig16
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/amba-pl022.c2
-rw-r--r--drivers/spi/davinci_spi.c11
-rw-r--r--drivers/spi/omap2_mcspi.c222
-rw-r--r--drivers/spi/ti-ssp-spi.c402
-rw-r--r--drivers/target/target_core_cdb.c8
-rw-r--r--drivers/target/target_core_hba.c1
-rw-r--r--drivers/tty/hvc/hvc_xen.c2
-rw-r--r--drivers/tty/hvc/hvcs.c76
-rw-r--r--drivers/tty/serial/Kconfig18
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/amba-pl010.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c513
-rw-r--r--drivers/tty/serial/msm_serial.c286
-rw-r--r--drivers/tty/serial/msm_serial.h28
-rw-r--r--drivers/tty/serial/mxs-auart.c798
-rw-r--r--drivers/tty/serial/pch_uart.c1
-rw-r--r--drivers/tty/serial/ucc_uart.c67
-rw-r--r--drivers/usb/host/ehci-mxc.c5
-rw-r--r--drivers/usb/musb/musb_core.c2
-rw-r--r--drivers/usb/musb/musb_core.h4
-rw-r--r--drivers/usb/musb/musbhsdma.h2
-rw-r--r--drivers/usb/otg/isp1301_omap.c2
-rw-r--r--drivers/video/Kconfig27
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/amba-clcd.c2
-rw-r--r--drivers/video/cyber2000fb.c263
-rw-r--r--drivers/video/cyber2000fb.h16
-rw-r--r--drivers/video/msm/mdp_hw.h11
-rw-r--r--drivers/video/msm/mdp_ppp.c1
-rw-r--r--drivers/video/msm/msm_fb.c27
-rw-r--r--drivers/video/mxsfb.c919
-rw-r--r--drivers/w1/masters/Kconfig2
-rw-r--r--drivers/watchdog/Kconfig34
-rw-r--r--drivers/watchdog/Makefile5
-rw-r--r--drivers/watchdog/alim1535_wdt.c10
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c4
-rw-r--r--drivers/watchdog/bfin_wdt.c4
-rw-r--r--drivers/watchdog/booke_wdt.c19
-rw-r--r--drivers/watchdog/cpwd.c36
-rw-r--r--drivers/watchdog/eurotechwdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/i6300esb.c2
-rw-r--r--drivers/watchdog/iTCO_wdt.c4
-rw-r--r--drivers/watchdog/intel_scu_watchdog.c572
-rw-r--r--drivers/watchdog/intel_scu_watchdog.h66
-rw-r--r--drivers/watchdog/it8712f_wdt.c2
-rw-r--r--drivers/watchdog/it87_wdt.c28
-rw-r--r--drivers/watchdog/jz4740_wdt.c322
-rw-r--r--drivers/watchdog/machzwd.c2
-rw-r--r--drivers/watchdog/max63xx_wdt.c2
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c6
-rw-r--r--drivers/watchdog/mpcore_wdt.c2
-rw-r--r--drivers/watchdog/mtx-1_wdt.c14
-rw-r--r--drivers/watchdog/nv_tco.c2
-rw-r--r--drivers/watchdog/omap_wdt.c25
-rw-r--r--drivers/watchdog/omap_wdt.h2
-rw-r--r--drivers/watchdog/pc87413_wdt.c2
-rw-r--r--drivers/watchdog/pcwd_pci.c2
-rw-r--r--drivers/watchdog/pnx4008_wdt.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c2
-rw-r--r--drivers/watchdog/sbc8360.c2
-rw-r--r--drivers/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/watchdog/sbc_fitpc2_wdt.c2
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c4
-rw-r--r--drivers/watchdog/softdog.c2
-rw-r--r--drivers/watchdog/sp5100_tco.c2
-rw-r--r--drivers/watchdog/sp805_wdt.c2
-rw-r--r--drivers/watchdog/ts72xx_wdt.c2
-rw-r--r--drivers/watchdog/w83697ug_wdt.c4
-rw-r--r--drivers/watchdog/wdt.c2
-rw-r--r--drivers/watchdog/wdt977.c2
-rw-r--r--drivers/watchdog/wdt_pci.c6
-rw-r--r--drivers/watchdog/xen_wdt.c359
-rw-r--r--drivers/xen/Kconfig10
-rw-r--r--drivers/xen/Makefile6
-rw-r--r--drivers/xen/balloon.c359
-rw-r--r--drivers/xen/events.c439
-rw-r--r--drivers/xen/gntalloc.c545
-rw-r--r--drivers/xen/gntdev.c382
-rw-r--r--drivers/xen/grant-table.c10
-rw-r--r--drivers/xen/manage.c16
-rw-r--r--drivers/xen/xen-balloon.c256
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c12
-rw-r--r--drivers/xen/xenbus/xenbus_probe.h3
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c11
-rw-r--r--fs/autofs4/root.c6
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/dcache.c7
-rw-r--r--fs/direct-io.c6
-rw-r--r--fs/dlm/ast.c257
-rw-r--r--fs/dlm/ast.h7
-rw-r--r--fs/dlm/config.c4
-rw-r--r--fs/dlm/debug_fs.c4
-rw-r--r--fs/dlm/dlm_internal.h35
-rw-r--r--fs/dlm/lock.c38
-rw-r--r--fs/dlm/lowcomms.c6
-rw-r--r--fs/dlm/rcom.c4
-rw-r--r--fs/dlm/user.c185
-rw-r--r--fs/dlm/user.h3
-rw-r--r--fs/eventpoll.c12
-rw-r--r--fs/ext3/balloc.c21
-rw-r--r--fs/ext3/namei.c2
-rw-r--r--fs/ext3/super.c7
-rw-r--r--fs/ext4/extents.c4
-rw-r--r--fs/fuse/cuse.c2
-rw-r--r--fs/internal.h5
-rw-r--r--fs/jbd/journal.c2
-rw-r--r--fs/jbd2/journal.c2
-rw-r--r--fs/namei.c9
-rw-r--r--fs/namespace.c292
-rw-r--r--fs/nfs/callback_proc.c2
-rw-r--r--fs/nfs/client.c131
-rw-r--r--fs/nfs/direct.c8
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfs/idmap.c90
-rw-r--r--fs/nfs/internal.h22
-rw-r--r--fs/nfs/nfs3proc.c1
-rw-r--r--fs/nfs/nfs4_fs.h28
-rw-r--r--fs/nfs/nfs4filelayout.c361
-rw-r--r--fs/nfs/nfs4filelayout.h19
-rw-r--r--fs/nfs/nfs4filelayoutdev.c252
-rw-r--r--fs/nfs/nfs4proc.c123
-rw-r--r--fs/nfs/nfs4renewd.c6
-rw-r--r--fs/nfs/nfs4state.c6
-rw-r--r--fs/nfs/nfs4xdr.c38
-rw-r--r--fs/nfs/pagelist.c22
-rw-r--r--fs/nfs/pnfs.c330
-rw-r--r--fs/nfs/pnfs.h118
-rw-r--r--fs/nfs/proc.c1
-rw-r--r--fs/nfs/read.c127
-rw-r--r--fs/nfs/super.c284
-rw-r--r--fs/nfs/write.c153
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/notify/fanotify/fanotify_user.c2
-rw-r--r--fs/notify/inotify/inotify_user.c2
-rw-r--r--fs/ocfs2/dir.c2
-rw-r--r--fs/omfs/dir.c66
-rw-r--r--fs/pstore/inode.c116
-rw-r--r--fs/quota/quota_v2.c2
-rw-r--r--fs/super.c96
-rw-r--r--fs/ubifs/Kconfig23
-rw-r--r--fs/ubifs/commit.c58
-rw-r--r--fs/ubifs/debug.c34
-rw-r--r--fs/ubifs/debug.h30
-rw-r--r--fs/ubifs/io.c201
-rw-r--r--fs/ubifs/journal.c28
-rw-r--r--fs/ubifs/lprops.c26
-rw-r--r--fs/ubifs/lpt_commit.c56
-rw-r--r--fs/ubifs/orphan.c10
-rw-r--r--fs/ubifs/recovery.c44
-rw-r--r--fs/ubifs/scan.c2
-rw-r--r--fs/ubifs/super.c54
-rw-r--r--fs/ubifs/tnc.c10
-rw-r--r--fs/ubifs/ubifs.h45
-rw-r--r--fs/udf/balloc.c4
-rw-r--r--fs/udf/file.c7
-rw-r--r--fs/udf/inode.c239
-rw-r--r--fs/udf/truncate.c146
-rw-r--r--fs/udf/udfdecl.h12
-rw-r--r--include/asm-generic/errno.h2
-rw-r--r--include/asm-generic/user.h4
-rw-r--r--include/linux/amba/bus.h8
-rw-r--r--include/linux/amba/mmci.h17
-rw-r--r--include/linux/cpufreq.h11
-rw-r--r--include/linux/dcache.h2
-rw-r--r--include/linux/firewire.h7
-rw-r--r--include/linux/fs.h1
-rw-r--r--include/linux/hid-roccat.h (renamed from drivers/hid/hid-roccat.h)19
-rw-r--r--include/linux/hid.h5
-rw-r--r--include/linux/hidraw.h3
-rw-r--r--include/linux/hwspinlock.h292
-rw-r--r--include/linux/i2c-tegra.h25
-rw-r--r--include/linux/i2c/max6639.h14
-rw-r--r--include/linux/i2c/pmbus.h45
-rw-r--r--include/linux/i2c/twl.h2
-rw-r--r--include/linux/kvm_host.h31
-rw-r--r--include/linux/mfd/ti_ssp.h93
-rw-r--r--include/linux/mfd/wm8994/pdata.h12
-rw-r--r--include/linux/mfd/wm8994/registers.h2
-rw-r--r--include/linux/mm.h24
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/msm_mdp.h1
-rw-r--r--include/linux/mtd/onenand_regs.h1
-rw-r--r--include/linux/mtd/ubi.h22
-rw-r--r--include/linux/namei.h2
-rw-r--r--include/linux/nfs_fs.h2
-rw-r--r--include/linux/nfs_fs_sb.h4
-rw-r--r--include/linux/nfs_idmap.h9
-rw-r--r--include/linux/nfs_iostat.h2
-rw-r--r--include/linux/nfs_page.h6
-rw-r--r--include/linux/nfs_xdr.h16
-rw-r--r--include/linux/oprofile.h7
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/perf_event.h2
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--include/linux/sunrpc/xprt.h3
-rw-r--r--include/scsi/fc/fc_ns.h11
-rw-r--r--include/scsi/fc_encode.h26
-rw-r--r--include/scsi/libfc.h74
-rw-r--r--include/scsi/libfcoe.h105
-rw-r--r--include/scsi/libiscsi.h8
-rw-r--r--include/scsi/scsi.h5
-rw-r--r--include/scsi/scsi_device.h1
-rw-r--r--include/scsi/scsi_transport_iscsi.h6
-rw-r--r--include/sound/ac97_codec.h5
-rw-r--r--include/sound/control.h2
-rw-r--r--include/sound/cs4271.h24
-rw-r--r--include/sound/hdspm.h179
-rw-r--r--include/sound/mixer_oss.h3
-rw-r--r--include/sound/pcm.h91
-rw-r--r--include/sound/sh_fsi.h76
-rw-r--r--include/sound/soc-dapm.h16
-rw-r--r--include/sound/soc.h147
-rw-r--r--include/sound/tlv320aic32x4.h31
-rw-r--r--include/sound/version.h2
-rw-r--r--include/sound/wm8903.h20
-rw-r--r--include/sound/wm9081.h9
-rw-r--r--include/trace/events/asoc.h25
-rw-r--r--include/trace/events/scsi.h28
-rw-r--r--include/xen/balloon.h25
-rw-r--r--include/xen/events.h24
-rw-r--r--include/xen/gntalloc.h82
-rw-r--r--include/xen/gntdev.h31
-rw-r--r--include/xen/interface/sched.h34
-rw-r--r--include/xen/xenbus.h2
-rw-r--r--init/Kconfig6
-rw-r--r--kernel/fork.c1
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/irq/proc.c3
-rw-r--r--kernel/perf_event.c17
-rw-r--r--kernel/pid.c2
-rw-r--r--kernel/smp.c71
-rw-r--r--kernel/trace/Kconfig4
-rw-r--r--kernel/trace/ring_buffer.c2
-rw-r--r--kernel/trace/trace_events_filter.c2
-rw-r--r--mm/internal.h5
-rw-r--r--mm/memory-failure.c32
-rw-r--r--mm/memory.c69
-rw-r--r--mm/mempolicy.c2
-rw-r--r--mm/page_alloc.c4
-rw-r--r--mm/shmem.c2
-rw-r--r--net/bluetooth/hidp/core.c197
-rw-r--r--net/bluetooth/hidp/hidp.h15
-rw-r--r--net/core/dev_addr_lists.c4
-rw-r--r--net/ipv6/inet6_hashtables.c2
-rw-r--r--net/mac80211/tx.c2
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/clnt.c18
-rw-r--r--net/sunrpc/sched.c29
-rw-r--r--net/sunrpc/xprt.c25
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c86
-rw-r--r--net/sunrpc/xprtrdma/verbs.c53
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h1
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/arm/aaci.c285
-rw-r--r--sound/arm/aaci.h9
-rw-r--r--sound/core/control.c68
-rw-r--r--sound/core/device.c7
-rw-r--r--sound/core/memalloc.c3
-rw-r--r--sound/core/oss/linear.c7
-rw-r--r--sound/core/oss/mixer_oss.c10
-rw-r--r--sound/core/oss/mulaw.c2
-rw-r--r--sound/core/oss/pcm_oss.c51
-rw-r--r--sound/core/oss/pcm_plugin.c40
-rw-r--r--sound/core/oss/pcm_plugin.h11
-rw-r--r--sound/core/oss/route.c6
-rw-r--r--sound/core/pcm.c10
-rw-r--r--sound/core/pcm_misc.c35
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c7
-rw-r--r--sound/core/seq/seq_memory.c6
-rw-r--r--sound/core/seq/seq_memory.h4
-rw-r--r--sound/core/seq/seq_ports.c2
-rw-r--r--sound/core/timer.c8
-rw-r--r--sound/core/vmaster.c2
-rw-r--r--sound/drivers/aloop.c19
-rw-r--r--sound/firewire/Kconfig25
-rw-r--r--sound/firewire/Makefile6
-rw-r--r--sound/firewire/amdtp.c562
-rw-r--r--sound/firewire/amdtp.h169
-rw-r--r--sound/firewire/cmp.c308
-rw-r--r--sound/firewire/cmp.h41
-rw-r--r--sound/firewire/fcp.c224
-rw-r--r--sound/firewire/fcp.h12
-rw-r--r--sound/firewire/iso-resources.c232
-rw-r--r--sound/firewire/iso-resources.h39
-rw-r--r--sound/firewire/lib.c85
-rw-r--r--sound/firewire/lib.h19
-rw-r--r--sound/firewire/packets-buffer.c74
-rw-r--r--sound/firewire/packets-buffer.h26
-rw-r--r--sound/firewire/speakers.c858
-rw-r--r--sound/oss/soundcard.c56
-rw-r--r--sound/pci/Kconfig12
-rw-r--r--sound/pci/ac97/ac97_codec.c90
-rw-r--r--sound/pci/ac97/ac97_patch.c52
-rw-r--r--sound/pci/asihpi/asihpi.c774
-rw-r--r--sound/pci/asihpi/hpi.h1214
-rw-r--r--sound/pci/asihpi/hpi6000.c299
-rw-r--r--sound/pci/asihpi/hpi6205.c603
-rw-r--r--sound/pci/asihpi/hpi6205.h7
-rw-r--r--sound/pci/asihpi/hpi_internal.h1118
-rw-r--r--sound/pci/asihpi/hpicmn.c480
-rw-r--r--sound/pci/asihpi/hpicmn.h24
-rw-r--r--sound/pci/asihpi/hpidebug.c157
-rw-r--r--sound/pci/asihpi/hpidebug.h323
-rw-r--r--sound/pci/asihpi/hpidspcd.c37
-rw-r--r--sound/pci/asihpi/hpidspcd.h2
-rw-r--r--sound/pci/asihpi/hpifunc.c2498
-rw-r--r--sound/pci/asihpi/hpimsginit.c18
-rw-r--r--sound/pci/asihpi/hpimsginit.h12
-rw-r--r--sound/pci/asihpi/hpimsgx.c203
-rw-r--r--sound/pci/asihpi/hpioctl.c90
-rw-r--r--sound/pci/asihpi/hpios.h10
-rw-r--r--sound/pci/atiixp.c2
-rw-r--r--sound/pci/atiixp_modem.c2
-rw-r--r--sound/pci/au88x0/au88x0.h4
-rw-r--r--sound/pci/au88x0/au88x0_core.c4
-rw-r--r--sound/pci/au88x0/au88x0_eq.c3
-rw-r--r--sound/pci/azt3328.c450
-rw-r--r--sound/pci/ctxfi/ctatc.c2
-rw-r--r--sound/pci/ctxfi/ctdaio.c2
-rw-r--r--sound/pci/ctxfi/cthw20k2.c28
-rw-r--r--sound/pci/ctxfi/ctmixer.c19
-rw-r--r--sound/pci/ctxfi/ctvmem.c3
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c2
-rw-r--r--sound/pci/hda/hda_codec.c105
-rw-r--r--sound/pci/hda/hda_codec.h5
-rw-r--r--sound/pci/hda/hda_intel.c7
-rw-r--r--sound/pci/hda/hda_local.h24
-rw-r--r--sound/pci/hda/patch_analog.c117
-rw-r--r--sound/pci/hda/patch_conexant.c124
-rw-r--r--sound/pci/hda/patch_hdmi.c22
-rw-r--r--sound/pci/hda/patch_realtek.c206
-rw-r--r--sound/pci/hda/patch_sigmatel.c318
-rw-r--r--sound/pci/intel8x0m.c107
-rw-r--r--sound/pci/rme9652/hdspm.c4466
-rw-r--r--sound/ppc/pmac.c6
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/codecs/Kconfig34
-rw-r--r--sound/soc/codecs/Makefile18
-rw-r--r--sound/soc/codecs/ak4104.c1
-rw-r--r--sound/soc/codecs/ak4642.c24
-rw-r--r--sound/soc/codecs/cs4270.c8
-rw-r--r--sound/soc/codecs/cs4271.c667
-rw-r--r--sound/soc/codecs/dfbmcs320.c72
-rw-r--r--sound/soc/codecs/lm4857.c276
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/codecs/max9850.c389
-rw-r--r--sound/soc/codecs/max9850.h38
-rw-r--r--sound/soc/codecs/sgtl5000.c1513
-rw-r--r--sound/soc/codecs/sgtl5000.h400
-rw-r--r--sound/soc/codecs/sn95031.c949
-rw-r--r--sound/soc/codecs/sn95031.h132
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c794
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h143
-rw-r--r--sound/soc/codecs/tlv320dac33.c1
-rw-r--r--sound/soc/codecs/twl6040.c4
-rw-r--r--sound/soc/codecs/wm2000.c14
-rw-r--r--sound/soc/codecs/wm8523.c8
-rw-r--r--sound/soc/codecs/wm8741.c13
-rw-r--r--sound/soc/codecs/wm8753.c296
-rw-r--r--sound/soc/codecs/wm8804.c2
-rw-r--r--sound/soc/codecs/wm8900.c2
-rw-r--r--sound/soc/codecs/wm8903.c641
-rw-r--r--sound/soc/codecs/wm8903.h8
-rw-r--r--sound/soc/codecs/wm8904.c43
-rw-r--r--sound/soc/codecs/wm8955.c27
-rw-r--r--sound/soc/codecs/wm8961.c2
-rw-r--r--sound/soc/codecs/wm8962.c36
-rw-r--r--sound/soc/codecs/wm8978.c7
-rw-r--r--sound/soc/codecs/wm8991.c1427
-rw-r--r--sound/soc/codecs/wm8991.h833
-rw-r--r--sound/soc/codecs/wm8993.c2
-rw-r--r--sound/soc/codecs/wm8994-tables.c12
-rw-r--r--sound/soc/codecs/wm8994.c127
-rw-r--r--sound/soc/codecs/wm8994.h2
-rw-r--r--sound/soc/codecs/wm8995.c103
-rw-r--r--sound/soc/codecs/wm9081.c84
-rw-r--r--sound/soc/codecs/wm9090.c45
-rw-r--r--sound/soc/codecs/wm_hubs.c3
-rw-r--r--sound/soc/davinci/davinci-i2s.c28
-rw-r--r--sound/soc/davinci/davinci-mcasp.c29
-rw-r--r--sound/soc/ep93xx/Kconfig9
-rw-r--r--sound/soc/ep93xx/Makefile2
-rw-r--r--sound/soc/ep93xx/edb93xx.c142
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c1
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c31
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c4
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c6
-rw-r--r--sound/soc/fsl/p1022_ds.c6
-rw-r--r--sound/soc/imx/Kconfig13
-rw-r--r--sound/soc/imx/Makefile2
-rw-r--r--sound/soc/imx/eukrea-tlv320.c3
-rw-r--r--sound/soc/imx/imx-ssi.c5
-rw-r--r--sound/soc/imx/mx27vis-aic32x4.c137
-rw-r--r--sound/soc/mid-x86/Kconfig14
-rw-r--r--sound/soc/mid-x86/Makefile5
-rw-r--r--sound/soc/mid-x86/mfld_machine.c452
-rw-r--r--sound/soc/mid-x86/sst_platform.c474
-rw-r--r--sound/soc/mid-x86/sst_platform.h63
-rw-r--r--sound/soc/omap/Kconfig1
-rw-r--r--sound/soc/omap/omap-mcbsp.c126
-rw-r--r--sound/soc/omap/omap-mcbsp.h4
-rw-r--r--sound/soc/omap/rx51.c131
-rw-r--r--sound/soc/pxa/raumfeld.c20
-rw-r--r--sound/soc/pxa/tosa.c4
-rw-r--r--sound/soc/pxa/z2.c7
-rw-r--r--sound/soc/pxa/zylonite.c9
-rw-r--r--sound/soc/samsung/Kconfig21
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/ac97.c8
-rw-r--r--sound/soc/samsung/ac97.h21
-rw-r--r--sound/soc/samsung/dma.c13
-rw-r--r--sound/soc/samsung/dma.h8
-rw-r--r--sound/soc/samsung/goni_wm8994.c10
-rw-r--r--sound/soc/samsung/h1940_uda1380.c9
-rw-r--r--sound/soc/samsung/i2s.c3
-rw-r--r--sound/soc/samsung/jive_wm8750.c11
-rw-r--r--sound/soc/samsung/lm4857.h32
-rw-r--r--sound/soc/samsung/ln2440sbc_alc650.c7
-rw-r--r--sound/soc/samsung/neo1973_gta02_wm8753.c504
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c635
-rw-r--r--sound/soc/samsung/pcm.c118
-rw-r--r--sound/soc/samsung/pcm.h107
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c11
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c3
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c12
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c14
-rw-r--r--sound/soc/samsung/s3c24xx_simtec.c7
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_hermes.c10
-rw-r--r--sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c12
-rw-r--r--sound/soc/samsung/s3c24xx_uda134x.c9
-rw-r--r--sound/soc/samsung/smartq_wm8987.c6
-rw-r--r--sound/soc/samsung/smdk2443_wm9710.c7
-rw-r--r--sound/soc/samsung/smdk_spdif.c5
-rw-r--r--sound/soc/samsung/smdk_wm8580.c7
-rw-r--r--sound/soc/samsung/smdk_wm9713.c5
-rw-r--r--sound/soc/samsung/spdif.c3
-rw-r--r--sound/soc/sh/fsi-ak4642.c24
-rw-r--r--sound/soc/sh/fsi-da7210.c13
-rw-r--r--sound/soc/sh/fsi-hdmi.c77
-rw-r--r--sound/soc/sh/fsi.c203
-rw-r--r--sound/soc/soc-cache.c386
-rw-r--r--sound/soc/soc-core.c548
-rw-r--r--sound/soc/soc-dapm.c257
-rw-r--r--sound/soc/soc-jack.c58
-rw-r--r--sound/soc/soc-utils.c23
-rw-r--r--sound/soc/tegra/Kconfig26
-rw-r--r--sound/soc/tegra/Makefile15
-rw-r--r--sound/soc/tegra/harmony.c393
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c155
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h45
-rw-r--r--sound/soc/tegra/tegra_das.c265
-rw-r--r--sound/soc/tegra/tegra_das.h135
-rw-r--r--sound/soc/tegra/tegra_i2s.c503
-rw-r--r--sound/soc/tegra/tegra_i2s.h165
-rw-r--r--sound/soc/tegra/tegra_pcm.c404
-rw-r--r--sound/soc/tegra/tegra_pcm.h55
-rw-r--r--sound/sound_core.c3
-rw-r--r--sound/usb/6fire/Makefile3
-rw-r--r--sound/usb/6fire/chip.c232
-rw-r--r--sound/usb/6fire/chip.h32
-rw-r--r--sound/usb/6fire/comm.c176
-rw-r--r--sound/usb/6fire/comm.h44
-rw-r--r--sound/usb/6fire/common.h30
-rw-r--r--sound/usb/6fire/control.c275
-rw-r--r--sound/usb/6fire/control.h37
-rw-r--r--sound/usb/6fire/firmware.c426
-rw-r--r--sound/usb/6fire/firmware.h27
-rw-r--r--sound/usb/6fire/midi.c203
-rw-r--r--sound/usb/6fire/midi.h46
-rw-r--r--sound/usb/6fire/pcm.c688
-rw-r--r--sound/usb/6fire/pcm.h76
-rw-r--r--sound/usb/Kconfig17
-rw-r--r--sound/usb/Makefile2
-rw-r--r--sound/usb/caiaq/audio.c1
-rw-r--r--sound/usb/caiaq/device.c6
-rw-r--r--sound/usb/caiaq/device.h1
-rw-r--r--sound/usb/card.c64
-rw-r--r--sound/usb/midi.c8
-rw-r--r--sound/usb/mixer.c65
-rw-r--r--sound/usb/mixer.h2
-rw-r--r--sound/usb/mixer_quirks.c174
-rw-r--r--sound/usb/pcm.c20
-rw-r--r--sound/usb/power.h17
-rw-r--r--sound/usb/quirks-table.h14
-rw-r--r--sound/usb/quirks.c56
-rw-r--r--sound/usb/usbaudio.h6
-rw-r--r--tools/perf/Documentation/perf-evlist.txt26
-rw-r--r--tools/perf/Documentation/perf-script.txt22
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-evlist.c54
-rw-r--r--tools/perf/builtin-lock.c13
-rw-r--r--tools/perf/builtin-script.c300
-rw-r--r--tools/perf/builtin-stat.c8
-rw-r--r--tools/perf/builtin-top.c20
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN8
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/parse-events.c22
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c11
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c11
-rw-r--r--tools/perf/util/session.c61
-rw-r--r--tools/perf/util/session.h4
-rw-r--r--tools/perf/util/symbol.c64
-rw-r--r--tools/perf/util/symbol.h31
-rw-r--r--tools/perf/util/top.c6
-rw-r--r--tools/perf/util/top.h4
-rw-r--r--tools/perf/util/trace-event-parse.c110
-rw-r--r--tools/perf/util/trace-event-scripting.c9
-rw-r--r--tools/perf/util/trace-event.h10
-rw-r--r--virt/kvm/eventfd.c5
-rw-r--r--virt/kvm/kvm_main.c139
1758 files changed, 110470 insertions, 33654 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid b/Documentation/ABI/testing/sysfs-driver-hid
new file mode 100644
index 000000000000..b6490e14fe83
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid
@@ -0,0 +1,10 @@
+What: For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
+ For BT devices : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
+ Symlink : /sys/class/hidraw/hidraw<num>/device/report_descriptor
+Date: Jan 2011
+KernelVersion: 2.0.39
+Contact: Alan Ott <alan@signal11.us>
+Description: When read, this file returns the device's raw binary HID
+ report descriptor.
+ This file cannot be written.
+Users: HIDAPI library (http://www.signal11.us/oss/hidapi)
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo b/Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo
new file mode 100644
index 000000000000..55e281b0071a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-arvo
@@ -0,0 +1,53 @@
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/actual_profile
+Date: Januar 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 1-5.
+ When read, this attribute returns the number of the actual
+ profile which is also the profile that's active on device startup.
+ When written this attribute activates the selected profile
+ immediately.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/button
+Date: Januar 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The keyboard can store short macros with consist of 1 button with
+ several modifier keys internally.
+ When written, this file lets one set the sequence for a specific
+ button for a specific profile. Button and profile numbers are
+ included in written data. The data has to be 24 bytes long.
+ This file is writeonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/info
+Date: Januar 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns some info about the device like the
+ installed firmware version.
+ The size of the data is 8 bytes in size.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/key_mask
+Date: Januar 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The keyboard lets the user deactivate 5 certain keys like the
+ windows and application keys, to protect the user from the outcome
+ of accidentally pressing them.
+ The integer value of this attribute has bits 0-4 set depending
+ on the state of the corresponding key.
+ When read, this file returns the current state of the buttons.
+ When written, the given buttons are activated/deactivated
+ immediately.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/mode_key
+Date: Januar 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The keyboard has a condensed layout without num-lock key.
+ Instead it uses a mode-key which activates a gaming mode where
+ the assignment of the number block changes.
+ The integer value of this attribute ranges from 0 (OFF) to 1 (ON).
+ When read, this file returns the actual state of the key.
+ When written, the key is activated/deactivated immediately.
+Users: http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
index 698b8081c473..b4c4f158ab9c 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
@@ -16,12 +16,14 @@ Description: It is possible to switch the dpi setting of the mouse with the
6 3200
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/actual_profile
Date: March 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/firmware_version
Date: March 2010
@@ -32,6 +34,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 138 means 1.38
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/profile[1-5]
Date: March 2010
@@ -47,6 +50,7 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data, whereas the profile number
stored in the profile doesn't need to fit the number of the
store.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/settings
Date: March 2010
@@ -57,6 +61,7 @@ Description: When read, this file returns the settings stored in the mouse.
When written, this file lets write settings back to the mouse.
The data has to be 36 bytes long. The mouse will reject invalid
data.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/startup_profile
Date: March 2010
@@ -66,6 +71,7 @@ Description: The integer value of this attribute ranges from 1 to 5.
that's active when the mouse is powered on.
When written, this file sets the number of the startup profile
and the mouse activates this profile immediately.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/tcu
Date: March 2010
@@ -77,6 +83,7 @@ Description: The mouse has a "Tracking Control Unit" which lets the user
Writing 0 in this file will switch the TCU off.
Writing 1 in this file will start the calibration which takes
around 6 seconds to complete and activates the TCU.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/weight
Date: March 2010
@@ -96,3 +103,4 @@ Description: The mouse can be equipped with one of four supplied weights
4 20g
This file is readonly.
+Users: http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
index 0f9f30eb1742..00efced73969 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
@@ -4,6 +4,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in
range 0-4.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version
Date: October 2010
@@ -14,6 +15,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 121 means 1.21
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro
Date: October 2010
@@ -24,6 +26,7 @@ Description: The mouse can store a macro with max 500 key/button strokes
button for a specific profile. Button and profile numbers are
included in written data. The data has to be 2082 bytes long.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_buttons
Date: August 2010
@@ -37,6 +40,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
Date: August 2010
@@ -47,6 +51,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile buttons.
The returned data is 77 bytes in size.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
Date: October 2010
@@ -61,6 +66,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
Date: August 2010
@@ -72,6 +78,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile settings.
The returned data is 43 bytes in size.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
Date: October 2010
@@ -80,6 +87,7 @@ Description: The mouse has a tracking- and a distance-control-unit. These
can be activated/deactivated and the lift-off distance can be
set. The data has to be 6 bytes long.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
Date: October 2010
@@ -89,6 +97,7 @@ Description: The integer value of this attribute ranges from 0-4.
that's active when the mouse is powered on.
When written, this file sets the number of the startup profile
and the mouse activates this profile immediately.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
Date: October 2010
@@ -97,6 +106,7 @@ Description: When written a calibration process for the tracking control unit
can be initiated/cancelled.
The data has to be 3 bytes long.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
Date: October 2010
@@ -106,3 +116,4 @@ Description: When read the mouse returns a 30x30 pixel image of the
calibration process initiated with tcu.
The returned data is 1028 bytes in size.
This file is readonly.
+Users: http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus
new file mode 100644
index 000000000000..fdfa16f8189b
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kovaplus
@@ -0,0 +1,100 @@
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_cpi
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 1-4.
+ When read, this attribute returns the number of the active
+ cpi level.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_profile
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 0-4.
+ When read, this attribute returns the number of the active
+ profile.
+ When written, the mouse activates this profile immediately.
+ The profile that's active when powered down is the same that's
+ active when the mouse is powered on.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_x
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 1-10.
+ When read, this attribute returns the number of the actual
+ sensitivity in x direction.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_y
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 1-10.
+ When read, this attribute returns the number of the actual
+ sensitivity in y direction.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/firmware_version
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: When read, this file returns the raw integer version number of the
+ firmware reported by the mouse. Using the integer value eases
+ further usage in other programs. To receive the real version
+ number the decimal point has to be shifted 2 positions to the
+ left. E.g. a returned value of 121 means 1.21
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When written, this file lets one write the respective profile
+ buttons back to the mouse. The data has to be 23 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_buttons
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_buttons holds informations about button layout.
+ When read, these files return the respective profile buttons.
+ The returned data is 23 bytes in size.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When written, this file lets one write the respective profile
+ settings back to the mouse. The data has to be 16 bytes long.
+ The mouse will reject invalid data.
+ Which profile to write is determined by the profile number
+ contained in the data.
+ This file is writeonly.
+Users: http://roccat.sourceforge.net
+
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_settings
+Date: January 2011
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The mouse can store 5 profiles which can be switched by the
+ press of a button. A profile is split in settings and buttons.
+ profile_settings holds informations like resolution, sensitivity
+ and light effects.
+ When read, these files return the respective profile settings.
+ The returned data is 16 bytes in size.
+ This file is readonly.
+Users: http://roccat.sourceforge.net
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
index 1c37b823f142..5fab71af3c46 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
@@ -13,6 +13,7 @@ Description: It is possible to switch the cpi setting of the mouse with the
4 1600
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_profile
Date: August 2010
@@ -20,6 +21,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in
range 0-4.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/firmware_version
Date: August 2010
@@ -30,6 +32,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 138 means 1.38
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings
Date: August 2010
@@ -44,6 +47,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
Date: August 2010
@@ -55,6 +59,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile settings.
The returned data is 13 bytes in size.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons
Date: August 2010
@@ -68,6 +73,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number
contained in the data.
This file is writeonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
Date: August 2010
@@ -78,6 +84,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile buttons.
The returned data is 19 bytes in size.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
Date: August 2010
@@ -86,6 +93,7 @@ Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the profile
that's active when the mouse is powered on.
This file is readonly.
+Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
Date: August 2010
@@ -96,3 +104,4 @@ Description: When read, this file returns the settings stored in the mouse.
When written, this file lets write settings back to the mouse.
The data has to be 3 bytes long. The mouse will reject invalid
data.
+Users: http://roccat.sourceforge.net
diff --git a/Documentation/cgroups/cpusets.txt b/Documentation/cgroups/cpusets.txt
index 5d0d5692a365..98a30829af7a 100644
--- a/Documentation/cgroups/cpusets.txt
+++ b/Documentation/cgroups/cpusets.txt
@@ -693,7 +693,7 @@ There are ways to query or modify cpusets:
- via the C library libcgroup.
(http://sourceforge.net/projects/libcg/)
- via the python application cset.
- (http://developer.novell.com/wiki/index.php/Cpuset)
+ (http://code.google.com/p/cpuset/)
The sched_setaffinity calls can also be done at the shell prompt using
SGI's runon or Robert Love's taskset. The mbind and set_mempolicy
@@ -725,13 +725,14 @@ Now you want to do something with this cpuset.
In this directory you can find several files:
# ls
-cpuset.cpu_exclusive cpuset.memory_spread_slab
-cpuset.cpus cpuset.mems
-cpuset.mem_exclusive cpuset.sched_load_balance
-cpuset.mem_hardwall cpuset.sched_relax_domain_level
-cpuset.memory_migrate notify_on_release
-cpuset.memory_pressure tasks
-cpuset.memory_spread_page
+cgroup.clone_children cpuset.memory_pressure
+cgroup.event_control cpuset.memory_spread_page
+cgroup.procs cpuset.memory_spread_slab
+cpuset.cpu_exclusive cpuset.mems
+cpuset.cpus cpuset.sched_load_balance
+cpuset.mem_exclusive cpuset.sched_relax_domain_level
+cpuset.mem_hardwall notify_on_release
+cpuset.memory_migrate tasks
Reading them will give you information about the state of this cpuset:
the CPUs and Memory Nodes it can use, the processes that are using
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index 7781857dc940..b6ed61c95856 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -485,8 +485,9 @@ The feature can be disabled by
# echo 0 > memory.use_hierarchy
-NOTE1: Enabling/disabling will fail if the cgroup already has other
- cgroups created below it.
+NOTE1: Enabling/disabling will fail if either the cgroup already has other
+ cgroups created below it, or if the parent cgroup has use_hierarchy
+ enabled.
NOTE2: When panic_on_oom is set to "2", the whole system will panic in
case of an OOM event in any cgroup.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index 737988fca64d..e74d0a2eb1cf 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -158,6 +158,17 @@ intensive calculation on your laptop that you do not care how long it
takes to complete as you can 'nice' it and prevent it from taking part
in the deciding process of whether to increase your CPU frequency.
+sampling_down_factor: this parameter controls the rate at which the
+kernel makes a decision on when to decrease the frequency while running
+at top speed. When set to 1 (the default) decisions to reevaluate load
+are made at the same interval regardless of current clock speed. But
+when set to greater than 1 (e.g. 100) it acts as a multiplier for the
+scheduling interval for reevaluating load when the CPU is at its top
+speed due to high load. This improves performance by reducing the overhead
+of load evaluation and helping the CPU stay at its top speed when truly
+busy, rather than shifting back and forth in speed. This tunable has no
+effect on behavior at lower speeds/lower CPU loads.
+
2.5 Conservative
----------------
diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
index 59293ac4a5d0..6b5c42dbbe84 100644
--- a/Documentation/device-mapper/dm-crypt.txt
+++ b/Documentation/device-mapper/dm-crypt.txt
@@ -41,7 +41,7 @@ Example scripts
===============
LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
encryption with dm-crypt using the 'cryptsetup' utility, see
-http://clemens.endorphin.org/cryptography
+http://code.google.com/p/cryptsetup/
[[
#!/bin/sh
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cache_sram.txt b/Documentation/devicetree/bindings/powerpc/fsl/cache_sram.txt
new file mode 100644
index 000000000000..781955f5217d
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/cache_sram.txt
@@ -0,0 +1,20 @@
+* Freescale PQ3 and QorIQ based Cache SRAM
+
+Freescale's mpc85xx and some QorIQ platforms provide an
+option of configuring a part of (or full) cache memory
+as SRAM. This cache SRAM representation in the device
+tree should be done as under:-
+
+Required properties:
+
+- compatible : should be "fsl,p2020-cache-sram"
+- fsl,cache-sram-ctlr-handle : points to the L2 controller
+- reg : offset and length of the cache-sram.
+
+Example:
+
+cache-sram@fff00000 {
+ fsl,cache-sram-ctlr-handle = <&L2>;
+ reg = <0 0xfff00000 0 0x10000>;
+ compatible = "fsl,p2020-cache-sram";
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
index 71e39cf3215b..8aa10f45ebe6 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
@@ -1,42 +1,211 @@
-* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
-
-The OpenPIC specification does not specify which interrupt source has to
-become which interrupt number. This is up to the software implementation
-of the interrupt controller. The only requirement is that every
-interrupt source has to have an unique interrupt number / vector number.
-To accomplish this the current implementation assigns the number zero to
-the first source, the number one to the second source and so on until
-all interrupt sources have their unique number.
-Usually the assigned vector number equals the interrupt number mentioned
-in the documentation for a given core / CPU. This is however not true
-for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
-between internal and external interrupt sources and starts counting at
-zero for both of them.
-
-So what to write for external interrupt source X or internal interrupt
-source Y into the device tree? Here is an example:
-
-The memory map for the interrupt controller in the MPC8544[0] shows,
-that the first interrupt source starts at 0x5_0000 (PIC Register Address
-Map-Interrupt Source Configuration Registers). This source becomes the
-number zero therefore:
- External interrupt 0 = interrupt number 0
- External interrupt 1 = interrupt number 1
- External interrupt 2 = interrupt number 2
- ...
-Every interrupt number allocates 0x20 bytes register space. So to get
-its number it is sufficient to shift the lower 16bits to right by five.
-So for the external interrupt 10 we have:
- 0x0140 >> 5 = 10
-
-After the external sources, the internal sources follow. The in core I2C
-controller on the MPC8544 for instance has the internal source number
-27. Oo obtain its interrupt number we take the lower 16bits of its memory
-address (0x5_0560) and shift it right:
- 0x0560 >> 5 = 43
-
-Therefore the I2C device node for the MPC8544 CPU has to have the
-interrupt number 43 specified in the device tree.
-
-[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
- MPC8544ERM Rev. 1 10/2007
+=====================================================================
+Freescale MPIC Interrupt Controller Node
+Copyright (C) 2010,2011 Freescale Semiconductor Inc.
+=====================================================================
+
+The Freescale MPIC interrupt controller is found on all PowerQUICC
+and QorIQ processors and is compatible with the Open PIC. The
+notable difference from Open PIC binding is the addition of 2
+additional cells in the interrupt specifier defining interrupt type
+information.
+
+PROPERTIES
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Shall include "fsl,mpic". Freescale MPIC
+ controllers compatible with this binding have Block
+ Revision Registers BRR1 and BRR2 at offset 0x0 and
+ 0x10 in the MPIC.
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the physical
+ offset and length of the device's registers within the
+ CCSR address space.
+
+ - interrupt-controller
+ Usage: required
+ Value type: <empty>
+ Definition: Specifies that this node is an interrupt
+ controller
+
+ - #interrupt-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Shall be 2 or 4. A value of 2 means that interrupt
+ specifiers do not contain the interrupt-type or type-specific
+ information cells.
+
+ - #address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Shall be 0.
+
+ - pic-no-reset
+ Usage: optional
+ Value type: <empty>
+ Definition: The presence of this property specifies that the
+ MPIC must not be reset by the client program, and that
+ the boot program has initialized all interrupt source
+ configuration registers to a sane state-- masked or
+ directed at other cores. This ensures that the client
+ program will not receive interrupts for sources not belonging
+ to the client. The presence of this property also mandates
+ that any initialization related to interrupt sources shall
+ be limited to sources explicitly referenced in the device tree.
+
+INTERRUPT SPECIFIER DEFINITION
+
+ Interrupt specifiers consists of 4 cells encoded as
+ follows:
+
+ <1st-cell> interrupt-number
+
+ Identifies the interrupt source. The meaning
+ depends on the type of interrupt.
+
+ Note: If the interrupt-type cell is undefined
+ (i.e. #interrupt-cells = 2), this cell
+ should be interpreted the same as for
+ interrupt-type 0-- i.e. an external or
+ normal SoC device interrupt.
+
+ <2nd-cell> level-sense information, encoded as follows:
+ 0 = low-to-high edge triggered
+ 1 = active low level-sensitive
+ 2 = active high level-sensitive
+ 3 = high-to-low edge triggered
+
+ <3rd-cell> interrupt-type
+
+ The following types are supported:
+
+ 0 = external or normal SoC device interrupt
+
+ The interrupt-number cell contains
+ the SoC device interrupt number. The
+ type-specific cell is undefined. The
+ interrupt-number is derived from the
+ MPIC a block of registers referred to as
+ the "Interrupt Source Configuration Registers".
+ Each source has 32-bytes of registers
+ (vector/priority and destination) in this
+ region. So interrupt 0 is at offset 0x0,
+ interrupt 1 is at offset 0x20, and so on.
+
+ 1 = error interrupt
+
+ The interrupt-number cell contains
+ the SoC device interrupt number for
+ the error interrupt. The type-specific
+ cell identifies the specific error
+ interrupt number.
+
+ 2 = MPIC inter-processor interrupt (IPI)
+
+ The interrupt-number cell identifies
+ the MPIC IPI number. The type-specific
+ cell is undefined.
+
+ 3 = MPIC timer interrupt
+
+ The interrupt-number cell identifies
+ the MPIC timer number. The type-specific
+ cell is undefined.
+
+ <4th-cell> type-specific information
+
+ The type-specific cell is encoded as follows:
+
+ - For interrupt-type 1 (error interrupt),
+ the type-specific cell contains the
+ bit number of the error interrupt in the
+ Error Interrupt Summary Register.
+
+EXAMPLE 1
+ /*
+ * mpic interrupt controller with 4 cells per specifier
+ */
+ mpic: pic@40000 {
+ compatible = "fsl,mpic";
+ interrupt-controller;
+ #interrupt-cells = <4>;
+ #address-cells = <0>;
+ reg = <0x40000 0x40000>;
+ };
+
+EXAMPLE 2
+ /*
+ * The MPC8544 I2C controller node has an internal
+ * interrupt number of 27. As per the reference manual
+ * this corresponds to interrupt source configuration
+ * registers at 0x5_0560.
+ *
+ * The interrupt source configuration registers begin
+ * at 0x5_0000.
+ *
+ * To compute the interrupt specifier interrupt number
+ *
+ * 0x560 >> 5 = 43
+ *
+ * The interrupt source configuration registers begin
+ * at 0x5_0000, and so the i2c vector/priority registers
+ * are at 0x5_0560.
+ */
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+
+EXAMPLE 3
+ /*
+ * Definition of a node defining the 4
+ * MPIC IPI interrupts. Note the interrupt
+ * type of 2.
+ */
+ ipi@410a0 {
+ compatible = "fsl,mpic-ipi";
+ reg = <0x40040 0x10>;
+ interrupts = <0 0 2 0
+ 1 0 2 0
+ 2 0 2 0
+ 3 0 2 0>;
+ };
+
+EXAMPLE 4
+ /*
+ * Definition of a node defining the MPIC
+ * global timers. Note the interrupt
+ * type of 3.
+ */
+ timer0: timer@41100 {
+ compatible = "fsl,mpic-global-timer";
+ reg = <0x41100 0x100>;
+ interrupts = <0 0 3 0
+ 1 0 3 0
+ 2 0 3 0
+ 3 0 3 0>;
+ };
+
+EXAMPLE 5
+ /*
+ * Definition of an error interrupt (interupt type 1).
+ * SoC interrupt number is 16 and the specific error
+ * interrupt bit in the error interrupt summary register
+ * is 23.
+ */
+ memory-controller@8000 {
+ compatible = "fsl,p4080-memory-controller";
+ reg = <0x8000 0x1000>;
+ interrupts = <16 2 1 23>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
index bcc30bac6831..70558c3f3682 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
@@ -5,14 +5,21 @@ Required properties:
first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
the parent type.
+
- reg : should contain the address and the length of the shared message
interrupt register set.
+
- msi-available-ranges: use <start count> style section to define which
msi interrupt can be used in the 256 msi interrupts. This property is
optional, without this, all the 256 MSI interrupts can be used.
+ Each available range must begin and end on a multiple of 32 (i.e.
+ no splitting an individual MSI register or the associated PIC interrupt).
+
- interrupts : each one of the interrupts here is one entry per 32 MSIs,
and routed to the host interrupt controller. the interrupts should
- be set as edge sensitive.
+ be set as edge sensitive. If msi-available-ranges is present, only
+ the interrupts that correspond to available ranges shall be present.
+
- interrupt-parent: the phandle for the interrupt controller
that services interrupts for this device. for 83xx cpu, the interrupts
are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
index bc0b9cfe095b..983e14abe7e9 100644
--- a/Documentation/filesystems/nfs/pnfs.txt
+++ b/Documentation/filesystems/nfs/pnfs.txt
@@ -46,3 +46,10 @@ data server cache
file driver devices refer to data servers, which are kept in a module
level cache. Its reference is held over the lifetime of the deviceid
pointing to it.
+
+lseg
+----
+lseg maintains an extra reference corresponding to the NFS_LSEG_VALID
+bit which holds it in the pnfs_layout_hdr's list. When the final lseg
+is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
+bit is set, preventing any new lsegs from being added.
diff --git a/Documentation/filesystems/romfs.txt b/Documentation/filesystems/romfs.txt
index 2d2a7b2a16b9..e2b07cc9120a 100644
--- a/Documentation/filesystems/romfs.txt
+++ b/Documentation/filesystems/romfs.txt
@@ -17,8 +17,7 @@ comparison, an actual rescue disk used up 3202 blocks with ext2, while
with romfs, it needed 3079 blocks.
To create such a file system, you'll need a user program named
-genromfs. It is available via anonymous ftp on sunsite.unc.edu and
-its mirrors, in the /pub/Linux/system/recovery/ directory.
+genromfs. It is available on http://romfs.sourceforge.net/
As the name suggests, romfs could be also used (space-efficiently) on
various read-only media, like (E)EPROM disks if someone will have the
diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt
index 12fedb7834c6..d7b13b01e980 100644
--- a/Documentation/filesystems/ubifs.txt
+++ b/Documentation/filesystems/ubifs.txt
@@ -82,12 +82,12 @@ Mount options
bulk_read read more in one go to take advantage of flash
media that read faster sequentially
no_bulk_read (*) do not bulk-read
-no_chk_data_crc skip checking of CRCs on data nodes in order to
+no_chk_data_crc (*) skip checking of CRCs on data nodes in order to
improve read performance. Use this option only
if the flash media is highly reliable. The effect
of this option is that corruption of the contents
of a file can go unnoticed.
-chk_data_crc (*) do not skip checking CRCs on data nodes
+chk_data_crc do not skip checking CRCs on data nodes
compr=none override default compressor and set it to "none"
compr=lzo override default compressor and set it to "lzo"
compr=zlib override default compressor and set it to "zlib"
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index ef0714aa8e40..306f0ae8df09 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -873,7 +873,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool, bool);
+ int (*d_manage)(struct dentry *, bool);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -969,10 +969,6 @@ struct dentry_operations {
mounted on it and not to check the automount flag. Any other error
code will abort pathwalk completely.
- If the 'mounting_here' parameter is true, then namespace_sem is being
- held by the caller and the function should not initiate any mounts or
- unmounts that it will then wait for.
-
If the 'rcu_walk' parameter is true, then the caller is doing a
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
and the caller can be asked to leave it and call again by returing
diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg
index a7952c2bd959..4d0bc70f1852 100644
--- a/Documentation/hwmon/f71882fg
+++ b/Documentation/hwmon/f71882fg
@@ -10,6 +10,10 @@ Supported chips:
Prefix: 'f71862fg'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Available from the Fintek website
+ * Fintek F71869F and F71869E
+ Prefix: 'f71869'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Available from the Fintek website
* Fintek F71882FG and F71883FG
Prefix: 'f71882fg'
Addresses scanned: none, address read from Super I/O config space
@@ -17,6 +21,10 @@ Supported chips:
* Fintek F71889FG
Prefix: 'f71889fg'
Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Available from the Fintek website
+ * Fintek F71889ED
+ Prefix: 'f71889ed'
+ Addresses scanned: none, address read from Super I/O config space
Datasheet: Should become available on the Fintek website soon
* Fintek F8000
Prefix: 'f8000'
@@ -29,9 +37,9 @@ Author: Hans de Goede <hdegoede@redhat.com>
Description
-----------
-Fintek F718xxFG/F8000 Super I/O chips include complete hardware monitoring
-capabilities. They can monitor up to 9 voltages (3 for the F8000), 4 fans and
-3 temperature sensors.
+Fintek F718xx/F8000 Super I/O chips include complete hardware monitoring
+capabilities. They can monitor up to 9 voltages, 4 fans and 3 temperature
+sensors.
These chips also have fan controlling features, using either DC or PWM, in
three different modes (one manual, two automatic).
@@ -99,5 +107,5 @@ Writing an unsupported mode will result in an invalid parameter error.
The fan speed is regulated to keep the temp the fan is mapped to between
temp#_auto_point2_temp and temp#_auto_point3_temp.
-Both of the automatic modes require that pwm1 corresponds to fan1, pwm2 to
+All of the automatic modes require that pwm1 corresponds to fan1, pwm2 to
fan2 and pwm3 to fan3.
diff --git a/Documentation/hwmon/lineage-pem b/Documentation/hwmon/lineage-pem
new file mode 100644
index 000000000000..2ba5ed126858
--- /dev/null
+++ b/Documentation/hwmon/lineage-pem
@@ -0,0 +1,77 @@
+Kernel driver lineage-pem
+=========================
+
+Supported devices:
+ * Lineage Compact Power Line Power Entry Modules
+ Prefix: 'lineage-pem'
+ Addresses scanned: -
+ Documentation:
+ http://www.lineagepower.com/oem/pdf/CPLI2C.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports various Lineage Compact Power Line DC/DC and AC/DC
+converters such as CP1800, CP2000AC, CP2000DC, CP2100DC, and others.
+
+Lineage CPL power entry modules are nominally PMBus compliant. However, most
+standard PMBus commands are not supported. Specifically, all hardware monitoring
+and status reporting commands are non-standard. For this reason, a standard
+PMBus driver can not be used.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for Lineage CPL devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for a Lineage PEM at address 0x40
+on I2C bus #1:
+$ modprobe lineage-pem
+$ echo lineage-pem 0x40 > /sys/bus/i2c/devices/i2c-1/new_device
+
+All Lineage CPL power entry modules have a built-in I2C bus master selector
+(PCA9541). To ensure device access, this driver should only be used as client
+driver to the pca9541 I2C master selector driver.
+
+
+Sysfs entries
+-------------
+
+All Lineage CPL devices report output voltage and device temperature as well as
+alarms for output voltage, temperature, input voltage, input current, input power,
+and fan status.
+
+Input voltage, input current, input power, and fan speed measurement is only
+supported on newer devices. The driver detects if those attributes are supported,
+and only creates respective sysfs entries if they are.
+
+in1_input Output voltage (mV)
+in1_min_alarm Output undervoltage alarm
+in1_max_alarm Output overvoltage alarm
+in1_crit Output voltage critical alarm
+
+in2_input Input voltage (mV, optional)
+in2_alarm Input voltage alarm
+
+curr1_input Input current (mA, optional)
+curr1_alarm Input overcurrent alarm
+
+power1_input Input power (uW, optional)
+power1_alarm Input power alarm
+
+fan1_input Fan 1 speed (rpm, optional)
+fan2_input Fan 2 speed (rpm, optional)
+fan3_input Fan 3 speed (rpm, optional)
+
+temp1_input
+temp1_max
+temp1_crit
+temp1_alarm
+temp1_crit_alarm
+temp1_fault
diff --git a/Documentation/hwmon/lm85 b/Documentation/hwmon/lm85
index 239258a63c81..7c49feaa79d2 100644
--- a/Documentation/hwmon/lm85
+++ b/Documentation/hwmon/lm85
@@ -26,6 +26,14 @@ Supported chips:
Prefix: 'emc6d102'
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
Datasheet: http://www.smsc.com/main/catalog/emc6d102.html
+ * SMSC EMC6D103
+ Prefix: 'emc6d103'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.smsc.com/main/catalog/emc6d103.html
+ * SMSC EMC6D103S
+ Prefix: 'emc6d103s'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: http://www.smsc.com/main/catalog/emc6d103s.html
Authors:
Philip Pokorny <ppokorny@penguincomputing.com>,
@@ -122,9 +130,11 @@ to be register compatible. The EMC6D100 offers all the features of the
EMC6D101 plus additional voltage monitoring and system control features.
Unfortunately it is not possible to distinguish between the package
versions on register level so these additional voltage inputs may read
-zero. The EMC6D102 features addtional ADC bits thus extending precision
+zero. EMC6D102 and EMC6D103 feature additional ADC bits thus extending precision
of voltage and temperature channels.
+SMSC EMC6D103S is similar to EMC6D103, but does not support pwm#_auto_pwm_minctl
+and temp#_auto_temp_off.
Hardware Configurations
-----------------------
diff --git a/Documentation/hwmon/ltc4151 b/Documentation/hwmon/ltc4151
new file mode 100644
index 000000000000..43c667e6677a
--- /dev/null
+++ b/Documentation/hwmon/ltc4151
@@ -0,0 +1,47 @@
+Kernel driver ltc4151
+=====================
+
+Supported chips:
+ * Linear Technology LTC4151
+ Prefix: 'ltc4151'
+ Addresses scanned: -
+ Datasheet:
+ http://www.linear.com/docs/Datasheet/4151fc.pdf
+
+Author: Per Dalen <per.dalen@appeartv.com>
+
+
+Description
+-----------
+
+The LTC4151 is a High Voltage I2C Current and Voltage Monitor.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4151 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4151 at address 0x6f
+on I2C bus #0:
+# modprobe ltc4151
+# echo ltc4151 0x6f > /sys/bus/i2c/devices/i2c-0/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADIN
+and VIN registers.
+
+Current reading provided by this driver is reported as obtained from the Current
+Sense register. The reported value assumes that a 1 mOhm sense resistor is
+installed.
+
+in1_input VDIN voltage (mV)
+
+in2_input ADIN voltage (mV)
+
+curr1_input SENSE current (mA)
diff --git a/Documentation/hwmon/max6639 b/Documentation/hwmon/max6639
new file mode 100644
index 000000000000..dc49f8be7167
--- /dev/null
+++ b/Documentation/hwmon/max6639
@@ -0,0 +1,49 @@
+Kernel driver max6639
+=====================
+
+Supported chips:
+ * Maxim MAX6639
+ Prefix: 'max6639'
+ Addresses scanned: I2C 0x2c, 0x2e, 0x2f
+ Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6639.pdf
+
+Authors:
+ He Changqing <hechangqing@semptian.com>
+ Roland Stigge <stigge@antcom.de>
+
+Description
+-----------
+
+This driver implements support for the Maxim MAX6639. This chip is a 2-channel
+temperature monitor with dual PWM fan speed controller. It can monitor its own
+temperature and one external diode-connected transistor or two external
+diode-connected transistors.
+
+The following device attributes are implemented via sysfs:
+
+Attribute R/W Contents
+----------------------------------------------------------------------------
+temp1_input R Temperature channel 1 input (0..150 C)
+temp2_input R Temperature channel 2 input (0..150 C)
+temp1_fault R Temperature channel 1 diode fault
+temp2_fault R Temperature channel 2 diode fault
+temp1_max RW Set THERM temperature for input 1
+ (in C, see datasheet)
+temp2_max RW Set THERM temperature for input 2
+temp1_crit RW Set ALERT temperature for input 1
+temp2_crit RW Set ALERT temperature for input 2
+temp1_emergency RW Set OT temperature for input 1
+ (in C, see datasheet)
+temp2_emergency RW Set OT temperature for input 2
+pwm1 RW Fan 1 target duty cycle (0..255)
+pwm2 RW Fan 2 target duty cycle (0..255)
+fan1_input R TACH1 fan tachometer input (in RPM)
+fan2_input R TACH2 fan tachometer input (in RPM)
+fan1_fault R Fan 1 fault
+fan2_fault R Fan 2 fault
+temp1_max_alarm R Alarm on THERM temperature on channel 1
+temp2_max_alarm R Alarm on THERM temperature on channel 2
+temp1_crit_alarm R Alarm on ALERT temperature on channel 1
+temp2_crit_alarm R Alarm on ALERT temperature on channel 2
+temp1_emergency_alarm R Alarm on OT temperature on channel 1
+temp2_emergency_alarm R Alarm on OT temperature on channel 2
diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus
new file mode 100644
index 000000000000..f2d42e8bdf48
--- /dev/null
+++ b/Documentation/hwmon/pmbus
@@ -0,0 +1,215 @@
+Kernel driver pmbus
+====================
+
+Supported chips:
+ * Ericsson BMR45X series
+ DC/DC Converter
+ Prefixes: 'bmr450', 'bmr451', 'bmr453', 'bmr454'
+ Addresses scanned: -
+ Datasheet:
+ http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395
+ * Linear Technology LTC2978
+ Octal PMBus Power Supply Monitor and Controller
+ Prefix: 'ltc2978'
+ Addresses scanned: -
+ Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
+ * Maxim MAX16064
+ Quad Power-Supply Controller
+ Prefix: 'max16064'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf
+ * Maxim MAX34440
+ PMBus 6-Channel Power-Supply Manager
+ Prefixes: 'max34440'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34440.pdf
+ * Maxim MAX34441
+ PMBus 5-Channel Power-Supply Manager and Intelligent Fan Controller
+ Prefixes: 'max34441'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX34441.pdf
+ * Maxim MAX8688
+ Digital Power-Supply Controller/Monitor
+ Prefix: 'max8688'
+ Addresses scanned: -
+ Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf
+ * Generic PMBus devices
+ Prefix: 'pmbus'
+ Addresses scanned: -
+ Datasheet: n.a.
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for various PMBus compliant devices.
+It supports voltage, current, power, and temperature sensors as supported
+by the device.
+
+Each monitored channel has its own high and low limits, plus a critical
+limit.
+
+Fan support will be added in a later version of this driver.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices, since there is no register
+which can be safely used to identify the chip (The MFG_ID register is not
+supported by all chips), and since there is no well defined address range for
+PMBus devices. You will have to instantiate the devices explicitly.
+
+Example: the following will load the driver for an LTC2978 at address 0x60
+on I2C bus #1:
+$ modprobe pmbus
+$ echo ltc2978 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Platform data support
+---------------------
+
+Support for additional PMBus chips can be added by defining chip parameters in
+a new chip specific driver file. For example, (untested) code to add support for
+Emerson DS1200 power modules might look as follows.
+
+static struct pmbus_driver_info ds1200_info = {
+ .pages = 1,
+ /* Note: All other sensors are in linear mode */
+ .direct[PSC_VOLTAGE_OUT] = true,
+ .direct[PSC_TEMPERATURE] = true,
+ .direct[PSC_CURRENT_OUT] = true,
+ .m[PSC_VOLTAGE_IN] = 1,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = 3,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 3,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+ | PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
+};
+
+static int ds1200_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &ds1200_info);
+}
+
+static int ds1200_remove(struct i2c_client *client)
+{
+ return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id ds1200_id[] = {
+ {"ds1200", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ds1200_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds1200_driver = {
+ .driver = {
+ .name = "ds1200",
+ },
+ .probe = ds1200_probe,
+ .remove = ds1200_remove,
+ .id_table = ds1200_id,
+};
+
+static int __init ds1200_init(void)
+{
+ return i2c_add_driver(&ds1200_driver);
+}
+
+static void __exit ds1200_exit(void)
+{
+ i2c_del_driver(&ds1200_driver);
+}
+
+
+Sysfs entries
+-------------
+
+When probing the chip, the driver identifies which PMBus registers are
+supported, and determines available sensors from this information.
+Attribute files only exist if respective sensors are suported by the chip.
+Labels are provided to inform the user about the sensor associated with
+a given sysfs entry.
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+inX_input Measured voltage. From READ_VIN or READ_VOUT register.
+inX_min Minumum Voltage.
+ From VIN_UV_WARN_LIMIT or VOUT_UV_WARN_LIMIT register.
+inX_max Maximum voltage.
+ From VIN_OV_WARN_LIMIT or VOUT_OV_WARN_LIMIT register.
+inX_lcrit Critical minumum Voltage.
+ From VIN_UV_FAULT_LIMIT or VOUT_UV_FAULT_LIMIT register.
+inX_crit Critical maximum voltage.
+ From VIN_OV_FAULT_LIMIT or VOUT_OV_FAULT_LIMIT register.
+inX_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
+inX_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
+inX_lcrit_alarm Voltage critical low alarm.
+ From VOLTAGE_UV_FAULT status.
+inX_crit_alarm Voltage critical high alarm.
+ From VOLTAGE_OV_FAULT status.
+inX_label "vin", "vcap", or "voutY"
+
+currX_input Measured current. From READ_IIN or READ_IOUT register.
+currX_max Maximum current.
+ From IIN_OC_WARN_LIMIT or IOUT_OC_WARN_LIMIT register.
+currX_lcrit Critical minumum output current.
+ From IOUT_UC_FAULT_LIMIT register.
+currX_crit Critical maximum current.
+ From IIN_OC_FAULT_LIMIT or IOUT_OC_FAULT_LIMIT register.
+currX_alarm Current high alarm.
+ From IIN_OC_WARNING or IOUT_OC_WARNING status.
+currX_lcrit_alarm Output current critical low alarm.
+ From IOUT_UC_FAULT status.
+currX_crit_alarm Current critical high alarm.
+ From IIN_OC_FAULT or IOUT_OC_FAULT status.
+currX_label "iin" or "vinY"
+
+powerX_input Measured power. From READ_PIN or READ_POUT register.
+powerX_cap Output power cap. From POUT_MAX register.
+powerX_max Power limit. From PIN_OP_WARN_LIMIT or
+ POUT_OP_WARN_LIMIT register.
+powerX_crit Critical output power limit.
+ From POUT_OP_FAULT_LIMIT register.
+powerX_alarm Power high alarm.
+ From PIN_OP_WARNING or POUT_OP_WARNING status.
+powerX_crit_alarm Output power critical high alarm.
+ From POUT_OP_FAULT status.
+powerX_label "pin" or "poutY"
+
+tempX_input Measured tempererature.
+ From READ_TEMPERATURE_X register.
+tempX_min Mimimum tempererature. From UT_WARN_LIMIT register.
+tempX_max Maximum tempererature. From OT_WARN_LIMIT register.
+tempX_lcrit Critical low tempererature.
+ From UT_FAULT_LIMIT register.
+tempX_crit Critical high tempererature.
+ From OT_FAULT_LIMIT register.
+tempX_min_alarm Chip temperature low alarm. Set by comparing
+ READ_TEMPERATURE_X with UT_WARN_LIMIT if
+ TEMP_UT_WARNING status is set.
+tempX_max_alarm Chip temperature high alarm. Set by comparing
+ READ_TEMPERATURE_X with OT_WARN_LIMIT if
+ TEMP_OT_WARNING status is set.
+tempX_lcrit_alarm Chip temperature critical low alarm. Set by comparing
+ READ_TEMPERATURE_X with UT_FAULT_LIMIT if
+ TEMP_UT_FAULT status is set.
+tempX_crit_alarm Chip temperature critical high alarm. Set by comparing
+ READ_TEMPERATURE_X with OT_FAULT_LIMIT if
+ TEMP_OT_FAULT status is set.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index c6559f153589..83a698773ade 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -187,6 +187,17 @@ fan[1-*]_div Fan divisor.
Note that this is actually an internal clock divisor, which
affects the measurable speed range, not the read value.
+fan[1-*]_pulses Number of tachometer pulses per fan revolution.
+ Integer value, typically between 1 and 4.
+ RW
+ This value is a characteristic of the fan connected to the
+ device's input, so it has to be set in accordance with the fan
+ model.
+ Should only be created if the chip has a register to configure
+ the number of pulses. In the absence of such a register (and
+ thus attribute) the value assumed by all devices is 2 pulses
+ per fan revolution.
+
fan[1-*]_target
Desired fan speed
Unit: revolution/min (RPM)
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 13d556112fc0..76ffef94ed75 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -5,13 +5,11 @@ Supported chips:
* Winbond W83627EHF/EHG (ISA access ONLY)
Prefix: 'w83627ehf'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet:
- http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf
+ Datasheet: not available
* Winbond W83627DHG
Prefix: 'w83627dhg'
Addresses scanned: ISA address retrieved from Super I/O registers
- Datasheet:
- http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+ Datasheet: not available
* Winbond W83627DHG-P
Prefix: 'w83627dhg'
Addresses scanned: ISA address retrieved from Super I/O registers
@@ -24,6 +22,14 @@ Supported chips:
Prefix: 'w83667hg'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT6775F/W83667HG-I
+ Prefix: 'nct6775'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT6776F
+ Prefix: 'nct6776'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
Authors:
Jean Delvare <khali@linux-fr.org>
@@ -36,19 +42,28 @@ Description
-----------
This driver implements support for the Winbond W83627EHF, W83627EHG,
-W83627DHG, W83627DHG-P, W83667HG and W83667HG-B super I/O chips.
-We will refer to them collectively as Winbond chips.
-
-The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
-VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms
-with beep warnings (control unimplemented), and some automatic fan
-regulation strategies (plus manual fan control mode).
+W83627DHG, W83627DHG-P, W83667HG, W83667HG-B, W83667HG-I (NCT6775F),
+and NCT6776F super I/O chips. We will refer to them collectively as
+Winbond chips.
+
+The chips implement three temperature sensors (up to four for 667HG-B, and nine
+for NCT6775F and NCT6776F), five fan rotation speed sensors, ten analog voltage
+sensors (only nine for the 627DHG), one VID (6 pins for the 627EHF/EHG, 8 pins
+for the 627DHG and 667HG), alarms with beep warnings (control unimplemented),
+and some automatic fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on W82677HG-B, NCT6775F, and NCT6776F are
+configurable. temp4 and higher attributes are only reported if its temperature
+source differs from the temperature sources of the already reported temperature
+sensors. The configured source for each of the temperature sensors is provided
+in tempX_label.
Temperatures are measured in degrees Celsius and measurement resolution is 1
-degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
-the temperature gets higher than high limit; it stays on until the temperature
-falls below the hysteresis value.
+degC for temp1 and and 0.5 degC for temp2 and temp3. For temp4 and higher,
+resolution is 1 degC for W83667HG-B and 0.0 degC for NCT6775F and NCT6776F.
+An alarm is triggered when the temperature gets higher than high limit;
+it stays on until the temperature falls below the hysteresis value.
+Alarms are only supported for temp1, temp2, and temp3.
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
triggered if the rotation speed has dropped below a programmable limit. Fan
@@ -80,7 +95,8 @@ prog -> pwm4 (not on 667HG and 667HG-B; the programmable setting is not
name - this is a standard hwmon device entry. For the W83627EHF and W83627EHG,
it is set to "w83627ehf", for the W83627DHG it is set to "w83627dhg",
- and for the W83667HG it is set to "w83667hg".
+ for the W83667HG and W83667HG-B it is set to "w83667hg", for NCT6775F it
+ is set to "nct6775", and for NCT6776F it is set to "nct6776".
pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
0 (stop) to 255 (full)
@@ -90,6 +106,18 @@ pwm[1-4]_enable - this file controls mode of fan/temperature control:
* 2 "Thermal Cruise" mode
* 3 "Fan Speed Cruise" mode
* 4 "Smart Fan III" mode
+ * 5 "Smart Fan IV" mode
+
+ SmartFan III mode is not supported on NCT6776F.
+
+ SmartFan IV mode is configurable only if it was configured at system
+ startup, and is only supported for W83677HG-B, NCT6775F, and NCT6776F.
+ SmartFan IV operational parameters can not be configured at this time,
+ and the various pwm attributes are not used in SmartFan IV mode.
+ The attributes can be written to, which is useful if you plan to
+ configure the system for a different pwm mode. However, the information
+ returned when reading pwm attributes is unrelated to SmartFan IV
+ operation.
pwm[1-4]_mode - controls if output is PWM or DC level
* 0 DC output (0 - 12v)
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
new file mode 100644
index 000000000000..7dcd1a4e726c
--- /dev/null
+++ b/Documentation/hwspinlock.txt
@@ -0,0 +1,293 @@
+Hardware Spinlock Framework
+
+1. Introduction
+
+Hardware spinlock modules provide hardware assistance for synchronization
+and mutual exclusion between heterogeneous processors and those not operating
+under a single, shared operating system.
+
+For example, OMAP4 has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP,
+each of which is running a different Operating System (the master, A9,
+is usually running Linux and the slave processors, the M3 and the DSP,
+are running some flavor of RTOS).
+
+A generic hwspinlock framework allows platform-independent drivers to use
+the hwspinlock device in order to access data structures that are shared
+between remote processors, that otherwise have no alternative mechanism
+to accomplish synchronization and mutual exclusion operations.
+
+This is necessary, for example, for Inter-processor communications:
+on OMAP4, cpu-intensive multimedia tasks are offloaded by the host to the
+remote M3 and/or C64x+ slave processors (by an IPC subsystem called Syslink).
+
+To achieve fast message-based communications, a minimal kernel support
+is needed to deliver messages arriving from a remote processor to the
+appropriate user process.
+
+This communication is based on simple data structures that is shared between
+the remote processors, and access to it is synchronized using the hwspinlock
+module (remote processor directly places new messages in this shared data
+structure).
+
+A common hwspinlock interface makes it possible to have generic, platform-
+independent, drivers.
+
+2. User API
+
+ struct hwspinlock *hwspin_lock_request(void);
+ - dynamically assign an hwspinlock and return its address, or NULL
+ in case an unused hwspinlock isn't available. Users of this
+ API will usually want to communicate the lock's id to the remote core
+ before it can be used to achieve synchronization.
+ Can be called from an atomic context (this function will not sleep) but
+ not from within interrupt context.
+
+ struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
+ - assign a specific hwspinlock id and return its address, or NULL
+ if that hwspinlock is already in use. Usually board code will
+ be calling this function in order to reserve specific hwspinlock
+ ids for predefined purposes.
+ Can be called from an atomic context (this function will not sleep) but
+ not from within interrupt context.
+
+ int hwspin_lock_free(struct hwspinlock *hwlock);
+ - free a previously-assigned hwspinlock; returns 0 on success, or an
+ appropriate error code on failure (e.g. -EINVAL if the hwspinlock
+ is already free).
+ Can be called from an atomic context (this function will not sleep) but
+ not from within interrupt context.
+
+ int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);
+ - lock a previously-assigned hwspinlock with a timeout limit (specified in
+ msecs). If the hwspinlock is already taken, the function will busy loop
+ waiting for it to be released, but give up when the timeout elapses.
+ Upon a successful return from this function, preemption is disabled so
+ the caller must not sleep, and is advised to release the hwspinlock as
+ soon as possible, in order to minimize remote cores polling on the
+ hardware interconnect.
+ Returns 0 when successful and an appropriate error code otherwise (most
+ notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+ The function will never sleep.
+
+ int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int timeout);
+ - lock a previously-assigned hwspinlock with a timeout limit (specified in
+ msecs). If the hwspinlock is already taken, the function will busy loop
+ waiting for it to be released, but give up when the timeout elapses.
+ Upon a successful return from this function, preemption and the local
+ interrupts are disabled, so the caller must not sleep, and is advised to
+ release the hwspinlock as soon as possible.
+ Returns 0 when successful and an appropriate error code otherwise (most
+ notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+ The function will never sleep.
+
+ int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to,
+ unsigned long *flags);
+ - lock a previously-assigned hwspinlock with a timeout limit (specified in
+ msecs). If the hwspinlock is already taken, the function will busy loop
+ waiting for it to be released, but give up when the timeout elapses.
+ Upon a successful return from this function, preemption is disabled,
+ local interrupts are disabled and their previous state is saved at the
+ given flags placeholder. The caller must not sleep, and is advised to
+ release the hwspinlock as soon as possible.
+ Returns 0 when successful and an appropriate error code otherwise (most
+ notably -ETIMEDOUT if the hwspinlock is still busy after timeout msecs).
+ The function will never sleep.
+
+ int hwspin_trylock(struct hwspinlock *hwlock);
+ - attempt to lock a previously-assigned hwspinlock, but immediately fail if
+ it is already taken.
+ Upon a successful return from this function, preemption is disabled so
+ caller must not sleep, and is advised to release the hwspinlock as soon as
+ possible, in order to minimize remote cores polling on the hardware
+ interconnect.
+ Returns 0 on success and an appropriate error code otherwise (most
+ notably -EBUSY if the hwspinlock was already taken).
+ The function will never sleep.
+
+ int hwspin_trylock_irq(struct hwspinlock *hwlock);
+ - attempt to lock a previously-assigned hwspinlock, but immediately fail if
+ it is already taken.
+ Upon a successful return from this function, preemption and the local
+ interrupts are disabled so caller must not sleep, and is advised to
+ release the hwspinlock as soon as possible.
+ Returns 0 on success and an appropriate error code otherwise (most
+ notably -EBUSY if the hwspinlock was already taken).
+ The function will never sleep.
+
+ int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags);
+ - attempt to lock a previously-assigned hwspinlock, but immediately fail if
+ it is already taken.
+ Upon a successful return from this function, preemption is disabled,
+ the local interrupts are disabled and their previous state is saved
+ at the given flags placeholder. The caller must not sleep, and is advised
+ to release the hwspinlock as soon as possible.
+ Returns 0 on success and an appropriate error code otherwise (most
+ notably -EBUSY if the hwspinlock was already taken).
+ The function will never sleep.
+
+ void hwspin_unlock(struct hwspinlock *hwlock);
+ - unlock a previously-locked hwspinlock. Always succeed, and can be called
+ from any context (the function never sleeps). Note: code should _never_
+ unlock an hwspinlock which is already unlocked (there is no protection
+ against this).
+
+ void hwspin_unlock_irq(struct hwspinlock *hwlock);
+ - unlock a previously-locked hwspinlock and enable local interrupts.
+ The caller should _never_ unlock an hwspinlock which is already unlocked.
+ Doing so is considered a bug (there is no protection against this).
+ Upon a successful return from this function, preemption and local
+ interrupts are enabled. This function will never sleep.
+
+ void
+ hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags);
+ - unlock a previously-locked hwspinlock.
+ The caller should _never_ unlock an hwspinlock which is already unlocked.
+ Doing so is considered a bug (there is no protection against this).
+ Upon a successful return from this function, preemption is reenabled,
+ and the state of the local interrupts is restored to the state saved at
+ the given flags. This function will never sleep.
+
+ int hwspin_lock_get_id(struct hwspinlock *hwlock);
+ - retrieve id number of a given hwspinlock. This is needed when an
+ hwspinlock is dynamically assigned: before it can be used to achieve
+ mutual exclusion with a remote cpu, the id number should be communicated
+ to the remote task with which we want to synchronize.
+ Returns the hwspinlock id number, or -EINVAL if hwlock is null.
+
+3. Typical usage
+
+#include <linux/hwspinlock.h>
+#include <linux/err.h>
+
+int hwspinlock_example1(void)
+{
+ struct hwspinlock *hwlock;
+ int ret;
+
+ /* dynamically assign a hwspinlock */
+ hwlock = hwspin_lock_request();
+ if (!hwlock)
+ ...
+
+ id = hwspin_lock_get_id(hwlock);
+ /* probably need to communicate id to a remote processor now */
+
+ /* take the lock, spin for 1 sec if it's already taken */
+ ret = hwspin_lock_timeout(hwlock, 1000);
+ if (ret)
+ ...
+
+ /*
+ * we took the lock, do our thing now, but do NOT sleep
+ */
+
+ /* release the lock */
+ hwspin_unlock(hwlock);
+
+ /* free the lock */
+ ret = hwspin_lock_free(hwlock);
+ if (ret)
+ ...
+
+ return ret;
+}
+
+int hwspinlock_example2(void)
+{
+ struct hwspinlock *hwlock;
+ int ret;
+
+ /*
+ * assign a specific hwspinlock id - this should be called early
+ * by board init code.
+ */
+ hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
+ if (!hwlock)
+ ...
+
+ /* try to take it, but don't spin on it */
+ ret = hwspin_trylock(hwlock);
+ if (!ret) {
+ pr_info("lock is already taken\n");
+ return -EBUSY;
+ }
+
+ /*
+ * we took the lock, do our thing now, but do NOT sleep
+ */
+
+ /* release the lock */
+ hwspin_unlock(hwlock);
+
+ /* free the lock */
+ ret = hwspin_lock_free(hwlock);
+ if (ret)
+ ...
+
+ return ret;
+}
+
+
+4. API for implementors
+
+ int hwspin_lock_register(struct hwspinlock *hwlock);
+ - to be called from the underlying platform-specific implementation, in
+ order to register a new hwspinlock instance. Can be called from an atomic
+ context (this function will not sleep) but not from within interrupt
+ context. Returns 0 on success, or appropriate error code on failure.
+
+ struct hwspinlock *hwspin_lock_unregister(unsigned int id);
+ - to be called from the underlying vendor-specific implementation, in order
+ to unregister an existing (and unused) hwspinlock instance.
+ Can be called from an atomic context (will not sleep) but not from
+ within interrupt context.
+ Returns the address of hwspinlock on success, or NULL on error (e.g.
+ if the hwspinlock is sill in use).
+
+5. struct hwspinlock
+
+This struct represents an hwspinlock instance. It is registered by the
+underlying hwspinlock implementation using the hwspin_lock_register() API.
+
+/**
+ * struct hwspinlock - vendor-specific hwspinlock implementation
+ *
+ * @dev: underlying device, will be used with runtime PM api
+ * @ops: vendor-specific hwspinlock handlers
+ * @id: a global, unique, system-wide, index of the lock.
+ * @lock: initialized and used by hwspinlock core
+ * @owner: underlying implementation module, used to maintain module ref count
+ */
+struct hwspinlock {
+ struct device *dev;
+ const struct hwspinlock_ops *ops;
+ int id;
+ spinlock_t lock;
+ struct module *owner;
+};
+
+The underlying implementation is responsible to assign the dev, ops, id and
+owner members. The lock member, OTOH, is initialized and used by the hwspinlock
+core.
+
+6. Implementation callbacks
+
+There are three possible callbacks defined in 'struct hwspinlock_ops':
+
+struct hwspinlock_ops {
+ int (*trylock)(struct hwspinlock *lock);
+ void (*unlock)(struct hwspinlock *lock);
+ void (*relax)(struct hwspinlock *lock);
+};
+
+The first two callbacks are mandatory:
+
+The ->trylock() callback should make a single attempt to take the lock, and
+return 0 on failure and 1 on success. This callback may _not_ sleep.
+
+The ->unlock() callback releases the lock. It always succeed, and it, too,
+may _not_ sleep.
+
+The ->relax() callback is optional. It is called by hwspinlock core while
+spinning on a lock, and can be used by the underlying implementation to force
+a delay between two successive invocations of ->trylock(). It may _not_ sleep.
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index ac293e955308..e68543f767d5 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -133,6 +133,7 @@ Code Seq#(hex) Include File Comments
'H' C0-DF net/bluetooth/hidp/hidp.h conflict!
'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict!
'H' C0-DF net/bluetooth/bnep/bnep.h conflict!
+'H' F1 linux/hid-roccat.h <mailto:erazor_de@users.sourceforge.net>
'I' all linux/isdn.h conflict!
'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict!
'I' 40-4F linux/mISDNif.h conflict!
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 4a990317b84a..8f63b224ab09 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -146,7 +146,7 @@ INSTALL_MOD_STRIP
INSTALL_MOD_STRIP, if defined, will cause modules to be
stripped after they are installed. If INSTALL_MOD_STRIP is '1', then
the default option --strip-debug will be used. Otherwise,
-INSTALL_MOD_STRIP will used as the options to the strip command.
+INSTALL_MOD_STRIP value will be used as the options to the strip command.
INSTALL_FW_PATH
--------------------------------------------------
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 86e3cd0d26a0..5d145bb443c0 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -1325,7 +1325,8 @@ The top Makefile exports the following variables:
If this variable is specified, will cause modules to be stripped
after they are installed. If INSTALL_MOD_STRIP is '1', then the
default option --strip-debug will be used. Otherwise,
- INSTALL_MOD_STRIP will used as the option(s) to the strip command.
+ INSTALL_MOD_STRIP value will be used as the option(s) to the strip
+ command.
=== 9 Makefile language
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 738c6fda3fb0..d18a9e12152a 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -626,6 +626,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
disable= [IPV6]
See Documentation/networking/ipv6.txt.
+ disable_ddw [PPC/PSERIES]
+ Disable Dynamic DMA Window support. Use this if
+ to workaround buggy firmware.
+
disable_ipv6= [IPV6]
See Documentation/networking/ipv6.txt.
@@ -1580,6 +1584,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
of returning the full 64-bit number.
The default is to return 64-bit inode numbers.
+ nfs.nfs4_disable_idmapping=
+ [NFSv4] When set, this option disables the NFSv4
+ idmapper on the client, but only if the mount
+ is using the 'sec=sys' security flavour. This may
+ make migration from legacy NFSv2/v3 systems easier
+ provided that the server has the appropriate support.
+ The default is to always enable NFSv4 idmapping.
+
nmi_debug= [KNL,AVR32,SH] Specify one or more actions to take
when a NMI is triggered.
Format: [state][,regs][,debounce][,die]
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index ad85797c1cf0..9bef4e4cec50 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -166,7 +166,7 @@ Returns: 0 on success, -1 on error
This ioctl is obsolete and has been removed.
-4.6 KVM_CREATE_VCPU
+4.7 KVM_CREATE_VCPU
Capability: basic
Architectures: all
@@ -177,7 +177,7 @@ Returns: vcpu fd on success, -1 on error
This API adds a vcpu to a virtual machine. The vcpu id is a small integer
in the range [0, max_vcpus).
-4.7 KVM_GET_DIRTY_LOG (vm ioctl)
+4.8 KVM_GET_DIRTY_LOG (vm ioctl)
Capability: basic
Architectures: x86
@@ -200,7 +200,7 @@ since the last call to this ioctl. Bit 0 is the first page in the
memory slot. Ensure the entire structure is cleared to avoid padding
issues.
-4.8 KVM_SET_MEMORY_ALIAS
+4.9 KVM_SET_MEMORY_ALIAS
Capability: basic
Architectures: x86
@@ -210,7 +210,7 @@ Returns: 0 (success), -1 (error)
This ioctl is obsolete and has been removed.
-4.9 KVM_RUN
+4.10 KVM_RUN
Capability: basic
Architectures: all
@@ -226,7 +226,7 @@ obtained by mmap()ing the vcpu fd at offset 0, with the size given by
KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct
kvm_run' (see below).
-4.10 KVM_GET_REGS
+4.11 KVM_GET_REGS
Capability: basic
Architectures: all
@@ -246,7 +246,7 @@ struct kvm_regs {
__u64 rip, rflags;
};
-4.11 KVM_SET_REGS
+4.12 KVM_SET_REGS
Capability: basic
Architectures: all
@@ -258,7 +258,7 @@ Writes the general purpose registers into the vcpu.
See KVM_GET_REGS for the data structure.
-4.12 KVM_GET_SREGS
+4.13 KVM_GET_SREGS
Capability: basic
Architectures: x86
@@ -283,7 +283,7 @@ interrupt_bitmap is a bitmap of pending external interrupts. At most
one bit may be set. This interrupt has been acknowledged by the APIC
but not yet injected into the cpu core.
-4.13 KVM_SET_SREGS
+4.14 KVM_SET_SREGS
Capability: basic
Architectures: x86
@@ -294,7 +294,7 @@ Returns: 0 on success, -1 on error
Writes special registers into the vcpu. See KVM_GET_SREGS for the
data structures.
-4.14 KVM_TRANSLATE
+4.15 KVM_TRANSLATE
Capability: basic
Architectures: x86
@@ -317,7 +317,7 @@ struct kvm_translation {
__u8 pad[5];
};
-4.15 KVM_INTERRUPT
+4.16 KVM_INTERRUPT
Capability: basic
Architectures: x86, ppc
@@ -365,7 +365,7 @@ c) KVM_INTERRUPT_SET_LEVEL
Note that any value for 'irq' other than the ones stated above is invalid
and incurs unexpected behavior.
-4.16 KVM_DEBUG_GUEST
+4.17 KVM_DEBUG_GUEST
Capability: basic
Architectures: none
@@ -375,7 +375,7 @@ Returns: -1 on error
Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
-4.17 KVM_GET_MSRS
+4.18 KVM_GET_MSRS
Capability: basic
Architectures: x86
@@ -403,7 +403,7 @@ Application code should set the 'nmsrs' member (which indicates the
size of the entries array) and the 'index' member of each array entry.
kvm will fill in the 'data' member.
-4.18 KVM_SET_MSRS
+4.19 KVM_SET_MSRS
Capability: basic
Architectures: x86
@@ -418,7 +418,7 @@ Application code should set the 'nmsrs' member (which indicates the
size of the entries array), and the 'index' and 'data' members of each
array entry.
-4.19 KVM_SET_CPUID
+4.20 KVM_SET_CPUID
Capability: basic
Architectures: x86
@@ -446,7 +446,7 @@ struct kvm_cpuid {
struct kvm_cpuid_entry entries[0];
};
-4.20 KVM_SET_SIGNAL_MASK
+4.21 KVM_SET_SIGNAL_MASK
Capability: basic
Architectures: x86
@@ -468,7 +468,7 @@ struct kvm_signal_mask {
__u8 sigset[0];
};
-4.21 KVM_GET_FPU
+4.22 KVM_GET_FPU
Capability: basic
Architectures: x86
@@ -493,7 +493,7 @@ struct kvm_fpu {
__u32 pad2;
};
-4.22 KVM_SET_FPU
+4.23 KVM_SET_FPU
Capability: basic
Architectures: x86
@@ -518,7 +518,7 @@ struct kvm_fpu {
__u32 pad2;
};
-4.23 KVM_CREATE_IRQCHIP
+4.24 KVM_CREATE_IRQCHIP
Capability: KVM_CAP_IRQCHIP
Architectures: x86, ia64
@@ -531,7 +531,7 @@ ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
only go to the IOAPIC. On ia64, a IOSAPIC is created.
-4.24 KVM_IRQ_LINE
+4.25 KVM_IRQ_LINE
Capability: KVM_CAP_IRQCHIP
Architectures: x86, ia64
@@ -552,7 +552,7 @@ struct kvm_irq_level {
__u32 level; /* 0 or 1 */
};
-4.25 KVM_GET_IRQCHIP
+4.26 KVM_GET_IRQCHIP
Capability: KVM_CAP_IRQCHIP
Architectures: x86, ia64
@@ -573,7 +573,7 @@ struct kvm_irqchip {
} chip;
};
-4.26 KVM_SET_IRQCHIP
+4.27 KVM_SET_IRQCHIP
Capability: KVM_CAP_IRQCHIP
Architectures: x86, ia64
@@ -594,7 +594,7 @@ struct kvm_irqchip {
} chip;
};
-4.27 KVM_XEN_HVM_CONFIG
+4.28 KVM_XEN_HVM_CONFIG
Capability: KVM_CAP_XEN_HVM
Architectures: x86
@@ -618,7 +618,7 @@ struct kvm_xen_hvm_config {
__u8 pad2[30];
};
-4.27 KVM_GET_CLOCK
+4.29 KVM_GET_CLOCK
Capability: KVM_CAP_ADJUST_CLOCK
Architectures: x86
@@ -636,7 +636,7 @@ struct kvm_clock_data {
__u32 pad[9];
};
-4.28 KVM_SET_CLOCK
+4.30 KVM_SET_CLOCK
Capability: KVM_CAP_ADJUST_CLOCK
Architectures: x86
@@ -654,7 +654,7 @@ struct kvm_clock_data {
__u32 pad[9];
};
-4.29 KVM_GET_VCPU_EVENTS
+4.31 KVM_GET_VCPU_EVENTS
Capability: KVM_CAP_VCPU_EVENTS
Extended by: KVM_CAP_INTR_SHADOW
@@ -693,7 +693,7 @@ struct kvm_vcpu_events {
KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
interrupt.shadow contains a valid state. Otherwise, this field is undefined.
-4.30 KVM_SET_VCPU_EVENTS
+4.32 KVM_SET_VCPU_EVENTS
Capability: KVM_CAP_VCPU_EVENTS
Extended by: KVM_CAP_INTR_SHADOW
@@ -719,7 +719,7 @@ If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
the flags field to signal that interrupt.shadow contains a valid state and
shall be written into the VCPU.
-4.32 KVM_GET_DEBUGREGS
+4.33 KVM_GET_DEBUGREGS
Capability: KVM_CAP_DEBUGREGS
Architectures: x86
@@ -737,7 +737,7 @@ struct kvm_debugregs {
__u64 reserved[9];
};
-4.33 KVM_SET_DEBUGREGS
+4.34 KVM_SET_DEBUGREGS
Capability: KVM_CAP_DEBUGREGS
Architectures: x86
@@ -750,7 +750,7 @@ Writes debug registers into the vcpu.
See KVM_GET_DEBUGREGS for the data structure. The flags field is unused
yet and must be cleared on entry.
-4.34 KVM_SET_USER_MEMORY_REGION
+4.35 KVM_SET_USER_MEMORY_REGION
Capability: KVM_CAP_USER_MEM
Architectures: all
@@ -796,7 +796,7 @@ It is recommended to use this API instead of the KVM_SET_MEMORY_REGION ioctl.
The KVM_SET_MEMORY_REGION does not allow fine grained control over memory
allocation and is deprecated.
-4.35 KVM_SET_TSS_ADDR
+4.36 KVM_SET_TSS_ADDR
Capability: KVM_CAP_SET_TSS_ADDR
Architectures: x86
@@ -814,7 +814,7 @@ This ioctl is required on Intel-based hosts. This is needed on Intel hardware
because of a quirk in the virtualization implementation (see the internals
documentation when it pops into existence).
-4.36 KVM_ENABLE_CAP
+4.37 KVM_ENABLE_CAP
Capability: KVM_CAP_ENABLE_CAP
Architectures: ppc
@@ -849,7 +849,7 @@ function properly, this is the place to put them.
__u8 pad[64];
};
-4.37 KVM_GET_MP_STATE
+4.38 KVM_GET_MP_STATE
Capability: KVM_CAP_MP_STATE
Architectures: x86, ia64
@@ -879,7 +879,7 @@ Possible values are:
This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel
irqchip, the multiprocessing state must be maintained by userspace.
-4.38 KVM_SET_MP_STATE
+4.39 KVM_SET_MP_STATE
Capability: KVM_CAP_MP_STATE
Architectures: x86, ia64
@@ -893,7 +893,7 @@ arguments.
This ioctl is only useful after KVM_CREATE_IRQCHIP. Without an in-kernel
irqchip, the multiprocessing state must be maintained by userspace.
-4.39 KVM_SET_IDENTITY_MAP_ADDR
+4.40 KVM_SET_IDENTITY_MAP_ADDR
Capability: KVM_CAP_SET_IDENTITY_MAP_ADDR
Architectures: x86
@@ -911,7 +911,7 @@ This ioctl is required on Intel-based hosts. This is needed on Intel hardware
because of a quirk in the virtualization implementation (see the internals
documentation when it pops into existence).
-4.40 KVM_SET_BOOT_CPU_ID
+4.41 KVM_SET_BOOT_CPU_ID
Capability: KVM_CAP_SET_BOOT_CPU_ID
Architectures: x86, ia64
@@ -923,7 +923,7 @@ Define which vcpu is the Bootstrap Processor (BSP). Values are the same
as the vcpu id in KVM_CREATE_VCPU. If this ioctl is not called, the default
is vcpu 0.
-4.41 KVM_GET_XSAVE
+4.42 KVM_GET_XSAVE
Capability: KVM_CAP_XSAVE
Architectures: x86
@@ -937,7 +937,7 @@ struct kvm_xsave {
This ioctl would copy current vcpu's xsave struct to the userspace.
-4.42 KVM_SET_XSAVE
+4.43 KVM_SET_XSAVE
Capability: KVM_CAP_XSAVE
Architectures: x86
@@ -951,7 +951,7 @@ struct kvm_xsave {
This ioctl would copy userspace's xsave struct to the kernel.
-4.43 KVM_GET_XCRS
+4.44 KVM_GET_XCRS
Capability: KVM_CAP_XCRS
Architectures: x86
@@ -974,7 +974,7 @@ struct kvm_xcrs {
This ioctl would copy current vcpu's xcrs to the userspace.
-4.44 KVM_SET_XCRS
+4.45 KVM_SET_XCRS
Capability: KVM_CAP_XCRS
Architectures: x86
@@ -997,7 +997,7 @@ struct kvm_xcrs {
This ioctl would set vcpu's xcr to the value userspace specified.
-4.45 KVM_GET_SUPPORTED_CPUID
+4.46 KVM_GET_SUPPORTED_CPUID
Capability: KVM_CAP_EXT_CPUID
Architectures: x86
@@ -1062,7 +1062,7 @@ emulate them efficiently. The fields in each entry are defined as follows:
eax, ebx, ecx, edx: the values returned by the cpuid instruction for
this function/index combination
-4.46 KVM_PPC_GET_PVINFO
+4.47 KVM_PPC_GET_PVINFO
Capability: KVM_CAP_PPC_GET_PVINFO
Architectures: ppc
@@ -1085,7 +1085,7 @@ of 4 instructions that make up a hypercall.
If any additional field gets added to this structure later on, a bit for that
additional piece of information will be set in the flags bitmap.
-4.47 KVM_ASSIGN_PCI_DEVICE
+4.48 KVM_ASSIGN_PCI_DEVICE
Capability: KVM_CAP_DEVICE_ASSIGNMENT
Architectures: x86 ia64
@@ -1113,7 +1113,7 @@ following flags are specified:
/* Depends on KVM_CAP_IOMMU */
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
-4.48 KVM_DEASSIGN_PCI_DEVICE
+4.49 KVM_DEASSIGN_PCI_DEVICE
Capability: KVM_CAP_DEVICE_DEASSIGNMENT
Architectures: x86 ia64
@@ -1126,7 +1126,7 @@ Ends PCI device assignment, releasing all associated resources.
See KVM_CAP_DEVICE_ASSIGNMENT for the data structure. Only assigned_dev_id is
used in kvm_assigned_pci_dev to identify the device.
-4.49 KVM_ASSIGN_DEV_IRQ
+4.50 KVM_ASSIGN_DEV_IRQ
Capability: KVM_CAP_ASSIGN_DEV_IRQ
Architectures: x86 ia64
@@ -1164,7 +1164,7 @@ The following flags are defined:
It is not valid to specify multiple types per host or guest IRQ. However, the
IRQ type of host and guest can differ or can even be null.
-4.50 KVM_DEASSIGN_DEV_IRQ
+4.51 KVM_DEASSIGN_DEV_IRQ
Capability: KVM_CAP_ASSIGN_DEV_IRQ
Architectures: x86 ia64
@@ -1178,7 +1178,7 @@ See KVM_ASSIGN_DEV_IRQ for the data structure. The target device is specified
by assigned_dev_id, flags must correspond to the IRQ type specified on
KVM_ASSIGN_DEV_IRQ. Partial deassignment of host or guest IRQ is allowed.
-4.51 KVM_SET_GSI_ROUTING
+4.52 KVM_SET_GSI_ROUTING
Capability: KVM_CAP_IRQ_ROUTING
Architectures: x86 ia64
@@ -1226,7 +1226,7 @@ struct kvm_irq_routing_msi {
__u32 pad;
};
-4.52 KVM_ASSIGN_SET_MSIX_NR
+4.53 KVM_ASSIGN_SET_MSIX_NR
Capability: KVM_CAP_DEVICE_MSIX
Architectures: x86 ia64
@@ -1245,7 +1245,7 @@ struct kvm_assigned_msix_nr {
#define KVM_MAX_MSIX_PER_DEV 256
-4.53 KVM_ASSIGN_SET_MSIX_ENTRY
+4.54 KVM_ASSIGN_SET_MSIX_ENTRY
Capability: KVM_CAP_DEVICE_MSIX
Architectures: x86 ia64
diff --git a/Documentation/kvm/locking.txt b/Documentation/kvm/locking.txt
new file mode 100644
index 000000000000..3b4cd3bf5631
--- /dev/null
+++ b/Documentation/kvm/locking.txt
@@ -0,0 +1,25 @@
+KVM Lock Overview
+=================
+
+1. Acquisition Orders
+---------------------
+
+(to be written)
+
+2. Reference
+------------
+
+Name: kvm_lock
+Type: raw_spinlock
+Arch: any
+Protects: - vm_list
+ - hardware virtualization enable/disable
+Comment: 'raw' because hardware enabling/disabling must be atomic /wrt
+ migration.
+
+Name: kvm_arch::tsc_write_lock
+Type: raw_spinlock
+Arch: x86
+Protects: - kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset}
+ - tsc offset in vmcb
+Comment: 'raw' because updating the tsc offsets must not be preempted.
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index b64d10d221ec..4d9ce73ff730 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,26 @@
+Release Date : Thu. Feb 24, 2011 17:00:00 PST 2010 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+Current Version : 00.00.05.34-rc1
+Old Version : 00.00.05.29-rc1
+ 1. Fix some failure gotos from megasas_probe_one(), etc.
+ 2. Add missing check_and_restore_queue_depth() call in
+ complete_cmd_fusion().
+ 3. Enable MSI-X before calling megasas_init_fw().
+ 4. Call tasklet_schedule() even if outbound_intr_status == 0 for MFI based
+ boards in MSI-X mode.
+ 5. Fix megasas_probe_one() to clear PCI_MSIX_FLAGS_ENABLE in msi control
+ register in kdump kernel.
+ 6. Fix megasas_get_cmd() to only print "Command pool empty" if
+ megasas_dbg_lvl is set.
+ 7. Fix megasas_build_dcdb_fusion() to not filter by TYPE_DISK.
+ 8. Fix megasas_build_dcdb_fusion() to use io_request->LUN[1] field.
+ 9. Add MR_EVT_CFG_CLEARED to megasas_aen_polling().
+ 10. Fix tasklet_init() in megasas_init_fw() to use instancet->tasklet.
+ 11. Fix fault state handling in megasas_transition_to_ready().
+ 12. Fix max_sectors setting for IEEE SGL's.
+ 13. Fix iMR OCR support to work correctly.
+-------------------------------------------------------------------------------
Release Date : Tues. Dec 14, 2010 17:00:00 PST 2010 -
(emaild-id:megaraidlinux@lsi.com)
Adam Radford
diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt
index dca658362cbf..891435a72fce 100644
--- a/Documentation/scsi/hpsa.txt
+++ b/Documentation/scsi/hpsa.txt
@@ -28,6 +28,12 @@ boot parameter "hpsa_allow_any=1" is specified, however these are not tested
nor supported by HP with this driver. For older Smart Arrays, the cciss
driver should still be used.
+The "hpsa_simple_mode=1" boot parameter may be used to prevent the driver from
+putting the controller into "performant" mode. The difference is that with simple
+mode, each command completion requires an interrupt, while with "performant mode"
+(the default, and ordinarily better performing) it is possible to have multiple
+command completions indicated by a single interrupt.
+
HPSA specific entries in /sys
-----------------------------
@@ -39,6 +45,8 @@ HPSA specific entries in /sys
/sys/class/scsi_host/host*/rescan
/sys/class/scsi_host/host*/firmware_revision
+ /sys/class/scsi_host/host*/resettable
+ /sys/class/scsi_host/host*/transport_mode
the host "rescan" attribute is a write only attribute. Writing to this
attribute will cause the driver to scan for new, changed, or removed devices
@@ -55,6 +63,21 @@ HPSA specific entries in /sys
root@host:/sys/class/scsi_host/host4# cat firmware_revision
7.14
+ The transport_mode indicates whether the controller is in "performant"
+ or "simple" mode. This is controlled by the "hpsa_simple_mode" module
+ parameter.
+
+ The "resettable" read-only attribute indicates whether a particular
+ controller is able to honor the "reset_devices" kernel parameter. If the
+ device is resettable, this file will contain a "1", otherwise, a "0". This
+ parameter is used by kdump, for example, to reset the controller at driver
+ load time to eliminate any outstanding commands on the controller and get the
+ controller into a known state so that the kdump initiated i/o will work right
+ and not be disrupted in any way by stale commands or other stale state
+ remaining on the controller from the previous kernel. This attribute enables
+ kexec tools to warn the user if they attempt to designate a device which is
+ unable to honor the reset_devices kernel parameter as a dump device.
+
HPSA specific disk attributes:
------------------------------
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index df322c103466..5f17d29c59b5 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -1343,7 +1343,7 @@ Members of interest:
underruns (overruns should be rare). If possible an LLD
should set 'resid' prior to invoking 'done'. The most
interesting case is data transfers from a SCSI target
- device device (i.e. READs) that underrun.
+ device (e.g. READs) that underrun.
underflow - LLD should place (DID_ERROR << 16) in 'result' if
actual number of bytes transferred is less than this
figure. Not many LLDs implement this check and some that
@@ -1351,6 +1351,18 @@ Members of interest:
report a DID_ERROR. Better for an LLD to implement
'resid'.
+It is recommended that a LLD set 'resid' on data transfers from a SCSI
+target device (e.g. READs). It is especially important that 'resid' is set
+when such data transfers have sense keys of MEDIUM ERROR and HARDWARE ERROR
+(and possibly RECOVERED ERROR). In these cases if a LLD is in doubt how much
+data has been received then the safest approach is to indicate no bytes have
+been received. For example: to indicate that no valid data has been received
+a LLD might use these helpers:
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+where 'SCpnt' is a pointer to a scsi_cmnd object. To indicate only three 512
+bytes blocks has been received 'resid' could be set like this:
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt) - (3 * 512));
+
The scsi_cmnd structure is defined in include/scsi/scsi_cmnd.h
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 11d5ceda5bb0..36f007514db3 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -367,7 +367,7 @@ the different loglevels.
- console_loglevel: messages with a higher priority than
this will be printed to the console
-- default_message_level: messages without an explicit priority
+- default_message_loglevel: messages without an explicit priority
will be printed with this priority
- minimum_console_loglevel: minimum (highest) value to which
console_loglevel can be set
diff --git a/Documentation/vm/unevictable-lru.txt b/Documentation/vm/unevictable-lru.txt
index 2d70d0d95108..97bae3c576c2 100644
--- a/Documentation/vm/unevictable-lru.txt
+++ b/Documentation/vm/unevictable-lru.txt
@@ -84,8 +84,7 @@ indicate that the page is being managed on the unevictable list.
The PG_unevictable flag is analogous to, and mutually exclusive with, the
PG_active flag in that it indicates on which LRU list a page resides when
-PG_lru is set. The unevictable list is compile-time configurable based on the
-UNEVICTABLE_LRU Kconfig option.
+PG_lru is set.
The Unevictable LRU infrastructure maintains unevictable pages on an additional
LRU list for a few reasons:
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index 7fbbaf85f5b7..48c13b8ab90c 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -189,13 +189,13 @@ ACPI
PCI
- pci=off Don't use PCI
- pci=conf1 Use conf1 access.
- pci=conf2 Use conf2 access.
- pci=rom Assign ROMs.
- pci=assign-busses Assign busses
- pci=irqmask=MASK Set PCI interrupt mask to MASK
- pci=lastbus=NUMBER Scan upto NUMBER busses, no matter what the mptable says.
+ pci=off Don't use PCI
+ pci=conf1 Use conf1 access.
+ pci=conf2 Use conf2 access.
+ pci=rom Assign ROMs.
+ pci=assign-busses Assign busses
+ pci=irqmask=MASK Set PCI interrupt mask to MASK
+ pci=lastbus=NUMBER Scan up to NUMBER busses, no matter what the mptable says.
pci=noacpi Don't use ACPI to set up PCI interrupt routing.
IOMMU (input/output memory management unit)
diff --git a/MAINTAINERS b/MAINTAINERS
index c07b1d7bb02e..c7a41b1fe453 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2376,7 +2376,7 @@ F: include/linux/edac_mce.h
EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com>
-M: "Arvind R." <arvind@jetztechnologies.com>
+M: "Arvind R." <arvino55@gmail.com>
L: bluesmoke-devel@lists.sourceforge.net (moderated for non-subscribers)
W: bluesmoke.sourceforge.net
S: Maintained
@@ -3472,6 +3472,7 @@ F: net/ipx/
IRDA SUBSYSTEM
M: Samuel Ortiz <samuel@sortiz.org>
L: irda-users@lists.sourceforge.net (subscribers-only)
+L: netdev@vger.kernel.org
W: http://irda.sourceforge.net/
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/irda-2.6.git
@@ -3909,6 +3910,12 @@ L: linux-security-module@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
S: Supported
+LIS3LV02D ACCELEROMETER DRIVER
+M: Eric Piel <eric.piel@tremplin-utc.net>
+S: Maintained
+F: Documentation/hwmon/lis3lv02d
+F: drivers/hwmon/lis3lv02d.*
+
LLC (802.2)
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
S: Maintained
@@ -3916,12 +3923,6 @@ F: include/linux/llc.h
F: include/net/llc*
F: net/llc/
-LIS3LV02D ACCELEROMETER DRIVER
-M: Eric Piel <eric.piel@tremplin-utc.net>
-S: Maintained
-F: Documentation/hwmon/lis3lv02d
-F: drivers/hwmon/lis3lv02d.*
-
LM73 HARDWARE MONITOR DRIVER
M: Guillaume Ligneul <guillaume.ligneul@gmail.com>
L: lm-sensors@lm-sensors.org
@@ -4510,11 +4511,21 @@ S: Maintained
F: arch/arm/*omap*/*clock*
OMAP POWER MANAGEMENT SUPPORT
-M: Kevin Hilman <khilman@deeprootsystems.com>
+M: Kevin Hilman <khilman@ti.com>
L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/*omap*/*pm*
+OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT
+M: Rajendra Nayak <rnayak@ti.com>
+M: Paul Walmsley <paul@pwsan.com>
+L: linux-omap@vger.kernel.org
+S: Maintained
+F: arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
+F: arch/arm/mach-omap2/powerdomain44xx.c
+F: arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+F: arch/arm/mach-omap2/clockdomain44xx.c
+
OMAP AUDIO SUPPORT
M: Jarkko Nikula <jhnikula@gmail.com>
L: alsa-devel@alsa-project.org (subscribers-only)
@@ -5359,8 +5370,7 @@ S: Supported
F: drivers/s390/crypto/
S390 ZFCP DRIVER
-M: Christof Schmitt <christof.schmitt@de.ibm.com>
-M: Swen Schillig <swen@vnet.ibm.com>
+M: Steffen Maier <maier@linux.vnet.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5399,6 +5409,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/samsung
+SERIAL DRIVERS
+M: Alan Cox <alan@linux.intel.com>
+L: linux-serial@vger.kernel.org
+S: Maintained
+F: drivers/tty/serial
+
TIMEKEEPING, NTP
M: John Stultz <johnstul@us.ibm.com>
M: Thomas Gleixner <tglx@linutronix.de>
@@ -5677,7 +5693,8 @@ F: arch/arm/mach-s3c2410/bast-ide.c
F: arch/arm/mach-s3c2410/bast-irq.c
TI DAVINCI MACHINE SUPPORT
-M: Kevin Hilman <khilman@deeprootsystems.com>
+M: Sekhar Nori <nsekhar@ti.com>
+M: Kevin Hilman <khilman@ti.com>
L: davinci-linux-open-source@linux.davincidsp.com (subscribers-only)
Q: http://patchwork.kernel.org/project/linux-davinci/list/
S: Supported
@@ -6117,6 +6134,7 @@ S: Supported
F: arch/tile/
F: drivers/tty/hvc/hvc_tile.c
F: drivers/net/tile/
+F: drivers/edac/tile_edac.c
TLAN NETWORK DRIVER
M: Samuel Chessman <chessman@tux.org>
diff --git a/Makefile b/Makefile
index d6592b63c8cb..92b8bed3059e 100644
--- a/Makefile
+++ b/Makefile
@@ -666,7 +666,7 @@ export MODLIB
# INSTALL_MOD_STRIP, if defined, will cause modules to be
# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then
# the default option --strip-debug will be used. Otherwise,
-# INSTALL_MOD_STRIP will used as the options to the strip command.
+# INSTALL_MOD_STRIP value will be used as the options to the strip command.
ifdef INSTALL_MOD_STRIP
ifeq ($(INSTALL_MOD_STRIP),1)
diff --git a/README b/README
index 1b81d2836873..8510017a3576 100644
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ ON WHAT HARDWARE DOES IT RUN?
today Linux also runs on (at least) the Compaq Alpha AXP, Sun SPARC and
UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell,
IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS,
- Xtensa, AVR32 and Renesas M32R architectures.
+ Xtensa, Tilera TILE, AVR32 and Renesas M32R architectures.
Linux is easily portable to most general-purpose 32- or 64-bit architectures
as long as they have a paged memory management unit (PMMU) and a port of the
diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h
index 012f1243b1c1..a9cb6aa447aa 100644
--- a/arch/alpha/include/asm/cacheflush.h
+++ b/arch/alpha/include/asm/cacheflush.h
@@ -63,7 +63,7 @@ extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr, int len);
#endif
-/* This is used only in do_no_page and do_swap_page. */
+/* This is used only in __do_fault and do_swap_page. */
#define flush_icache_page(vma, page) \
flush_icache_user_range((vma), (page), 0, 0)
diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h
index 98099bda9370..e5f29ca28180 100644
--- a/arch/alpha/include/asm/errno.h
+++ b/arch/alpha/include/asm/errno.h
@@ -122,4 +122,6 @@
#define ERFKILL 138 /* Operation not possible due to RF-kill */
+#define EHWPOISON 139 /* Memory page has hardware error */
+
#endif
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e34bf0272da4..599e1634840d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -626,6 +626,7 @@ config ARCH_MSM
select HAVE_CLK
select GENERIC_CLOCKEVENTS
select ARCH_REQUIRE_GPIOLIB
+ select CLKDEV_LOOKUP
help
Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory
@@ -722,7 +723,8 @@ config ARCH_S5P64X0
select GENERIC_GPIO
select HAVE_CLK
select HAVE_S3C2410_WATCHDOG if WATCHDOG
- select ARCH_USES_GETTIMEOFFSET
+ select GENERIC_CLOCKEVENTS
+ select HAVE_SCHED_CLOCK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C_RTC if RTC_CLASS
help
@@ -760,15 +762,16 @@ config ARCH_S5PV210
select HAVE_CLK
select ARM_L1_CACHE_SHIFT_6
select ARCH_HAS_CPUFREQ
- select ARCH_USES_GETTIMEOFFSET
+ select GENERIC_CLOCKEVENTS
+ select HAVE_SCHED_CLOCK
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C_RTC if RTC_CLASS
select HAVE_S3C2410_WATCHDOG if WATCHDOG
help
Samsung S5PV210/S5PC110 series based systems
-config ARCH_S5PV310
- bool "Samsung S5PV310/S5PC210"
+config ARCH_EXYNOS4
+ bool "Samsung EXYNOS4"
select CPU_V7
select ARCH_SPARSEMEM_ENABLE
select GENERIC_GPIO
@@ -779,7 +782,7 @@ config ARCH_S5PV310
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
help
- Samsung S5PV310 series based systems
+ Samsung EXYNOS4 series based systems
config ARCH_SHARK
bool "Shark"
@@ -993,7 +996,7 @@ source "arch/arm/mach-s5pc100/Kconfig"
source "arch/arm/mach-s5pv210/Kconfig"
-source "arch/arm/mach-s5pv310/Kconfig"
+source "arch/arm/mach-exynos4/Kconfig"
source "arch/arm/mach-shmobile/Kconfig"
@@ -1315,7 +1318,7 @@ config SMP
depends on GENERIC_CLOCKEVENTS
depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
- ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
+ ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE
select USE_GENERIC_SMP_HELPERS
select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
@@ -1403,7 +1406,7 @@ config LOCAL_TIMERS
bool "Use local timer interrupts"
depends on SMP
default y
- select HAVE_ARM_TWD if !ARCH_MSM_SCORPIONMP
+ select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT)
help
Enable support for local timers on SMP platforms, rather then the
legacy IPI broadcast method. Local timers allows the system
@@ -1415,7 +1418,7 @@ source kernel/Kconfig.preempt
config HZ
int
default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
- ARCH_S5P6442 || ARCH_S5PV210 || ARCH_S5PV310
+ ARCH_S5P6442 || ARCH_S5PV210 || ARCH_EXYNOS4
default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
default AT91_TIMER_HZ if ARCH_AT91
default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 5c7114bb8a25..c7d321a3d95d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -181,7 +181,7 @@ machine-$(CONFIG_ARCH_S5P64X0) := s5p64x0
machine-$(CONFIG_ARCH_S5P6442) := s5p6442
machine-$(CONFIG_ARCH_S5PC100) := s5pc100
machine-$(CONFIG_ARCH_S5PV210) := s5pv210
-machine-$(CONFIG_ARCH_S5PV310) := s5pv310
+machine-$(CONFIG_ARCH_EXYNOS4) := exynos4
machine-$(CONFIG_ARCH_SA1100) := sa1100
machine-$(CONFIG_ARCH_SHARK) := shark
machine-$(CONFIG_ARCH_SHMOBILE) := shmobile
diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig
new file mode 100644
index 000000000000..2ffba24d2e2a
--- /dev/null
+++ b/arch/arm/configs/exynos4_defconfig
@@ -0,0 +1,70 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_EXYNOS4=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=1
+CONFIG_MACH_SMDKC210=y
+CONFIG_MACH_SMDKV310=y
+CONFIG_MACH_UNIVERSAL_C210=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M"
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_S3C_UART=1
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
index 2f7042813765..aeb3af541fed 100644
--- a/arch/arm/configs/kirkwood_defconfig
+++ b/arch/arm/configs/kirkwood_defconfig
@@ -24,6 +24,7 @@ CONFIG_MACH_OPENRD_ULTIMATE=y
CONFIG_MACH_NETSPACE_V2=y
CONFIG_MACH_INETSPACE_V2=y
CONFIG_MACH_NETSPACE_MAX_V2=y
+CONFIG_MACH_D2NET_V2=y
CONFIG_MACH_NET2BIG_V2=y
CONFIG_MACH_NET5BIG_V2=y
CONFIG_MACH_T5325=y
diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig
index 9cba68cfa51a..e3c903281f70 100644
--- a/arch/arm/configs/mx51_defconfig
+++ b/arch/arm/configs/mx51_defconfig
@@ -110,7 +110,7 @@ CONFIG_MMC=y
CONFIG_MMC_BLOCK=m
CONFIG_MMC_SDHCI=m
CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_CLASS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index ae890caa17a7..019fb7c67dc3 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -58,6 +58,7 @@ CONFIG_ARM_ERRATA_411920=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
+CONFIG_NR_CPUS=2
# CONFIG_LOCAL_TIMERS is not set
CONFIG_AEABI=y
CONFIG_LEDS=y
diff --git a/arch/arm/configs/s5p64x0_defconfig b/arch/arm/configs/s5p64x0_defconfig
index 2993ecd35145..ad6b61b0bd11 100644
--- a/arch/arm/configs/s5p64x0_defconfig
+++ b/arch/arm/configs/s5p64x0_defconfig
@@ -10,6 +10,8 @@ CONFIG_S3C_BOOT_ERROR_RESET=y
CONFIG_S3C_LOWLEVEL_UART_PORT=1
CONFIG_MACH_SMDK6440=y
CONFIG_MACH_SMDK6450=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_CPU_32v6K=y
CONFIG_AEABI=y
CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
diff --git a/arch/arm/configs/s5pv210_defconfig b/arch/arm/configs/s5pv210_defconfig
index 0488a1eb4d7d..fa989902236d 100644
--- a/arch/arm/configs/s5pv210_defconfig
+++ b/arch/arm/configs/s5pv210_defconfig
@@ -13,6 +13,8 @@ CONFIG_MACH_AQUILA=y
CONFIG_MACH_GONI=y
CONFIG_MACH_SMDKC110=y
CONFIG_MACH_SMDKV210=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index 52d86c4485bf..a5cce242a775 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -1,7 +1,6 @@
CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_KALLSYMS_ALL=y
CONFIG_MODULES=y
@@ -13,43 +12,89 @@ CONFIG_UX500_SOC_DB5500=y
CONFIG_UX500_SOC_DB8500=y
CONFIG_MACH_U8500=y
CONFIG_MACH_U5500=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
+CONFIG_HOTPLUG_CPU=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_VFP=y
CONFIG_NEON=y
+CONFIG_NET=y
+CONFIG_PHONET=y
+CONFIG_PHONET_PIPECTRLR=y
+# CONFIG_WIRELESS is not set
+CONFIG_CAIF=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=65536
-# CONFIG_MISC_DEVICES is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_AB8500_PWM=y
+CONFIG_SENSORS_BH1780=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_NOMADIK=y
+CONFIG_KEYBOARD_STMPE=y
+CONFIG_KEYBOARD_TC3589X=y
# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_BU21013=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AB8500_PONKEY=y
# CONFIG_SERIO is not set
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_NOMADIK=y
+CONFIG_I2C=y
+CONFIG_I2C_NOMADIK=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
+CONFIG_GPIO_STMPE=y
+CONFIG_GPIO_TC3589X=y
# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TC3589X=y
+CONFIG_AB8500_CORE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_AB8500=y
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_ARMMMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_LP5521=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AB8500=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_DMADEVICES=y
+CONFIG_STE_DMA40=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
-CONFIG_INOTIFY=y
+CONFIG_EXT3_FS=y
+CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_CONFIGFS_FS=m
# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
@@ -58,5 +103,3 @@ CONFIG_DEBUG_INFO=y
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
-CONFIG_CRC_T10DIF=m
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/configs/vexpress_defconfig b/arch/arm/configs/vexpress_defconfig
new file mode 100644
index 000000000000..f2de51f0bd18
--- /dev/null
+++ b/arch/arm/configs/vexpress_defconfig
@@ -0,0 +1,140 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CPUSETS=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_VEXPRESS_CA9X4=y
+# CONFIG_SWP_EMULATE is not set
+CONFIG_SMP=y
+CONFIG_VMSPLIT_2G=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_AEABI=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MISC_DEVICES=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_ARMAACI=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_USB_ISP1760_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+CONFIG_MMC_ARMMMCI=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_PL031=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index c0094d8edae4..c2b9b4bdec00 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -50,6 +50,9 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
}
}
+/* Function pointer to optional machine-specific reinitialization */
+extern void (*kexec_reinit)(void);
+
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_KEXEC */
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 8ccea012722c..7544ce6b481a 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -12,11 +12,25 @@
#ifndef __ARM_PMU_H__
#define __ARM_PMU_H__
+#include <linux/interrupt.h>
+
enum arm_pmu_type {
ARM_PMU_DEVICE_CPU = 0,
ARM_NUM_PMU_DEVICES,
};
+/*
+ * struct arm_pmu_platdata - ARM PMU platform data
+ *
+ * @handle_irq: an optional handler which will be called from the interrupt and
+ * passed the address of the low level handler, and can be used to implement
+ * any platform specific handling before or after calling it.
+ */
+struct arm_pmu_platdata {
+ irqreturn_t (*handle_irq)(int irq, void *dev,
+ irq_handler_t pmu_handler);
+};
+
#ifdef CONFIG_CPU_HAS_PMU
/**
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 11db62806a1a..052b509e2d5f 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -338,7 +338,7 @@ static struct miscdevice etb_miscdev = {
.fops = &etb_fops,
};
-static int __init etb_probe(struct amba_device *dev, struct amba_id *id)
+static int __init etb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct tracectx *t = &tracer;
int ret = 0;
@@ -530,7 +530,7 @@ static ssize_t trace_mode_store(struct kobject *kobj,
static struct kobj_attribute trace_mode_attr =
__ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
-static int __init etm_probe(struct amba_device *dev, struct amba_id *id)
+static int __init etm_probe(struct amba_device *dev, const struct amba_id *id)
{
struct tracectx *t = &tracer;
int ret = 0;
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 30ead135ff5f..e59bbd496c39 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -75,6 +75,11 @@ void machine_crash_shutdown(struct pt_regs *regs)
printk(KERN_INFO "Loading crashdump kernel...\n");
}
+/*
+ * Function pointer to optional machine-specific reinitialization
+ */
+void (*kexec_reinit)(void);
+
void machine_kexec(struct kimage *image)
{
unsigned long page_list;
@@ -104,6 +109,8 @@ void machine_kexec(struct kimage *image)
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
printk(KERN_INFO "Bye!\n");
+ if (kexec_reinit)
+ kexec_reinit();
local_irq_disable();
local_fiq_disable();
setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d150ad1ccb5d..22e194eb8536 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -377,9 +377,18 @@ validate_group(struct perf_event *event)
return 0;
}
+static irqreturn_t armpmu_platform_irq(int irq, void *dev)
+{
+ struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev);
+
+ return plat->handle_irq(irq, dev, armpmu->handle_irq);
+}
+
static int
armpmu_reserve_hardware(void)
{
+ struct arm_pmu_platdata *plat;
+ irq_handler_t handle_irq;
int i, err = -ENODEV, irq;
pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
@@ -390,6 +399,12 @@ armpmu_reserve_hardware(void)
init_pmu(ARM_PMU_DEVICE_CPU);
+ plat = dev_get_platdata(&pmu_device->dev);
+ if (plat && plat->handle_irq)
+ handle_irq = armpmu_platform_irq;
+ else
+ handle_irq = armpmu->handle_irq;
+
if (pmu_device->num_resources < 1) {
pr_err("no irqs for PMUs defined\n");
return -ENODEV;
@@ -400,7 +415,7 @@ armpmu_reserve_hardware(void)
if (irq < 0)
continue;
- err = request_irq(irq, armpmu->handle_irq,
+ err = request_irq(irq, handle_irq,
IRQF_DISABLED | IRQF_NOBALANCING,
"armpmu", NULL);
if (err) {
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index b52a3a1abd94..8bc3701aa05c 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -20,6 +20,8 @@
#include <linux/i2c/at24.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -30,6 +32,7 @@
#include <mach/da8xx.h>
#include <mach/usb.h>
#include <mach/aemif.h>
+#include <mach/spi.h>
#define DA830_EVM_PHY_ID ""
/*
@@ -534,6 +537,64 @@ static struct edma_rsv_info da830_edma_rsv[] = {
},
};
+static struct mtd_partition da830evm_spiflash_part[] = {
+ [0] = {
+ .name = "DSP-UBL",
+ .offset = 0,
+ .size = SZ_8K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [1] = {
+ .name = "ARM-UBL",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_16K + SZ_8K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [2] = {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_256K - SZ_32K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [3] = {
+ .name = "U-Boot-Environment",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_16K,
+ .mask_flags = 0,
+ },
+ [4] = {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0,
+ },
+};
+
+static struct flash_platform_data da830evm_spiflash_data = {
+ .name = "m25p80",
+ .parts = da830evm_spiflash_part,
+ .nr_parts = ARRAY_SIZE(da830evm_spiflash_part),
+ .type = "w25x32",
+};
+
+static struct davinci_spi_config da830evm_spiflash_cfg = {
+ .io_type = SPI_IO_TYPE_DMA,
+ .c2tdelay = 8,
+ .t2cdelay = 8,
+};
+
+static struct spi_board_info da830evm_spi_info[] = {
+ {
+ .modalias = "m25p80",
+ .platform_data = &da830evm_spiflash_data,
+ .controller_data = &da830evm_spiflash_cfg,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 30000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ },
+};
+
static __init void da830_evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -590,6 +651,12 @@ static __init void da830_evm_init(void)
ret = da8xx_register_rtc();
if (ret)
pr_warning("da830_evm_init: rtc setup failed: %d\n", ret);
+
+ ret = da8xx_register_spi(0, da830evm_spi_info,
+ ARRAY_SIZE(da830evm_spi_info));
+ if (ret)
+ pr_warning("da830_evm_init: spi 0 registration failed: %d\n",
+ ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index b01fb2ab944a..a7b41bf505f1 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -29,6 +29,8 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -38,6 +40,7 @@
#include <mach/nand.h>
#include <mach/mux.h>
#include <mach/aemif.h>
+#include <mach/spi.h>
#define DA850_EVM_PHY_ID "0:00"
#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
@@ -48,6 +51,70 @@
#define DA850_MII_MDIO_CLKEN_PIN GPIO_TO_PIN(2, 6)
+static struct mtd_partition da850evm_spiflash_part[] = {
+ [0] = {
+ .name = "UBL",
+ .offset = 0,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [1] = {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_512K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [2] = {
+ .name = "U-Boot-Env",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [3] = {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M + SZ_512K,
+ .mask_flags = 0,
+ },
+ [4] = {
+ .name = "Filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_4M,
+ .mask_flags = 0,
+ },
+ [5] = {
+ .name = "MAC-Address",
+ .offset = SZ_8M - SZ_64K,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+};
+
+static struct flash_platform_data da850evm_spiflash_data = {
+ .name = "m25p80",
+ .parts = da850evm_spiflash_part,
+ .nr_parts = ARRAY_SIZE(da850evm_spiflash_part),
+ .type = "m25p64",
+};
+
+static struct davinci_spi_config da850evm_spiflash_cfg = {
+ .io_type = SPI_IO_TYPE_DMA,
+ .c2tdelay = 8,
+ .t2cdelay = 8,
+};
+
+static struct spi_board_info da850evm_spi_info[] = {
+ {
+ .modalias = "m25p80",
+ .platform_data = &da850evm_spiflash_data,
+ .controller_data = &da850evm_spiflash_cfg,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 30000000,
+ .bus_num = 1,
+ .chip_select = 0,
+ },
+};
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "bootloaders + env",
@@ -231,8 +298,6 @@ static const short da850_evm_nor_pins[] = {
-1
};
-static u32 ui_card_detected;
-
#if defined(CONFIG_MMC_DAVINCI) || \
defined(CONFIG_MMC_DAVINCI_MODULE)
#define HAS_MMC 1
@@ -244,7 +309,7 @@ static inline void da850_evm_setup_nor_nand(void)
{
int ret = 0;
- if (ui_card_detected & !HAS_MMC) {
+ if (!HAS_MMC) {
ret = davinci_cfg_reg_list(da850_evm_nand_pins);
if (ret)
pr_warning("da850_evm_init: nand mux setup failed: "
@@ -394,7 +459,6 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio,
goto exp_setup_keys_fail;
}
- ui_card_detected = 1;
pr_info("DA850/OMAP-L138 EVM UI card detected\n");
da850_evm_setup_nor_nand();
@@ -664,6 +728,13 @@ static struct snd_platform_data da850_evm_snd_data = {
.rxnumevt = 1,
};
+static const short da850_evm_mcasp_pins[] __initconst = {
+ DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
+ DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
+ DA850_AXR_11, DA850_AXR_12,
+ -1
+};
+
static int da850_evm_mmc_get_ro(int index)
{
return gpio_get_value(DA850_MMCSD_WP_PIN);
@@ -683,6 +754,13 @@ static struct davinci_mmc_config da850_mmc_config = {
.version = MMC_CTLR_VERSION_2,
};
+static const short da850_evm_mmcsd0_pins[] __initconst = {
+ DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2,
+ DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD,
+ DA850_GPIO4_0, DA850_GPIO4_1,
+ -1
+};
+
static void da850_panel_power_ctrl(int val)
{
/* lcd backlight */
@@ -1070,7 +1148,7 @@ static __init void da850_evm_init(void)
ret);
if (HAS_MMC) {
- ret = davinci_cfg_reg_list(da850_mmcsd0_pins);
+ ret = davinci_cfg_reg_list(da850_evm_mmcsd0_pins);
if (ret)
pr_warning("da850_evm_init: mmcsd0 mux setup failed:"
" %d\n", ret);
@@ -1106,7 +1184,7 @@ static __init void da850_evm_init(void)
__raw_writel(0, IO_ADDRESS(DA8XX_UART1_BASE) + 0x30);
__raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30);
- ret = davinci_cfg_reg_list(da850_mcasp_pins);
+ ret = davinci_cfg_reg_list(da850_evm_mcasp_pins);
if (ret)
pr_warning("da850_evm_init: mcasp mux setup failed: %d\n",
ret);
@@ -1153,6 +1231,12 @@ static __init void da850_evm_init(void)
if (ret)
pr_warning("da850_evm_init: suspend registration failed: %d\n",
ret);
+
+ ret = da8xx_register_spi(1, da850evm_spi_info,
+ ARRAY_SIZE(da850evm_spi_info));
+ if (ret)
+ pr_warning("da850_evm_init: spi 1 registration failed: %d\n",
+ ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 0ca90b834586..556bbd468db3 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -440,11 +440,6 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
gpio_request(gpio + 7, "nCF_SEL");
gpio_direction_output(gpio + 7, 1);
- /* irlml6401 switches over 1A, in under 8 msec;
- * now it can be managed by nDRV_VBUS ...
- */
- davinci_setup_usb(1000, 8);
-
return 0;
}
@@ -705,6 +700,9 @@ static __init void davinci_evm_init(void)
davinci_serial_init(&uart_config);
dm644x_init_asp(&dm644x_evm_snd_data);
+ /* irlml6401 switches over 1A, in under 8 msec */
+ davinci_setup_usb(1000, 8);
+
soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
/* Register the fixup for PHY on DaVinci */
phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index 0bb5f0ce4fdc..2aa79c54f98e 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -17,6 +17,8 @@
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
#include <linux/etherdevice.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -25,6 +27,7 @@
#include <mach/da8xx.h>
#include <mach/nand.h>
#include <mach/mux.h>
+#include <mach/spi.h>
#define MITYOMAPL138_PHY_ID "0:03"
@@ -44,38 +47,109 @@ struct factory_config {
static struct factory_config factory_config;
+struct part_no_info {
+ const char *part_no; /* part number string of interest */
+ int max_freq; /* khz */
+};
+
+static struct part_no_info mityomapl138_pn_info[] = {
+ {
+ .part_no = "L138-C",
+ .max_freq = 300000,
+ },
+ {
+ .part_no = "L138-D",
+ .max_freq = 375000,
+ },
+ {
+ .part_no = "L138-F",
+ .max_freq = 456000,
+ },
+ {
+ .part_no = "1808-C",
+ .max_freq = 300000,
+ },
+ {
+ .part_no = "1808-D",
+ .max_freq = 375000,
+ },
+ {
+ .part_no = "1808-F",
+ .max_freq = 456000,
+ },
+ {
+ .part_no = "1810-D",
+ .max_freq = 375000,
+ },
+};
+
+#ifdef CONFIG_CPU_FREQ
+static void mityomapl138_cpufreq_init(const char *partnum)
+{
+ int i, ret;
+
+ for (i = 0; partnum && i < ARRAY_SIZE(mityomapl138_pn_info); i++) {
+ /*
+ * the part number has additional characters beyond what is
+ * stored in the table. This information is not needed for
+ * determining the speed grade, and would require several
+ * more table entries. Only check the first N characters
+ * for a match.
+ */
+ if (!strncmp(partnum, mityomapl138_pn_info[i].part_no,
+ strlen(mityomapl138_pn_info[i].part_no))) {
+ da850_max_speed = mityomapl138_pn_info[i].max_freq;
+ break;
+ }
+ }
+
+ ret = da850_register_cpufreq("pll0_sysclk3");
+ if (ret)
+ pr_warning("cpufreq registration failed: %d\n", ret);
+}
+#else
+static void mityomapl138_cpufreq_init(const char *partnum) { }
+#endif
+
static void read_factory_config(struct memory_accessor *a, void *context)
{
int ret;
+ const char *partnum = NULL;
struct davinci_soc_info *soc_info = &davinci_soc_info;
ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
if (ret != sizeof(struct factory_config)) {
pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
ret);
- return;
+ goto bad_config;
}
if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
factory_config.magic);
- return;
+ goto bad_config;
}
if (factory_config.version != FACTORY_CONFIG_VERSION) {
pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
factory_config.version);
- return;
+ goto bad_config;
}
pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
- pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum);
if (is_valid_ether_addr(factory_config.mac))
memcpy(soc_info->emac_pdata->mac_addr,
factory_config.mac, ETH_ALEN);
else
pr_warning("MityOMAPL138: Invalid MAC found "
"in factory config block\n");
+
+ partnum = factory_config.partnum;
+ pr_info("MityOMAPL138: Part Number = %s\n", partnum);
+
+bad_config:
+ /* default maximum speed is valid for all platforms */
+ mityomapl138_cpufreq_init(partnum);
}
static struct at24_platform_data mityomapl138_fd_chip = {
@@ -223,6 +297,82 @@ static int __init pmic_tps65023_init(void)
}
/*
+ * SPI Devices:
+ * SPI1_CS0: 8M Flash ST-M25P64-VME6G
+ */
+static struct mtd_partition spi_flash_partitions[] = {
+ [0] = {
+ .name = "ubl",
+ .offset = 0,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [1] = {
+ .name = "u-boot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_512K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [2] = {
+ .name = "u-boot-env",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [3] = {
+ .name = "periph-config",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_64K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ [4] = {
+ .name = "reserved",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_256K + SZ_64K,
+ },
+ [5] = {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M + SZ_1M,
+ },
+ [6] = {
+ .name = "fpga",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ },
+ [7] = {
+ .name = "spare",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct flash_platform_data mityomapl138_spi_flash_data = {
+ .name = "m25p80",
+ .parts = spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(spi_flash_partitions),
+ .type = "m24p64",
+};
+
+static struct davinci_spi_config spi_eprom_config = {
+ .io_type = SPI_IO_TYPE_DMA,
+ .c2tdelay = 8,
+ .t2cdelay = 8,
+};
+
+static struct spi_board_info mityomapl138_spi_flash_info[] = {
+ {
+ .modalias = "m25p80",
+ .platform_data = &mityomapl138_spi_flash_data,
+ .controller_data = &spi_eprom_config,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 30000000,
+ .bus_num = 1,
+ .chip_select = 0,
+ },
+};
+
+/*
* MityDSP-L138 includes a 256 MByte large-page NAND flash
* (128K blocks).
*/
@@ -377,16 +527,17 @@ static void __init mityomapl138_init(void)
mityomapl138_setup_nand();
+ ret = da8xx_register_spi(1, mityomapl138_spi_flash_info,
+ ARRAY_SIZE(mityomapl138_spi_flash_info));
+ if (ret)
+ pr_warning("spi 1 registration failed: %d\n", ret);
+
mityomapl138_config_emac();
ret = da8xx_register_rtc();
if (ret)
pr_warning("rtc setup failed: %d\n", ret);
- ret = da850_register_cpufreq("pll0_sysclk3");
- if (ret)
- pr_warning("cpufreq registration failed: %d\n", ret);
-
ret = da8xx_register_cpuidle();
if (ret)
pr_warning("cpuidle registration failed: %d\n", ret);
diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c
index 0b8dbdb79fe0..67c38d0ecd10 100644
--- a/arch/arm/mach-davinci/board-omapl138-hawk.c
+++ b/arch/arm/mach-davinci/board-omapl138-hawk.c
@@ -19,6 +19,279 @@
#include <mach/cp_intc.h>
#include <mach/da8xx.h>
+#include <mach/mux.h>
+
+#define HAWKBOARD_PHY_ID "0:07"
+#define DA850_HAWK_MMCSD_CD_PIN GPIO_TO_PIN(3, 12)
+#define DA850_HAWK_MMCSD_WP_PIN GPIO_TO_PIN(3, 13)
+
+#define DA850_USB1_VBUS_PIN GPIO_TO_PIN(2, 4)
+#define DA850_USB1_OC_PIN GPIO_TO_PIN(6, 13)
+
+static short omapl138_hawk_mii_pins[] __initdata = {
+ DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+ DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+ DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+ DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+ DA850_MDIO_D,
+ -1
+};
+
+static __init void omapl138_hawk_config_emac(void)
+{
+ void __iomem *cfgchip3 = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+ int ret;
+ u32 val;
+ struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+ val = __raw_readl(cfgchip3);
+ val &= ~BIT(8);
+ ret = davinci_cfg_reg_list(omapl138_hawk_mii_pins);
+ if (ret) {
+ pr_warning("%s: cpgmac/mii mux setup failed: %d\n",
+ __func__, ret);
+ return;
+ }
+
+ /* configure the CFGCHIP3 register for MII */
+ __raw_writel(val, cfgchip3);
+ pr_info("EMAC: MII PHY configured\n");
+
+ soc_info->emac_pdata->phy_id = HAWKBOARD_PHY_ID;
+
+ ret = da8xx_register_emac();
+ if (ret)
+ pr_warning("%s: emac registration failed: %d\n",
+ __func__, ret);
+}
+
+/*
+ * The following EDMA channels/slots are not being used by drivers (for
+ * example: Timer, GPIO, UART events etc) on da850/omap-l138 EVM/Hawkboard,
+ * hence they are being reserved for codecs on the DSP side.
+ */
+static const s16 da850_dma0_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma0_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 8, 6},
+ {24, 4},
+ {30, 50},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_chans[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 2},
+ {-1, -1}
+};
+
+static const s16 da850_dma1_rsv_slots[][2] = {
+ /* (offset, number) */
+ { 0, 28},
+ {30, 90},
+ {-1, -1}
+};
+
+static struct edma_rsv_info da850_edma_cc0_rsv = {
+ .rsv_chans = da850_dma0_rsv_chans,
+ .rsv_slots = da850_dma0_rsv_slots,
+};
+
+static struct edma_rsv_info da850_edma_cc1_rsv = {
+ .rsv_chans = da850_dma1_rsv_chans,
+ .rsv_slots = da850_dma1_rsv_slots,
+};
+
+static struct edma_rsv_info *da850_edma_rsv[2] = {
+ &da850_edma_cc0_rsv,
+ &da850_edma_cc1_rsv,
+};
+
+static const short hawk_mmcsd0_pins[] = {
+ DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2,
+ DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD,
+ DA850_GPIO3_12, DA850_GPIO3_13,
+ -1
+};
+
+static int da850_hawk_mmc_get_ro(int index)
+{
+ return gpio_get_value(DA850_HAWK_MMCSD_WP_PIN);
+}
+
+static int da850_hawk_mmc_get_cd(int index)
+{
+ return !gpio_get_value(DA850_HAWK_MMCSD_CD_PIN);
+}
+
+static struct davinci_mmc_config da850_mmc_config = {
+ .get_ro = da850_hawk_mmc_get_ro,
+ .get_cd = da850_hawk_mmc_get_cd,
+ .wires = 4,
+ .max_freq = 50000000,
+ .caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .version = MMC_CTLR_VERSION_2,
+};
+
+static __init void omapl138_hawk_mmc_init(void)
+{
+ int ret;
+
+ ret = davinci_cfg_reg_list(hawk_mmcsd0_pins);
+ if (ret) {
+ pr_warning("%s: MMC/SD0 mux setup failed: %d\n",
+ __func__, ret);
+ return;
+ }
+
+ ret = gpio_request_one(DA850_HAWK_MMCSD_CD_PIN,
+ GPIOF_DIR_IN, "MMC CD");
+ if (ret < 0) {
+ pr_warning("%s: can not open GPIO %d\n",
+ __func__, DA850_HAWK_MMCSD_CD_PIN);
+ return;
+ }
+
+ ret = gpio_request_one(DA850_HAWK_MMCSD_WP_PIN,
+ GPIOF_DIR_IN, "MMC WP");
+ if (ret < 0) {
+ pr_warning("%s: can not open GPIO %d\n",
+ __func__, DA850_HAWK_MMCSD_WP_PIN);
+ goto mmc_setup_wp_fail;
+ }
+
+ ret = da8xx_register_mmcsd0(&da850_mmc_config);
+ if (ret) {
+ pr_warning("%s: MMC/SD0 registration failed: %d\n",
+ __func__, ret);
+ goto mmc_setup_mmcsd_fail;
+ }
+
+ return;
+
+mmc_setup_mmcsd_fail:
+ gpio_free(DA850_HAWK_MMCSD_WP_PIN);
+mmc_setup_wp_fail:
+ gpio_free(DA850_HAWK_MMCSD_CD_PIN);
+}
+
+static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id);
+static da8xx_ocic_handler_t hawk_usb_ocic_handler;
+
+static const short da850_hawk_usb11_pins[] = {
+ DA850_GPIO2_4, DA850_GPIO6_13,
+ -1
+};
+
+static int hawk_usb_set_power(unsigned port, int on)
+{
+ gpio_set_value(DA850_USB1_VBUS_PIN, on);
+ return 0;
+}
+
+static int hawk_usb_get_power(unsigned port)
+{
+ return gpio_get_value(DA850_USB1_VBUS_PIN);
+}
+
+static int hawk_usb_get_oci(unsigned port)
+{
+ return !gpio_get_value(DA850_USB1_OC_PIN);
+}
+
+static int hawk_usb_ocic_notify(da8xx_ocic_handler_t handler)
+{
+ int irq = gpio_to_irq(DA850_USB1_OC_PIN);
+ int error = 0;
+
+ if (handler != NULL) {
+ hawk_usb_ocic_handler = handler;
+
+ error = request_irq(irq, omapl138_hawk_usb_ocic_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "OHCI over-current indicator", NULL);
+ if (error)
+ pr_err("%s: could not request IRQ to watch "
+ "over-current indicator changes\n", __func__);
+ } else {
+ free_irq(irq, NULL);
+ }
+ return error;
+}
+
+static struct da8xx_ohci_root_hub omapl138_hawk_usb11_pdata = {
+ .set_power = hawk_usb_set_power,
+ .get_power = hawk_usb_get_power,
+ .get_oci = hawk_usb_get_oci,
+ .ocic_notify = hawk_usb_ocic_notify,
+ /* TPS2087 switch @ 5V */
+ .potpgt = (3 + 1) / 2, /* 3 ms max */
+};
+
+static irqreturn_t omapl138_hawk_usb_ocic_irq(int irq, void *dev_id)
+{
+ hawk_usb_ocic_handler(&omapl138_hawk_usb11_pdata, 1);
+ return IRQ_HANDLED;
+}
+
+static __init void omapl138_hawk_usb_init(void)
+{
+ int ret;
+ u32 cfgchip2;
+
+ ret = davinci_cfg_reg_list(da850_hawk_usb11_pins);
+ if (ret) {
+ pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
+ __func__, ret);
+ return;
+ }
+
+ /* Setup the Ref. clock frequency for the HAWK at 24 MHz. */
+
+ cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+ cfgchip2 &= ~CFGCHIP2_REFFREQ;
+ cfgchip2 |= CFGCHIP2_REFFREQ_24MHZ;
+ __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
+
+ ret = gpio_request_one(DA850_USB1_VBUS_PIN,
+ GPIOF_DIR_OUT, "USB1 VBUS");
+ if (ret < 0) {
+ pr_err("%s: failed to request GPIO for USB 1.1 port "
+ "power control: %d\n", __func__, ret);
+ return;
+ }
+
+ ret = gpio_request_one(DA850_USB1_OC_PIN,
+ GPIOF_DIR_IN, "USB1 OC");
+ if (ret < 0) {
+ pr_err("%s: failed to request GPIO for USB 1.1 port "
+ "over-current indicator: %d\n", __func__, ret);
+ goto usb11_setup_oc_fail;
+ }
+
+ ret = da8xx_register_usb11(&omapl138_hawk_usb11_pdata);
+ if (ret) {
+ pr_warning("%s: USB 1.1 registration failed: %d\n",
+ __func__, ret);
+ goto usb11_setup_fail;
+ }
+
+ return;
+
+usb11_setup_fail:
+ gpio_free(DA850_USB1_OC_PIN);
+usb11_setup_oc_fail:
+ gpio_free(DA850_USB1_VBUS_PIN);
+}
static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
.enabled_uarts = 0x7,
@@ -30,6 +303,17 @@ static __init void omapl138_hawk_init(void)
davinci_serial_init(&omapl138_hawk_uart_config);
+ omapl138_hawk_config_emac();
+
+ ret = da850_register_edma(da850_edma_rsv);
+ if (ret)
+ pr_warning("%s: EDMA registration failed: %d\n",
+ __func__, ret);
+
+ omapl138_hawk_mmc_init();
+
+ omapl138_hawk_usb_init();
+
ret = da8xx_register_watchdog();
if (ret)
pr_warning("omapl138_hawk_init: "
diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c
index a6db85460227..1a656e882262 100644
--- a/arch/arm/mach-davinci/board-tnetv107x-evm.c
+++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c
@@ -25,6 +25,7 @@
#include <linux/mtd/partitions.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
+#include <linux/spi/spi.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -37,6 +38,7 @@
#define EVM_MMC_WP_GPIO 21
#define EVM_MMC_CD_GPIO 24
+#define EVM_SPI_CS_GPIO 54
static int initialize_gpio(int gpio, char *desc)
{
@@ -99,6 +101,12 @@ static const short uart1_pins[] __initdata = {
-1
};
+static const short ssp_pins[] __initdata = {
+ TNETV107X_SSP0_0, TNETV107X_SSP0_1, TNETV107X_SSP0_2,
+ TNETV107X_SSP1_0, TNETV107X_SSP1_1, TNETV107X_SSP1_2,
+ TNETV107X_SSP1_3, -1
+};
+
static struct mtd_partition nand_partitions[] = {
/* bootloader (U-Boot, etc) in first 12 sectors */
{
@@ -196,19 +204,68 @@ static struct matrix_keypad_platform_data keypad_config = {
.no_autorepeat = 0,
};
+static void spi_select_device(int cs)
+{
+ static int gpio;
+
+ if (!gpio) {
+ int ret;
+ ret = gpio_request(EVM_SPI_CS_GPIO, "spi chipsel");
+ if (ret < 0) {
+ pr_err("cannot open spi chipsel gpio\n");
+ gpio = -ENOSYS;
+ return;
+ } else {
+ gpio = EVM_SPI_CS_GPIO;
+ gpio_direction_output(gpio, 0);
+ }
+ }
+
+ if (gpio < 0)
+ return;
+
+ return gpio_set_value(gpio, cs ? 1 : 0);
+}
+
+static struct ti_ssp_spi_data spi_master_data = {
+ .num_cs = 2,
+ .select = spi_select_device,
+ .iosel = SSP_PIN_SEL(0, SSP_CLOCK) | SSP_PIN_SEL(1, SSP_DATA) |
+ SSP_PIN_SEL(2, SSP_CHIPSEL) | SSP_PIN_SEL(3, SSP_IN) |
+ SSP_INPUT_SEL(3),
+};
+
+static struct ti_ssp_data ssp_config = {
+ .out_clock = 250 * 1000,
+ .dev_data = {
+ [1] = {
+ .dev_name = "ti-ssp-spi",
+ .pdata = &spi_master_data,
+ .pdata_size = sizeof(spi_master_data),
+ },
+ },
+};
+
static struct tnetv107x_device_info evm_device_info __initconst = {
.serial_config = &serial_config,
.mmc_config[1] = &mmc_config, /* controller 1 */
.nand_config[0] = &nand_config, /* chip select 0 */
.keypad_config = &keypad_config,
+ .ssp_config = &ssp_config,
+};
+
+static struct spi_board_info spi_info[] __initconst = {
};
static __init void tnetv107x_evm_board_init(void)
{
davinci_cfg_reg_list(sdio1_pins);
davinci_cfg_reg_list(uart1_pins);
+ davinci_cfg_reg_list(ssp_pins);
tnetv107x_devices_init(&evm_device_info);
+
+ spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index ec23ab473620..2ed2f822fc40 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -148,7 +148,7 @@ static struct clk scr2_ss_clk = {
static struct clk dmax_clk = {
.name = "dmax",
.parent = &pll0_sysclk2,
- .lpsc = DA8XX_LPSC0_DMAX,
+ .lpsc = DA8XX_LPSC0_PRUSS,
.flags = ALWAYS_ENABLED,
};
@@ -397,8 +397,8 @@ static struct clk_lookup da830_clks[] = {
CLK(NULL, "uart0", &uart0_clk),
CLK(NULL, "uart1", &uart1_clk),
CLK(NULL, "uart2", &uart2_clk),
- CLK("dm_spi.0", NULL, &spi0_clk),
- CLK("dm_spi.1", NULL, &spi1_clk),
+ CLK("spi_davinci.0", NULL, &spi0_clk),
+ CLK("spi_davinci.1", NULL, &spi1_clk),
CLK(NULL, "ecap0", &ecap0_clk),
CLK(NULL, "ecap1", &ecap1_clk),
CLK(NULL, "ecap2", &ecap2_clk),
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 78b5ae29ae40..68fe4c289d77 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -345,6 +345,34 @@ static struct clk aemif_clk = {
.flags = ALWAYS_ENABLED,
};
+static struct clk usb11_clk = {
+ .name = "usb11",
+ .parent = &pll0_sysclk4,
+ .lpsc = DA8XX_LPSC1_USB11,
+ .gpsc = 1,
+};
+
+static struct clk usb20_clk = {
+ .name = "usb20",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_USB20,
+ .gpsc = 1,
+};
+
+static struct clk spi0_clk = {
+ .name = "spi0",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC0_SPI0,
+};
+
+static struct clk spi1_clk = {
+ .name = "spi1",
+ .parent = &pll0_sysclk2,
+ .lpsc = DA8XX_LPSC1_SPI1,
+ .gpsc = 1,
+ .flags = DA850_CLK_ASYNC3,
+};
+
static struct clk_lookup da850_clks[] = {
CLK(NULL, "ref", &ref_clk),
CLK(NULL, "pll0", &pll0_clk),
@@ -387,6 +415,10 @@ static struct clk_lookup da850_clks[] = {
CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
CLK(NULL, "aemif", &aemif_clk),
+ CLK(NULL, "usb11", &usb11_clk),
+ CLK(NULL, "usb20", &usb20_clk),
+ CLK("spi_davinci.0", NULL, &spi0_clk),
+ CLK("spi_davinci.1", NULL, &spi1_clk),
CLK(NULL, NULL, NULL),
};
@@ -543,30 +575,19 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, EMA_WAIT_1, 6, 24, 15, 1, false)
MUX_CFG(DA850, NEMA_CS_2, 7, 0, 15, 1, false)
/* GPIO function */
+ MUX_CFG(DA850, GPIO2_4, 6, 12, 15, 8, false)
MUX_CFG(DA850, GPIO2_6, 6, 4, 15, 8, false)
MUX_CFG(DA850, GPIO2_8, 5, 28, 15, 8, false)
MUX_CFG(DA850, GPIO2_15, 5, 0, 15, 8, false)
+ MUX_CFG(DA850, GPIO3_12, 7, 12, 15, 8, false)
+ MUX_CFG(DA850, GPIO3_13, 7, 8, 15, 8, false)
MUX_CFG(DA850, GPIO4_0, 10, 28, 15, 8, false)
MUX_CFG(DA850, GPIO4_1, 10, 24, 15, 8, false)
+ MUX_CFG(DA850, GPIO6_13, 13, 8, 15, 8, false)
MUX_CFG(DA850, RTC_ALARM, 0, 28, 15, 2, false)
#endif
};
-const short da850_uart0_pins[] __initdata = {
- DA850_NUART0_CTS, DA850_NUART0_RTS, DA850_UART0_RXD, DA850_UART0_TXD,
- -1
-};
-
-const short da850_uart1_pins[] __initdata = {
- DA850_UART1_RXD, DA850_UART1_TXD,
- -1
-};
-
-const short da850_uart2_pins[] __initdata = {
- DA850_UART2_RXD, DA850_UART2_TXD,
- -1
-};
-
const short da850_i2c0_pins[] __initdata = {
DA850_I2C0_SDA, DA850_I2C0_SCL,
-1
@@ -577,24 +598,6 @@ const short da850_i2c1_pins[] __initdata = {
-1
};
-const short da850_cpgmac_pins[] __initdata = {
- DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
- DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
- DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
- DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
- DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
- DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER,
- DA850_RMII_MHZ_50_CLK,
- -1
-};
-
-const short da850_mcasp_pins[] __initdata = {
- DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
- DA850_AHCLKR, DA850_ACLKR, DA850_AFSR, DA850_AMUTE,
- DA850_AXR_11, DA850_AXR_12,
- -1
-};
-
const short da850_lcdcntl_pins[] __initdata = {
DA850_LCD_D_0, DA850_LCD_D_1, DA850_LCD_D_2, DA850_LCD_D_3,
DA850_LCD_D_4, DA850_LCD_D_5, DA850_LCD_D_6, DA850_LCD_D_7,
@@ -604,29 +607,6 @@ const short da850_lcdcntl_pins[] __initdata = {
-1
};
-const short da850_mmcsd0_pins[] __initdata = {
- DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2,
- DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD,
- DA850_GPIO4_0, DA850_GPIO4_1,
- -1
-};
-
-const short da850_emif25_pins[] __initdata = {
- DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
- DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE,
- DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
- DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
- DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
- DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
- DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3,
- DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7,
- DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11,
- DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15,
- DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19,
- DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23,
- -1
-};
-
/* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */
static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = {
[IRQ_DA8XX_COMMTX] = 7,
@@ -764,6 +744,13 @@ static struct davinci_id da850_ids[] = {
.cpu_id = DAVINCI_CPU_ID_DA850,
.name = "da850/omap-l138",
},
+ {
+ .variant = 0x1,
+ .part_no = 0xb7d1,
+ .manufacturer = 0x017, /* 0x02f >> 1 */
+ .cpu_id = DAVINCI_CPU_ID_DA850,
+ .name = "da850/omap-l138/am18x",
+ },
};
static struct davinci_timer_instance da850_timer_instance[4] = {
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index beda8a4133a0..625d4b66718b 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -38,12 +38,23 @@
#define DA8XX_EMAC_MDIO_BASE 0x01e24000
#define DA8XX_GPIO_BASE 0x01e26000
#define DA8XX_I2C1_BASE 0x01e28000
+#define DA8XX_SPI0_BASE 0x01c41000
+#define DA8XX_SPI1_BASE 0x01f0e000
#define DA8XX_EMAC_CTRL_REG_OFFSET 0x3000
#define DA8XX_EMAC_MOD_REG_OFFSET 0x2000
#define DA8XX_EMAC_RAM_OFFSET 0x0000
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
+#define DA8XX_DMA_SPI0_RX EDMA_CTLR_CHAN(0, 14)
+#define DA8XX_DMA_SPI0_TX EDMA_CTLR_CHAN(0, 15)
+#define DA8XX_DMA_MMCSD0_RX EDMA_CTLR_CHAN(0, 16)
+#define DA8XX_DMA_MMCSD0_TX EDMA_CTLR_CHAN(0, 17)
+#define DA8XX_DMA_SPI1_RX EDMA_CTLR_CHAN(0, 18)
+#define DA8XX_DMA_SPI1_TX EDMA_CTLR_CHAN(0, 19)
+#define DA850_DMA_MMCSD1_RX EDMA_CTLR_CHAN(1, 28)
+#define DA850_DMA_MMCSD1_TX EDMA_CTLR_CHAN(1, 29)
+
void __iomem *da8xx_syscfg0_base;
void __iomem *da8xx_syscfg1_base;
@@ -573,13 +584,13 @@ static struct resource da8xx_mmcsd0_resources[] = {
.flags = IORESOURCE_IRQ,
},
{ /* DMA RX */
- .start = EDMA_CTLR_CHAN(0, 16),
- .end = EDMA_CTLR_CHAN(0, 16),
+ .start = DA8XX_DMA_MMCSD0_RX,
+ .end = DA8XX_DMA_MMCSD0_RX,
.flags = IORESOURCE_DMA,
},
{ /* DMA TX */
- .start = EDMA_CTLR_CHAN(0, 17),
- .end = EDMA_CTLR_CHAN(0, 17),
+ .start = DA8XX_DMA_MMCSD0_TX,
+ .end = DA8XX_DMA_MMCSD0_TX,
.flags = IORESOURCE_DMA,
},
};
@@ -610,13 +621,13 @@ static struct resource da850_mmcsd1_resources[] = {
.flags = IORESOURCE_IRQ,
},
{ /* DMA RX */
- .start = EDMA_CTLR_CHAN(1, 28),
- .end = EDMA_CTLR_CHAN(1, 28),
+ .start = DA850_DMA_MMCSD1_RX,
+ .end = DA850_DMA_MMCSD1_RX,
.flags = IORESOURCE_DMA,
},
{ /* DMA TX */
- .start = EDMA_CTLR_CHAN(1, 29),
- .end = EDMA_CTLR_CHAN(1, 29),
+ .start = DA850_DMA_MMCSD1_TX,
+ .end = DA850_DMA_MMCSD1_TX,
.flags = IORESOURCE_DMA,
},
};
@@ -725,3 +736,101 @@ int __init da8xx_register_cpuidle(void)
return platform_device_register(&da8xx_cpuidle_device);
}
+
+static struct resource da8xx_spi0_resources[] = {
+ [0] = {
+ .start = DA8XX_SPI0_BASE,
+ .end = DA8XX_SPI0_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DA8XX_SPINT0,
+ .end = IRQ_DA8XX_SPINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = DA8XX_DMA_SPI0_RX,
+ .end = DA8XX_DMA_SPI0_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DA8XX_DMA_SPI0_TX,
+ .end = DA8XX_DMA_SPI0_TX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource da8xx_spi1_resources[] = {
+ [0] = {
+ .start = DA8XX_SPI1_BASE,
+ .end = DA8XX_SPI1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DA8XX_SPINT1,
+ .end = IRQ_DA8XX_SPINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = DA8XX_DMA_SPI1_RX,
+ .end = DA8XX_DMA_SPI1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ [3] = {
+ .start = DA8XX_DMA_SPI1_TX,
+ .end = DA8XX_DMA_SPI1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct davinci_spi_platform_data da8xx_spi_pdata[] = {
+ [0] = {
+ .version = SPI_VERSION_2,
+ .intr_line = 1,
+ .dma_event_q = EVENTQ_0,
+ },
+ [1] = {
+ .version = SPI_VERSION_2,
+ .intr_line = 1,
+ .dma_event_q = EVENTQ_0,
+ },
+};
+
+static struct platform_device da8xx_spi_device[] = {
+ [0] = {
+ .name = "spi_davinci",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(da8xx_spi0_resources),
+ .resource = da8xx_spi0_resources,
+ .dev = {
+ .platform_data = &da8xx_spi_pdata[0],
+ },
+ },
+ [1] = {
+ .name = "spi_davinci",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(da8xx_spi1_resources),
+ .resource = da8xx_spi1_resources,
+ .dev = {
+ .platform_data = &da8xx_spi_pdata[1],
+ },
+ },
+};
+
+int __init da8xx_register_spi(int instance, struct spi_board_info *info,
+ unsigned len)
+{
+ int ret;
+
+ if (instance < 0 || instance > 1)
+ return -EINVAL;
+
+ ret = spi_register_board_info(info, len);
+ if (ret)
+ pr_warning("%s: failed to register board info for spi %d :"
+ " %d\n", __func__, instance, ret);
+
+ da8xx_spi_pdata[instance].num_chipselect = len;
+
+ return platform_device_register(&da8xx_spi_device[instance]);
+}
diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index 85503debda51..6162cae7f868 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -35,6 +35,7 @@
#define TNETV107X_SDIO0_BASE 0x08088700
#define TNETV107X_SDIO1_BASE 0x08088800
#define TNETV107X_KEYPAD_BASE 0x08088a00
+#define TNETV107X_SSP_BASE 0x08088c00
#define TNETV107X_ASYNC_EMIF_CNTRL_BASE 0x08200000
#define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE 0x30000000
#define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE 0x40000000
@@ -342,6 +343,25 @@ static struct platform_device tsc_device = {
.resource = tsc_resources,
};
+static struct resource ssp_resources[] = {
+ {
+ .start = TNETV107X_SSP_BASE,
+ .end = TNETV107X_SSP_BASE + 0x1ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_TNETV107X_SSP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ssp_device = {
+ .name = "ti-ssp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ssp_resources),
+ .resource = ssp_resources,
+};
+
void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
{
int i, error;
@@ -380,4 +400,9 @@ void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
keypad_device.dev.platform_data = info->keypad_config;
platform_device_register(&keypad_device);
}
+
+ if (info->ssp_config) {
+ ssp_device.dev.platform_data = info->ssp_config;
+ platform_device_register(&ssp_device);
+ }
}
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index a5f8a80c1f28..76364d1345df 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -403,16 +403,13 @@ static struct resource dm355_spi0_resources[] = {
.start = 16,
.flags = IORESOURCE_DMA,
},
- {
- .start = EVENTQ_1,
- .flags = IORESOURCE_DMA,
- },
};
static struct davinci_spi_platform_data dm355_spi0_pdata = {
.version = SPI_VERSION_1,
.num_chipselect = 2,
.cshold_bug = true,
+ .dma_event_q = EVENTQ_1,
};
static struct platform_device dm355_spi0_device = {
.name = "spi_davinci",
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 02d2cc380df7..4604e72d7d99 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -625,6 +625,7 @@ static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32);
static struct davinci_spi_platform_data dm365_spi0_pdata = {
.version = SPI_VERSION_1,
.num_chipselect = 2,
+ .dma_event_q = EVENTQ_3,
};
static struct resource dm365_spi0_resources[] = {
@@ -645,10 +646,6 @@ static struct resource dm365_spi0_resources[] = {
.start = 16,
.flags = IORESOURCE_DMA,
},
- {
- .start = EVENTQ_3,
- .flags = IORESOURCE_DMA,
- },
};
static struct platform_device dm365_spi0_device = {
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index e7f952066527..e4fc1af8500e 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/davinci_emac.h>
+#include <linux/spi/spi.h>
#include <mach/serial.h>
#include <mach/edma.h>
@@ -23,6 +24,7 @@
#include <mach/mmc.h>
#include <mach/usb.h>
#include <mach/pm.h>
+#include <mach/spi.h>
extern void __iomem *da8xx_syscfg0_base;
extern void __iomem *da8xx_syscfg1_base;
@@ -77,6 +79,7 @@ void __init da850_init(void);
int da830_register_edma(struct edma_rsv_info *rsv);
int da850_register_edma(struct edma_rsv_info *rsv[2]);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
+int da8xx_register_spi(int instance, struct spi_board_info *info, unsigned len);
int da8xx_register_watchdog(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
@@ -95,6 +98,7 @@ extern struct platform_device da8xx_serial_device;
extern struct emac_platform_data da8xx_emac_pdata;
extern struct da8xx_lcdc_platform_data sharp_lcd035q3dg01_pdata;
extern struct da8xx_lcdc_platform_data sharp_lk043t1dg01_pdata;
+extern struct davinci_spi_platform_data da8xx_spi_pdata[];
extern struct platform_device da8xx_wdt_device;
@@ -123,15 +127,8 @@ extern const short da830_ecap2_pins[];
extern const short da830_eqep0_pins[];
extern const short da830_eqep1_pins[];
-extern const short da850_uart0_pins[];
-extern const short da850_uart1_pins[];
-extern const short da850_uart2_pins[];
extern const short da850_i2c0_pins[];
extern const short da850_i2c1_pins[];
-extern const short da850_cpgmac_pins[];
-extern const short da850_mcasp_pins[];
extern const short da850_lcdcntl_pins[];
-extern const short da850_mmcsd0_pins[];
-extern const short da850_emif25_pins[];
#endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index dc10ef6cf572..20c77f29bf0f 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -151,42 +151,6 @@ struct edmacc_param {
#define DA830_DMACH2EVENT_MAP1 0x00000000u
#define DA830_EDMA_ARM_OWN 0x30FFCCFFu
-/* DA830 specific EDMA3 Events Information */
-enum DA830_edma_ch {
- DA830_DMACH_MCASP0_RX,
- DA830_DMACH_MCASP0_TX,
- DA830_DMACH_MCASP1_RX,
- DA830_DMACH_MCASP1_TX,
- DA830_DMACH_MCASP2_RX,
- DA830_DMACH_MCASP2_TX,
- DA830_DMACH_GPIO_BNK0INT,
- DA830_DMACH_GPIO_BNK1INT,
- DA830_DMACH_UART0_RX,
- DA830_DMACH_UART0_TX,
- DA830_DMACH_TMR64P0_EVTOUT12,
- DA830_DMACH_TMR64P0_EVTOUT34,
- DA830_DMACH_UART1_RX,
- DA830_DMACH_UART1_TX,
- DA830_DMACH_SPI0_RX,
- DA830_DMACH_SPI0_TX,
- DA830_DMACH_MMCSD_RX,
- DA830_DMACH_MMCSD_TX,
- DA830_DMACH_SPI1_RX,
- DA830_DMACH_SPI1_TX,
- DA830_DMACH_DMAX_EVTOUT6,
- DA830_DMACH_DMAX_EVTOUT7,
- DA830_DMACH_GPIO_BNK2INT,
- DA830_DMACH_GPIO_BNK3INT,
- DA830_DMACH_I2C0_RX,
- DA830_DMACH_I2C0_TX,
- DA830_DMACH_I2C1_RX,
- DA830_DMACH_I2C1_TX,
- DA830_DMACH_GPIO_BNK4INT,
- DA830_DMACH_GPIO_BNK5INT,
- DA830_DMACH_UART2_RX,
- DA830_DMACH_UART2_TX
-};
-
/*ch_status paramater of callback function possible values*/
#define DMA_COMPLETE 1
#define DMA_CC_ERROR 2
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index de11aac76a80..5d4e0fed828a 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -908,11 +908,15 @@ enum davinci_da850_index {
DA850_NEMA_CS_2,
/* GPIO function */
+ DA850_GPIO2_4,
DA850_GPIO2_6,
DA850_GPIO2_8,
DA850_GPIO2_15,
+ DA850_GPIO3_12,
+ DA850_GPIO3_13,
DA850_GPIO4_0,
DA850_GPIO4_1,
+ DA850_GPIO6_13,
DA850_RTC_ALARM,
};
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 62b0858f68ca..a47e6f29206e 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -150,7 +150,7 @@
#define DA8XX_LPSC0_SCR0_SS 10
#define DA8XX_LPSC0_SCR1_SS 11
#define DA8XX_LPSC0_SCR2_SS 12
-#define DA8XX_LPSC0_DMAX 13
+#define DA8XX_LPSC0_PRUSS 13
#define DA8XX_LPSC0_ARM 14
#define DA8XX_LPSC0_GEM 15
diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h
index 38f4da5ca135..7af305b37868 100644
--- a/arch/arm/mach-davinci/include/mach/spi.h
+++ b/arch/arm/mach-davinci/include/mach/spi.h
@@ -19,6 +19,8 @@
#ifndef __ARCH_ARM_DAVINCI_SPI_H
#define __ARCH_ARM_DAVINCI_SPI_H
+#include <mach/edma.h>
+
#define SPI_INTERN_CS 0xFF
enum {
@@ -39,13 +41,16 @@ enum {
* to populate if all chip-selects are internal.
* @cshold_bug: set this to true if the SPI controller on your chip requires
* a write to CSHOLD bit in between transfers (like in DM355).
+ * @dma_event_q: DMA event queue to use if SPI_IO_TYPE_DMA is used for any
+ * device on the bus.
*/
struct davinci_spi_platform_data {
- u8 version;
- u8 num_chipselect;
- u8 intr_line;
- u8 *chip_sel;
- bool cshold_bug;
+ u8 version;
+ u8 num_chipselect;
+ u8 intr_line;
+ u8 *chip_sel;
+ bool cshold_bug;
+ enum dma_event_q dma_event_q;
};
/**
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 5a681d880dcb..89c1fdc63c0b 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -34,6 +34,7 @@
#include <linux/serial_8250.h>
#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/ti_ssp.h>
#include <mach/mmc.h>
#include <mach/nand.h>
@@ -44,6 +45,7 @@ struct tnetv107x_device_info {
struct davinci_mmc_config *mmc_config[2]; /* 2 controllers */
struct davinci_nand_pdata *nand_config[4]; /* 4 chipsels */
struct matrix_keypad_platform_data *keypad_config;
+ struct ti_ssp_data *ssp_config;
};
extern struct platform_device tnetv107x_wdt_device;
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 6fcdecec8d8c..1b28fdd892a6 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -278,7 +278,7 @@ static struct clk_lookup clks[] = {
CLK(NULL, "timer1", &clk_timer1),
CLK("tnetv107x_wdt.0", NULL, &clk_wdt_arm),
CLK(NULL, "clk_wdt_dsp", &clk_wdt_dsp),
- CLK("ti-ssp.0", NULL, &clk_ssp),
+ CLK("ti-ssp", NULL, &clk_ssp),
CLK(NULL, "clk_tdm0", &clk_tdm0),
CLK(NULL, "clk_vlynq", &clk_vlynq),
CLK(NULL, "clk_mcdma", &clk_mcdma),
diff --git a/arch/arm/mach-dove/cm-a510.c b/arch/arm/mach-dove/cm-a510.c
index 96e0e94e5fa9..03e11f9dca97 100644
--- a/arch/arm/mach-dove/cm-a510.c
+++ b/arch/arm/mach-dove/cm-a510.c
@@ -90,6 +90,7 @@ MACHINE_START(CM_A510, "Compulab CM-A510 Board")
.boot_params = 0x00000100,
.init_machine = cm_a510_init,
.map_io = dove_map_io,
+ .init_early = dove_init_early,
.init_irq = dove_init_irq,
.timer = &dove_timer,
MACHINE_END
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index fe627aba6da7..e06a88f1f81d 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -532,6 +532,11 @@ void __init dove_i2c_init(void)
/*****************************************************************************
* Time handling
****************************************************************************/
+void __init dove_init_early(void)
+{
+ orion_time_set_base(TIMER_VIRT_BASE);
+}
+
static int get_tclk(void)
{
/* use DOVE_RESET_SAMPLE_HI/LO to detect tclk */
@@ -540,7 +545,8 @@ static int get_tclk(void)
static void dove_timer_init(void)
{
- orion_time_init(IRQ_DOVE_BRIDGE, get_tclk());
+ orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
+ IRQ_DOVE_BRIDGE, get_tclk());
}
struct sys_timer dove_timer = {
diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h
index a51517c3fe76..6a2046e44706 100644
--- a/arch/arm/mach-dove/common.h
+++ b/arch/arm/mach-dove/common.h
@@ -22,6 +22,7 @@ extern struct mbus_dram_target_info dove_mbus_dram_info;
*/
void dove_map_io(void);
void dove_init(void);
+void dove_init_early(void);
void dove_init_irq(void);
void dove_setup_cpu_mbus(void);
void dove_ge00_init(struct mv643xx_eth_platform_data *eth_data);
diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c
index 95925aa76dd9..2ac34ecfa745 100644
--- a/arch/arm/mach-dove/dove-db-setup.c
+++ b/arch/arm/mach-dove/dove-db-setup.c
@@ -97,6 +97,7 @@ MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
.boot_params = 0x00000100,
.init_machine = dove_db_init,
.map_io = dove_map_io,
+ .init_early = dove_init_early,
.init_irq = dove_init_irq,
.timer = &dove_timer,
MACHINE_END
diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h
index 214a4c31f069..226949dc4ac0 100644
--- a/arch/arm/mach-dove/include/mach/bridge-regs.h
+++ b/arch/arm/mach-dove/include/mach/bridge-regs.h
@@ -26,10 +26,6 @@
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE | 0x010c)
#define SOFT_RESET 0x00000001
-#define BRIDGE_CAUSE (BRIDGE_VIRT_BASE | 0x0110)
-#define BRIDGE_MASK (BRIDGE_VIRT_BASE | 0x0114)
-#define BRIDGE_INT_TIMER0 0x0002
-#define BRIDGE_INT_TIMER1 0x0004
#define BRIDGE_INT_TIMER1_CLR (~0x0004)
#define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0200)
diff --git a/arch/arm/mach-dove/include/mach/dove.h b/arch/arm/mach-dove/include/mach/dove.h
index 27b414578f2e..e5fcdd3f5bf5 100644
--- a/arch/arm/mach-dove/include/mach/dove.h
+++ b/arch/arm/mach-dove/include/mach/dove.h
@@ -130,7 +130,8 @@
#define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10)
#define DOVE_RESET_SAMPLE_LO (DOVE_MPP_VIRT_BASE | 0x014)
#define DOVE_RESET_SAMPLE_HI (DOVE_MPP_VIRT_BASE | 0x018)
-#define DOVE_GPIO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xd0400)
+#define DOVE_GPIO_LO_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xd0400)
+#define DOVE_GPIO_HI_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xd0420)
#define DOVE_GPIO2_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xe8400)
#define DOVE_MPP_GENERAL_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE | 0xe803c)
#define DOVE_AU1_SPDIFO_GPIO_EN (1 << 1)
diff --git a/arch/arm/mach-dove/include/mach/gpio.h b/arch/arm/mach-dove/include/mach/gpio.h
index 340bb7af529d..e7e5101e35a5 100644
--- a/arch/arm/mach-dove/include/mach/gpio.h
+++ b/arch/arm/mach-dove/include/mach/gpio.h
@@ -6,46 +6,4 @@
* warranty of any kind, whether express or implied.
*/
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <asm/errno.h>
-#include <mach/irqs.h>
#include <plat/gpio.h>
-#include <asm-generic/gpio.h> /* cansleep wrappers */
-
-#define GPIO_MAX 72
-
-#define GPIO_BASE_LO (DOVE_GPIO_VIRT_BASE + 0x00)
-#define GPIO_BASE_HI (DOVE_GPIO_VIRT_BASE + 0x20)
-
-#define GPIO_BASE(pin) ((pin < 32) ? GPIO_BASE_LO : \
- ((pin < 64) ? GPIO_BASE_HI : \
- DOVE_GPIO2_VIRT_BASE))
-
-#define GPIO_OUT(pin) (GPIO_BASE(pin) + 0x00)
-#define GPIO_IO_CONF(pin) (GPIO_BASE(pin) + 0x04)
-#define GPIO_BLINK_EN(pin) (GPIO_BASE(pin) + 0x08)
-#define GPIO_IN_POL(pin) (GPIO_BASE(pin) + 0x0c)
-#define GPIO_DATA_IN(pin) (GPIO_BASE(pin) + 0x10)
-#define GPIO_EDGE_CAUSE(pin) (GPIO_BASE(pin) + 0x14)
-#define GPIO_EDGE_MASK(pin) (GPIO_BASE(pin) + 0x18)
-#define GPIO_LEVEL_MASK(pin) (GPIO_BASE(pin) + 0x1c)
-
-static inline int gpio_to_irq(int pin)
-{
- if (pin < NR_GPIO_IRQS)
- return pin + IRQ_DOVE_GPIO_START;
-
- return -EINVAL;
-}
-
-static inline int irq_to_gpio(int irq)
-{
- if (IRQ_DOVE_GPIO_START < irq && irq < NR_IRQS)
- return irq - IRQ_DOVE_GPIO_START;
-
- return -EINVAL;
-}
-
-#endif
diff --git a/arch/arm/mach-dove/include/mach/irqs.h b/arch/arm/mach-dove/include/mach/irqs.h
index 46681466f92b..03d401d20453 100644
--- a/arch/arm/mach-dove/include/mach/irqs.h
+++ b/arch/arm/mach-dove/include/mach/irqs.h
@@ -92,10 +92,5 @@
#define NR_IRQS (IRQ_DOVE_PMU_START + NR_PMU_IRQS)
-/* Required for compatability with PXA AC97 driver. */
-#define IRQ_AC97 IRQ_DOVE_AC97
-/* Required for compatability with PXA DMA driver. */
-#define IRQ_DMA IRQ_DOVE_PDMA
-/* Required for compatability with PXA NAND driver */
-#define IRQ_NAND IRQ_DOVE_NAND
+
#endif
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
index 9317f0558b57..101707fa2e2c 100644
--- a/arch/arm/mach-dove/irq.c
+++ b/arch/arm/mach-dove/irq.c
@@ -99,11 +99,21 @@ void __init dove_init_irq(void)
orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
/*
- * Mask and clear GPIO IRQ interrupts.
+ * Initialize gpiolib for GPIOs 0-71.
*/
- writel(0, GPIO_LEVEL_MASK(0));
- writel(0, GPIO_EDGE_MASK(0));
- writel(0, GPIO_EDGE_CAUSE(0));
+ orion_gpio_init(0, 32, DOVE_GPIO_LO_VIRT_BASE, 0,
+ IRQ_DOVE_GPIO_START);
+ set_irq_chained_handler(IRQ_DOVE_GPIO_0_7, gpio_irq_handler);
+ set_irq_chained_handler(IRQ_DOVE_GPIO_8_15, gpio_irq_handler);
+ set_irq_chained_handler(IRQ_DOVE_GPIO_16_23, gpio_irq_handler);
+ set_irq_chained_handler(IRQ_DOVE_GPIO_24_31, gpio_irq_handler);
+
+ orion_gpio_init(32, 32, DOVE_GPIO_HI_VIRT_BASE, 0,
+ IRQ_DOVE_GPIO_START + 32);
+ set_irq_chained_handler(IRQ_DOVE_HIGH_GPIO, gpio_irq_handler);
+
+ orion_gpio_init(64, 8, DOVE_GPIO2_VIRT_BASE, 0,
+ IRQ_DOVE_GPIO_START + 64);
/*
* Mask and clear PMU interrupts
@@ -111,18 +121,6 @@ void __init dove_init_irq(void)
writel(0, PMU_INTERRUPT_MASK);
writel(0, PMU_INTERRUPT_CAUSE);
- for (i = IRQ_DOVE_GPIO_START; i < IRQ_DOVE_PMU_START; i++) {
- set_irq_chip(i, &orion_gpio_irq_chip);
- set_irq_handler(i, handle_level_irq);
- irq_desc[i].status |= IRQ_LEVEL;
- set_irq_flags(i, IRQF_VALID);
- }
- set_irq_chained_handler(IRQ_DOVE_GPIO_0_7, gpio_irq_handler);
- set_irq_chained_handler(IRQ_DOVE_GPIO_8_15, gpio_irq_handler);
- set_irq_chained_handler(IRQ_DOVE_GPIO_16_23, gpio_irq_handler);
- set_irq_chained_handler(IRQ_DOVE_GPIO_24_31, gpio_irq_handler);
- set_irq_chained_handler(IRQ_DOVE_HIGH_GPIO, gpio_irq_handler);
-
for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) {
set_irq_chip(i, &pmu_irq_chip);
set_irq_handler(i, handle_level_irq);
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
new file mode 100644
index 000000000000..a021b5240bba
--- /dev/null
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -0,0 +1,195 @@
+# arch/arm/mach-exynos4/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+# Configuration options for the EXYNOS4
+
+if ARCH_EXYNOS4
+
+config CPU_EXYNOS4210
+ bool
+ select S3C_PL330_DMA
+ help
+ Enable EXYNOS4210 CPU support
+
+config EXYNOS4_MCT
+ bool "Kernel timer support by MCT"
+ help
+ Use MCT (Multi Core Timer) as kernel timers
+
+config EXYNOS4_DEV_PD
+ bool
+ help
+ Compile in platform device definitions for Power Domain
+
+config EXYNOS4_DEV_SYSMMU
+ bool
+ help
+ Common setup code for SYSTEM MMU in EXYNOS4
+
+config EXYNOS4_SETUP_I2C1
+ bool
+ help
+ Common setup code for i2c bus 1.
+
+config EXYNOS4_SETUP_I2C2
+ bool
+ help
+ Common setup code for i2c bus 2.
+
+config EXYNOS4_SETUP_I2C3
+ bool
+ help
+ Common setup code for i2c bus 3.
+
+config EXYNOS4_SETUP_I2C4
+ bool
+ help
+ Common setup code for i2c bus 4.
+
+config EXYNOS4_SETUP_I2C5
+ bool
+ help
+ Common setup code for i2c bus 5.
+
+config EXYNOS4_SETUP_I2C6
+ bool
+ help
+ Common setup code for i2c bus 6.
+
+config EXYNOS4_SETUP_I2C7
+ bool
+ help
+ Common setup code for i2c bus 7.
+
+config EXYNOS4_SETUP_KEYPAD
+ bool
+ help
+ Common setup code for keypad.
+
+config EXYNOS4_SETUP_SDHCI
+ bool
+ select EXYNOS4_SETUP_SDHCI_GPIO
+ help
+ Internal helper functions for EXYNOS4 based SDHCI systems.
+
+config EXYNOS4_SETUP_SDHCI_GPIO
+ bool
+ help
+ Common setup code for SDHCI gpio.
+
+config EXYNOS4_SETUP_FIMC
+ bool
+ help
+ Common setup code for the camera interfaces.
+
+# machine support
+
+menu "EXYNOS4 Machines"
+
+config MACH_SMDKC210
+ bool "SMDKC210"
+ select CPU_EXYNOS4210
+ select S3C_DEV_RTC
+ select S3C_DEV_WDT
+ select S3C_DEV_I2C1
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC1
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select EXYNOS4_DEV_PD
+ select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_SETUP_I2C1
+ select EXYNOS4_SETUP_SDHCI
+ help
+ Machine support for Samsung SMDKC210
+
+config MACH_SMDKV310
+ bool "SMDKV310"
+ select CPU_EXYNOS4210
+ select S3C_DEV_RTC
+ select S3C_DEV_WDT
+ select S3C_DEV_I2C1
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC1
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select SAMSUNG_DEV_KEYPAD
+ select EXYNOS4_DEV_PD
+ select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_SETUP_I2C1
+ select EXYNOS4_SETUP_KEYPAD
+ select EXYNOS4_SETUP_SDHCI
+ help
+ Machine support for Samsung SMDKV310
+
+config MACH_ARMLEX4210
+ bool "ARMLEX4210"
+ select CPU_EXYNOS4210
+ select S3C_DEV_RTC
+ select S3C_DEV_WDT
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select EXYNOS4_DEV_SYSMMU
+ select EXYNOS4_SETUP_SDHCI
+ select SATA_AHCI_PLATFORM
+ help
+ Machine support for Samsung ARMLEX4210 based on EXYNOS4210
+
+config MACH_UNIVERSAL_C210
+ bool "Mobile UNIVERSAL_C210 Board"
+ select CPU_EXYNOS4210
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select S3C_DEV_I2C1
+ select S3C_DEV_I2C5
+ select S5P_DEV_ONENAND
+ select EXYNOS4_SETUP_I2C1
+ select EXYNOS4_SETUP_I2C5
+ select EXYNOS4_SETUP_SDHCI
+ help
+ Machine support for Samsung Mobile Universal S5PC210 Reference
+ Board.
+
+config MACH_NURI
+ bool "Mobile NURI Board"
+ select CPU_EXYNOS4210
+ select S3C_DEV_WDT
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select S3C_DEV_I2C1
+ select S3C_DEV_I2C5
+ select EXYNOS4_SETUP_I2C1
+ select EXYNOS4_SETUP_I2C5
+ select EXYNOS4_SETUP_SDHCI
+ select SAMSUNG_DEV_PWM
+ help
+ Machine support for Samsung Mobile NURI Board.
+
+endmenu
+
+comment "Configuration for HSMMC bus width"
+
+menu "Use 8-bit bus width"
+
+config EXYNOS4_SDHCI_CH0_8BIT
+ bool "Channel 0 with 8-bit bus"
+ help
+ Support HSMMC Channel 0 8-bit bus.
+ If selected, Channel 1 is disabled.
+
+config EXYNOS4_SDHCI_CH2_8BIT
+ bool "Channel 2 with 8-bit bus"
+ help
+ Support HSMMC Channel 2 8-bit bus.
+ If selected, Channel 3 is disabled.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
new file mode 100644
index 000000000000..b8f0e7d82d7e
--- /dev/null
+++ b/arch/arm/mach-exynos4/Makefile
@@ -0,0 +1,56 @@
+# arch/arm/mach-exynos4/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+# Core support for EXYNOS4 system
+
+obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o
+obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o gpiolib.o irq-eint.o dma.o
+obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
+
+ifeq ($(CONFIG_EXYNOS4_MCT),y)
+obj-y += mct.o
+else
+obj-y += time.o
+obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
+endif
+
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+
+# machine support
+
+obj-$(CONFIG_MACH_SMDKC210) += mach-smdkc210.o
+obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o
+obj-$(CONFIG_MACH_ARMLEX4210) += mach-armlex4210.o
+obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
+obj-$(CONFIG_MACH_NURI) += mach-nuri.o
+
+# device support
+
+obj-y += dev-audio.o
+obj-$(CONFIG_EXYNOS4_DEV_PD) += dev-pd.o
+obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
+
+obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C1) += setup-i2c1.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C2) += setup-i2c2.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C3) += setup-i2c3.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C4) += setup-i2c4.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C5) += setup-i2c5.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C6) += setup-i2c6.o
+obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
+obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
+obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o
+obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += dev-ahci.o
diff --git a/arch/arm/mach-s5pv310/Makefile.boot b/arch/arm/mach-exynos4/Makefile.boot
index d65956ffb43d..d65956ffb43d 100644
--- a/arch/arm/mach-s5pv310/Makefile.boot
+++ b/arch/arm/mach-exynos4/Makefile.boot
diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-exynos4/clock.c
index fc7c2f8d165e..871f9d508fde 100644
--- a/arch/arm/mach-s5pv310/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/clock.c
+/* linux/arch/arm/mach-exynos4/clock.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Clock support
+ * EXYNOS4 - Clock support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,6 +23,7 @@
#include <mach/map.h>
#include <mach/regs-clock.h>
+#include <mach/sysmmu.h>
static struct clk clk_sclk_hdmi27m = {
.name = "sclk_hdmi27m",
@@ -46,72 +47,82 @@ static struct clk clk_sclk_usbphy1 = {
.id = -1,
};
-static int s5pv310_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
}
-static int s5pv310_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable);
}
-static int s5pv310_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable);
}
-static int s5pv310_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable);
}
-static int s5pv310_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable);
}
-static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable);
}
-static int s5pv310_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
+static int exynos4_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable);
}
-static int s5pv310_clk_ip_cam_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_mfc_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(S5P_CLKGATE_IP_MFC, clk, enable);
+}
+
+static int exynos4_clk_ip_cam_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable);
}
-static int s5pv310_clk_ip_image_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(S5P_CLKGATE_IP_TV, clk, enable);
+}
+
+static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable);
}
-static int s5pv310_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable);
}
-static int s5pv310_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable);
}
-static int s5pv310_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable);
}
-static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_peril_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
}
-static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable)
+static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
}
@@ -358,7 +369,7 @@ static struct clksrc_clk clk_vpllsrc = {
.clk = {
.name = "vpll_src",
.id = -1,
- .enable = s5pv310_clksrc_mask_top_ctrl,
+ .enable = exynos4_clksrc_mask_top_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_vpllsrc,
@@ -389,239 +400,322 @@ static struct clk init_clocks_off[] = {
.name = "timers",
.id = -1,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1<<24),
}, {
.name = "csis",
.id = 0,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 4),
}, {
.name = "csis",
.id = 1,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 5),
}, {
.name = "fimc",
.id = 0,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "fimc",
.id = 1,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 1),
}, {
.name = "fimc",
.id = 2,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 2),
}, {
.name = "fimc",
.id = 3,
- .enable = s5pv310_clk_ip_cam_ctrl,
+ .enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 3),
}, {
.name = "fimd",
.id = 0,
- .enable = s5pv310_clk_ip_lcd0_ctrl,
+ .enable = exynos4_clk_ip_lcd0_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "fimd",
.id = 1,
- .enable = s5pv310_clk_ip_lcd1_ctrl,
+ .enable = exynos4_clk_ip_lcd1_ctrl,
.ctrlbit = (1 << 0),
}, {
+ .name = "sataphy",
+ .id = -1,
+ .parent = &clk_aclk_133.clk,
+ .enable = exynos4_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 3),
+ }, {
.name = "hsmmc",
.id = 0,
.parent = &clk_aclk_133.clk,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 5),
}, {
.name = "hsmmc",
.id = 1,
.parent = &clk_aclk_133.clk,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 6),
}, {
.name = "hsmmc",
.id = 2,
.parent = &clk_aclk_133.clk,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 7),
}, {
.name = "hsmmc",
.id = 3,
.parent = &clk_aclk_133.clk,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 8),
}, {
.name = "hsmmc",
.id = 4,
.parent = &clk_aclk_133.clk,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 9),
}, {
.name = "sata",
.id = -1,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .parent = &clk_aclk_133.clk,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 10),
}, {
.name = "pdma",
.id = 0,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "pdma",
.id = 1,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 1),
}, {
.name = "adc",
.id = -1,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 15),
}, {
+ .name = "keypad",
+ .id = -1,
+ .enable = exynos4_clk_ip_perir_ctrl,
+ .ctrlbit = (1 << 16),
+ }, {
.name = "rtc",
.id = -1,
- .enable = s5pv310_clk_ip_perir_ctrl,
+ .enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 15),
}, {
.name = "watchdog",
.id = -1,
- .enable = s5pv310_clk_ip_perir_ctrl,
+ .parent = &clk_aclk_100.clk,
+ .enable = exynos4_clk_ip_perir_ctrl,
.ctrlbit = (1 << 14),
}, {
.name = "usbhost",
.id = -1,
- .enable = s5pv310_clk_ip_fsys_ctrl ,
+ .enable = exynos4_clk_ip_fsys_ctrl ,
.ctrlbit = (1 << 12),
}, {
.name = "otg",
.id = -1,
- .enable = s5pv310_clk_ip_fsys_ctrl,
+ .enable = exynos4_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 13),
}, {
.name = "spi",
.id = 0,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 16),
}, {
.name = "spi",
.id = 1,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 17),
}, {
.name = "spi",
.id = 2,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 18),
}, {
.name = "iis",
.id = 0,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 19),
}, {
.name = "iis",
.id = 1,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 20),
}, {
.name = "iis",
.id = 2,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 21),
}, {
.name = "ac97",
.id = -1,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 27),
}, {
.name = "fimg2d",
.id = -1,
- .enable = s5pv310_clk_ip_image_ctrl,
+ .enable = exynos4_clk_ip_image_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "i2c",
.id = 0,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 6),
}, {
.name = "i2c",
.id = 1,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 7),
}, {
.name = "i2c",
.id = 2,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 8),
}, {
.name = "i2c",
.id = 3,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 9),
}, {
.name = "i2c",
.id = 4,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 10),
}, {
.name = "i2c",
.id = 5,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 11),
}, {
.name = "i2c",
.id = 6,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 12),
}, {
.name = "i2c",
.id = 7,
.parent = &clk_aclk_100.clk,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 13),
- },
+ }, {
+ .name = "SYSMMU_MDMA",
+ .id = -1,
+ .enable = exynos4_clk_ip_image_ctrl,
+ .ctrlbit = (1 << 5),
+ }, {
+ .name = "SYSMMU_FIMC0",
+ .id = -1,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 7),
+ }, {
+ .name = "SYSMMU_FIMC1",
+ .id = -1,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 8),
+ }, {
+ .name = "SYSMMU_FIMC2",
+ .id = -1,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 9),
+ }, {
+ .name = "SYSMMU_FIMC3",
+ .id = -1,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 10),
+ }, {
+ .name = "SYSMMU_JPEG",
+ .id = -1,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 11),
+ }, {
+ .name = "SYSMMU_FIMD0",
+ .id = -1,
+ .enable = exynos4_clk_ip_lcd0_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = "SYSMMU_FIMD1",
+ .id = -1,
+ .enable = exynos4_clk_ip_lcd1_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = "SYSMMU_PCIe",
+ .id = -1,
+ .enable = exynos4_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 18),
+ }, {
+ .name = "SYSMMU_G2D",
+ .id = -1,
+ .enable = exynos4_clk_ip_image_ctrl,
+ .ctrlbit = (1 << 3),
+ }, {
+ .name = "SYSMMU_ROTATOR",
+ .id = -1,
+ .enable = exynos4_clk_ip_image_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = "SYSMMU_TV",
+ .id = -1,
+ .enable = exynos4_clk_ip_tv_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = "SYSMMU_MFC_L",
+ .id = -1,
+ .enable = exynos4_clk_ip_mfc_ctrl,
+ .ctrlbit = (1 << 1),
+ }, {
+ .name = "SYSMMU_MFC_R",
+ .id = -1,
+ .enable = exynos4_clk_ip_mfc_ctrl,
+ .ctrlbit = (1 << 2),
+ }
};
static struct clk init_clocks[] = {
{
.name = "uart",
.id = 0,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "uart",
.id = 1,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 1),
}, {
.name = "uart",
.id = 2,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 2),
}, {
.name = "uart",
.id = 3,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 3),
}, {
.name = "uart",
.id = 4,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 4),
}, {
.name = "uart",
.id = 5,
- .enable = s5pv310_clk_ip_peril_ctrl,
+ .enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 5),
}
};
@@ -746,7 +840,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "uclk1",
.id = 0,
- .enable = s5pv310_clksrc_mask_peril0_ctrl,
+ .enable = exynos4_clksrc_mask_peril0_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_group,
@@ -756,7 +850,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "uclk1",
.id = 1,
- .enable = s5pv310_clksrc_mask_peril0_ctrl,
+ .enable = exynos4_clksrc_mask_peril0_ctrl,
.ctrlbit = (1 << 4),
},
.sources = &clkset_group,
@@ -766,7 +860,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "uclk1",
.id = 2,
- .enable = s5pv310_clksrc_mask_peril0_ctrl,
+ .enable = exynos4_clksrc_mask_peril0_ctrl,
.ctrlbit = (1 << 8),
},
.sources = &clkset_group,
@@ -776,7 +870,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "uclk1",
.id = 3,
- .enable = s5pv310_clksrc_mask_peril0_ctrl,
+ .enable = exynos4_clksrc_mask_peril0_ctrl,
.ctrlbit = (1 << 12),
},
.sources = &clkset_group,
@@ -786,7 +880,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_pwm",
.id = -1,
- .enable = s5pv310_clksrc_mask_peril0_ctrl,
+ .enable = exynos4_clksrc_mask_peril0_ctrl,
.ctrlbit = (1 << 24),
},
.sources = &clkset_group,
@@ -796,7 +890,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_csis",
.id = 0,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 24),
},
.sources = &clkset_group,
@@ -806,7 +900,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_csis",
.id = 1,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 28),
},
.sources = &clkset_group,
@@ -816,7 +910,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_cam",
.id = 0,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 16),
},
.sources = &clkset_group,
@@ -826,7 +920,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_cam",
.id = 1,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 20),
},
.sources = &clkset_group,
@@ -836,7 +930,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimc",
.id = 0,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_group,
@@ -846,7 +940,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimc",
.id = 1,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 4),
},
.sources = &clkset_group,
@@ -856,7 +950,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimc",
.id = 2,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 8),
},
.sources = &clkset_group,
@@ -866,7 +960,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimc",
.id = 3,
- .enable = s5pv310_clksrc_mask_cam_ctrl,
+ .enable = exynos4_clksrc_mask_cam_ctrl,
.ctrlbit = (1 << 12),
},
.sources = &clkset_group,
@@ -876,7 +970,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimd",
.id = 0,
- .enable = s5pv310_clksrc_mask_lcd0_ctrl,
+ .enable = exynos4_clksrc_mask_lcd0_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_group,
@@ -886,7 +980,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_fimd",
.id = 1,
- .enable = s5pv310_clksrc_mask_lcd1_ctrl,
+ .enable = exynos4_clksrc_mask_lcd1_ctrl,
.ctrlbit = (1 << 0),
},
.sources = &clkset_group,
@@ -896,7 +990,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_sata",
.id = -1,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 24),
},
.sources = &clkset_mout_corebus,
@@ -906,7 +1000,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_spi",
.id = 0,
- .enable = s5pv310_clksrc_mask_peril1_ctrl,
+ .enable = exynos4_clksrc_mask_peril1_ctrl,
.ctrlbit = (1 << 16),
},
.sources = &clkset_group,
@@ -916,7 +1010,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_spi",
.id = 1,
- .enable = s5pv310_clksrc_mask_peril1_ctrl,
+ .enable = exynos4_clksrc_mask_peril1_ctrl,
.ctrlbit = (1 << 20),
},
.sources = &clkset_group,
@@ -926,7 +1020,7 @@ static struct clksrc_clk clksrcs[] = {
.clk = {
.name = "sclk_spi",
.id = 2,
- .enable = s5pv310_clksrc_mask_peril1_ctrl,
+ .enable = exynos4_clksrc_mask_peril1_ctrl,
.ctrlbit = (1 << 24),
},
.sources = &clkset_group,
@@ -945,7 +1039,7 @@ static struct clksrc_clk clksrcs[] = {
.name = "sclk_mmc",
.id = 0,
.parent = &clk_dout_mmc0.clk,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 0),
},
.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
@@ -954,7 +1048,7 @@ static struct clksrc_clk clksrcs[] = {
.name = "sclk_mmc",
.id = 1,
.parent = &clk_dout_mmc1.clk,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 4),
},
.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
@@ -963,7 +1057,7 @@ static struct clksrc_clk clksrcs[] = {
.name = "sclk_mmc",
.id = 2,
.parent = &clk_dout_mmc2.clk,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 8),
},
.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
@@ -972,7 +1066,7 @@ static struct clksrc_clk clksrcs[] = {
.name = "sclk_mmc",
.id = 3,
.parent = &clk_dout_mmc3.clk,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 12),
},
.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
@@ -981,7 +1075,7 @@ static struct clksrc_clk clksrcs[] = {
.name = "sclk_mmc",
.id = 4,
.parent = &clk_dout_mmc4.clk,
- .enable = s5pv310_clksrc_mask_fsys_ctrl,
+ .enable = exynos4_clksrc_mask_fsys_ctrl,
.ctrlbit = (1 << 16),
},
.reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 },
@@ -1022,16 +1116,16 @@ static struct clksrc_clk *sysclks[] = {
static int xtal_rate;
-static unsigned long s5pv310_fout_apll_get_rate(struct clk *clk)
+static unsigned long exynos4_fout_apll_get_rate(struct clk *clk)
{
return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0), pll_4508);
}
-static struct clk_ops s5pv310_fout_apll_ops = {
- .get_rate = s5pv310_fout_apll_get_rate,
+static struct clk_ops exynos4_fout_apll_ops = {
+ .get_rate = exynos4_fout_apll_get_rate,
};
-void __init_or_cpufreq s5pv310_setup_clocks(void)
+void __init_or_cpufreq exynos4_setup_clocks(void)
{
struct clk *xtal_clk;
unsigned long apll;
@@ -1070,12 +1164,12 @@ void __init_or_cpufreq s5pv310_setup_clocks(void)
vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
__raw_readl(S5P_VPLL_CON1), pll_4650);
- clk_fout_apll.ops = &s5pv310_fout_apll_ops;
+ clk_fout_apll.ops = &exynos4_fout_apll_ops;
clk_fout_mpll.rate = mpll;
clk_fout_epll.rate = epll;
clk_fout_vpll.rate = vpll;
- printk(KERN_INFO "S5PV310: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
+ printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
apll, mpll, epll, vpll);
armclk = clk_get_rate(&clk_armclk.clk);
@@ -1086,7 +1180,7 @@ void __init_or_cpufreq s5pv310_setup_clocks(void)
aclk_160 = clk_get_rate(&clk_aclk_160.clk);
aclk_133 = clk_get_rate(&clk_aclk_133.clk);
- printk(KERN_INFO "S5PV310: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
+ printk(KERN_INFO "EXYNOS4: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
"ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
armclk, sclk_dmc, aclk_200,
aclk_100, aclk_160, aclk_133);
@@ -1103,7 +1197,7 @@ static struct clk *clks[] __initdata = {
/* Nothing here yet */
};
-void __init s5pv310_register_clocks(void)
+void __init exynos4_register_clocks(void)
{
int ptr;
diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 0db0fb65bd70..793011391943 100644
--- a/arch/arm/mach-s5pv310/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/cpu.c
+/* linux/arch/arm/mach-exynos4/cpu.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,8 +19,10 @@
#include <plat/cpu.h>
#include <plat/clock.h>
-#include <plat/s5pv310.h>
+#include <plat/exynos4.h>
#include <plat/sdhci.h>
+#include <plat/devs.h>
+#include <plat/fimc-core.h>
#include <mach/regs-irq.h>
@@ -29,55 +31,60 @@ extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
/* Initial IO mappings */
-static struct map_desc s5pv310_iodesc[] __initdata = {
+static struct map_desc exynos4_iodesc[] __initdata = {
{
+ .virtual = (unsigned long)S5P_VA_SYSTIMER,
+ .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
.virtual = (unsigned long)S5P_VA_SYSRAM,
- .pfn = __phys_to_pfn(S5PV310_PA_SYSRAM),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_CMU,
- .pfn = __phys_to_pfn(S5PV310_PA_CMU),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
.length = SZ_128K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_PMU,
- .pfn = __phys_to_pfn(S5PV310_PA_PMU),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_PMU),
.length = SZ_64K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_COMBINER_BASE,
- .pfn = __phys_to_pfn(S5PV310_PA_COMBINER),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_COREPERI_BASE,
- .pfn = __phys_to_pfn(S5PV310_PA_COREPERI),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI),
.length = SZ_8K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_L2CC,
- .pfn = __phys_to_pfn(S5PV310_PA_L2CC),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_GPIO1,
- .pfn = __phys_to_pfn(S5PV310_PA_GPIO1),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO1),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_GPIO2,
- .pfn = __phys_to_pfn(S5PV310_PA_GPIO2),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO2),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_GPIO3,
- .pfn = __phys_to_pfn(S5PV310_PA_GPIO3),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO3),
.length = SZ_256,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_DMC0,
- .pfn = __phys_to_pfn(S5PV310_PA_DMC0),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
@@ -87,13 +94,13 @@ static struct map_desc s5pv310_iodesc[] __initdata = {
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_SROMC,
- .pfn = __phys_to_pfn(S5PV310_PA_SROMC),
+ .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
.length = SZ_4K,
.type = MT_DEVICE,
},
};
-static void s5pv310_idle(void)
+static void exynos4_idle(void)
{
if (!need_resched())
cpu_do_idle();
@@ -101,32 +108,38 @@ static void s5pv310_idle(void)
local_irq_enable();
}
-/* s5pv310_map_io
+/*
+ * exynos4_map_io
*
* register the standard cpu IO areas
-*/
-void __init s5pv310_map_io(void)
+ */
+void __init exynos4_map_io(void)
{
- iotable_init(s5pv310_iodesc, ARRAY_SIZE(s5pv310_iodesc));
+ iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
/* initialize device information early */
- s5pv310_default_sdhci0();
- s5pv310_default_sdhci1();
- s5pv310_default_sdhci2();
- s5pv310_default_sdhci3();
+ exynos4_default_sdhci0();
+ exynos4_default_sdhci1();
+ exynos4_default_sdhci2();
+ exynos4_default_sdhci3();
+
+ s3c_fimc_setname(0, "exynos4-fimc");
+ s3c_fimc_setname(1, "exynos4-fimc");
+ s3c_fimc_setname(2, "exynos4-fimc");
+ s3c_fimc_setname(3, "exynos4-fimc");
}
-void __init s5pv310_init_clocks(int xtal)
+void __init exynos4_init_clocks(int xtal)
{
printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
s3c24xx_register_baseclocks(xtal);
s5p_register_clocks(xtal);
- s5pv310_register_clocks();
- s5pv310_setup_clocks();
+ exynos4_register_clocks();
+ exynos4_setup_clocks();
}
-void __init s5pv310_init_irq(void)
+void __init exynos4_init_irq(void)
{
int irq;
@@ -148,29 +161,29 @@ void __init s5pv310_init_irq(void)
}
/* The parameters of s5p_init_irq() are for VIC init.
- * Theses parameters should be NULL and 0 because S5PV310
+ * Theses parameters should be NULL and 0 because EXYNOS4
* uses GIC instead of VIC.
*/
s5p_init_irq(NULL, 0);
}
-struct sysdev_class s5pv310_sysclass = {
- .name = "s5pv310-core",
+struct sysdev_class exynos4_sysclass = {
+ .name = "exynos4-core",
};
-static struct sys_device s5pv310_sysdev = {
- .cls = &s5pv310_sysclass,
+static struct sys_device exynos4_sysdev = {
+ .cls = &exynos4_sysclass,
};
-static int __init s5pv310_core_init(void)
+static int __init exynos4_core_init(void)
{
- return sysdev_class_register(&s5pv310_sysclass);
+ return sysdev_class_register(&exynos4_sysclass);
}
-core_initcall(s5pv310_core_init);
+core_initcall(exynos4_core_init);
#ifdef CONFIG_CACHE_L2X0
-static int __init s5pv310_l2x0_cache_init(void)
+static int __init exynos4_l2x0_cache_init(void)
{
/* TAG, Data Latency Control: 2cycle */
__raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
@@ -188,15 +201,15 @@ static int __init s5pv310_l2x0_cache_init(void)
return 0;
}
-early_initcall(s5pv310_l2x0_cache_init);
+early_initcall(exynos4_l2x0_cache_init);
#endif
-int __init s5pv310_init(void)
+int __init exynos4_init(void)
{
- printk(KERN_INFO "S5PV310: Initializing architecture\n");
+ printk(KERN_INFO "EXYNOS4: Initializing architecture\n");
/* set idle function */
- pm_idle = s5pv310_idle;
+ pm_idle = exynos4_idle;
- return sysdev_register(&s5pv310_sysdev);
+ return sysdev_register(&exynos4_sysdev);
}
diff --git a/arch/arm/mach-s5pv310/cpufreq.c b/arch/arm/mach-exynos4/cpufreq.c
index b04cbc731128..a1bd258f0c4d 100644
--- a/arch/arm/mach-s5pv310/cpufreq.c
+++ b/arch/arm/mach-exynos4/cpufreq.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/cpufreq.c
+/* linux/arch/arm/mach-exynos4/cpufreq.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 - CPU frequency scaling support
+ * EXYNOS4 - CPU frequency scaling support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,15 +31,13 @@ static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
-#ifdef CONFIG_REGULATOR
static struct regulator *arm_regulator;
static struct regulator *int_regulator;
-#endif
static struct cpufreq_freqs freqs;
static unsigned int memtype;
-enum s5pv310_memory_type {
+enum exynos4_memory_type {
DDR2 = 4,
LPDDR2,
DDR3,
@@ -49,7 +47,7 @@ enum cpufreq_level_index {
L0, L1, L2, L3, CPUFREQ_LEVEL_END,
};
-static struct cpufreq_frequency_table s5pv310_freq_table[] = {
+static struct cpufreq_frequency_table exynos4_freq_table[] = {
{L0, 1000*1000},
{L1, 800*1000},
{L2, 400*1000},
@@ -160,7 +158,7 @@ struct cpufreq_voltage_table {
unsigned int int_volt;
};
-static struct cpufreq_voltage_table s5pv310_volt_table[CPUFREQ_LEVEL_END] = {
+static struct cpufreq_voltage_table exynos4_volt_table[CPUFREQ_LEVEL_END] = {
{
.index = L0,
.arm_volt = 1200000,
@@ -180,7 +178,7 @@ static struct cpufreq_voltage_table s5pv310_volt_table[CPUFREQ_LEVEL_END] = {
},
};
-static unsigned int s5pv310_apll_pms_table[CPUFREQ_LEVEL_END] = {
+static unsigned int exynos4_apll_pms_table[CPUFREQ_LEVEL_END] = {
/* APLL FOUT L0: 1000MHz */
((250 << 16) | (6 << 8) | 1),
@@ -194,17 +192,17 @@ static unsigned int s5pv310_apll_pms_table[CPUFREQ_LEVEL_END] = {
((200 << 16) | (6 << 8) | 4),
};
-int s5pv310_verify_speed(struct cpufreq_policy *policy)
+int exynos4_verify_speed(struct cpufreq_policy *policy)
{
- return cpufreq_frequency_table_verify(policy, s5pv310_freq_table);
+ return cpufreq_frequency_table_verify(policy, exynos4_freq_table);
}
-unsigned int s5pv310_getspeed(unsigned int cpu)
+unsigned int exynos4_getspeed(unsigned int cpu)
{
return clk_get_rate(cpu_clk) / 1000;
}
-void s5pv310_set_clkdiv(unsigned int div_index)
+void exynos4_set_clkdiv(unsigned int div_index)
{
unsigned int tmp;
@@ -321,7 +319,7 @@ void s5pv310_set_clkdiv(unsigned int div_index)
} while (tmp & 0x11);
}
-static void s5pv310_set_apll(unsigned int index)
+static void exynos4_set_apll(unsigned int index)
{
unsigned int tmp;
@@ -340,7 +338,7 @@ static void s5pv310_set_apll(unsigned int index)
/* 3. Change PLL PMS values */
tmp = __raw_readl(S5P_APLL_CON0);
tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
- tmp |= s5pv310_apll_pms_table[index];
+ tmp |= exynos4_apll_pms_table[index];
__raw_writel(tmp, S5P_APLL_CON0);
/* 4. wait_lock_time */
@@ -357,99 +355,95 @@ static void s5pv310_set_apll(unsigned int index)
} while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
}
-static void s5pv310_set_frequency(unsigned int old_index, unsigned int new_index)
+static void exynos4_set_frequency(unsigned int old_index, unsigned int new_index)
{
unsigned int tmp;
if (old_index > new_index) {
/* The frequency changing to L0 needs to change apll */
- if (freqs.new == s5pv310_freq_table[L0].frequency) {
+ if (freqs.new == exynos4_freq_table[L0].frequency) {
/* 1. Change the system clock divider values */
- s5pv310_set_clkdiv(new_index);
+ exynos4_set_clkdiv(new_index);
/* 2. Change the apll m,p,s value */
- s5pv310_set_apll(new_index);
+ exynos4_set_apll(new_index);
} else {
/* 1. Change the system clock divider values */
- s5pv310_set_clkdiv(new_index);
+ exynos4_set_clkdiv(new_index);
/* 2. Change just s value in apll m,p,s value */
tmp = __raw_readl(S5P_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (s5pv310_apll_pms_table[new_index] & 0x7);
+ tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, S5P_APLL_CON0);
}
}
else if (old_index < new_index) {
/* The frequency changing from L0 needs to change apll */
- if (freqs.old == s5pv310_freq_table[L0].frequency) {
+ if (freqs.old == exynos4_freq_table[L0].frequency) {
/* 1. Change the apll m,p,s value */
- s5pv310_set_apll(new_index);
+ exynos4_set_apll(new_index);
/* 2. Change the system clock divider values */
- s5pv310_set_clkdiv(new_index);
+ exynos4_set_clkdiv(new_index);
} else {
/* 1. Change just s value in apll m,p,s value */
tmp = __raw_readl(S5P_APLL_CON0);
tmp &= ~(0x7 << 0);
- tmp |= (s5pv310_apll_pms_table[new_index] & 0x7);
+ tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
__raw_writel(tmp, S5P_APLL_CON0);
/* 2. Change the system clock divider values */
- s5pv310_set_clkdiv(new_index);
+ exynos4_set_clkdiv(new_index);
}
}
}
-static int s5pv310_target(struct cpufreq_policy *policy,
+static int exynos4_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int index, old_index;
unsigned int arm_volt, int_volt;
- freqs.old = s5pv310_getspeed(policy->cpu);
+ freqs.old = exynos4_getspeed(policy->cpu);
- if (cpufreq_frequency_table_target(policy, s5pv310_freq_table,
+ if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
freqs.old, relation, &old_index))
return -EINVAL;
- if (cpufreq_frequency_table_target(policy, s5pv310_freq_table,
+ if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
target_freq, relation, &index))
return -EINVAL;
- freqs.new = s5pv310_freq_table[index].frequency;
+ freqs.new = exynos4_freq_table[index].frequency;
freqs.cpu = policy->cpu;
if (freqs.new == freqs.old)
return 0;
/* get the voltage value */
- arm_volt = s5pv310_volt_table[index].arm_volt;
- int_volt = s5pv310_volt_table[index].int_volt;
+ arm_volt = exynos4_volt_table[index].arm_volt;
+ int_volt = exynos4_volt_table[index].int_volt;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* control regulator */
if (freqs.new > freqs.old) {
/* Voltage up */
-#ifdef CONFIG_REGULATOR
regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
regulator_set_voltage(int_regulator, int_volt, int_volt);
-#endif
}
/* Clock Configuration Procedure */
- s5pv310_set_frequency(old_index, index);
+ exynos4_set_frequency(old_index, index);
/* control regulator */
if (freqs.new < freqs.old) {
/* Voltage down */
-#ifdef CONFIG_REGULATOR
regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
regulator_set_voltage(int_regulator, int_volt, int_volt);
-#endif
}
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -458,52 +452,51 @@ static int s5pv310_target(struct cpufreq_policy *policy,
}
#ifdef CONFIG_PM
-static int s5pv310_cpufreq_suspend(struct cpufreq_policy *policy,
- pm_message_t pmsg)
+static int exynos4_cpufreq_suspend(struct cpufreq_policy *policy)
{
return 0;
}
-static int s5pv310_cpufreq_resume(struct cpufreq_policy *policy)
+static int exynos4_cpufreq_resume(struct cpufreq_policy *policy)
{
return 0;
}
#endif
-static int s5pv310_cpufreq_cpu_init(struct cpufreq_policy *policy)
+static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- policy->cur = policy->min = policy->max = s5pv310_getspeed(policy->cpu);
+ policy->cur = policy->min = policy->max = exynos4_getspeed(policy->cpu);
- cpufreq_frequency_table_get_attr(s5pv310_freq_table, policy->cpu);
+ cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
/* set the transition latency value */
policy->cpuinfo.transition_latency = 100000;
/*
- * S5PV310 multi-core processors has 2 cores
+ * EXYNOS4 multi-core processors has 2 cores
* that the frequency cannot be set independently.
* Each cpu is bound to the same speed.
* So the affected cpu is all of the cpus.
*/
cpumask_setall(policy->cpus);
- return cpufreq_frequency_table_cpuinfo(policy, s5pv310_freq_table);
+ return cpufreq_frequency_table_cpuinfo(policy, exynos4_freq_table);
}
-static struct cpufreq_driver s5pv310_driver = {
+static struct cpufreq_driver exynos4_driver = {
.flags = CPUFREQ_STICKY,
- .verify = s5pv310_verify_speed,
- .target = s5pv310_target,
- .get = s5pv310_getspeed,
- .init = s5pv310_cpufreq_cpu_init,
- .name = "s5pv310_cpufreq",
+ .verify = exynos4_verify_speed,
+ .target = exynos4_target,
+ .get = exynos4_getspeed,
+ .init = exynos4_cpufreq_cpu_init,
+ .name = "exynos4_cpufreq",
#ifdef CONFIG_PM
- .suspend = s5pv310_cpufreq_suspend,
- .resume = s5pv310_cpufreq_resume,
+ .suspend = exynos4_cpufreq_suspend,
+ .resume = exynos4_cpufreq_resume,
#endif
};
-static int __init s5pv310_cpufreq_init(void)
+static int __init exynos4_cpufreq_init(void)
{
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
@@ -521,7 +514,6 @@ static int __init s5pv310_cpufreq_init(void)
if (IS_ERR(mout_apll))
goto out;
-#ifdef CONFIG_REGULATOR
arm_regulator = regulator_get(NULL, "vdd_arm");
if (IS_ERR(arm_regulator)) {
printk(KERN_ERR "failed to get resource %s\n", "vdd_arm");
@@ -533,7 +525,6 @@ static int __init s5pv310_cpufreq_init(void)
printk(KERN_ERR "failed to get resource %s\n", "vdd_int");
goto out;
}
-#endif
/*
* Check DRAM type.
@@ -550,7 +541,7 @@ static int __init s5pv310_cpufreq_init(void)
printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
}
- return cpufreq_register_driver(&s5pv310_driver);
+ return cpufreq_register_driver(&exynos4_driver);
out:
if (!IS_ERR(cpu_clk))
@@ -565,16 +556,14 @@ out:
if (!IS_ERR(mout_apll))
clk_put(mout_apll);
-#ifdef CONFIG_REGULATOR
if (!IS_ERR(arm_regulator))
regulator_put(arm_regulator);
if (!IS_ERR(int_regulator))
regulator_put(int_regulator);
-#endif
printk(KERN_ERR "%s: failed initialization\n", __func__);
return -EINVAL;
}
-late_initcall(s5pv310_cpufreq_init);
+late_initcall(exynos4_cpufreq_init);
diff --git a/arch/arm/mach-exynos4/dev-ahci.c b/arch/arm/mach-exynos4/dev-ahci.c
new file mode 100644
index 000000000000..f57a3de8e1d2
--- /dev/null
+++ b/arch/arm/mach-exynos4/dev-ahci.c
@@ -0,0 +1,263 @@
+/* linux/arch/arm/mach-exynos4/dev-ahci.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - AHCI support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+
+#include <plat/cpu.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <mach/regs-pmu.h>
+
+/* PHY Control Register */
+#define SATA_CTRL0 0x0
+/* PHY Link Control Register */
+#define SATA_CTRL1 0x4
+/* PHY Status Register */
+#define SATA_PHY_STATUS 0x8
+
+#define SATA_CTRL0_RX_DATA_VALID(x) (x << 27)
+#define SATA_CTRL0_SPEED_MODE (1 << 26)
+#define SATA_CTRL0_M_PHY_CAL (1 << 19)
+#define SATA_CTRL0_PHY_CMU_RST_N (1 << 10)
+#define SATA_CTRL0_M_PHY_LN_RST_N (1 << 9)
+#define SATA_CTRL0_PHY_POR_N (1 << 8)
+
+#define SATA_CTRL1_RST_PMALIVE_N (1 << 8)
+#define SATA_CTRL1_RST_RXOOB_N (1 << 7)
+#define SATA_CTRL1_RST_RX_N (1 << 6)
+#define SATA_CTRL1_RST_TX_N (1 << 5)
+
+#define SATA_PHY_STATUS_CMU_OK (1 << 18)
+#define SATA_PHY_STATUS_LANE_OK (1 << 16)
+
+#define LANE0 0x200
+#define COM_LANE 0xA00
+
+#define HOST_PORTS_IMPL 0xC
+#define SCLK_SATA_FREQ (67 * MHZ)
+
+static void __iomem *phy_base, *phy_ctrl;
+
+struct phy_reg {
+ u8 reg;
+ u8 val;
+};
+
+/* SATA PHY setup */
+static const struct phy_reg exynos4_sataphy_cmu[] = {
+ { 0x00, 0x06 }, { 0x02, 0x80 }, { 0x22, 0xa0 }, { 0x23, 0x42 },
+ { 0x2e, 0x04 }, { 0x2f, 0x50 }, { 0x30, 0x70 }, { 0x31, 0x02 },
+ { 0x32, 0x25 }, { 0x33, 0x40 }, { 0x34, 0x01 }, { 0x35, 0x40 },
+ { 0x61, 0x2e }, { 0x63, 0x5e }, { 0x65, 0x42 }, { 0x66, 0xd1 },
+ { 0x67, 0x20 }, { 0x68, 0x28 }, { 0x69, 0x78 }, { 0x6a, 0x04 },
+ { 0x6b, 0xc8 }, { 0x6c, 0x06 },
+};
+
+static const struct phy_reg exynos4_sataphy_lane[] = {
+ { 0x00, 0x02 }, { 0x05, 0x10 }, { 0x06, 0x84 }, { 0x07, 0x04 },
+ { 0x08, 0xe0 }, { 0x10, 0x23 }, { 0x13, 0x05 }, { 0x14, 0x30 },
+ { 0x15, 0x00 }, { 0x17, 0x70 }, { 0x18, 0xf2 }, { 0x19, 0x1e },
+ { 0x1a, 0x18 }, { 0x1b, 0x0d }, { 0x1c, 0x08 }, { 0x50, 0x60 },
+ { 0x51, 0x0f },
+};
+
+static const struct phy_reg exynos4_sataphy_comlane[] = {
+ { 0x01, 0x20 }, { 0x03, 0x40 }, { 0x04, 0x3c }, { 0x05, 0x7d },
+ { 0x06, 0x1d }, { 0x07, 0xcf }, { 0x08, 0x05 }, { 0x09, 0x63 },
+ { 0x0a, 0x29 }, { 0x0b, 0xc4 }, { 0x0c, 0x01 }, { 0x0d, 0x03 },
+ { 0x0e, 0x28 }, { 0x0f, 0x98 }, { 0x10, 0x19 }, { 0x13, 0x80 },
+ { 0x14, 0xf0 }, { 0x15, 0xd0 }, { 0x39, 0xa0 }, { 0x3a, 0xa0 },
+ { 0x3b, 0xa0 }, { 0x3c, 0xa0 }, { 0x3d, 0xa0 }, { 0x3e, 0xa0 },
+ { 0x3f, 0xa0 }, { 0x40, 0x42 }, { 0x42, 0x80 }, { 0x43, 0x58 },
+ { 0x45, 0x44 }, { 0x46, 0x5c }, { 0x47, 0x86 }, { 0x48, 0x8d },
+ { 0x49, 0xd0 }, { 0x4a, 0x09 }, { 0x4b, 0x90 }, { 0x4c, 0x07 },
+ { 0x4d, 0x40 }, { 0x51, 0x20 }, { 0x52, 0x32 }, { 0x7f, 0xd8 },
+ { 0x80, 0x1a }, { 0x81, 0xff }, { 0x82, 0x11 }, { 0x83, 0x00 },
+ { 0x87, 0xf0 }, { 0x87, 0xff }, { 0x87, 0xff }, { 0x87, 0xff },
+ { 0x87, 0xff }, { 0x8c, 0x1c }, { 0x8d, 0xc2 }, { 0x8e, 0xc3 },
+ { 0x8f, 0x3f }, { 0x90, 0x0a }, { 0x96, 0xf8 },
+};
+
+static int wait_for_phy_ready(void __iomem *reg, unsigned long bit)
+{
+ unsigned long timeout;
+
+ /* wait for maximum of 3 sec */
+ timeout = jiffies + msecs_to_jiffies(3000);
+ while (!(__raw_readl(reg) & bit)) {
+ if (time_after(jiffies, timeout))
+ return -1;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static int ahci_phy_init(void __iomem *mmio)
+{
+ int i, ctrl0;
+
+ for (i = 0; i < ARRAY_SIZE(exynos4_sataphy_cmu); i++)
+ __raw_writeb(exynos4_sataphy_cmu[i].val,
+ phy_base + (exynos4_sataphy_cmu[i].reg * 4));
+
+ for (i = 0; i < ARRAY_SIZE(exynos4_sataphy_lane); i++)
+ __raw_writeb(exynos4_sataphy_lane[i].val,
+ phy_base + (LANE0 + exynos4_sataphy_lane[i].reg) * 4);
+
+ for (i = 0; i < ARRAY_SIZE(exynos4_sataphy_comlane); i++)
+ __raw_writeb(exynos4_sataphy_comlane[i].val,
+ phy_base + (COM_LANE + exynos4_sataphy_comlane[i].reg) * 4);
+
+ __raw_writeb(0x07, phy_base);
+
+ ctrl0 = __raw_readl(phy_ctrl + SATA_CTRL0);
+ ctrl0 |= SATA_CTRL0_PHY_CMU_RST_N;
+ __raw_writel(ctrl0, phy_ctrl + SATA_CTRL0);
+
+ if (wait_for_phy_ready(phy_ctrl + SATA_PHY_STATUS,
+ SATA_PHY_STATUS_CMU_OK) < 0) {
+ printk(KERN_ERR "PHY CMU not ready\n");
+ return -EBUSY;
+ }
+
+ __raw_writeb(0x03, phy_base + (COM_LANE * 4));
+
+ ctrl0 = __raw_readl(phy_ctrl + SATA_CTRL0);
+ ctrl0 |= SATA_CTRL0_M_PHY_LN_RST_N;
+ __raw_writel(ctrl0, phy_ctrl + SATA_CTRL0);
+
+ if (wait_for_phy_ready(phy_ctrl + SATA_PHY_STATUS,
+ SATA_PHY_STATUS_LANE_OK) < 0) {
+ printk(KERN_ERR "PHY LANE not ready\n");
+ return -EBUSY;
+ }
+
+ ctrl0 = __raw_readl(phy_ctrl + SATA_CTRL0);
+ ctrl0 |= SATA_CTRL0_M_PHY_CAL;
+ __raw_writel(ctrl0, phy_ctrl + SATA_CTRL0);
+
+ return 0;
+}
+
+static int exynos4_ahci_init(struct device *dev, void __iomem *mmio)
+{
+ struct clk *clk_sata, *clk_sataphy, *clk_sclk_sata;
+ int val, ret;
+
+ phy_base = ioremap(EXYNOS4_PA_SATAPHY, SZ_64K);
+ if (!phy_base) {
+ dev_err(dev, "failed to allocate memory for SATA PHY\n");
+ return -ENOMEM;
+ }
+
+ phy_ctrl = ioremap(EXYNOS4_PA_SATAPHY_CTRL, SZ_16);
+ if (!phy_ctrl) {
+ dev_err(dev, "failed to allocate memory for SATA PHY CTRL\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ clk_sata = clk_get(dev, "sata");
+ if (IS_ERR(clk_sata)) {
+ dev_err(dev, "failed to get sata clock\n");
+ ret = PTR_ERR(clk_sata);
+ clk_sata = NULL;
+ goto err2;
+
+ }
+ clk_enable(clk_sata);
+
+ clk_sataphy = clk_get(dev, "sataphy");
+ if (IS_ERR(clk_sataphy)) {
+ dev_err(dev, "failed to get sataphy clock\n");
+ ret = PTR_ERR(clk_sataphy);
+ clk_sataphy = NULL;
+ goto err3;
+ }
+ clk_enable(clk_sataphy);
+
+ clk_sclk_sata = clk_get(dev, "sclk_sata");
+ if (IS_ERR(clk_sclk_sata)) {
+ dev_err(dev, "failed to get sclk_sata\n");
+ ret = PTR_ERR(clk_sclk_sata);
+ clk_sclk_sata = NULL;
+ goto err4;
+ }
+ clk_enable(clk_sclk_sata);
+ clk_set_rate(clk_sclk_sata, SCLK_SATA_FREQ);
+
+ __raw_writel(S5P_PMU_SATA_PHY_CONTROL_EN, S5P_PMU_SATA_PHY_CONTROL);
+
+ /* Enable PHY link control */
+ val = SATA_CTRL1_RST_PMALIVE_N | SATA_CTRL1_RST_RXOOB_N |
+ SATA_CTRL1_RST_RX_N | SATA_CTRL1_RST_TX_N;
+ __raw_writel(val, phy_ctrl + SATA_CTRL1);
+
+ /* Set communication speed as 3Gbps and enable PHY power */
+ val = SATA_CTRL0_RX_DATA_VALID(3) | SATA_CTRL0_SPEED_MODE |
+ SATA_CTRL0_PHY_POR_N;
+ __raw_writel(val, phy_ctrl + SATA_CTRL0);
+
+ /* Port0 is available */
+ __raw_writel(0x1, mmio + HOST_PORTS_IMPL);
+
+ return ahci_phy_init(mmio);
+
+err4:
+ clk_disable(clk_sataphy);
+ clk_put(clk_sataphy);
+err3:
+ clk_disable(clk_sata);
+ clk_put(clk_sata);
+err2:
+ iounmap(phy_ctrl);
+err1:
+ iounmap(phy_base);
+
+ return ret;
+}
+
+static struct ahci_platform_data exynos4_ahci_pdata = {
+ .init = exynos4_ahci_init,
+};
+
+static struct resource exynos4_ahci_resource[] = {
+ [0] = {
+ .start = EXYNOS4_PA_SATA,
+ .end = EXYNOS4_PA_SATA + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SATA,
+ .end = IRQ_SATA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 exynos4_ahci_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device exynos4_device_ahci = {
+ .name = "ahci",
+ .id = -1,
+ .resource = exynos4_ahci_resource,
+ .num_resources = ARRAY_SIZE(exynos4_ahci_resource),
+ .dev = {
+ .platform_data = &exynos4_ahci_pdata,
+ .dma_mask = &exynos4_ahci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
diff --git a/arch/arm/mach-s5pv310/dev-audio.c b/arch/arm/mach-exynos4/dev-audio.c
index a1964242f0fa..1eed5f9f7bd3 100644
--- a/arch/arm/mach-s5pv310/dev-audio.c
+++ b/arch/arm/mach-exynos4/dev-audio.c
@@ -1,4 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/dev-audio.c
+/* linux/arch/arm/mach-exynos4/dev-audio.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright (c) 2010 Samsung Electronics Co. Ltd
* Jaswinder Singh <jassi.brar@samsung.com>
@@ -24,18 +27,18 @@ static const char *rclksrc[] = {
[1] = "i2sclk",
};
-static int s5pv310_cfg_i2s(struct platform_device *pdev)
+static int exynos4_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case 0:
- s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 7, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPZ(0), 7, S3C_GPIO_SFN(2));
break;
case 1:
- s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(2));
break;
case 2:
- s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(4));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(4));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
@@ -46,7 +49,7 @@ static int s5pv310_cfg_i2s(struct platform_device *pdev)
}
static struct s3c_audio_pdata i2sv5_pdata = {
- .cfg_gpio = s5pv310_cfg_i2s,
+ .cfg_gpio = exynos4_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
@@ -56,10 +59,10 @@ static struct s3c_audio_pdata i2sv5_pdata = {
},
};
-static struct resource s5pv310_i2s0_resource[] = {
+static struct resource exynos4_i2s0_resource[] = {
[0] = {
- .start = S5PV310_PA_I2S0,
- .end = S5PV310_PA_I2S0 + 0x100 - 1,
+ .start = EXYNOS4_PA_I2S0,
+ .end = EXYNOS4_PA_I2S0 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -79,11 +82,11 @@ static struct resource s5pv310_i2s0_resource[] = {
},
};
-struct platform_device s5pv310_device_i2s0 = {
+struct platform_device exynos4_device_i2s0 = {
.name = "samsung-i2s",
.id = 0,
- .num_resources = ARRAY_SIZE(s5pv310_i2s0_resource),
- .resource = s5pv310_i2s0_resource,
+ .num_resources = ARRAY_SIZE(exynos4_i2s0_resource),
+ .resource = exynos4_i2s0_resource,
.dev = {
.platform_data = &i2sv5_pdata,
},
@@ -95,7 +98,7 @@ static const char *rclksrc_v3[] = {
};
static struct s3c_audio_pdata i2sv3_pdata = {
- .cfg_gpio = s5pv310_cfg_i2s,
+ .cfg_gpio = exynos4_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_NO_MUXPSR,
@@ -104,10 +107,10 @@ static struct s3c_audio_pdata i2sv3_pdata = {
},
};
-static struct resource s5pv310_i2s1_resource[] = {
+static struct resource exynos4_i2s1_resource[] = {
[0] = {
- .start = S5PV310_PA_I2S1,
- .end = S5PV310_PA_I2S1 + 0x100 - 1,
+ .start = EXYNOS4_PA_I2S1,
+ .end = EXYNOS4_PA_I2S1 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -122,20 +125,20 @@ static struct resource s5pv310_i2s1_resource[] = {
},
};
-struct platform_device s5pv310_device_i2s1 = {
+struct platform_device exynos4_device_i2s1 = {
.name = "samsung-i2s",
.id = 1,
- .num_resources = ARRAY_SIZE(s5pv310_i2s1_resource),
- .resource = s5pv310_i2s1_resource,
+ .num_resources = ARRAY_SIZE(exynos4_i2s1_resource),
+ .resource = exynos4_i2s1_resource,
.dev = {
.platform_data = &i2sv3_pdata,
},
};
-static struct resource s5pv310_i2s2_resource[] = {
+static struct resource exynos4_i2s2_resource[] = {
[0] = {
- .start = S5PV310_PA_I2S2,
- .end = S5PV310_PA_I2S2 + 0x100 - 1,
+ .start = EXYNOS4_PA_I2S2,
+ .end = EXYNOS4_PA_I2S2 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -150,11 +153,11 @@ static struct resource s5pv310_i2s2_resource[] = {
},
};
-struct platform_device s5pv310_device_i2s2 = {
+struct platform_device exynos4_device_i2s2 = {
.name = "samsung-i2s",
.id = 2,
- .num_resources = ARRAY_SIZE(s5pv310_i2s2_resource),
- .resource = s5pv310_i2s2_resource,
+ .num_resources = ARRAY_SIZE(exynos4_i2s2_resource),
+ .resource = exynos4_i2s2_resource,
.dev = {
.platform_data = &i2sv3_pdata,
},
@@ -162,17 +165,17 @@ struct platform_device s5pv310_device_i2s2 = {
/* PCM Controller platform_devices */
-static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
+static int exynos4_pcm_cfg_gpio(struct platform_device *pdev)
{
switch (pdev->id) {
case 0:
- s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 5, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPZ(0), 5, S3C_GPIO_SFN(3));
break;
case 1:
- s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(3));
break;
case 2:
- s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(3));
break;
default:
printk(KERN_DEBUG "Invalid PCM Controller number!");
@@ -183,13 +186,13 @@ static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
}
static struct s3c_audio_pdata s3c_pcm_pdata = {
- .cfg_gpio = s5pv310_pcm_cfg_gpio,
+ .cfg_gpio = exynos4_pcm_cfg_gpio,
};
-static struct resource s5pv310_pcm0_resource[] = {
+static struct resource exynos4_pcm0_resource[] = {
[0] = {
- .start = S5PV310_PA_PCM0,
- .end = S5PV310_PA_PCM0 + 0x100 - 1,
+ .start = EXYNOS4_PA_PCM0,
+ .end = EXYNOS4_PA_PCM0 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -204,20 +207,20 @@ static struct resource s5pv310_pcm0_resource[] = {
},
};
-struct platform_device s5pv310_device_pcm0 = {
+struct platform_device exynos4_device_pcm0 = {
.name = "samsung-pcm",
.id = 0,
- .num_resources = ARRAY_SIZE(s5pv310_pcm0_resource),
- .resource = s5pv310_pcm0_resource,
+ .num_resources = ARRAY_SIZE(exynos4_pcm0_resource),
+ .resource = exynos4_pcm0_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
};
-static struct resource s5pv310_pcm1_resource[] = {
+static struct resource exynos4_pcm1_resource[] = {
[0] = {
- .start = S5PV310_PA_PCM1,
- .end = S5PV310_PA_PCM1 + 0x100 - 1,
+ .start = EXYNOS4_PA_PCM1,
+ .end = EXYNOS4_PA_PCM1 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -232,20 +235,20 @@ static struct resource s5pv310_pcm1_resource[] = {
},
};
-struct platform_device s5pv310_device_pcm1 = {
+struct platform_device exynos4_device_pcm1 = {
.name = "samsung-pcm",
.id = 1,
- .num_resources = ARRAY_SIZE(s5pv310_pcm1_resource),
- .resource = s5pv310_pcm1_resource,
+ .num_resources = ARRAY_SIZE(exynos4_pcm1_resource),
+ .resource = exynos4_pcm1_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
};
-static struct resource s5pv310_pcm2_resource[] = {
+static struct resource exynos4_pcm2_resource[] = {
[0] = {
- .start = S5PV310_PA_PCM2,
- .end = S5PV310_PA_PCM2 + 0x100 - 1,
+ .start = EXYNOS4_PA_PCM2,
+ .end = EXYNOS4_PA_PCM2 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -260,11 +263,11 @@ static struct resource s5pv310_pcm2_resource[] = {
},
};
-struct platform_device s5pv310_device_pcm2 = {
+struct platform_device exynos4_device_pcm2 = {
.name = "samsung-pcm",
.id = 2,
- .num_resources = ARRAY_SIZE(s5pv310_pcm2_resource),
- .resource = s5pv310_pcm2_resource,
+ .num_resources = ARRAY_SIZE(exynos4_pcm2_resource),
+ .resource = exynos4_pcm2_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
@@ -272,15 +275,15 @@ struct platform_device s5pv310_device_pcm2 = {
/* AC97 Controller platform devices */
-static int s5pv310_ac97_cfg_gpio(struct platform_device *pdev)
+static int exynos4_ac97_cfg_gpio(struct platform_device *pdev)
{
- return s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(4));
+ return s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(4));
}
-static struct resource s5pv310_ac97_resource[] = {
+static struct resource exynos4_ac97_resource[] = {
[0] = {
- .start = S5PV310_PA_AC97,
- .end = S5PV310_PA_AC97 + 0x100 - 1,
+ .start = EXYNOS4_PA_AC97,
+ .end = EXYNOS4_PA_AC97 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -306,36 +309,36 @@ static struct resource s5pv310_ac97_resource[] = {
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
- .cfg_gpio = s5pv310_ac97_cfg_gpio,
+ .cfg_gpio = exynos4_ac97_cfg_gpio,
};
-static u64 s5pv310_ac97_dmamask = DMA_BIT_MASK(32);
+static u64 exynos4_ac97_dmamask = DMA_BIT_MASK(32);
-struct platform_device s5pv310_device_ac97 = {
+struct platform_device exynos4_device_ac97 = {
.name = "samsung-ac97",
.id = -1,
- .num_resources = ARRAY_SIZE(s5pv310_ac97_resource),
- .resource = s5pv310_ac97_resource,
+ .num_resources = ARRAY_SIZE(exynos4_ac97_resource),
+ .resource = exynos4_ac97_resource,
.dev = {
.platform_data = &s3c_ac97_pdata,
- .dma_mask = &s5pv310_ac97_dmamask,
+ .dma_mask = &exynos4_ac97_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
/* S/PDIF Controller platform_device */
-static int s5pv310_spdif_cfg_gpio(struct platform_device *pdev)
+static int exynos4_spdif_cfg_gpio(struct platform_device *pdev)
{
- s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 2, S3C_GPIO_SFN(3));
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(3));
return 0;
}
-static struct resource s5pv310_spdif_resource[] = {
+static struct resource exynos4_spdif_resource[] = {
[0] = {
- .start = S5PV310_PA_SPDIF,
- .end = S5PV310_PA_SPDIF + 0x100 - 1,
+ .start = EXYNOS4_PA_SPDIF,
+ .end = EXYNOS4_PA_SPDIF + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -346,19 +349,19 @@ static struct resource s5pv310_spdif_resource[] = {
};
static struct s3c_audio_pdata samsung_spdif_pdata = {
- .cfg_gpio = s5pv310_spdif_cfg_gpio,
+ .cfg_gpio = exynos4_spdif_cfg_gpio,
};
-static u64 s5pv310_spdif_dmamask = DMA_BIT_MASK(32);
+static u64 exynos4_spdif_dmamask = DMA_BIT_MASK(32);
-struct platform_device s5pv310_device_spdif = {
+struct platform_device exynos4_device_spdif = {
.name = "samsung-spdif",
.id = -1,
- .num_resources = ARRAY_SIZE(s5pv310_spdif_resource),
- .resource = s5pv310_spdif_resource,
+ .num_resources = ARRAY_SIZE(exynos4_spdif_resource),
+ .resource = exynos4_spdif_resource,
.dev = {
.platform_data = &samsung_spdif_pdata,
- .dma_mask = &s5pv310_spdif_dmamask,
+ .dma_mask = &exynos4_spdif_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
diff --git a/arch/arm/mach-s5pv310/dev-pd.c b/arch/arm/mach-exynos4/dev-pd.c
index 58a50c2d0b67..3273f25d6a75 100644
--- a/arch/arm/mach-s5pv310/dev-pd.c
+++ b/arch/arm/mach-exynos4/dev-pd.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/dev-pd.c
+/* linux/arch/arm/mach-exynos4/dev-pd.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 - Power Domain support
+ * EXYNOS4 - Power Domain support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,7 @@
#include <plat/pd.h>
-static int s5pv310_pd_enable(struct device *dev)
+static int exynos4_pd_enable(struct device *dev)
{
struct samsung_pd_info *pdata = dev->platform_data;
u32 timeout;
@@ -42,7 +42,7 @@ static int s5pv310_pd_enable(struct device *dev)
return 0;
}
-static int s5pv310_pd_disable(struct device *dev)
+static int exynos4_pd_disable(struct device *dev)
{
struct samsung_pd_info *pdata = dev->platform_data;
u32 timeout;
@@ -64,14 +64,14 @@ static int s5pv310_pd_disable(struct device *dev)
return 0;
}
-struct platform_device s5pv310_device_pd[] = {
+struct platform_device exynos4_device_pd[] = {
{
.name = "samsung-pd",
.id = 0,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_MFC_CONF,
},
},
@@ -80,8 +80,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 1,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_G3D_CONF,
},
},
@@ -90,8 +90,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 2,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_LCD0_CONF,
},
},
@@ -100,8 +100,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 3,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_LCD1_CONF,
},
},
@@ -110,8 +110,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 4,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_TV_CONF,
},
},
@@ -120,8 +120,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 5,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_CAM_CONF,
},
},
@@ -130,8 +130,8 @@ struct platform_device s5pv310_device_pd[] = {
.id = 6,
.dev = {
.platform_data = &(struct samsung_pd_info) {
- .enable = s5pv310_pd_enable,
- .disable = s5pv310_pd_disable,
+ .enable = exynos4_pd_enable,
+ .disable = exynos4_pd_disable,
.base = S5P_PMU_GPS_CONF,
},
},
diff --git a/arch/arm/mach-s5pv310/dev-sysmmu.c b/arch/arm/mach-exynos4/dev-sysmmu.c
index e1bb200ac0f0..3b7cae0fe23e 100644
--- a/arch/arm/mach-s5pv310/dev-sysmmu.c
+++ b/arch/arm/mach-exynos4/dev-sysmmu.c
@@ -1,8 +1,10 @@
-/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
+/* linux/arch/arm/mach-exynos4/dev-sysmmu.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
+ * EXYNOS4 - System MMU support
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -13,11 +15,33 @@
#include <mach/map.h>
#include <mach/irqs.h>
+#include <mach/sysmmu.h>
+#include <plat/s5p-clock.h>
+
+/* These names must be equal to the clock names in mach-exynos4/clock.c */
+const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = {
+ "SYSMMU_MDMA" ,
+ "SYSMMU_SSS" ,
+ "SYSMMU_FIMC0" ,
+ "SYSMMU_FIMC1" ,
+ "SYSMMU_FIMC2" ,
+ "SYSMMU_FIMC3" ,
+ "SYSMMU_JPEG" ,
+ "SYSMMU_FIMD0" ,
+ "SYSMMU_FIMD1" ,
+ "SYSMMU_PCIe" ,
+ "SYSMMU_G2D" ,
+ "SYSMMU_ROTATOR",
+ "SYSMMU_MDMA2" ,
+ "SYSMMU_TV" ,
+ "SYSMMU_MFC_L" ,
+ "SYSMMU_MFC_R" ,
+};
-static struct resource s5pv310_sysmmu_resource[] = {
+static struct resource exynos4_sysmmu_resource[] = {
[0] = {
- .start = S5PV310_PA_SYSMMU_MDMA,
- .end = S5PV310_PA_SYSMMU_MDMA + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_MDMA,
+ .end = EXYNOS4_PA_SYSMMU_MDMA + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -26,8 +50,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[2] = {
- .start = S5PV310_PA_SYSMMU_SSS,
- .end = S5PV310_PA_SYSMMU_SSS + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_SSS,
+ .end = EXYNOS4_PA_SYSMMU_SSS + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[3] = {
@@ -36,8 +60,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[4] = {
- .start = S5PV310_PA_SYSMMU_FIMC0,
- .end = S5PV310_PA_SYSMMU_FIMC0 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMC0,
+ .end = EXYNOS4_PA_SYSMMU_FIMC0 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[5] = {
@@ -46,8 +70,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[6] = {
- .start = S5PV310_PA_SYSMMU_FIMC1,
- .end = S5PV310_PA_SYSMMU_FIMC1 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMC1,
+ .end = EXYNOS4_PA_SYSMMU_FIMC1 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[7] = {
@@ -56,8 +80,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[8] = {
- .start = S5PV310_PA_SYSMMU_FIMC2,
- .end = S5PV310_PA_SYSMMU_FIMC2 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMC2,
+ .end = EXYNOS4_PA_SYSMMU_FIMC2 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[9] = {
@@ -66,8 +90,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[10] = {
- .start = S5PV310_PA_SYSMMU_FIMC3,
- .end = S5PV310_PA_SYSMMU_FIMC3 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMC3,
+ .end = EXYNOS4_PA_SYSMMU_FIMC3 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[11] = {
@@ -76,8 +100,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[12] = {
- .start = S5PV310_PA_SYSMMU_JPEG,
- .end = S5PV310_PA_SYSMMU_JPEG + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_JPEG,
+ .end = EXYNOS4_PA_SYSMMU_JPEG + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[13] = {
@@ -86,8 +110,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[14] = {
- .start = S5PV310_PA_SYSMMU_FIMD0,
- .end = S5PV310_PA_SYSMMU_FIMD0 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMD0,
+ .end = EXYNOS4_PA_SYSMMU_FIMD0 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[15] = {
@@ -96,8 +120,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[16] = {
- .start = S5PV310_PA_SYSMMU_FIMD1,
- .end = S5PV310_PA_SYSMMU_FIMD1 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_FIMD1,
+ .end = EXYNOS4_PA_SYSMMU_FIMD1 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[17] = {
@@ -106,8 +130,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[18] = {
- .start = S5PV310_PA_SYSMMU_PCIe,
- .end = S5PV310_PA_SYSMMU_PCIe + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_PCIe,
+ .end = EXYNOS4_PA_SYSMMU_PCIe + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[19] = {
@@ -116,8 +140,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[20] = {
- .start = S5PV310_PA_SYSMMU_G2D,
- .end = S5PV310_PA_SYSMMU_G2D + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_G2D,
+ .end = EXYNOS4_PA_SYSMMU_G2D + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[21] = {
@@ -126,8 +150,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[22] = {
- .start = S5PV310_PA_SYSMMU_ROTATOR,
- .end = S5PV310_PA_SYSMMU_ROTATOR + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_ROTATOR,
+ .end = EXYNOS4_PA_SYSMMU_ROTATOR + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[23] = {
@@ -136,8 +160,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[24] = {
- .start = S5PV310_PA_SYSMMU_MDMA2,
- .end = S5PV310_PA_SYSMMU_MDMA2 + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_MDMA2,
+ .end = EXYNOS4_PA_SYSMMU_MDMA2 + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[25] = {
@@ -146,8 +170,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[26] = {
- .start = S5PV310_PA_SYSMMU_TV,
- .end = S5PV310_PA_SYSMMU_TV + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_TV,
+ .end = EXYNOS4_PA_SYSMMU_TV + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[27] = {
@@ -156,8 +180,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[28] = {
- .start = S5PV310_PA_SYSMMU_MFC_L,
- .end = S5PV310_PA_SYSMMU_MFC_L + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_MFC_L,
+ .end = EXYNOS4_PA_SYSMMU_MFC_L + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[29] = {
@@ -166,8 +190,8 @@ static struct resource s5pv310_sysmmu_resource[] = {
.flags = IORESOURCE_IRQ,
},
[30] = {
- .start = S5PV310_PA_SYSMMU_MFC_R,
- .end = S5PV310_PA_SYSMMU_MFC_R + SZ_64K - 1,
+ .start = EXYNOS4_PA_SYSMMU_MFC_R,
+ .end = EXYNOS4_PA_SYSMMU_MFC_R + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[31] = {
@@ -177,11 +201,32 @@ static struct resource s5pv310_sysmmu_resource[] = {
},
};
-struct platform_device s5pv310_device_sysmmu = {
+struct platform_device exynos4_device_sysmmu = {
.name = "s5p-sysmmu",
.id = 32,
- .num_resources = ARRAY_SIZE(s5pv310_sysmmu_resource),
- .resource = s5pv310_sysmmu_resource,
+ .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource),
+ .resource = exynos4_sysmmu_resource,
};
+EXPORT_SYMBOL(exynos4_device_sysmmu);
+
+static struct clk *sysmmu_clk[S5P_SYSMMU_TOTAL_IPNUM];
+void sysmmu_clk_init(struct device *dev, sysmmu_ips ips)
+{
+ sysmmu_clk[ips] = clk_get(dev, sysmmu_ips_name[ips]);
+ if (IS_ERR(sysmmu_clk[ips]))
+ sysmmu_clk[ips] = NULL;
+ else
+ clk_put(sysmmu_clk[ips]);
+}
+
+void sysmmu_clk_enable(sysmmu_ips ips)
+{
+ if (sysmmu_clk[ips])
+ clk_enable(sysmmu_clk[ips]);
+}
-EXPORT_SYMBOL(s5pv310_device_sysmmu);
+void sysmmu_clk_disable(sysmmu_ips ips)
+{
+ if (sysmmu_clk[ips])
+ clk_disable(sysmmu_clk[ips]);
+}
diff --git a/arch/arm/mach-s5pv310/dma.c b/arch/arm/mach-exynos4/dma.c
index 20066c7c9e56..564bb530f332 100644
--- a/arch/arm/mach-s5pv310/dma.c
+++ b/arch/arm/mach-exynos4/dma.c
@@ -1,4 +1,8 @@
-/*
+/* linux/arch/arm/mach-exynos4/dma.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
@@ -30,10 +34,10 @@
static u64 dma_dmamask = DMA_BIT_MASK(32);
-static struct resource s5pv310_pdma0_resource[] = {
+static struct resource exynos4_pdma0_resource[] = {
[0] = {
- .start = S5PV310_PA_PDMA0,
- .end = S5PV310_PA_PDMA0 + SZ_4K,
+ .start = EXYNOS4_PA_PDMA0,
+ .end = EXYNOS4_PA_PDMA0 + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -43,7 +47,7 @@ static struct resource s5pv310_pdma0_resource[] = {
},
};
-static struct s3c_pl330_platdata s5pv310_pdma0_pdata = {
+static struct s3c_pl330_platdata exynos4_pdma0_pdata = {
.peri = {
[0] = DMACH_PCM0_RX,
[1] = DMACH_PCM0_TX,
@@ -80,22 +84,22 @@ static struct s3c_pl330_platdata s5pv310_pdma0_pdata = {
},
};
-static struct platform_device s5pv310_device_pdma0 = {
+static struct platform_device exynos4_device_pdma0 = {
.name = "s3c-pl330",
.id = 0,
- .num_resources = ARRAY_SIZE(s5pv310_pdma0_resource),
- .resource = s5pv310_pdma0_resource,
+ .num_resources = ARRAY_SIZE(exynos4_pdma0_resource),
+ .resource = exynos4_pdma0_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &s5pv310_pdma0_pdata,
+ .platform_data = &exynos4_pdma0_pdata,
},
};
-static struct resource s5pv310_pdma1_resource[] = {
+static struct resource exynos4_pdma1_resource[] = {
[0] = {
- .start = S5PV310_PA_PDMA1,
- .end = S5PV310_PA_PDMA1 + SZ_4K,
+ .start = EXYNOS4_PA_PDMA1,
+ .end = EXYNOS4_PA_PDMA1 + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -105,7 +109,7 @@ static struct resource s5pv310_pdma1_resource[] = {
},
};
-static struct s3c_pl330_platdata s5pv310_pdma1_pdata = {
+static struct s3c_pl330_platdata exynos4_pdma1_pdata = {
.peri = {
[0] = DMACH_PCM0_RX,
[1] = DMACH_PCM0_TX,
@@ -142,27 +146,27 @@ static struct s3c_pl330_platdata s5pv310_pdma1_pdata = {
},
};
-static struct platform_device s5pv310_device_pdma1 = {
+static struct platform_device exynos4_device_pdma1 = {
.name = "s3c-pl330",
.id = 1,
- .num_resources = ARRAY_SIZE(s5pv310_pdma1_resource),
- .resource = s5pv310_pdma1_resource,
+ .num_resources = ARRAY_SIZE(exynos4_pdma1_resource),
+ .resource = exynos4_pdma1_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &s5pv310_pdma1_pdata,
+ .platform_data = &exynos4_pdma1_pdata,
},
};
-static struct platform_device *s5pv310_dmacs[] __initdata = {
- &s5pv310_device_pdma0,
- &s5pv310_device_pdma1,
+static struct platform_device *exynos4_dmacs[] __initdata = {
+ &exynos4_device_pdma0,
+ &exynos4_device_pdma1,
};
-static int __init s5pv310_dma_init(void)
+static int __init exynos4_dma_init(void)
{
- platform_add_devices(s5pv310_dmacs, ARRAY_SIZE(s5pv310_dmacs));
+ platform_add_devices(exynos4_dmacs, ARRAY_SIZE(exynos4_dmacs));
return 0;
}
-arch_initcall(s5pv310_dma_init);
+arch_initcall(exynos4_dma_init);
diff --git a/arch/arm/mach-exynos4/gpiolib.c b/arch/arm/mach-exynos4/gpiolib.c
new file mode 100644
index 000000000000..d54ca6adb660
--- /dev/null
+++ b/arch/arm/mach-exynos4/gpiolib.c
@@ -0,0 +1,365 @@
+/* linux/arch/arm/mach-exynos4/gpiolib.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - GPIOlib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+static struct s3c_gpio_cfg gpio_cfg = {
+ .set_config = s3c_gpio_setcfg_s3c64xx_4bit,
+ .set_pull = s3c_gpio_setpull_updown,
+ .get_pull = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_cfg_noint = {
+ .set_config = s3c_gpio_setcfg_s3c64xx_4bit,
+ .set_pull = s3c_gpio_setpull_updown,
+ .get_pull = s3c_gpio_getpull_updown,
+};
+
+/*
+ * Following are the gpio banks in v310.
+ *
+ * The 'config' member when left to NULL, is initialized to the default
+ * structure gpio_cfg in the init function below.
+ *
+ * The 'base' member is also initialized in the init function below.
+ * Note: The initialization of 'base' member of s3c_gpio_chip structure
+ * uses the above macro and depends on the banks being listed in order here.
+ */
+static struct s3c_gpio_chip exynos4_gpio_part1_4bit[] = {
+ {
+ .chip = {
+ .base = EXYNOS4_GPA0(0),
+ .ngpio = EXYNOS4_GPIO_A0_NR,
+ .label = "GPA0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPA1(0),
+ .ngpio = EXYNOS4_GPIO_A1_NR,
+ .label = "GPA1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPB(0),
+ .ngpio = EXYNOS4_GPIO_B_NR,
+ .label = "GPB",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPC0(0),
+ .ngpio = EXYNOS4_GPIO_C0_NR,
+ .label = "GPC0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPC1(0),
+ .ngpio = EXYNOS4_GPIO_C1_NR,
+ .label = "GPC1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPD0(0),
+ .ngpio = EXYNOS4_GPIO_D0_NR,
+ .label = "GPD0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPD1(0),
+ .ngpio = EXYNOS4_GPIO_D1_NR,
+ .label = "GPD1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPE0(0),
+ .ngpio = EXYNOS4_GPIO_E0_NR,
+ .label = "GPE0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPE1(0),
+ .ngpio = EXYNOS4_GPIO_E1_NR,
+ .label = "GPE1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPE2(0),
+ .ngpio = EXYNOS4_GPIO_E2_NR,
+ .label = "GPE2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPE3(0),
+ .ngpio = EXYNOS4_GPIO_E3_NR,
+ .label = "GPE3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPE4(0),
+ .ngpio = EXYNOS4_GPIO_E4_NR,
+ .label = "GPE4",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPF0(0),
+ .ngpio = EXYNOS4_GPIO_F0_NR,
+ .label = "GPF0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPF1(0),
+ .ngpio = EXYNOS4_GPIO_F1_NR,
+ .label = "GPF1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPF2(0),
+ .ngpio = EXYNOS4_GPIO_F2_NR,
+ .label = "GPF2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPF3(0),
+ .ngpio = EXYNOS4_GPIO_F3_NR,
+ .label = "GPF3",
+ },
+ },
+};
+
+static struct s3c_gpio_chip exynos4_gpio_part2_4bit[] = {
+ {
+ .chip = {
+ .base = EXYNOS4_GPJ0(0),
+ .ngpio = EXYNOS4_GPIO_J0_NR,
+ .label = "GPJ0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPJ1(0),
+ .ngpio = EXYNOS4_GPIO_J1_NR,
+ .label = "GPJ1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPK0(0),
+ .ngpio = EXYNOS4_GPIO_K0_NR,
+ .label = "GPK0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPK1(0),
+ .ngpio = EXYNOS4_GPIO_K1_NR,
+ .label = "GPK1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPK2(0),
+ .ngpio = EXYNOS4_GPIO_K2_NR,
+ .label = "GPK2",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPK3(0),
+ .ngpio = EXYNOS4_GPIO_K3_NR,
+ .label = "GPK3",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPL0(0),
+ .ngpio = EXYNOS4_GPIO_L0_NR,
+ .label = "GPL0",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPL1(0),
+ .ngpio = EXYNOS4_GPIO_L1_NR,
+ .label = "GPL1",
+ },
+ }, {
+ .chip = {
+ .base = EXYNOS4_GPL2(0),
+ .ngpio = EXYNOS4_GPIO_L2_NR,
+ .label = "GPL2",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY0(0),
+ .ngpio = EXYNOS4_GPIO_Y0_NR,
+ .label = "GPY0",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY1(0),
+ .ngpio = EXYNOS4_GPIO_Y1_NR,
+ .label = "GPY1",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY2(0),
+ .ngpio = EXYNOS4_GPIO_Y2_NR,
+ .label = "GPY2",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY3(0),
+ .ngpio = EXYNOS4_GPIO_Y3_NR,
+ .label = "GPY3",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY4(0),
+ .ngpio = EXYNOS4_GPIO_Y4_NR,
+ .label = "GPY4",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY5(0),
+ .ngpio = EXYNOS4_GPIO_Y5_NR,
+ .label = "GPY5",
+ },
+ }, {
+ .config = &gpio_cfg_noint,
+ .chip = {
+ .base = EXYNOS4_GPY6(0),
+ .ngpio = EXYNOS4_GPIO_Y6_NR,
+ .label = "GPY6",
+ },
+ }, {
+ .base = (S5P_VA_GPIO2 + 0xC00),
+ .config = &gpio_cfg_noint,
+ .irq_base = IRQ_EINT(0),
+ .chip = {
+ .base = EXYNOS4_GPX0(0),
+ .ngpio = EXYNOS4_GPIO_X0_NR,
+ .label = "GPX0",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .base = (S5P_VA_GPIO2 + 0xC20),
+ .config = &gpio_cfg_noint,
+ .irq_base = IRQ_EINT(8),
+ .chip = {
+ .base = EXYNOS4_GPX1(0),
+ .ngpio = EXYNOS4_GPIO_X1_NR,
+ .label = "GPX1",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .base = (S5P_VA_GPIO2 + 0xC40),
+ .config = &gpio_cfg_noint,
+ .irq_base = IRQ_EINT(16),
+ .chip = {
+ .base = EXYNOS4_GPX2(0),
+ .ngpio = EXYNOS4_GPIO_X2_NR,
+ .label = "GPX2",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ }, {
+ .base = (S5P_VA_GPIO2 + 0xC60),
+ .config = &gpio_cfg_noint,
+ .irq_base = IRQ_EINT(24),
+ .chip = {
+ .base = EXYNOS4_GPX3(0),
+ .ngpio = EXYNOS4_GPIO_X3_NR,
+ .label = "GPX3",
+ .to_irq = samsung_gpiolib_to_irq,
+ },
+ },
+};
+
+static struct s3c_gpio_chip exynos4_gpio_part3_4bit[] = {
+ {
+ .chip = {
+ .base = EXYNOS4_GPZ(0),
+ .ngpio = EXYNOS4_GPIO_Z_NR,
+ .label = "GPZ",
+ },
+ },
+};
+
+static __init int exynos4_gpiolib_init(void)
+{
+ struct s3c_gpio_chip *chip;
+ int i;
+ int group = 0;
+ int nr_chips;
+
+ /* GPIO part 1 */
+
+ chip = exynos4_gpio_part1_4bit;
+ nr_chips = ARRAY_SIZE(exynos4_gpio_part1_4bit);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (chip->config == NULL) {
+ chip->config = &gpio_cfg;
+ /* Assign the GPIO interrupt group */
+ chip->group = group++;
+ }
+ if (chip->base == NULL)
+ chip->base = S5P_VA_GPIO1 + (i) * 0x20;
+ }
+
+ samsung_gpiolib_add_4bit_chips(exynos4_gpio_part1_4bit, nr_chips);
+
+ /* GPIO part 2 */
+
+ chip = exynos4_gpio_part2_4bit;
+ nr_chips = ARRAY_SIZE(exynos4_gpio_part2_4bit);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (chip->config == NULL) {
+ chip->config = &gpio_cfg;
+ /* Assign the GPIO interrupt group */
+ chip->group = group++;
+ }
+ if (chip->base == NULL)
+ chip->base = S5P_VA_GPIO2 + (i) * 0x20;
+ }
+
+ samsung_gpiolib_add_4bit_chips(exynos4_gpio_part2_4bit, nr_chips);
+
+ /* GPIO part 3 */
+
+ chip = exynos4_gpio_part3_4bit;
+ nr_chips = ARRAY_SIZE(exynos4_gpio_part3_4bit);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (chip->config == NULL) {
+ chip->config = &gpio_cfg;
+ /* Assign the GPIO interrupt group */
+ chip->group = group++;
+ }
+ if (chip->base == NULL)
+ chip->base = S5P_VA_GPIO3 + (i) * 0x20;
+ }
+
+ samsung_gpiolib_add_4bit_chips(exynos4_gpio_part3_4bit, nr_chips);
+ s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
+ s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
+
+ return 0;
+}
+core_initcall(exynos4_gpiolib_init);
diff --git a/arch/arm/mach-s5pv310/headsmp.S b/arch/arm/mach-exynos4/headsmp.S
index 164b7b045713..6c6cfc50c46b 100644
--- a/arch/arm/mach-s5pv310/headsmp.S
+++ b/arch/arm/mach-exynos4/headsmp.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/headsmp.S
+ * linux/arch/arm/mach-exynos4/headsmp.S
*
* Cloned from linux/arch/arm/mach-realview/headsmp.S
*
@@ -16,11 +16,11 @@
__INIT
/*
- * s5pv310 specific entry point for secondary CPUs. This provides
+ * exynos4 specific entry point for secondary CPUs. This provides
* a "holding pen" into which all secondary cores are held until we're
* ready for them to initialise.
*/
-ENTRY(s5pv310_secondary_startup)
+ENTRY(exynos4_secondary_startup)
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #15
adr r4, 1f
diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-exynos4/hotplug.c
index c24235c89eed..2b5909e2ccd3 100644
--- a/arch/arm/mach-s5pv310/hotplug.c
+++ b/arch/arm/mach-exynos4/hotplug.c
@@ -1,4 +1,4 @@
-/* linux arch/arm/mach-s5pv310/hotplug.c
+/* linux arch/arm/mach-exynos4/hotplug.c
*
* Cloned from linux/arch/arm/mach-realview/hotplug.c
*
@@ -30,13 +30,13 @@ static inline void cpu_enter_lowpower(void)
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1\n"
- " bic %0, %0, #0x20\n"
+ " bic %0, %0, %3\n"
" mcr p15, 0, %0, c1, c0, 1\n"
" mrc p15, 0, %0, c1, c0, 0\n"
" bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
- : "r" (0), "Ir" (CR_C)
+ : "r" (0), "Ir" (CR_C), "Ir" (0x40)
: "cc");
}
@@ -49,10 +49,10 @@ static inline void cpu_leave_lowpower(void)
" orr %0, %0, %1\n"
" mcr p15, 0, %0, c1, c0, 0\n"
" mrc p15, 0, %0, c1, c0, 1\n"
- " orr %0, %0, #0x20\n"
+ " orr %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 1\n"
: "=&r" (v)
- : "Ir" (CR_C)
+ : "Ir" (CR_C), "Ir" (0x40)
: "cc");
}
diff --git a/arch/arm/mach-s5pv310/include/mach/debug-macro.S b/arch/arm/mach-exynos4/include/mach/debug-macro.S
index b0d920c474d3..58bbd049a6c4 100644
--- a/arch/arm/mach-s5pv310/include/mach/debug-macro.S
+++ b/arch/arm/mach-exynos4/include/mach/debug-macro.S
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/debug-macro.S
+/* linux/arch/arm/mach-exynos4/include/mach/debug-macro.S
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Based on arch/arm/mach-s3c6400/include/mach/debug-macro.S
*
diff --git a/arch/arm/mach-s5pv310/include/mach/dma.h b/arch/arm/mach-exynos4/include/mach/dma.h
index 81209eb1409b..81209eb1409b 100644
--- a/arch/arm/mach-s5pv310/include/mach/dma.h
+++ b/arch/arm/mach-exynos4/include/mach/dma.h
diff --git a/arch/arm/mach-s5pv310/include/mach/entry-macro.S b/arch/arm/mach-exynos4/include/mach/entry-macro.S
index e600e1d522df..d8f38c2e5654 100644
--- a/arch/arm/mach-s5pv310/include/mach/entry-macro.S
+++ b/arch/arm/mach-exynos4/include/mach/entry-macro.S
@@ -1,8 +1,8 @@
-/* arch/arm/mach-s5pv310/include/mach/entry-macro.S
+/* arch/arm/mach-exynos4/include/mach/entry-macro.S
*
* Cloned from arch/arm/mach-realview/include/mach/entry-macro.S
*
- * Low-level IRQ helper macros for S5PV310 platforms
+ * Low-level IRQ helper macros for EXYNOS4 platforms
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/arch/arm/mach-exynos4/include/mach/gpio.h b/arch/arm/mach-exynos4/include/mach/gpio.h
new file mode 100644
index 000000000000..939728b38d48
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/gpio.h
@@ -0,0 +1,156 @@
+/* linux/arch/arm/mach-exynos4/include/mach/gpio.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - GPIO lib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H __FILE__
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
+
+/* Practically, GPIO banks upto GPZ are the configurable gpio banks */
+
+/* GPIO bank sizes */
+#define EXYNOS4_GPIO_A0_NR (8)
+#define EXYNOS4_GPIO_A1_NR (6)
+#define EXYNOS4_GPIO_B_NR (8)
+#define EXYNOS4_GPIO_C0_NR (5)
+#define EXYNOS4_GPIO_C1_NR (5)
+#define EXYNOS4_GPIO_D0_NR (4)
+#define EXYNOS4_GPIO_D1_NR (4)
+#define EXYNOS4_GPIO_E0_NR (5)
+#define EXYNOS4_GPIO_E1_NR (8)
+#define EXYNOS4_GPIO_E2_NR (6)
+#define EXYNOS4_GPIO_E3_NR (8)
+#define EXYNOS4_GPIO_E4_NR (8)
+#define EXYNOS4_GPIO_F0_NR (8)
+#define EXYNOS4_GPIO_F1_NR (8)
+#define EXYNOS4_GPIO_F2_NR (8)
+#define EXYNOS4_GPIO_F3_NR (6)
+#define EXYNOS4_GPIO_J0_NR (8)
+#define EXYNOS4_GPIO_J1_NR (5)
+#define EXYNOS4_GPIO_K0_NR (7)
+#define EXYNOS4_GPIO_K1_NR (7)
+#define EXYNOS4_GPIO_K2_NR (7)
+#define EXYNOS4_GPIO_K3_NR (7)
+#define EXYNOS4_GPIO_L0_NR (8)
+#define EXYNOS4_GPIO_L1_NR (3)
+#define EXYNOS4_GPIO_L2_NR (8)
+#define EXYNOS4_GPIO_X0_NR (8)
+#define EXYNOS4_GPIO_X1_NR (8)
+#define EXYNOS4_GPIO_X2_NR (8)
+#define EXYNOS4_GPIO_X3_NR (8)
+#define EXYNOS4_GPIO_Y0_NR (6)
+#define EXYNOS4_GPIO_Y1_NR (4)
+#define EXYNOS4_GPIO_Y2_NR (6)
+#define EXYNOS4_GPIO_Y3_NR (8)
+#define EXYNOS4_GPIO_Y4_NR (8)
+#define EXYNOS4_GPIO_Y5_NR (8)
+#define EXYNOS4_GPIO_Y6_NR (8)
+#define EXYNOS4_GPIO_Z_NR (7)
+
+/* GPIO bank numbers */
+
+#define EXYNOS4_GPIO_NEXT(__gpio) \
+ ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+enum s5p_gpio_number {
+ EXYNOS4_GPIO_A0_START = 0,
+ EXYNOS4_GPIO_A1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A0),
+ EXYNOS4_GPIO_B_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_A1),
+ EXYNOS4_GPIO_C0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_B),
+ EXYNOS4_GPIO_C1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C0),
+ EXYNOS4_GPIO_D0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_C1),
+ EXYNOS4_GPIO_D1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D0),
+ EXYNOS4_GPIO_E0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_D1),
+ EXYNOS4_GPIO_E1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E0),
+ EXYNOS4_GPIO_E2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E1),
+ EXYNOS4_GPIO_E3_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E2),
+ EXYNOS4_GPIO_E4_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E3),
+ EXYNOS4_GPIO_F0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_E4),
+ EXYNOS4_GPIO_F1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F0),
+ EXYNOS4_GPIO_F2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F1),
+ EXYNOS4_GPIO_F3_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F2),
+ EXYNOS4_GPIO_J0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_F3),
+ EXYNOS4_GPIO_J1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J0),
+ EXYNOS4_GPIO_K0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_J1),
+ EXYNOS4_GPIO_K1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K0),
+ EXYNOS4_GPIO_K2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K1),
+ EXYNOS4_GPIO_K3_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K2),
+ EXYNOS4_GPIO_L0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_K3),
+ EXYNOS4_GPIO_L1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L0),
+ EXYNOS4_GPIO_L2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L1),
+ EXYNOS4_GPIO_X0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_L2),
+ EXYNOS4_GPIO_X1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X0),
+ EXYNOS4_GPIO_X2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X1),
+ EXYNOS4_GPIO_X3_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X2),
+ EXYNOS4_GPIO_Y0_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_X3),
+ EXYNOS4_GPIO_Y1_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y0),
+ EXYNOS4_GPIO_Y2_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y1),
+ EXYNOS4_GPIO_Y3_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y2),
+ EXYNOS4_GPIO_Y4_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y3),
+ EXYNOS4_GPIO_Y5_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y4),
+ EXYNOS4_GPIO_Y6_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y5),
+ EXYNOS4_GPIO_Z_START = EXYNOS4_GPIO_NEXT(EXYNOS4_GPIO_Y6),
+};
+
+/* EXYNOS4 GPIO number definitions */
+#define EXYNOS4_GPA0(_nr) (EXYNOS4_GPIO_A0_START + (_nr))
+#define EXYNOS4_GPA1(_nr) (EXYNOS4_GPIO_A1_START + (_nr))
+#define EXYNOS4_GPB(_nr) (EXYNOS4_GPIO_B_START + (_nr))
+#define EXYNOS4_GPC0(_nr) (EXYNOS4_GPIO_C0_START + (_nr))
+#define EXYNOS4_GPC1(_nr) (EXYNOS4_GPIO_C1_START + (_nr))
+#define EXYNOS4_GPD0(_nr) (EXYNOS4_GPIO_D0_START + (_nr))
+#define EXYNOS4_GPD1(_nr) (EXYNOS4_GPIO_D1_START + (_nr))
+#define EXYNOS4_GPE0(_nr) (EXYNOS4_GPIO_E0_START + (_nr))
+#define EXYNOS4_GPE1(_nr) (EXYNOS4_GPIO_E1_START + (_nr))
+#define EXYNOS4_GPE2(_nr) (EXYNOS4_GPIO_E2_START + (_nr))
+#define EXYNOS4_GPE3(_nr) (EXYNOS4_GPIO_E3_START + (_nr))
+#define EXYNOS4_GPE4(_nr) (EXYNOS4_GPIO_E4_START + (_nr))
+#define EXYNOS4_GPF0(_nr) (EXYNOS4_GPIO_F0_START + (_nr))
+#define EXYNOS4_GPF1(_nr) (EXYNOS4_GPIO_F1_START + (_nr))
+#define EXYNOS4_GPF2(_nr) (EXYNOS4_GPIO_F2_START + (_nr))
+#define EXYNOS4_GPF3(_nr) (EXYNOS4_GPIO_F3_START + (_nr))
+#define EXYNOS4_GPJ0(_nr) (EXYNOS4_GPIO_J0_START + (_nr))
+#define EXYNOS4_GPJ1(_nr) (EXYNOS4_GPIO_J1_START + (_nr))
+#define EXYNOS4_GPK0(_nr) (EXYNOS4_GPIO_K0_START + (_nr))
+#define EXYNOS4_GPK1(_nr) (EXYNOS4_GPIO_K1_START + (_nr))
+#define EXYNOS4_GPK2(_nr) (EXYNOS4_GPIO_K2_START + (_nr))
+#define EXYNOS4_GPK3(_nr) (EXYNOS4_GPIO_K3_START + (_nr))
+#define EXYNOS4_GPL0(_nr) (EXYNOS4_GPIO_L0_START + (_nr))
+#define EXYNOS4_GPL1(_nr) (EXYNOS4_GPIO_L1_START + (_nr))
+#define EXYNOS4_GPL2(_nr) (EXYNOS4_GPIO_L2_START + (_nr))
+#define EXYNOS4_GPX0(_nr) (EXYNOS4_GPIO_X0_START + (_nr))
+#define EXYNOS4_GPX1(_nr) (EXYNOS4_GPIO_X1_START + (_nr))
+#define EXYNOS4_GPX2(_nr) (EXYNOS4_GPIO_X2_START + (_nr))
+#define EXYNOS4_GPX3(_nr) (EXYNOS4_GPIO_X3_START + (_nr))
+#define EXYNOS4_GPY0(_nr) (EXYNOS4_GPIO_Y0_START + (_nr))
+#define EXYNOS4_GPY1(_nr) (EXYNOS4_GPIO_Y1_START + (_nr))
+#define EXYNOS4_GPY2(_nr) (EXYNOS4_GPIO_Y2_START + (_nr))
+#define EXYNOS4_GPY3(_nr) (EXYNOS4_GPIO_Y3_START + (_nr))
+#define EXYNOS4_GPY4(_nr) (EXYNOS4_GPIO_Y4_START + (_nr))
+#define EXYNOS4_GPY5(_nr) (EXYNOS4_GPIO_Y5_START + (_nr))
+#define EXYNOS4_GPY6(_nr) (EXYNOS4_GPIO_Y6_START + (_nr))
+#define EXYNOS4_GPZ(_nr) (EXYNOS4_GPIO_Z_START + (_nr))
+
+/* the end of the EXYNOS4 specific gpios */
+#define EXYNOS4_GPIO_END (EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) + 1)
+#define S3C_GPIO_END EXYNOS4_GPIO_END
+
+/* define the number of gpios we need to the one after the GPZ() range */
+#define ARCH_NR_GPIOS (EXYNOS4_GPZ(EXYNOS4_GPIO_Z_NR) + \
+ CONFIG_SAMSUNG_GPIO_EXTRA + 1)
+
+#include <asm-generic/gpio.h>
+
+#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/hardware.h b/arch/arm/mach-exynos4/include/mach/hardware.h
index 28ff9881f1a6..5109eb232f23 100644
--- a/arch/arm/mach-s5pv310/include/mach/hardware.h
+++ b/arch/arm/mach-exynos4/include/mach/hardware.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/hardware.h
+/* linux/arch/arm/mach-exynos4/include/mach/hardware.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Hardware support
+ * EXYNOS4 - Hardware support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/io.h b/arch/arm/mach-exynos4/include/mach/io.h
index 8a7f9128391f..d5478d247535 100644
--- a/arch/arm/mach-s5pv310/include/mach/io.h
+++ b/arch/arm/mach-exynos4/include/mach/io.h
@@ -1,13 +1,13 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/io.h
+/* linux/arch/arm/mach-exynos4/include/mach/io.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright 2008-2010 Ben Dooks <ben-linux@fluff.org>
*
* Based on arch/arm/mach-s5p6442/include/mach/io.h
*
- * Default IO routines for S5PV310
+ * Default IO routines for EXYNOS4
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 536b0b59fc83..5d037301d21a 100644
--- a/arch/arm/mach-s5pv310/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/irqs.h
+/* linux/arch/arm/mach-exynos4/include/mach/irqs.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - IRQ definitions
+ * EXYNOS4 - IRQ definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -85,6 +85,9 @@
#define IRQ_RTC_ALARM COMBINER_IRQ(23, 0)
#define IRQ_RTC_TIC COMBINER_IRQ(23, 1)
+#define IRQ_GPIO_XB COMBINER_IRQ(24, 0)
+#define IRQ_GPIO_XA COMBINER_IRQ(24, 1)
+
#define IRQ_UART0 COMBINER_IRQ(26, 0)
#define IRQ_UART1 COMBINER_IRQ(26, 1)
#define IRQ_UART2 COMBINER_IRQ(26, 2)
@@ -108,6 +111,11 @@
#define IRQ_MIPI_CSIS0 COMBINER_IRQ(30, 0)
#define IRQ_MIPI_CSIS1 COMBINER_IRQ(30, 1)
+#define IRQ_FIMC0 COMBINER_IRQ(32, 0)
+#define IRQ_FIMC1 COMBINER_IRQ(32, 1)
+#define IRQ_FIMC2 COMBINER_IRQ(33, 0)
+#define IRQ_FIMC3 COMBINER_IRQ(33, 1)
+
#define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0)
#define IRQ_MCT_L1 COMBINER_IRQ(35, 3)
@@ -131,6 +139,7 @@
#define IRQ_MCT_L0 COMBINER_IRQ(51, 0)
#define IRQ_WDT COMBINER_IRQ(53, 0)
+#define IRQ_MCT_G0 COMBINER_IRQ(53, 4)
#define MAX_COMBINER_NR 54
@@ -139,8 +148,13 @@
#define S5P_EINT_BASE1 (S5P_IRQ_EINT_BASE + 0)
#define S5P_EINT_BASE2 (S5P_IRQ_EINT_BASE + 16)
-/* Set the default NR_IRQS */
+/* optional GPIO interrupts */
+#define S5P_GPIOINT_BASE (S5P_IRQ_EINT_BASE + 32)
+#define IRQ_GPIO1_NR_GROUPS 16
+#define IRQ_GPIO2_NR_GROUPS 9
+#define IRQ_GPIO_END (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
-#define NR_IRQS (S5P_IRQ_EINT_BASE + 32)
+/* Set the default NR_IRQS */
+#define NR_IRQS (IRQ_GPIO_END)
#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h
new file mode 100644
index 000000000000..6330b73b9ea7
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/map.h
@@ -0,0 +1,162 @@
+/* linux/arch/arm/mach-exynos4/include/mach/map.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS4 - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H __FILE__
+
+#include <plat/map-base.h>
+
+/*
+ * EXYNOS4 UART offset is 0x10000 but the older S5P SoCs are 0x400.
+ * So need to define it, and here is to avoid redefinition warning.
+ */
+#define S3C_UART_OFFSET (0x10000)
+
+#include <plat/map-s5p.h>
+
+#define EXYNOS4_PA_SYSRAM 0x02020000
+
+#define EXYNOS4_PA_FIMC0 0x11800000
+#define EXYNOS4_PA_FIMC1 0x11810000
+#define EXYNOS4_PA_FIMC2 0x11820000
+#define EXYNOS4_PA_FIMC3 0x11830000
+
+#define EXYNOS4_PA_I2S0 0x03830000
+#define EXYNOS4_PA_I2S1 0xE3100000
+#define EXYNOS4_PA_I2S2 0xE2A00000
+
+#define EXYNOS4_PA_PCM0 0x03840000
+#define EXYNOS4_PA_PCM1 0x13980000
+#define EXYNOS4_PA_PCM2 0x13990000
+
+#define EXYNOS4_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000))
+
+#define EXYNOS4_PA_ONENAND 0x0C000000
+#define EXYNOS4_PA_ONENAND_DMA 0x0C600000
+
+#define EXYNOS4_PA_CHIPID 0x10000000
+
+#define EXYNOS4_PA_SYSCON 0x10010000
+#define EXYNOS4_PA_PMU 0x10020000
+#define EXYNOS4_PA_CMU 0x10030000
+
+#define EXYNOS4_PA_SYSTIMER 0x10050000
+#define EXYNOS4_PA_WATCHDOG 0x10060000
+#define EXYNOS4_PA_RTC 0x10070000
+
+#define EXYNOS4_PA_KEYPAD 0x100A0000
+
+#define EXYNOS4_PA_DMC0 0x10400000
+
+#define EXYNOS4_PA_COMBINER 0x10448000
+
+#define EXYNOS4_PA_COREPERI 0x10500000
+#define EXYNOS4_PA_GIC_CPU 0x10500100
+#define EXYNOS4_PA_TWD 0x10500600
+#define EXYNOS4_PA_GIC_DIST 0x10501000
+#define EXYNOS4_PA_L2CC 0x10502000
+
+#define EXYNOS4_PA_MDMA 0x10810000
+#define EXYNOS4_PA_PDMA0 0x12680000
+#define EXYNOS4_PA_PDMA1 0x12690000
+
+#define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000
+#define EXYNOS4_PA_SYSMMU_SSS 0x10A50000
+#define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000
+#define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000
+#define EXYNOS4_PA_SYSMMU_FIMC2 0x11A40000
+#define EXYNOS4_PA_SYSMMU_FIMC3 0x11A50000
+#define EXYNOS4_PA_SYSMMU_JPEG 0x11A60000
+#define EXYNOS4_PA_SYSMMU_FIMD0 0x11E20000
+#define EXYNOS4_PA_SYSMMU_FIMD1 0x12220000
+#define EXYNOS4_PA_SYSMMU_PCIe 0x12620000
+#define EXYNOS4_PA_SYSMMU_G2D 0x12A20000
+#define EXYNOS4_PA_SYSMMU_ROTATOR 0x12A30000
+#define EXYNOS4_PA_SYSMMU_MDMA2 0x12A40000
+#define EXYNOS4_PA_SYSMMU_TV 0x12E20000
+#define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000
+#define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000
+
+#define EXYNOS4_PA_GPIO1 0x11400000
+#define EXYNOS4_PA_GPIO2 0x11000000
+#define EXYNOS4_PA_GPIO3 0x03860000
+
+#define EXYNOS4_PA_MIPI_CSIS0 0x11880000
+#define EXYNOS4_PA_MIPI_CSIS1 0x11890000
+
+#define EXYNOS4_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
+
+#define EXYNOS4_PA_SATA 0x12560000
+#define EXYNOS4_PA_SATAPHY 0x125D0000
+#define EXYNOS4_PA_SATAPHY_CTRL 0x126B0000
+
+#define EXYNOS4_PA_SROMC 0x12570000
+
+#define EXYNOS4_PA_UART 0x13800000
+
+#define EXYNOS4_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
+
+#define EXYNOS4_PA_AC97 0x139A0000
+
+#define EXYNOS4_PA_SPDIF 0x139B0000
+
+#define EXYNOS4_PA_TIMER 0x139D0000
+
+#define EXYNOS4_PA_SDRAM 0x40000000
+
+/* Compatibiltiy Defines */
+
+#define S3C_PA_HSMMC0 EXYNOS4_PA_HSMMC(0)
+#define S3C_PA_HSMMC1 EXYNOS4_PA_HSMMC(1)
+#define S3C_PA_HSMMC2 EXYNOS4_PA_HSMMC(2)
+#define S3C_PA_HSMMC3 EXYNOS4_PA_HSMMC(3)
+#define S3C_PA_IIC EXYNOS4_PA_IIC(0)
+#define S3C_PA_IIC1 EXYNOS4_PA_IIC(1)
+#define S3C_PA_IIC2 EXYNOS4_PA_IIC(2)
+#define S3C_PA_IIC3 EXYNOS4_PA_IIC(3)
+#define S3C_PA_IIC4 EXYNOS4_PA_IIC(4)
+#define S3C_PA_IIC5 EXYNOS4_PA_IIC(5)
+#define S3C_PA_IIC6 EXYNOS4_PA_IIC(6)
+#define S3C_PA_IIC7 EXYNOS4_PA_IIC(7)
+#define S3C_PA_RTC EXYNOS4_PA_RTC
+#define S3C_PA_WDT EXYNOS4_PA_WATCHDOG
+
+#define S5P_PA_CHIPID EXYNOS4_PA_CHIPID
+#define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0
+#define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1
+#define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2
+#define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3
+#define S5P_PA_MIPI_CSIS0 EXYNOS4_PA_MIPI_CSIS0
+#define S5P_PA_MIPI_CSIS1 EXYNOS4_PA_MIPI_CSIS1
+#define S5P_PA_ONENAND EXYNOS4_PA_ONENAND
+#define S5P_PA_ONENAND_DMA EXYNOS4_PA_ONENAND_DMA
+#define S5P_PA_SDRAM EXYNOS4_PA_SDRAM
+#define S5P_PA_SROMC EXYNOS4_PA_SROMC
+#define S5P_PA_SYSCON EXYNOS4_PA_SYSCON
+#define S5P_PA_TIMER EXYNOS4_PA_TIMER
+
+#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
+
+/* UART */
+
+#define S3C_PA_UART EXYNOS4_PA_UART
+
+#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0 S5P_PA_UART(0)
+#define S5P_PA_UART1 S5P_PA_UART(1)
+#define S5P_PA_UART2 S5P_PA_UART(2)
+#define S5P_PA_UART3 S5P_PA_UART(3)
+#define S5P_PA_UART4 S5P_PA_UART(4)
+
+#define S5P_SZ_UART SZ_256
+
+#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/memory.h b/arch/arm/mach-exynos4/include/mach/memory.h
index 470b01bf8614..374ef2cf7152 100644
--- a/arch/arm/mach-s5pv310/include/mach/memory.h
+++ b/arch/arm/mach-exynos4/include/mach/memory.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/memory.h
+/* linux/arch/arm/mach-exynos4/include/mach/memory.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Memory definitions
+ * EXYNOS4 - Memory definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-exynos4/include/mach/pm-core.h b/arch/arm/mach-exynos4/include/mach/pm-core.h
new file mode 100644
index 000000000000..f26e46bc06ca
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/pm-core.h
@@ -0,0 +1,49 @@
+/* linux/arch/arm/mach-exynos4/include/mach/pm-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h,
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * EXYNOS4210 - PM core support for arch/arm/plat-s5p/pm.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#include <mach/regs-pmu.h>
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+ /* nothing here yet */
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+ unsigned int tmp;
+ tmp = __raw_readl(S5P_WAKEUP_MASK);
+ tmp &= ~(1 << 31);
+ __raw_writel(tmp, S5P_WAKEUP_MASK);
+
+ __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK);
+ __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK);
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+ /* nothing here yet */
+}
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+ /* nothing here yet */
+}
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+ struct pm_uart_save *save)
+{
+ /* nothing here yet */
+}
diff --git a/arch/arm/mach-s5pv310/include/mach/pwm-clock.h b/arch/arm/mach-exynos4/include/mach/pwm-clock.h
index 7e6da2701088..8e12090287bb 100644
--- a/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+++ b/arch/arm/mach-exynos4/include/mach/pwm-clock.h
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/pwm-clock.h
+/* linux/arch/arm/mach-exynos4/include/mach/pwm-clock.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
@@ -10,7 +10,7 @@
*
* Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
*
- * S5PV310 - pwm clock and timer support
+ * EXYNOS4 - pwm clock and timer support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-exynos4/include/mach/regs-clock.h
index b5c4ada1cff5..6e311c1157f5 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-clock.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+/* linux/arch/arm/mach-exynos4/include/mach/regs-clock.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Clock register definitions
+ * EXYNOS4 - Clock register definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,13 +17,13 @@
#define S5P_CLKREG(x) (S5P_VA_CMU + (x))
-#define S5P_INFORM0 S5P_CLKREG(0x800)
-
#define S5P_CLKDIV_LEFTBUS S5P_CLKREG(0x04500)
#define S5P_CLKDIV_STAT_LEFTBUS S5P_CLKREG(0x04600)
+#define S5P_CLKGATE_IP_LEFTBUS S5P_CLKREG(0x04800)
#define S5P_CLKDIV_RIGHTBUS S5P_CLKREG(0x08500)
#define S5P_CLKDIV_STAT_RIGHTBUS S5P_CLKREG(0x08600)
+#define S5P_CLKGATE_IP_RIGHTBUS S5P_CLKREG(0x08800)
#define S5P_EPLL_CON0 S5P_CLKREG(0x0C110)
#define S5P_EPLL_CON1 S5P_CLKREG(0x0C114)
@@ -33,18 +33,24 @@
#define S5P_CLKSRC_TOP0 S5P_CLKREG(0x0C210)
#define S5P_CLKSRC_TOP1 S5P_CLKREG(0x0C214)
#define S5P_CLKSRC_CAM S5P_CLKREG(0x0C220)
+#define S5P_CLKSRC_MFC S5P_CLKREG(0x0C228)
#define S5P_CLKSRC_IMAGE S5P_CLKREG(0x0C230)
#define S5P_CLKSRC_LCD0 S5P_CLKREG(0x0C234)
#define S5P_CLKSRC_LCD1 S5P_CLKREG(0x0C238)
+#define S5P_CLKSRC_MAUDIO S5P_CLKREG(0x0C23C)
#define S5P_CLKSRC_FSYS S5P_CLKREG(0x0C240)
#define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250)
#define S5P_CLKSRC_PERIL1 S5P_CLKREG(0x0C254)
#define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510)
#define S5P_CLKDIV_CAM S5P_CLKREG(0x0C520)
+#define S5P_CLKDIV_TV S5P_CLKREG(0x0C524)
+#define S5P_CLKDIV_MFC S5P_CLKREG(0x0C528)
+#define S5P_CLKDIV_G3D S5P_CLKREG(0x0C52C)
#define S5P_CLKDIV_IMAGE S5P_CLKREG(0x0C530)
#define S5P_CLKDIV_LCD0 S5P_CLKREG(0x0C534)
#define S5P_CLKDIV_LCD1 S5P_CLKREG(0x0C538)
+#define S5P_CLKDIV_MAUDIO S5P_CLKREG(0x0C53C)
#define S5P_CLKDIV_FSYS0 S5P_CLKREG(0x0C540)
#define S5P_CLKDIV_FSYS1 S5P_CLKREG(0x0C544)
#define S5P_CLKDIV_FSYS2 S5P_CLKREG(0x0C548)
@@ -58,25 +64,36 @@
#define S5P_CLKSRC_MASK_TOP S5P_CLKREG(0x0C310)
#define S5P_CLKSRC_MASK_CAM S5P_CLKREG(0x0C320)
+#define S5P_CLKSRC_MASK_TV S5P_CLKREG(0x0C324)
#define S5P_CLKSRC_MASK_LCD0 S5P_CLKREG(0x0C334)
#define S5P_CLKSRC_MASK_LCD1 S5P_CLKREG(0x0C338)
+#define S5P_CLKSRC_MASK_MAUDIO S5P_CLKREG(0x0C33C)
#define S5P_CLKSRC_MASK_FSYS S5P_CLKREG(0x0C340)
#define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350)
#define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354)
#define S5P_CLKDIV_STAT_TOP S5P_CLKREG(0x0C610)
+#define S5P_CLKGATE_SCLKCAM S5P_CLKREG(0x0C820)
#define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920)
+#define S5P_CLKGATE_IP_TV S5P_CLKREG(0x0C924)
+#define S5P_CLKGATE_IP_MFC S5P_CLKREG(0x0C928)
+#define S5P_CLKGATE_IP_G3D S5P_CLKREG(0x0C92C)
#define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930)
#define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934)
#define S5P_CLKGATE_IP_LCD1 S5P_CLKREG(0x0C938)
#define S5P_CLKGATE_IP_FSYS S5P_CLKREG(0x0C940)
+#define S5P_CLKGATE_IP_GPS S5P_CLKREG(0x0C94C)
#define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950)
#define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960)
+#define S5P_CLKGATE_BLOCK S5P_CLKREG(0x0C970)
+#define S5P_CLKSRC_MASK_DMC S5P_CLKREG(0x10300)
#define S5P_CLKSRC_DMC S5P_CLKREG(0x10200)
#define S5P_CLKDIV_DMC0 S5P_CLKREG(0x10500)
+#define S5P_CLKDIV_DMC1 S5P_CLKREG(0x10504)
#define S5P_CLKDIV_STAT_DMC0 S5P_CLKREG(0x10600)
+#define S5P_CLKGATE_IP_DMC S5P_CLKREG(0x10900)
#define S5P_APLL_LOCK S5P_CLKREG(0x14000)
#define S5P_MPLL_LOCK S5P_CLKREG(0x14004)
@@ -94,21 +111,18 @@
#define S5P_CLKDIV_STATCPU1 S5P_CLKREG(0x14604)
#define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800)
+#define S5P_CLKGATE_IP_CPU S5P_CLKREG(0x14900)
-/* APLL_LOCK */
#define S5P_APLL_LOCKTIME (0x1C20) /* 300us */
-/* APLL_CON0 */
#define S5P_APLLCON0_ENABLE_SHIFT (31)
#define S5P_APLLCON0_LOCKED_SHIFT (29)
#define S5P_APLL_VAL_1000 ((250 << 16) | (6 << 8) | 1)
#define S5P_APLL_VAL_800 ((200 << 16) | (6 << 8) | 1)
-/* CLK_SRC_CPU */
#define S5P_CLKSRC_CPU_MUXCORE_SHIFT (16)
#define S5P_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)
-/* CLKDIV_CPU0 */
#define S5P_CLKDIV_CPU0_CORE_SHIFT (0)
#define S5P_CLKDIV_CPU0_CORE_MASK (0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT)
#define S5P_CLKDIV_CPU0_COREM0_SHIFT (4)
@@ -124,7 +138,6 @@
#define S5P_CLKDIV_CPU0_APLL_SHIFT (24)
#define S5P_CLKDIV_CPU0_APLL_MASK (0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT)
-/* CLKDIV_DMC0 */
#define S5P_CLKDIV_DMC0_ACP_SHIFT (0)
#define S5P_CLKDIV_DMC0_ACP_MASK (0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT)
#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT (4)
@@ -142,7 +155,6 @@
#define S5P_CLKDIV_DMC0_CORETI_SHIFT (28)
#define S5P_CLKDIV_DMC0_CORETI_MASK (0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT)
-/* CLKDIV_TOP */
#define S5P_CLKDIV_TOP_ACLK200_SHIFT (0)
#define S5P_CLKDIV_TOP_ACLK200_MASK (0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT)
#define S5P_CLKDIV_TOP_ACLK100_SHIFT (4)
@@ -154,13 +166,14 @@
#define S5P_CLKDIV_TOP_ONENAND_SHIFT (16)
#define S5P_CLKDIV_TOP_ONENAND_MASK (0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT)
-/* CLKDIV_LEFTBUS / CLKDIV_RIGHTBUS*/
#define S5P_CLKDIV_BUS_GDLR_SHIFT (0)
#define S5P_CLKDIV_BUS_GDLR_MASK (0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT)
#define S5P_CLKDIV_BUS_GPLR_SHIFT (4)
#define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
-/* Compatibility defines */
+/* Compatibility defines and inclusion */
+
+#include <mach/regs-pmu.h>
#define S5P_EPLL_CON S5P_EPLL_CON0
diff --git a/arch/arm/mach-exynos4/include/mach/regs-gpio.h b/arch/arm/mach-exynos4/include/mach/regs-gpio.h
new file mode 100644
index 000000000000..1401b21663a5
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/regs-gpio.h
@@ -0,0 +1,42 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - GPIO (including EINT) register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#define EXYNOS4_EINT40CON (S5P_VA_GPIO2 + 0xE00)
+#define S5P_EINT_CON(x) (EXYNOS4_EINT40CON + ((x) * 0x4))
+
+#define EXYNOS4_EINT40FLTCON0 (S5P_VA_GPIO2 + 0xE80)
+#define S5P_EINT_FLTCON(x) (EXYNOS4_EINT40FLTCON0 + ((x) * 0x4))
+
+#define EXYNOS4_EINT40MASK (S5P_VA_GPIO2 + 0xF00)
+#define S5P_EINT_MASK(x) (EXYNOS4_EINT40MASK + ((x) * 0x4))
+
+#define EXYNOS4_EINT40PEND (S5P_VA_GPIO2 + 0xF40)
+#define S5P_EINT_PEND(x) (EXYNOS4_EINT40PEND + ((x) * 0x4))
+
+#define EINT_REG_NR(x) (EINT_OFFSET(x) >> 3)
+
+#define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7))
+
+#define EINT_MODE S3C_GPIO_SFN(0xf)
+
+#define EINT_GPIO_0(x) EXYNOS4_GPX0(x)
+#define EINT_GPIO_1(x) EXYNOS4_GPX1(x)
+#define EINT_GPIO_2(x) EXYNOS4_GPX2(x)
+#define EINT_GPIO_3(x) EXYNOS4_GPX3(x)
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-irq.h b/arch/arm/mach-exynos4/include/mach/regs-irq.h
index c6e09c7f9161..9c7b4bfd546f 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-irq.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-irq.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-irq.h
+/* linux/arch/arm/mach-exynos4/include/mach/regs-irq.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - IRQ register definitions
+ * EXYNOS4 - IRQ register definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-exynos4/include/mach/regs-mct.h b/arch/arm/mach-exynos4/include/mach/regs-mct.h
new file mode 100644
index 000000000000..ca9c8434b023
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/regs-mct.h
@@ -0,0 +1,52 @@
+/* arch/arm/mach-exynos4/include/mach/regs-mct.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 MCT configutation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_MCT_H
+#define __ASM_ARCH_REGS_MCT_H __FILE__
+
+#include <mach/map.h>
+
+#define EXYNOS4_MCTREG(x) (S5P_VA_SYSTIMER + (x))
+
+#define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)
+#define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104)
+#define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110)
+
+#define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200)
+#define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204)
+#define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208)
+
+#define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240)
+
+#define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244)
+#define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248)
+#define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C)
+
+#define EXYNOS4_MCT_L0_BASE EXYNOS4_MCTREG(0x300)
+#define EXYNOS4_MCT_L1_BASE EXYNOS4_MCTREG(0x400)
+
+#define MCT_L_TCNTB_OFFSET (0x00)
+#define MCT_L_ICNTB_OFFSET (0x08)
+#define MCT_L_TCON_OFFSET (0x20)
+#define MCT_L_INT_CSTAT_OFFSET (0x30)
+#define MCT_L_INT_ENB_OFFSET (0x34)
+#define MCT_L_WSTAT_OFFSET (0x40)
+
+#define MCT_G_TCON_START (1 << 8)
+#define MCT_G_TCON_COMP0_AUTO_INC (1 << 1)
+#define MCT_G_TCON_COMP0_ENABLE (1 << 0)
+
+#define MCT_L_TCON_INTERVAL_MODE (1 << 2)
+#define MCT_L_TCON_INT_START (1 << 1)
+#define MCT_L_TCON_TIMER_START (1 << 0)
+
+#endif /* __ASM_ARCH_REGS_MCT_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-mem.h b/arch/arm/mach-exynos4/include/mach/regs-mem.h
index 834227140eaa..0368b5a27252 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-mem.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-mem.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-mem.h
+/* linux/arch/arm/mach-exynos4/include/mach/regs-mem.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 - SROMC and DMC register definitions
+ * EXYNOS4 - SROMC and DMC register definitions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
new file mode 100644
index 000000000000..62b0014d05e0
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
@@ -0,0 +1,162 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-pmu.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - Power management unit definition
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_PMU_H
+#define __ASM_ARCH_REGS_PMU_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_PMUREG(x) (S5P_VA_PMU + (x))
+
+#define S5P_CENTRAL_SEQ_CONFIGURATION S5P_PMUREG(0x0200)
+
+#define S5P_CENTRAL_LOWPWR_CFG (1 << 16)
+
+#define S5P_CENTRAL_SEQ_OPTION S5P_PMUREG(0x0208)
+
+#define S5P_USE_STANDBY_WFI0 (1 << 16)
+#define S5P_USE_STANDBY_WFI1 (1 << 17)
+#define S5P_USE_STANDBY_WFE0 (1 << 24)
+#define S5P_USE_STANDBY_WFE1 (1 << 25)
+#define S5P_USE_MASK ((0x3 << 16) | (0x3 << 24))
+
+#define S5P_WAKEUP_STAT S5P_PMUREG(0x0600)
+#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
+#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
+
+#define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4)
+#define S5P_MIPI_DPHY_ENABLE (1 << 0)
+#define S5P_MIPI_DPHY_SRESETN (1 << 1)
+#define S5P_MIPI_DPHY_MRESETN (1 << 2)
+
+#define S5P_PMU_SATA_PHY_CONTROL S5P_PMUREG(0x0720)
+#define S5P_INFORM0 S5P_PMUREG(0x0800)
+#define S5P_INFORM1 S5P_PMUREG(0x0804)
+#define S5P_INFORM2 S5P_PMUREG(0x0808)
+#define S5P_INFORM3 S5P_PMUREG(0x080C)
+#define S5P_INFORM4 S5P_PMUREG(0x0810)
+#define S5P_INFORM5 S5P_PMUREG(0x0814)
+#define S5P_INFORM6 S5P_PMUREG(0x0818)
+#define S5P_INFORM7 S5P_PMUREG(0x081C)
+
+#define S5P_ARM_CORE0_LOWPWR S5P_PMUREG(0x1000)
+#define S5P_DIS_IRQ_CORE0 S5P_PMUREG(0x1004)
+#define S5P_DIS_IRQ_CENTRAL0 S5P_PMUREG(0x1008)
+#define S5P_ARM_CORE1_LOWPWR S5P_PMUREG(0x1010)
+#define S5P_DIS_IRQ_CORE1 S5P_PMUREG(0x1014)
+#define S5P_DIS_IRQ_CENTRAL1 S5P_PMUREG(0x1018)
+#define S5P_ARM_COMMON_LOWPWR S5P_PMUREG(0x1080)
+#define S5P_L2_0_LOWPWR S5P_PMUREG(0x10C0)
+#define S5P_L2_1_LOWPWR S5P_PMUREG(0x10C4)
+#define S5P_CMU_ACLKSTOP_LOWPWR S5P_PMUREG(0x1100)
+#define S5P_CMU_SCLKSTOP_LOWPWR S5P_PMUREG(0x1104)
+#define S5P_CMU_RESET_LOWPWR S5P_PMUREG(0x110C)
+#define S5P_APLL_SYSCLK_LOWPWR S5P_PMUREG(0x1120)
+#define S5P_MPLL_SYSCLK_LOWPWR S5P_PMUREG(0x1124)
+#define S5P_VPLL_SYSCLK_LOWPWR S5P_PMUREG(0x1128)
+#define S5P_EPLL_SYSCLK_LOWPWR S5P_PMUREG(0x112C)
+#define S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR S5P_PMUREG(0x1138)
+#define S5P_CMU_RESET_GPSALIVE_LOWPWR S5P_PMUREG(0x113C)
+#define S5P_CMU_CLKSTOP_CAM_LOWPWR S5P_PMUREG(0x1140)
+#define S5P_CMU_CLKSTOP_TV_LOWPWR S5P_PMUREG(0x1144)
+#define S5P_CMU_CLKSTOP_MFC_LOWPWR S5P_PMUREG(0x1148)
+#define S5P_CMU_CLKSTOP_G3D_LOWPWR S5P_PMUREG(0x114C)
+#define S5P_CMU_CLKSTOP_LCD0_LOWPWR S5P_PMUREG(0x1150)
+#define S5P_CMU_CLKSTOP_LCD1_LOWPWR S5P_PMUREG(0x1154)
+#define S5P_CMU_CLKSTOP_MAUDIO_LOWPWR S5P_PMUREG(0x1158)
+#define S5P_CMU_CLKSTOP_GPS_LOWPWR S5P_PMUREG(0x115C)
+#define S5P_CMU_RESET_CAM_LOWPWR S5P_PMUREG(0x1160)
+#define S5P_CMU_RESET_TV_LOWPWR S5P_PMUREG(0x1164)
+#define S5P_CMU_RESET_MFC_LOWPWR S5P_PMUREG(0x1168)
+#define S5P_CMU_RESET_G3D_LOWPWR S5P_PMUREG(0x116C)
+#define S5P_CMU_RESET_LCD0_LOWPWR S5P_PMUREG(0x1170)
+#define S5P_CMU_RESET_LCD1_LOWPWR S5P_PMUREG(0x1174)
+#define S5P_CMU_RESET_MAUDIO_LOWPWR S5P_PMUREG(0x1178)
+#define S5P_CMU_RESET_GPS_LOWPWR S5P_PMUREG(0x117C)
+#define S5P_TOP_BUS_LOWPWR S5P_PMUREG(0x1180)
+#define S5P_TOP_RETENTION_LOWPWR S5P_PMUREG(0x1184)
+#define S5P_TOP_PWR_LOWPWR S5P_PMUREG(0x1188)
+#define S5P_LOGIC_RESET_LOWPWR S5P_PMUREG(0x11A0)
+#define S5P_ONENAND_MEM_LOWPWR S5P_PMUREG(0x11C0)
+#define S5P_MODIMIF_MEM_LOWPWR S5P_PMUREG(0x11C4)
+#define S5P_G2D_ACP_MEM_LOWPWR S5P_PMUREG(0x11C8)
+#define S5P_USBOTG_MEM_LOWPWR S5P_PMUREG(0x11CC)
+#define S5P_HSMMC_MEM_LOWPWR S5P_PMUREG(0x11D0)
+#define S5P_CSSYS_MEM_LOWPWR S5P_PMUREG(0x11D4)
+#define S5P_SECSS_MEM_LOWPWR S5P_PMUREG(0x11D8)
+#define S5P_PCIE_MEM_LOWPWR S5P_PMUREG(0x11E0)
+#define S5P_SATA_MEM_LOWPWR S5P_PMUREG(0x11E4)
+#define S5P_PAD_RETENTION_DRAM_LOWPWR S5P_PMUREG(0x1200)
+#define S5P_PAD_RETENTION_MAUDIO_LOWPWR S5P_PMUREG(0x1204)
+#define S5P_PAD_RETENTION_GPIO_LOWPWR S5P_PMUREG(0x1220)
+#define S5P_PAD_RETENTION_UART_LOWPWR S5P_PMUREG(0x1224)
+#define S5P_PAD_RETENTION_MMCA_LOWPWR S5P_PMUREG(0x1228)
+#define S5P_PAD_RETENTION_MMCB_LOWPWR S5P_PMUREG(0x122C)
+#define S5P_PAD_RETENTION_EBIA_LOWPWR S5P_PMUREG(0x1230)
+#define S5P_PAD_RETENTION_EBIB_LOWPWR S5P_PMUREG(0x1234)
+#define S5P_PAD_RETENTION_ISOLATION_LOWPWR S5P_PMUREG(0x1240)
+#define S5P_PAD_RETENTION_ALV_SEL_LOWPWR S5P_PMUREG(0x1260)
+#define S5P_XUSBXTI_LOWPWR S5P_PMUREG(0x1280)
+#define S5P_XXTI_LOWPWR S5P_PMUREG(0x1284)
+#define S5P_EXT_REGULATOR_LOWPWR S5P_PMUREG(0x12C0)
+#define S5P_GPIO_MODE_LOWPWR S5P_PMUREG(0x1300)
+#define S5P_GPIO_MODE_MAUDIO_LOWPWR S5P_PMUREG(0x1340)
+#define S5P_CAM_LOWPWR S5P_PMUREG(0x1380)
+#define S5P_TV_LOWPWR S5P_PMUREG(0x1384)
+#define S5P_MFC_LOWPWR S5P_PMUREG(0x1388)
+#define S5P_G3D_LOWPWR S5P_PMUREG(0x138C)
+#define S5P_LCD0_LOWPWR S5P_PMUREG(0x1390)
+#define S5P_LCD1_LOWPWR S5P_PMUREG(0x1394)
+#define S5P_MAUDIO_LOWPWR S5P_PMUREG(0x1398)
+#define S5P_GPS_LOWPWR S5P_PMUREG(0x139C)
+#define S5P_GPS_ALIVE_LOWPWR S5P_PMUREG(0x13A0)
+
+#define S5P_ARM_CORE0_CONFIGURATION S5P_PMUREG(0x2000)
+#define S5P_ARM_CORE0_OPTION S5P_PMUREG(0x2008)
+#define S5P_ARM_CORE1_CONFIGURATION S5P_PMUREG(0x2080)
+#define S5P_ARM_CORE1_STATUS S5P_PMUREG(0x2084)
+#define S5P_ARM_CORE1_OPTION S5P_PMUREG(0x2088)
+
+#define S5P_ARM_COMMON_OPTION S5P_PMUREG(0x2408)
+#define S5P_TOP_PWR_OPTION S5P_PMUREG(0x2C48)
+#define S5P_CAM_OPTION S5P_PMUREG(0x3C08)
+#define S5P_TV_OPTION S5P_PMUREG(0x3C28)
+#define S5P_MFC_OPTION S5P_PMUREG(0x3C48)
+#define S5P_G3D_OPTION S5P_PMUREG(0x3C68)
+#define S5P_LCD0_OPTION S5P_PMUREG(0x3C88)
+#define S5P_LCD1_OPTION S5P_PMUREG(0x3CA8)
+#define S5P_MAUDIO_OPTION S5P_PMUREG(0x3CC8)
+#define S5P_GPS_OPTION S5P_PMUREG(0x3CE8)
+#define S5P_GPS_ALIVE_OPTION S5P_PMUREG(0x3D08)
+
+#define S5P_PAD_RET_MAUDIO_OPTION S5P_PMUREG(0x3028)
+#define S5P_PAD_RET_GPIO_OPTION S5P_PMUREG(0x3108)
+#define S5P_PAD_RET_UART_OPTION S5P_PMUREG(0x3128)
+#define S5P_PAD_RET_MMCA_OPTION S5P_PMUREG(0x3148)
+#define S5P_PAD_RET_MMCB_OPTION S5P_PMUREG(0x3168)
+#define S5P_PAD_RET_EBIA_OPTION S5P_PMUREG(0x3188)
+#define S5P_PAD_RET_EBIB_OPTION S5P_PMUREG(0x31A8)
+
+#define S5P_PMU_CAM_CONF S5P_PMUREG(0x3C00)
+#define S5P_PMU_TV_CONF S5P_PMUREG(0x3C20)
+#define S5P_PMU_MFC_CONF S5P_PMUREG(0x3C40)
+#define S5P_PMU_G3D_CONF S5P_PMUREG(0x3C60)
+#define S5P_PMU_LCD0_CONF S5P_PMUREG(0x3C80)
+#define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0)
+#define S5P_PMU_GPS_CONF S5P_PMUREG(0x3CE0)
+
+#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1
+#define S5P_INT_LOCAL_PWR_EN 0x7
+
+#define S5P_CHECK_SLEEP 0x00000BAD
+
+#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
index 0b28e81a16f7..68ff6ad08a2b 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
+/* linux/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 - System MMU register
+ * EXYNOS4 - System MMU register
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,6 +19,10 @@
#define S5P_MMU_FLUSH 0x00C
#define S5P_PT_BASE_ADDR 0x014
#define S5P_INT_STATUS 0x018
+#define S5P_INT_CLEAR 0x01C
#define S5P_PAGE_FAULT_ADDR 0x024
+#define S5P_AW_FAULT_ADDR 0x028
+#define S5P_AR_FAULT_ADDR 0x02C
+#define S5P_DEFAULT_SLAVE_ADDR 0x030
#endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/smp.h b/arch/arm/mach-exynos4/include/mach/smp.h
index 393ccbd52c4a..a463dcebcfd3 100644
--- a/arch/arm/mach-s5pv310/include/mach/smp.h
+++ b/arch/arm/mach-exynos4/include/mach/smp.h
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/smp.h
+/* linux/arch/arm/mach-exynos4/include/mach/smp.h
*
* Cloned from arch/arm/mach-realview/include/mach/smp.h
*/
diff --git a/arch/arm/mach-exynos4/include/mach/sysmmu.h b/arch/arm/mach-exynos4/include/mach/sysmmu.h
new file mode 100644
index 000000000000..6a5fbb534e82
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/sysmmu.h
@@ -0,0 +1,46 @@
+/* linux/arch/arm/mach-exynos4/include/mach/sysmmu.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung sysmmu driver for EXYNOS4
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARM_ARCH_SYSMMU_H
+#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
+
+enum exynos4_sysmmu_ips {
+ SYSMMU_MDMA,
+ SYSMMU_SSS,
+ SYSMMU_FIMC0,
+ SYSMMU_FIMC1,
+ SYSMMU_FIMC2,
+ SYSMMU_FIMC3,
+ SYSMMU_JPEG,
+ SYSMMU_FIMD0,
+ SYSMMU_FIMD1,
+ SYSMMU_PCIe,
+ SYSMMU_G2D,
+ SYSMMU_ROTATOR,
+ SYSMMU_MDMA2,
+ SYSMMU_TV,
+ SYSMMU_MFC_L,
+ SYSMMU_MFC_R,
+ EXYNOS4_SYSMMU_TOTAL_IPNUM,
+};
+
+#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM
+
+extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM];
+
+typedef enum exynos4_sysmmu_ips sysmmu_ips;
+
+void sysmmu_clk_init(struct device *dev, sysmmu_ips ips);
+void sysmmu_clk_enable(sysmmu_ips ips);
+void sysmmu_clk_disable(sysmmu_ips ips);
+
+#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/system.h b/arch/arm/mach-exynos4/include/mach/system.h
index d10c009cf0f1..5e3220c18fc7 100644
--- a/arch/arm/mach-s5pv310/include/mach/system.h
+++ b/arch/arm/mach-exynos4/include/mach/system.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/system.h
+/* linux/arch/arm/mach-exynos4/include/mach/system.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - system support header
+ * EXYNOS4 - system support header
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/timex.h b/arch/arm/mach-exynos4/include/mach/timex.h
index bd2359b952b4..6d138750a708 100644
--- a/arch/arm/mach-s5pv310/include/mach/timex.h
+++ b/arch/arm/mach-exynos4/include/mach/timex.h
@@ -1,14 +1,14 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/timex.h
+/* linux/arch/arm/mach-exynos4/include/mach/timex.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright (c) 2003-2010 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Based on arch/arm/mach-s5p6442/include/mach/timex.h
*
- * S5PV310 - time parameters
+ * EXYNOS4 - time parameters
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/uncompress.h b/arch/arm/mach-exynos4/include/mach/uncompress.h
index 59593c1e2416..21d97bcd9acb 100644
--- a/arch/arm/mach-s5pv310/include/mach/uncompress.h
+++ b/arch/arm/mach-exynos4/include/mach/uncompress.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/uncompress.h
+/* linux/arch/arm/mach-exynos4/include/mach/uncompress.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - uncompress code
+ * EXYNOS4 - uncompress code
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5pv310/include/mach/vmalloc.h b/arch/arm/mach-exynos4/include/mach/vmalloc.h
index 65759fb97581..284330e571d2 100644
--- a/arch/arm/mach-s5pv310/include/mach/vmalloc.h
+++ b/arch/arm/mach-exynos4/include/mach/vmalloc.h
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/vmalloc.h
+/* linux/arch/arm/mach-exynos4/include/mach/vmalloc.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright 2010 Ben Dooks <ben-linux@fluff.org>
*
@@ -11,7 +11,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * S5PV310 vmalloc definition
+ * EXYNOS4 vmalloc definition
*/
#ifndef __ASM_ARCH_VMALLOC_H
diff --git a/arch/arm/mach-s5pv310/init.c b/arch/arm/mach-exynos4/init.c
index 182dcf42cfb4..cf91f50e43ab 100644
--- a/arch/arm/mach-s5pv310/init.c
+++ b/arch/arm/mach-exynos4/init.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s5pv310/init.c
+/* linux/arch/arm/mach-exynos4/init.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
@@ -14,7 +14,7 @@
#include <plat/devs.h>
#include <plat/regs-serial.h>
-static struct s3c24xx_uart_clksrc s5pv310_serial_clocks[] = {
+static struct s3c24xx_uart_clksrc exynos4_serial_clocks[] = {
[0] = {
.name = "uclk1",
.divisor = 1,
@@ -24,7 +24,7 @@ static struct s3c24xx_uart_clksrc s5pv310_serial_clocks[] = {
};
/* uart registration process */
-void __init s5pv310_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
struct s3c2410_uartcfg *tcfg = cfg;
u32 ucnt;
@@ -32,8 +32,8 @@ void __init s5pv310_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
if (!tcfg->clocks) {
tcfg->has_fracval = 1;
- tcfg->clocks = s5pv310_serial_clocks;
- tcfg->clocks_size = ARRAY_SIZE(s5pv310_serial_clocks);
+ tcfg->clocks = exynos4_serial_clocks;
+ tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks);
}
}
diff --git a/arch/arm/mach-s5pv310/irq-combiner.c b/arch/arm/mach-exynos4/irq-combiner.c
index 1ea4a9e83bbe..31618d91ce15 100644
--- a/arch/arm/mach-s5pv310/irq-combiner.c
+++ b/arch/arm/mach-exynos4/irq-combiner.c
@@ -1,6 +1,6 @@
-/* linux/arch/arm/mach-s5pv310/irq-combiner.c
+/* linux/arch/arm/mach-exynos4/irq-combiner.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Based on arch/arm/common/gic.c
diff --git a/arch/arm/mach-s5pv310/irq-eint.c b/arch/arm/mach-exynos4/irq-eint.c
index 477bd9e97f0f..4f7ad4a796e4 100644
--- a/arch/arm/mach-s5pv310/irq-eint.c
+++ b/arch/arm/mach-exynos4/irq-eint.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/irq-eint.c
+/* linux/arch/arm/mach-exynos4/irq-eint.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 - IRQ EINT support
+ * EXYNOS4 - IRQ EINT support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -27,7 +27,7 @@ static DEFINE_SPINLOCK(eint_lock);
static unsigned int eint0_15_data[16];
-static unsigned int s5pv310_get_irq_nr(unsigned int number)
+static unsigned int exynos4_get_irq_nr(unsigned int number)
{
u32 ret = 0;
@@ -48,7 +48,7 @@ static unsigned int s5pv310_get_irq_nr(unsigned int number)
return ret;
}
-static inline void s5pv310_irq_eint_mask(struct irq_data *data)
+static inline void exynos4_irq_eint_mask(struct irq_data *data)
{
u32 mask;
@@ -59,7 +59,7 @@ static inline void s5pv310_irq_eint_mask(struct irq_data *data)
spin_unlock(&eint_lock);
}
-static void s5pv310_irq_eint_unmask(struct irq_data *data)
+static void exynos4_irq_eint_unmask(struct irq_data *data)
{
u32 mask;
@@ -70,19 +70,19 @@ static void s5pv310_irq_eint_unmask(struct irq_data *data)
spin_unlock(&eint_lock);
}
-static inline void s5pv310_irq_eint_ack(struct irq_data *data)
+static inline void exynos4_irq_eint_ack(struct irq_data *data)
{
__raw_writel(eint_irq_to_bit(data->irq),
S5P_EINT_PEND(EINT_REG_NR(data->irq)));
}
-static void s5pv310_irq_eint_maskack(struct irq_data *data)
+static void exynos4_irq_eint_maskack(struct irq_data *data)
{
- s5pv310_irq_eint_mask(data);
- s5pv310_irq_eint_ack(data);
+ exynos4_irq_eint_mask(data);
+ exynos4_irq_eint_ack(data);
}
-static int s5pv310_irq_eint_set_type(struct irq_data *data, unsigned int type)
+static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
{
int offs = EINT_OFFSET(data->irq);
int shift;
@@ -145,19 +145,19 @@ static int s5pv310_irq_eint_set_type(struct irq_data *data, unsigned int type)
return 0;
}
-static struct irq_chip s5pv310_irq_eint = {
- .name = "s5pv310-eint",
- .irq_mask = s5pv310_irq_eint_mask,
- .irq_unmask = s5pv310_irq_eint_unmask,
- .irq_mask_ack = s5pv310_irq_eint_maskack,
- .irq_ack = s5pv310_irq_eint_ack,
- .irq_set_type = s5pv310_irq_eint_set_type,
+static struct irq_chip exynos4_irq_eint = {
+ .name = "exynos4-eint",
+ .irq_mask = exynos4_irq_eint_mask,
+ .irq_unmask = exynos4_irq_eint_unmask,
+ .irq_mask_ack = exynos4_irq_eint_maskack,
+ .irq_ack = exynos4_irq_eint_ack,
+ .irq_set_type = exynos4_irq_eint_set_type,
#ifdef CONFIG_PM
.irq_set_wake = s3c_irqext_wake,
#endif
};
-/* s5pv310_irq_demux_eint
+/* exynos4_irq_demux_eint
*
* This function demuxes the IRQ from from EINTs 16 to 31.
* It is designed to be inlined into the specific handler
@@ -165,7 +165,7 @@ static struct irq_chip s5pv310_irq_eint = {
*
* Each EINT pend/mask registers handle eight of them.
*/
-static inline void s5pv310_irq_demux_eint(unsigned int start)
+static inline void exynos4_irq_demux_eint(unsigned int start)
{
unsigned int irq;
@@ -182,13 +182,13 @@ static inline void s5pv310_irq_demux_eint(unsigned int start)
}
}
-static void s5pv310_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
{
- s5pv310_irq_demux_eint(IRQ_EINT(16));
- s5pv310_irq_demux_eint(IRQ_EINT(24));
+ exynos4_irq_demux_eint(IRQ_EINT(16));
+ exynos4_irq_demux_eint(IRQ_EINT(24));
}
-static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
+static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
{
u32 *irq_data = get_irq_data(irq);
struct irq_chip *chip = get_irq_chip(irq);
@@ -203,27 +203,27 @@ static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
chip->irq_unmask(&desc->irq_data);
}
-int __init s5pv310_init_irq_eint(void)
+int __init exynos4_init_irq_eint(void)
{
int irq;
for (irq = 0 ; irq <= 31 ; irq++) {
- set_irq_chip(IRQ_EINT(irq), &s5pv310_irq_eint);
+ set_irq_chip(IRQ_EINT(irq), &exynos4_irq_eint);
set_irq_handler(IRQ_EINT(irq), handle_level_irq);
set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
}
- set_irq_chained_handler(IRQ_EINT16_31, s5pv310_irq_demux_eint16_31);
+ set_irq_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
for (irq = 0 ; irq <= 15 ; irq++) {
eint0_15_data[irq] = IRQ_EINT(irq);
- set_irq_data(s5pv310_get_irq_nr(irq), &eint0_15_data[irq]);
- set_irq_chained_handler(s5pv310_get_irq_nr(irq),
- s5pv310_irq_eint0_15);
+ set_irq_data(exynos4_get_irq_nr(irq), &eint0_15_data[irq]);
+ set_irq_chained_handler(exynos4_get_irq_nr(irq),
+ exynos4_irq_eint0_15);
}
return 0;
}
-arch_initcall(s5pv310_init_irq_eint);
+arch_initcall(exynos4_init_irq_eint);
diff --git a/arch/arm/mach-s5pv310/localtimer.c b/arch/arm/mach-exynos4/localtimer.c
index 2784036cd8b1..2a2993ae8d86 100644
--- a/arch/arm/mach-s5pv310/localtimer.c
+++ b/arch/arm/mach-exynos4/localtimer.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s5pv310/localtimer.c
+/* linux/arch/arm/mach-exynos4/localtimer.c
*
* Cloned from linux/arch/arm/mach-realview/localtimer.c
*
diff --git a/arch/arm/mach-exynos4/mach-armlex4210.c b/arch/arm/mach-exynos4/mach-armlex4210.c
new file mode 100644
index 000000000000..b482c6285fc4
--- /dev/null
+++ b/arch/arm/mach-exynos4/mach-armlex4210.c
@@ -0,0 +1,215 @@
+/* linux/arch/arm/mach-exynos4/mach-armlex4210.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/smsc911x.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/exynos4.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-srom.h>
+#include <plat/sdhci.h>
+
+#include <mach/map.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define ARMLEX4210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI | \
+ S3C2443_UCON_RXERR_IRQEN)
+
+#define ARMLEX4210_ULCON_DEFAULT S3C2410_LCON_CS8
+
+#define ARMLEX4210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S5PV210_UFCON_TXTRIG4 | \
+ S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg armlex4210_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = ARMLEX4210_UCON_DEFAULT,
+ .ulcon = ARMLEX4210_ULCON_DEFAULT,
+ .ufcon = ARMLEX4210_UFCON_DEFAULT,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = ARMLEX4210_UCON_DEFAULT,
+ .ulcon = ARMLEX4210_ULCON_DEFAULT,
+ .ufcon = ARMLEX4210_UFCON_DEFAULT,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = ARMLEX4210_UCON_DEFAULT,
+ .ulcon = ARMLEX4210_ULCON_DEFAULT,
+ .ufcon = ARMLEX4210_UFCON_DEFAULT,
+ },
+ [3] = {
+ .hwport = 3,
+ .flags = 0,
+ .ucon = ARMLEX4210_UCON_DEFAULT,
+ .ulcon = ARMLEX4210_ULCON_DEFAULT,
+ .ufcon = ARMLEX4210_UFCON_DEFAULT,
+ },
+};
+
+static struct s3c_sdhci_platdata armlex4210_hsmmc0_pdata __initdata = {
+ .cd_type = S3C_SDHCI_CD_PERMANENT,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
+ .max_width = 8,
+ .host_caps = MMC_CAP_8_BIT_DATA,
+#endif
+};
+
+static struct s3c_sdhci_platdata armlex4210_hsmmc2_pdata __initdata = {
+ .cd_type = S3C_SDHCI_CD_GPIO,
+ .ext_cd_gpio = EXYNOS4_GPX2(5),
+ .ext_cd_gpio_invert = 1,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+ .max_width = 4,
+};
+
+static struct s3c_sdhci_platdata armlex4210_hsmmc3_pdata __initdata = {
+ .cd_type = S3C_SDHCI_CD_PERMANENT,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+ .max_width = 4,
+};
+
+static void __init armlex4210_sdhci_init(void)
+{
+ s3c_sdhci0_set_platdata(&armlex4210_hsmmc0_pdata);
+ s3c_sdhci2_set_platdata(&armlex4210_hsmmc2_pdata);
+ s3c_sdhci3_set_platdata(&armlex4210_hsmmc3_pdata);
+}
+
+static void __init armlex4210_wlan_init(void)
+{
+ /* enable */
+ s3c_gpio_cfgpin(EXYNOS4_GPX2(0), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(EXYNOS4_GPX2(0), S3C_GPIO_PULL_UP);
+
+ /* reset */
+ s3c_gpio_cfgpin(EXYNOS4_GPX1(6), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(EXYNOS4_GPX1(6), S3C_GPIO_PULL_UP);
+
+ /* wakeup */
+ s3c_gpio_cfgpin(EXYNOS4_GPX1(5), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(EXYNOS4_GPX1(5), S3C_GPIO_PULL_UP);
+}
+
+static struct resource armlex4210_smsc911x_resources[] = {
+ [0] = {
+ .start = EXYNOS4_PA_SROM_BANK(3),
+ .end = EXYNOS4_PA_SROM_BANK(3) + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_EINT(27),
+ .end = IRQ_EINT(27),
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
+ },
+};
+
+static struct smsc911x_platform_config smsc9215_config = {
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+ .flags = SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .mac = {0x00, 0x80, 0x00, 0x23, 0x45, 0x67},
+};
+
+static struct platform_device armlex4210_smsc911x = {
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(armlex4210_smsc911x_resources),
+ .resource = armlex4210_smsc911x_resources,
+ .dev = {
+ .platform_data = &smsc9215_config,
+ },
+};
+
+static struct platform_device *armlex4210_devices[] __initdata = {
+ &s3c_device_hsmmc0,
+ &s3c_device_hsmmc2,
+ &s3c_device_hsmmc3,
+ &s3c_device_rtc,
+ &s3c_device_wdt,
+ &exynos4_device_sysmmu,
+ &samsung_asoc_dma,
+ &armlex4210_smsc911x,
+ &exynos4_device_ahci,
+};
+
+static void __init armlex4210_smsc911x_init(void)
+{
+ u32 cs1;
+
+ /* configure nCS1 width to 16 bits */
+ cs1 = __raw_readl(S5P_SROM_BW) &
+ ~(S5P_SROM_BW__CS_MASK << S5P_SROM_BW__NCS1__SHIFT);
+ cs1 |= ((1 << S5P_SROM_BW__DATAWIDTH__SHIFT) |
+ (0 << S5P_SROM_BW__WAITENABLE__SHIFT) |
+ (1 << S5P_SROM_BW__ADDRMODE__SHIFT) |
+ (1 << S5P_SROM_BW__BYTEENABLE__SHIFT)) <<
+ S5P_SROM_BW__NCS1__SHIFT;
+ __raw_writel(cs1, S5P_SROM_BW);
+
+ /* set timing for nCS1 suitable for ethernet chip */
+ __raw_writel((0x1 << S5P_SROM_BCX__PMC__SHIFT) |
+ (0x9 << S5P_SROM_BCX__TACP__SHIFT) |
+ (0xc << S5P_SROM_BCX__TCAH__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOH__SHIFT) |
+ (0x6 << S5P_SROM_BCX__TACC__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOS__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TACS__SHIFT), S5P_SROM_BC1);
+}
+
+static void __init armlex4210_map_io(void)
+{
+ s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+ s3c24xx_init_clocks(24000000);
+ s3c24xx_init_uarts(armlex4210_uartcfgs,
+ ARRAY_SIZE(armlex4210_uartcfgs));
+}
+
+static void __init armlex4210_machine_init(void)
+{
+ armlex4210_smsc911x_init();
+
+ armlex4210_sdhci_init();
+
+ armlex4210_wlan_init();
+
+ platform_add_devices(armlex4210_devices,
+ ARRAY_SIZE(armlex4210_devices));
+}
+
+MACHINE_START(ARMLEX4210, "ARMLEX4210")
+ /* Maintainer: Alim Akhtar <alim.akhtar@samsung.com> */
+ .boot_params = S5P_PA_SDRAM + 0x100,
+ .init_irq = exynos4_init_irq,
+ .map_io = armlex4210_map_io,
+ .init_machine = armlex4210_machine_init,
+ .timer = &exynos4_timer,
+MACHINE_END
diff --git a/arch/arm/mach-exynos4/mach-nuri.c b/arch/arm/mach-exynos4/mach-nuri.c
new file mode 100644
index 000000000000..b79ad010d194
--- /dev/null
+++ b/arch/arm/mach-exynos4/mach-nuri.c
@@ -0,0 +1,305 @@
+/*
+ * linux/arch/arm/mach-exynos4/mach-nuri.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/mmc/host.h>
+#include <linux/fb.h>
+#include <linux/pwm_backlight.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/exynos4.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/sdhci.h>
+
+#include <mach/map.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define NURI_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI | \
+ S3C2443_UCON_RXERR_IRQEN)
+
+#define NURI_ULCON_DEFAULT S3C2410_LCON_CS8
+
+#define NURI_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S5PV210_UFCON_TXTRIG256 | \
+ S5PV210_UFCON_RXTRIG256)
+
+enum fixed_regulator_id {
+ FIXED_REG_ID_MMC = 0,
+};
+
+static struct s3c2410_uartcfg nuri_uartcfgs[] __initdata = {
+ {
+ .hwport = 0,
+ .ucon = NURI_UCON_DEFAULT,
+ .ulcon = NURI_ULCON_DEFAULT,
+ .ufcon = NURI_UFCON_DEFAULT,
+ },
+ {
+ .hwport = 1,
+ .ucon = NURI_UCON_DEFAULT,
+ .ulcon = NURI_ULCON_DEFAULT,
+ .ufcon = NURI_UFCON_DEFAULT,
+ },
+ {
+ .hwport = 2,
+ .ucon = NURI_UCON_DEFAULT,
+ .ulcon = NURI_ULCON_DEFAULT,
+ .ufcon = NURI_UFCON_DEFAULT,
+ },
+ {
+ .hwport = 3,
+ .ucon = NURI_UCON_DEFAULT,
+ .ulcon = NURI_ULCON_DEFAULT,
+ .ufcon = NURI_UFCON_DEFAULT,
+ },
+};
+
+/* eMMC */
+static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = {
+ .max_width = 8,
+ .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE | MMC_CAP_ERASE),
+ .cd_type = S3C_SDHCI_CD_PERMANENT,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct regulator_consumer_supply emmc_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+ REGULATOR_SUPPLY("vmmc", "dw_mmc"),
+};
+
+static struct regulator_init_data emmc_fixed_voltage_init_data = {
+ .constraints = {
+ .name = "VMEM_VDD_2.8V",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(emmc_supplies),
+ .consumer_supplies = emmc_supplies,
+};
+
+static struct fixed_voltage_config emmc_fixed_voltage_config = {
+ .supply_name = "MASSMEMORY_EN (inverted)",
+ .microvolts = 2800000,
+ .gpio = EXYNOS4_GPL1(1),
+ .enable_high = false,
+ .init_data = &emmc_fixed_voltage_init_data,
+};
+
+static struct platform_device emmc_fixed_voltage = {
+ .name = "reg-fixed-voltage",
+ .id = FIXED_REG_ID_MMC,
+ .dev = {
+ .platform_data = &emmc_fixed_voltage_config,
+ },
+};
+
+/* SD */
+static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE,
+ .ext_cd_gpio = EXYNOS4_GPX3(3), /* XEINT_27 */
+ .ext_cd_gpio_invert = 1,
+ .cd_type = S3C_SDHCI_CD_GPIO,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+/* WLAN */
+static struct s3c_sdhci_platdata nuri_hsmmc3_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+ .cd_type = S3C_SDHCI_CD_EXTERNAL,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static void __init nuri_sdhci_init(void)
+{
+ s3c_sdhci0_set_platdata(&nuri_hsmmc0_data);
+ s3c_sdhci2_set_platdata(&nuri_hsmmc2_data);
+ s3c_sdhci3_set_platdata(&nuri_hsmmc3_data);
+}
+
+/* GPIO KEYS */
+static struct gpio_keys_button nuri_gpio_keys_tables[] = {
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = EXYNOS4_GPX2(0), /* XEINT16 */
+ .desc = "gpio-keys: KEY_VOLUMEUP",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = EXYNOS4_GPX2(1), /* XEINT17 */
+ .desc = "gpio-keys: KEY_VOLUMEDOWN",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_POWER,
+ .gpio = EXYNOS4_GPX2(7), /* XEINT23 */
+ .desc = "gpio-keys: KEY_POWER",
+ .type = EV_KEY,
+ .active_low = 1,
+ .wakeup = 1,
+ .debounce_interval = 1,
+ },
+};
+
+static struct gpio_keys_platform_data nuri_gpio_keys_data = {
+ .buttons = nuri_gpio_keys_tables,
+ .nbuttons = ARRAY_SIZE(nuri_gpio_keys_tables),
+};
+
+static struct platform_device nuri_gpio_keys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &nuri_gpio_keys_data,
+ },
+};
+
+static void nuri_lcd_power_on(struct plat_lcd_data *pd, unsigned int power)
+{
+ int gpio = EXYNOS4_GPE1(5);
+
+ gpio_request(gpio, "LVDS_nSHDN");
+ gpio_direction_output(gpio, power);
+ gpio_free(gpio);
+}
+
+static int nuri_bl_init(struct device *dev)
+{
+ int ret, gpio = EXYNOS4_GPE2(3);
+
+ ret = gpio_request(gpio, "LCD_LDO_EN");
+ if (!ret)
+ gpio_direction_output(gpio, 0);
+
+ return ret;
+}
+
+static int nuri_bl_notify(struct device *dev, int brightness)
+{
+ if (brightness < 1)
+ brightness = 0;
+
+ gpio_set_value(EXYNOS4_GPE2(3), 1);
+
+ return brightness;
+}
+
+static void nuri_bl_exit(struct device *dev)
+{
+ gpio_free(EXYNOS4_GPE2(3));
+}
+
+/* nuri pwm backlight */
+static struct platform_pwm_backlight_data nuri_backlight_data = {
+ .pwm_id = 0,
+ .pwm_period_ns = 30000,
+ .max_brightness = 100,
+ .dft_brightness = 50,
+ .init = nuri_bl_init,
+ .notify = nuri_bl_notify,
+ .exit = nuri_bl_exit,
+};
+
+static struct platform_device nuri_backlight_device = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .parent = &s3c_device_timer[0].dev,
+ .platform_data = &nuri_backlight_data,
+ },
+};
+
+static struct plat_lcd_data nuri_lcd_platform_data = {
+ .set_power = nuri_lcd_power_on,
+};
+
+static struct platform_device nuri_lcd_device = {
+ .name = "platform-lcd",
+ .id = -1,
+ .dev = {
+ .platform_data = &nuri_lcd_platform_data,
+ },
+};
+
+/* I2C1 */
+static struct i2c_board_info i2c1_devs[] __initdata = {
+ /* Gyro, To be updated */
+};
+
+/* GPIO I2C 5 (PMIC) */
+static struct i2c_board_info i2c5_devs[] __initdata = {
+ /* max8997, To be updated */
+};
+
+static struct platform_device *nuri_devices[] __initdata = {
+ /* Samsung Platform Devices */
+ &emmc_fixed_voltage,
+ &s3c_device_hsmmc0,
+ &s3c_device_hsmmc2,
+ &s3c_device_hsmmc3,
+ &s3c_device_wdt,
+ &s3c_device_timer[0],
+
+ /* NURI Devices */
+ &nuri_gpio_keys,
+ &nuri_lcd_device,
+ &nuri_backlight_device,
+};
+
+static void __init nuri_map_io(void)
+{
+ s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+ s3c24xx_init_clocks(24000000);
+ s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs));
+}
+
+static void __init nuri_machine_init(void)
+{
+ nuri_sdhci_init();
+
+ i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+ i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
+
+ /* Last */
+ platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
+}
+
+MACHINE_START(NURI, "NURI")
+ /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
+ .boot_params = S5P_PA_SDRAM + 0x100,
+ .init_irq = exynos4_init_irq,
+ .map_io = nuri_map_io,
+ .init_machine = nuri_machine_init,
+ .timer = &exynos4_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s5pv310/mach-smdkc210.c b/arch/arm/mach-exynos4/mach-smdkc210.c
index d9cab02e23ca..25a256818122 100644
--- a/arch/arm/mach-s5pv310/mach-smdkc210.c
+++ b/arch/arm/mach-exynos4/mach-smdkc210.c
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/mach-smdkc210.c
+/* linux/arch/arm/mach-exynos4/mach-smdkc210.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,7 +21,7 @@
#include <plat/regs-serial.h>
#include <plat/regs-srom.h>
-#include <plat/s5pv310.h>
+#include <plat/exynos4.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
@@ -77,10 +77,10 @@ static struct s3c2410_uartcfg smdkc210_uartcfgs[] __initdata = {
static struct s3c_sdhci_platdata smdkc210_hsmmc0_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK0(2),
+ .ext_cd_gpio = EXYNOS4_GPK0(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-#ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT
+#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
#endif
@@ -88,17 +88,17 @@ static struct s3c_sdhci_platdata smdkc210_hsmmc0_pdata __initdata = {
static struct s3c_sdhci_platdata smdkc210_hsmmc1_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK0(2),
+ .ext_cd_gpio = EXYNOS4_GPK0(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct s3c_sdhci_platdata smdkc210_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK2(2),
+ .ext_cd_gpio = EXYNOS4_GPK2(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-#ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT
+#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
#endif
@@ -106,15 +106,15 @@ static struct s3c_sdhci_platdata smdkc210_hsmmc2_pdata __initdata = {
static struct s3c_sdhci_platdata smdkc210_hsmmc3_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK2(2),
+ .ext_cd_gpio = EXYNOS4_GPK2(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct resource smdkc210_smsc911x_resources[] = {
[0] = {
- .start = S5PV310_PA_SROM_BANK(1),
- .end = S5PV310_PA_SROM_BANK(1) + SZ_64K - 1,
+ .start = EXYNOS4_PA_SROM_BANK(1),
+ .end = EXYNOS4_PA_SROM_BANK(1) + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -154,16 +154,16 @@ static struct platform_device *smdkc210_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_rtc,
&s3c_device_wdt,
- &s5pv310_device_ac97,
- &s5pv310_device_i2s0,
- &s5pv310_device_pd[PD_MFC],
- &s5pv310_device_pd[PD_G3D],
- &s5pv310_device_pd[PD_LCD0],
- &s5pv310_device_pd[PD_LCD1],
- &s5pv310_device_pd[PD_CAM],
- &s5pv310_device_pd[PD_TV],
- &s5pv310_device_pd[PD_GPS],
- &s5pv310_device_sysmmu,
+ &exynos4_device_ac97,
+ &exynos4_device_i2s0,
+ &exynos4_device_pd[PD_MFC],
+ &exynos4_device_pd[PD_G3D],
+ &exynos4_device_pd[PD_LCD0],
+ &exynos4_device_pd[PD_LCD1],
+ &exynos4_device_pd[PD_CAM],
+ &exynos4_device_pd[PD_TV],
+ &exynos4_device_pd[PD_GPS],
+ &exynos4_device_sysmmu,
&samsung_asoc_dma,
&smdkc210_smsc911x,
};
@@ -216,8 +216,8 @@ static void __init smdkc210_machine_init(void)
MACHINE_START(SMDKC210, "SMDKC210")
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
.boot_params = S5P_PA_SDRAM + 0x100,
- .init_irq = s5pv310_init_irq,
+ .init_irq = exynos4_init_irq,
.map_io = smdkc210_map_io,
.init_machine = smdkc210_machine_init,
- .timer = &s5pv310_timer,
+ .timer = &exynos4_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv310/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c
index b1cddbf3c616..88e0275143be 100644
--- a/arch/arm/mach-s5pv310/mach-smdkv310.c
+++ b/arch/arm/mach-exynos4/mach-smdkv310.c
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/mach-smdkv310.c
+/* linux/arch/arm/mach-exynos4/mach-smdkv310.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,15 +15,17 @@
#include <linux/smsc911x.h>
#include <linux/io.h>
#include <linux/i2c.h>
+#include <linux/input.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
#include <plat/regs-serial.h>
#include <plat/regs-srom.h>
-#include <plat/s5pv310.h>
+#include <plat/exynos4.h>
#include <plat/cpu.h>
#include <plat/devs.h>
+#include <plat/keypad.h>
#include <plat/sdhci.h>
#include <plat/iic.h>
#include <plat/pd.h>
@@ -77,10 +79,10 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = {
static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK0(2),
+ .ext_cd_gpio = EXYNOS4_GPK0(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-#ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT
+#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
#endif
@@ -88,17 +90,17 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK0(2),
+ .ext_cd_gpio = EXYNOS4_GPK0(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK2(2),
+ .ext_cd_gpio = EXYNOS4_GPK2(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-#ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT
+#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
#endif
@@ -106,15 +108,15 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
static struct s3c_sdhci_platdata smdkv310_hsmmc3_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
- .ext_cd_gpio = S5PV310_GPK2(2),
+ .ext_cd_gpio = EXYNOS4_GPK2(2),
.ext_cd_gpio_invert = 1,
.clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct resource smdkv310_smsc911x_resources[] = {
[0] = {
- .start = S5PV310_PA_SROM_BANK(1),
- .end = S5PV310_PA_SROM_BANK(1) + SZ_64K - 1,
+ .start = EXYNOS4_PA_SROM_BANK(1),
+ .end = EXYNOS4_PA_SROM_BANK(1) + SZ_64K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -142,6 +144,25 @@ static struct platform_device smdkv310_smsc911x = {
},
};
+static uint32_t smdkv310_keymap[] __initdata = {
+ /* KEY(row, col, keycode) */
+ KEY(0, 3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3),
+ KEY(0, 6, KEY_4), KEY(0, 7, KEY_5),
+ KEY(1, 3, KEY_A), KEY(1, 4, KEY_B), KEY(1, 5, KEY_C),
+ KEY(1, 6, KEY_D), KEY(1, 7, KEY_E)
+};
+
+static struct matrix_keymap_data smdkv310_keymap_data __initdata = {
+ .keymap = smdkv310_keymap,
+ .keymap_size = ARRAY_SIZE(smdkv310_keymap),
+};
+
+static struct samsung_keypad_platdata smdkv310_keypad_data __initdata = {
+ .keymap_data = &smdkv310_keymap_data,
+ .rows = 2,
+ .cols = 8,
+};
+
static struct i2c_board_info i2c_devs1[] __initdata = {
{I2C_BOARD_INFO("wm8994", 0x1a),},
};
@@ -154,16 +175,17 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_rtc,
&s3c_device_wdt,
- &s5pv310_device_ac97,
- &s5pv310_device_i2s0,
- &s5pv310_device_pd[PD_MFC],
- &s5pv310_device_pd[PD_G3D],
- &s5pv310_device_pd[PD_LCD0],
- &s5pv310_device_pd[PD_LCD1],
- &s5pv310_device_pd[PD_CAM],
- &s5pv310_device_pd[PD_TV],
- &s5pv310_device_pd[PD_GPS],
- &s5pv310_device_sysmmu,
+ &exynos4_device_ac97,
+ &exynos4_device_i2s0,
+ &samsung_device_keypad,
+ &exynos4_device_pd[PD_MFC],
+ &exynos4_device_pd[PD_G3D],
+ &exynos4_device_pd[PD_LCD0],
+ &exynos4_device_pd[PD_LCD1],
+ &exynos4_device_pd[PD_CAM],
+ &exynos4_device_pd[PD_TV],
+ &exynos4_device_pd[PD_GPS],
+ &exynos4_device_sysmmu,
&samsung_asoc_dma,
&smdkv310_smsc911x,
};
@@ -210,6 +232,8 @@ static void __init smdkv310_machine_init(void)
s3c_sdhci2_set_platdata(&smdkv310_hsmmc2_pdata);
s3c_sdhci3_set_platdata(&smdkv310_hsmmc3_pdata);
+ samsung_keypad_set_platdata(&smdkv310_keypad_data);
+
platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
}
@@ -217,8 +241,8 @@ MACHINE_START(SMDKV310, "SMDKV310")
/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
/* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */
.boot_params = S5P_PA_SDRAM + 0x100,
- .init_irq = s5pv310_init_irq,
+ .init_irq = exynos4_init_irq,
.map_io = smdkv310_map_io,
.init_machine = smdkv310_machine_init,
- .timer = &s5pv310_timer,
+ .timer = &exynos4_timer,
MACHINE_END
diff --git a/arch/arm/mach-exynos4/mach-universal_c210.c b/arch/arm/mach-exynos4/mach-universal_c210.c
new file mode 100644
index 000000000000..97d329fff2cf
--- /dev/null
+++ b/arch/arm/mach-exynos4/mach-universal_c210.c
@@ -0,0 +1,650 @@
+/* linux/arch/arm/mach-exynos4/mach-universal_c210.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/mfd/max8998.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/max8952.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/exynos4.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/iic.h>
+#include <plat/sdhci.h>
+
+#include <mach/map.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define UNIVERSAL_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI | \
+ S3C2443_UCON_RXERR_IRQEN)
+
+#define UNIVERSAL_ULCON_DEFAULT S3C2410_LCON_CS8
+
+#define UNIVERSAL_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S5PV210_UFCON_TXTRIG256 | \
+ S5PV210_UFCON_RXTRIG256)
+
+static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .ucon = UNIVERSAL_UCON_DEFAULT,
+ .ulcon = UNIVERSAL_ULCON_DEFAULT,
+ .ufcon = UNIVERSAL_UFCON_DEFAULT,
+ },
+ [1] = {
+ .hwport = 1,
+ .ucon = UNIVERSAL_UCON_DEFAULT,
+ .ulcon = UNIVERSAL_ULCON_DEFAULT,
+ .ufcon = UNIVERSAL_UFCON_DEFAULT,
+ },
+ [2] = {
+ .hwport = 2,
+ .ucon = UNIVERSAL_UCON_DEFAULT,
+ .ulcon = UNIVERSAL_ULCON_DEFAULT,
+ .ufcon = UNIVERSAL_UFCON_DEFAULT,
+ },
+ [3] = {
+ .hwport = 3,
+ .ucon = UNIVERSAL_UCON_DEFAULT,
+ .ulcon = UNIVERSAL_ULCON_DEFAULT,
+ .ufcon = UNIVERSAL_UFCON_DEFAULT,
+ },
+};
+
+static struct regulator_consumer_supply max8952_consumer =
+ REGULATOR_SUPPLY("vddarm", NULL);
+
+static struct max8952_platform_data universal_max8952_pdata __initdata = {
+ .gpio_vid0 = EXYNOS4_GPX0(3),
+ .gpio_vid1 = EXYNOS4_GPX0(4),
+ .gpio_en = -1, /* Not controllable, set "Always High" */
+ .default_mode = 0, /* vid0 = 0, vid1 = 0 */
+ .dvs_mode = { 48, 32, 28, 18 }, /* 1.25, 1.20, 1.05, 0.95V */
+ .sync_freq = 0, /* default: fastest */
+ .ramp_speed = 0, /* default: fastest */
+
+ .reg_data = {
+ .constraints = {
+ .name = "VARM_1.2V",
+ .min_uV = 770000,
+ .max_uV = 1400000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &max8952_consumer,
+ },
+};
+
+static struct regulator_consumer_supply lp3974_buck1_consumer =
+ REGULATOR_SUPPLY("vddint", NULL);
+
+static struct regulator_consumer_supply lp3974_buck2_consumer =
+ REGULATOR_SUPPLY("vddg3d", NULL);
+
+static struct regulator_init_data lp3974_buck1_data = {
+ .constraints = {
+ .name = "VINT_1.1V",
+ .min_uV = 750000,
+ .max_uV = 1500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &lp3974_buck1_consumer,
+};
+
+static struct regulator_init_data lp3974_buck2_data = {
+ .constraints = {
+ .name = "VG3D_1.1V",
+ .min_uV = 750000,
+ .max_uV = 1500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &lp3974_buck2_consumer,
+};
+
+static struct regulator_init_data lp3974_buck3_data = {
+ .constraints = {
+ .name = "VCC_1.8V",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = 1,
+ .always_on = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_buck4_data = {
+ .constraints = {
+ .name = "VMEM_1.2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .apply_uV = 1,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo2_data = {
+ .constraints = {
+ .name = "VALIVE_1.2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .apply_uV = 1,
+ .always_on = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo3_data = {
+ .constraints = {
+ .name = "VUSB+MIPI_1.1V",
+ .min_uV = 1100000,
+ .max_uV = 1100000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo4_data = {
+ .constraints = {
+ .name = "VADC_3.3V",
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo5_data = {
+ .constraints = {
+ .name = "VTF_2.8V",
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo6_data = {
+ .constraints = {
+ .name = "LDO6",
+ .min_uV = 2000000,
+ .max_uV = 2000000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo7_data = {
+ .constraints = {
+ .name = "VLCD+VMIPI_1.8V",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo8_data = {
+ .constraints = {
+ .name = "VUSB+VDAC_3.3V",
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo9_data = {
+ .constraints = {
+ .name = "VCC_2.8V",
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = 1,
+ .always_on = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo10_data = {
+ .constraints = {
+ .name = "VPLL_1.1V",
+ .min_uV = 1100000,
+ .max_uV = 1100000,
+ .boot_on = 1,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo11_data = {
+ .constraints = {
+ .name = "CAM_AF_3.3V",
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo12_data = {
+ .constraints = {
+ .name = "PS_2.8V",
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo13_data = {
+ .constraints = {
+ .name = "VHIC_1.2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo14_data = {
+ .constraints = {
+ .name = "CAM_I_HOST_1.8V",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo15_data = {
+ .constraints = {
+ .name = "CAM_S_DIG+FM33_CORE_1.2V",
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo16_data = {
+ .constraints = {
+ .name = "CAM_S_ANA_2.8V",
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_ldo17_data = {
+ .constraints = {
+ .name = "VCC_3.0V_LCD",
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_32khz_ap_data = {
+ .constraints = {
+ .name = "32KHz AP",
+ .always_on = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_32khz_cp_data = {
+ .constraints = {
+ .name = "32KHz CP",
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_vichg_data = {
+ .constraints = {
+ .name = "VICHG",
+ .state_mem = {
+ .disabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_esafeout1_data = {
+ .constraints = {
+ .name = "SAFEOUT1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data lp3974_esafeout2_data = {
+ .constraints = {
+ .name = "SAFEOUT2",
+ .boot_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+};
+
+static struct max8998_regulator_data lp3974_regulators[] = {
+ { MAX8998_LDO2, &lp3974_ldo2_data },
+ { MAX8998_LDO3, &lp3974_ldo3_data },
+ { MAX8998_LDO4, &lp3974_ldo4_data },
+ { MAX8998_LDO5, &lp3974_ldo5_data },
+ { MAX8998_LDO6, &lp3974_ldo6_data },
+ { MAX8998_LDO7, &lp3974_ldo7_data },
+ { MAX8998_LDO8, &lp3974_ldo8_data },
+ { MAX8998_LDO9, &lp3974_ldo9_data },
+ { MAX8998_LDO10, &lp3974_ldo10_data },
+ { MAX8998_LDO11, &lp3974_ldo11_data },
+ { MAX8998_LDO12, &lp3974_ldo12_data },
+ { MAX8998_LDO13, &lp3974_ldo13_data },
+ { MAX8998_LDO14, &lp3974_ldo14_data },
+ { MAX8998_LDO15, &lp3974_ldo15_data },
+ { MAX8998_LDO16, &lp3974_ldo16_data },
+ { MAX8998_LDO17, &lp3974_ldo17_data },
+ { MAX8998_BUCK1, &lp3974_buck1_data },
+ { MAX8998_BUCK2, &lp3974_buck2_data },
+ { MAX8998_BUCK3, &lp3974_buck3_data },
+ { MAX8998_BUCK4, &lp3974_buck4_data },
+ { MAX8998_EN32KHZ_AP, &lp3974_32khz_ap_data },
+ { MAX8998_EN32KHZ_CP, &lp3974_32khz_cp_data },
+ { MAX8998_ENVICHG, &lp3974_vichg_data },
+ { MAX8998_ESAFEOUT1, &lp3974_esafeout1_data },
+ { MAX8998_ESAFEOUT2, &lp3974_esafeout2_data },
+};
+
+static struct max8998_platform_data universal_lp3974_pdata = {
+ .num_regulators = ARRAY_SIZE(lp3974_regulators),
+ .regulators = lp3974_regulators,
+ .buck1_voltage1 = 1100000, /* INT */
+ .buck1_voltage2 = 1000000,
+ .buck1_voltage3 = 1100000,
+ .buck1_voltage4 = 1000000,
+ .buck1_set1 = EXYNOS4_GPX0(5),
+ .buck1_set2 = EXYNOS4_GPX0(6),
+ .buck2_voltage1 = 1200000, /* G3D */
+ .buck2_voltage2 = 1100000,
+ .buck1_default_idx = 0,
+ .buck2_set3 = EXYNOS4_GPE2(0),
+ .buck2_default_idx = 0,
+ .wakeup = true,
+};
+
+/* GPIO I2C 5 (PMIC) */
+static struct i2c_board_info i2c5_devs[] __initdata = {
+ {
+ I2C_BOARD_INFO("max8952", 0xC0 >> 1),
+ .platform_data = &universal_max8952_pdata,
+ }, {
+ I2C_BOARD_INFO("lp3974", 0xCC >> 1),
+ .platform_data = &universal_lp3974_pdata,
+ },
+};
+
+/* GPIO KEYS */
+static struct gpio_keys_button universal_gpio_keys_tables[] = {
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = EXYNOS4_GPX2(0), /* XEINT16 */
+ .desc = "gpio-keys: KEY_VOLUMEUP",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = EXYNOS4_GPX2(1), /* XEINT17 */
+ .desc = "gpio-keys: KEY_VOLUMEDOWN",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_CONFIG,
+ .gpio = EXYNOS4_GPX2(2), /* XEINT18 */
+ .desc = "gpio-keys: KEY_CONFIG",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_CAMERA,
+ .gpio = EXYNOS4_GPX2(3), /* XEINT19 */
+ .desc = "gpio-keys: KEY_CAMERA",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ }, {
+ .code = KEY_OK,
+ .gpio = EXYNOS4_GPX3(5), /* XEINT29 */
+ .desc = "gpio-keys: KEY_OK",
+ .type = EV_KEY,
+ .active_low = 1,
+ .debounce_interval = 1,
+ },
+};
+
+static struct gpio_keys_platform_data universal_gpio_keys_data = {
+ .buttons = universal_gpio_keys_tables,
+ .nbuttons = ARRAY_SIZE(universal_gpio_keys_tables),
+};
+
+static struct platform_device universal_gpio_keys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &universal_gpio_keys_data,
+ },
+};
+
+/* eMMC */
+static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
+ .max_width = 8,
+ .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE),
+ .cd_type = S3C_SDHCI_CD_PERMANENT,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct regulator_consumer_supply mmc0_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+};
+
+static struct regulator_init_data mmc0_fixed_voltage_init_data = {
+ .constraints = {
+ .name = "VMEM_VDD_2.8V",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(mmc0_supplies),
+ .consumer_supplies = mmc0_supplies,
+};
+
+static struct fixed_voltage_config mmc0_fixed_voltage_config = {
+ .supply_name = "MASSMEMORY_EN",
+ .microvolts = 2800000,
+ .gpio = EXYNOS4_GPE1(3),
+ .enable_high = true,
+ .init_data = &mmc0_fixed_voltage_init_data,
+};
+
+static struct platform_device mmc0_fixed_voltage = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &mmc0_fixed_voltage_config,
+ },
+};
+
+/* SD */
+static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE,
+ .ext_cd_gpio = EXYNOS4_GPX3(4), /* XEINT_28 */
+ .ext_cd_gpio_invert = 1,
+ .cd_type = S3C_SDHCI_CD_GPIO,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+/* WiFi */
+static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE,
+ .cd_type = S3C_SDHCI_CD_EXTERNAL,
+};
+
+static void __init universal_sdhci_init(void)
+{
+ s3c_sdhci0_set_platdata(&universal_hsmmc0_data);
+ s3c_sdhci2_set_platdata(&universal_hsmmc2_data);
+ s3c_sdhci3_set_platdata(&universal_hsmmc3_data);
+}
+
+/* I2C0 */
+static struct i2c_board_info i2c0_devs[] __initdata = {
+ /* Camera, To be updated */
+};
+
+/* I2C1 */
+static struct i2c_board_info i2c1_devs[] __initdata = {
+ /* Gyro, To be updated */
+};
+
+static struct platform_device *universal_devices[] __initdata = {
+ /* Samsung Platform Devices */
+ &mmc0_fixed_voltage,
+ &s3c_device_hsmmc0,
+ &s3c_device_hsmmc2,
+ &s3c_device_hsmmc3,
+ &s3c_device_i2c5,
+
+ /* Universal Devices */
+ &universal_gpio_keys,
+ &s5p_device_onenand,
+};
+
+static void __init universal_map_io(void)
+{
+ s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+ s3c24xx_init_clocks(24000000);
+ s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs));
+}
+
+static void __init universal_machine_init(void)
+{
+ universal_sdhci_init();
+
+ i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs));
+ i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+
+ s3c_i2c5_set_platdata(NULL);
+ i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
+
+ /* Last */
+ platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices));
+}
+
+MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
+ /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
+ .boot_params = S5P_PA_SDRAM + 0x100,
+ .init_irq = exynos4_init_irq,
+ .map_io = universal_map_io,
+ .init_machine = universal_machine_init,
+ .timer = &exynos4_timer,
+MACHINE_END
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c
new file mode 100644
index 000000000000..af82a8fbb68b
--- /dev/null
+++ b/arch/arm/mach-exynos4/mct.c
@@ -0,0 +1,421 @@
+/* linux/arch/arm/mach-exynos4/mct.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 MCT(Multi-Core Timer) support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/percpu.h>
+
+#include <mach/map.h>
+#include <mach/regs-mct.h>
+#include <asm/mach/time.h>
+
+static unsigned long clk_cnt_per_tick;
+static unsigned long clk_rate;
+
+struct mct_clock_event_device {
+ struct clock_event_device *evt;
+ void __iomem *base;
+};
+
+struct mct_clock_event_device mct_tick[2];
+
+static void exynos4_mct_write(unsigned int value, void *addr)
+{
+ void __iomem *stat_addr;
+ u32 mask;
+ u32 i;
+
+ __raw_writel(value, addr);
+
+ switch ((u32) addr) {
+ case (u32) EXYNOS4_MCT_G_TCON:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 16; /* G_TCON write status */
+ break;
+ case (u32) EXYNOS4_MCT_G_COMP0_L:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 0; /* G_COMP0_L write status */
+ break;
+ case (u32) EXYNOS4_MCT_G_COMP0_U:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 1; /* G_COMP0_U write status */
+ break;
+ case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR:
+ stat_addr = EXYNOS4_MCT_G_WSTAT;
+ mask = 1 << 2; /* G_COMP0_ADD_INCR write status */
+ break;
+ case (u32) EXYNOS4_MCT_G_CNT_L:
+ stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
+ mask = 1 << 0; /* G_CNT_L write status */
+ break;
+ case (u32) EXYNOS4_MCT_G_CNT_U:
+ stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
+ mask = 1 << 1; /* G_CNT_U write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_TCON_OFFSET):
+ stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 3; /* L0_TCON write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_TCON_OFFSET):
+ stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 3; /* L1_TCON write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_TCNTB_OFFSET):
+ stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 0; /* L0_TCNTB write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_TCNTB_OFFSET):
+ stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 0; /* L1_TCNTB write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_ICNTB_OFFSET):
+ stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 1; /* L0_ICNTB write status */
+ break;
+ case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_ICNTB_OFFSET):
+ stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET;
+ mask = 1 << 1; /* L1_ICNTB write status */
+ break;
+ default:
+ return;
+ }
+
+ /* Wait maximum 1 ms until written values are applied */
+ for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
+ if (__raw_readl(stat_addr) & mask) {
+ __raw_writel(mask, stat_addr);
+ return;
+ }
+
+ panic("MCT hangs after writing %d (addr:0x%08x)\n", value, (u32)addr);
+}
+
+/* Clocksource handling */
+static void exynos4_mct_frc_start(u32 hi, u32 lo)
+{
+ u32 reg;
+
+ exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
+ exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
+
+ reg = __raw_readl(EXYNOS4_MCT_G_TCON);
+ reg |= MCT_G_TCON_START;
+ exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
+}
+
+static cycle_t exynos4_frc_read(struct clocksource *cs)
+{
+ unsigned int lo, hi;
+ u32 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
+
+ do {
+ hi = hi2;
+ lo = __raw_readl(EXYNOS4_MCT_G_CNT_L);
+ hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
+ } while (hi != hi2);
+
+ return ((cycle_t)hi << 32) | lo;
+}
+
+struct clocksource mct_frc = {
+ .name = "mct-frc",
+ .rating = 400,
+ .read = exynos4_frc_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init exynos4_clocksource_init(void)
+{
+ exynos4_mct_frc_start(0, 0);
+
+ if (clocksource_register_hz(&mct_frc, clk_rate))
+ panic("%s: can't register clocksource\n", mct_frc.name);
+}
+
+static void exynos4_mct_comp0_stop(void)
+{
+ unsigned int tcon;
+
+ tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
+ tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
+
+ exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
+ exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
+}
+
+static void exynos4_mct_comp0_start(enum clock_event_mode mode,
+ unsigned long cycles)
+{
+ unsigned int tcon;
+ cycle_t comp_cycle;
+
+ tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
+
+ if (mode == CLOCK_EVT_MODE_PERIODIC) {
+ tcon |= MCT_G_TCON_COMP0_AUTO_INC;
+ exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
+ }
+
+ comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
+ exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
+ exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
+
+ exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
+
+ tcon |= MCT_G_TCON_COMP0_ENABLE;
+ exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
+}
+
+static int exynos4_comp_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ exynos4_mct_comp0_start(evt->mode, cycles);
+
+ return 0;
+}
+
+static void exynos4_comp_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ exynos4_mct_comp0_stop();
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ exynos4_mct_comp0_start(mode, clk_cnt_per_tick);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device mct_comp_device = {
+ .name = "mct-comp",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 250,
+ .set_next_event = exynos4_comp_set_next_event,
+ .set_mode = exynos4_comp_set_mode,
+};
+
+static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mct_comp_event_irq = {
+ .name = "mct_comp_irq",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = exynos4_mct_comp_isr,
+ .dev_id = &mct_comp_device,
+};
+
+static void exynos4_clockevent_init(void)
+{
+ clk_cnt_per_tick = clk_rate / 2 / HZ;
+
+ clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5);
+ mct_comp_device.max_delta_ns =
+ clockevent_delta2ns(0xffffffff, &mct_comp_device);
+ mct_comp_device.min_delta_ns =
+ clockevent_delta2ns(0xf, &mct_comp_device);
+ mct_comp_device.cpumask = cpumask_of(0);
+ clockevents_register_device(&mct_comp_device);
+
+ setup_irq(IRQ_MCT_G0, &mct_comp_event_irq);
+}
+
+#ifdef CONFIG_LOCAL_TIMERS
+/* Clock event handling */
+static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
+{
+ unsigned long tmp;
+ unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
+ void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET;
+
+ tmp = __raw_readl(addr);
+ if (tmp & mask) {
+ tmp &= ~mask;
+ exynos4_mct_write(tmp, addr);
+ }
+}
+
+static void exynos4_mct_tick_start(unsigned long cycles,
+ struct mct_clock_event_device *mevt)
+{
+ unsigned long tmp;
+
+ exynos4_mct_tick_stop(mevt);
+
+ tmp = (1 << 31) | cycles; /* MCT_L_UPDATE_ICNTB */
+
+ /* update interrupt count buffer */
+ exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
+
+ /* enable MCT tick interupt */
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
+
+ tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET);
+ tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
+ MCT_L_TCON_INTERVAL_MODE;
+ exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
+}
+
+static int exynos4_tick_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ struct mct_clock_event_device *mevt = &mct_tick[smp_processor_id()];
+
+ exynos4_mct_tick_start(cycles, mevt);
+
+ return 0;
+}
+
+static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct mct_clock_event_device *mevt = &mct_tick[smp_processor_id()];
+
+ exynos4_mct_tick_stop(mevt);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ exynos4_mct_tick_start(clk_cnt_per_tick, mevt);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
+{
+ struct mct_clock_event_device *mevt = dev_id;
+ struct clock_event_device *evt = mevt->evt;
+
+ /*
+ * This is for supporting oneshot mode.
+ * Mct would generate interrupt periodically
+ * without explicit stopping.
+ */
+ if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
+ exynos4_mct_tick_stop(mevt);
+
+ /* Clear the MCT tick interrupt */
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mct_tick0_event_irq = {
+ .name = "mct_tick0_irq",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = exynos4_mct_tick_isr,
+};
+
+static struct irqaction mct_tick1_event_irq = {
+ .name = "mct_tick1_irq",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = exynos4_mct_tick_isr,
+};
+
+static void exynos4_mct_tick_init(struct clock_event_device *evt)
+{
+ unsigned int cpu = smp_processor_id();
+
+ mct_tick[cpu].evt = evt;
+
+ if (cpu == 0) {
+ mct_tick[cpu].base = EXYNOS4_MCT_L0_BASE;
+ evt->name = "mct_tick0";
+ } else {
+ mct_tick[cpu].base = EXYNOS4_MCT_L1_BASE;
+ evt->name = "mct_tick1";
+ }
+
+ evt->cpumask = cpumask_of(cpu);
+ evt->set_next_event = exynos4_tick_set_next_event;
+ evt->set_mode = exynos4_tick_set_mode;
+ evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ evt->rating = 450;
+
+ clockevents_calc_mult_shift(evt, clk_rate / 2, 5);
+ evt->max_delta_ns =
+ clockevent_delta2ns(0x7fffffff, evt);
+ evt->min_delta_ns =
+ clockevent_delta2ns(0xf, evt);
+
+ clockevents_register_device(evt);
+
+ exynos4_mct_write(0x1, mct_tick[cpu].base + MCT_L_TCNTB_OFFSET);
+
+ if (cpu == 0) {
+ mct_tick0_event_irq.dev_id = &mct_tick[cpu];
+ setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
+ } else {
+ mct_tick1_event_irq.dev_id = &mct_tick[cpu];
+ irq_set_affinity(IRQ_MCT1, cpumask_of(1));
+ setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
+ }
+}
+
+/* Setup the local clock events for a CPU */
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+ exynos4_mct_tick_init(evt);
+}
+
+int local_timer_ack(void)
+{
+ return 0;
+}
+
+#endif /* CONFIG_LOCAL_TIMERS */
+
+static void __init exynos4_timer_resources(void)
+{
+ struct clk *mct_clk;
+ mct_clk = clk_get(NULL, "xtal");
+
+ clk_rate = clk_get_rate(mct_clk);
+}
+
+static void __init exynos4_timer_init(void)
+{
+ exynos4_timer_resources();
+ exynos4_clocksource_init();
+ exynos4_clockevent_init();
+}
+
+struct sys_timer exynos4_timer = {
+ .init = exynos4_timer_init,
+};
diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-exynos4/platsmp.c
index 34093b069f67..6d35878ec1aa 100644
--- a/arch/arm/mach-s5pv310/platsmp.c
+++ b/arch/arm/mach-exynos4/platsmp.c
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5pv310/platsmp.c
+/* linux/arch/arm/mach-exynos4/platsmp.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Cloned from linux/arch/arm/mach-vexpress/platsmp.c
*
@@ -28,7 +28,7 @@
#include <mach/hardware.h>
#include <mach/regs-clock.h>
-extern void s5pv310_secondary_startup(void);
+extern void exynos4_secondary_startup(void);
/*
* control for which core is the next to come out of the secondary
@@ -139,7 +139,7 @@ void __init smp_init_cpus(void)
/* sanity check */
if (ncores > NR_CPUS) {
printk(KERN_WARNING
- "S5PV310: no. of cores (%d) greater than configured "
+ "EXYNOS4: no. of cores (%d) greater than configured "
"maximum of %d - clipping\n",
ncores, NR_CPUS);
ncores = NR_CPUS;
@@ -168,5 +168,5 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
* until it receives a soft interrupt, and then the
* secondary CPU branches to this address.
*/
- __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM);
+ __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), S5P_VA_SYSRAM);
}
diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c
new file mode 100644
index 000000000000..10d917d9e3ad
--- /dev/null
+++ b/arch/arm/mach-exynos4/pm.c
@@ -0,0 +1,420 @@
+/* linux/arch/arm/mach-exynos4/pm.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4210 - Power Management support
+ *
+ * Based on arch/arm/mach-s3c2410/pm.c
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-pmu.h>
+#include <mach/pm-core.h>
+
+static struct sleep_save exynos4_sleep[] = {
+ { .reg = S5P_ARM_CORE0_LOWPWR , .val = 0x2, },
+ { .reg = S5P_DIS_IRQ_CORE0 , .val = 0x0, },
+ { .reg = S5P_DIS_IRQ_CENTRAL0 , .val = 0x0, },
+ { .reg = S5P_ARM_CORE1_LOWPWR , .val = 0x2, },
+ { .reg = S5P_DIS_IRQ_CORE1 , .val = 0x0, },
+ { .reg = S5P_DIS_IRQ_CENTRAL1 , .val = 0x0, },
+ { .reg = S5P_ARM_COMMON_LOWPWR , .val = 0x2, },
+ { .reg = S5P_L2_0_LOWPWR , .val = 0x3, },
+ { .reg = S5P_L2_1_LOWPWR , .val = 0x3, },
+ { .reg = S5P_CMU_ACLKSTOP_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_SCLKSTOP_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_LOWPWR , .val = 0x0, },
+ { .reg = S5P_APLL_SYSCLK_LOWPWR , .val = 0x0, },
+ { .reg = S5P_MPLL_SYSCLK_LOWPWR , .val = 0x0, },
+ { .reg = S5P_VPLL_SYSCLK_LOWPWR , .val = 0x0, },
+ { .reg = S5P_EPLL_SYSCLK_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_GPSALIVE_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_CAM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_TV_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_MFC_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_G3D_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_LCD0_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_LCD1_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_MAUDIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_CLKSTOP_GPS_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_CAM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_TV_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_MFC_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_G3D_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_LCD0_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_LCD1_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_MAUDIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CMU_RESET_GPS_LOWPWR , .val = 0x0, },
+ { .reg = S5P_TOP_BUS_LOWPWR , .val = 0x0, },
+ { .reg = S5P_TOP_RETENTION_LOWPWR , .val = 0x1, },
+ { .reg = S5P_TOP_PWR_LOWPWR , .val = 0x3, },
+ { .reg = S5P_LOGIC_RESET_LOWPWR , .val = 0x0, },
+ { .reg = S5P_ONENAND_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_MODIMIF_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_G2D_ACP_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_USBOTG_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_HSMMC_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CSSYS_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_SECSS_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PCIE_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_SATA_MEM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_DRAM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_MAUDIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_GPIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_UART_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_MMCA_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_MMCB_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_EBIA_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_EBIB_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_ISOLATION_LOWPWR , .val = 0x0, },
+ { .reg = S5P_PAD_RETENTION_ALV_SEL_LOWPWR , .val = 0x0, },
+ { .reg = S5P_XUSBXTI_LOWPWR , .val = 0x0, },
+ { .reg = S5P_XXTI_LOWPWR , .val = 0x0, },
+ { .reg = S5P_EXT_REGULATOR_LOWPWR , .val = 0x0, },
+ { .reg = S5P_GPIO_MODE_LOWPWR , .val = 0x0, },
+ { .reg = S5P_GPIO_MODE_MAUDIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_CAM_LOWPWR , .val = 0x0, },
+ { .reg = S5P_TV_LOWPWR , .val = 0x0, },
+ { .reg = S5P_MFC_LOWPWR , .val = 0x0, },
+ { .reg = S5P_G3D_LOWPWR , .val = 0x0, },
+ { .reg = S5P_LCD0_LOWPWR , .val = 0x0, },
+ { .reg = S5P_LCD1_LOWPWR , .val = 0x0, },
+ { .reg = S5P_MAUDIO_LOWPWR , .val = 0x0, },
+ { .reg = S5P_GPS_LOWPWR , .val = 0x0, },
+ { .reg = S5P_GPS_ALIVE_LOWPWR , .val = 0x0, },
+};
+
+static struct sleep_save exynos4_set_clksrc[] = {
+ { .reg = S5P_CLKSRC_MASK_TOP , .val = 0x00000001, },
+ { .reg = S5P_CLKSRC_MASK_CAM , .val = 0x11111111, },
+ { .reg = S5P_CLKSRC_MASK_TV , .val = 0x00000111, },
+ { .reg = S5P_CLKSRC_MASK_LCD0 , .val = 0x00001111, },
+ { .reg = S5P_CLKSRC_MASK_LCD1 , .val = 0x00001111, },
+ { .reg = S5P_CLKSRC_MASK_MAUDIO , .val = 0x00000001, },
+ { .reg = S5P_CLKSRC_MASK_FSYS , .val = 0x01011111, },
+ { .reg = S5P_CLKSRC_MASK_PERIL0 , .val = 0x01111111, },
+ { .reg = S5P_CLKSRC_MASK_PERIL1 , .val = 0x01110111, },
+ { .reg = S5P_CLKSRC_MASK_DMC , .val = 0x00010000, },
+};
+
+static struct sleep_save exynos4_core_save[] = {
+ /* CMU side */
+ SAVE_ITEM(S5P_CLKDIV_LEFTBUS),
+ SAVE_ITEM(S5P_CLKGATE_IP_LEFTBUS),
+ SAVE_ITEM(S5P_CLKDIV_RIGHTBUS),
+ SAVE_ITEM(S5P_CLKGATE_IP_RIGHTBUS),
+ SAVE_ITEM(S5P_EPLL_CON0),
+ SAVE_ITEM(S5P_EPLL_CON1),
+ SAVE_ITEM(S5P_VPLL_CON0),
+ SAVE_ITEM(S5P_VPLL_CON1),
+ SAVE_ITEM(S5P_CLKSRC_TOP0),
+ SAVE_ITEM(S5P_CLKSRC_TOP1),
+ SAVE_ITEM(S5P_CLKSRC_CAM),
+ SAVE_ITEM(S5P_CLKSRC_MFC),
+ SAVE_ITEM(S5P_CLKSRC_IMAGE),
+ SAVE_ITEM(S5P_CLKSRC_LCD0),
+ SAVE_ITEM(S5P_CLKSRC_LCD1),
+ SAVE_ITEM(S5P_CLKSRC_MAUDIO),
+ SAVE_ITEM(S5P_CLKSRC_FSYS),
+ SAVE_ITEM(S5P_CLKSRC_PERIL0),
+ SAVE_ITEM(S5P_CLKSRC_PERIL1),
+ SAVE_ITEM(S5P_CLKDIV_CAM),
+ SAVE_ITEM(S5P_CLKDIV_TV),
+ SAVE_ITEM(S5P_CLKDIV_MFC),
+ SAVE_ITEM(S5P_CLKDIV_G3D),
+ SAVE_ITEM(S5P_CLKDIV_IMAGE),
+ SAVE_ITEM(S5P_CLKDIV_LCD0),
+ SAVE_ITEM(S5P_CLKDIV_LCD1),
+ SAVE_ITEM(S5P_CLKDIV_MAUDIO),
+ SAVE_ITEM(S5P_CLKDIV_FSYS0),
+ SAVE_ITEM(S5P_CLKDIV_FSYS1),
+ SAVE_ITEM(S5P_CLKDIV_FSYS2),
+ SAVE_ITEM(S5P_CLKDIV_FSYS3),
+ SAVE_ITEM(S5P_CLKDIV_PERIL0),
+ SAVE_ITEM(S5P_CLKDIV_PERIL1),
+ SAVE_ITEM(S5P_CLKDIV_PERIL2),
+ SAVE_ITEM(S5P_CLKDIV_PERIL3),
+ SAVE_ITEM(S5P_CLKDIV_PERIL4),
+ SAVE_ITEM(S5P_CLKDIV_PERIL5),
+ SAVE_ITEM(S5P_CLKDIV_TOP),
+ SAVE_ITEM(S5P_CLKSRC_MASK_CAM),
+ SAVE_ITEM(S5P_CLKSRC_MASK_TV),
+ SAVE_ITEM(S5P_CLKSRC_MASK_LCD0),
+ SAVE_ITEM(S5P_CLKSRC_MASK_LCD1),
+ SAVE_ITEM(S5P_CLKSRC_MASK_MAUDIO),
+ SAVE_ITEM(S5P_CLKSRC_MASK_FSYS),
+ SAVE_ITEM(S5P_CLKSRC_MASK_PERIL0),
+ SAVE_ITEM(S5P_CLKSRC_MASK_PERIL1),
+ SAVE_ITEM(S5P_CLKGATE_SCLKCAM),
+ SAVE_ITEM(S5P_CLKGATE_IP_CAM),
+ SAVE_ITEM(S5P_CLKGATE_IP_TV),
+ SAVE_ITEM(S5P_CLKGATE_IP_MFC),
+ SAVE_ITEM(S5P_CLKGATE_IP_G3D),
+ SAVE_ITEM(S5P_CLKGATE_IP_IMAGE),
+ SAVE_ITEM(S5P_CLKGATE_IP_LCD0),
+ SAVE_ITEM(S5P_CLKGATE_IP_LCD1),
+ SAVE_ITEM(S5P_CLKGATE_IP_FSYS),
+ SAVE_ITEM(S5P_CLKGATE_IP_GPS),
+ SAVE_ITEM(S5P_CLKGATE_IP_PERIL),
+ SAVE_ITEM(S5P_CLKGATE_IP_PERIR),
+ SAVE_ITEM(S5P_CLKGATE_BLOCK),
+ SAVE_ITEM(S5P_CLKSRC_MASK_DMC),
+ SAVE_ITEM(S5P_CLKSRC_DMC),
+ SAVE_ITEM(S5P_CLKDIV_DMC0),
+ SAVE_ITEM(S5P_CLKDIV_DMC1),
+ SAVE_ITEM(S5P_CLKGATE_IP_DMC),
+ SAVE_ITEM(S5P_CLKSRC_CPU),
+ SAVE_ITEM(S5P_CLKDIV_CPU),
+ SAVE_ITEM(S5P_CLKGATE_SCLKCPU),
+ SAVE_ITEM(S5P_CLKGATE_IP_CPU),
+ /* GIC side */
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x000),
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x004),
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x008),
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x00C),
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x014),
+ SAVE_ITEM(S5P_VA_GIC_CPU + 0x018),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x000),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x004),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x100),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x104),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x108),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x300),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x304),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x308),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x400),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x404),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x408),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x410),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x414),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x418),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x420),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x424),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x428),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x430),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x434),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x438),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x440),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x444),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x448),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x450),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x454),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x458),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C),
+
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x800),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x804),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x808),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x810),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x814),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x818),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x820),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x824),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x828),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x830),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x834),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x838),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x840),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x844),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x848),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x850),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x854),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x858),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C),
+
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10),
+ SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14),
+
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080),
+ SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090),
+};
+
+static struct sleep_save exynos4_l2cc_save[] = {
+ SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL),
+ SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL),
+ SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL),
+ SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL),
+ SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
+};
+
+void exynos4_cpu_suspend(void)
+{
+ unsigned long tmp;
+ unsigned long mask = 0xFFFFFFFF;
+
+ /* Setting Central Sequence Register for power down mode */
+
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp &= ~(S5P_CENTRAL_LOWPWR_CFG);
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+ /* Setting Central Sequence option Register */
+
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION);
+ tmp &= ~(S5P_USE_MASK);
+ tmp |= S5P_USE_STANDBY_WFI0;
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+
+ /* Clear all interrupt pending to avoid early wakeup */
+
+ __raw_writel(mask, (S5P_VA_GIC_DIST + 0x280));
+ __raw_writel(mask, (S5P_VA_GIC_DIST + 0x284));
+ __raw_writel(mask, (S5P_VA_GIC_DIST + 0x288));
+
+ /* Disable all interrupt */
+
+ __raw_writel(0x0, (S5P_VA_GIC_CPU + 0x000));
+ __raw_writel(0x0, (S5P_VA_GIC_DIST + 0x000));
+ __raw_writel(mask, (S5P_VA_GIC_DIST + 0x184));
+ __raw_writel(mask, (S5P_VA_GIC_DIST + 0x188));
+
+ outer_flush_all();
+
+ /* issue the standby signal into the pm unit. */
+ cpu_do_idle();
+
+ /* we should never get past here */
+ panic("sleep resumed to originator?");
+}
+
+static void exynos4_pm_prepare(void)
+{
+ u32 tmp;
+
+ s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
+ s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
+
+ tmp = __raw_readl(S5P_INFORM1);
+
+ /* Set value of power down register for sleep mode */
+
+ s3c_pm_do_restore_core(exynos4_sleep, ARRAY_SIZE(exynos4_sleep));
+ __raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1);
+
+ /* ensure at least INFORM0 has the resume address */
+
+ __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
+
+ /* Before enter central sequence mode, clock src register have to set */
+
+ s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
+
+}
+
+static int exynos4_pm_add(struct sys_device *sysdev)
+{
+ pm_cpu_prep = exynos4_pm_prepare;
+ pm_cpu_sleep = exynos4_cpu_suspend;
+
+ return 0;
+}
+
+/* This function copy from linux/arch/arm/kernel/smp_scu.c */
+
+void exynos4_scu_enable(void __iomem *scu_base)
+{
+ u32 scu_ctrl;
+
+ scu_ctrl = __raw_readl(scu_base);
+ /* already enabled? */
+ if (scu_ctrl & 1)
+ return;
+
+ scu_ctrl |= 1;
+ __raw_writel(scu_ctrl, scu_base);
+
+ /*
+ * Ensure that the data accessed by CPU0 before the SCU was
+ * initialised is visible to the other CPUs.
+ */
+ flush_cache_all();
+}
+
+static int exynos4_pm_resume(struct sys_device *dev)
+{
+ /* For release retention */
+
+ __raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
+ __raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
+
+ s3c_pm_do_restore_core(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
+
+ exynos4_scu_enable(S5P_VA_SCU);
+
+#ifdef CONFIG_CACHE_L2X0
+ s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
+ outer_inv_all();
+ /* enable L2X0*/
+ writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
+#endif
+
+ return 0;
+}
+
+static struct sysdev_driver exynos4_pm_driver = {
+ .add = exynos4_pm_add,
+ .resume = exynos4_pm_resume,
+};
+
+static __init int exynos4_pm_drvinit(void)
+{
+ unsigned int tmp;
+
+ s3c_pm_init();
+
+ /* All wakeup disable */
+
+ tmp = __raw_readl(S5P_WAKEUP_MASK);
+ tmp |= ((0xFF << 8) | (0x1F << 1));
+ __raw_writel(tmp, S5P_WAKEUP_MASK);
+
+ return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
+}
+arch_initcall(exynos4_pm_drvinit);
diff --git a/arch/arm/mach-exynos4/setup-fimc.c b/arch/arm/mach-exynos4/setup-fimc.c
new file mode 100644
index 000000000000..6a45078d9d12
--- /dev/null
+++ b/arch/arm/mach-exynos4/setup-fimc.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * Exynos4 camera interface GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <plat/camport.h>
+
+int exynos4_fimc_setup_gpio(enum s5p_camport_id id)
+{
+ u32 gpio8, gpio5;
+ u32 sfn;
+ int ret;
+
+ switch (id) {
+ case S5P_CAMPORT_A:
+ gpio8 = EXYNOS4_GPJ0(0); /* PCLK, VSYNC, HREF, DATA[0:4] */
+ gpio5 = EXYNOS4_GPJ1(0); /* DATA[5:7], CLKOUT, FIELD */
+ sfn = S3C_GPIO_SFN(2);
+ break;
+
+ case S5P_CAMPORT_B:
+ gpio8 = EXYNOS4_GPE0(0); /* DATA[0:7] */
+ gpio5 = EXYNOS4_GPE1(0); /* PCLK, VSYNC, HREF, CLKOUT, FIELD */
+ sfn = S3C_GPIO_SFN(3);
+ break;
+
+ default:
+ WARN(1, "Wrong camport id: %d\n", id);
+ return -EINVAL;
+ }
+
+ ret = s3c_gpio_cfgall_range(gpio8, 8, sfn, S3C_GPIO_PULL_UP);
+ if (ret)
+ return ret;
+
+ return s3c_gpio_cfgall_range(gpio5, 5, sfn, S3C_GPIO_PULL_UP);
+}
diff --git a/arch/arm/mach-s5pv310/setup-i2c0.c b/arch/arm/mach-exynos4/setup-i2c0.c
index f47f8f3152ec..d395bd17c38b 100644
--- a/arch/arm/mach-s5pv310/setup-i2c0.c
+++ b/arch/arm/mach-exynos4/setup-i2c0.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c0.c
+ * linux/arch/arm/mach-exynos4/setup-i2c0.c
*
* Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
@@ -21,6 +21,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPD1(0), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPD1(0), 2,
S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c1.c b/arch/arm/mach-exynos4/setup-i2c1.c
index 9d07e4e2f14c..fd7235a43f6e 100644
--- a/arch/arm/mach-s5pv310/setup-i2c1.c
+++ b/arch/arm/mach-exynos4/setup-i2c1.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c1.c
+ * linux/arch/arm/mach-exynos4/setup-i2c1.c
*
* Copyright (C) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c1_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPD1(2), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPD1(2), 2,
S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c2.c b/arch/arm/mach-exynos4/setup-i2c2.c
index 4163b1233daf..2694b19e8b37 100644
--- a/arch/arm/mach-s5pv310/setup-i2c2.c
+++ b/arch/arm/mach-exynos4/setup-i2c2.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c2.c
+ * linux/arch/arm/mach-exynos4/setup-i2c2.c
*
* Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c2_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPA0(6), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPA0(6), 2,
S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c3.c b/arch/arm/mach-exynos4/setup-i2c3.c
index 180f153d2a20..379bd306993f 100644
--- a/arch/arm/mach-s5pv310/setup-i2c3.c
+++ b/arch/arm/mach-exynos4/setup-i2c3.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c3.c
+ * linux/arch/arm/mach-exynos4/setup-i2c3.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c3_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPA1(2), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPA1(2), 2,
S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c4.c b/arch/arm/mach-exynos4/setup-i2c4.c
index 909e8dfc5316..9f3c04855b76 100644
--- a/arch/arm/mach-s5pv310/setup-i2c4.c
+++ b/arch/arm/mach-exynos4/setup-i2c4.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c4.c
+ * linux/arch/arm/mach-exynos4/setup-i2c4.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c4_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPB(2), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c5.c b/arch/arm/mach-exynos4/setup-i2c5.c
index 5d0fa4ac0283..77e1a1e57c76 100644
--- a/arch/arm/mach-s5pv310/setup-i2c5.c
+++ b/arch/arm/mach-exynos4/setup-i2c5.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c5.c
+ * linux/arch/arm/mach-exynos4/setup-i2c5.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c5_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPB(6), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(6), 2,
S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c6.c b/arch/arm/mach-exynos4/setup-i2c6.c
index 34aafab92ac4..284d12b7af0e 100644
--- a/arch/arm/mach-s5pv310/setup-i2c6.c
+++ b/arch/arm/mach-exynos4/setup-i2c6.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c6.c
+ * linux/arch/arm/mach-exynos4/setup-i2c6.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c6_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPC1(3), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPC1(3), 2,
S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5pv310/setup-i2c7.c b/arch/arm/mach-exynos4/setup-i2c7.c
index 9b25b8d18920..b7611ee359a2 100644
--- a/arch/arm/mach-s5pv310/setup-i2c7.c
+++ b/arch/arm/mach-exynos4/setup-i2c7.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-s5pv310/setup-i2c7.c
+ * linux/arch/arm/mach-exynos4/setup-i2c7.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
*
@@ -18,6 +18,6 @@ struct platform_device; /* don't need the contents */
void s3c_i2c7_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(S5PV310_GPD0(2), 2,
+ s3c_gpio_cfgall_range(EXYNOS4_GPD0(2), 2,
S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos4/setup-keypad.c b/arch/arm/mach-exynos4/setup-keypad.c
new file mode 100644
index 000000000000..1ee0ebff111f
--- /dev/null
+++ b/arch/arm/mach-exynos4/setup-keypad.c
@@ -0,0 +1,35 @@
+/* linux/arch/arm/mach-exynos4/setup-keypad.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * GPIO configuration for Exynos4 KeyPad device
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+
+void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
+{
+ /* Keypads can be of various combinations, Just making sure */
+
+ if (rows > 8) {
+ /* Set all the necessary GPX2 pins: KP_ROW[0~7] */
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), 8, S3C_GPIO_SFN(3));
+
+ /* Set all the necessary GPX3 pins: KP_ROW[8~] */
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPX3(0), (rows - 8),
+ S3C_GPIO_SFN(3));
+ } else {
+ /* Set all the necessary GPX2 pins: KP_ROW[x] */
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPX2(0), rows,
+ S3C_GPIO_SFN(3));
+ }
+
+ /* Set all the necessary GPX1 pins to special-function 3: KP_COL[x] */
+ s3c_gpio_cfgrange_nopull(EXYNOS4_GPX1(0), cols, S3C_GPIO_SFN(3));
+}
diff --git a/arch/arm/mach-s5pv310/setup-sdhci-gpio.c b/arch/arm/mach-exynos4/setup-sdhci-gpio.c
index 86d38cc49135..1b3d3a2de95c 100644
--- a/arch/arm/mach-s5pv310/setup-sdhci-gpio.c
+++ b/arch/arm/mach-exynos4/setup-sdhci-gpio.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/setup-sdhci-gpio.c
+/* linux/arch/arm/mach-exynos4/setup-sdhci-gpio.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ * EXYNOS4 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,13 +23,13 @@
#include <plat/regs-sdhci.h>
#include <plat/sdhci.h>
-void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+void exynos4_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
{
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
unsigned int gpio;
/* Set all the necessary GPK0[0:1] pins to special-function 2 */
- for (gpio = S5PV310_GPK0(0); gpio < S5PV310_GPK0(2); gpio++) {
+ for (gpio = EXYNOS4_GPK0(0); gpio < EXYNOS4_GPK0(2); gpio++) {
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
@@ -37,14 +37,14 @@ void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
switch (width) {
case 8:
- for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) {
+ for (gpio = EXYNOS4_GPK1(3); gpio <= EXYNOS4_GPK1(6); gpio++) {
/* Data pin GPK1[3:6] to special-funtion 3 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
case 4:
- for (gpio = S5PV310_GPK0(3); gpio <= S5PV310_GPK0(6); gpio++) {
+ for (gpio = EXYNOS4_GPK0(3); gpio <= EXYNOS4_GPK0(6); gpio++) {
/* Data pin GPK0[3:6] to special-funtion 2 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
@@ -55,25 +55,25 @@ void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
}
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- s3c_gpio_cfgpin(S5PV310_GPK0(2), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(S5PV310_GPK0(2), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(EXYNOS4_GPK0(2), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPK0(2), S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
}
-void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+void exynos4_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
{
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
unsigned int gpio;
/* Set all the necessary GPK1[0:1] pins to special-function 2 */
- for (gpio = S5PV310_GPK1(0); gpio < S5PV310_GPK1(2); gpio++) {
+ for (gpio = EXYNOS4_GPK1(0); gpio < EXYNOS4_GPK1(2); gpio++) {
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
- for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) {
+ for (gpio = EXYNOS4_GPK1(3); gpio <= EXYNOS4_GPK1(6); gpio++) {
/* Data pin GPK1[3:6] to special-function 2 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
@@ -81,19 +81,19 @@ void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
}
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- s3c_gpio_cfgpin(S5PV310_GPK1(2), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(S5PV310_GPK1(2), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(EXYNOS4_GPK1(2), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPK1(2), S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
}
-void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
+void exynos4_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
{
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
unsigned int gpio;
/* Set all the necessary GPK2[0:1] pins to special-function 2 */
- for (gpio = S5PV310_GPK2(0); gpio < S5PV310_GPK2(2); gpio++) {
+ for (gpio = EXYNOS4_GPK2(0); gpio < EXYNOS4_GPK2(2); gpio++) {
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
@@ -101,14 +101,14 @@ void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
switch (width) {
case 8:
- for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) {
+ for (gpio = EXYNOS4_GPK3(3); gpio <= EXYNOS4_GPK3(6); gpio++) {
/* Data pin GPK3[3:6] to special-function 3 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
case 4:
- for (gpio = S5PV310_GPK2(3); gpio <= S5PV310_GPK2(6); gpio++) {
+ for (gpio = EXYNOS4_GPK2(3); gpio <= EXYNOS4_GPK2(6); gpio++) {
/* Data pin GPK2[3:6] to special-function 2 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
@@ -119,25 +119,25 @@ void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
}
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- s3c_gpio_cfgpin(S5PV310_GPK2(2), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(S5PV310_GPK2(2), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(EXYNOS4_GPK2(2), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPK2(2), S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
}
-void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
+void exynos4_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
{
struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
unsigned int gpio;
/* Set all the necessary GPK3[0:1] pins to special-function 2 */
- for (gpio = S5PV310_GPK3(0); gpio < S5PV310_GPK3(2); gpio++) {
+ for (gpio = EXYNOS4_GPK3(0); gpio < EXYNOS4_GPK3(2); gpio++) {
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
- for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) {
+ for (gpio = EXYNOS4_GPK3(3); gpio <= EXYNOS4_GPK3(6); gpio++) {
/* Data pin GPK3[3:6] to special-function 2 */
s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
@@ -145,8 +145,8 @@ void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
}
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- s3c_gpio_cfgpin(S5PV310_GPK3(2), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(S5PV310_GPK3(2), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgpin(EXYNOS4_GPK3(2), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPK3(2), S3C_GPIO_PULL_UP);
s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
}
}
diff --git a/arch/arm/mach-s5pv310/setup-sdhci.c b/arch/arm/mach-exynos4/setup-sdhci.c
index db8358fc4662..85f9433d4836 100644
--- a/arch/arm/mach-s5pv310/setup-sdhci.c
+++ b/arch/arm/mach-exynos4/setup-sdhci.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/setup-sdhci.c
+/* linux/arch/arm/mach-exynos4/setup-sdhci.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
- * S5PV310 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ * EXYNOS4 - Helper functions for settign up SDHCI device(s) (HSMMC)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,14 +23,14 @@
/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
-char *s5pv310_hsmmc_clksrcs[4] = {
+char *exynos4_hsmmc_clksrcs[4] = {
[0] = NULL,
[1] = NULL,
[2] = "sclk_mmc", /* mmc_bus */
[3] = NULL,
};
-void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev, void __iomem *r,
+void exynos4_setup_sdhci_cfg_card(struct platform_device *dev, void __iomem *r,
struct mmc_ios *ios, struct mmc_card *card)
{
u32 ctrl2, ctrl3;
diff --git a/arch/arm/mach-exynos4/sleep.S b/arch/arm/mach-exynos4/sleep.S
new file mode 100644
index 000000000000..6b62425417a6
--- /dev/null
+++ b/arch/arm/mach-exynos4/sleep.S
@@ -0,0 +1,76 @@
+/* linux/arch/arm/mach-exynos4/sleep.S
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4210 power Manager (Suspend-To-RAM) support
+ * Based on S3C2410 sleep code by:
+ * Ben Dooks, (c) 2004 Simtec Electronics
+ *
+ * Based on PXA/SA1100 sleep code by:
+ * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ * Cliff Brake, (c) 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+ .text
+
+ /*
+ * s3c_cpu_save
+ *
+ * entry:
+ * r1 = v:p offset
+ */
+
+ENTRY(s3c_cpu_save)
+
+ stmfd sp!, { r3 - r12, lr }
+ ldr r3, =resume_with_mmu
+ bl cpu_suspend
+
+ ldr r0, =pm_cpu_sleep
+ ldr r0, [ r0 ]
+ mov pc, r0
+
+resume_with_mmu:
+ ldmfd sp!, { r3 - r12, pc }
+
+ .ltorg
+
+ /*
+ * sleep magic, to allow the bootloader to check for an valid
+ * image to resume to. Must be the first word before the
+ * s3c_cpu_resume entry.
+ */
+
+ .word 0x2bedf00d
+
+ /*
+ * s3c_cpu_resume
+ *
+ * resume code entry for bootloader to call
+ *
+ * we must put this code here in the data segment as we have no
+ * other way of restoring the stack pointer after sleep, and we
+ * must not write to the code segment (code is read-only)
+ */
+
+ENTRY(s3c_cpu_resume)
+ b cpu_resume
diff --git a/arch/arm/mach-s5pv310/time.c b/arch/arm/mach-exynos4/time.c
index b262d4615331..86b9fa0d3639 100644
--- a/arch/arm/mach-s5pv310/time.c
+++ b/arch/arm/mach-exynos4/time.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5pv310/time.c
+/* linux/arch/arm/mach-exynos4/time.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * S5PV310 (and compatible) HRT support
+ * EXYNOS4 (and compatible) HRT support
* PWM 2/4 is used for this feature
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@ static struct clk *tdiv2;
static struct clk *tdiv4;
static struct clk *timerclk;
-static void s5pv310_pwm_stop(unsigned int pwm_id)
+static void exynos4_pwm_stop(unsigned int pwm_id)
{
unsigned long tcon;
@@ -52,7 +52,7 @@ static void s5pv310_pwm_stop(unsigned int pwm_id)
__raw_writel(tcon, S3C2410_TCON);
}
-static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
+static void exynos4_pwm_init(unsigned int pwm_id, unsigned long tcnt)
{
unsigned long tcon;
@@ -86,7 +86,7 @@ static void s5pv310_pwm_init(unsigned int pwm_id, unsigned long tcnt)
}
}
-static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
+static inline void exynos4_pwm_start(unsigned int pwm_id, bool periodic)
{
unsigned long tcon;
@@ -117,23 +117,23 @@ static inline void s5pv310_pwm_start(unsigned int pwm_id, bool periodic)
__raw_writel(tcon, S3C2410_TCON);
}
-static int s5pv310_pwm_set_next_event(unsigned long cycles,
+static int exynos4_pwm_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- s5pv310_pwm_init(2, cycles);
- s5pv310_pwm_start(2, 0);
+ exynos4_pwm_init(2, cycles);
+ exynos4_pwm_start(2, 0);
return 0;
}
-static void s5pv310_pwm_set_mode(enum clock_event_mode mode,
+static void exynos4_pwm_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- s5pv310_pwm_stop(2);
+ exynos4_pwm_stop(2);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- s5pv310_pwm_init(2, clock_count_per_tick);
- s5pv310_pwm_start(2, 1);
+ exynos4_pwm_init(2, clock_count_per_tick);
+ exynos4_pwm_start(2, 1);
break;
case CLOCK_EVT_MODE_ONESHOT:
break;
@@ -149,11 +149,11 @@ static struct clock_event_device pwm_event_device = {
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.rating = 200,
.shift = 32,
- .set_next_event = s5pv310_pwm_set_next_event,
- .set_mode = s5pv310_pwm_set_mode,
+ .set_next_event = exynos4_pwm_set_next_event,
+ .set_mode = exynos4_pwm_set_mode,
};
-irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
+irqreturn_t exynos4_clock_event_isr(int irq, void *dev_id)
{
struct clock_event_device *evt = &pwm_event_device;
@@ -162,13 +162,13 @@ irqreturn_t s5pv310_clock_event_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct irqaction s5pv310_clock_event_irq = {
+static struct irqaction exynos4_clock_event_irq = {
.name = "pwm_timer2_irq",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = s5pv310_clock_event_isr,
+ .handler = exynos4_clock_event_isr,
};
-static void __init s5pv310_clockevent_init(void)
+static void __init exynos4_clockevent_init(void)
{
unsigned long pclk;
unsigned long clock_rate;
@@ -198,23 +198,39 @@ static void __init s5pv310_clockevent_init(void)
pwm_event_device.cpumask = cpumask_of(0);
clockevents_register_device(&pwm_event_device);
- setup_irq(IRQ_TIMER2, &s5pv310_clock_event_irq);
+ setup_irq(IRQ_TIMER2, &exynos4_clock_event_irq);
}
-static cycle_t s5pv310_pwm4_read(struct clocksource *cs)
+static cycle_t exynos4_pwm4_read(struct clocksource *cs)
{
return (cycle_t) ~__raw_readl(S3C_TIMERREG(0x40));
}
+static void exynos4_pwm4_resume(struct clocksource *cs)
+{
+ unsigned long pclk;
+
+ pclk = clk_get_rate(timerclk);
+
+ clk_set_rate(tdiv4, pclk / 2);
+ clk_set_parent(tin4, tdiv4);
+
+ exynos4_pwm_init(4, ~0);
+ exynos4_pwm_start(4, 1);
+}
+
struct clocksource pwm_clocksource = {
.name = "pwm_timer4",
.rating = 250,
- .read = s5pv310_pwm4_read,
+ .read = exynos4_pwm4_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS ,
+#ifdef CONFIG_PM
+ .resume = exynos4_pwm4_resume,
+#endif
};
-static void __init s5pv310_clocksource_init(void)
+static void __init exynos4_clocksource_init(void)
{
unsigned long pclk;
unsigned long clock_rate;
@@ -226,14 +242,14 @@ static void __init s5pv310_clocksource_init(void)
clock_rate = clk_get_rate(tin4);
- s5pv310_pwm_init(4, ~0);
- s5pv310_pwm_start(4, 1);
+ exynos4_pwm_init(4, ~0);
+ exynos4_pwm_start(4, 1);
if (clocksource_register_hz(&pwm_clocksource, clock_rate))
panic("%s: can't register clocksource\n", pwm_clocksource.name);
}
-static void __init s5pv310_timer_resources(void)
+static void __init exynos4_timer_resources(void)
{
struct platform_device tmpdev;
@@ -267,17 +283,17 @@ static void __init s5pv310_timer_resources(void)
clk_enable(tin4);
}
-static void __init s5pv310_timer_init(void)
+static void __init exynos4_timer_init(void)
{
#ifdef CONFIG_LOCAL_TIMERS
twd_base = S5P_VA_TWD;
#endif
- s5pv310_timer_resources();
- s5pv310_clockevent_init();
- s5pv310_clocksource_init();
+ exynos4_timer_resources();
+ exynos4_clockevent_init();
+ exynos4_clocksource_init();
}
-struct sys_timer s5pv310_timer = {
- .init = s5pv310_timer_init,
+struct sys_timer exynos4_timer = {
+ .init = exynos4_timer_init,
};
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 56684b517070..5eec099e0c72 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -100,6 +100,7 @@ config MACH_MX25_3DS
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMXDI_RTC
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_FB
select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
@@ -238,6 +239,7 @@ config MACH_MX27_3DS
select SOC_IMX27
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_MXC_EHCI
@@ -265,6 +267,7 @@ config MACH_IMX27LITE
bool "LogicPD MX27 LITEKIT platform"
select SOC_IMX27
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX_SSI
help
Include support for MX27 LITEKIT platform. This includes specific
configurations for the board and its peripherals.
@@ -300,4 +303,13 @@ config MACH_MXT_TD60
Include support for i-MXT (aka td60) platform. This
includes specific configurations for the module and its peripherals.
+config MACH_IMX27IPCAM
+ bool "IMX27 IPCAM platform"
+ select SOC_IMX27
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Include support for IMX27 IPCAM platform. This includes specific
+ configurations for the board and its peripherals.
+
endif
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 77100bf26153..b85794d27991 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -9,10 +9,10 @@ obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o
obj-$(CONFIG_ARCH_MX1) += clock-imx1.o mm-imx1.o
obj-$(CONFIG_MACH_MX21) += clock-imx21.o mm-imx21.o
-obj-$(CONFIG_ARCH_MX25) += clock-imx25.o mm-imx25.o
+obj-$(CONFIG_ARCH_MX25) += clock-imx25.o mm-imx25.o ehci-imx25.o
obj-$(CONFIG_MACH_MX27) += cpu-imx27.o pm-imx27.o
-obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o
+obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
# Support for CMOS sensor interface
obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
@@ -36,3 +36,4 @@ obj-$(CONFIG_MACH_CPUIMX27) += mach-cpuimx27.o
obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
obj-$(CONFIG_MACH_MXT_TD60) += mach-mxt_td60.o
+obj-$(CONFIG_MACH_IMX27IPCAM) += mach-imx27ipcam.o
diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c
index 3938a563b280..dcc41728fe72 100644
--- a/arch/arm/mach-imx/clock-imx1.c
+++ b/arch/arm/mach-imx/clock-imx1.c
@@ -592,6 +592,7 @@ static struct clk_lookup lookups[] __initdata = {
_REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
_REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
+ _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk)
_REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk)
_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
_REGISTER_CLOCK(NULL, "mshc", mshc_clk)
diff --git a/arch/arm/mach-imx/clock-imx25.c b/arch/arm/mach-imx/clock-imx25.c
index daa0165b6772..a65838fc061c 100644
--- a/arch/arm/mach-imx/clock-imx25.c
+++ b/arch/arm/mach-imx/clock-imx25.c
@@ -228,6 +228,7 @@ DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0, 3, get_rate_esdhc1, NULL,
DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2, NULL, NULL);
DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0, 4, get_rate_esdhc2, NULL,
&esdhc2_ahb_clk);
+DEFINE_CLOCK(sdma_ahb_clk, 0, CCM_CGCR0, 26, NULL, NULL, NULL);
DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL, NULL, NULL);
DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL, NULL, NULL);
DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0, 7, NULL, NULL, &lcdc_ahb_clk);
@@ -253,6 +254,7 @@ DEFINE_CLOCK(lcdc_clk, 0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk);
DEFINE_CLOCK(wdt_clk, 0, CCM_CGCR2, 19, get_rate_ipg, NULL, NULL);
DEFINE_CLOCK(ssi1_clk, 0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk);
DEFINE_CLOCK(ssi2_clk, 1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk);
+DEFINE_CLOCK(sdma_clk, 0, CCM_CGCR2, 6, get_rate_ipg, NULL, &sdma_ahb_clk);
DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGCR1, 13, get_rate_esdhc1, NULL,
&esdhc1_per_clk);
DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGCR1, 14, get_rate_esdhc2, NULL,
@@ -304,6 +306,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
_REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
_REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
+ _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
};
int __init mx25_clocks_init(void)
diff --git a/arch/arm/mach-imx/devices-imx1.h b/arch/arm/mach-imx/devices-imx1.h
index 81979486218e..da593657ff3f 100644
--- a/arch/arm/mach-imx/devices-imx1.h
+++ b/arch/arm/mach-imx/devices-imx1.h
@@ -9,6 +9,10 @@
#include <mach/mx1.h>
#include <mach/devices-common.h>
+extern const struct imx_imx_fb_data imx1_imx_fb_data __initconst;
+#define imx1_add_imx_fb(pdata) \
+ imx_add_imx_fb(&imx1_imx_fb_data, pdata)
+
extern const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst;
#define imx1_add_imx_i2c(pdata) \
imx_add_imx_i2c(&imx1_imx_i2c_data, pdata)
@@ -18,3 +22,10 @@ extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst;
imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata)
#define imx1_add_imx_uart0(pdata) imx1_add_imx_uart(0, pdata)
#define imx1_add_imx_uart1(pdata) imx1_add_imx_uart(1, pdata)
+
+extern const struct imx_spi_imx_data imx1_cspi_data[] __initconst;
+#define imx1_add_cspi(id, pdata) \
+ imx_add_spi_imx(&imx1_cspi_data[id], pdata)
+
+#define imx1_add_spi_imx0(pdata) imx1_add_cspi(0, pdata)
+#define imx1_add_spi_imx1(pdata) imx1_add_cspi(1, pdata)
diff --git a/arch/arm/mach-imx/devices-imx25.h b/arch/arm/mach-imx/devices-imx25.h
index bde33caf1b90..b591d72f6037 100644
--- a/arch/arm/mach-imx/devices-imx25.h
+++ b/arch/arm/mach-imx/devices-imx25.h
@@ -81,7 +81,11 @@ imx25_sdhci_esdhc_imx_data[] __initconst;
extern const struct imx_spi_imx_data imx25_cspi_data[] __initconst;
#define imx25_add_spi_imx(id, pdata) \
- imx_add_spi_imx(&imx25_spi_imx_data[id], pdata)
+ imx_add_spi_imx(&imx25_cspi_data[id], pdata)
#define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata)
#define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata)
#define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata)
+
+extern struct imx_mxc_pwm_data imx25_mxc_pwm_data[] __initconst;
+#define imx25_add_mxc_pwm(id) \
+ imx_add_mxc_pwm(&imx25_mxc_pwm_data[id])
diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c
index e9f1769b49f5..236f1495efad 100644
--- a/arch/arm/mach-imx/dma-v1.c
+++ b/arch/arm/mach-imx/dma-v1.c
@@ -699,7 +699,7 @@ int imx_dma_request(int channel, const char *name)
local_irq_restore(flags);
return -EBUSY;
}
- memset(imxdma, 0, sizeof(imxdma));
+ memset(imxdma, 0, sizeof(*imxdma));
imxdma->name = name;
local_irq_restore(flags); /* request_irq() can block */
diff --git a/arch/arm/mach-imx/ehci-imx25.c b/arch/arm/mach-imx/ehci-imx25.c
new file mode 100644
index 000000000000..865daf0b09e9
--- /dev/null
+++ b/arch/arm/mach-imx/ehci-imx25.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/mxc_ehci.h>
+
+#define USBCTRL_OTGBASE_OFFSET 0x600
+
+#define MX25_OTG_SIC_SHIFT 29
+#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT)
+#define MX25_OTG_PM_BIT (1 << 24)
+
+#define MX25_H1_SIC_SHIFT 21
+#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
+#define MX25_H1_PM_BIT (1 << 8)
+#define MX25_H1_IPPUE_UP_BIT (1 << 7)
+#define MX25_H1_IPPUE_DOWN_BIT (1 << 6)
+#define MX25_H1_TLL_BIT (1 << 5)
+#define MX25_H1_USBTE_BIT (1 << 4)
+
+int mx25_initialize_usb_hw(int port, unsigned int flags)
+{
+ unsigned int v;
+
+ v = readl(MX25_IO_ADDRESS(MX25_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ switch (port) {
+ case 0: /* OTG port */
+ v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX25_OTG_PM_BIT;
+
+ break;
+ case 1: /* H1 port */
+ v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_TLL_BIT |
+ MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT | MX25_H1_IPPUE_UP_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX25_H1_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX25_H1_TLL_BIT;
+
+ if (flags & MXC_EHCI_INTERNAL_PHY)
+ v |= MX25_H1_USBTE_BIT;
+
+ if (flags & MXC_EHCI_IPPUE_DOWN)
+ v |= MX25_H1_IPPUE_DOWN_BIT;
+
+ if (flags & MXC_EHCI_IPPUE_UP)
+ v |= MX25_H1_IPPUE_UP_BIT;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(v, MX25_IO_ADDRESS(MX25_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-imx/ehci-imx27.c b/arch/arm/mach-imx/ehci-imx27.c
new file mode 100644
index 000000000000..fa69419eabdd
--- /dev/null
+++ b/arch/arm/mach-imx/ehci-imx27.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/mxc_ehci.h>
+
+#define USBCTRL_OTGBASE_OFFSET 0x600
+
+#define MX27_OTG_SIC_SHIFT 29
+#define MX27_OTG_SIC_MASK (0x3 << MX27_OTG_SIC_SHIFT)
+#define MX27_OTG_PM_BIT (1 << 24)
+
+#define MX27_H2_SIC_SHIFT 21
+#define MX27_H2_SIC_MASK (0x3 << MX27_H2_SIC_SHIFT)
+#define MX27_H2_PM_BIT (1 << 16)
+#define MX27_H2_DT_BIT (1 << 5)
+
+#define MX27_H1_SIC_SHIFT 13
+#define MX27_H1_SIC_MASK (0x3 << MX27_H1_SIC_SHIFT)
+#define MX27_H1_PM_BIT (1 << 8)
+#define MX27_H1_DT_BIT (1 << 4)
+
+int mx27_initialize_usb_hw(int port, unsigned int flags)
+{
+ unsigned int v;
+
+ v = readl(MX27_IO_ADDRESS(MX27_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ switch (port) {
+ case 0: /* OTG port */
+ v &= ~(MX27_OTG_SIC_MASK | MX27_OTG_PM_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_OTG_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX27_OTG_PM_BIT;
+ break;
+ case 1: /* H1 port */
+ v &= ~(MX27_H1_SIC_MASK | MX27_H1_PM_BIT | MX27_H1_DT_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_H1_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX27_H1_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX27_H1_DT_BIT;
+
+ break;
+ case 2: /* H2 port */
+ v &= ~(MX27_H2_SIC_MASK | MX27_H2_PM_BIT | MX27_H2_DT_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_H2_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX27_H2_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX27_H2_DT_BIT;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(v, MX27_IO_ADDRESS(MX27_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index 275c8589d797..fa5288018ba7 100644
--- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
@@ -249,7 +249,7 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
#define ADS7846_PENDOWN (GPIO_PORTD | 25)
-static void ads7846_dev_init(void)
+static void __maybe_unused ads7846_dev_init(void)
{
if (gpio_request(ADS7846_PENDOWN, "ADS7846 pendown") < 0) {
printk(KERN_ERR "can't get ads746 pen down GPIO\n");
@@ -268,7 +268,8 @@ static struct ads7846_platform_data ads7846_config __initdata = {
.keep_vref_on = 1,
};
-static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
+static struct spi_board_info __maybe_unused
+ eukrea_mbimx27_spi_board_info[] __initdata = {
[0] = {
.modalias = "ads7846",
.bus_num = 0,
@@ -357,13 +358,11 @@ void __init eukrea_mbimx27_baseboard_init(void)
ads7846_dev_init();
#endif
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
/* SPI_CS0 init */
mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
imx27_add_spi_imx0(&eukrea_mbimx27_spi0_data);
spi_register_board_info(eukrea_mbimx27_spi_board_info,
ARRAY_SIZE(eukrea_mbimx27_spi_board_info));
-#endif
/* Leds configuration */
mxc_gpio_mode(GPIO_PORTF | 16 | GPIO_GPIO | GPIO_OUT);
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 6cf04da2456a..759299bb035b 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -209,17 +209,25 @@ static struct platform_device serial_device = {
};
#endif
-#if defined(CONFIG_USB_ULPI)
+static int eukrea_cpuimx27_otg_init(struct platform_device *pdev)
+{
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = eukrea_cpuimx27_otg_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+static int eukrea_cpuimx27_usbh2_init(struct platform_device *pdev)
+{
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
+ .init = eukrea_cpuimx27_usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
-#endif
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -273,21 +281,19 @@ static void __init eukrea_cpuimx27_init(void)
platform_device_register(&serial_device);
#endif
-#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx27_add_mxc_ehci_otg(&otg_pdata);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (otg_pdata.otg)
+ imx27_add_mxc_ehci_otg(&otg_pdata);
+ } else {
+ imx27_add_fsl_usb2_udc(&otg_device_pdata);
}
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
- if (!otg_mode_host)
- imx27_add_fsl_usb2_udc(&otg_device_pdata);
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
#ifdef CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD
eukrea_mbimx27_baseboard_init();
@@ -304,9 +310,10 @@ static struct sys_timer eukrea_cpuimx27_timer = {
};
MACHINE_START(CPUIMX27, "EUKREA CPUIMX27")
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = eukrea_cpuimx27_init,
- .timer = &eukrea_cpuimx27_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &eukrea_cpuimx27_timer,
+ .init_machine = eukrea_cpuimx27_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index eb395aba9237..9da8d18eeb00 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -84,15 +84,25 @@ static struct i2c_board_info eukrea_cpuimx25_i2c_devices[] = {
},
};
+static int eukrea_cpuimx25_otg_init(struct platform_device *pdev)
+{
+ return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static const struct mxc_usbh_platform_data otg_pdata __initconst = {
+ .init = eukrea_cpuimx25_otg_init,
.portsc = MXC_EHCI_MODE_UTMI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+static int eukrea_cpuimx25_usbh2_init(struct platform_device *pdev)
+{
+ return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI |
+ MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN);
+}
+
static const struct mxc_usbh_platform_data usbh2_pdata __initconst = {
+ .init = eukrea_cpuimx25_usbh2_init,
.portsc = MXC_EHCI_MODE_SERIAL,
- .flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
- MXC_EHCI_IPPUE_DOWN,
};
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
@@ -153,9 +163,10 @@ static struct sys_timer eukrea_cpuimx25_timer = {
MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
/* Maintainer: Eukrea Electromatique */
- .boot_params = MX25_PHYS_OFFSET + 0x100,
- .map_io = mx25_map_io,
- .init_irq = mx25_init_irq,
- .init_machine = eukrea_cpuimx25_init,
- .timer = &eukrea_cpuimx25_timer,
+ .boot_params = MX25_PHYS_OFFSET + 0x100,
+ .map_io = mx25_map_io,
+ .init_early = imx25_init_early,
+ .init_irq = mx25_init_irq,
+ .timer = &eukrea_cpuimx25_timer,
+ .init_machine = eukrea_cpuimx25_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index 40a3666ea632..d7e0d219726a 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -30,6 +30,7 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
@@ -66,6 +67,11 @@ static const int visstrim_m10_pins[] __initconst = {
PD15_AOUT_FEC_COL,
PD16_AIN_FEC_TX_ER,
PF23_AIN_FEC_TX_EN,
+ /* SSI1 */
+ PC20_PF_SSI1_FS,
+ PC21_PF_SSI1_RXD,
+ PC22_PF_SSI1_TXD,
+ PC23_PF_SSI1_CLK,
/* SDHC1 */
PE18_PF_SD1_D0,
PE19_PF_SD1_D1,
@@ -204,20 +210,30 @@ static struct i2c_board_info visstrim_m10_i2c_devices[] = {
I2C_BOARD_INFO("pca9555", 0x20),
.platform_data = &visstrim_m10_pca9555_pdata,
},
+ {
+ I2C_BOARD_INFO("tlv320aic32x4", 0x18),
+ }
};
/* USB OTG */
static int otg_phy_init(struct platform_device *pdev)
{
gpio_set_value(OTG_PHY_CS_GPIO, 0);
- return 0;
+
+ mdelay(10);
+
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
}
static const struct mxc_usbh_platform_data
visstrim_m10_usbotg_pdata __initconst = {
.init = otg_phy_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+/* SSI */
+static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
+ .flags = IMX_SSI_DMA | IMX_SSI_SYN,
};
static void __init visstrim_m10_board_init(void)
@@ -229,6 +245,7 @@ static void __init visstrim_m10_board_init(void)
if (ret)
pr_err("Failed to setup pins (%d)\n", ret);
+ imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata);
imx27_add_imx_uart0(&uart_pdata);
i2c_register_board_info(0, visstrim_m10_i2c_devices,
@@ -251,9 +268,10 @@ static struct sys_timer visstrim_m10_timer = {
};
MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = visstrim_m10_board_init,
- .timer = &visstrim_m10_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &visstrim_m10_timer,
+ .init_machine = visstrim_m10_board_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27ipcam.c b/arch/arm/mach-imx/mach-imx27ipcam.c
new file mode 100644
index 000000000000..9be6cd6fbf8c
--- /dev/null
+++ b/arch/arm/mach-imx/mach-imx27ipcam.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx27.h>
+
+#include "devices-imx27.h"
+
+static const int mx27ipcam_pins[] __initconst = {
+ /* UART1 */
+ PE12_PF_UART1_TXD,
+ PE13_PF_UART1_RXD,
+ /* FEC */
+ PD0_AIN_FEC_TXD0,
+ PD1_AIN_FEC_TXD1,
+ PD2_AIN_FEC_TXD2,
+ PD3_AIN_FEC_TXD3,
+ PD4_AOUT_FEC_RX_ER,
+ PD5_AOUT_FEC_RXD1,
+ PD6_AOUT_FEC_RXD2,
+ PD7_AOUT_FEC_RXD3,
+ PD8_AF_FEC_MDIO,
+ PD9_AIN_FEC_MDC,
+ PD10_AOUT_FEC_CRS,
+ PD11_AOUT_FEC_TX_CLK,
+ PD12_AOUT_FEC_RXD0,
+ PD13_AOUT_FEC_RX_DV,
+ PD14_AOUT_FEC_RX_CLK,
+ PD15_AOUT_FEC_COL,
+ PD16_AIN_FEC_TX_ER,
+ PF23_AIN_FEC_TX_EN,
+};
+
+static void __init mx27ipcam_init(void)
+{
+ mxc_gpio_setup_multiple_pins(mx27ipcam_pins, ARRAY_SIZE(mx27ipcam_pins),
+ "mx27ipcam");
+
+ imx27_add_imx_uart0(NULL);
+ imx27_add_fec(NULL);
+ imx27_add_imx2_wdt(NULL);
+}
+
+static void __init mx27ipcam_timer_init(void)
+{
+ mx27_clocks_init(25000000);
+}
+
+static struct sys_timer mx27ipcam_timer = {
+ .init = mx27ipcam_timer_init,
+};
+
+MACHINE_START(IMX27IPCAM, "Freescale IMX27IPCAM")
+ /* maintainer: Freescale Semiconductor, Inc. */
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &mx27ipcam_timer,
+ .init_machine = mx27ipcam_init,
+MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx27lite.c b/arch/arm/mach-imx/mach-imx27lite.c
index 3a1202e47212..841140516ede 100644
--- a/arch/arm/mach-imx/mach-imx27lite.c
+++ b/arch/arm/mach-imx/mach-imx27lite.c
@@ -75,9 +75,10 @@ static struct sys_timer mx27lite_timer = {
};
MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = mx27lite_init,
- .timer = &mx27lite_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &mx27lite_timer,
+ .init_machine = mx27lite_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c
index 1f446e5eb636..47cf56ac6d5b 100644
--- a/arch/arm/mach-imx/mach-mx1ads.c
+++ b/arch/arm/mach-imx/mach-mx1ads.c
@@ -144,17 +144,19 @@ struct sys_timer mx1ads_timer = {
MACHINE_START(MX1ADS, "Freescale MX1ADS")
/* Maintainer: Sascha Hauer, Pengutronix */
- .boot_params = MX1_PHYS_OFFSET + 0x100,
- .map_io = mx1_map_io,
- .init_irq = mx1_init_irq,
- .timer = &mx1ads_timer,
- .init_machine = mx1ads_init,
+ .boot_params = MX1_PHYS_OFFSET + 0x100,
+ .map_io = mx1_map_io,
+ .init_early = imx1_init_early,
+ .init_irq = mx1_init_irq,
+ .timer = &mx1ads_timer,
+ .init_machine = mx1ads_init,
MACHINE_END
MACHINE_START(MXLADS, "Freescale MXLADS")
- .boot_params = MX1_PHYS_OFFSET + 0x100,
- .map_io = mx1_map_io,
- .init_irq = mx1_init_irq,
- .timer = &mx1ads_timer,
- .init_machine = mx1ads_init,
+ .boot_params = MX1_PHYS_OFFSET + 0x100,
+ .map_io = mx1_map_io,
+ .init_early = imx1_init_early,
+ .init_irq = mx1_init_irq,
+ .timer = &mx1ads_timer,
+ .init_machine = mx1ads_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index 0a372577c2ac..fa52a1086eae 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -304,9 +304,10 @@ static struct sys_timer mx21ads_timer = {
MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
/* maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX21_PHYS_OFFSET + 0x100,
- .map_io = mx21ads_map_io,
- .init_irq = mx21_init_irq,
- .init_machine = mx21ads_board_init,
- .timer = &mx21ads_timer,
+ .boot_params = MX21_PHYS_OFFSET + 0x100,
+ .map_io = mx21ads_map_io,
+ .init_early = imx21_init_early,
+ .init_irq = mx21_init_irq,
+ .timer = &mx21ads_timer,
+ .init_machine = mx21ads_board_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c
index 8382e7902078..06da438282aa 100644
--- a/arch/arm/mach-imx/mach-mx25_3ds.c
+++ b/arch/arm/mach-imx/mach-mx25_3ds.c
@@ -103,14 +103,18 @@ static iomux_v3_cfg_t mx25pdk_pads[] = {
MX25_PAD_SD1_DATA1__SD1_DATA1,
MX25_PAD_SD1_DATA2__SD1_DATA2,
MX25_PAD_SD1_DATA3__SD1_DATA3,
+
+ /* I2C1 */
+ MX25_PAD_I2C1_CLK__I2C1_CLK,
+ MX25_PAD_I2C1_DAT__I2C1_DAT,
};
static const struct fec_platform_data mx25_fec_pdata __initconst = {
.phy = PHY_INTERFACE_MODE_RMII,
};
-#define FEC_ENABLE_GPIO 35
-#define FEC_RESET_B_GPIO 104
+#define FEC_ENABLE_GPIO IMX_GPIO_NR(2, 3)
+#define FEC_RESET_B_GPIO IMX_GPIO_NR(4, 8)
static void __init mx25pdk_fec_reset(void)
{
@@ -185,9 +189,14 @@ static const struct matrix_keymap_data mx25pdk_keymap_data __initconst = {
.keymap_size = ARRAY_SIZE(mx25pdk_keymap),
};
+static int mx25pdk_usbh2_init(struct platform_device *pdev)
+{
+ return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY);
+}
+
static const struct mxc_usbh_platform_data usbh2_pdata __initconst = {
+ .init = mx25pdk_usbh2_init,
.portsc = MXC_EHCI_MODE_SERIAL,
- .flags = MXC_EHCI_INTERNAL_PHY,
};
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
@@ -195,6 +204,10 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.phy_mode = FSL_USB2_PHY_UTMI,
};
+static const struct imxi2c_platform_data mx25_3ds_i2c0_data __initconst = {
+ .bitrate = 100000,
+};
+
static void __init mx25pdk_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
@@ -213,6 +226,7 @@ static void __init mx25pdk_init(void)
imx25_add_imx_keypad(&mx25pdk_keymap_data);
imx25_add_sdhci_esdhc_imx(0, NULL);
+ imx25_add_imx_i2c0(&mx25_3ds_i2c0_data);
}
static void __init mx25pdk_timer_init(void)
@@ -226,10 +240,10 @@ static struct sys_timer mx25pdk_timer = {
MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)")
/* Maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX25_PHYS_OFFSET + 0x100,
- .map_io = mx25_map_io,
- .init_irq = mx25_init_irq,
- .init_machine = mx25pdk_init,
- .timer = &mx25pdk_timer,
+ .boot_params = MX25_PHYS_OFFSET + 0x100,
+ .map_io = mx25_map_io,
+ .init_early = imx25_init_early,
+ .init_irq = mx25_init_irq,
+ .timer = &mx25pdk_timer,
+ .init_machine = mx25pdk_init,
MACHINE_END
-
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 164331518bdd..614b3c00c4a0 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -98,6 +98,9 @@ static const int mx27pdk_pins[] __initconst = {
PD22_PF_CSPI2_SCLK,
PD23_PF_CSPI2_MISO,
PD24_PF_CSPI2_MOSI,
+ /* I2C1 */
+ PD17_PF_I2C_DATA,
+ PD18_PF_I2C_CLK,
};
static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -159,13 +162,15 @@ static int otg_phy_init(void)
return 0;
}
-#if defined(CONFIG_USB_ULPI)
+static int mx27_3ds_otg_init(struct platform_device *pdev)
+{
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = mx27_3ds_otg_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
-#endif
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -216,7 +221,7 @@ static struct regulator_init_data vgen_init = {
.consumer_supplies = vgen_consumers,
};
-static struct mc13783_regulator_init_data mx27_3ds_regulators[] = {
+static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = {
{
.id = MC13783_REG_VMMC1,
.init_data = &vmmc1_init,
@@ -227,10 +232,10 @@ static struct mc13783_regulator_init_data mx27_3ds_regulators[] = {
};
/* MC13783 */
-static struct mc13783_platform_data mc13783_pdata __initdata = {
+static struct mc13xxx_platform_data mc13783_pdata __initdata = {
.regulators = mx27_3ds_regulators,
.num_regulators = ARRAY_SIZE(mx27_3ds_regulators),
- .flags = MC13783_USE_REGULATOR,
+ .flags = MC13XXX_USE_REGULATOR,
};
/* SPI */
@@ -253,6 +258,9 @@ static struct spi_board_info mx27_3ds_spi_devs[] __initdata = {
},
};
+static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = {
+ .bitrate = 100000,
+};
static void __init mx27pdk_init(void)
{
@@ -265,14 +273,15 @@ static void __init mx27pdk_init(void)
imx27_add_mxc_mmc(0, &sdhc1_pdata);
imx27_add_imx2_wdt(NULL);
otg_phy_init();
-#if defined(CONFIG_USB_ULPI)
+
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
- imx27_add_mxc_ehci_otg(&otg_pdata);
+ if (otg_pdata.otg)
+ imx27_add_mxc_ehci_otg(&otg_pdata);
}
-#endif
+
if (!otg_mode_host)
imx27_add_fsl_usb2_udc(&otg_device_pdata);
@@ -282,6 +291,7 @@ static void __init mx27pdk_init(void)
if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT))
pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n");
+ imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data);
}
static void __init mx27pdk_timer_init(void)
@@ -295,9 +305,10 @@ static struct sys_timer mx27pdk_timer = {
MACHINE_START(MX27_3DS, "Freescale MX27PDK")
/* maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = mx27pdk_init,
- .timer = &mx27pdk_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &mx27pdk_timer,
+ .init_machine = mx27pdk_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c
index b832f960fec4..367d1e4384c7 100644
--- a/arch/arm/mach-imx/mach-mx27ads.c
+++ b/arch/arm/mach-imx/mach-mx27ads.c
@@ -344,9 +344,10 @@ static void __init mx27ads_map_io(void)
MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
/* maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27ads_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = mx27ads_board_init,
- .timer = &mx27ads_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27ads_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &mx27ads_timer,
+ .init_machine = mx27ads_board_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-mxt_td60.c b/arch/arm/mach-imx/mach-mxt_td60.c
index 4ce71b0401db..69787c30c320 100644
--- a/arch/arm/mach-imx/mach-mxt_td60.c
+++ b/arch/arm/mach-imx/mach-mxt_td60.c
@@ -266,10 +266,10 @@ static struct sys_timer mxt_td60_timer = {
MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
/* maintainer: Maxtrack Industrial */
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = mxt_td60_board_init,
- .timer = &mxt_td60_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &mxt_td60_timer,
+ .init_machine = mxt_td60_board_init,
MACHINE_END
-
diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c
index cccc0a0a9c72..63e182556778 100644
--- a/arch/arm/mach-imx/mach-pca100.c
+++ b/arch/arm/mach-imx/mach-pca100.c
@@ -187,7 +187,6 @@ static struct i2c_board_info pca100_i2c_devices[] = {
}
};
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
static struct spi_eeprom at25320 = {
.name = "at25320an",
.byte_len = 4096,
@@ -211,7 +210,6 @@ static const struct spi_imx_master pca100_spi0_data __initconst = {
.chipselect = pca100_spi_cs,
.num_chipselect = ARRAY_SIZE(pca100_spi_cs),
};
-#endif
static void pca100_ac97_warm_reset(struct snd_ac97 *ac97)
{
@@ -269,31 +267,33 @@ static const struct imxmmc_platform_data sdhc_pdata __initconst = {
.exit = pca100_sdhc2_exit,
};
-#if defined(CONFIG_USB_ULPI)
static int otg_phy_init(struct platform_device *pdev)
{
gpio_set_value(OTG_PHY_CS_GPIO, 0);
- return 0;
+
+ mdelay(10);
+
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
}
static struct mxc_usbh_platform_data otg_pdata __initdata = {
.init = otg_phy_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
static int usbh2_phy_init(struct platform_device *pdev)
{
gpio_set_value(USBH2_PHY_CS_GPIO, 0);
- return 0;
+
+ mdelay(10);
+
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
}
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
.init = usbh2_phy_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
-#endif
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -389,36 +389,33 @@ static void __init pca100_init(void)
imx27_add_imx_i2c(1, &pca100_i2c1_data);
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN);
mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN);
spi_register_board_info(pca100_spi_board_info,
ARRAY_SIZE(pca100_spi_board_info));
imx27_add_spi_imx0(&pca100_spi0_data);
-#endif
gpio_request(OTG_PHY_CS_GPIO, "usb-otg-cs");
gpio_direction_output(OTG_PHY_CS_GPIO, 1);
gpio_request(USBH2_PHY_CS_GPIO, "usb-host2-cs");
gpio_direction_output(USBH2_PHY_CS_GPIO, 1);
-#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
- imx27_add_mxc_ehci_otg(&otg_pdata);
+ if (otg_pdata.otg)
+ imx27_add_mxc_ehci_otg(&otg_pdata);
+ } else {
+ gpio_set_value(OTG_PHY_CS_GPIO, 0);
+ imx27_add_fsl_usb2_udc(&otg_device_pdata);
}
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
- imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
- if (!otg_mode_host) {
- gpio_set_value(OTG_PHY_CS_GPIO, 0);
- imx27_add_fsl_usb2_udc(&otg_device_pdata);
- }
+ if (usbh2_pdata.otg)
+ imx27_add_mxc_ehci_hs(2, &usbh2_pdata);
imx27_add_imx_fb(&pca100_fb_data);
@@ -437,10 +434,10 @@ static struct sys_timer pca100_timer = {
};
MACHINE_START(PCA100, "phyCARD-i.MX27")
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = pca100_init,
- .timer = &pca100_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .init_machine = pca100_init,
+ .timer = &pca100_timer,
MACHINE_END
-
diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c
index 505614803bc6..38c77084b615 100644
--- a/arch/arm/mach-imx/mach-pcm038.c
+++ b/arch/arm/mach-imx/mach-pcm038.c
@@ -252,7 +252,7 @@ static struct regulator_init_data cam_data = {
.consumer_supplies = cam_consumers,
};
-static struct mc13783_regulator_init_data pcm038_regulators[] = {
+static struct mc13xxx_regulator_init_data pcm038_regulators[] = {
{
.id = MC13783_REG_VCAM,
.init_data = &cam_data,
@@ -262,11 +262,11 @@ static struct mc13783_regulator_init_data pcm038_regulators[] = {
},
};
-static struct mc13783_platform_data pcm038_pmic = {
+static struct mc13xxx_platform_data pcm038_pmic = {
.regulators = pcm038_regulators,
.num_regulators = ARRAY_SIZE(pcm038_regulators),
- .flags = MC13783_USE_ADC | MC13783_USE_REGULATOR |
- MC13783_USE_TOUCHSCREEN,
+ .flags = MC13XXX_USE_ADC | MC13XXX_USE_REGULATOR |
+ MC13XXX_USE_TOUCHSCREEN,
};
static struct spi_board_info pcm038_spi_board_info[] __initdata = {
@@ -281,9 +281,15 @@ static struct spi_board_info pcm038_spi_board_info[] __initdata = {
}
};
+static int pcm038_usbh2_init(struct platform_device *pdev)
+{
+ return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static const struct mxc_usbh_platform_data usbh2_pdata __initconst = {
+ .init = pcm038_usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_DIFF_UNI,
};
static void __init pcm038_init(void)
@@ -340,9 +346,10 @@ static struct sys_timer pcm038_timer = {
};
MACHINE_START(PCM038, "phyCORE-i.MX27")
- .boot_params = MX27_PHYS_OFFSET + 0x100,
- .map_io = mx27_map_io,
- .init_irq = mx27_init_irq,
- .init_machine = pcm038_init,
- .timer = &pcm038_timer,
+ .boot_params = MX27_PHYS_OFFSET + 0x100,
+ .map_io = mx27_map_io,
+ .init_early = imx27_init_early,
+ .init_irq = mx27_init_irq,
+ .timer = &pcm038_timer,
+ .init_machine = pcm038_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-scb9328.c b/arch/arm/mach-imx/mach-scb9328.c
index eae878f306c6..dcaee043628e 100644
--- a/arch/arm/mach-imx/mach-scb9328.c
+++ b/arch/arm/mach-imx/mach-scb9328.c
@@ -145,10 +145,11 @@ static struct sys_timer scb9328_timer = {
};
MACHINE_START(SCB9328, "Synertronixx scb9328")
- /* Sascha Hauer */
- .boot_params = 0x08000100,
- .map_io = mx1_map_io,
- .init_irq = mx1_init_irq,
- .timer = &scb9328_timer,
- .init_machine = scb9328_init,
+ /* Sascha Hauer */
+ .boot_params = 0x08000100,
+ .map_io = mx1_map_io,
+ .init_early = imx1_init_early,
+ .init_irq = mx1_init_irq,
+ .timer = &scb9328_timer,
+ .init_machine = scb9328_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c
index 729ae0915af8..2e482ba5a0e7 100644
--- a/arch/arm/mach-imx/mm-imx1.c
+++ b/arch/arm/mach-imx/mm-imx1.c
@@ -23,6 +23,9 @@
#include <mach/common.h>
#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <mach/iomux-v1.h>
static struct map_desc imx_io_desc[] __initdata = {
imx_map_entry(MX1, IO, MT_DEVICE),
@@ -30,16 +33,26 @@ static struct map_desc imx_io_desc[] __initdata = {
void __init mx1_map_io(void)
{
+ iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
+}
+
+void __init imx1_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX1);
mxc_arch_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR));
-
- iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
+ imx_iomuxv1_init(MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR),
+ MX1_NUM_GPIO_PORT);
}
-int imx1_register_gpios(void);
+static struct mxc_gpio_port imx1_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX1, 0, 1, MX1_GPIO_INT_PORTA),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX1, 1, 2, MX1_GPIO_INT_PORTB),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX1, 2, 3, MX1_GPIO_INT_PORTC),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX1, 3, 4, MX1_GPIO_INT_PORTD),
+};
void __init mx1_init_irq(void)
{
mxc_init_irq(MX1_IO_ADDRESS(MX1_AVIC_BASE_ADDR));
- imx1_register_gpios();
+ mxc_gpio_init(imx1_gpio_ports, ARRAY_SIZE(imx1_gpio_ports));
}
diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c
index e728af81d1b1..7a0c500ac2c8 100644
--- a/arch/arm/mach-imx/mm-imx21.c
+++ b/arch/arm/mach-imx/mm-imx21.c
@@ -24,6 +24,9 @@
#include <mach/common.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <mach/iomux-v1.h>
/* MX21 memory map definition */
static struct map_desc imx21_io_desc[] __initdata = {
@@ -56,16 +59,28 @@ static struct map_desc imx21_io_desc[] __initdata = {
*/
void __init mx21_map_io(void)
{
+ iotable_init(imx21_io_desc, ARRAY_SIZE(imx21_io_desc));
+}
+
+void __init imx21_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX21);
mxc_arch_reset_init(MX21_IO_ADDRESS(MX21_WDOG_BASE_ADDR));
-
- iotable_init(imx21_io_desc, ARRAY_SIZE(imx21_io_desc));
+ imx_iomuxv1_init(MX21_IO_ADDRESS(MX21_GPIO_BASE_ADDR),
+ MX21_NUM_GPIO_PORT);
}
-int imx21_register_gpios(void);
+static struct mxc_gpio_port imx21_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX21, 0, 1, MX21_INT_GPIO),
+ DEFINE_IMX_GPIO_PORT(MX21, 1, 2),
+ DEFINE_IMX_GPIO_PORT(MX21, 2, 3),
+ DEFINE_IMX_GPIO_PORT(MX21, 3, 4),
+ DEFINE_IMX_GPIO_PORT(MX21, 4, 5),
+ DEFINE_IMX_GPIO_PORT(MX21, 5, 6),
+};
void __init mx21_init_irq(void)
{
mxc_init_irq(MX21_IO_ADDRESS(MX21_AVIC_BASE_ADDR));
- imx21_register_gpios();
+ mxc_gpio_init(imx21_gpio_ports, ARRAY_SIZE(imx21_gpio_ports));
}
diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c
index 2edec6ce8fe7..02f7b5c7fa8e 100644
--- a/arch/arm/mach-imx/mm-imx25.c
+++ b/arch/arm/mach-imx/mm-imx25.c
@@ -27,6 +27,8 @@
#include <mach/hardware.h>
#include <mach/mx25.h>
#include <mach/iomux-v3.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
/*
* This table defines static virtual address mappings for I/O regions.
@@ -45,18 +47,26 @@ static struct map_desc mx25_io_desc[] __initdata = {
*/
void __init mx25_map_io(void)
{
+ iotable_init(mx25_io_desc, ARRAY_SIZE(mx25_io_desc));
+}
+
+void __init imx25_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX25);
mxc_iomux_v3_init(MX25_IO_ADDRESS(MX25_IOMUXC_BASE_ADDR));
mxc_arch_reset_init(MX25_IO_ADDRESS(MX25_WDOG_BASE_ADDR));
-
- iotable_init(mx25_io_desc, ARRAY_SIZE(mx25_io_desc));
}
-int imx25_register_gpios(void);
+static struct mxc_gpio_port imx25_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX25, 0, 1, MX25_INT_GPIO1),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX25, 1, 2, MX25_INT_GPIO2),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX25, 2, 3, MX25_INT_GPIO3),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX25, 3, 4, MX25_INT_GPIO4),
+};
void __init mx25_init_irq(void)
{
mxc_init_irq(MX25_IO_ADDRESS(MX25_AVIC_BASE_ADDR));
- imx25_register_gpios();
+ mxc_gpio_init(imx25_gpio_ports, ARRAY_SIZE(imx25_gpio_ports));
}
diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c
index 374e48b7a412..a6761a39f08c 100644
--- a/arch/arm/mach-imx/mm-imx27.c
+++ b/arch/arm/mach-imx/mm-imx27.c
@@ -24,6 +24,9 @@
#include <mach/common.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <mach/iomux-v1.h>
/* MX27 memory map definition */
static struct map_desc imx27_io_desc[] __initdata = {
@@ -56,16 +59,28 @@ static struct map_desc imx27_io_desc[] __initdata = {
*/
void __init mx27_map_io(void)
{
+ iotable_init(imx27_io_desc, ARRAY_SIZE(imx27_io_desc));
+}
+
+void __init imx27_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX27);
mxc_arch_reset_init(MX27_IO_ADDRESS(MX27_WDOG_BASE_ADDR));
-
- iotable_init(imx27_io_desc, ARRAY_SIZE(imx27_io_desc));
+ imx_iomuxv1_init(MX27_IO_ADDRESS(MX27_GPIO_BASE_ADDR),
+ MX27_NUM_GPIO_PORT);
}
-int imx27_register_gpios(void);
+static struct mxc_gpio_port imx27_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX27, 0, 1, MX27_INT_GPIO),
+ DEFINE_IMX_GPIO_PORT(MX27, 1, 2),
+ DEFINE_IMX_GPIO_PORT(MX27, 2, 3),
+ DEFINE_IMX_GPIO_PORT(MX27, 3, 4),
+ DEFINE_IMX_GPIO_PORT(MX27, 4, 5),
+ DEFINE_IMX_GPIO_PORT(MX27, 5, 6),
+};
void __init mx27_init_irq(void)
{
mxc_init_irq(MX27_IO_ADDRESS(MX27_AVIC_BASE_ADDR));
- imx27_register_gpios();
+ mxc_gpio_init(imx27_gpio_ports, ARRAY_SIZE(imx27_gpio_ports));
}
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 3688123b5ad8..20e71df3e3bb 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -21,6 +21,7 @@
#include <net/dsa.h>
#include <asm/page.h>
#include <asm/timex.h>
+#include <asm/kexec.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <mach/kirkwood.h>
@@ -846,9 +847,14 @@ static void __init kirkwood_wdt_init(void)
/*****************************************************************************
* Time handling
****************************************************************************/
+void __init kirkwood_init_early(void)
+{
+ orion_time_set_base(TIMER_VIRT_BASE);
+}
+
int kirkwood_tclk;
-int __init kirkwood_find_tclk(void)
+static int __init kirkwood_find_tclk(void)
{
u32 dev, rev;
@@ -864,7 +870,9 @@ int __init kirkwood_find_tclk(void)
static void __init kirkwood_timer_init(void)
{
kirkwood_tclk = kirkwood_find_tclk();
- orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
+
+ orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
+ IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
}
struct sys_timer kirkwood_timer = {
@@ -1003,6 +1011,10 @@ void __init kirkwood_init(void)
kirkwood_xor0_init();
kirkwood_xor1_init();
kirkwood_crypto_init();
+
+#ifdef CONFIG_KEXEC
+ kexec_reinit = kirkwood_enable_pcie;
+#endif
}
static int __init kirkwood_clock_gate(void)
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 95bb0a73adfb..b9b0f0968a36 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -27,11 +27,13 @@ struct kirkwood_asoc_platform_data;
*/
void kirkwood_map_io(void);
void kirkwood_init(void);
+void kirkwood_init_early(void);
void kirkwood_init_irq(void);
extern struct mbus_dram_target_info kirkwood_mbus_dram_info;
void kirkwood_setup_cpu_mbus(void);
+void kirkwood_enable_pcie(void);
void kirkwood_pcie_id(u32 *dev, u32 *rev);
void kirkwood_ehci_init(void);
diff --git a/arch/arm/mach-kirkwood/d2net_v2-setup.c b/arch/arm/mach-kirkwood/d2net_v2-setup.c
index a31c9499ab36..043cfd5e140b 100644
--- a/arch/arm/mach-kirkwood/d2net_v2-setup.c
+++ b/arch/arm/mach-kirkwood/d2net_v2-setup.c
@@ -224,6 +224,7 @@ MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
.boot_params = 0x00000100,
.init_machine = d2net_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
index 9ea71182d31a..bff04e04d679 100644
--- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
+++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
@@ -100,6 +100,7 @@ MACHINE_START(DB88F6281_BP, "Marvell DB-88F6281-BP Development Board")
.boot_params = 0x00000100,
.init_machine = db88f6281_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/dockstar-setup.c b/arch/arm/mach-kirkwood/dockstar-setup.c
index 433ea368c060..f14dfb8508c5 100644
--- a/arch/arm/mach-kirkwood/dockstar-setup.c
+++ b/arch/arm/mach-kirkwood/dockstar-setup.c
@@ -105,6 +105,7 @@ MACHINE_START(DOCKSTAR, "Seagate FreeAgent DockStar")
.boot_params = 0x00000100,
.init_machine = dockstar_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c
index 8f47dc0a2fef..41d1b40696a3 100644
--- a/arch/arm/mach-kirkwood/guruplug-setup.c
+++ b/arch/arm/mach-kirkwood/guruplug-setup.c
@@ -124,6 +124,7 @@ MACHINE_START(GURUPLUG, "Marvell GuruPlug Reference Board")
.boot_params = 0x00000100,
.init_machine = guruplug_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
index aff0e1327e38..957bd7997d7e 100644
--- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
+++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
@@ -29,9 +29,6 @@
#define BRIDGE_CAUSE (BRIDGE_VIRT_BASE | 0x0110)
#define WDT_INT_REQ 0x0008
-#define BRIDGE_MASK (BRIDGE_VIRT_BASE | 0x0114)
-#define BRIDGE_INT_TIMER0 0x0002
-#define BRIDGE_INT_TIMER1 0x0004
#define BRIDGE_INT_TIMER1_CLR (~0x0004)
#define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0200)
diff --git a/arch/arm/mach-kirkwood/include/mach/gpio.h b/arch/arm/mach-kirkwood/include/mach/gpio.h
index 81b335eb62ec..84f340b546c0 100644
--- a/arch/arm/mach-kirkwood/include/mach/gpio.h
+++ b/arch/arm/mach-kirkwood/include/mach/gpio.h
@@ -6,33 +6,4 @@
* warranty of any kind, whether express or implied.
*/
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <mach/irqs.h>
#include <plat/gpio.h>
-#include <asm-generic/gpio.h> /* cansleep wrappers */
-
-#define GPIO_MAX 50
-#define GPIO_OFF(pin) (((pin) >> 5) ? 0x0140 : 0x0100)
-#define GPIO_OUT(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x00)
-#define GPIO_IO_CONF(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x04)
-#define GPIO_BLINK_EN(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x08)
-#define GPIO_IN_POL(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x0c)
-#define GPIO_DATA_IN(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x10)
-#define GPIO_EDGE_CAUSE(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x14)
-#define GPIO_EDGE_MASK(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x18)
-#define GPIO_LEVEL_MASK(pin) (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x1c)
-
-static inline int gpio_to_irq(int pin)
-{
- return pin + IRQ_KIRKWOOD_GPIO_START;
-}
-
-static inline int irq_to_gpio(int irq)
-{
- return irq - IRQ_KIRKWOOD_GPIO_START;
-}
-
-
-#endif
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index 6e924b398919..010bdeb4ac5f 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -69,6 +69,8 @@
#define DEV_BUS_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x10000)
#define SAMPLE_AT_RESET (DEV_BUS_VIRT_BASE | 0x0030)
#define DEVICE_ID (DEV_BUS_VIRT_BASE | 0x0034)
+#define GPIO_LOW_VIRT_BASE (DEV_BUS_VIRT_BASE | 0x0100)
+#define GPIO_HIGH_VIRT_BASE (DEV_BUS_VIRT_BASE | 0x0140)
#define RTC_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x0300)
#define SPI_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x0600)
#define I2C_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x1000)
diff --git a/arch/arm/mach-kirkwood/irq.c b/arch/arm/mach-kirkwood/irq.c
index 28020abf49e1..cbdb5863d13b 100644
--- a/arch/arm/mach-kirkwood/irq.c
+++ b/arch/arm/mach-kirkwood/irq.c
@@ -27,31 +27,21 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
void __init kirkwood_init_irq(void)
{
- int i;
-
orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
/*
- * Mask and clear GPIO IRQ interrupts.
+ * Initialize gpiolib for GPIOs 0-49.
*/
- writel(0, GPIO_LEVEL_MASK(0));
- writel(0, GPIO_EDGE_MASK(0));
- writel(0, GPIO_EDGE_CAUSE(0));
- writel(0, GPIO_LEVEL_MASK(32));
- writel(0, GPIO_EDGE_MASK(32));
- writel(0, GPIO_EDGE_CAUSE(32));
-
- for (i = IRQ_KIRKWOOD_GPIO_START; i < NR_IRQS; i++) {
- set_irq_chip(i, &orion_gpio_irq_chip);
- set_irq_handler(i, handle_level_irq);
- irq_desc[i].status |= IRQ_LEVEL;
- set_irq_flags(i, IRQF_VALID);
- }
+ orion_gpio_init(0, 32, GPIO_LOW_VIRT_BASE, 0,
+ IRQ_KIRKWOOD_GPIO_START);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_0_7, gpio_irq_handler);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_8_15, gpio_irq_handler);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_16_23, gpio_irq_handler);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_24_31, gpio_irq_handler);
+
+ orion_gpio_init(32, 18, GPIO_HIGH_VIRT_BASE, 0,
+ IRQ_KIRKWOOD_GPIO_START + 32);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_0_7, gpio_irq_handler);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_8_15, gpio_irq_handler);
set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_16_23, gpio_irq_handler);
diff --git a/arch/arm/mach-kirkwood/mpp.c b/arch/arm/mach-kirkwood/mpp.c
index 27901f702feb..7ce201848067 100644
--- a/arch/arm/mach-kirkwood/mpp.c
+++ b/arch/arm/mach-kirkwood/mpp.c
@@ -49,9 +49,6 @@ void __init kirkwood_mpp_conf(unsigned int *mpp_list)
if (!variant_mask)
return;
- /* Initialize gpiolib. */
- orion_gpio_init();
-
printk(KERN_DEBUG "initial MPP regs:");
for (i = 0; i < MPP_NR_REGS; i++) {
mpp_ctrl[i] = readl(MPP_CTRL(i));
diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
index 1e5266f57e2a..00cca22eca6f 100644
--- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
+++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
@@ -166,6 +166,7 @@ MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board")
.boot_params = 0x00000100,
.init_machine = mv88f6281gtw_ge_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/netspace_v2-setup.c b/arch/arm/mach-kirkwood/netspace_v2-setup.c
index 65ee21fd2f3b..7cdab5776452 100644
--- a/arch/arm/mach-kirkwood/netspace_v2-setup.c
+++ b/arch/arm/mach-kirkwood/netspace_v2-setup.c
@@ -261,6 +261,7 @@ MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
.boot_params = 0x00000100,
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -271,6 +272,7 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
.boot_params = 0x00000100,
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -281,6 +283,7 @@ MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
.boot_params = 0x00000100,
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/netxbig_v2-setup.c b/arch/arm/mach-kirkwood/netxbig_v2-setup.c
index 93afd3c8bfd8..6be627deb0fc 100644
--- a/arch/arm/mach-kirkwood/netxbig_v2-setup.c
+++ b/arch/arm/mach-kirkwood/netxbig_v2-setup.c
@@ -402,6 +402,7 @@ MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
.boot_params = 0x00000100,
.init_machine = netxbig_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -412,6 +413,7 @@ MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
.boot_params = 0x00000100,
.init_machine = netxbig_v2_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index cfcca4174e25..f69beeff4450 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -217,6 +217,7 @@ MACHINE_START(OPENRD_BASE, "Marvell OpenRD Base Board")
.boot_params = 0x00000100,
.init_machine = openrd_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -228,6 +229,7 @@ MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
.boot_params = 0x00000100,
.init_machine = openrd_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -239,6 +241,7 @@ MACHINE_START(OPENRD_ULTIMATE, "Marvell OpenRD Ultimate Board")
.boot_params = 0x00000100,
.init_machine = openrd_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index 513ad3102d7c..ca294ff6d5be 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -18,8 +18,16 @@
#include <mach/bridge-regs.h>
#include "common.h"
+void kirkwood_enable_pcie(void)
+{
+ u32 curr = readl(CLOCK_GATING_CTRL);
+ if (!(curr & CGC_PEX0))
+ writel(curr | CGC_PEX0, CLOCK_GATING_CTRL);
+}
+
void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
{
+ kirkwood_enable_pcie();
*dev = orion_pcie_dev_id((void __iomem *)PCIE_VIRT_BASE);
*rev = orion_pcie_rev((void __iomem *)PCIE_VIRT_BASE);
}
diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
index 0049614cd324..75c6601b8d87 100644
--- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
@@ -82,6 +82,7 @@ MACHINE_START(RD88F6192_NAS, "Marvell RD-88F6192-NAS Development Board")
.boot_params = 0x00000100,
.init_machine = rd88f6192_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index 0998a08cf42d..0f75494d5902 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -118,6 +118,7 @@ MACHINE_START(RD88F6281, "Marvell RD-88F6281 Reference Board")
.boot_params = 0x00000100,
.init_machine = rd88f6281_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c
index d2eec35dfe0f..0a95063f6d32 100644
--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c
+++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c
@@ -134,6 +134,7 @@ MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board")
.boot_params = 0x00000100,
.init_machine = sheevaplug_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
@@ -144,6 +145,7 @@ MACHINE_START(ESATA_SHEEVAPLUG, "Marvell eSATA SheevaPlug Reference Board")
.boot_params = 0x00000100,
.init_machine = sheevaplug_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c
index ce50e61aac9f..e6b9b1b22a35 100644
--- a/arch/arm/mach-kirkwood/t5325-setup.c
+++ b/arch/arm/mach-kirkwood/t5325-setup.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
+#include <sound/alc5623.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
@@ -134,6 +135,7 @@ static unsigned int hp_t5325_mpp_config[] __initdata = {
MPP33_GE1_TXCTL,
MPP39_AU_I2SBCLK,
MPP40_AU_I2SDO,
+ MPP43_AU_I2SDI,
MPP41_AU_I2SLRCLK,
MPP42_AU_I2SMCLK,
MPP45_GPIO, /* Power button */
@@ -141,6 +143,18 @@ static unsigned int hp_t5325_mpp_config[] __initdata = {
0
};
+static struct alc5623_platform_data alc5621_data = {
+ .add_ctrl = 0x3700,
+ .jack_det_ctrl = 0x4810,
+};
+
+static struct i2c_board_info i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("alc5621", 0x1a),
+ .platform_data = &alc5621_data,
+ },
+};
+
#define HP_T5325_GPIO_POWER_OFF 48
static void hp_t5325_power_off(void)
@@ -166,6 +180,9 @@ static void __init hp_t5325_init(void)
kirkwood_ehci_init();
platform_device_register(&hp_t5325_button_device);
+ i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info));
+ kirkwood_audio_init();
+
if (gpio_request(HP_T5325_GPIO_POWER_OFF, "power-off") == 0 &&
gpio_direction_output(HP_T5325_GPIO_POWER_OFF, 0) == 0)
pm_power_off = hp_t5325_power_off;
@@ -187,6 +204,7 @@ MACHINE_START(T5325, "HP t5325 Thin Client")
.boot_params = 0x00000100,
.init_machine = hp_t5325_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/ts219-setup.c b/arch/arm/mach-kirkwood/ts219-setup.c
index dc999c4c5806..68f32f2bf552 100644
--- a/arch/arm/mach-kirkwood/ts219-setup.c
+++ b/arch/arm/mach-kirkwood/ts219-setup.c
@@ -135,6 +135,7 @@ MACHINE_START(TS219, "QNAP TS-119/TS-219")
.boot_params = 0x00000100,
.init_machine = qnap_ts219_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-kirkwood/ts41x-setup.c b/arch/arm/mach-kirkwood/ts41x-setup.c
index 9a44029915e2..d5d009970705 100644
--- a/arch/arm/mach-kirkwood/ts41x-setup.c
+++ b/arch/arm/mach-kirkwood/ts41x-setup.c
@@ -154,6 +154,8 @@ static void __init qnap_ts41x_init(void)
static int __init ts41x_pci_init(void)
{
if (machine_is_ts41x()) {
+ u32 dev, rev;
+
/*
* Without this explicit reset, the PCIe SATA controller
* (Marvell 88sx7042/sata_mv) is known to stop working
@@ -161,7 +163,11 @@ static int __init ts41x_pci_init(void)
*/
orion_pcie_reset((void __iomem *)PCIE_VIRT_BASE);
- kirkwood_pcie_init(KW_PCIE0);
+ kirkwood_pcie_id(&dev, &rev);
+ if (dev == MV88F6282_DEV_ID)
+ kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
+ else
+ kirkwood_pcie_init(KW_PCIE0);
}
return 0;
@@ -173,6 +179,7 @@ MACHINE_START(TS41X, "QNAP TS-41x")
.boot_params = 0x00000100,
.init_machine = qnap_ts41x_init,
.map_io = kirkwood_map_io,
+ .init_early = kirkwood_init_early,
.init_irq = kirkwood_init_irq,
.timer = &kirkwood_timer,
MACHINE_END
diff --git a/arch/arm/mach-loki/common.c b/arch/arm/mach-loki/common.c
index 818f19d7ab1f..e41e909cf8f4 100644
--- a/arch/arm/mach-loki/common.c
+++ b/arch/arm/mach-loki/common.c
@@ -18,6 +18,7 @@
#include <asm/timex.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
+#include <mach/bridge-regs.h>
#include <mach/loki.h>
#include <plat/orion_nand.h>
#include <plat/time.h>
@@ -290,9 +291,15 @@ void __init loki_uart1_init(void)
/*****************************************************************************
* Time handling
****************************************************************************/
+void __init loki_init_early(void)
+{
+ orion_time_set_base(TIMER_VIRT_BASE);
+}
+
static void loki_timer_init(void)
{
- orion_time_init(IRQ_LOKI_BRIDGE, LOKI_TCLK);
+ orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
+ IRQ_LOKI_BRIDGE, LOKI_TCLK);
}
struct sys_timer loki_timer = {
diff --git a/arch/arm/mach-loki/common.h b/arch/arm/mach-loki/common.h
index 26054fd0f05e..a315dcf8887c 100644
--- a/arch/arm/mach-loki/common.h
+++ b/arch/arm/mach-loki/common.h
@@ -18,6 +18,7 @@ struct mv643xx_eth_platform_data;
*/
void loki_map_io(void);
void loki_init(void);
+void loki_init_early(void);
void loki_init_irq(void);
extern struct mbus_dram_target_info loki_mbus_dram_info;
diff --git a/arch/arm/mach-loki/include/mach/bridge-regs.h b/arch/arm/mach-loki/include/mach/bridge-regs.h
index a3fabf70044f..fd87732097cd 100644
--- a/arch/arm/mach-loki/include/mach/bridge-regs.h
+++ b/arch/arm/mach-loki/include/mach/bridge-regs.h
@@ -17,11 +17,6 @@
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE | 0x010c)
#define SOFT_RESET 0x00000001
-#define BRIDGE_CAUSE (BRIDGE_VIRT_BASE | 0x0110)
-
-#define BRIDGE_MASK (BRIDGE_VIRT_BASE | 0x0114)
-#define BRIDGE_INT_TIMER0 0x0002
-#define BRIDGE_INT_TIMER1 0x0004
#define BRIDGE_INT_TIMER1_CLR 0x0004
#define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0200)
diff --git a/arch/arm/mach-loki/lb88rc8480-setup.c b/arch/arm/mach-loki/lb88rc8480-setup.c
index a1e75e7fc500..35eae4e6abb2 100644
--- a/arch/arm/mach-loki/lb88rc8480-setup.c
+++ b/arch/arm/mach-loki/lb88rc8480-setup.c
@@ -93,6 +93,7 @@ MACHINE_START(LB88RC8480, "Marvell LB88RC8480 Development Board")
.boot_params = 0x00000100,
.init_machine = lb88rc8480_init,
.map_io = loki_map_io,
+ .init_early = loki_init_early,
.init_irq = loki_init_irq,
.timer = &loki_timer,
MACHINE_END
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5d3d9ade12fb..1516896e8d17 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -45,7 +45,16 @@ config ARCH_MSM8X60
select CPU_V7
select MSM_V2_TLMM
select MSM_GPIOMUX
- select IOMMU_API
+ select MSM_SCM if SMP
+
+config ARCH_MSM8960
+ bool "MSM8960"
+ select ARCH_MSM_SCORPIONMP
+ select MACH_MSM8960_SIM if (!MACH_MSM8960_RUMI3)
+ select ARM_GIC
+ select CPU_V7
+ select MSM_V2_TLMM
+ select MSM_GPIOMUX
select MSM_SCM if SMP
endchoice
@@ -125,11 +134,35 @@ config MACH_MSM8X60_FFA
help
Support for the Qualcomm MSM8x60 FFA eval board.
+config MACH_MSM8960_SIM
+ depends on ARCH_MSM8960
+ bool "MSM8960 Simulator"
+ help
+ Support for the Qualcomm MSM8960 simulator.
+
+config MACH_MSM8960_RUMI3
+ depends on ARCH_MSM8960
+ bool "MSM8960 RUMI3"
+ help
+ Support for the Qualcomm MSM8960 RUMI3 emulator.
+
endmenu
+config MSM_IOMMU
+ bool "MSM IOMMU Support"
+ depends on ARCH_MSM8X60 || ARCH_MSM8960
+ select IOMMU_API
+ default n
+ help
+ Support for the IOMMUs found on certain Qualcomm SOCs.
+ These IOMMUs allow virtualization of the address space used by most
+ cores within the multimedia subsystem.
+
+ If unsure, say N here.
+
config IOMMU_PGTABLES_L2
def_bool y
- depends on ARCH_MSM8X60 && MMU && SMP && CPU_DCACHE_DISABLE=n
+ depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n
config MSM_DEBUG_UART
int
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 94195c190e13..9519fd28a025 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -1,21 +1,16 @@
obj-y += io.o idle.o timer.o
-ifndef CONFIG_ARCH_MSM8X60
-obj-y += acpuclock-arm11.o
-obj-y += dma.o
-endif
+obj-y += clock.o
+obj-$(CONFIG_DEBUG_FS) += clock-debug.o
-ifdef CONFIG_MSM_VIC
-obj-y += irq-vic.o
-else
-ifndef CONFIG_ARCH_MSM8X60
-obj-y += irq.o
-endif
-endif
+obj-$(CONFIG_MSM_VIC) += irq-vic.o
+obj-$(CONFIG_MSM_IOMMU) += iommu.o iommu_dev.o devices-iommu.o
+
+obj-$(CONFIG_ARCH_MSM7X00A) += dma.o irq.o acpuclock-arm11.o
+obj-$(CONFIG_ARCH_MSM7X30) += dma.o
+obj-$(CONFIG_ARCH_QSD8X50) += dma.o sirc.o
-obj-$(CONFIG_ARCH_MSM8X60) += clock-dummy.o iommu.o iommu_dev.o devices-msm8x60-iommu.o
obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o clock-pcom.o vreg.o
-obj-$(CONFIG_MSM_PROC_COMM) += clock.o
-obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
+
obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
obj-$(CONFIG_MSM_SMD) += last_radio_log.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -29,12 +24,16 @@ obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60.o
+obj-$(CONFIG_ARCH_MSM8960) += board-msm8960.o devices-msm8960.o
-obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
ifdef CONFIG_MSM_V2_TLMM
+ifndef CONFIG_ARCH_MSM8960
+# TODO: TLMM Mapping issues need to be resolved
obj-y += gpio-v2.o
+endif
else
obj-y += gpio.o
endif
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index 75dabb16c802..18a3c97bc863 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -93,8 +93,6 @@ static void __init halibut_map_io(void)
}
MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = 0x10000100,
.fixup = halibut_fixup,
.map_io = halibut_map_io,
diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
index ef3ebf2f763b..7a9a03eb189c 100644
--- a/arch/arm/mach-msm/board-mahimahi.c
+++ b/arch/arm/mach-msm/board-mahimahi.c
@@ -74,8 +74,6 @@ static void __init mahimahi_map_io(void)
extern struct sys_timer msm_timer;
MACHINE_START(MAHIMAHI, "mahimahi")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = 0x20000100,
.fixup = mahimahi_fixup,
.map_io = mahimahi_map_io,
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index 08fcd40a8cbd..c03f269e2e4b 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -130,8 +130,6 @@ static void __init msm7x2x_map_io(void)
}
MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x2x_map_io,
.init_irq = msm7x2x_init_irq,
@@ -140,8 +138,6 @@ MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
MACHINE_END
MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x2x_map_io,
.init_irq = msm7x2x_init_irq,
@@ -150,8 +146,6 @@ MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
MACHINE_END
MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x2x_map_io,
.init_irq = msm7x2x_init_irq,
@@ -160,8 +154,6 @@ MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF")
MACHINE_END
MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x2x_map_io,
.init_irq = msm7x2x_init_irq,
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 25db8fd71a70..b7a84966b711 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -23,6 +23,7 @@
#include <linux/io.h>
#include <linux/smsc911x.h>
#include <linux/usb/msm_hsusb.h>
+#include <linux/clkdev.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -36,6 +37,7 @@
#include <mach/vreg.h>
#include "devices.h"
+#include "gpiomux.h"
#include "proc_comm.h"
extern struct sys_timer msm_timer;
@@ -52,6 +54,27 @@ static struct msm_otg_platform_data msm_otg_pdata = {
.otg_control = OTG_PHY_CONTROL,
};
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+ [49] = { /* UART2 RFR */
+ .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+ GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+ },
+ [50] = { /* UART2 CTS */
+ .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+ GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+ },
+ [51] = { /* UART2 RX */
+ .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+ GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+ },
+ [52] = { /* UART2 TX */
+ .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+ GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+ },
+#endif
+};
+
static struct platform_device *devices[] __initdata = {
#if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
&msm_device_uart2,
@@ -83,8 +106,6 @@ static void __init msm7x30_map_io(void)
}
MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
@@ -93,8 +114,6 @@ MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
MACHINE_END
MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
@@ -103,8 +122,6 @@ MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
MACHINE_END
MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = msm7x30_map_io,
.init_irq = msm7x30_init_irq,
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
new file mode 100644
index 000000000000..1993721d472e
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clkdev.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+#include "devices.h"
+
+static void __init msm8960_map_io(void)
+{
+ msm_map_msm8960_io();
+}
+
+static void __init msm8960_init_irq(void)
+{
+ unsigned int i;
+ gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
+ (void *)MSM_QGIC_CPU_BASE);
+
+ /* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
+ writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+
+ if (machine_is_msm8960_rumi3())
+ writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
+
+ /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
+ * as they are configured as level, which does not play nice with
+ * handle_percpu_irq.
+ */
+ for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
+ if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
+ set_irq_handler(i, handle_percpu_irq);
+ }
+}
+
+static struct platform_device *sim_devices[] __initdata = {
+ &msm8960_device_uart_gsbi2,
+};
+
+static struct platform_device *rumi3_devices[] __initdata = {
+ &msm8960_device_uart_gsbi5,
+};
+
+static void __init msm8960_sim_init(void)
+{
+ platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
+}
+
+static void __init msm8960_rumi3_init(void)
+{
+ platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
+}
+
+MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR")
+ .map_io = msm8960_map_io,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_sim_init,
+MACHINE_END
+
+MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3")
+ .map_io = msm8960_map_io,
+ .init_irq = msm8960_init_irq,
+ .timer = &msm_timer,
+ .init_machine = msm8960_rumi3_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 9b5eb2b4ae1b..b3c55f138fce 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -28,10 +28,6 @@
#include <mach/board.h>
#include <mach/msm_iomap.h>
-unsigned long clk_get_max_axi_khz(void)
-{
- return 0;
-}
static void __init msm8x60_map_io(void)
{
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 15c2bbd2ef81..7f568611547e 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,8 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/usb/msm_hsusb.h>
+#include <linux/err.h>
+#include <linux/clkdev.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -31,6 +33,8 @@
#include <mach/irqs.h>
#include <mach/sirc.h>
#include <mach/gpio.h>
+#include <mach/vreg.h>
+#include <mach/mmc.h>
#include "devices.h"
@@ -95,6 +99,81 @@ static struct platform_device *devices[] __initdata = {
&msm_device_hsusb_host,
};
+static struct msm_mmc_gpio sdc1_gpio_cfg[] = {
+ {51, "sdc1_dat_3"},
+ {52, "sdc1_dat_2"},
+ {53, "sdc1_dat_1"},
+ {54, "sdc1_dat_0"},
+ {55, "sdc1_cmd"},
+ {56, "sdc1_clk"}
+};
+
+static struct vreg *vreg_mmc;
+static unsigned long vreg_sts;
+
+static uint32_t msm_sdcc_setup_power(struct device *dv, unsigned int vdd)
+{
+ int rc = 0;
+ struct platform_device *pdev;
+
+ pdev = container_of(dv, struct platform_device, dev);
+
+ if (vdd == 0) {
+ if (!vreg_sts)
+ return 0;
+
+ clear_bit(pdev->id, &vreg_sts);
+
+ if (!vreg_sts) {
+ rc = vreg_disable(vreg_mmc);
+ if (rc)
+ pr_err("vreg_mmc disable failed for slot "
+ "%d: %d\n", pdev->id, rc);
+ }
+ return 0;
+ }
+
+ if (!vreg_sts) {
+ rc = vreg_set_level(vreg_mmc, 2900);
+ if (rc)
+ pr_err("vreg_mmc set level failed for slot %d: %d\n",
+ pdev->id, rc);
+ rc = vreg_enable(vreg_mmc);
+ if (rc)
+ pr_err("vreg_mmc enable failed for slot %d: %d\n",
+ pdev->id, rc);
+ }
+ set_bit(pdev->id, &vreg_sts);
+ return 0;
+}
+
+static struct msm_mmc_gpio_data sdc1_gpio = {
+ .gpio = sdc1_gpio_cfg,
+ .size = ARRAY_SIZE(sdc1_gpio_cfg),
+};
+
+static struct msm_mmc_platform_data qsd8x50_sdc1_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .translate_vdd = msm_sdcc_setup_power,
+ .gpio_data = &sdc1_gpio,
+};
+
+static void __init qsd8x50_init_mmc(void)
+{
+ if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa())
+ vreg_mmc = vreg_get(NULL, "gp6");
+ else
+ vreg_mmc = vreg_get(NULL, "gp5");
+
+ if (IS_ERR(vreg_mmc)) {
+ pr_err("vreg get for vreg_mmc failed (%ld)\n",
+ PTR_ERR(vreg_mmc));
+ return;
+ }
+
+ msm_add_sdcc(1, &qsd8x50_sdc1_data, 0, 0);
+}
+
static void __init qsd8x50_map_io(void)
{
msm_map_qsd8x50_io();
@@ -113,11 +192,10 @@ static void __init qsd8x50_init(void)
msm_device_hsusb.dev.parent = &msm_device_otg.dev;
msm_device_hsusb_host.dev.parent = &msm_device_otg.dev;
platform_add_devices(devices, ARRAY_SIZE(devices));
+ qsd8x50_init_mmc();
}
MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = qsd8x50_map_io,
.init_irq = qsd8x50_init_irq,
@@ -126,8 +204,6 @@ MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
MACHINE_END
MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.map_io = qsd8x50_map_io,
.init_irq = qsd8x50_init_irq,
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
index 83604f526f0f..68f930f07d77 100644
--- a/arch/arm/mach-msm/board-sapphire.c
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -105,8 +105,6 @@ static void __init sapphire_map_io(void)
MACHINE_START(SAPPHIRE, "sapphire")
/* Maintainer: Brian Swetland <swetland@google.com> */
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = PLAT_PHYS_OFFSET + 0x100,
.fixup = sapphire_fixup,
.map_io = sapphire_map_io,
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
index a604ec1e44bf..31117a4499c4 100644
--- a/arch/arm/mach-msm/board-trout-gpio.c
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -74,8 +74,6 @@ static int msm_gpiolib_direction_output(struct gpio_chip *chip,
static int trout_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct msm_gpio_chip *msm_gpio = to_msm_gpio_chip(chip);
-
return TROUT_GPIO_TO_INT(offset + chip->base);
}
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index 73f146066542..814386772c66 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/clkdev.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -92,8 +93,6 @@ static void __init trout_map_io(void)
}
MACHINE_START(TROUT, "HTC Dream")
-#ifdef CONFIG_MSM_DEBUG_UART
-#endif
.boot_params = 0x10000100,
.fixup = trout_fixup,
.map_io = trout_map_io,
diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h
index e16f72f32829..14104453688b 100644
--- a/arch/arm/mach-msm/clock-7x30.h
+++ b/arch/arm/mach-msm/clock-7x30.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_7X30_H
@@ -147,22 +130,26 @@ void pll_disable(uint32_t pll);
extern int internal_pwr_rail_ctl_auto(unsigned rail_id, bool enable);
#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \
- .name = clk_name, \
- .id = L_7X30_##clk_id, \
- .remote_id = P_##clk_id, \
- .flags = clk_flags, \
- .dev = clk_dev, \
- .dbg_name = #clk_id, \
+ .con_id = clk_name, \
+ .dev_id = clk_dev, \
+ .clk = &(struct clk){ \
+ .id = L_7X30_##clk_id, \
+ .remote_id = P_##clk_id, \
+ .flags = clk_flags, \
+ .dbg_name = #clk_id, \
+ }, \
}
#define CLK_7X30S(clk_name, l_id, r_id, clk_dev, clk_flags) { \
- .name = clk_name, \
- .id = L_7X30_##l_id, \
- .remote_id = P_##r_id, \
- .flags = clk_flags, \
- .dev = clk_dev, \
- .dbg_name = #l_id, \
+ .con_id = clk_name, \
+ .dev_id = clk_dev, \
+ .clk = &(struct clk){ \
+ .id = L_7X30_##l_id, \
+ .remote_id = P_##r_id, \
+ .flags = clk_flags, \
+ .dbg_name = #l_id, \
+ .ops = &clk_ops_pcom, \
+ }, \
}
#endif
-
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
new file mode 100644
index 000000000000..4886404d42f5
--- /dev/null
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/clk.h>
+#include "clock.h"
+
+static int clock_debug_rate_set(void *data, u64 val)
+{
+ struct clk *clock = data;
+ int ret;
+
+ /* Only increases to max rate will succeed, but that's actually good
+ * for debugging purposes so we don't check for error. */
+ if (clock->flags & CLK_MAX)
+ clk_set_max_rate(clock, val);
+ if (clock->flags & CLK_MIN)
+ ret = clk_set_min_rate(clock, val);
+ else
+ ret = clk_set_rate(clock, val);
+ if (ret != 0)
+ printk(KERN_ERR "clk_set%s_rate failed (%d)\n",
+ (clock->flags & CLK_MIN) ? "_min" : "", ret);
+ return ret;
+}
+
+static int clock_debug_rate_get(void *data, u64 *val)
+{
+ struct clk *clock = data;
+ *val = clk_get_rate(clock);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
+ clock_debug_rate_set, "%llu\n");
+
+static int clock_debug_enable_set(void *data, u64 val)
+{
+ struct clk *clock = data;
+ int rc = 0;
+
+ if (val)
+ rc = clock->ops->enable(clock->id);
+ else
+ clock->ops->disable(clock->id);
+
+ return rc;
+}
+
+static int clock_debug_enable_get(void *data, u64 *val)
+{
+ struct clk *clock = data;
+
+ *val = clock->ops->is_enabled(clock->id);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
+ clock_debug_enable_set, "%llu\n");
+
+static int clock_debug_local_get(void *data, u64 *val)
+{
+ struct clk *clock = data;
+
+ *val = clock->ops->is_local(clock->id);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get,
+ NULL, "%llu\n");
+
+static struct dentry *debugfs_base;
+
+int __init clock_debug_init(void)
+{
+ debugfs_base = debugfs_create_dir("clk", NULL);
+ if (!debugfs_base)
+ return -ENOMEM;
+ return 0;
+}
+
+int __init clock_debug_add(struct clk *clock)
+{
+ char temp[50], *ptr;
+ struct dentry *clk_dir;
+
+ if (!debugfs_base)
+ return -ENOMEM;
+
+ strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1);
+ for (ptr = temp; *ptr; ptr++)
+ *ptr = tolower(*ptr);
+
+ clk_dir = debugfs_create_dir(temp, debugfs_base);
+ if (!clk_dir)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("rate", S_IRUGO | S_IWUSR, clk_dir,
+ clock, &clock_rate_fops))
+ goto error;
+
+ if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, clk_dir,
+ clock, &clock_enable_fops))
+ goto error;
+
+ if (!debugfs_create_file("is_local", S_IRUGO, clk_dir, clock,
+ &clock_local_fops))
+ goto error;
+ return 0;
+error:
+ debugfs_remove_recursive(clk_dir);
+ return -ENOMEM;
+}
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
deleted file mode 100644
index 1250d22082ee..000000000000
--- a/arch/arm/mach-msm/clock-dummy.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/module.h>
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
- return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
-
-int clk_enable(struct clk *clk)
-{
- return -ENOENT;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- return -ENOENT;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
index a3b45627eb4a..63b711311086 100644
--- a/arch/arm/mach-msm/clock-pcom.c
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -20,6 +20,7 @@
#include "proc_comm.h"
#include "clock.h"
+#include "clock-pcom.h"
/*
* glue for the proc_comm interface
@@ -116,6 +117,11 @@ long pc_clk_round_rate(unsigned id, unsigned rate)
return rate;
}
+static bool pc_clk_is_local(unsigned id)
+{
+ return false;
+}
+
struct clk_ops clk_ops_pcom = {
.enable = pc_clk_enable,
.disable = pc_clk_disable,
@@ -128,4 +134,5 @@ struct clk_ops clk_ops_pcom = {
.get_rate = pc_clk_get_rate,
.is_enabled = pc_clk_is_enabled,
.round_rate = pc_clk_round_rate,
+ .is_local = pc_clk_is_local,
};
diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h
index 17d027b23501..974d0032f3a3 100644
--- a/arch/arm/mach-msm/clock-pcom.h
+++ b/arch/arm/mach-msm/clock-pcom.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H
@@ -132,8 +115,10 @@
#define P_CSI1_P_CLK 97
#define P_GSBI_CLK 98
#define P_GSBI_P_CLK 99
+#define P_CE_CLK 100 /* Crypto engine */
+#define P_CODEC_SSBI_CLK 101
-#define P_NR_CLKS 100
+#define P_NR_CLKS 102
struct clk_ops;
extern struct clk_ops clk_ops_pcom;
@@ -141,13 +126,15 @@ extern struct clk_ops clk_ops_pcom;
int pc_clk_reset(unsigned id, enum clk_reset_action action);
#define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) { \
- .name = clk_name, \
- .id = P_##clk_id, \
- .remote_id = P_##clk_id, \
- .ops = &clk_ops_pcom, \
- .flags = clk_flags, \
- .dev = clk_dev, \
- .dbg_name = #clk_id, \
+ .con_id = clk_name, \
+ .dev_id = clk_dev, \
+ .clk = &(struct clk){ \
+ .id = P_##clk_id, \
+ .remote_id = P_##clk_id, \
+ .ops = &clk_ops_pcom, \
+ .flags = clk_flags, \
+ .dbg_name = #clk_id, \
+ }, \
}
#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 2069bfaa3a26..22a537669624 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -15,74 +15,32 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/list.h>
#include <linux/err.h>
-#include <linux/clk.h>
#include <linux/spinlock.h>
-#include <linux/debugfs.h>
-#include <linux/ctype.h>
#include <linux/pm_qos_params.h>
-#include <mach/clk.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/clkdev.h>
#include "clock.h"
-#include "proc_comm.h"
-#include "clock-7x30.h"
static DEFINE_MUTEX(clocks_mutex);
static DEFINE_SPINLOCK(clocks_lock);
static LIST_HEAD(clocks);
-struct clk *msm_clocks;
-unsigned msm_num_clocks;
-
-/*
- * Bitmap of enabled clocks, excluding ACPU which is always
- * enabled
- */
-static DECLARE_BITMAP(clock_map_enabled, NR_CLKS);
-static DEFINE_SPINLOCK(clock_map_lock);
/*
* Standard clock functions defined in include/linux/clk.h
*/
-struct clk *clk_get(struct device *dev, const char *id)
-{
- struct clk *clk;
-
- mutex_lock(&clocks_mutex);
-
- list_for_each_entry(clk, &clocks, list)
- if (!strcmp(id, clk->name) && clk->dev == dev)
- goto found_it;
-
- list_for_each_entry(clk, &clocks, list)
- if (!strcmp(id, clk->name) && clk->dev == NULL)
- goto found_it;
-
- clk = ERR_PTR(-ENOENT);
-found_it:
- mutex_unlock(&clocks_mutex);
- return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
int clk_enable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
clk->count++;
- if (clk->count == 1) {
+ if (clk->count == 1)
clk->ops->enable(clk->id);
- spin_lock(&clock_map_lock);
- clock_map_enabled[BIT_WORD(clk->id)] |= BIT_MASK(clk->id);
- spin_unlock(&clock_map_lock);
- }
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
@@ -94,20 +52,14 @@ void clk_disable(struct clk *clk)
spin_lock_irqsave(&clocks_lock, flags);
BUG_ON(clk->count == 0);
clk->count--;
- if (clk->count == 0) {
+ if (clk->count == 0)
clk->ops->disable(clk->id);
- spin_lock(&clock_map_lock);
- clock_map_enabled[BIT_WORD(clk->id)] &= ~BIT_MASK(clk->id);
- spin_unlock(&clock_map_lock);
- }
spin_unlock_irqrestore(&clocks_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
int clk_reset(struct clk *clk, enum clk_reset_action action)
{
- if (!clk->ops->reset)
- clk->ops->reset = &pc_clk_reset;
return clk->ops->reset(clk->remote_id, action);
}
EXPORT_SYMBOL(clk_reset);
@@ -184,25 +136,14 @@ EXPORT_SYMBOL(clk_set_flags);
*/
static struct clk *ebi1_clk;
-static void __init set_clock_ops(struct clk *clk)
-{
- if (!clk->ops) {
- clk->ops = &clk_ops_pcom;
- clk->id = clk->remote_id;
- }
-}
-
-void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks)
+void __init msm_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks)
{
unsigned n;
- spin_lock_init(&clocks_lock);
mutex_lock(&clocks_mutex);
- msm_clocks = clock_tbl;
- msm_num_clocks = num_clocks;
- for (n = 0; n < msm_num_clocks; n++) {
- set_clock_ops(&msm_clocks[n]);
- list_add_tail(&msm_clocks[n].list, &clocks);
+ for (n = 0; n < num_clocks; n++) {
+ clkdev_add(&clock_tbl[n]);
+ list_add_tail(&clock_tbl[n].clk->list, &clocks);
}
mutex_unlock(&clocks_mutex);
@@ -211,115 +152,6 @@ void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks)
}
-#if defined(CONFIG_DEBUG_FS)
-static struct clk *msm_clock_get_nth(unsigned index)
-{
- if (index < msm_num_clocks)
- return msm_clocks + index;
- else
- return 0;
-}
-
-static int clock_debug_rate_set(void *data, u64 val)
-{
- struct clk *clock = data;
- int ret;
-
- /* Only increases to max rate will succeed, but that's actually good
- * for debugging purposes. So we don't check for error. */
- if (clock->flags & CLK_MAX)
- clk_set_max_rate(clock, val);
- if (clock->flags & CLK_MIN)
- ret = clk_set_min_rate(clock, val);
- else
- ret = clk_set_rate(clock, val);
- if (ret != 0)
- printk(KERN_ERR "clk_set%s_rate failed (%d)\n",
- (clock->flags & CLK_MIN) ? "_min" : "", ret);
- return ret;
-}
-
-static int clock_debug_rate_get(void *data, u64 *val)
-{
- struct clk *clock = data;
- *val = clk_get_rate(clock);
- return 0;
-}
-
-static int clock_debug_enable_set(void *data, u64 val)
-{
- struct clk *clock = data;
- int rc = 0;
-
- if (val)
- rc = clock->ops->enable(clock->id);
- else
- clock->ops->disable(clock->id);
-
- return rc;
-}
-
-static int clock_debug_enable_get(void *data, u64 *val)
-{
- struct clk *clock = data;
-
- *val = clock->ops->is_enabled(clock->id);
-
- return 0;
-}
-
-static int clock_debug_local_get(void *data, u64 *val)
-{
- struct clk *clock = data;
-
- *val = clock->ops != &clk_ops_pcom;
-
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
- clock_debug_rate_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
- clock_debug_enable_set, "%llu\n");
-DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get,
- NULL, "%llu\n");
-
-static int __init clock_debug_init(void)
-{
- struct dentry *dent_rate, *dent_enable, *dent_local;
- struct clk *clock;
- unsigned n = 0;
- char temp[50], *ptr;
-
- dent_rate = debugfs_create_dir("clk_rate", 0);
- if (IS_ERR(dent_rate))
- return PTR_ERR(dent_rate);
-
- dent_enable = debugfs_create_dir("clk_enable", 0);
- if (IS_ERR(dent_enable))
- return PTR_ERR(dent_enable);
-
- dent_local = debugfs_create_dir("clk_local", NULL);
- if (IS_ERR(dent_local))
- return PTR_ERR(dent_local);
-
- while ((clock = msm_clock_get_nth(n++)) != 0) {
- strncpy(temp, clock->dbg_name, ARRAY_SIZE(temp)-1);
- for (ptr = temp; *ptr; ptr++)
- *ptr = tolower(*ptr);
- debugfs_create_file(temp, 0644, dent_rate,
- clock, &clock_rate_fops);
- debugfs_create_file(temp, 0644, dent_enable,
- clock, &clock_enable_fops);
- debugfs_create_file(temp, S_IRUGO, dent_local,
- clock, &clock_local_fops);
- }
- return 0;
-}
-
-device_initcall(clock_debug_init);
-#endif
-
/* The bootloader and/or AMSS may have left various clocks enabled.
* Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have
* not been explicitly enabled by a clk_enable() call.
@@ -330,8 +162,10 @@ static int __init clock_late_init(void)
struct clk *clk;
unsigned count = 0;
+ clock_debug_init();
mutex_lock(&clocks_mutex);
list_for_each_entry(clk, &clocks, list) {
+ clock_debug_add(clk);
if (clk->flags & CLKFLAG_AUTO_OFF) {
spin_lock_irqsave(&clocks_lock, flags);
if (!clk->count) {
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index c270b552ed13..2c007f606d29 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -17,12 +17,10 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_H
#define __ARCH_ARM_MACH_MSM_CLOCK_H
+#include <linux/init.h>
#include <linux/list.h>
#include <mach/clk.h>
-#include "clock-pcom.h"
-#include "clock-7x30.h"
-
#define CLKFLAG_INVERT 0x00000001
#define CLKFLAG_NOINVERT 0x00000002
#define CLKFLAG_NONEST 0x00000004
@@ -45,6 +43,7 @@ struct clk_ops {
unsigned (*get_rate)(unsigned id);
unsigned (*is_enabled)(unsigned id);
long (*round_rate)(unsigned id, unsigned rate);
+ bool (*is_local)(unsigned id);
};
struct clk {
@@ -52,58 +51,22 @@ struct clk {
uint32_t remote_id;
uint32_t count;
uint32_t flags;
- const char *name;
struct clk_ops *ops;
const char *dbg_name;
struct list_head list;
- struct device *dev;
};
-#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
-#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
-#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
-
-#ifdef CONFIG_DEBUG_FS
-#define CLOCK_DBG_NAME(x) .dbg_name = x,
-#else
-#define CLOCK_DBG_NAME(x)
-#endif
-
-#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \
- .name = clk_name, \
- .id = clk_id, \
- .flags = clk_flags, \
- .dev = clk_dev, \
- CLOCK_DBG_NAME(#clk_id) \
- }
-
#define OFF CLKFLAG_AUTO_OFF
#define CLK_MIN CLKFLAG_MIN
#define CLK_MAX CLKFLAG_MAX
#define CLK_MINMAX (CLK_MIN | CLK_MAX)
-#define NR_CLKS P_NR_CLKS
-
-enum {
- PLL_0 = 0,
- PLL_1,
- PLL_2,
- PLL_3,
- PLL_4,
- PLL_5,
- PLL_6,
- NUM_PLL
-};
-
-enum clkvote_client {
- CLKVOTE_ACPUCLK = 0,
- CLKVOTE_PMQOS,
- CLKVOTE_MAX,
-};
-
-int msm_clock_require_tcxo(unsigned long *reason, int nbits);
-int msm_clock_get_name(uint32_t id, char *name, uint32_t size);
-int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate);
-unsigned long clk_get_max_axi_khz(void);
+#ifdef CONFIG_DEBUG_FS
+int __init clock_debug_init(void);
+int __init clock_debug_add(struct clk *clock);
+#else
+static inline int __init clock_debug_init(void) { return 0; }
+static inline int __init clock_debug_add(struct clk *clock) { return 0; }
#endif
+#endif
diff --git a/arch/arm/mach-msm/devices-msm8x60-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index f9e7bd34ec59..24030d0da6e3 100644
--- a/arch/arm/mach-msm/devices-msm8x60-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,15 +18,13 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/bootmem.h>
-
-#include <mach/msm_iomap-8x60.h>
-#include <mach/irqs-8x60.h>
+#include <mach/irqs.h>
#include <mach/iommu.h>
static struct resource msm_iommu_jpegd_resources[] = {
{
- .start = MSM_IOMMU_JPEGD_PHYS,
- .end = MSM_IOMMU_JPEGD_PHYS + MSM_IOMMU_JPEGD_SIZE - 1,
+ .start = 0x07300000,
+ .end = 0x07300000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -46,8 +44,8 @@ static struct resource msm_iommu_jpegd_resources[] = {
static struct resource msm_iommu_vpe_resources[] = {
{
- .start = MSM_IOMMU_VPE_PHYS,
- .end = MSM_IOMMU_VPE_PHYS + MSM_IOMMU_VPE_SIZE - 1,
+ .start = 0x07400000,
+ .end = 0x07400000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -67,8 +65,8 @@ static struct resource msm_iommu_vpe_resources[] = {
static struct resource msm_iommu_mdp0_resources[] = {
{
- .start = MSM_IOMMU_MDP0_PHYS,
- .end = MSM_IOMMU_MDP0_PHYS + MSM_IOMMU_MDP0_SIZE - 1,
+ .start = 0x07500000,
+ .end = 0x07500000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -88,8 +86,8 @@ static struct resource msm_iommu_mdp0_resources[] = {
static struct resource msm_iommu_mdp1_resources[] = {
{
- .start = MSM_IOMMU_MDP1_PHYS,
- .end = MSM_IOMMU_MDP1_PHYS + MSM_IOMMU_MDP1_SIZE - 1,
+ .start = 0x07600000,
+ .end = 0x07600000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -109,8 +107,8 @@ static struct resource msm_iommu_mdp1_resources[] = {
static struct resource msm_iommu_rot_resources[] = {
{
- .start = MSM_IOMMU_ROT_PHYS,
- .end = MSM_IOMMU_ROT_PHYS + MSM_IOMMU_ROT_SIZE - 1,
+ .start = 0x07700000,
+ .end = 0x07700000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -130,8 +128,8 @@ static struct resource msm_iommu_rot_resources[] = {
static struct resource msm_iommu_ijpeg_resources[] = {
{
- .start = MSM_IOMMU_IJPEG_PHYS,
- .end = MSM_IOMMU_IJPEG_PHYS + MSM_IOMMU_IJPEG_SIZE - 1,
+ .start = 0x07800000,
+ .end = 0x07800000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -151,8 +149,8 @@ static struct resource msm_iommu_ijpeg_resources[] = {
static struct resource msm_iommu_vfe_resources[] = {
{
- .start = MSM_IOMMU_VFE_PHYS,
- .end = MSM_IOMMU_VFE_PHYS + MSM_IOMMU_VFE_SIZE - 1,
+ .start = 0x07900000,
+ .end = 0x07900000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -172,8 +170,8 @@ static struct resource msm_iommu_vfe_resources[] = {
static struct resource msm_iommu_vcodec_a_resources[] = {
{
- .start = MSM_IOMMU_VCODEC_A_PHYS,
- .end = MSM_IOMMU_VCODEC_A_PHYS + MSM_IOMMU_VCODEC_A_SIZE - 1,
+ .start = 0x07A00000,
+ .end = 0x07A00000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -193,8 +191,8 @@ static struct resource msm_iommu_vcodec_a_resources[] = {
static struct resource msm_iommu_vcodec_b_resources[] = {
{
- .start = MSM_IOMMU_VCODEC_B_PHYS,
- .end = MSM_IOMMU_VCODEC_B_PHYS + MSM_IOMMU_VCODEC_B_SIZE - 1,
+ .start = 0x07B00000,
+ .end = 0x07B00000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -214,8 +212,8 @@ static struct resource msm_iommu_vcodec_b_resources[] = {
static struct resource msm_iommu_gfx3d_resources[] = {
{
- .start = MSM_IOMMU_GFX3D_PHYS,
- .end = MSM_IOMMU_GFX3D_PHYS + MSM_IOMMU_GFX3D_SIZE - 1,
+ .start = 0x07C00000,
+ .end = 0x07C00000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -235,8 +233,8 @@ static struct resource msm_iommu_gfx3d_resources[] = {
static struct resource msm_iommu_gfx2d0_resources[] = {
{
- .start = MSM_IOMMU_GFX2D0_PHYS,
- .end = MSM_IOMMU_GFX2D0_PHYS + MSM_IOMMU_GFX2D0_SIZE - 1,
+ .start = 0x07D00000,
+ .end = 0x07D00000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -256,8 +254,8 @@ static struct resource msm_iommu_gfx2d0_resources[] = {
static struct resource msm_iommu_gfx2d1_resources[] = {
{
- .start = MSM_IOMMU_GFX2D1_PHYS,
- .end = MSM_IOMMU_GFX2D1_PHYS + MSM_IOMMU_GFX2D1_SIZE - 1,
+ .start = 0x07E00000,
+ .end = 0x07E00000 + SZ_1M - 1,
.name = "physbase",
.flags = IORESOURCE_MEM,
},
@@ -282,55 +280,62 @@ static struct platform_device msm_root_iommu_dev = {
static struct msm_iommu_dev jpegd_iommu = {
.name = "jpegd",
- .clk_rate = -1
+ .ncb = 2,
};
static struct msm_iommu_dev vpe_iommu = {
- .name = "vpe"
+ .name = "vpe",
+ .ncb = 2,
};
static struct msm_iommu_dev mdp0_iommu = {
- .name = "mdp0"
+ .name = "mdp0",
+ .ncb = 2,
};
static struct msm_iommu_dev mdp1_iommu = {
- .name = "mdp1"
+ .name = "mdp1",
+ .ncb = 2,
};
static struct msm_iommu_dev rot_iommu = {
- .name = "rot"
+ .name = "rot",
+ .ncb = 2,
};
static struct msm_iommu_dev ijpeg_iommu = {
- .name = "ijpeg"
+ .name = "ijpeg",
+ .ncb = 2,
};
static struct msm_iommu_dev vfe_iommu = {
.name = "vfe",
- .clk_rate = -1
+ .ncb = 2,
};
static struct msm_iommu_dev vcodec_a_iommu = {
- .name = "vcodec_a"
+ .name = "vcodec_a",
+ .ncb = 2,
};
static struct msm_iommu_dev vcodec_b_iommu = {
- .name = "vcodec_b"
+ .name = "vcodec_b",
+ .ncb = 2,
};
static struct msm_iommu_dev gfx3d_iommu = {
.name = "gfx3d",
- .clk_rate = 27000000
+ .ncb = 3,
};
static struct msm_iommu_dev gfx2d0_iommu = {
.name = "gfx2d0",
- .clk_rate = 27000000
+ .ncb = 2,
};
static struct msm_iommu_dev gfx2d1_iommu = {
.name = "gfx2d1",
- .clk_rate = 27000000
+ .ncb = 2,
};
static struct platform_device msm_device_iommu_jpegd = {
diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
index fb548a8a21db..c4f5e26feb4d 100644
--- a/arch/arm/mach-msm/devices-msm7x00.c
+++ b/arch/arm/mach-msm/devices-msm7x00.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/clkdev.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
@@ -24,8 +25,8 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
-
#include "clock.h"
+#include "clock-pcom.h"
#include <mach/mmc.h>
static struct resource resources_uart1[] = {
@@ -38,6 +39,7 @@ static struct resource resources_uart1[] = {
.start = MSM_UART1_PHYS,
.end = MSM_UART1_PHYS + MSM_UART1_SIZE - 1,
.flags = IORESOURCE_MEM,
+ .name = "uart_resource"
},
};
@@ -51,6 +53,7 @@ static struct resource resources_uart2[] = {
.start = MSM_UART2_PHYS,
.end = MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
.flags = IORESOURCE_MEM,
+ .name = "uart_resource"
},
};
@@ -64,6 +67,7 @@ static struct resource resources_uart3[] = {
.start = MSM_UART3_PHYS,
.end = MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
.flags = IORESOURCE_MEM,
+ .name = "uart_resource"
},
};
@@ -414,7 +418,7 @@ struct platform_device msm_device_mdp = {
.resource = resources_mdp,
};
-struct clk msm_clocks_7x01a[] = {
+struct clk_lookup msm_clocks_7x01a[] = {
CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0),
CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, 0),
@@ -423,7 +427,7 @@ struct clk msm_clocks_7x01a[] = {
CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF),
CLK_PCOM("gp_clk", GP_CLK, NULL, 0),
CLK_PCOM("grp_clk", GRP_3D_CLK, NULL, OFF),
- CLK_PCOM("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0),
+ CLK_PCOM("i2c_clk", I2C_CLK, "msm_i2c.0", 0),
CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0),
CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0),
CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF),
@@ -433,25 +437,25 @@ struct clk msm_clocks_7x01a[] = {
CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0),
CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF),
- CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF),
- CLK_PCOM("sdc_pclk", SDC1_P_CLK, &msm_device_sdc1.dev, OFF),
- CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
- CLK_PCOM("sdc_pclk", SDC2_P_CLK, &msm_device_sdc2.dev, OFF),
- CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
- CLK_PCOM("sdc_pclk", SDC3_P_CLK, &msm_device_sdc3.dev, OFF),
- CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
- CLK_PCOM("sdc_pclk", SDC4_P_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_PCOM("sdc_pclk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_PCOM("sdc_pclk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, "msm_sdcc.3", OFF),
+ CLK_PCOM("sdc_pclk", SDC3_P_CLK, "msm_sdcc.3", OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, "msm_sdcc.4", OFF),
+ CLK_PCOM("sdc_pclk", SDC4_P_CLK, "msm_sdcc.4", OFF),
CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0),
CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0),
CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0),
CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0),
- CLK_PCOM("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF),
- CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0),
- CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF),
+ CLK_PCOM("uart_clk", UART1_CLK, "msm_serial.0", OFF),
+ CLK_PCOM("uart_clk", UART2_CLK, "msm_serial.1", 0),
+ CLK_PCOM("uart_clk", UART3_CLK, "msm_serial.2", OFF),
CLK_PCOM("uart1dm_clk", UART1DM_CLK, NULL, OFF),
CLK_PCOM("uart2dm_clk", UART2DM_CLK, NULL, 0),
- CLK_PCOM("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF),
- CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, &msm_device_hsusb.dev, OFF),
+ CLK_PCOM("usb_hs_clk", USB_HS_CLK, "msm_hsusb", OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, "msm_hsusb", OFF),
CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF ),
CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF),
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 4e9a0ab3e937..09b4f1403824 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/clkdev.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
@@ -28,6 +29,7 @@
#include <asm/mach/flash.h>
#include "clock-pcom.h"
+#include "clock-7x30.h"
#include <mach/mmc.h>
@@ -41,6 +43,7 @@ static struct resource resources_uart2[] = {
.start = MSM_UART2_PHYS,
.end = MSM_UART2_PHYS + MSM_UART2_SIZE - 1,
.flags = IORESOURCE_MEM,
+ .name = "uart_resource"
},
};
@@ -127,11 +130,13 @@ struct platform_device msm_device_hsusb_host = {
},
};
-struct clk msm_clocks_7x30[] = {
+struct clk_lookup msm_clocks_7x30[] = {
CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
CLK_PCOM("adsp_clk", ADSP_CLK, NULL, 0),
CLK_PCOM("cam_m_clk", CAM_M_CLK, NULL, 0),
CLK_PCOM("camif_pad_pclk", CAMIF_PAD_P_CLK, NULL, OFF),
+ CLK_PCOM("ce_clk", CE_CLK, NULL, 0),
+ CLK_PCOM("codec_ssbi_clk", CODEC_SSBI_CLK, NULL, 0),
CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN),
CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0),
CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX),
@@ -177,7 +182,7 @@ struct clk msm_clocks_7x30[] = {
CLK_7X30S("tv_src_clk", TV_CLK, TV_ENC_CLK, NULL, 0),
CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0),
CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0),
- CLK_PCOM("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0),
+ CLK_PCOM("uart_clk", UART2_CLK, "msm_serial.1", 0),
CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0),
CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF),
CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, NULL, OFF),
diff --git a/arch/arm/mach-msm/devices-msm8960.c b/arch/arm/mach-msm/devices-msm8960.c
new file mode 100644
index 000000000000..d9e1f26475de
--- /dev/null
+++ b/arch/arm/mach-msm/devices-msm8960.c
@@ -0,0 +1,85 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/irqs-8960.h>
+#include <mach/board.h>
+
+#include "devices.h"
+
+#define MSM_GSBI2_PHYS 0x16100000
+#define MSM_UART2DM_PHYS (MSM_GSBI2_PHYS + 0x40000)
+
+#define MSM_GSBI5_PHYS 0x16400000
+#define MSM_UART5DM_PHYS (MSM_GSBI5_PHYS + 0x40000)
+
+static struct resource resources_uart_gsbi2[] = {
+ {
+ .start = GSBI2_UARTDM_IRQ,
+ .end = GSBI2_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART2DM_PHYS,
+ .end = MSM_UART2DM_PHYS + PAGE_SIZE - 1,
+ .name = "uart_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI2_PHYS,
+ .end = MSM_GSBI2_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_device_uart_gsbi2 = {
+ .name = "msm_serial",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi2),
+ .resource = resources_uart_gsbi2,
+};
+
+static struct resource resources_uart_gsbi5[] = {
+ {
+ .start = GSBI5_UARTDM_IRQ,
+ .end = GSBI5_UARTDM_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM_UART5DM_PHYS,
+ .end = MSM_UART5DM_PHYS + PAGE_SIZE - 1,
+ .name = "uart_resource",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_GSBI5_PHYS,
+ .end = MSM_GSBI5_PHYS + PAGE_SIZE - 1,
+ .name = "gsbi_resource",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_device_uart_gsbi5 = {
+ .name = "msm_serial",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(resources_uart_gsbi5),
+ .resource = resources_uart_gsbi5,
+};
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index a4b798f20ccb..12d8deb78d9c 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,8 +15,9 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
-
+#include <linux/clkdev.h>
#include <linux/dma-mapping.h>
+
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
#include <mach/dma.h>
@@ -27,6 +28,7 @@
#include <asm/mach/flash.h>
#include <mach/mmc.h>
+#include "clock-pcom.h"
static struct resource resources_uart3[] = {
{
@@ -38,6 +40,7 @@ static struct resource resources_uart3[] = {
.start = MSM_UART3_PHYS,
.end = MSM_UART3_PHYS + MSM_UART3_SIZE - 1,
.flags = IORESOURCE_MEM,
+ .name = "uart_resource"
},
};
@@ -124,14 +127,204 @@ struct platform_device msm_device_hsusb_host = {
},
};
-struct clk msm_clocks_8x50[] = {
+static struct resource resources_sdc1[] = {
+ {
+ .start = MSM_SDC1_PHYS,
+ .end = MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SDC1_0,
+ .end = INT_SDC1_0,
+ .flags = IORESOURCE_IRQ,
+ .name = "cmd_irq",
+ },
+ {
+ .start = INT_SDC1_1,
+ .end = INT_SDC1_1,
+ .flags = IORESOURCE_IRQ,
+ .name = "pio_irq",
+ },
+ {
+ .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
+ .name = "status_irq"
+ },
+ {
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource resources_sdc2[] = {
+ {
+ .start = MSM_SDC2_PHYS,
+ .end = MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SDC2_0,
+ .end = INT_SDC2_0,
+ .flags = IORESOURCE_IRQ,
+ .name = "cmd_irq",
+ },
+ {
+ .start = INT_SDC2_1,
+ .end = INT_SDC2_1,
+ .flags = IORESOURCE_IRQ,
+ .name = "pio_irq",
+ },
+ {
+ .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
+ .name = "status_irq"
+ },
+ {
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource resources_sdc3[] = {
+ {
+ .start = MSM_SDC3_PHYS,
+ .end = MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SDC3_0,
+ .end = INT_SDC3_0,
+ .flags = IORESOURCE_IRQ,
+ .name = "cmd_irq",
+ },
+ {
+ .start = INT_SDC3_1,
+ .end = INT_SDC3_1,
+ .flags = IORESOURCE_IRQ,
+ .name = "pio_irq",
+ },
+ {
+ .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
+ .name = "status_irq"
+ },
+ {
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static struct resource resources_sdc4[] = {
+ {
+ .start = MSM_SDC4_PHYS,
+ .end = MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_SDC4_0,
+ .end = INT_SDC4_0,
+ .flags = IORESOURCE_IRQ,
+ .name = "cmd_irq",
+ },
+ {
+ .start = INT_SDC4_1,
+ .end = INT_SDC4_1,
+ .flags = IORESOURCE_IRQ,
+ .name = "pio_irq",
+ },
+ {
+ .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED,
+ .name = "status_irq"
+ },
+ {
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device msm_device_sdc1 = {
+ .name = "msm_sdcc",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(resources_sdc1),
+ .resource = resources_sdc1,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm_device_sdc2 = {
+ .name = "msm_sdcc",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(resources_sdc2),
+ .resource = resources_sdc2,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm_device_sdc3 = {
+ .name = "msm_sdcc",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(resources_sdc3),
+ .resource = resources_sdc3,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+struct platform_device msm_device_sdc4 = {
+ .name = "msm_sdcc",
+ .id = 4,
+ .num_resources = ARRAY_SIZE(resources_sdc4),
+ .resource = resources_sdc4,
+ .dev = {
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+static struct platform_device *msm_sdcc_devices[] __initdata = {
+ &msm_device_sdc1,
+ &msm_device_sdc2,
+ &msm_device_sdc3,
+ &msm_device_sdc4,
+};
+
+int __init msm_add_sdcc(unsigned int controller,
+ struct msm_mmc_platform_data *plat,
+ unsigned int stat_irq, unsigned long stat_irq_flags)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+
+ if (controller < 1 || controller > 4)
+ return -EINVAL;
+
+ pdev = msm_sdcc_devices[controller-1];
+ pdev->dev.platform_data = plat;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq");
+ if (!res)
+ return -EINVAL;
+ else if (stat_irq) {
+ res->start = res->end = stat_irq;
+ res->flags &= ~IORESOURCE_DISABLED;
+ res->flags |= stat_irq_flags;
+ }
+
+ return platform_device_register(pdev);
+}
+
+struct clk_lookup msm_clocks_8x50[] = {
CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
+ CLK_PCOM("ce_clk", CE_CLK, NULL, 0),
CLK_PCOM("ebi1_clk", EBI1_CLK, NULL, CLK_MIN),
CLK_PCOM("ebi2_clk", EBI2_CLK, NULL, 0),
CLK_PCOM("ecodec_clk", ECODEC_CLK, NULL, 0),
CLK_PCOM("emdh_clk", EMDH_CLK, NULL, OFF | CLK_MINMAX),
CLK_PCOM("gp_clk", GP_CLK, NULL, 0),
CLK_PCOM("grp_clk", GRP_3D_CLK, NULL, 0),
+ CLK_PCOM("i2c_clk", I2C_CLK, NULL, 0),
CLK_PCOM("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0),
CLK_PCOM("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0),
CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF),
@@ -144,12 +337,24 @@ struct clk msm_clocks_8x50[] = {
CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN),
CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0),
CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF),
+ CLK_PCOM("sdc_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_PCOM("sdc_pclk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_PCOM("sdc_pclk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, "msm_sdcc.3", OFF),
+ CLK_PCOM("sdc_pclk", SDC3_P_CLK, "msm_sdcc.3", OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, "msm_sdcc.4", OFF),
+ CLK_PCOM("sdc_pclk", SDC4_P_CLK, "msm_sdcc.4", OFF),
CLK_PCOM("spi_clk", SPI_CLK, NULL, 0),
CLK_PCOM("tsif_clk", TSIF_CLK, NULL, 0),
CLK_PCOM("tsif_ref_clk", TSIF_REF_CLK, NULL, 0),
CLK_PCOM("tv_dac_clk", TV_DAC_CLK, NULL, 0),
CLK_PCOM("tv_enc_clk", TV_ENC_CLK, NULL, 0),
- CLK_PCOM("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF),
+ CLK_PCOM("uart_clk", UART1_CLK, NULL, OFF),
+ CLK_PCOM("uart_clk", UART2_CLK, NULL, 0),
+ CLK_PCOM("uart_clk", UART3_CLK, "msm_serial.2", OFF),
+ CLK_PCOM("uartdm_clk", UART1DM_CLK, NULL, OFF),
+ CLK_PCOM("uartdm_clk", UART2DM_CLK, NULL, 0),
CLK_PCOM("usb_hs_clk", USB_HS_CLK, NULL, OFF),
CLK_PCOM("usb_hs_pclk", USB_HS_P_CLK, NULL, OFF),
CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 87c70bfce2bd..9545c196c6e8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -16,12 +16,17 @@
#ifndef __ARCH_ARM_MACH_MSM_DEVICES_H
#define __ARCH_ARM_MACH_MSM_DEVICES_H
+#include <linux/clkdev.h>
+
#include "clock.h"
extern struct platform_device msm_device_uart1;
extern struct platform_device msm_device_uart2;
extern struct platform_device msm_device_uart3;
+extern struct platform_device msm8960_device_uart_gsbi2;
+extern struct platform_device msm8960_device_uart_gsbi5;
+
extern struct platform_device msm_device_sdc1;
extern struct platform_device msm_device_sdc2;
extern struct platform_device msm_device_sdc3;
@@ -41,13 +46,13 @@ extern struct platform_device msm_device_mddi0;
extern struct platform_device msm_device_mddi1;
extern struct platform_device msm_device_mdp;
-extern struct clk msm_clocks_7x01a[];
+extern struct clk_lookup msm_clocks_7x01a[];
extern unsigned msm_num_clocks_7x01a;
-extern struct clk msm_clocks_7x30[];
+extern struct clk_lookup msm_clocks_7x30[];
extern unsigned msm_num_clocks_7x30;
-extern struct clk msm_clocks_8x50[];
+extern struct clk_lookup msm_clocks_8x50[];
extern unsigned msm_num_clocks_8x50;
#endif
diff --git a/arch/arm/mach-msm/gpiomux-7x30.c b/arch/arm/mach-msm/gpiomux-7x30.c
deleted file mode 100644
index 6ce41c5241a5..000000000000
--- a/arch/arm/mach-msm/gpiomux-7x30.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-#include "gpiomux.h"
-
-struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
- [49] = { /* UART2 RFR */
- .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
- GPIOMUX_FUNC_2 | GPIOMUX_VALID,
- },
- [50] = { /* UART2 CTS */
- .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
- GPIOMUX_FUNC_2 | GPIOMUX_VALID,
- },
- [51] = { /* UART2 RX */
- .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
- GPIOMUX_FUNC_2 | GPIOMUX_VALID,
- },
- [52] = { /* UART2 TX */
- .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
- GPIOMUX_FUNC_2 | GPIOMUX_VALID,
- },
-#endif
-};
diff --git a/arch/arm/mach-msm/gpiomux-8x50.c b/arch/arm/mach-msm/gpiomux-8x50.c
index 4406e0f4ae95..f7a4ea593c95 100644
--- a/arch/arm/mach-msm/gpiomux-8x50.c
+++ b/arch/arm/mach-msm/gpiomux-8x50.c
@@ -16,6 +16,19 @@
*/
#include "gpiomux.h"
+#if defined(CONFIG_MMC_MSM) || defined(CONFIG_MMC_MSM_MODULE)
+ #define SDCC_DAT_0_3_CMD_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_UP\
+ | GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
+ #define SDCC_CLK_ACTV_CFG (GPIOMUX_VALID | GPIOMUX_PULL_NONE\
+ | GPIOMUX_FUNC_1 | GPIOMUX_DRV_8MA)
+#else
+ #define SDCC_DAT_0_3_CMD_ACTV_CFG 0
+ #define SDCC_CLK_ACTV_CFG 0
+#endif
+
+#define SDC1_SUSPEND_CONFIG (GPIOMUX_VALID | GPIOMUX_PULL_DOWN\
+ | GPIOMUX_FUNC_GPIO | GPIOMUX_DRV_2MA)
+
struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
[86] = { /* UART3 RX */
.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
@@ -25,4 +38,14 @@ struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
GPIOMUX_FUNC_1 | GPIOMUX_VALID,
},
+ /* SDC1 data[3:0] & CMD */
+ [51 ... 55] = {
+ .active = SDCC_DAT_0_3_CMD_ACTV_CFG,
+ .suspended = SDC1_SUSPEND_CONFIG
+ },
+ /* SDC1 CLK */
+ [56] = {
+ .active = SDCC_CLK_ACTV_CFG,
+ .suspended = SDC1_SUSPEND_CONFIG
+ },
};
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index d0c214338df9..0c631a9f8647 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -11,7 +11,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
- __INIT
+ __CPUINIT
/*
* MSM specific entry point for secondary CPUs. This provides
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 6abf4a6eadc1..2ce8f1f2fc4d 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -31,7 +31,7 @@ struct msm_acpu_clock_platform_data
unsigned long wait_for_irq_khz;
};
-struct clk;
+struct clk_lookup;
extern struct sys_timer msm_timer;
@@ -41,7 +41,7 @@ void __init msm_add_devices(void);
void __init msm_map_common_io(void);
void __init msm_init_irq(void);
void __init msm_init_gpio(void);
-void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks);
+void __init msm_clock_init(struct clk_lookup *clock_tbl, unsigned num_clocks);
void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
int __init msm_add_sdcc(unsigned int controller,
struct msm_mmc_platform_data *plat,
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
index c05ca40478c7..e8d38428d813 100644
--- a/arch/arm/mach-msm/include/mach/clk.h
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __MACH_CLK_H
#define __MACH_CLK_H
diff --git a/arch/arm/mach-msm/include/mach/clkdev.h b/arch/arm/mach-msm/include/mach/clkdev.h
new file mode 100644
index 000000000000..f87a57b59534
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clkdev.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __ASM_ARCH_MSM_CLKDEV_H
+#define __ASM_ARCH_MSM_CLKDEV_H
+
+struct clk;
+
+static inline int __clk_get(struct clk *clk) { return 1; }
+static inline void __clk_put(struct clk *clk) { }
+#endif
diff --git a/arch/arm/mach-msm/include/mach/cpu.h b/arch/arm/mach-msm/include/mach/cpu.h
new file mode 100644
index 000000000000..a9481b08d5c7
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/cpu.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CPU_H__
+#define __ARCH_ARM_MACH_MSM_CPU_H__
+
+/* TODO: For now, only one CPU can be compiled at a time. */
+
+#define cpu_is_msm7x01() 0
+#define cpu_is_msm7x30() 0
+#define cpu_is_qsd8x50() 0
+#define cpu_is_msm8x60() 0
+#define cpu_is_msm8960() 0
+
+#ifdef CONFIG_ARCH_MSM7X00A
+# undef cpu_is_msm7x01
+# define cpu_is_msm7x01() 1
+#endif
+
+#ifdef CONFIG_ARCH_MSM7X30
+# undef cpu_is_msm7x30
+# define cpu_is_msm7x30() 1
+#endif
+
+#ifdef CONFIG_ARCH_QSD8X50
+# undef cpu_is_qsd8x50
+# define cpu_is_qsd8x50() 1
+#endif
+
+#ifdef CONFIG_ARCH_MSM8X60
+# undef cpu_is_msm8x60
+# define cpu_is_msm8x60() 1
+#endif
+
+#ifdef CONFIG_ARCH_MSM8960
+# undef cpu_is_msm8960
+# define cpu_is_msm8960() 1
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h
index 7386e732baad..dc1b928745e9 100644
--- a/arch/arm/mach-msm/include/mach/io.h
+++ b/arch/arm/mach-msm/include/mach/io.h
@@ -29,6 +29,7 @@ void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int m
void msm_map_qsd8x50_io(void);
void msm_map_msm7x30_io(void);
void msm_map_msm8x60_io(void);
+void msm_map_msm8960_io(void);
extern unsigned int msm_shared_ram_phys;
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 296c0f10f230..5c7c955e6d25 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#define MSM_IOMMU_H
#include <linux/interrupt.h>
+#include <linux/clk.h>
/* Sharability attributes of MSM IOMMU mappings */
#define MSM_IOMMU_ATTR_NON_SH 0x0
@@ -44,14 +45,11 @@
/**
* struct msm_iommu_dev - a single IOMMU hardware instance
* name Human-readable name given to this IOMMU HW instance
- * clk_rate Rate to set for this IOMMU's clock, if applicable to this
- * particular IOMMU. 0 means don't set a rate.
- * -1 means it is an AXI clock with no valid rate
- *
+ * ncb Number of context banks present on this IOMMU HW instance
*/
struct msm_iommu_dev {
const char *name;
- int clk_rate;
+ int ncb;
};
/**
@@ -73,14 +71,20 @@ struct msm_iommu_ctx_dev {
/**
* struct msm_iommu_drvdata - A single IOMMU hardware instance
* @base: IOMMU config port base address (VA)
+ * @ncb The number of contexts on this IOMMU
* @irq: Interrupt number
- *
+ * @clk: The bus clock for this IOMMU hardware instance
+ * @pclk: The clock for the IOMMU bus interconnect
+ *
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
*/
struct msm_iommu_drvdata {
void __iomem *base;
int irq;
+ int ncb;
+ struct clk *clk;
+ struct clk *pclk;
};
/**
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
index c2c3da9444f4..fc160101dead 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -68,6 +68,7 @@ do { \
#define FL_CACHEABLE (1 << 3)
#define FL_TEX0 (1 << 12)
#define FL_OFFSET(va) (((va) & 0xFFF00000) >> 20)
+#define FL_NG (1 << 17)
/* Second-level page table bits */
#define SL_BASE_MASK_LARGE 0xFFFF0000
@@ -81,6 +82,7 @@ do { \
#define SL_CACHEABLE (1 << 3)
#define SL_TEX0 (1 << 6)
#define SL_OFFSET(va) (((va) & 0xFF000) >> 12)
+#define SL_NG (1 << 11)
/* Memory type and cache policy attributes */
#define MT_SO 0
@@ -623,20 +625,6 @@ do { \
#define SET_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PSR, INDEX, v)
-/* V2Pxx UW UR PW PR */
-#define SET_V2PUW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX, v)
-#define SET_V2PUW_VA(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA, v)
-
-#define SET_V2PUR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX, v)
-#define SET_V2PUR_VA(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA, v)
-
-#define SET_V2PPW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX, v)
-#define SET_V2PPW_VA(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA, v)
-
-#define SET_V2PPR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX, v)
-#define SET_V2PPR_VA(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA, v)
-
-
/* Context Register getters */
/* ACTLR */
#define GET_CFERE(b, c) GET_CONTEXT_FIELD(b, c, ACTLR, CFERE)
@@ -824,20 +812,6 @@ do { \
#define GET_INDEX(b, c) GET_CONTEXT_FIELD(b, c, V2PSR, INDEX)
-/* V2Pxx UW UR PW PR */
-#define GET_V2PUW_INDEX(b, c) GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX)
-#define GET_V2PUW_VA(b, c) GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA)
-
-#define GET_V2PUR_INDEX(b, c) GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX)
-#define GET_V2PUR_VA(b, c) GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA)
-
-#define GET_V2PPW_INDEX(b, c) GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX)
-#define GET_V2PPW_VA(b, c) GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA)
-
-#define GET_V2PPR_INDEX(b, c) GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX)
-#define GET_V2PPR_VA(b, c) GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA)
-
-
/* Global Registers */
#define M2VCBR_N (0xFF000)
#define CBACR_N (0xFF800)
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h
index 67c5396514fe..1f15902655fd 100644
--- a/arch/arm/mach-msm/include/mach/irqs-7x30.h
+++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ASM_ARCH_MSM_IRQS_7X30_H
diff --git a/arch/arm/mach-msm/include/mach/irqs-8960.h b/arch/arm/mach-msm/include/mach/irqs-8960.h
new file mode 100644
index 000000000000..81ab2a6792bd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8960.h
@@ -0,0 +1,277 @@
+/* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8960_H
+#define __ASM_ARCH_MSM_IRQS_8960_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/* 0-15: STI/SGI (software triggered/generated interrupts)
+ 16-31: PPI (private peripheral interrupts)
+ 32+: SPI (shared peripheral interrupts) */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_VGIC (GIC_PPI_START + 0)
+#define INT_DEBUG_TIMER_EXP (GIC_PPI_START + 1)
+#define INT_GP_TIMER_EXP (GIC_PPI_START + 2)
+#define INT_GP_TIMER2_EXP (GIC_PPI_START + 3)
+#define WDT0_ACCSCSSNBARK_INT (GIC_PPI_START + 4)
+#define WDT1_ACCSCSSNBARK_INT (GIC_PPI_START + 5)
+#define AVS_SVICINT (GIC_PPI_START + 6)
+#define AVS_SVICINTSWDONE (GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMRXFULL (GIC_PPI_START + 8)
+#define CPU_DBGCPUXCOMMTXEMPTY (GIC_PPI_START + 9)
+#define CPU_SICCPUXPERFMONIRPTREQ (GIC_PPI_START + 10)
+#define SC_AVSCPUXDOWN (GIC_PPI_START + 11)
+#define SC_AVSCPUXUP (GIC_PPI_START + 12)
+#define SC_SICCPUXACGIRPTREQ (GIC_PPI_START + 13)
+#define SC_SICCPUXEXTFAULTIRPTREQ (GIC_PPI_START + 14)
+/* PPI 15 is unused */
+
+#define SC_SICMPUIRPTREQ (GIC_SPI_START + 0)
+#define SC_SICL2IRPTREQ (GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ (GIC_SPI_START + 2)
+#define SC_SICAGCIRPTREQ (GIC_SPI_START + 3)
+#define TLMM_APCC_DIR_CONN_IRQ_0 (GIC_SPI_START + 4)
+#define TLMM_APCC_DIR_CONN_IRQ_1 (GIC_SPI_START + 5)
+#define TLMM_APCC_DIR_CONN_IRQ_2 (GIC_SPI_START + 6)
+#define TLMM_APCC_DIR_CONN_IRQ_3 (GIC_SPI_START + 7)
+#define TLMM_APCC_DIR_CONN_IRQ_4 (GIC_SPI_START + 8)
+#define TLMM_APCC_DIR_CONN_IRQ_5 (GIC_SPI_START + 9)
+#define TLMM_APCC_DIR_CONN_IRQ_6 (GIC_SPI_START + 10)
+#define TLMM_APCC_DIR_CONN_IRQ_7 (GIC_SPI_START + 11)
+#define TLMM_APCC_DIR_CONN_IRQ_8 (GIC_SPI_START + 12)
+#define TLMM_APCC_DIR_CONN_IRQ_9 (GIC_SPI_START + 13)
+#define PM8921_SEC_IRQ_103 (GIC_SPI_START + 14)
+#define PM8018_SEC_IRQ_106 (GIC_SPI_START + 15)
+#define TLMM_APCC_SUMMARY_IRQ (GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ (GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ (GIC_SPI_START + 18)
+#define RPM_APCC_CPU0_GP_HIGH_IRQ (GIC_SPI_START + 19)
+#define RPM_APCC_CPU0_GP_MEDIUM_IRQ (GIC_SPI_START + 20)
+#define RPM_APCC_CPU0_GP_LOW_IRQ (GIC_SPI_START + 21)
+#define RPM_APCC_CPU0_WAKE_UP_IRQ (GIC_SPI_START + 22)
+#define RPM_APCC_CPU1_GP_HIGH_IRQ (GIC_SPI_START + 23)
+#define RPM_APCC_CPU1_GP_MEDIUM_IRQ (GIC_SPI_START + 24)
+#define RPM_APCC_CPU1_GP_LOW_IRQ (GIC_SPI_START + 25)
+#define RPM_APCC_CPU1_WAKE_UP_IRQ (GIC_SPI_START + 26)
+#define SSBI2_2_SC_CPU0_SECURE_IRQ (GIC_SPI_START + 27)
+#define SSBI2_2_SC_CPU0_NON_SECURE_IRQ (GIC_SPI_START + 28)
+#define SSBI2_1_SC_CPU0_SECURE_IRQ (GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_IRQ (GIC_SPI_START + 30)
+#define MSMC_SC_SEC_CE_IRQ (GIC_SPI_START + 31)
+#define MSMC_SC_PRI_CE_IRQ (GIC_SPI_START + 32)
+#define SLIMBUS0_CORE_EE1_IRQ (GIC_SPI_START + 33)
+#define SLIMBUS0_BAM_EE1_IRQ (GIC_SPI_START + 34)
+#define Q6FW_WDOG_EXPIRED_IRQ (GIC_SPI_START + 35)
+#define Q6SW_WDOG_EXPIRED_IRQ (GIC_SPI_START + 36)
+#define MSS_TO_APPS_IRQ_0 (GIC_SPI_START + 37)
+#define MSS_TO_APPS_IRQ_1 (GIC_SPI_START + 38)
+#define MSS_TO_APPS_IRQ_2 (GIC_SPI_START + 39)
+#define MSS_TO_APPS_IRQ_3 (GIC_SPI_START + 40)
+#define MSS_TO_APPS_IRQ_4 (GIC_SPI_START + 41)
+#define MSS_TO_APPS_IRQ_5 (GIC_SPI_START + 42)
+#define MSS_TO_APPS_IRQ_6 (GIC_SPI_START + 43)
+#define MSS_TO_APPS_IRQ_7 (GIC_SPI_START + 44)
+#define MSS_TO_APPS_IRQ_8 (GIC_SPI_START + 45)
+#define MSS_TO_APPS_IRQ_9 (GIC_SPI_START + 46)
+#define VPE_IRQ (GIC_SPI_START + 47)
+#define VFE_IRQ (GIC_SPI_START + 48)
+#define VCODEC_IRQ (GIC_SPI_START + 49)
+#define TV_ENC_IRQ (GIC_SPI_START + 50)
+#define SMMU_VPE_CB_SC_SECURE_IRQ (GIC_SPI_START + 51)
+#define SMMU_VPE_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 52)
+#define SMMU_VFE_CB_SC_SECURE_IRQ (GIC_SPI_START + 53)
+#define SMMU_VFE_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 54)
+#define SMMU_VCODEC_B_CB_SC_SECURE_IRQ (GIC_SPI_START + 55)
+#define SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 56)
+#define SMMU_VCODEC_A_CB_SC_SECURE_IRQ (GIC_SPI_START + 57)
+#define SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 58)
+#define SMMU_ROT_CB_SC_SECURE_IRQ (GIC_SPI_START + 59)
+#define SMMU_ROT_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 60)
+#define SMMU_MDP1_CB_SC_SECURE_IRQ (GIC_SPI_START + 61)
+#define SMMU_MDP1_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 62)
+#define SMMU_MDP0_CB_SC_SECURE_IRQ (GIC_SPI_START + 63)
+#define SMMU_MDP0_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 64)
+#define SMMU_JPEGD_CB_SC_SECURE_IRQ (GIC_SPI_START + 65)
+#define SMMU_JPEGD_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 66)
+#define SMMU_IJPEG_CB_SC_SECURE_IRQ (GIC_SPI_START + 67)
+#define SMMU_IJPEG_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 68)
+#define SMMU_GFX3D_CB_SC_SECURE_IRQ (GIC_SPI_START + 69)
+#define SMMU_GFX3D_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 70)
+#define SMMU_GFX2D0_CB_SC_SECURE_IRQ (GIC_SPI_START + 71)
+#define SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 72)
+#define ROT_IRQ (GIC_SPI_START + 73)
+#define MMSS_FABRIC_IRQ (GIC_SPI_START + 74)
+#define MDP_IRQ (GIC_SPI_START + 75)
+#define JPEGD_IRQ (GIC_SPI_START + 76)
+#define JPEG_IRQ (GIC_SPI_START + 77)
+#define MMSS_IMEM_IRQ (GIC_SPI_START + 78)
+#define HDMI_IRQ (GIC_SPI_START + 79)
+#define GFX3D_IRQ (GIC_SPI_START + 80)
+#define GFX2D0_IRQ (GIC_SPI_START + 81)
+#define DSI1_IRQ (GIC_SPI_START + 82)
+#define CSI_1_IRQ (GIC_SPI_START + 83)
+#define CSI_0_IRQ (GIC_SPI_START + 84)
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ (GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ (GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED (GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ (GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ (GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ (GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ (GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ (GIC_SPI_START + 92)
+#define FABRIC_APPS_IRQ (GIC_SPI_START + 93)
+#define USB1_HS_BAM_IRQ (GIC_SPI_START + 94)
+#define SDC4_BAM_IRQ (GIC_SPI_START + 95)
+#define SDC3_BAM_IRQ (GIC_SPI_START + 96)
+#define SDC2_BAM_IRQ (GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ (GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ (GIC_SPI_START + 99)
+#define USB1_HS_IRQ (GIC_SPI_START + 100)
+#define SDC4_IRQ_0 (GIC_SPI_START + 101)
+#define SDC3_IRQ_0 (GIC_SPI_START + 102)
+#define SDC2_IRQ_0 (GIC_SPI_START + 103)
+#define SDC1_IRQ_0 (GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ (GIC_SPI_START + 106)
+#define SPS_MTI_0 (GIC_SPI_START + 107)
+#define SPS_MTI_1 (GIC_SPI_START + 108)
+#define SPS_MTI_2 (GIC_SPI_START + 109)
+#define SPS_MTI_3 (GIC_SPI_START + 110)
+#define SPS_MTI_4 (GIC_SPI_START + 111)
+#define SPS_MTI_5 (GIC_SPI_START + 112)
+#define SPS_MTI_6 (GIC_SPI_START + 113)
+#define SPS_MTI_7 (GIC_SPI_START + 114)
+#define SPS_MTI_8 (GIC_SPI_START + 115)
+#define SPS_MTI_9 (GIC_SPI_START + 116)
+#define SPS_MTI_10 (GIC_SPI_START + 117)
+#define SPS_MTI_11 (GIC_SPI_START + 118)
+#define SPS_MTI_12 (GIC_SPI_START + 119)
+#define SPS_MTI_13 (GIC_SPI_START + 120)
+#define SPS_MTI_14 (GIC_SPI_START + 121)
+#define SPS_MTI_15 (GIC_SPI_START + 122)
+#define SPS_MTI_16 (GIC_SPI_START + 123)
+#define SPS_MTI_17 (GIC_SPI_START + 124)
+#define SPS_MTI_18 (GIC_SPI_START + 125)
+#define SPS_MTI_19 (GIC_SPI_START + 126)
+#define SPS_MTI_20 (GIC_SPI_START + 127)
+#define SPS_MTI_21 (GIC_SPI_START + 128)
+#define SPS_MTI_22 (GIC_SPI_START + 129)
+#define SPS_MTI_23 (GIC_SPI_START + 130)
+#define SPS_MTI_24 (GIC_SPI_START + 131)
+#define SPS_MTI_25 (GIC_SPI_START + 132)
+#define SPS_MTI_26 (GIC_SPI_START + 133)
+#define SPS_MTI_27 (GIC_SPI_START + 134)
+#define SPS_MTI_28 (GIC_SPI_START + 135)
+#define SPS_MTI_29 (GIC_SPI_START + 136)
+#define SPS_MTI_30 (GIC_SPI_START + 137)
+#define SPS_MTI_31 (GIC_SPI_START + 138)
+#define CSIPHY_4LN_IRQ (GIC_SPI_START + 139)
+#define CSIPHY_2LN_IRQ (GIC_SPI_START + 140)
+#define USB2_IRQ (GIC_SPI_START + 141)
+#define USB1_IRQ (GIC_SPI_START + 142)
+#define TSSC_SSBI_IRQ (GIC_SPI_START + 143)
+#define TSSC_SAMPLE_IRQ (GIC_SPI_START + 144)
+#define TSSC_PENUP_IRQ (GIC_SPI_START + 145)
+#define GSBI1_UARTDM_IRQ (GIC_SPI_START + 146)
+#define GSBI1_QUP_IRQ (GIC_SPI_START + 147)
+#define GSBI2_UARTDM_IRQ (GIC_SPI_START + 148)
+#define GSBI2_QUP_IRQ (GIC_SPI_START + 149)
+#define GSBI3_UARTDM_IRQ (GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ (GIC_SPI_START + 151)
+#define GSBI4_UARTDM_IRQ (GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ (GIC_SPI_START + 153)
+#define GSBI5_UARTDM_IRQ (GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ (GIC_SPI_START + 155)
+#define GSBI6_UARTDM_IRQ (GIC_SPI_START + 156)
+#define GSBI6_QUP_IRQ (GIC_SPI_START + 157)
+#define GSBI7_UARTDM_IRQ (GIC_SPI_START + 158)
+#define GSBI7_QUP_IRQ (GIC_SPI_START + 159)
+#define GSBI8_UARTDM_IRQ (GIC_SPI_START + 160)
+#define GSBI8_QUP_IRQ (GIC_SPI_START + 161)
+#define TSIF_TSPP_IRQ (GIC_SPI_START + 162)
+#define TSIF_BAM_IRQ (GIC_SPI_START + 163)
+#define TSIF2_IRQ (GIC_SPI_START + 164)
+#define TSIF1_IRQ (GIC_SPI_START + 165)
+#define DSI2_IRQ (GIC_SPI_START + 166)
+#define ISPIF_IRQ (GIC_SPI_START + 167)
+#define MSMC_SC_SEC_TMR_IRQ (GIC_SPI_START + 168)
+#define MSMC_SC_SEC_WDOG_BARK_IRQ (GIC_SPI_START + 169)
+#define INT_ADM0_SCSS_0_IRQ (GIC_SPI_START + 170)
+#define INT_ADM0_SCSS_1_IRQ (GIC_SPI_START + 171)
+#define INT_ADM0_SCSS_2_IRQ (GIC_SPI_START + 172)
+#define INT_ADM0_SCSS_3_IRQ (GIC_SPI_START + 173)
+#define CC_SCSS_WDT1CPU1BITEEXPIRED (GIC_SPI_START + 174)
+#define CC_SCSS_WDT1CPU0BITEEXPIRED (GIC_SPI_START + 175)
+#define CC_SCSS_WDT0CPU1BITEEXPIRED (GIC_SPI_START + 176)
+#define CC_SCSS_WDT0CPU0BITEEXPIRED (GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT (GIC_SPI_START + 178)
+#define SSBI2_2_SC_CPU1_SECURE_INT (GIC_SPI_START + 179)
+#define SSBI2_2_SC_CPU1_NON_SECURE_INT (GIC_SPI_START + 180)
+#define SSBI2_1_SC_CPU1_SECURE_INT (GIC_SPI_START + 181)
+#define SSBI2_1_SC_CPU1_NON_SECURE_INT (GIC_SPI_START + 182)
+#define XPU_SUMMARY_IRQ (GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ (GIC_SPI_START + 184)
+#define HSDDRX_EBI1CH0_IRQ (GIC_SPI_START + 185)
+#define HSDDRX_EBI1CH1_IRQ (GIC_SPI_START + 186)
+#define SDC5_BAM_IRQ (GIC_SPI_START + 187)
+#define SDC5_IRQ_0 (GIC_SPI_START + 188)
+#define GSBI9_UARTDM_IRQ (GIC_SPI_START + 189)
+#define GSBI9_QUP_IRQ (GIC_SPI_START + 190)
+#define GSBI10_UARTDM_IRQ (GIC_SPI_START + 191)
+#define GSBI10_QUP_IRQ (GIC_SPI_START + 192)
+#define GSBI11_UARTDM_IRQ (GIC_SPI_START + 193)
+#define GSBI11_QUP_IRQ (GIC_SPI_START + 194)
+#define GSBI12_UARTDM_IRQ (GIC_SPI_START + 195)
+#define GSBI12_QUP_IRQ (GIC_SPI_START + 196)
+#define RIVA_APSS_LTECOEX_IRQ (GIC_SPI_START + 197)
+#define RIVA_APSS_SPARE_IRQ (GIC_SPI_START + 198)
+#define RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ (GIC_SPI_START + 199)
+#define RIVA_ASS_RESET_DONE_IRQ (GIC_SPI_START + 200)
+#define RIVA_APSS_ASIC_IRQ (GIC_SPI_START + 201)
+#define RIVA_APPS_WLAN_RX_DATA_AVAIL_IRQ (GIC_SPI_START + 202)
+#define RIVA_APPS_WLAN_DATA_XFER_DONE_IRQ (GIC_SPI_START + 203)
+#define RIVA_APPS_WLAM_SMSM_IRQ (GIC_SPI_START + 204)
+#define RIVA_APPS_LOG_CTRL_IRQ (GIC_SPI_START + 205)
+#define RIVA_APPS_FM_CTRL_IRQ (GIC_SPI_START + 206)
+#define RIVA_APPS_HCI_IRQ (GIC_SPI_START + 207)
+#define RIVA_APPS_WLAN_CTRL_IRQ (GIC_SPI_START + 208)
+#define A2_BAM_IRQ (GIC_SPI_START + 209)
+#define SMMU_GFX2D1_CB_SC_SECURE_IRQ (GIC_SPI_START + 210)
+#define SMMU_GFX2D1_CB_SC_NON_SECURE_IRQ (GIC_SPI_START + 211)
+#define GFX2D1_IRQ (GIC_SPI_START + 212)
+#define PPSS_WDOG_TIMER_IRQ (GIC_SPI_START + 213)
+#define SPS_SLIMBUS_CORE_EE0_IRQ (GIC_SPI_START + 214)
+#define SPS_SLIMBUS_BAM_EE0_IRQ (GIC_SPI_START + 215)
+#define QDSS_ETB_IRQ (GIC_SPI_START + 216)
+#define QDSS_CTI2KPSS_CPU1_IRQ (GIC_SPI_START + 217)
+#define QDSS_CTI2KPSS_CPU0_IRQ (GIC_SPI_START + 218)
+#define TLMM_APCC_DIR_CONN_IRQ_16 (GIC_SPI_START + 219)
+#define TLMM_APCC_DIR_CONN_IRQ_17 (GIC_SPI_START + 220)
+#define TLMM_APCC_DIR_CONN_IRQ_18 (GIC_SPI_START + 221)
+#define TLMM_APCC_DIR_CONN_IRQ_19 (GIC_SPI_START + 222)
+#define TLMM_APCC_DIR_CONN_IRQ_20 (GIC_SPI_START + 223)
+#define TLMM_APCC_DIR_CONN_IRQ_21 (GIC_SPI_START + 224)
+#define PM8921_SEC_IRQ_104 (GIC_SPI_START + 225)
+#define PM8018_SEC_IRQ_107 (GIC_SPI_START + 226)
+
+/* For now, use the maximum number of interrupts until a pending GIC issue
+ * is sorted out */
+#define NR_MSM_IRQS 1020
+#define NR_BOARD_IRQS 0
+#define NR_GPIO_IRQS 0
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x50.h b/arch/arm/mach-msm/include/mach/irqs-8x50.h
index de3d8fe24e4e..26adbe0e9406 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8x50.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8x50.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ASM_ARCH_MSM_IRQS_8XXX_H
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 8679a4564744..3cd78b165abb 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -26,6 +26,9 @@
#include "sirc.h"
#elif defined(CONFIG_ARCH_MSM8X60)
#include "irqs-8x60.h"
+#elif defined(CONFIG_ARCH_MSM8960)
+/* TODO: Make these not generic. */
+#include "irqs-8960.h"
#elif defined(CONFIG_ARCH_MSM_ARM11)
#include "irqs-7x00.h"
#else
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index 176875df241f..f2f8d299ba95 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -25,6 +25,8 @@
#define PLAT_PHYS_OFFSET UL(0x00200000)
#elif defined(CONFIG_ARCH_MSM8X60)
#define PLAT_PHYS_OFFSET UL(0x40200000)
+#elif defined(CONFIG_ARCH_MSM8960)
+#define PLAT_PHYS_OFFSET UL(0x40200000)
#else
#define PLAT_PHYS_OFFSET UL(0x10000000)
#endif
diff --git a/arch/arm/mach-msm/include/mach/mmc.h b/arch/arm/mach-msm/include/mach/mmc.h
index d54b6b086cff..5631b51cec46 100644
--- a/arch/arm/mach-msm/include/mach/mmc.h
+++ b/arch/arm/mach-msm/include/mach/mmc.h
@@ -15,12 +15,23 @@ struct embedded_sdio_data {
int num_funcs;
};
+struct msm_mmc_gpio {
+ unsigned no;
+ const char *name;
+};
+
+struct msm_mmc_gpio_data {
+ struct msm_mmc_gpio *gpio;
+ u8 size;
+};
+
struct msm_mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
u32 (*translate_vdd)(struct device *, unsigned int);
unsigned int (*status)(struct device *);
struct embedded_sdio_data *embedded_sdio;
int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
+ struct msm_mmc_gpio_data *gpio_data;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
index cfff0e74f128..8f99d97615a0 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/msm_iomap.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -47,13 +48,8 @@
#define MSM_VIC_PHYS 0xC0000000
#define MSM_VIC_SIZE SZ_4K
-#define MSM_CSR_BASE IOMEM(0xE0001000)
-#define MSM_CSR_PHYS 0xC0100000
-#define MSM_CSR_SIZE SZ_4K
-
-#define MSM_GPT_PHYS MSM_CSR_PHYS
-#define MSM_GPT_BASE MSM_CSR_BASE
-#define MSM_GPT_SIZE SZ_4K
+#define MSM7X00_CSR_PHYS 0xC0100000
+#define MSM7X00_CSR_SIZE SZ_4K
#define MSM_DMOV_BASE IOMEM(0xE0002000)
#define MSM_DMOV_PHYS 0xA9700000
@@ -130,10 +126,4 @@
#define MSM_AD5_SIZE (SZ_1M*13)
-#if defined(CONFIG_ARCH_MSM7X30)
-#define MSM_GCC_BASE IOMEM(0xF8009000)
-#define MSM_GCC_PHYS 0xC0182000
-#define MSM_GCC_SIZE SZ_4K
-#endif
-
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
index 0fd7b68ca114..4d84be15955e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011 Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -39,16 +39,8 @@
#define MSM_VIC_PHYS 0xC0080000
#define MSM_VIC_SIZE SZ_4K
-#define MSM_CSR_BASE IOMEM(0xE0001000)
-#define MSM_CSR_PHYS 0xC0100000
-#define MSM_CSR_SIZE SZ_4K
-
-#define MSM_TMR_PHYS MSM_CSR_PHYS
-#define MSM_TMR_BASE MSM_CSR_BASE
-#define MSM_TMR_SIZE SZ_4K
-
-#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
-#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
+#define MSM7X30_CSR_PHYS 0xC0100000
+#define MSM7X30_CSR_SIZE SZ_4K
#define MSM_DMOV_BASE IOMEM(0xE0002000)
#define MSM_DMOV_PHYS 0xAC400000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
new file mode 100644
index 000000000000..3c9d9602a318
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough. Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8960_H
+#define __ASM_ARCH_MSM_IOMAP_8960_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+
+#define MSM8960_QGIC_DIST_PHYS 0x02000000
+#define MSM8960_QGIC_DIST_SIZE SZ_4K
+
+#define MSM8960_QGIC_CPU_PHYS 0x02002000
+#define MSM8960_QGIC_CPU_SIZE SZ_4K
+
+#define MSM8960_TMR_PHYS 0x0200A000
+#define MSM8960_TMR_SIZE SZ_4K
+
+#define MSM8960_TMR0_PHYS 0x0208A000
+#define MSM8960_TMR0_SIZE SZ_4K
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
index acc819eb76e5..d4143201999f 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011 Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -39,16 +39,8 @@
#define MSM_VIC_PHYS 0xAC000000
#define MSM_VIC_SIZE SZ_4K
-#define MSM_CSR_BASE IOMEM(0xE0001000)
-#define MSM_CSR_PHYS 0xAC100000
-#define MSM_CSR_SIZE SZ_4K
-
-#define MSM_TMR_PHYS MSM_CSR_PHYS
-#define MSM_TMR_BASE MSM_CSR_BASE
-#define MSM_TMR_SIZE SZ_4K
-
-#define MSM_GPT_BASE MSM_TMR_BASE
-#define MSM_DGT_BASE (MSM_TMR_BASE + 0x10)
+#define QSD8X50_CSR_PHYS 0xAC100000
+#define QSD8X50_CSR_SIZE SZ_4K
#define MSM_DMOV_BASE IOMEM(0xE0002000)
#define MSM_DMOV_PHYS 0xA9700000
@@ -132,16 +124,16 @@
#define MSM_UART2DM_PHYS 0xA0900000
-#define MSM_SDC1_PHYS 0xA0400000
+#define MSM_SDC1_PHYS 0xA0300000
#define MSM_SDC1_SIZE SZ_4K
-#define MSM_SDC2_PHYS 0xA0500000
+#define MSM_SDC2_PHYS 0xA0400000
#define MSM_SDC2_SIZE SZ_4K
-#define MSM_SDC3_PHYS 0xA0600000
+#define MSM_SDC3_PHYS 0xA0500000
#define MSM_SDC3_SIZE SZ_4K
-#define MSM_SDC4_PHYS 0xA0700000
+#define MSM_SDC4_PHYS 0xA0600000
#define MSM_SDC4_SIZE SZ_4K
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index a54e33b0882e..3b19b8f244b8 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -35,13 +35,11 @@
*
*/
-#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
-#define MSM_QGIC_DIST_PHYS 0x02080000
-#define MSM_QGIC_DIST_SIZE SZ_4K
+#define MSM8X60_QGIC_DIST_PHYS 0x02080000
+#define MSM8X60_QGIC_DIST_SIZE SZ_4K
-#define MSM_QGIC_CPU_BASE IOMEM(0xF0001000)
-#define MSM_QGIC_CPU_PHYS 0x02081000
-#define MSM_QGIC_CPU_SIZE SZ_4K
+#define MSM8X60_QGIC_CPU_PHYS 0x02081000
+#define MSM8X60_QGIC_CPU_SIZE SZ_4K
#define MSM_ACC_BASE IOMEM(0xF0002000)
#define MSM_ACC_PHYS 0x02001000
@@ -58,51 +56,10 @@
#define MSM_SHARED_RAM_BASE IOMEM(0xF0100000)
#define MSM_SHARED_RAM_SIZE SZ_1M
-#define MSM_TMR_BASE IOMEM(0xF0200000)
-#define MSM_TMR_PHYS 0x02000000
-#define MSM_TMR_SIZE SZ_4K
+#define MSM8X60_TMR_PHYS 0x02000000
+#define MSM8X60_TMR_SIZE SZ_4K
-#define MSM_TMR0_BASE IOMEM(0xF0201000)
-#define MSM_TMR0_PHYS 0x02040000
-#define MSM_TMR0_SIZE SZ_4K
-
-#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
-#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
-
-#define MSM_IOMMU_JPEGD_PHYS 0x07300000
-#define MSM_IOMMU_JPEGD_SIZE SZ_1M
-
-#define MSM_IOMMU_VPE_PHYS 0x07400000
-#define MSM_IOMMU_VPE_SIZE SZ_1M
-
-#define MSM_IOMMU_MDP0_PHYS 0x07500000
-#define MSM_IOMMU_MDP0_SIZE SZ_1M
-
-#define MSM_IOMMU_MDP1_PHYS 0x07600000
-#define MSM_IOMMU_MDP1_SIZE SZ_1M
-
-#define MSM_IOMMU_ROT_PHYS 0x07700000
-#define MSM_IOMMU_ROT_SIZE SZ_1M
-
-#define MSM_IOMMU_IJPEG_PHYS 0x07800000
-#define MSM_IOMMU_IJPEG_SIZE SZ_1M
-
-#define MSM_IOMMU_VFE_PHYS 0x07900000
-#define MSM_IOMMU_VFE_SIZE SZ_1M
-
-#define MSM_IOMMU_VCODEC_A_PHYS 0x07A00000
-#define MSM_IOMMU_VCODEC_A_SIZE SZ_1M
-
-#define MSM_IOMMU_VCODEC_B_PHYS 0x07B00000
-#define MSM_IOMMU_VCODEC_B_SIZE SZ_1M
-
-#define MSM_IOMMU_GFX3D_PHYS 0x07C00000
-#define MSM_IOMMU_GFX3D_SIZE SZ_1M
-
-#define MSM_IOMMU_GFX2D0_PHYS 0x07D00000
-#define MSM_IOMMU_GFX2D0_SIZE SZ_1M
-
-#define MSM_IOMMU_GFX2D1_PHYS 0x07E00000
-#define MSM_IOMMU_GFX2D1_SIZE SZ_1M
+#define MSM8X60_TMR0_PHYS 0x02040000
+#define MSM8X60_TMR0_SIZE SZ_4K
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8e24dd812139..c98c7591f3b8 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -53,6 +53,13 @@
#include "msm_iomap-7x00.h"
#endif
+#include "msm_iomap-8960.h"
+/* Virtual addressses shared across all MSM targets. */
+#define MSM_CSR_BASE IOMEM(0xE0001000)
+#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
+#define MSM_QGIC_CPU_BASE IOMEM(0xF0001000)
+#define MSM_TMR_BASE IOMEM(0xF0200000)
+#define MSM_TMR0_BASE IOMEM(0xF0201000)
#endif
diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h
index 7281337ee28d..ef55868a5b8a 100644
--- a/arch/arm/mach-msm/include/mach/sirc.h
+++ b/arch/arm/mach-msm/include/mach/sirc.h
@@ -1,30 +1,13 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ASM_ARCH_MSM_SIRC_H
diff --git a/arch/arm/mach-msm/include/mach/smp.h b/arch/arm/mach-msm/include/mach/smp.h
index a95f7b9efe31..3c01000ecc80 100644
--- a/arch/arm/mach-msm/include/mach/smp.h
+++ b/arch/arm/mach-msm/include/mach/smp.h
@@ -1,29 +1,13 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Code Aurora nor
- * the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __ASM_ARCH_MSM_SMP_H
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1260007a9dd1..cec6ed1c91d3 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -3,7 +3,7 @@
* MSM7K, QSD io support
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -28,19 +28,20 @@
#include <mach/board.h>
-#define MSM_DEVICE(name) { \
+#define MSM_CHIP_DEVICE(name, chip) { \
.virtual = (unsigned long) MSM_##name##_BASE, \
- .pfn = __phys_to_pfn(MSM_##name##_PHYS), \
- .length = MSM_##name##_SIZE, \
+ .pfn = __phys_to_pfn(chip##_##name##_PHYS), \
+ .length = chip##_##name##_SIZE, \
.type = MT_DEVICE_NONSHARED, \
}
+#define MSM_DEVICE(name) MSM_CHIP_DEVICE(name, MSM)
+
#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X27) \
|| defined(CONFIG_ARCH_MSM7X25)
static struct map_desc msm_io_desc[] __initdata = {
MSM_DEVICE(VIC),
- MSM_DEVICE(CSR),
- MSM_DEVICE(GPT),
+ MSM_CHIP_DEVICE(CSR, MSM7X00),
MSM_DEVICE(DMOV),
MSM_DEVICE(GPIO1),
MSM_DEVICE(GPIO2),
@@ -73,8 +74,7 @@ void __init msm_map_common_io(void)
#ifdef CONFIG_ARCH_QSD8X50
static struct map_desc qsd8x50_io_desc[] __initdata = {
MSM_DEVICE(VIC),
- MSM_DEVICE(CSR),
- MSM_DEVICE(TMR),
+ MSM_CHIP_DEVICE(CSR, QSD8X50),
MSM_DEVICE(DMOV),
MSM_DEVICE(GPIO1),
MSM_DEVICE(GPIO2),
@@ -102,10 +102,10 @@ void __init msm_map_qsd8x50_io(void)
#ifdef CONFIG_ARCH_MSM8X60
static struct map_desc msm8x60_io_desc[] __initdata = {
- MSM_DEVICE(QGIC_DIST),
- MSM_DEVICE(QGIC_CPU),
- MSM_DEVICE(TMR),
- MSM_DEVICE(TMR0),
+ MSM_CHIP_DEVICE(QGIC_DIST, MSM8X60),
+ MSM_CHIP_DEVICE(QGIC_CPU, MSM8X60),
+ MSM_CHIP_DEVICE(TMR, MSM8X60),
+ MSM_CHIP_DEVICE(TMR0, MSM8X60),
MSM_DEVICE(ACC),
MSM_DEVICE(GCC),
};
@@ -116,11 +116,24 @@ void __init msm_map_msm8x60_io(void)
}
#endif /* CONFIG_ARCH_MSM8X60 */
+#ifdef CONFIG_ARCH_MSM8960
+static struct map_desc msm8960_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSM8960),
+ MSM_CHIP_DEVICE(QGIC_CPU, MSM8960),
+ MSM_CHIP_DEVICE(TMR, MSM8960),
+ MSM_CHIP_DEVICE(TMR0, MSM8960),
+};
+
+void __init msm_map_msm8960_io(void)
+{
+ iotable_init(msm8960_io_desc, ARRAY_SIZE(msm8960_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8960 */
+
#ifdef CONFIG_ARCH_MSM7X30
static struct map_desc msm7x30_io_desc[] __initdata = {
MSM_DEVICE(VIC),
- MSM_DEVICE(CSR),
- MSM_DEVICE(TMR),
+ MSM_CHIP_DEVICE(CSR, MSM7X30),
MSM_DEVICE(DMOV),
MSM_DEVICE(GPIO1),
MSM_DEVICE(GPIO2),
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index e2d58e4cb0d7..1a584e077c61 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/iommu.h>
+#include <linux/clk.h>
#include <asm/cacheflush.h>
#include <asm/sizes.h>
@@ -50,6 +51,30 @@ struct msm_priv {
struct list_head list_attached;
};
+static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+ int ret;
+
+ ret = clk_enable(drvdata->pclk);
+ if (ret)
+ goto fail;
+
+ if (drvdata->clk) {
+ ret = clk_enable(drvdata->clk);
+ if (ret)
+ clk_disable(drvdata->pclk);
+ }
+fail:
+ return ret;
+}
+
+static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
+{
+ if (drvdata->clk)
+ clk_disable(drvdata->clk);
+ clk_disable(drvdata->pclk);
+}
+
static int __flush_iotlb(struct iommu_domain *domain)
{
struct msm_priv *priv = domain->priv;
@@ -77,9 +102,16 @@ static int __flush_iotlb(struct iommu_domain *domain)
BUG();
iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+ BUG_ON(!iommu_drvdata);
+
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
+ __disable_clocks(iommu_drvdata);
}
-
+fail:
return ret;
}
@@ -105,7 +137,6 @@ static void __reset_context(void __iomem *base, int ctx)
SET_TLBLKCR(base, ctx, 0);
SET_PRRR(base, ctx, 0);
SET_NMRR(base, ctx, 0);
- SET_CONTEXTIDR(base, ctx, 0);
}
static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
@@ -265,9 +296,14 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
goto fail;
}
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
__program_context(iommu_drvdata->base, ctx_dev->num,
__pa(priv->pgtable));
+ __disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ret = __flush_iotlb(domain);
@@ -303,7 +339,12 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,
if (ret)
goto fail;
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
__reset_context(iommu_drvdata->base, ctx_dev->num);
+ __disable_clocks(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
fail:
@@ -376,11 +417,11 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
for (i = 0; i < 16; i++)
*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
- FL_SHARED | pgprot;
+ FL_SHARED | FL_NG | pgprot;
}
if (len == SZ_1M)
- *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
+ *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE | FL_NG |
FL_TYPE_SECT | FL_SHARED | pgprot;
/* Need a 2nd level table */
@@ -405,7 +446,7 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
if (len == SZ_4K)
- *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
+ *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 | SL_NG |
SL_SHARED | SL_TYPE_SMALL | pgprot;
if (len == SZ_64K) {
@@ -413,7 +454,7 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
for (i = 0; i < 16; i++)
*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
- SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
+ SL_NG | SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
}
ret = __flush_iotlb(domain);
@@ -532,9 +573,13 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
base = iommu_drvdata->base;
ctx = ctx_drvdata->num;
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
/* Invalidate context TLB */
SET_CTX_TLBIALL(base, ctx, 0);
- SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
+ SET_V2PPR(base, ctx, va & V2Pxx_VA);
par = GET_PAR(base, ctx);
@@ -547,6 +592,7 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
if (GET_FAULT(base, ctx))
ret = 0;
+ __disable_clocks(iommu_drvdata);
fail:
spin_unlock_irqrestore(&msm_iommu_lock, flags);
return ret;
@@ -590,7 +636,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
struct msm_iommu_drvdata *drvdata = dev_id;
void __iomem *base;
unsigned int fsr;
- int ncb, i;
+ int i, ret;
spin_lock(&msm_iommu_lock);
@@ -604,8 +650,11 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
pr_err("Unexpected IOMMU page fault!\n");
pr_err("base = %08x\n", (unsigned int) base);
- ncb = GET_NCB(base)+1;
- for (i = 0; i < ncb; i++) {
+ ret = __enable_clocks(drvdata);
+ if (ret)
+ goto fail;
+
+ for (i = 0; i < drvdata->ncb; i++) {
fsr = GET_FSR(base, i);
if (fsr) {
pr_err("Fault occurred in context %d.\n", i);
@@ -614,6 +663,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
SET_FSR(base, i, 0x4000000F);
}
}
+ __disable_clocks(drvdata);
fail:
spin_unlock(&msm_iommu_lock);
return 0;
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index b83c73b41fd1..8e8fb079852d 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
#include <mach/iommu_hw-8xxx.h>
#include <mach/iommu.h>
+#include <mach/clk.h>
struct iommu_ctx_iter_data {
/* input */
@@ -84,9 +85,9 @@ fail:
}
EXPORT_SYMBOL(msm_iommu_get_ctx);
-static void msm_iommu_reset(void __iomem *base)
+static void msm_iommu_reset(void __iomem *base, int ncb)
{
- int ctx, ncb;
+ int ctx;
SET_RPUE(base, 0);
SET_RPUEIE(base, 0);
@@ -99,7 +100,6 @@ static void msm_iommu_reset(void __iomem *base)
SET_GLOBAL_TLBIALL(base, 0);
SET_RPU_ACR(base, 0);
SET_TLBLKCRWE(base, 1);
- ncb = GET_NCB(base)+1;
for (ctx = 0; ctx < ncb; ctx++) {
SET_BPRCOSH(base, ctx, 0);
@@ -130,117 +130,140 @@ static int msm_iommu_probe(struct platform_device *pdev)
{
struct resource *r, *r2;
struct clk *iommu_clk;
+ struct clk *iommu_pclk;
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
void __iomem *regs_base;
resource_size_t len;
- int ret = 0, ncb, nm2v, irq;
+ int ret, irq, par;
- if (pdev->id != -1) {
- drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ if (pdev->id == -1) {
+ msm_iommu_root_dev = pdev;
+ return 0;
+ }
- if (!drvdata) {
- ret = -ENOMEM;
- goto fail;
- }
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
- if (!iommu_dev) {
- ret = -ENODEV;
- goto fail;
- }
+ if (!drvdata) {
+ ret = -ENOMEM;
+ goto fail;
+ }
- if (iommu_dev->clk_rate != 0) {
- iommu_clk = clk_get(&pdev->dev, "iommu_clk");
-
- if (IS_ERR(iommu_clk)) {
- ret = -ENODEV;
- goto fail;
- }
-
- if (iommu_dev->clk_rate > 0) {
- ret = clk_set_rate(iommu_clk,
- iommu_dev->clk_rate);
- if (ret) {
- clk_put(iommu_clk);
- goto fail;
- }
- }
-
- ret = clk_enable(iommu_clk);
- if (ret) {
- clk_put(iommu_clk);
- goto fail;
- }
+ if (!iommu_dev) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ iommu_pclk = clk_get(NULL, "smmu_pclk");
+ if (IS_ERR(iommu_pclk)) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ ret = clk_enable(iommu_pclk);
+ if (ret)
+ goto fail_enable;
+
+ iommu_clk = clk_get(&pdev->dev, "iommu_clk");
+
+ if (!IS_ERR(iommu_clk)) {
+ if (clk_get_rate(iommu_clk) == 0)
+ clk_set_min_rate(iommu_clk, 1);
+
+ ret = clk_enable(iommu_clk);
+ if (ret) {
clk_put(iommu_clk);
+ goto fail_pclk;
}
+ } else
+ iommu_clk = NULL;
- r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "physbase");
- if (!r) {
- ret = -ENODEV;
- goto fail;
- }
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
- len = r->end - r->start + 1;
+ if (!r) {
+ ret = -ENODEV;
+ goto fail_clk;
+ }
- r2 = request_mem_region(r->start, len, r->name);
- if (!r2) {
- pr_err("Could not request memory region: "
- "start=%p, len=%d\n", (void *) r->start, len);
- ret = -EBUSY;
- goto fail;
- }
+ len = resource_size(r);
- regs_base = ioremap(r2->start, len);
+ r2 = request_mem_region(r->start, len, r->name);
+ if (!r2) {
+ pr_err("Could not request memory region: start=%p, len=%d\n",
+ (void *) r->start, len);
+ ret = -EBUSY;
+ goto fail_clk;
+ }
- if (!regs_base) {
- pr_err("Could not ioremap: start=%p, len=%d\n",
- (void *) r2->start, len);
- ret = -EBUSY;
- goto fail_mem;
- }
+ regs_base = ioremap(r2->start, len);
- irq = platform_get_irq_byname(pdev, "secure_irq");
- if (irq < 0) {
- ret = -ENODEV;
- goto fail_io;
- }
+ if (!regs_base) {
+ pr_err("Could not ioremap: start=%p, len=%d\n",
+ (void *) r2->start, len);
+ ret = -EBUSY;
+ goto fail_mem;
+ }
- mb();
+ irq = platform_get_irq_byname(pdev, "secure_irq");
+ if (irq < 0) {
+ ret = -ENODEV;
+ goto fail_io;
+ }
- if (GET_IDR(regs_base) == 0) {
- pr_err("Invalid IDR value detected\n");
- ret = -ENODEV;
- goto fail_io;
- }
+ msm_iommu_reset(regs_base, iommu_dev->ncb);
- ret = request_irq(irq, msm_iommu_fault_handler, 0,
- "msm_iommu_secure_irpt_handler", drvdata);
- if (ret) {
- pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
- goto fail_io;
- }
+ SET_M(regs_base, 0, 1);
+ SET_PAR(regs_base, 0, 0);
+ SET_V2PCFG(regs_base, 0, 1);
+ SET_V2PPR(regs_base, 0, 0);
+ par = GET_PAR(regs_base, 0);
+ SET_V2PCFG(regs_base, 0, 0);
+ SET_M(regs_base, 0, 0);
- msm_iommu_reset(regs_base);
- drvdata->base = regs_base;
- drvdata->irq = irq;
+ if (!par) {
+ pr_err("%s: Invalid PAR value detected\n", iommu_dev->name);
+ ret = -ENODEV;
+ goto fail_io;
+ }
- nm2v = GET_NM2VCBMT((unsigned long) regs_base);
- ncb = GET_NCB((unsigned long) regs_base);
+ ret = request_irq(irq, msm_iommu_fault_handler, 0,
+ "msm_iommu_secure_irpt_handler", drvdata);
+ if (ret) {
+ pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
+ goto fail_io;
+ }
- pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
- iommu_dev->name, regs_base, irq, ncb+1);
- platform_set_drvdata(pdev, drvdata);
- } else
- msm_iommu_root_dev = pdev;
+ drvdata->pclk = iommu_pclk;
+ drvdata->clk = iommu_clk;
+ drvdata->base = regs_base;
+ drvdata->irq = irq;
+ drvdata->ncb = iommu_dev->ncb;
- return 0;
+ pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
+ iommu_dev->name, regs_base, irq, iommu_dev->ncb);
+
+ platform_set_drvdata(pdev, drvdata);
+
+ if (iommu_clk)
+ clk_disable(iommu_clk);
+
+ clk_disable(iommu_pclk);
+ return 0;
fail_io:
iounmap(regs_base);
fail_mem:
release_mem_region(r->start, len);
+fail_clk:
+ if (iommu_clk) {
+ clk_disable(iommu_clk);
+ clk_put(iommu_clk);
+ }
+fail_pclk:
+ clk_disable(iommu_pclk);
+fail_enable:
+ clk_put(iommu_pclk);
fail:
kfree(drvdata);
return ret;
@@ -252,7 +275,10 @@ static int msm_iommu_remove(struct platform_device *pdev)
drv = platform_get_drvdata(pdev);
if (drv) {
- memset(drv, 0, sizeof(struct msm_iommu_drvdata));
+ if (drv->clk)
+ clk_put(drv->clk);
+ clk_put(drv->pclk);
+ memset(drv, 0, sizeof(*drv));
kfree(drv);
platform_set_drvdata(pdev, NULL);
}
@@ -264,7 +290,7 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
- int i, ret = 0;
+ int i, ret;
if (!c || !pdev->dev.parent) {
ret = -EINVAL;
goto fail;
@@ -288,6 +314,18 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
platform_set_drvdata(pdev, ctx_drvdata);
+ ret = clk_enable(drvdata->pclk);
+ if (ret)
+ goto fail;
+
+ if (drvdata->clk) {
+ ret = clk_enable(drvdata->clk);
+ if (ret) {
+ clk_disable(drvdata->pclk);
+ goto fail;
+ }
+ }
+
/* Program the M2V tables for this context */
for (i = 0; i < MAX_NUM_MIDS; i++) {
int mid = c->mids[i];
@@ -297,21 +335,27 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
SET_M2VCBR_N(drvdata->base, mid, 0);
SET_CBACR_N(drvdata->base, c->num, 0);
- /* Set VMID = MID */
- SET_VMID(drvdata->base, mid, mid);
+ /* Set VMID = 0 */
+ SET_VMID(drvdata->base, mid, 0);
/* Set the context number for that MID to this context */
SET_CBNDX(drvdata->base, mid, c->num);
- /* Set MID associated with this context bank */
- SET_CBVMID(drvdata->base, c->num, mid);
+ /* Set MID associated with this context bank to 0*/
+ SET_CBVMID(drvdata->base, c->num, 0);
+
+ /* Set the ASID for TLB tagging for this context */
+ SET_CONTEXTIDR_ASID(drvdata->base, c->num, c->num);
/* Set security bit override to be Non-secure */
SET_NSCFG(drvdata->base, mid, 3);
}
- pr_info("context device %s with bank index %d\n", c->name, c->num);
+ if (drvdata->clk)
+ clk_disable(drvdata->clk);
+ clk_disable(drvdata->pclk);
+ dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
return 0;
fail:
kfree(ctx_drvdata);
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index 68f9b6153d74..7be32ff5d687 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -1,29 +1,13 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __MACH_SCM_BOOT_H
#define __MACH_SCM_BOOT_H
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index f4b9bc90d6a7..cfa808dd4897 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -174,15 +174,18 @@ static u32 smc(u32 cmd_addr)
register u32 r0 asm("r0") = 1;
register u32 r1 asm("r1") = (u32)&context_id;
register u32 r2 asm("r2") = cmd_addr;
- asm(
- __asmeq("%0", "r0")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- __asmeq("%3", "r2")
- "smc #0 @ switch to secure world\n"
- : "=r" (r0)
- : "r" (r0), "r" (r1), "r" (r2)
- : "r3");
+ do {
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r0")
+ __asmeq("%2", "r1")
+ __asmeq("%3", "r2")
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0)
+ : "r" (r0), "r" (r1), "r" (r2)
+ : "r3");
+ } while (r0 == SCM_INTERRUPTED);
+
return r0;
}
@@ -197,13 +200,9 @@ static int __scm_call(const struct scm_command *cmd)
* side in the buffer.
*/
flush_cache_all();
- do {
- ret = smc(cmd_addr);
- if (ret < 0) {
- ret = scm_remap_error(ret);
- break;
- }
- } while (ret == SCM_INTERRUPTED);
+ ret = smc(cmd_addr);
+ if (ret < 0)
+ ret = scm_remap_error(ret);
return ret;
}
@@ -264,21 +263,28 @@ u32 scm_get_version(void)
{
int context_id;
static u32 version = -1;
- register u32 r0 asm("r0") = 0x1 << 8;
- register u32 r1 asm("r1") = (u32)&context_id;
+ register u32 r0 asm("r0");
+ register u32 r1 asm("r1");
if (version != -1)
return version;
mutex_lock(&scm_lock);
- asm(
- __asmeq("%0", "r1")
- __asmeq("%1", "r0")
- __asmeq("%2", "r1")
- "smc #0 @ switch to secure world\n"
- : "=r" (r1)
- : "r" (r0), "r" (r1)
- : "r2", "r3");
+
+ r0 = 0x1 << 8;
+ r1 = (u32)&context_id;
+ do {
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r1")
+ __asmeq("%2", "r0")
+ __asmeq("%3", "r1")
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0), "=r" (r1)
+ : "r" (r0), "r" (r1)
+ : "r2", "r3");
+ } while (r0 == SCM_INTERRUPTED);
+
version = r1;
mutex_unlock(&scm_lock);
diff --git a/arch/arm/mach-msm/scm.h b/arch/arm/mach-msm/scm.h
index 261786be11c5..00b31ea58f29 100644
--- a/arch/arm/mach-msm/scm.h
+++ b/arch/arm/mach-msm/scm.h
@@ -1,29 +1,13 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of Code Aurora Forum, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
*
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
#ifndef __MACH_SCM_H
#define __MACH_SCM_H
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index c105d28b53e3..e7f8e5a4d48f 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -24,10 +24,7 @@
#include <asm/mach/time.h>
#include <mach/msm_iomap.h>
-
-#ifndef MSM_DGT_BASE
-#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
-#endif
+#include <mach/cpu.h>
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
@@ -52,18 +49,14 @@ enum timer_location {
GLOBAL_TIMER = 1,
};
-#ifdef MSM_TMR0_BASE
-#define MSM_TMR_GLOBAL (MSM_TMR0_BASE - MSM_TMR_BASE)
-#else
-#define MSM_TMR_GLOBAL 0
-#endif
-
#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT
+/* TODO: Remove these ifdefs */
#if defined(CONFIG_ARCH_QSD8X50)
#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
#define MSM_DGT_SHIFT (0)
-#elif defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60)
+#elif defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60) || \
+ defined(CONFIG_ARCH_MSM8960)
#define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
#define MSM_DGT_SHIFT (0)
#else
@@ -177,11 +170,7 @@ static struct msm_clock msm_clocks[] = {
.dev_id = &msm_clocks[0].clockevent,
.irq = INT_GP_TIMER_EXP
},
- .regbase = MSM_GPT_BASE,
.freq = GPT_HZ,
- .local_counter = MSM_GPT_BASE + TIMER_COUNT_VAL,
- .global_counter = MSM_GPT_BASE + TIMER_COUNT_VAL +
- MSM_TMR_GLOBAL,
},
[MSM_CLOCK_DGT] = {
.clockevent = {
@@ -206,12 +195,8 @@ static struct msm_clock msm_clocks[] = {
.dev_id = &msm_clocks[1].clockevent,
.irq = INT_DEBUG_TIMER_EXP
},
- .regbase = MSM_DGT_BASE,
.freq = DGT_HZ >> MSM_DGT_SHIFT,
.shift = MSM_DGT_SHIFT,
- .local_counter = MSM_DGT_BASE + TIMER_COUNT_VAL,
- .global_counter = MSM_DGT_BASE + TIMER_COUNT_VAL +
- MSM_TMR_GLOBAL,
}
};
@@ -219,6 +204,25 @@ static void __init msm_timer_init(void)
{
int i;
int res;
+ int global_offset = 0;
+
+ if (cpu_is_msm7x01()) {
+ msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
+ msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
+ } else if (cpu_is_msm7x30()) {
+ msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE + 0x04;
+ msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x24;
+ } else if (cpu_is_qsd8x50()) {
+ msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
+ msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
+ } else if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+ msm_clocks[MSM_CLOCK_GPT].regbase = MSM_TMR_BASE + 0x04;
+ msm_clocks[MSM_CLOCK_DGT].regbase = MSM_TMR_BASE + 0x24;
+
+ /* Use CPU0's timer as the global timer. */
+ global_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
+ } else
+ BUG();
#ifdef CONFIG_ARCH_MSM_SCORPIONMP
writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
@@ -228,6 +232,10 @@ static void __init msm_timer_init(void)
struct msm_clock *clock = &msm_clocks[i];
struct clock_event_device *ce = &clock->clockevent;
struct clocksource *cs = &clock->clocksource;
+
+ clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
+ clock->global_counter = clock->local_counter + global_offset;
+
writel(0, clock->regbase + TIMER_ENABLE);
writel(0, clock->regbase + TIMER_CLEAR);
writel(~0, clock->regbase + TIMER_MATCH_VAL);
diff --git a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
index 29e390e89ff4..20f3f125ed2b 100644
--- a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
+++ b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
@@ -148,6 +148,7 @@ MACHINE_START(TERASTATION_WXL, "Buffalo Nas WXL")
.boot_params = 0x00000100,
.init_machine = wxl_init,
.map_io = mv78xx0_map_io,
+ .init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
.timer = &mv78xx0_timer,
MACHINE_END
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 08465eb6a2c2..44fb4e55be0d 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -818,9 +818,15 @@ void __init mv78xx0_uart3_init(void)
/*****************************************************************************
* Time handling
****************************************************************************/
+void __init mv78xx0_init_early(void)
+{
+ orion_time_set_base(TIMER_VIRT_BASE);
+}
+
static void mv78xx0_timer_init(void)
{
- orion_time_init(IRQ_MV78XX0_TIMER_1, get_tclk());
+ orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
+ IRQ_MV78XX0_TIMER_1, get_tclk());
}
struct sys_timer mv78xx0_timer = {
diff --git a/arch/arm/mach-mv78xx0/common.h b/arch/arm/mach-mv78xx0/common.h
index befc22475469..632e63d65e7a 100644
--- a/arch/arm/mach-mv78xx0/common.h
+++ b/arch/arm/mach-mv78xx0/common.h
@@ -20,6 +20,7 @@ struct mv_sata_platform_data;
int mv78xx0_core_index(void);
void mv78xx0_map_io(void);
void mv78xx0_init(void);
+void mv78xx0_init_early(void);
void mv78xx0_init_irq(void);
extern struct mbus_dram_target_info mv78xx0_mbus_dram_info;
diff --git a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
index 207c95e403b9..df5aebe5b0fa 100644
--- a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
+++ b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
@@ -96,6 +96,7 @@ MACHINE_START(DB78X00_BP, "Marvell DB-78x00-BP Development Board")
.boot_params = 0x00000100,
.init_machine = db78x00_init,
.map_io = mv78xx0_map_io,
+ .init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
.timer = &mv78xx0_timer,
MACHINE_END
diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
index 2d14c4fe294d..c64dbb96dbad 100644
--- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
+++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
@@ -20,10 +20,6 @@
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE | 0x010c)
#define SOFT_RESET 0x00000001
-#define BRIDGE_CAUSE (BRIDGE_VIRT_BASE | 0x0110)
-#define BRIDGE_MASK (BRIDGE_VIRT_BASE | 0x0114)
-#define BRIDGE_INT_TIMER0 0x0002
-#define BRIDGE_INT_TIMER1 0x0004
#define BRIDGE_INT_TIMER1_CLR (~0x0004)
#define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE | 0x0200)
diff --git a/arch/arm/mach-mv78xx0/include/mach/gpio.h b/arch/arm/mach-mv78xx0/include/mach/gpio.h
index d9d1535ea100..77e1b843e768 100644
--- a/arch/arm/mach-mv78xx0/include/mach/gpio.h
+++ b/arch/arm/mach-mv78xx0/include/mach/gpio.h
@@ -6,35 +6,4 @@
* warranty of any kind, whether express or implied.
*/
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <mach/irqs.h>
#include <plat/gpio.h>
-#include <asm-generic/gpio.h> /* cansleep wrappers */
-
-extern int mv78xx0_core_index(void);
-
-#define GPIO_MAX 32
-#define GPIO_OUT(pin) (DEV_BUS_VIRT_BASE + 0x0100)
-#define GPIO_IO_CONF(pin) (DEV_BUS_VIRT_BASE + 0x0104)
-#define GPIO_BLINK_EN(pin) (DEV_BUS_VIRT_BASE + 0x0108)
-#define GPIO_IN_POL(pin) (DEV_BUS_VIRT_BASE + 0x010c)
-#define GPIO_DATA_IN(pin) (DEV_BUS_VIRT_BASE + 0x0110)
-#define GPIO_EDGE_CAUSE(pin) (DEV_BUS_VIRT_BASE + 0x0114)
-#define GPIO_MASK_OFF (mv78xx0_core_index() ? 0x18 : 0)
-#define GPIO_EDGE_MASK(pin) (DEV_BUS_VIRT_BASE + 0x0118 + GPIO_MASK_OFF)
-#define GPIO_LEVEL_MASK(pin) (DEV_BUS_VIRT_BASE + 0x011c + GPIO_MASK_OFF)
-
-static inline int gpio_to_irq(int pin)
-{
- return pin + IRQ_MV78XX0_GPIO_START;
-}
-
-static inline int irq_to_gpio(int irq)
-{
- return irq - IRQ_MV78XX0_GPIO_START;
-}
-
-
-#endif
diff --git a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
index 3eff39921d4d..3674497162e3 100644
--- a/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
+++ b/arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
@@ -71,6 +71,7 @@
#define DEV_BUS_VIRT_BASE (MV78XX0_REGS_VIRT_BASE | 0x10000)
#define SAMPLE_AT_RESET_LOW (DEV_BUS_VIRT_BASE | 0x0030)
#define SAMPLE_AT_RESET_HIGH (DEV_BUS_VIRT_BASE | 0x0034)
+#define GPIO_VIRT_BASE (DEV_BUS_VIRT_BASE | 0x0100)
#define I2C_0_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x1000)
#define I2C_1_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x1100)
#define UART0_PHYS_BASE (DEV_BUS_PHYS_BASE | 0x2000)
diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c
index 22b4ff893b3c..08da497c39c2 100644
--- a/arch/arm/mach-mv78xx0/irq.c
+++ b/arch/arm/mach-mv78xx0/irq.c
@@ -26,28 +26,18 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
void __init mv78xx0_init_irq(void)
{
- int i;
-
- /* Initialize gpiolib. */
- orion_gpio_init();
-
orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF));
/*
- * Mask and clear GPIO IRQ interrupts.
+ * Initialize gpiolib for GPIOs 0-31. (The GPIO interrupt mask
+ * registers for core #1 are at an offset of 0x18 from those of
+ * core #0.)
*/
- writel(0, GPIO_LEVEL_MASK(0));
- writel(0, GPIO_EDGE_MASK(0));
- writel(0, GPIO_EDGE_CAUSE(0));
-
- for (i = IRQ_MV78XX0_GPIO_START; i < NR_IRQS; i++) {
- set_irq_chip(i, &orion_gpio_irq_chip);
- set_irq_handler(i, handle_level_irq);
- irq_desc[i].status |= IRQ_LEVEL;
- set_irq_flags(i, IRQF_VALID);
- }
+ orion_gpio_init(0, 32, GPIO_VIRT_BASE,
+ mv78xx0_core_index() ? 0x18 : 0,
+ IRQ_MV78XX0_GPIO_START);
set_irq_chained_handler(IRQ_MV78XX0_GPIO_0_7, gpio_irq_handler);
set_irq_chained_handler(IRQ_MV78XX0_GPIO_8_15, gpio_irq_handler);
set_irq_chained_handler(IRQ_MV78XX0_GPIO_16_23, gpio_irq_handler);
diff --git a/arch/arm/mach-mv78xx0/mpp.c b/arch/arm/mach-mv78xx0/mpp.c
index 84db2dfc475c..65b72c454cb0 100644
--- a/arch/arm/mach-mv78xx0/mpp.c
+++ b/arch/arm/mach-mv78xx0/mpp.c
@@ -44,9 +44,6 @@ void __init mv78xx0_mpp_conf(unsigned int *mpp_list)
if (!variant_mask)
return;
- /* Initialize gpiolib. */
- orion_gpio_init();
-
printk(KERN_DEBUG "initial MPP regs:");
for (i = 0; i < MPP_NR_REGS; i++) {
mpp_ctrl[i] = readl(MPP_CTRL(i));
diff --git a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
index 3511ad4d973b..d927f14c6810 100644
--- a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
+++ b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
@@ -81,6 +81,7 @@ MACHINE_START(RD78X00_MASA, "Marvell RD-78x00-MASA Development Board")
.boot_params = 0x00000100,
.init_machine = rd78x00_masa_init,
.map_io = mv78xx0_map_io,
+ .init_early = mv78xx0_init_early,
.init_irq = mv78xx0_init_irq,
.timer = &mv78xx0_timer,
MACHINE_END
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
index 0717f887cba0..340809a7d233 100644
--- a/arch/arm/mach-mx3/Kconfig
+++ b/arch/arm/mach-mx3/Kconfig
@@ -94,6 +94,7 @@ config MACH_MX31_3DS
select MXC_DEBUG_BOARD
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_MXC_EHCI
@@ -183,6 +184,7 @@ config MACH_MX35_3DS
select MXC_DEBUG_BOARD
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_MXC_EHCI
select IMX_HAVE_PLATFORM_MXC_NAND
@@ -199,6 +201,15 @@ config MACH_KZM_ARM11_01
Include support for KZM-ARM11-01. This includes specific
configurations for the board and its peripherals.
+config MACH_BUG
+ bool "Support Buglabs BUGBase platform"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ default y
+ help
+ Include support for BUGBase 1.3 platform. This includes specific
+ configurations for the board and its peripherals.
+
config MACH_EUKREA_CPUIMX35
bool "Support Eukrea CPUIMX35 Platform"
select SOC_IMX35
@@ -229,4 +240,18 @@ config MACH_EUKREA_MBIMXSD35_BASEBOARD
endchoice
+config MACH_VPR200
+ bool "Support VPR200 platform"
+ select SOC_IMX35
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ help
+ Include support for VPR200 platform. This includes specific
+ configurations for the board and its peripherals.
+
endif
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
index 8db13294ad27..a54faf2cf5fa 100644
--- a/arch/arm/mach-mx3/Makefile
+++ b/arch/arm/mach-mx3/Makefile
@@ -5,8 +5,8 @@
# Object file lists.
obj-y := mm.o devices.o cpu.o
-obj-$(CONFIG_SOC_IMX31) += clock-imx31.o iomux-imx31.o
-obj-$(CONFIG_SOC_IMX35) += clock-imx35.o
+obj-$(CONFIG_SOC_IMX31) += clock-imx31.o iomux-imx31.o ehci-imx31.o
+obj-$(CONFIG_SOC_IMX35) += clock-imx35.o ehci-imx35.o
obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o
obj-$(CONFIG_MACH_MX31LILLY) += mach-mx31lilly.o mx31lilly-db.o
obj-$(CONFIG_MACH_MX31LITE) += mach-mx31lite.o mx31lite-db.o
@@ -20,5 +20,7 @@ obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o
+obj-$(CONFIG_MACH_BUG) += mach-bug.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
diff --git a/arch/arm/mach-mx3/devices-imx35.h b/arch/arm/mach-mx3/devices-imx35.h
index 677b18aa7ae6..d545d86cc202 100644
--- a/arch/arm/mach-mx3/devices-imx35.h
+++ b/arch/arm/mach-mx3/devices-imx35.h
@@ -35,7 +35,7 @@ extern const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst;
#define imx35_add_imx_i2c2(pdata) imx35_add_imx_i2c(2, pdata)
extern const struct imx_imx_keypad_data imx35_imx_keypad_data __initconst;
-#define imx31_add_imx_keypad(pdata) \
+#define imx35_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx35_imx_keypad_data, pdata)
extern const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst;
diff --git a/arch/arm/mach-mx3/ehci-imx31.c b/arch/arm/mach-mx3/ehci-imx31.c
new file mode 100644
index 000000000000..314a983ac614
--- /dev/null
+++ b/arch/arm/mach-mx3/ehci-imx31.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/mxc_ehci.h>
+
+#define USBCTRL_OTGBASE_OFFSET 0x600
+
+#define MX31_OTG_SIC_SHIFT 29
+#define MX31_OTG_SIC_MASK (0x3 << MX31_OTG_SIC_SHIFT)
+#define MX31_OTG_PM_BIT (1 << 24)
+
+#define MX31_H2_SIC_SHIFT 21
+#define MX31_H2_SIC_MASK (0x3 << MX31_H2_SIC_SHIFT)
+#define MX31_H2_PM_BIT (1 << 16)
+#define MX31_H2_DT_BIT (1 << 5)
+
+#define MX31_H1_SIC_SHIFT 13
+#define MX31_H1_SIC_MASK (0x3 << MX31_H1_SIC_SHIFT)
+#define MX31_H1_PM_BIT (1 << 8)
+#define MX31_H1_DT_BIT (1 << 4)
+
+int mx31_initialize_usb_hw(int port, unsigned int flags)
+{
+ unsigned int v;
+
+ v = readl(MX31_IO_ADDRESS(MX31_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ switch (port) {
+ case 0: /* OTG port */
+ v &= ~(MX31_OTG_SIC_MASK | MX31_OTG_PM_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_OTG_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX31_OTG_PM_BIT;
+
+ break;
+ case 1: /* H1 port */
+ v &= ~(MX31_H1_SIC_MASK | MX31_H1_PM_BIT | MX31_H1_DT_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H1_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX31_H1_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX31_H1_DT_BIT;
+
+ break;
+ case 2: /* H2 port */
+ v &= ~(MX31_H2_SIC_MASK | MX31_H2_PM_BIT | MX31_H2_DT_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H2_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX31_H2_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX31_H2_DT_BIT;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(v, MX31_IO_ADDRESS(MX31_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-mx3/ehci-imx35.c b/arch/arm/mach-mx3/ehci-imx35.c
new file mode 100644
index 000000000000..33983a478c6b
--- /dev/null
+++ b/arch/arm/mach-mx3/ehci-imx35.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/mxc_ehci.h>
+
+#define USBCTRL_OTGBASE_OFFSET 0x600
+
+#define MX35_OTG_SIC_SHIFT 29
+#define MX35_OTG_SIC_MASK (0x3 << MX35_OTG_SIC_SHIFT)
+#define MX35_OTG_PM_BIT (1 << 24)
+
+#define MX35_H1_SIC_SHIFT 21
+#define MX35_H1_SIC_MASK (0x3 << MX35_H1_SIC_SHIFT)
+#define MX35_H1_PM_BIT (1 << 8)
+#define MX35_H1_IPPUE_UP_BIT (1 << 7)
+#define MX35_H1_IPPUE_DOWN_BIT (1 << 6)
+#define MX35_H1_TLL_BIT (1 << 5)
+#define MX35_H1_USBTE_BIT (1 << 4)
+
+int mx35_initialize_usb_hw(int port, unsigned int flags)
+{
+ unsigned int v;
+
+ v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ switch (port) {
+ case 0: /* OTG port */
+ v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_OTG_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX35_OTG_PM_BIT;
+
+ break;
+ case 1: /* H1 port */
+ v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT |
+ MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
+ v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_H1_SIC_SHIFT;
+
+ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
+ v |= MX35_H1_PM_BIT;
+
+ if (!(flags & MXC_EHCI_TTL_ENABLED))
+ v |= MX35_H1_TLL_BIT;
+
+ if (flags & MXC_EHCI_INTERNAL_PHY)
+ v |= MX35_H1_USBTE_BIT;
+
+ if (flags & MXC_EHCI_IPPUE_DOWN)
+ v |= MX35_H1_IPPUE_DOWN_BIT;
+
+ if (flags & MXC_EHCI_IPPUE_UP)
+ v |= MX35_H1_IPPUE_UP_BIT;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(v, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET));
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
index 14a5ffc939ad..80761474c0f8 100644
--- a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
+++ b/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
@@ -165,8 +165,8 @@ static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
};
-#define GPIO_LED1 (2 * 32 + 29)
-#define GPIO_SWITCH1 (2 * 32 + 25)
+#define GPIO_LED1 IMX_GPIO_NR(3, 29)
+#define GPIO_SWITCH1 IMX_GPIO_NR(3, 25)
#define GPIO_LCDPWR (4)
static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
diff --git a/arch/arm/mach-mx3/iomux-imx31.c b/arch/arm/mach-mx3/iomux-imx31.c
index a1d7fa5123dc..cf8f8099ebd7 100644
--- a/arch/arm/mach-mx3/iomux-imx31.c
+++ b/arch/arm/mach-mx3/iomux-imx31.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL(mxc_iomux_set_pad);
* - reserves the pin so that it is not claimed by another driver
* - setups the iomux according to the configuration
*/
-int mxc_iomux_alloc_pin(const unsigned int pin, const char *label)
+int mxc_iomux_alloc_pin(unsigned int pin, const char *label)
{
unsigned pad = pin & IOMUX_PADNUM_MASK;
@@ -118,10 +118,10 @@ int mxc_iomux_alloc_pin(const unsigned int pin, const char *label)
}
EXPORT_SYMBOL(mxc_iomux_alloc_pin);
-int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
+int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
const char *label)
{
- unsigned int *p = pin_list;
+ const unsigned int *p = pin_list;
int i;
int ret = -EINVAL;
@@ -139,7 +139,7 @@ setup_error:
}
EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins);
-void mxc_iomux_release_pin(const unsigned int pin)
+void mxc_iomux_release_pin(unsigned int pin)
{
unsigned pad = pin & IOMUX_PADNUM_MASK;
@@ -148,9 +148,9 @@ void mxc_iomux_release_pin(const unsigned int pin)
}
EXPORT_SYMBOL(mxc_iomux_release_pin);
-void mxc_iomux_release_multiple_pins(unsigned int *pin_list, int count)
+void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count)
{
- unsigned int *p = pin_list;
+ const unsigned int *p = pin_list;
int i;
for (i = 0; i < count; i++) {
diff --git a/arch/arm/mach-mx3/mach-armadillo5x0.c b/arch/arm/mach-mx3/mach-armadillo5x0.c
index 28b6f414b5d5..226829bf7c25 100644
--- a/arch/arm/mach-mx3/mach-armadillo5x0.c
+++ b/arch/arm/mach-mx3/mach-armadillo5x0.c
@@ -133,7 +133,6 @@ static int armadillo5x0_pins[] = {
};
/* USB */
-#if defined(CONFIG_USB_ULPI)
#define OTG_RESET IOMUX_TO_GPIO(MX31_PIN_STXD4)
#define USBH2_RESET IOMUX_TO_GPIO(MX31_PIN_SCK6)
@@ -176,8 +175,10 @@ static int usbotg_init(struct platform_device *pdev)
gpio_set_value(OTG_RESET, 0/*LOW*/);
mdelay(5);
gpio_set_value(OTG_RESET, 1/*HIGH*/);
+ mdelay(10);
- return 0;
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_DIFF_UNI);
otg_free_reset:
gpio_free(OTG_RESET);
@@ -233,8 +234,10 @@ static int usbh2_init(struct platform_device *pdev)
gpio_set_value(USBH2_RESET, 0/*LOW*/);
mdelay(5);
gpio_set_value(USBH2_RESET, 1/*HIGH*/);
+ mdelay(10);
- return 0;
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_DIFF_UNI);
h2_free_reset:
gpio_free(USBH2_RESET);
@@ -246,15 +249,12 @@ h2_free_cs:
static struct mxc_usbh_platform_data usbotg_pdata __initdata = {
.init = usbotg_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_DIFF_UNI,
};
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
.init = usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_DIFF_UNI,
};
-#endif /* CONFIG_USB_ULPI */
/* RTC over I2C*/
#define ARMADILLO5X0_RTC_GPIO IOMUX_TO_GPIO(MX31_PIN_SRXD4)
@@ -547,15 +547,15 @@ static void __init armadillo5x0_init(void)
i2c_register_board_info(1, &armadillo5x0_i2c_rtc, 1);
/* USB */
-#if defined(CONFIG_USB_ULPI)
- usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx31_add_mxc_ehci_otg(&usbotg_pdata);
- imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
+
+ usbotg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbotg_pdata.otg)
+ imx31_add_mxc_ehci_otg(&usbotg_pdata);
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
}
static void __init armadillo5x0_timer_init(void)
@@ -569,9 +569,10 @@ static struct sys_timer armadillo5x0_timer = {
MACHINE_START(ARMADILLO5X0, "Armadillo-500")
/* Maintainer: Alberto Panizzo */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_map_io,
- .init_irq = mx31_init_irq,
- .timer = &armadillo5x0_timer,
- .init_machine = armadillo5x0_init,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &armadillo5x0_timer,
+ .init_machine = armadillo5x0_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-bug.c b/arch/arm/mach-mx3/mach-bug.c
new file mode 100644
index 000000000000..d137d7078ee9
--- /dev/null
+++ b/arch/arm/mach-mx3/mach-bug.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <mach/iomux-mx3.h>
+#include <mach/imx-uart.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include "devices-imx31.h"
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static const unsigned int bug_pins[] __initconst = {
+ MX31_PIN_PC_RST__CTS5,
+ MX31_PIN_PC_VS2__RTS5,
+ MX31_PIN_PC_BVD2__TXD5,
+ MX31_PIN_PC_BVD1__RXD5,
+};
+
+static void __init bug_board_init(void)
+{
+ mxc_iomux_setup_multiple_pins(bug_pins,
+ ARRAY_SIZE(bug_pins), "uart-4");
+ imx31_add_imx_uart4(&uart_pdata);
+}
+
+static void __init bug_timer_init(void)
+{
+ mx31_clocks_init(26000000);
+}
+
+static struct sys_timer bug_timer = {
+ .init = bug_timer_init,
+};
+
+MACHINE_START(BUG, "BugLabs BUGBase")
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &bug_timer,
+ .init_machine = bug_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-mx3/mach-cpuimx35.c
index 26ae90f02582..ec63d998f647 100644
--- a/arch/arm/mach-mx3/mach-cpuimx35.c
+++ b/arch/arm/mach-mx3/mach-cpuimx35.c
@@ -60,7 +60,7 @@ static struct tsc2007_platform_data tsc2007_info = {
.x_plate_ohms = 180,
};
-#define TSC2007_IRQGPIO (2 * 32 + 2)
+#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2)
static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
{
I2C_BOARD_INFO("pcf8563", 0x51),
@@ -111,15 +111,25 @@ static const struct mxc_nand_platform_data
.flash_bbt = 1,
};
+static int eukrea_cpuimx35_otg_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static const struct mxc_usbh_platform_data otg_pdata __initconst = {
+ .init = eukrea_cpuimx35_otg_init,
.portsc = MXC_EHCI_MODE_UTMI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+static int eukrea_cpuimx35_usbh1_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI |
+ MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN);
+}
+
static const struct mxc_usbh_platform_data usbh1_pdata __initconst = {
+ .init = eukrea_cpuimx35_usbh1_init,
.portsc = MXC_EHCI_MODE_SERIAL,
- .flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
- MXC_EHCI_IPPUE_DOWN,
};
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
@@ -146,7 +156,7 @@ __setup("otg_mode=", eukrea_cpuimx35_otg_mode);
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init eukrea_cpuimx35_init(void)
{
mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads,
ARRAY_SIZE(eukrea_cpuimx35_pads));
@@ -184,9 +194,10 @@ struct sys_timer eukrea_cpuimx35_timer = {
MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
/* Maintainer: Eukrea Electromatique */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx35_map_io,
- .init_irq = mx35_init_irq,
- .init_machine = mxc_board_init,
- .timer = &eukrea_cpuimx35_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx35_map_io,
+ .init_early = imx35_init_early,
+ .init_irq = mx35_init_irq,
+ .timer = &eukrea_cpuimx35_timer,
+ .init_machine = eukrea_cpuimx35_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-kzm_arm11_01.c b/arch/arm/mach-mx3/mach-kzm_arm11_01.c
index df1a6ce8e3e1..d35621d62b4d 100644
--- a/arch/arm/mach-mx3/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-mx3/mach-kzm_arm11_01.c
@@ -266,17 +266,14 @@ static void __init kzm_timer_init(void)
}
static struct sys_timer kzm_timer = {
- .init = kzm_timer_init,
+ .init = kzm_timer_init,
};
-/*
- * The following uses standard kernel macros define in arch.h in order to
- * initialize __mach_desc_KZM_ARM11_01 data structure.
- */
MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = kzm_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = kzm_board_init,
- .timer = &kzm_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = kzm_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &kzm_timer,
+ .init_machine = kzm_board_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c
index 0d65db885be7..544d3e414f58 100644
--- a/arch/arm/mach-mx3/mach-mx31_3ds.c
+++ b/arch/arm/mach-mx3/mach-mx31_3ds.c
@@ -21,9 +21,13 @@
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
#include <linux/spi/spi.h>
+#include <linux/spi/l4f00242t03.h>
#include <linux/regulator/machine.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
+#include <linux/memblock.h>
+
+#include <media/soc_camera.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -35,6 +39,10 @@
#include <mach/iomux-mx3.h>
#include <mach/3ds_debugboard.h>
#include <mach/ulpi.h>
+#include <mach/mmc.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+#include <mach/mx3_camera.h>
#include "devices-imx31.h"
#include "devices.h"
@@ -42,10 +50,6 @@
/* CPLD IRQ line for external uart, external ethernet etc */
#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
-/*
- * This file contains the board-specific initialization routines.
- */
-
static int mx31_3ds_pins[] = {
/* UART1 */
MX31_PIN_CTS1__CTS1,
@@ -53,6 +57,12 @@ static int mx31_3ds_pins[] = {
MX31_PIN_TXD1__TXD1,
MX31_PIN_RXD1__RXD1,
IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO),
+ /*SPI0*/
+ MX31_PIN_CSPI1_SCLK__SCLK,
+ MX31_PIN_CSPI1_MOSI__MOSI,
+ MX31_PIN_CSPI1_MISO__MISO,
+ MX31_PIN_CSPI1_SPI_RDY__SPI_RDY,
+ MX31_PIN_CSPI1_SS2__SS2, /* CS for LCD */
/* SPI 1 */
MX31_PIN_CSPI2_SCLK__SCLK,
MX31_PIN_CSPI2_MOSI__MOSI,
@@ -100,6 +110,252 @@ static int mx31_3ds_pins[] = {
IOMUX_MODE(MX31_PIN_PC_RW_B, IOMUX_CONFIG_ALT1),
/* USB Host2 reset */
IOMUX_MODE(MX31_PIN_USB_BYP, IOMUX_CONFIG_GPIO),
+ /* I2C1 */
+ MX31_PIN_I2C_CLK__I2C1_SCL,
+ MX31_PIN_I2C_DAT__I2C1_SDA,
+ /* SDHC1 */
+ MX31_PIN_SD1_DATA3__SD1_DATA3,
+ MX31_PIN_SD1_DATA2__SD1_DATA2,
+ MX31_PIN_SD1_DATA1__SD1_DATA1,
+ MX31_PIN_SD1_DATA0__SD1_DATA0,
+ MX31_PIN_SD1_CLK__SD1_CLK,
+ MX31_PIN_SD1_CMD__SD1_CMD,
+ MX31_PIN_GPIO3_1__GPIO3_1, /* Card detect */
+ MX31_PIN_GPIO3_0__GPIO3_0, /* OE */
+ /* Framebuffer */
+ MX31_PIN_LD0__LD0,
+ MX31_PIN_LD1__LD1,
+ MX31_PIN_LD2__LD2,
+ MX31_PIN_LD3__LD3,
+ MX31_PIN_LD4__LD4,
+ MX31_PIN_LD5__LD5,
+ MX31_PIN_LD6__LD6,
+ MX31_PIN_LD7__LD7,
+ MX31_PIN_LD8__LD8,
+ MX31_PIN_LD9__LD9,
+ MX31_PIN_LD10__LD10,
+ MX31_PIN_LD11__LD11,
+ MX31_PIN_LD12__LD12,
+ MX31_PIN_LD13__LD13,
+ MX31_PIN_LD14__LD14,
+ MX31_PIN_LD15__LD15,
+ MX31_PIN_LD16__LD16,
+ MX31_PIN_LD17__LD17,
+ MX31_PIN_VSYNC3__VSYNC3,
+ MX31_PIN_HSYNC__HSYNC,
+ MX31_PIN_FPSHIFT__FPSHIFT,
+ MX31_PIN_CONTRAST__CONTRAST,
+ /* CSI */
+ MX31_PIN_CSI_D6__CSI_D6,
+ MX31_PIN_CSI_D7__CSI_D7,
+ MX31_PIN_CSI_D8__CSI_D8,
+ MX31_PIN_CSI_D9__CSI_D9,
+ MX31_PIN_CSI_D10__CSI_D10,
+ MX31_PIN_CSI_D11__CSI_D11,
+ MX31_PIN_CSI_D12__CSI_D12,
+ MX31_PIN_CSI_D13__CSI_D13,
+ MX31_PIN_CSI_D14__CSI_D14,
+ MX31_PIN_CSI_D15__CSI_D15,
+ MX31_PIN_CSI_HSYNC__CSI_HSYNC,
+ MX31_PIN_CSI_MCLK__CSI_MCLK,
+ MX31_PIN_CSI_PIXCLK__CSI_PIXCLK,
+ MX31_PIN_CSI_VSYNC__CSI_VSYNC,
+ MX31_PIN_CSI_D5__GPIO3_5, /* CMOS PWDN */
+ IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_GPIO), /* CMOS reset */
+};
+
+/*
+ * Camera support
+ */
+static phys_addr_t mx3_camera_base __initdata;
+#define MX31_3DS_CAMERA_BUF_SIZE SZ_8M
+
+#define MX31_3DS_GPIO_CAMERA_PW IOMUX_TO_GPIO(MX31_PIN_CSI_D5)
+#define MX31_3DS_GPIO_CAMERA_RST IOMUX_TO_GPIO(MX31_PIN_RI_DTE1)
+
+static struct gpio mx31_3ds_camera_gpios[] = {
+ { MX31_3DS_GPIO_CAMERA_PW, GPIOF_OUT_INIT_HIGH, "camera-power" },
+ { MX31_3DS_GPIO_CAMERA_RST, GPIOF_OUT_INIT_HIGH, "camera-reset" },
+};
+
+static int __init mx31_3ds_camera_alloc_dma(void)
+{
+ int dma;
+
+ if (!mx3_camera_base)
+ return -ENOMEM;
+
+ dma = dma_declare_coherent_memory(&mx3_camera.dev,
+ mx3_camera_base, mx3_camera_base,
+ MX31_3DS_CAMERA_BUF_SIZE,
+ DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+
+ if (!(dma & DMA_MEMORY_MAP))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int mx31_3ds_camera_power(struct device *dev, int on)
+{
+ /* enable or disable the camera */
+ pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
+ gpio_set_value(MX31_3DS_GPIO_CAMERA_PW, on ? 0 : 1);
+
+ if (!on)
+ goto out;
+
+ /* If enabled, give a reset impulse */
+ gpio_set_value(MX31_3DS_GPIO_CAMERA_RST, 0);
+ msleep(20);
+ gpio_set_value(MX31_3DS_GPIO_CAMERA_RST, 1);
+ msleep(100);
+
+out:
+ return 0;
+}
+
+static struct i2c_board_info mx31_3ds_i2c_camera = {
+ I2C_BOARD_INFO("ov2640", 0x30),
+};
+
+static struct regulator_bulk_data mx31_3ds_camera_regs[] = {
+ { .supply = "cmos_vcore" },
+ { .supply = "cmos_2v8" },
+};
+
+static struct soc_camera_link iclink_ov2640 = {
+ .bus_id = 0,
+ .board_info = &mx31_3ds_i2c_camera,
+ .i2c_adapter_id = 0,
+ .power = mx31_3ds_camera_power,
+ .regulators = mx31_3ds_camera_regs,
+ .num_regulators = ARRAY_SIZE(mx31_3ds_camera_regs),
+};
+
+static struct platform_device mx31_3ds_ov2640 = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink_ov2640,
+ },
+};
+
+struct mx3_camera_pdata mx31_3ds_camera_pdata = {
+ .dma_dev = &mx3_ipu.dev,
+ .flags = MX3_CAMERA_DATAWIDTH_10,
+ .mclk_10khz = 2600,
+};
+
+/*
+ * FB support
+ */
+static const struct fb_videomode fb_modedb[] = {
+ { /* 480x640 @ 60 Hz */
+ .name = "Epson-VGA",
+ .refresh = 60,
+ .xres = 480,
+ .yres = 640,
+ .pixclock = 41701,
+ .left_margin = 20,
+ .right_margin = 41,
+ .upper_margin = 10,
+ .lower_margin = 5,
+ .hsync_len = 20,
+ .vsync_len = 10,
+ .sync = FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+ },
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+ .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+ .dma_dev = &mx3_ipu.dev,
+ .name = "Epson-VGA",
+ .mode = fb_modedb,
+ .num_modes = ARRAY_SIZE(fb_modedb),
+};
+
+/* LCD */
+static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = {
+ .reset_gpio = IOMUX_TO_GPIO(MX31_PIN_LCS1),
+ .data_enable_gpio = IOMUX_TO_GPIO(MX31_PIN_SER_RS),
+ .core_supply = "lcd_2v8",
+ .io_supply = "vdd_lcdio",
+};
+
+/*
+ * Support for SD card slot in personality board
+ */
+#define MX31_3DS_GPIO_SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_GPIO3_1)
+#define MX31_3DS_GPIO_SDHC1_BE IOMUX_TO_GPIO(MX31_PIN_GPIO3_0)
+
+static struct gpio mx31_3ds_sdhc1_gpios[] = {
+ { MX31_3DS_GPIO_SDHC1_CD, GPIOF_IN, "sdhc1-card-detect" },
+ { MX31_3DS_GPIO_SDHC1_BE, GPIOF_OUT_INIT_LOW, "sdhc1-bus-en" },
+};
+
+static int mx31_3ds_sdhc1_init(struct device *dev,
+ irq_handler_t detect_irq,
+ void *data)
+{
+ int ret;
+
+ ret = gpio_request_array(mx31_3ds_sdhc1_gpios,
+ ARRAY_SIZE(mx31_3ds_sdhc1_gpios));
+ if (ret) {
+ pr_warning("Unable to request the SD/MMC GPIOs.\n");
+ return ret;
+ }
+
+ ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO3_1),
+ detect_irq, IRQF_DISABLED |
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "sdhc1-detect", data);
+ if (ret) {
+ pr_warning("Unable to request the SD/MMC card-detect IRQ.\n");
+ goto gpio_free;
+ }
+
+ return 0;
+
+gpio_free:
+ gpio_free_array(mx31_3ds_sdhc1_gpios,
+ ARRAY_SIZE(mx31_3ds_sdhc1_gpios));
+ return ret;
+}
+
+static void mx31_3ds_sdhc1_exit(struct device *dev, void *data)
+{
+ free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO3_1), data);
+ gpio_free_array(mx31_3ds_sdhc1_gpios,
+ ARRAY_SIZE(mx31_3ds_sdhc1_gpios));
+}
+
+static void mx31_3ds_sdhc1_setpower(struct device *dev, unsigned int vdd)
+{
+ /*
+ * While the voltage stuff is done by the driver, activate the
+ * Buffer Enable Pin only if there is a card in slot to fix the card
+ * voltage issue caused by bi-directional chip TXB0108 on 3Stack.
+ * Done here because at this stage we have for sure a debounced value
+ * of the presence of the card, showed by the value of vdd.
+ * 7 == ilog2(MMC_VDD_165_195)
+ */
+ if (vdd > 7)
+ gpio_set_value(MX31_3DS_GPIO_SDHC1_BE, 1);
+ else
+ gpio_set_value(MX31_3DS_GPIO_SDHC1_BE, 0);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+ .init = mx31_3ds_sdhc1_init,
+ .exit = mx31_3ds_sdhc1_exit,
+ .setpower = mx31_3ds_sdhc1_setpower,
};
/*
@@ -138,7 +394,71 @@ static struct regulator_init_data gpo_init = {
}
};
-static struct mc13783_regulator_init_data mx31_3ds_regulators[] = {
+static struct regulator_consumer_supply vmmc2_consumers[] = {
+ REGULATOR_SUPPLY("vmmc", "mxc-mmc.0"),
+};
+
+static struct regulator_init_data vmmc2_init = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vmmc2_consumers),
+ .consumer_supplies = vmmc2_consumers,
+};
+
+static struct regulator_consumer_supply vmmc1_consumers[] = {
+ REGULATOR_SUPPLY("lcd_2v8", NULL),
+ REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data vmmc1_init = {
+ .constraints = {
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vmmc1_consumers),
+ .consumer_supplies = vmmc1_consumers,
+};
+
+static struct regulator_consumer_supply vgen_consumers[] = {
+ REGULATOR_SUPPLY("vdd_lcdio", NULL),
+};
+
+static struct regulator_init_data vgen_init = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vgen_consumers),
+ .consumer_supplies = vgen_consumers,
+};
+
+static struct regulator_consumer_supply vvib_consumers[] = {
+ REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data vvib_init = {
+ .constraints = {
+ .min_uV = 1300000,
+ .max_uV = 1300000,
+ .apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vvib_consumers),
+ .consumer_supplies = vvib_consumers,
+};
+
+static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = {
{
.id = MC13783_REG_PWGT1SPI, /* Power Gate for ARM core. */
.init_data = &pwgtx_init,
@@ -152,17 +472,38 @@ static struct mc13783_regulator_init_data mx31_3ds_regulators[] = {
}, {
.id = MC13783_REG_GPO3, /* Turn on 3.3V */
.init_data = &gpo_init,
+ }, {
+ .id = MC13783_REG_VMMC2, /* Power MMC/SD, WiFi/Bluetooth. */
+ .init_data = &vmmc2_init,
+ }, {
+ .id = MC13783_REG_VMMC1, /* Power LCD, CMOS, FM, GPS, Accel. */
+ .init_data = &vmmc1_init,
+ }, {
+ .id = MC13783_REG_VGEN, /* Power LCD */
+ .init_data = &vgen_init,
+ }, {
+ .id = MC13783_REG_VVIB, /* Power CMOS */
+ .init_data = &vvib_init,
},
};
/* MC13783 */
-static struct mc13783_platform_data mc13783_pdata __initdata = {
+static struct mc13xxx_platform_data mc13783_pdata __initdata = {
.regulators = mx31_3ds_regulators,
.num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
- .flags = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN,
+ .flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_TOUCHSCREEN
};
/* SPI */
+static int spi0_internal_chipselect[] = {
+ MXC_SPI_CS(2),
+};
+
+static const struct spi_imx_master spi0_pdata __initconst = {
+ .chipselect = spi0_internal_chipselect,
+ .num_chipselect = ARRAY_SIZE(spi0_internal_chipselect),
+};
+
static int spi1_internal_chipselect[] = {
MXC_SPI_CS(0),
MXC_SPI_CS(2),
@@ -182,6 +523,12 @@ static struct spi_board_info mx31_3ds_spi_devs[] __initdata = {
.platform_data = &mc13783_pdata,
.irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3),
.mode = SPI_CS_HIGH,
+ }, {
+ .modalias = "l4f00242t03",
+ .max_speed_hz = 5000000,
+ .bus_num = 0,
+ .chip_select = 0, /* SS2 */
+ .platform_data = &mx31_3ds_l4f00242t03_pdata,
},
};
@@ -245,6 +592,11 @@ usbotg_free_reset:
return err;
}
+static int mx31_3ds_otg_init(struct platform_device *pdev)
+{
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
+}
+
static int mx31_3ds_host2_init(struct platform_device *pdev)
{
int err;
@@ -276,25 +628,25 @@ static int mx31_3ds_host2_init(struct platform_device *pdev)
mdelay(1);
gpio_set_value(USBH2_RST_B, 1);
- return 0;
+
+ mdelay(10);
+
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
usbotg_free_reset:
gpio_free(USBH2_RST_B);
return err;
}
-#if defined(CONFIG_USB_ULPI)
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = mx31_3ds_otg_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
.init = mx31_3ds_host2_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
-#endif
static const struct fsl_usb2_platform_data usbotg_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -320,19 +672,18 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-/*
- * Set up static virtual mappings.
- */
-static void __init mx31_3ds_map_io(void)
-{
- mx31_map_io();
-}
+static const struct imxi2c_platform_data mx31_3ds_i2c0_data __initconst = {
+ .bitrate = 100000,
+};
-/*!
- * Board specific initialization.
- */
-static void __init mxc_board_init(void)
+static struct platform_device *devices[] __initdata = {
+ &mx31_3ds_ov2640,
+};
+
+static void __init mx31_3ds_init(void)
{
+ int ret;
+
mxc_iomux_setup_multiple_pins(mx31_3ds_pins, ARRAY_SIZE(mx31_3ds_pins),
"mx31_3ds");
@@ -343,20 +694,22 @@ static void __init mxc_board_init(void)
spi_register_board_info(mx31_3ds_spi_devs,
ARRAY_SIZE(mx31_3ds_spi_devs));
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
imx31_add_imx_keypad(&mx31_3ds_keymap_data);
mx31_3ds_usbotg_init();
-#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx31_add_mxc_ehci_otg(&otg_pdata);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (otg_pdata.otg)
+ imx31_add_mxc_ehci_otg(&otg_pdata);
}
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
- imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
+
if (!otg_mode_host)
imx31_add_fsl_usb2_udc(&usbotg_pdata);
@@ -364,6 +717,26 @@ static void __init mxc_board_init(void)
printk(KERN_WARNING "Init of the debug board failed, all "
"devices on the debug board are unusable.\n");
imx31_add_imx2_wdt(NULL);
+ imx31_add_imx_i2c0(&mx31_3ds_i2c0_data);
+ imx31_add_mxc_mmc(0, &sdhc1_pdata);
+
+ imx31_add_spi_imx0(&spi0_pdata);
+ mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+ mxc_register_device(&mx3_fb, &mx3fb_pdata);
+
+ /* CSI */
+ /* Camera power: default - off */
+ ret = gpio_request_array(mx31_3ds_camera_gpios,
+ ARRAY_SIZE(mx31_3ds_camera_gpios));
+ if (ret) {
+ pr_err("Failed to request camera gpios");
+ iclink_ov2640.power = NULL;
+ }
+
+ if (!mx31_3ds_camera_alloc_dma())
+ mxc_register_device(&mx3_camera, &mx31_3ds_camera_pdata);
+ else
+ pr_err("Failed to allocate dma memory for camera");
}
static void __init mx31_3ds_timer_init(void)
@@ -375,15 +748,22 @@ static struct sys_timer mx31_3ds_timer = {
.init = mx31_3ds_timer_init,
};
-/*
- * The following uses standard kernel macros defined in arch.h in order to
- * initialize __mach_desc_MX31_3DS data structure.
- */
+static void __init mx31_3ds_reserve(void)
+{
+ /* reserve MX31_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */
+ mx3_camera_base = memblock_alloc(MX31_3DS_CAMERA_BUF_SIZE,
+ MX31_3DS_CAMERA_BUF_SIZE);
+ memblock_free(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE);
+ memblock_remove(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE);
+}
+
MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
/* Maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_3ds_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mx31_3ds_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &mx31_3ds_timer,
+ .init_machine = mx31_3ds_init,
+ .reserve = mx31_3ds_reserve,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-mx31ads.c b/arch/arm/mach-mx3/mach-mx31ads.c
index 88b97d62b57e..4e4b780c481d 100644
--- a/arch/arm/mach-mx3/mach-mx31ads.c
+++ b/arch/arm/mach-mx3/mach-mx31ads.c
@@ -69,12 +69,8 @@
#define EXPIO_INT_XUART_INTB (MXC_EXP_IO_BASE + 11)
#define MXC_MAX_EXP_IO_LINES 16
-/*
- * This file contains the board-specific initialization routines.
- */
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
-/*!
+/*
* The serial port definition structure.
*/
static struct plat_serial8250_port serial_platform_data[] = {
@@ -110,14 +106,7 @@ static int __init mxc_init_extuart(void)
{
return platform_device_register(&serial_device);
}
-#else
-static inline int mxc_init_extuart(void)
-{
- return 0;
-}
-#endif
-#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
@@ -134,11 +123,6 @@ static inline void mxc_init_imx_uart(void)
mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0");
imx31_add_imx_uart0(&uart_pdata);
}
-#else /* !SERIAL_IMX */
-static inline void mxc_init_imx_uart(void)
-{
-}
-#endif /* !SERIAL_IMX */
static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc)
{
@@ -160,7 +144,7 @@ static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc)
/*
* Disable an expio pin's interrupt by setting the bit in the imr.
- * @param irq an expio virtual irq number
+ * @param d an expio virtual irq description
*/
static void expio_mask_irq(struct irq_data *d)
{
@@ -172,7 +156,7 @@ static void expio_mask_irq(struct irq_data *d)
/*
* Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
- * @param irq an expanded io virtual irq number
+ * @param d an expio virtual irq description
*/
static void expio_ack_irq(struct irq_data *d)
{
@@ -183,7 +167,7 @@ static void expio_ack_irq(struct irq_data *d)
/*
* Enable a expio pin's interrupt by clearing the bit in the imr.
- * @param irq a expio virtual irq number
+ * @param d an expio virtual irq description
*/
static void expio_unmask_irq(struct irq_data *d)
{
@@ -476,7 +460,6 @@ static struct wm8350_platform_data __initdata mx31_wm8350_pdata = {
};
#endif
-#if defined(CONFIG_I2C_IMX) || defined(CONFIG_I2C_IMX_MODULE)
static struct i2c_board_info __initdata mx31ads_i2c1_devices[] = {
#ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
{
@@ -497,11 +480,6 @@ static void mxc_init_i2c(void)
imx31_add_imx_i2c1(NULL);
}
-#else
-static void mxc_init_i2c(void)
-{
-}
-#endif
static unsigned int ssi_pins[] = {
MX31_PIN_SFS5__SFS5,
@@ -516,9 +494,7 @@ static void mxc_init_audio(void)
mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
}
-/*!
- * This structure defines static mappings for the i.MX31ADS board.
- */
+/* static mappings */
static struct map_desc mx31ads_io_desc[] __initdata = {
{
.virtual = MX31_CS4_BASE_ADDR_VIRT,
@@ -528,9 +504,6 @@ static struct map_desc mx31ads_io_desc[] __initdata = {
},
};
-/*!
- * Set up static virtual mappings.
- */
static void __init mx31ads_map_io(void)
{
mx31_map_io();
@@ -543,10 +516,7 @@ static void __init mx31ads_init_irq(void)
mx31ads_init_expio();
}
-/*!
- * Board specific initialization.
- */
-static void __init mxc_board_init(void)
+static void __init mx31ads_init(void)
{
mxc_init_extuart();
mxc_init_imx_uart();
@@ -563,15 +533,12 @@ static struct sys_timer mx31ads_timer = {
.init = mx31ads_timer_init,
};
-/*
- * The following uses standard kernel macros defined in arch.h in order to
- * initialize __mach_desc_MX31ADS data structure.
- */
MACHINE_START(MX31ADS, "Freescale MX31ADS")
/* Maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31ads_map_io,
- .init_irq = mx31ads_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mx31ads_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31ads_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31ads_init_irq,
+ .timer = &mx31ads_timer,
+ .init_machine = mx31ads_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-mx31lilly.c b/arch/arm/mach-mx3/mach-mx31lilly.c
index 2c595483f356..ed95745163b8 100644
--- a/arch/arm/mach-mx3/mach-mx31lilly.c
+++ b/arch/arm/mach-mx3/mach-mx31lilly.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/smsc911x.h>
@@ -110,55 +111,9 @@ static struct platform_device physmap_flash_device = {
/* USB */
-#if defined(CONFIG_USB_ULPI)
-
#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
-static int usbotg_init(struct platform_device *pdev)
-{
- unsigned int pins[] = {
- MX31_PIN_USBOTG_DATA0__USBOTG_DATA0,
- MX31_PIN_USBOTG_DATA1__USBOTG_DATA1,
- MX31_PIN_USBOTG_DATA2__USBOTG_DATA2,
- MX31_PIN_USBOTG_DATA3__USBOTG_DATA3,
- MX31_PIN_USBOTG_DATA4__USBOTG_DATA4,
- MX31_PIN_USBOTG_DATA5__USBOTG_DATA5,
- MX31_PIN_USBOTG_DATA6__USBOTG_DATA6,
- MX31_PIN_USBOTG_DATA7__USBOTG_DATA7,
- MX31_PIN_USBOTG_CLK__USBOTG_CLK,
- MX31_PIN_USBOTG_DIR__USBOTG_DIR,
- MX31_PIN_USBOTG_NXT__USBOTG_NXT,
- MX31_PIN_USBOTG_STP__USBOTG_STP,
- };
-
- mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB OTG");
-
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG);
- mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG);
-
- mxc_iomux_set_gpr(MUX_PGP_USB_4WIRE, true);
- mxc_iomux_set_gpr(MUX_PGP_USB_COMMON, true);
-
- /* chip select */
- mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE2, IOMUX_CONFIG_GPIO),
- "USBOTG_CS");
- gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE2), "USBH1 CS");
- gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE2), 0);
-
- return 0;
-}
-
static int usbh1_init(struct platform_device *pdev)
{
int pins[] = {
@@ -183,7 +138,10 @@ static int usbh1_init(struct platform_device *pdev)
mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true);
- return 0;
+ mdelay(10);
+
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_SINGLE_UNI);
}
static int usbh2_init(struct platform_device *pdev)
@@ -220,41 +178,30 @@ static int usbh2_init(struct platform_device *pdev)
gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS");
gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0);
- return 0;
-}
+ mdelay(10);
-static struct mxc_usbh_platform_data usbotg_pdata = {
- .init = usbotg_init,
- .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
-};
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
+}
static const struct mxc_usbh_platform_data usbh1_pdata __initconst = {
.init = usbh1_init,
.portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
};
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
.init = usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
static void lilly1131_usb_init(void)
{
- usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
imx31_add_mxc_ehci_hs(1, &usbh1_pdata);
- imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
-}
-#else
-static inline void lilly1131_usb_init(void) {}
-#endif /* CONFIG_USB_ULPI */
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
+}
/* SPI */
@@ -274,8 +221,8 @@ static const struct spi_imx_master spi1_pdata __initconst = {
.num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
};
-static struct mc13783_platform_data mc13783_pdata __initdata = {
- .flags = MC13783_USE_RTC | MC13783_USE_TOUCHSCREEN,
+static struct mc13xxx_platform_data mc13783_pdata __initdata = {
+ .flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN,
};
static struct spi_board_info mc13783_dev __initdata = {
@@ -347,10 +294,10 @@ static struct sys_timer mx31lilly_timer = {
};
MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mx31lilly_board_init,
- .timer = &mx31lilly_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &mx31lilly_timer,
+ .init_machine = mx31lilly_board_init,
MACHINE_END
-
diff --git a/arch/arm/mach-mx3/mach-mx31lite.c b/arch/arm/mach-mx3/mach-mx31lite.c
index 9e64c66396e0..24a21a384bf1 100644
--- a/arch/arm/mach-mx3/mach-mx31lite.c
+++ b/arch/arm/mach-mx3/mach-mx31lite.c
@@ -27,6 +27,7 @@
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
#include <linux/mtd/physmap.h>
+#include <linux/delay.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -111,9 +112,9 @@ static const struct spi_imx_master spi1_pdata __initconst = {
.num_chipselect = ARRAY_SIZE(spi_internal_chipselect),
};
-static struct mc13783_platform_data mc13783_pdata __initdata = {
- .flags = MC13783_USE_RTC |
- MC13783_USE_REGULATOR,
+static struct mc13xxx_platform_data mc13783_pdata __initdata = {
+ .flags = MC13XXX_USE_RTC |
+ MC13XXX_USE_REGULATOR,
};
static struct spi_board_info mc13783_spi_dev __initdata = {
@@ -129,7 +130,6 @@ static struct spi_board_info mc13783_spi_dev __initdata = {
* USB
*/
-#if defined(CONFIG_USB_ULPI)
#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
@@ -167,15 +167,15 @@ static int usbh2_init(struct platform_device *pdev)
gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS");
gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0);
- return 0;
+ mdelay(10);
+
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
}
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
.init = usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
-#endif
/*
* NOR flash
@@ -227,7 +227,7 @@ void __init mx31lite_map_io(void)
static int mx31lite_baseboard;
core_param(mx31lite_baseboard, mx31lite_baseboard, int, 0444);
-static void __init mxc_board_init(void)
+static void __init mx31lite_init(void)
{
int ret;
@@ -252,13 +252,11 @@ static void __init mxc_board_init(void)
imx31_add_spi_imx1(&spi1_pdata);
spi_register_board_info(&mc13783_spi_dev, 1);
-#if defined(CONFIG_USB_ULPI)
/* USB */
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
/* SMSC9117 IRQ pin */
ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
@@ -281,9 +279,10 @@ struct sys_timer mx31lite_timer = {
MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
/* Maintainer: Freescale Semiconductor, Inc. */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31lite_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mx31lite_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31lite_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &mx31lite_timer,
+ .init_machine = mx31lite_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-mx31moboard.c b/arch/arm/mach-mx3/mach-mx31moboard.c
index 1aa8d65fccbb..6f3692bccb8a 100644
--- a/arch/arm/mach-mx3/mach-mx31moboard.c
+++ b/arch/arm/mach-mx3/mach-mx31moboard.c
@@ -214,7 +214,7 @@ static struct regulator_init_data cam_vreg_data = {
.consumer_supplies = cam_consumers,
};
-static struct mc13783_regulator_init_data moboard_regulators[] = {
+static struct mc13xxx_regulator_init_data moboard_regulators[] = {
{
.id = MC13783_REG_VMMC1,
.init_data = &sdhc_vreg_data,
@@ -267,12 +267,12 @@ static struct mc13783_leds_platform_data moboard_leds = {
.tc2_period = MC13783_LED_PERIOD_10MS,
};
-static struct mc13783_platform_data moboard_pmic = {
+static struct mc13xxx_platform_data moboard_pmic = {
.regulators = moboard_regulators,
.num_regulators = ARRAY_SIZE(moboard_regulators),
.leds = &moboard_leds,
- .flags = MC13783_USE_REGULATOR | MC13783_USE_RTC |
- MC13783_USE_ADC | MC13783_USE_LED,
+ .flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_RTC |
+ MC13XXX_USE_ADC | MC13XXX_USE_LED,
};
static struct spi_board_info moboard_spi_board_info[] __initdata = {
@@ -400,19 +400,24 @@ static void usb_xcvr_reset(void)
mdelay(1);
}
-#if defined(CONFIG_USB_ULPI)
+static int moboard_usbh2_init_hw(struct platform_device *pdev)
+{
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
+}
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
+ .init = moboard_usbh2_init_hw,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
static int __init moboard_usbh2_init(void)
{
struct platform_device *pdev;
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (!usbh2_pdata.otg)
+ return -ENODEV;
pdev = imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
if (IS_ERR(pdev))
@@ -420,10 +425,6 @@ static int __init moboard_usbh2_init(void)
return 0;
}
-#else
-static inline int moboard_usbh2_init(void) { return 0; }
-#endif
-
static struct gpio_led mx31moboard_leds[] = {
{
@@ -503,7 +504,7 @@ core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444);
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init mx31moboard_init(void)
{
mxc_iomux_setup_multiple_pins(moboard_pins, ARRAY_SIZE(moboard_pins),
"moboard");
@@ -564,10 +565,10 @@ struct sys_timer mx31moboard_timer = {
MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
/* Maintainer: Valentin Longchamp, EPFL Mobots group */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mx31moboard_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &mx31moboard_timer,
+ .init_machine = mx31moboard_init,
MACHINE_END
-
diff --git a/arch/arm/mach-mx3/mach-mx35_3ds.c b/arch/arm/mach-mx3/mach-mx35_3ds.c
index b1963f257c20..ff5fe231b8d6 100644
--- a/arch/arm/mach-mx3/mach-mx35_3ds.c
+++ b/arch/arm/mach-mx3/mach-mx35_3ds.c
@@ -118,24 +118,42 @@ static iomux_v3_cfg_t mx35pdk_pads[] = {
MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
+ /* I2C1 */
+ MX35_PAD_I2C1_CLK__I2C1_SCL,
+ MX35_PAD_I2C1_DAT__I2C1_SDA,
};
+static int mx35_3ds_otg_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY);
+}
+
/* OTG config */
static const struct fsl_usb2_platform_data usb_otg_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
.phy_mode = FSL_USB2_PHY_UTMI_WIDE,
+ .workaround = FLS_USB2_WORKAROUND_ENGCM09152,
+/*
+ * ENGCM09152 also requires a hardware change.
+ * Please check the MX35 Chip Errata document for details.
+ */
};
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = mx35_3ds_otg_init,
.portsc = MXC_EHCI_MODE_UTMI,
- .flags = MXC_EHCI_INTERNAL_PHY,
};
+static int mx35_3ds_usbh_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI |
+ MXC_EHCI_INTERNAL_PHY);
+}
+
/* USB HOST config */
static const struct mxc_usbh_platform_data usb_host_pdata __initconst = {
+ .init = mx35_3ds_usbh_init,
.portsc = MXC_EHCI_MODE_SERIAL,
- .flags = MXC_EHCI_INTERFACE_SINGLE_UNI |
- MXC_EHCI_INTERNAL_PHY,
};
static int otg_mode_host;
@@ -153,10 +171,14 @@ static int __init mx35_3ds_otg_mode(char *options)
}
__setup("otg_mode=", mx35_3ds_otg_mode);
+static const struct imxi2c_platform_data mx35_3ds_i2c0_data __initconst = {
+ .bitrate = 100000,
+};
+
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init mx35_3ds_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
@@ -180,6 +202,7 @@ static void __init mxc_board_init(void)
if (mxc_expio_init(MX35_CS5_BASE_ADDR, EXPIO_PARENT_INT))
pr_warn("Init of the debugboard failed, all "
"devices on the debugboard are unusable.\n");
+ imx35_add_imx_i2c0(&mx35_3ds_i2c0_data);
}
static void __init mx35pdk_timer_init(void)
@@ -193,9 +216,10 @@ struct sys_timer mx35pdk_timer = {
MACHINE_START(MX35_3DS, "Freescale MX35PDK")
/* Maintainer: Freescale Semiconductor, Inc */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx35_map_io,
- .init_irq = mx35_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mx35pdk_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx35_map_io,
+ .init_early = imx35_init_early,
+ .init_irq = mx35_init_irq,
+ .timer = &mx35pdk_timer,
+ .init_machine = mx35_3ds_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-mx3/mach-pcm037.c
index b752f6bc20a2..f07d3bded674 100644
--- a/arch/arm/mach-mx3/mach-pcm037.c
+++ b/arch/arm/mach-mx3/mach-pcm037.c
@@ -533,17 +533,25 @@ static struct platform_device pcm970_sja1000 = {
.num_resources = ARRAY_SIZE(pcm970_sja1000_resources),
};
-#if defined(CONFIG_USB_ULPI)
+static int pcm037_otg_init(struct platform_device *pdev)
+{
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = pcm037_otg_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+static int pcm037_usbh2_init(struct platform_device *pdev)
+{
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static struct mxc_usbh_platform_data usbh2_pdata __initdata = {
+ .init = pcm037_usbh2_init,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
-#endif
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -568,7 +576,7 @@ __setup("otg_mode=", pcm037_otg_mode);
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init pcm037_init(void)
{
int ret;
@@ -646,19 +654,18 @@ static void __init mxc_board_init(void)
platform_device_register(&pcm970_sja1000);
-#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx31_add_mxc_ehci_otg(&otg_pdata);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (otg_pdata.otg)
+ imx31_add_mxc_ehci_otg(&otg_pdata);
}
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+ usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (usbh2_pdata.otg)
+ imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
- imx31_add_mxc_ehci_hs(2, &usbh2_pdata);
-#endif
if (!otg_mode_host)
imx31_add_fsl_usb2_udc(&otg_device_pdata);
@@ -675,9 +682,10 @@ struct sys_timer pcm037_timer = {
MACHINE_START(PCM037, "Phytec Phycore pcm037")
/* Maintainer: Pengutronix */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mxc_board_init,
- .timer = &pcm037_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &pcm037_timer,
+ .init_machine = pcm037_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-pcm037_eet.c b/arch/arm/mach-mx3/mach-pcm037_eet.c
index fda56545d2fd..df6fb07d037e 100644
--- a/arch/arm/mach-mx3/mach-pcm037_eet.c
+++ b/arch/arm/mach-mx3/mach-pcm037_eet.c
@@ -180,9 +180,7 @@ static int __init eet_init_devices(void)
/* SPI */
spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
imx31_add_spi_imx0(&pcm037_spi1_pdata);
-#endif
platform_device_register(&pcm037_gpio_keys_device);
diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-mx3/mach-pcm043.c
index bcf83fc7e701..b3ecfb22d241 100644
--- a/arch/arm/mach-mx3/mach-pcm043.c
+++ b/arch/arm/mach-mx3/mach-pcm043.c
@@ -115,7 +115,6 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
static const struct imxi2c_platform_data pcm043_i2c0_data __initconst = {
.bitrate = 50000,
};
@@ -134,7 +133,6 @@ static struct i2c_board_info pcm043_i2c_devices[] = {
I2C_BOARD_INFO("pcf8563", 0x51),
}
};
-#endif
static struct platform_device *devices[] __initdata = {
&pcm043_flash,
@@ -221,9 +219,9 @@ static iomux_v3_cfg_t pcm043_pads[] = {
MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
};
-#define AC97_GPIO_TXFS (1 * 32 + 31)
-#define AC97_GPIO_TXD (1 * 32 + 28)
-#define AC97_GPIO_RESET (1 * 32 + 0)
+#define AC97_GPIO_TXFS IMX_GPIO_NR(2, 31)
+#define AC97_GPIO_TXD IMX_GPIO_NR(2, 28)
+#define AC97_GPIO_RESET IMX_GPIO_NR(2, 0)
static void pcm043_ac97_warm_reset(struct snd_ac97 *ac97)
{
@@ -307,18 +305,26 @@ pcm037_nand_board_info __initconst = {
.hw_ecc = 1,
};
-#if defined(CONFIG_USB_ULPI)
+static int pcm043_otg_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI);
+}
+
static struct mxc_usbh_platform_data otg_pdata __initdata = {
+ .init = pcm043_otg_init,
.portsc = MXC_EHCI_MODE_UTMI,
- .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+static int pcm043_usbh1_init(struct platform_device *pdev)
+{
+ return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI |
+ MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN);
+}
+
static const struct mxc_usbh_platform_data usbh1_pdata __initconst = {
+ .init = pcm043_usbh1_init,
.portsc = MXC_EHCI_MODE_SERIAL,
- .flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
- MXC_EHCI_IPPUE_DOWN,
};
-#endif
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -343,7 +349,7 @@ __setup("otg_mode=", pcm043_otg_mode);
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init pcm043_init(void)
{
mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads));
@@ -369,26 +375,22 @@ static void __init mxc_board_init(void)
imx35_add_imx_uart1(&uart_pdata);
-#if defined CONFIG_I2C_IMX || defined CONFIG_I2C_IMX_MODULE
i2c_register_board_info(0, pcm043_i2c_devices,
ARRAY_SIZE(pcm043_i2c_devices));
imx35_add_imx_i2c0(&pcm043_i2c0_data);
-#endif
mxc_register_device(&mx3_ipu, &mx3_ipu_data);
mxc_register_device(&mx3_fb, &mx3fb_pdata);
-#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
- otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
- imx35_add_mxc_ehci_otg(&otg_pdata);
+ otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (otg_pdata.otg)
+ imx35_add_mxc_ehci_otg(&otg_pdata);
}
-
imx35_add_mxc_ehci_hs(&usbh1_pdata);
-#endif
+
if (!otg_mode_host)
imx35_add_fsl_usb2_udc(&otg_device_pdata);
@@ -407,10 +409,10 @@ struct sys_timer pcm043_timer = {
MACHINE_START(PCM043, "Phytec Phycore pcm043")
/* Maintainer: Pengutronix */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx35_map_io,
- .init_irq = mx35_init_irq,
- .init_machine = mxc_board_init,
- .timer = &pcm043_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx35_map_io,
+ .init_early = imx35_init_early,
+ .init_irq = mx35_init_irq,
+ .timer = &pcm043_timer,
+ .init_machine = pcm043_init,
MACHINE_END
-
diff --git a/arch/arm/mach-mx3/mach-qong.c b/arch/arm/mach-mx3/mach-qong.c
index fd1050c40964..17f758b77623 100644
--- a/arch/arm/mach-mx3/mach-qong.c
+++ b/arch/arm/mach-mx3/mach-qong.c
@@ -54,10 +54,6 @@
#define QONG_FPGA_IRQ IOMUX_TO_IRQ(MX31_PIN_DTR_DCE1)
-/*
- * This file contains the board-specific initialization routines.
- */
-
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
@@ -247,7 +243,7 @@ static void __init qong_init_fpga(void)
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init qong_init(void)
{
mxc_init_imx_uart();
qong_init_nor_mtd();
@@ -263,16 +259,12 @@ static struct sys_timer qong_timer = {
.init = qong_timer_init,
};
-/*
- * The following uses standard kernel macros defined in arch.h in order to
- * initialize __mach_desc_QONG data structure.
- */
-
MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
/* Maintainer: DENX Software Engineering GmbH */
- .boot_params = MX3x_PHYS_OFFSET + 0x100,
- .map_io = mx31_map_io,
- .init_irq = mx31_init_irq,
- .init_machine = mxc_board_init,
- .timer = &qong_timer,
+ .boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .map_io = mx31_map_io,
+ .init_early = imx31_init_early,
+ .init_irq = mx31_init_irq,
+ .timer = &qong_timer,
+ .init_machine = qong_init,
MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-vpr200.c b/arch/arm/mach-mx3/mach-vpr200.c
new file mode 100644
index 000000000000..2cf390fbd980
--- /dev/null
+++ b/arch/arm/mach-mx3/mach-vpr200.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Marc Kleine-Budde, Pengutronix
+ * Copyright 2010 Creative Product Design
+ *
+ * Derived from mx35 3stack.
+ * Original author: Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/memory.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/iomux-mx35.h>
+#include <mach/irqs.h>
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/gpio_keys.h>
+
+#include "devices-imx35.h"
+#include "devices.h"
+
+#define GPIO_LCDPWR IMX_GPIO_NR(1, 2)
+#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)
+
+#define GPIO_BUTTON1 IMX_GPIO_NR(1, 4)
+#define GPIO_BUTTON2 IMX_GPIO_NR(1, 5)
+#define GPIO_BUTTON3 IMX_GPIO_NR(1, 7)
+#define GPIO_BUTTON4 IMX_GPIO_NR(1, 8)
+#define GPIO_BUTTON5 IMX_GPIO_NR(1, 9)
+#define GPIO_BUTTON6 IMX_GPIO_NR(1, 10)
+#define GPIO_BUTTON7 IMX_GPIO_NR(1, 11)
+#define GPIO_BUTTON8 IMX_GPIO_NR(1, 12)
+
+static const struct fb_videomode fb_modedb[] = {
+ {
+ /* 800x480 @ 60 Hz */
+ .name = "PT0708048",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(33260),
+ .left_margin = 50,
+ .right_margin = 156,
+ .upper_margin = 10,
+ .lower_margin = 10,
+ .hsync_len = 1, /* note: DE only display */
+ .vsync_len = 1, /* note: DE only display */
+ .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+ }, {
+ /* 800x480 @ 60 Hz */
+ .name = "CTP-CLAA070LC0ACW",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = KHZ2PICOS(27000),
+ .left_margin = 50,
+ .right_margin = 50, /* whole line should have 900 clocks */
+ .upper_margin = 10,
+ .lower_margin = 10, /* whole frame should have 500 lines */
+ .hsync_len = 1, /* note: DE only display */
+ .vsync_len = 1, /* note: DE only display */
+ .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+ }
+};
+
+static struct ipu_platform_data mx3_ipu_data = {
+ .irq_base = MXC_IPU_IRQ_START,
+};
+
+static struct mx3fb_platform_data mx3fb_pdata = {
+ .dma_dev = &mx3_ipu.dev,
+ .name = "PT0708048",
+ .mode = fb_modedb,
+ .num_modes = ARRAY_SIZE(fb_modedb),
+};
+
+static struct physmap_flash_data vpr200_flash_data = {
+ .width = 2,
+};
+
+static struct resource vpr200_flash_resource = {
+ .start = MX35_CS0_BASE_ADDR,
+ .end = MX35_CS0_BASE_ADDR + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device vpr200_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &vpr200_flash_data,
+ },
+ .resource = &vpr200_flash_resource,
+ .num_resources = 1,
+};
+
+static const struct mxc_nand_platform_data
+ vpr200_nand_board_info __initconst = {
+ .width = 1,
+ .hw_ecc = 1,
+ .flash_bbt = 1,
+};
+
+#define VPR_KEY_DEBOUNCE 500
+static struct gpio_keys_button vpr200_gpio_keys_table[] = {
+ {KEY_F2, GPIO_BUTTON1, 1, "vpr-keys: F2", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F3, GPIO_BUTTON2, 1, "vpr-keys: F3", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F4, GPIO_BUTTON3, 1, "vpr-keys: F4", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F5, GPIO_BUTTON4, 1, "vpr-keys: F5", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F6, GPIO_BUTTON5, 1, "vpr-keys: F6", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F7, GPIO_BUTTON6, 1, "vpr-keys: F7", 0, VPR_KEY_DEBOUNCE},
+ {KEY_F8, GPIO_BUTTON7, 1, "vpr-keys: F8", 1, VPR_KEY_DEBOUNCE},
+ {KEY_F9, GPIO_BUTTON8, 1, "vpr-keys: F9", 1, VPR_KEY_DEBOUNCE},
+};
+
+static struct gpio_keys_platform_data vpr200_gpio_keys_data = {
+ .buttons = vpr200_gpio_keys_table,
+ .nbuttons = ARRAY_SIZE(vpr200_gpio_keys_table),
+};
+
+static struct platform_device vpr200_device_gpiokeys = {
+ .name = "gpio-keys",
+ .dev = {
+ .platform_data = &vpr200_gpio_keys_data,
+ }
+};
+
+static struct mc13xxx_platform_data vpr200_pmic = {
+ .flags = MC13XXX_USE_ADC | MC13XXX_USE_TOUCHSCREEN,
+};
+
+static const struct imxi2c_platform_data vpr200_i2c0_data __initconst = {
+ .bitrate = 50000,
+};
+
+static struct at24_platform_data vpr200_eeprom = {
+ .byte_len = 2048 / 8,
+ .page_size = 1,
+};
+
+static struct i2c_board_info vpr200_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("at24", 0x50), /* E0=0, E1=0, E2=0 */
+ .platform_data = &vpr200_eeprom,
+ }, {
+ I2C_BOARD_INFO("mc13892", 0x08),
+ .platform_data = &vpr200_pmic,
+ .irq = gpio_to_irq(GPIO_PMIC_INT),
+ }
+};
+
+static iomux_v3_cfg_t vpr200_pads[] = {
+ /* UART1 */
+ MX35_PAD_TXD1__UART1_TXD_MUX,
+ MX35_PAD_RXD1__UART1_RXD_MUX,
+ /* UART3 */
+ MX35_PAD_ATA_DATA10__UART3_RXD_MUX,
+ MX35_PAD_ATA_DATA11__UART3_TXD_MUX,
+ /* FEC */
+ MX35_PAD_FEC_TX_CLK__FEC_TX_CLK,
+ MX35_PAD_FEC_RX_CLK__FEC_RX_CLK,
+ MX35_PAD_FEC_RX_DV__FEC_RX_DV,
+ MX35_PAD_FEC_COL__FEC_COL,
+ MX35_PAD_FEC_RDATA0__FEC_RDATA_0,
+ MX35_PAD_FEC_TDATA0__FEC_TDATA_0,
+ MX35_PAD_FEC_TX_EN__FEC_TX_EN,
+ MX35_PAD_FEC_MDC__FEC_MDC,
+ MX35_PAD_FEC_MDIO__FEC_MDIO,
+ MX35_PAD_FEC_TX_ERR__FEC_TX_ERR,
+ MX35_PAD_FEC_RX_ERR__FEC_RX_ERR,
+ MX35_PAD_FEC_CRS__FEC_CRS,
+ MX35_PAD_FEC_RDATA1__FEC_RDATA_1,
+ MX35_PAD_FEC_TDATA1__FEC_TDATA_1,
+ MX35_PAD_FEC_RDATA2__FEC_RDATA_2,
+ MX35_PAD_FEC_TDATA2__FEC_TDATA_2,
+ MX35_PAD_FEC_RDATA3__FEC_RDATA_3,
+ MX35_PAD_FEC_TDATA3__FEC_TDATA_3,
+ /* Display */
+ MX35_PAD_LD0__IPU_DISPB_DAT_0,
+ MX35_PAD_LD1__IPU_DISPB_DAT_1,
+ MX35_PAD_LD2__IPU_DISPB_DAT_2,
+ MX35_PAD_LD3__IPU_DISPB_DAT_3,
+ MX35_PAD_LD4__IPU_DISPB_DAT_4,
+ MX35_PAD_LD5__IPU_DISPB_DAT_5,
+ MX35_PAD_LD6__IPU_DISPB_DAT_6,
+ MX35_PAD_LD7__IPU_DISPB_DAT_7,
+ MX35_PAD_LD8__IPU_DISPB_DAT_8,
+ MX35_PAD_LD9__IPU_DISPB_DAT_9,
+ MX35_PAD_LD10__IPU_DISPB_DAT_10,
+ MX35_PAD_LD11__IPU_DISPB_DAT_11,
+ MX35_PAD_LD12__IPU_DISPB_DAT_12,
+ MX35_PAD_LD13__IPU_DISPB_DAT_13,
+ MX35_PAD_LD14__IPU_DISPB_DAT_14,
+ MX35_PAD_LD15__IPU_DISPB_DAT_15,
+ MX35_PAD_LD16__IPU_DISPB_DAT_16,
+ MX35_PAD_LD17__IPU_DISPB_DAT_17,
+ MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK,
+ MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY,
+ MX35_PAD_CONTRAST__IPU_DISPB_CONTR,
+ /* LCD Enable */
+ MX35_PAD_D3_VSYNC__GPIO1_2,
+ /* USBOTG */
+ MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR,
+ MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC,
+ /* SDCARD */
+ MX35_PAD_SD1_CMD__ESDHC1_CMD,
+ MX35_PAD_SD1_CLK__ESDHC1_CLK,
+ MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+ MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+ MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+ MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
+ /* PMIC */
+ MX35_PAD_GPIO2_0__GPIO2_0,
+ /* GPIO keys */
+ MX35_PAD_SCKR__GPIO1_4,
+ MX35_PAD_COMPARE__GPIO1_5,
+ MX35_PAD_SCKT__GPIO1_7,
+ MX35_PAD_FST__GPIO1_8,
+ MX35_PAD_HCKT__GPIO1_9,
+ MX35_PAD_TX5_RX0__GPIO1_10,
+ MX35_PAD_TX4_RX1__GPIO1_11,
+ MX35_PAD_TX3_RX2__GPIO1_12,
+};
+
+/* USB Device config */
+static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
+ .operating_mode = FSL_USB2_DR_DEVICE,
+ .phy_mode = FSL_USB2_PHY_UTMI,
+ .workaround = FLS_USB2_WORKAROUND_ENGCM09152,
+};
+
+/* USB HOST config */
+static const struct mxc_usbh_platform_data usb_host_pdata __initconst = {
+ .portsc = MXC_EHCI_MODE_SERIAL,
+ .flags = MXC_EHCI_INTERFACE_SINGLE_UNI |
+ MXC_EHCI_INTERNAL_PHY,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &vpr200_flash,
+ &vpr200_device_gpiokeys,
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init vpr200_board_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(vpr200_pads, ARRAY_SIZE(vpr200_pads));
+
+ imx35_add_fec(NULL);
+ imx35_add_imx2_wdt(NULL);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ if (0 != gpio_request(GPIO_LCDPWR, "LCDPWR"))
+ printk(KERN_WARNING "vpr200: Couldn't get LCDPWR gpio\n");
+ else
+ gpio_direction_output(GPIO_LCDPWR, 0);
+
+ if (0 != gpio_request(GPIO_PMIC_INT, "PMIC_INT"))
+ printk(KERN_WARNING "vpr200: Couldn't get PMIC_INT gpio\n");
+ else
+ gpio_direction_input(GPIO_PMIC_INT);
+
+ imx35_add_imx_uart0(NULL);
+ imx35_add_imx_uart2(NULL);
+
+ mxc_register_device(&mx3_ipu, &mx3_ipu_data);
+ mxc_register_device(&mx3_fb, &mx3fb_pdata);
+
+ imx35_add_fsl_usb2_udc(&otg_device_pdata);
+ imx35_add_mxc_ehci_hs(&usb_host_pdata);
+
+ imx35_add_mxc_nand(&vpr200_nand_board_info);
+ imx35_add_sdhci_esdhc_imx(0, NULL);
+
+ i2c_register_board_info(0, vpr200_i2c_devices,
+ ARRAY_SIZE(vpr200_i2c_devices));
+
+ imx35_add_imx_i2c0(&vpr200_i2c0_data);
+}
+
+static void __init vpr200_timer_init(void)
+{
+ mx35_clocks_init();
+}
+
+struct sys_timer vpr200_timer = {
+ .init = vpr200_timer_init,
+};
+
+MACHINE_START(VPR200, "VPR200")
+ /* Maintainer: Creative Product Design */
+ .map_io = mx35_map_io,
+ .init_early = imx35_init_early,
+ .init_irq = mx35_init_irq,
+ .timer = &vpr200_timer,
+ .init_machine = vpr200_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
index 47118f760244..54d7174b4202 100644
--- a/arch/arm/mach-mx3/mm.c
+++ b/arch/arm/mach-mx3/mm.c
@@ -27,14 +27,8 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-v3.h>
-
-/*!
- * @file mm.c
- *
- * @brief This file creates static virtual to physical mappings, common to all MX3 boards.
- *
- * @ingroup Memory
- */
+#include <mach/gpio.h>
+#include <mach/irqs.h>
#ifdef CONFIG_SOC_IMX31
static struct map_desc mx31_io_desc[] __initdata = {
@@ -52,17 +46,25 @@ static struct map_desc mx31_io_desc[] __initdata = {
*/
void __init mx31_map_io(void)
{
+ iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc));
+}
+
+void __init imx31_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX31);
mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR));
-
- iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc));
}
-int imx31_register_gpios(void);
+static struct mxc_gpio_port imx31_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 0, 1, MX31_INT_GPIO1),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 1, 2, MX31_INT_GPIO2),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 2, 3, MX31_INT_GPIO3),
+};
+
void __init mx31_init_irq(void)
{
mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR));
- imx31_register_gpios();
+ mxc_gpio_init(imx31_gpio_ports, ARRAY_SIZE(imx31_gpio_ports));
}
#endif /* ifdef CONFIG_SOC_IMX31 */
@@ -77,18 +79,26 @@ static struct map_desc mx35_io_desc[] __initdata = {
void __init mx35_map_io(void)
{
+ iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc));
+}
+
+void __init imx35_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX35);
mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR));
mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR));
-
- iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc));
}
-int imx35_register_gpios(void);
+static struct mxc_gpio_port imx35_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 0, 1, MX35_INT_GPIO1),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 1, 2, MX35_INT_GPIO2),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 2, 3, MX35_INT_GPIO3),
+};
+
void __init mx35_init_irq(void)
{
mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR));
- imx35_register_gpios();
+ mxc_gpio_init(imx35_gpio_ports, ARRAY_SIZE(imx35_gpio_ports));
}
#endif /* ifdef CONFIG_SOC_IMX35 */
@@ -129,4 +139,3 @@ static int mxc_init_l2x0(void)
arch_initcall(mxc_init_l2x0);
#endif
-
diff --git a/arch/arm/mach-mx3/mx31moboard-devboard.c b/arch/arm/mach-mx3/mx31moboard-devboard.c
index 94a0b9e4b7f3..6410b9c48a02 100644
--- a/arch/arm/mach-mx3/mx31moboard-devboard.c
+++ b/arch/arm/mach-mx3/mx31moboard-devboard.c
@@ -15,6 +15,7 @@
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -149,7 +150,10 @@ static int devboard_usbh1_hw_init(struct platform_device *pdev)
mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG);
mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG);
- return 0;
+ mdelay(10);
+
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_SINGLE_UNI);
}
#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
@@ -187,7 +191,6 @@ static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
.init = devboard_usbh1_hw_init,
.portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
};
static int __init devboard_usbh1_init(void)
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c
index f449a97ae1a2..57f7b00cb709 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c
@@ -265,7 +265,10 @@ static int marxbot_usbh1_hw_init(struct platform_device *pdev)
mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG);
mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG);
- return 0;
+ mdelay(10);
+
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_INTERFACE_SINGLE_UNI);
}
#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B)
@@ -303,7 +306,6 @@ static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on)
static struct mxc_usbh_platform_data usbh1_pdata __initdata = {
.init = marxbot_usbh1_hw_init,
.portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL,
- .flags = MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_INTERFACE_SINGLE_UNI,
};
static int __init marxbot_usbh1_init(void)
diff --git a/arch/arm/mach-mx3/mx31moboard-smartbot.c b/arch/arm/mach-mx3/mx31moboard-smartbot.c
index bbec3c82264a..35f806e737c1 100644
--- a/arch/arm/mach-mx3/mx31moboard-smartbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-smartbot.c
@@ -123,17 +123,24 @@ static const struct fsl_usb2_platform_data usb_pdata __initconst = {
#if defined(CONFIG_USB_ULPI)
+static int smartbot_otg_init(struct platform_device *pdev)
+{
+ return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED);
+}
+
static struct mxc_usbh_platform_data otg_host_pdata __initdata = {
+ .init = smartbot_otg_init,
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
- .flags = MXC_EHCI_POWER_PINS_ENABLED,
};
static int __init smartbot_otg_host_init(void)
{
struct platform_device *pdev;
- otg_host_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+ otg_host_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT);
+ if (!otg_host_pdata.otg)
+ return -ENODEV;
pdev = imx31_add_mxc_ehci_otg(&otg_host_pdata);
if (IS_ERR(pdev))
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index de4fa992fc3e..83ee08847d4d 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -1,5 +1,6 @@
if ARCH_MX5
-# ARCH_MX51 and ARCH_MX50 are left for compatibility
+# ARCH_MX50/51/53 are left to mark places where prevent multi-soc in single
+# image. So for most time, SOC_IMX50/51/53 should be used.
config ARCH_MX50
bool
@@ -50,6 +51,7 @@ config MACH_MX51_BABBAGE
config MACH_MX51_3DS
bool "Support MX51PDK (3DS)"
select SOC_IMX51
+ select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
@@ -112,19 +114,32 @@ config MACH_EUKREA_MBIMXSD51_BASEBOARD
endchoice
-config MACH_MX51_EFIKAMX
- bool "Support MX51 Genesi Efika MX nettop"
+config MX51_EFIKA_COMMON
+ bool
select SOC_IMX51
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
select IMX_HAVE_PLATFORM_SPI_IMX
+ select MXC_ULPI if USB_ULPI
+
+config MACH_MX51_EFIKAMX
+ bool "Support MX51 Genesi Efika MX nettop"
+ select MX51_EFIKA_COMMON
help
Include support for Genesi Efika MX nettop. This includes specific
configurations for the board and its peripherals.
+config MACH_MX51_EFIKASB
+ bool "Support MX51 Genesi Efika Smartbook"
+ select MX51_EFIKA_COMMON
+ help
+ Include support for Genesi Efika Smartbook. This includes specific
+ configurations for the board and its peripherals.
+
config MACH_MX53_EVK
bool "Support MX53 EVK platforms"
select SOC_IMX53
+ select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
@@ -136,6 +151,8 @@ config MACH_MX53_EVK
config MACH_MX53_SMD
bool "Support MX53 SMD platforms"
select SOC_IMX53
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
help
Include support for MX53 SMD platform. This includes specific
@@ -144,7 +161,10 @@ config MACH_MX53_SMD
config MACH_MX53_LOCO
bool "Support MX53 LOCO platforms"
select SOC_IMX53
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
help
Include support for MX53 LOCO platform. This includes specific
configurations for the board and its peripherals.
@@ -157,6 +177,7 @@ config MACH_MX50_RDP
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
select IMX_HAVE_PLATFORM_SPI_IMX
+ select IMX_HAVE_PLATFORM_FEC
help
Include support for MX50 reference design platform (RDP) board. This
includes specific configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 0d43be98e51c..4f63048be3ca 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -3,7 +3,7 @@
#
# Object file lists.
-obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o
+obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o
obj-$(CONFIG_SOC_IMX50) += mm-mx50.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
@@ -16,5 +16,7 @@ obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o
obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o
+obj-$(CONFIG_MACH_MX51_EFIKASB) += board-mx51_efikasb.o
obj-$(CONFIG_MACH_MX50_RDP) += board-mx50_rdp.o
diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c
index f8652ef25f85..d0296a94c475 100644
--- a/arch/arm/mach-mx5/board-cpuimx51.c
+++ b/arch/arm/mach-mx5/board-cpuimx51.c
@@ -60,7 +60,6 @@
#define MX51_USB_PLL_DIV_19_2_MHZ 0x01
#define MX51_USB_PLL_DIV_24_MHZ 0x02
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x400000),
@@ -105,12 +104,9 @@ static struct platform_device serial_device = {
.platform_data = serial_platform_data,
},
};
-#endif
static struct platform_device *devices[] __initdata = {
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
&serial_device,
-#endif
};
static iomux_v3_cfg_t eukrea_cpuimx51_pads[] = {
@@ -188,7 +184,10 @@ static int initialize_otg_port(struct platform_device *pdev)
v |= MX51_USB_PLL_DIV_19_2_MHZ;
__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
}
static int initialize_usbh1_port(struct platform_device *pdev)
@@ -206,13 +205,16 @@ static int initialize_usbh1_port(struct platform_device *pdev)
v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
__raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_ITC_NO_THRESHOLD);
}
static struct mxc_usbh_platform_data dr_utmi_config = {
.init = initialize_otg_port,
.portsc = MXC_EHCI_UTMI_16BIT,
- .flags = MXC_EHCI_INTERNAL_PHY,
};
static struct fsl_usb2_platform_data usb_pdata = {
@@ -223,7 +225,6 @@ static struct fsl_usb2_platform_data usb_pdata = {
static struct mxc_usbh_platform_data usbh1_config = {
.init = initialize_usbh1_port,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
};
static int otg_mode_host;
@@ -298,7 +299,8 @@ MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
/* Maintainer: Eric Bénard <eric@eukrea.com> */
.boot_params = MX51_PHYS_OFFSET + 0x100,
.map_io = mx51_map_io,
+ .init_early = imx51_init_early,
.init_irq = mx51_init_irq,
- .init_machine = eukrea_cpuimx51_init,
.timer = &mxc_timer,
+ .init_machine = eukrea_cpuimx51_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c
index ad931895d8b6..29b180823bf5 100644
--- a/arch/arm/mach-mx5/board-cpuimx51sd.c
+++ b/arch/arm/mach-mx5/board-cpuimx51sd.c
@@ -42,6 +42,7 @@
#include "devices-imx51.h"
#include "devices.h"
+#include "cpu_op-mx51.h"
#define USBH1_RST IMX_GPIO_NR(2, 28)
#define ETH_RST IMX_GPIO_NR(2, 31)
@@ -109,7 +110,7 @@ static iomux_v3_cfg_t eukrea_cpuimx51sd_pads[] = {
/* Touchscreen */
/* IRQ */
- _MX51_PAD_CSI1_D8__GPIO3_12 | MUX_PAD_CTRL(PAD_CTL_PUS_22K_UP |
+ _MX51_PAD_GPIO_NAND__GPIO_NAND | MUX_PAD_CTRL(PAD_CTL_PUS_22K_UP |
PAD_CTL_PKE | PAD_CTL_SRE_FAST |
PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
};
@@ -118,15 +119,9 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-static int ts_get_pendown_state(void)
-{
- return gpio_get_value(TSC2007_IRQGPIO) ? 0 : 1;
-}
-
static struct tsc2007_platform_data tsc2007_info = {
.model = 2007,
.x_plate_ohms = 180,
- .get_pendown_state = ts_get_pendown_state,
};
static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
@@ -167,7 +162,10 @@ static int initialize_otg_port(struct platform_device *pdev)
v |= MX51_USB_PLL_DIV_19_2_MHZ;
__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
}
static int initialize_usbh1_port(struct platform_device *pdev)
@@ -186,13 +184,16 @@ static int initialize_usbh1_port(struct platform_device *pdev)
__raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN,
usbother_base + MX51_USB_CTRL_1_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_ITC_NO_THRESHOLD);
}
static struct mxc_usbh_platform_data dr_utmi_config = {
.init = initialize_otg_port,
.portsc = MXC_EHCI_UTMI_16BIT,
- .flags = MXC_EHCI_INTERNAL_PHY,
};
static struct fsl_usb2_platform_data usb_pdata = {
@@ -203,7 +204,6 @@ static struct fsl_usb2_platform_data usb_pdata = {
static struct mxc_usbh_platform_data usbh1_config = {
.init = initialize_usbh1_port,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
};
static int otg_mode_host;
@@ -242,7 +242,7 @@ static struct mcp251x_platform_data mcp251x_info = {
static struct spi_board_info cpuimx51sd_spi_device[] = {
{
.modalias = "mcp2515",
- .max_speed_hz = 6500000,
+ .max_speed_hz = 10000000,
.bus_num = 0,
.mode = SPI_MODE_0,
.chip_select = 0,
@@ -269,6 +269,10 @@ static void __init eukrea_cpuimx51sd_init(void)
mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51sd_pads,
ARRAY_SIZE(eukrea_cpuimx51sd_pads));
+#if defined(CONFIG_CPU_FREQ_IMX)
+ get_cpu_op = mx51_get_cpu_op;
+#endif
+
imx51_add_imx_uart(0, &uart_pdata);
imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
@@ -329,7 +333,8 @@ MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD")
/* Maintainer: Eric Bénard <eric@eukrea.com> */
.boot_params = MX51_PHYS_OFFSET + 0x100,
.map_io = mx51_map_io,
+ .init_early = imx51_init_early,
.init_irq = mx51_init_irq,
- .init_machine = eukrea_cpuimx51sd_init,
.timer = &mxc_timer,
+ .init_machine = eukrea_cpuimx51sd_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx50_rdp.c b/arch/arm/mach-mx5/board-mx50_rdp.c
index fd32e4c450e8..dedf7f2d6d0f 100644
--- a/arch/arm/mach-mx5/board-mx50_rdp.c
+++ b/arch/arm/mach-mx5/board-mx50_rdp.c
@@ -35,7 +35,10 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-#include "devices-mx50.h"
+#include "devices-imx50.h"
+
+#define FEC_EN IMX_GPIO_NR(6, 23)
+#define FEC_RESET_B IMX_GPIO_NR(4, 12)
static iomux_v3_cfg_t mx50_rdp_pads[] __initdata = {
/* SD1 */
@@ -102,7 +105,7 @@ static iomux_v3_cfg_t mx50_rdp_pads[] __initdata = {
MX50_PAD_I2C3_SCL__USBOTG_OC,
MX50_PAD_SSI_RXC__FEC_MDIO,
- MX50_PAD_SSI_RXC__FEC_MDIO,
+ MX50_PAD_SSI_RXFS__FEC_MDC,
MX50_PAD_DISP_D0__FEC_TXCLK,
MX50_PAD_DISP_D1__FEC_RX_ER,
MX50_PAD_DISP_D2__FEC_RX_DV,
@@ -111,7 +114,6 @@ static iomux_v3_cfg_t mx50_rdp_pads[] __initdata = {
MX50_PAD_DISP_D5__FEC_TX_EN,
MX50_PAD_DISP_D6__FEC_TXD1,
MX50_PAD_DISP_D7__FEC_TXD0,
- MX50_PAD_SSI_RXFS__FEC_MDC,
MX50_PAD_I2C3_SDA__GPIO_6_23,
MX50_PAD_ECSPI1_SCLK__GPIO_4_12,
@@ -168,6 +170,24 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
+static const struct fec_platform_data fec_data __initconst = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static inline void mx50_rdp_fec_reset(void)
+{
+ gpio_request(FEC_EN, "fec-en");
+ gpio_direction_output(FEC_EN, 0);
+ gpio_request(FEC_RESET_B, "fec-reset_b");
+ gpio_direction_output(FEC_RESET_B, 0);
+ msleep(1);
+ gpio_set_value(FEC_RESET_B, 1);
+}
+
+static const struct imxi2c_platform_data i2c_data __initconst = {
+ .bitrate = 100000,
+};
+
/*
* Board specific initialization.
*/
@@ -178,6 +198,11 @@ static void __init mx50_rdp_board_init(void)
imx50_add_imx_uart(0, &uart_pdata);
imx50_add_imx_uart(1, &uart_pdata);
+ mx50_rdp_fec_reset();
+ imx50_add_fec(&fec_data);
+ imx50_add_imx_i2c(0, &i2c_data);
+ imx50_add_imx_i2c(1, &i2c_data);
+ imx50_add_imx_i2c(2, &i2c_data);
}
static void __init mx50_rdp_timer_init(void)
@@ -191,7 +216,8 @@ static struct sys_timer mx50_rdp_timer = {
MACHINE_START(MX50_RDP, "Freescale MX50 Reference Design Platform")
.map_io = mx50_map_io,
+ .init_early = imx50_init_early,
.init_irq = mx50_init_irq,
- .init_machine = mx50_rdp_board_init,
.timer = &mx50_rdp_timer,
+ .init_machine = mx50_rdp_board_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-mx5/board-mx51_3ds.c
index 49d644842379..63dfbeafbc1e 100644
--- a/arch/arm/mach-mx5/board-mx51_3ds.c
+++ b/arch/arm/mach-mx5/board-mx51_3ds.c
@@ -71,24 +71,10 @@ static iomux_v3_cfg_t mx51_3ds_pads[] = {
};
/* Serial ports */
-#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-static inline void mxc_init_imx_uart(void)
-{
- imx51_add_imx_uart(0, &uart_pdata);
- imx51_add_imx_uart(1, &uart_pdata);
- imx51_add_imx_uart(2, &uart_pdata);
-}
-#else /* !SERIAL_IMX */
-static inline void mxc_init_imx_uart(void)
-{
-}
-#endif /* SERIAL_IMX */
-
-#if defined(CONFIG_KEYBOARD_IMX) || defined(CONFIG_KEYBOARD_IMX_MODULE)
static int mx51_3ds_board_keymap[] = {
KEY(0, 0, KEY_1),
KEY(0, 1, KEY_2),
@@ -124,16 +110,6 @@ static const struct matrix_keymap_data mx51_3ds_map_data __initconst = {
.keymap_size = ARRAY_SIZE(mx51_3ds_board_keymap),
};
-static void mxc_init_keypad(void)
-{
- imx51_add_imx_keypad(&mx51_3ds_map_data);
-}
-#else
-static inline void mxc_init_keypad(void)
-{
-}
-#endif
-
static int mx51_3ds_spi2_cs[] = {
MXC_SPI_CS(0),
MX51_3DS_ECSPI2_CS,
@@ -157,11 +133,14 @@ static struct spi_board_info mx51_3ds_spi_nor_device[] = {
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init mx51_3ds_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx51_3ds_pads,
ARRAY_SIZE(mx51_3ds_pads));
- mxc_init_imx_uart();
+
+ imx51_add_imx_uart(0, &uart_pdata);
+ imx51_add_imx_uart(1, &uart_pdata);
+ imx51_add_imx_uart(2, &uart_pdata);
imx51_add_ecspi(1, &mx51_3ds_ecspi2_pdata);
spi_register_board_info(mx51_3ds_spi_nor_device,
@@ -172,7 +151,8 @@ static void __init mxc_board_init(void)
"devices on the board are unusable.\n");
imx51_add_sdhci_esdhc_imx(0, NULL);
- mxc_init_keypad();
+ imx51_add_imx_keypad(&mx51_3ds_map_data);
+ imx51_add_imx2_wdt(0, NULL);
}
static void __init mx51_3ds_timer_init(void)
@@ -180,15 +160,16 @@ static void __init mx51_3ds_timer_init(void)
mx51_clocks_init(32768, 24000000, 22579200, 0);
}
-static struct sys_timer mxc_timer = {
- .init = mx51_3ds_timer_init,
+static struct sys_timer mx51_3ds_timer = {
+ .init = mx51_3ds_timer_init,
};
MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.boot_params = MX51_PHYS_OFFSET + 0x100,
.map_io = mx51_map_io,
+ .init_early = imx51_init_early,
.init_irq = mx51_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mxc_timer,
+ .timer = &mx51_3ds_timer,
+ .init_machine = mx51_3ds_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index 1d231e84107c..b2ecd194e76d 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -161,23 +161,10 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
};
/* Serial ports */
-#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-static inline void mxc_init_imx_uart(void)
-{
- imx51_add_imx_uart(0, &uart_pdata);
- imx51_add_imx_uart(1, &uart_pdata);
- imx51_add_imx_uart(2, &uart_pdata);
-}
-#else /* !SERIAL_IMX */
-static inline void mxc_init_imx_uart(void)
-{
-}
-#endif /* SERIAL_IMX */
-
static const struct imxi2c_platform_data babbage_i2c_data __initconst = {
.bitrate = 100000,
};
@@ -272,7 +259,10 @@ static int initialize_otg_port(struct platform_device *pdev)
v |= MX51_USB_PLL_DIV_19_2_MHZ;
__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
}
static int initialize_usbh1_port(struct platform_device *pdev)
@@ -290,13 +280,16 @@ static int initialize_usbh1_port(struct platform_device *pdev)
v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
__raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
iounmap(usb_base);
- return 0;
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
+ MXC_EHCI_ITC_NO_THRESHOLD);
}
static struct mxc_usbh_platform_data dr_utmi_config = {
.init = initialize_otg_port,
.portsc = MXC_EHCI_UTMI_16BIT,
- .flags = MXC_EHCI_INTERNAL_PHY,
};
static struct fsl_usb2_platform_data usb_pdata = {
@@ -307,7 +300,6 @@ static struct fsl_usb2_platform_data usb_pdata = {
static struct mxc_usbh_platform_data usbh1_config = {
.init = initialize_usbh1_port,
.portsc = MXC_EHCI_MODE_ULPI,
- .flags = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
};
static int otg_mode_host;
@@ -349,7 +341,7 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
/*
* Board specific initialization.
*/
-static void __init mxc_board_init(void)
+static void __init mx51_babbage_init(void)
{
iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP;
iomux_v3_cfg_t power_key = _MX51_PAD_EIM_A27__GPIO2_21 |
@@ -360,7 +352,11 @@ static void __init mxc_board_init(void)
#endif
mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
ARRAY_SIZE(mx51babbage_pads));
- mxc_init_imx_uart();
+
+ imx51_add_imx_uart(0, &uart_pdata);
+ imx51_add_imx_uart(1, &uart_pdata);
+ imx51_add_imx_uart(2, &uart_pdata);
+
babbage_fec_reset();
imx51_add_fec(NULL);
@@ -399,15 +395,16 @@ static void __init mx51_babbage_timer_init(void)
mx51_clocks_init(32768, 24000000, 22579200, 0);
}
-static struct sys_timer mxc_timer = {
- .init = mx51_babbage_timer_init,
+static struct sys_timer mx51_babbage_timer = {
+ .init = mx51_babbage_timer_init,
};
MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
/* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
.boot_params = MX51_PHYS_OFFSET + 0x100,
.map_io = mx51_map_io,
+ .init_early = imx51_init_early,
.init_irq = mx51_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mxc_timer,
+ .timer = &mx51_babbage_timer,
+ .init_machine = mx51_babbage_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c
index b7946f8e8d40..acab1911cb3c 100644
--- a/arch/arm/mach-mx5/board-mx51_efikamx.c
+++ b/arch/arm/mach-mx5/board-mx51_efikamx.c
@@ -25,6 +25,9 @@
#include <linux/fsl_devices.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
#include <mach/common.h>
#include <mach/hardware.h>
@@ -40,8 +43,7 @@
#include "devices-imx51.h"
#include "devices.h"
-
-#define MX51_USB_PLL_DIV_24_MHZ 0x01
+#include "efika.h"
#define EFIKAMX_PCBID0 IMX_GPIO_NR(3, 16)
#define EFIKAMX_PCBID1 IMX_GPIO_NR(3, 17)
@@ -53,13 +55,14 @@
#define EFIKAMX_POWER_KEY IMX_GPIO_NR(2, 31)
-#define EFIKAMX_SPI_CS0 IMX_GPIO_NR(4, 24)
-#define EFIKAMX_SPI_CS1 IMX_GPIO_NR(4, 25)
-
/* board 1.1 doesn't have same reset gpio */
#define EFIKAMX_RESET1_1 IMX_GPIO_NR(3, 2)
#define EFIKAMX_RESET IMX_GPIO_NR(1, 4)
+#define EFIKAMX_POWEROFF IMX_GPIO_NR(4, 13)
+
+#define EFIKAMX_PMIC IMX_GPIO_NR(1, 6)
+
/* the pci ids pin have pull up. they're driven low according to board id */
#define MX51_PAD_PCBID0 IOMUX_PAD(0x518, 0x130, 3, 0x0, 0, PAD_CTL_PUS_100K_UP)
#define MX51_PAD_PCBID1 IOMUX_PAD(0x51C, 0x134, 3, 0x0, 0, PAD_CTL_PUS_100K_UP)
@@ -67,38 +70,11 @@
#define MX51_PAD_PWRKEY IOMUX_PAD(0x48c, 0x0f8, 1, 0x0, 0, PAD_CTL_PUS_100K_UP | PAD_CTL_PKE)
static iomux_v3_cfg_t mx51efikamx_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,
/* board id */
MX51_PAD_PCBID0,
MX51_PAD_PCBID1,
MX51_PAD_PCBID2,
- /* SD 1 */
- 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,
-
- /* SD 2 */
- 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,
-
- /* SD/MMC WP/CD */
- MX51_PAD_GPIO1_0__SD1_CD,
- MX51_PAD_GPIO1_1__SD1_WP,
- MX51_PAD_GPIO1_7__SD2_WP,
- MX51_PAD_GPIO1_8__SD2_CD,
-
/* leds */
MX51_PAD_CSI1_D9__GPIO3_13,
MX51_PAD_CSI1_VSYNC__GPIO3_14,
@@ -107,64 +83,12 @@ static iomux_v3_cfg_t mx51efikamx_pads[] = {
/* power key */
MX51_PAD_PWRKEY,
- /* spi */
- MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
- MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
- MX51_PAD_CSPI1_SS0__GPIO4_24,
- MX51_PAD_CSPI1_SS1__GPIO4_25,
- MX51_PAD_CSPI1_RDY__ECSPI1_RDY,
- MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
-
/* reset */
MX51_PAD_DI1_PIN13__GPIO3_2,
MX51_PAD_GPIO1_4__GPIO1_4,
-};
-/* Serial ports */
-#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static const struct imxuart_platform_data uart_pdata = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static inline void mxc_init_imx_uart(void)
-{
- imx51_add_imx_uart(0, &uart_pdata);
- imx51_add_imx_uart(1, &uart_pdata);
- imx51_add_imx_uart(2, &uart_pdata);
-}
-#else /* !SERIAL_IMX */
-static inline void mxc_init_imx_uart(void)
-{
-}
-#endif /* SERIAL_IMX */
-
-/* This function is board specific as the bit mask for the plldiv will also
- * be different for other Freescale SoCs, thus a common bitmask is not
- * possible and cannot get place in /plat-mxc/ehci.c.
- */
-static int initialize_otg_port(struct platform_device *pdev)
-{
- u32 v;
- void __iomem *usb_base;
- void __iomem *usbother_base;
- usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
- if (!usb_base)
- return -ENOMEM;
- usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET);
-
- /* Set the PHY clock to 19.2MHz */
- v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
- v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
- v |= MX51_USB_PLL_DIV_24_MHZ;
- __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
- iounmap(usb_base);
- return 0;
-}
-
-static struct mxc_usbh_platform_data dr_utmi_config = {
- .init = initialize_otg_port,
- .portsc = MXC_EHCI_UTMI_16BIT,
- .flags = MXC_EHCI_INTERNAL_PHY,
+ /* power off */
+ MX51_PAD_CSI2_VSYNC__GPIO4_13,
};
/* PCBID2 PCBID1 PCBID0 STATE
@@ -265,47 +189,6 @@ static const struct gpio_keys_platform_data mx51_efikamx_powerkey_data __initcon
.nbuttons = ARRAY_SIZE(mx51_efikamx_powerkey),
};
-static struct mtd_partition mx51_efikamx_spi_nor_partitions[] = {
- {
- .name = "u-boot",
- .offset = 0,
- .size = SZ_256K,
- },
- {
- .name = "config",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_64K,
- },
-};
-
-static struct flash_platform_data mx51_efikamx_spi_flash_data = {
- .name = "spi_flash",
- .parts = mx51_efikamx_spi_nor_partitions,
- .nr_parts = ARRAY_SIZE(mx51_efikamx_spi_nor_partitions),
- .type = "sst25vf032b",
-};
-
-static struct spi_board_info mx51_efikamx_spi_board_info[] __initdata = {
- {
- .modalias = "m25p80",
- .max_speed_hz = 25000000,
- .bus_num = 0,
- .chip_select = 1,
- .platform_data = &mx51_efikamx_spi_flash_data,
- .irq = -1,
- },
-};
-
-static int mx51_efikamx_spi_cs[] = {
- EFIKAMX_SPI_CS0,
- EFIKAMX_SPI_CS1,
-};
-
-static const struct spi_imx_master mx51_efikamx_spi_pdata __initconst = {
- .chipselect = mx51_efikamx_spi_cs,
- .num_chipselect = ARRAY_SIZE(mx51_efikamx_spi_cs),
-};
-
void mx51_efikamx_reset(void)
{
if (system_rev == 0x11)
@@ -314,14 +197,53 @@ void mx51_efikamx_reset(void)
gpio_direction_output(EFIKAMX_RESET, 0);
}
-static void __init mxc_board_init(void)
+static struct regulator *pwgt1, *pwgt2, *coincell;
+
+static void mx51_efikamx_power_off(void)
+{
+ if (!IS_ERR(coincell))
+ regulator_disable(coincell);
+
+ if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) {
+ regulator_disable(pwgt2);
+ regulator_disable(pwgt1);
+ }
+ gpio_direction_output(EFIKAMX_POWEROFF, 1);
+}
+
+static int __init mx51_efikamx_power_init(void)
+{
+ if (machine_is_mx51_efikamx()) {
+ pwgt1 = regulator_get(NULL, "pwgt1");
+ pwgt2 = regulator_get(NULL, "pwgt2");
+ if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) {
+ regulator_enable(pwgt1);
+ regulator_enable(pwgt2);
+ }
+ gpio_request(EFIKAMX_POWEROFF, "poweroff");
+ pm_power_off = mx51_efikamx_power_off;
+
+ /* enable coincell charger. maybe need a small power driver ? */
+ coincell = regulator_get(NULL, "coincell");
+ if (!IS_ERR(coincell)) {
+ regulator_set_voltage(coincell, 3000000, 3000000);
+ regulator_enable(coincell);
+ }
+
+ regulator_has_full_constraints();
+ }
+
+ return 0;
+}
+late_initcall(mx51_efikamx_power_init);
+
+static void __init mx51_efikamx_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx51efikamx_pads,
ARRAY_SIZE(mx51efikamx_pads));
+ efika_board_common_init();
+
mx51_efikamx_board_id();
- mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
- mxc_init_imx_uart();
- imx51_add_sdhci_esdhc_imx(0, NULL);
/* on < 1.2 boards both SD controllers are used */
if (system_rev < 0x12) {
@@ -332,10 +254,6 @@ static void __init mxc_board_init(void)
platform_device_register(&mx51_efikamx_leds_device);
imx51_add_gpio_keys(&mx51_efikamx_powerkey_data);
- spi_register_board_info(mx51_efikamx_spi_board_info,
- ARRAY_SIZE(mx51_efikamx_spi_board_info));
- imx51_add_ecspi(0, &mx51_efikamx_spi_pdata);
-
if (system_rev == 0x11) {
gpio_request(EFIKAMX_RESET1_1, "reset");
gpio_direction_output(EFIKAMX_RESET1_1, 1);
@@ -343,6 +261,20 @@ static void __init mxc_board_init(void)
gpio_request(EFIKAMX_RESET, "reset");
gpio_direction_output(EFIKAMX_RESET, 1);
}
+
+ /*
+ * enable wifi by default only on mx
+ * sb and mx have same wlan pin but the value to enable it are
+ * different :/
+ */
+ gpio_request(EFIKA_WLAN_EN, "wlan_en");
+ gpio_direction_output(EFIKA_WLAN_EN, 0);
+ msleep(10);
+
+ gpio_request(EFIKA_WLAN_RESET, "wlan_rst");
+ gpio_direction_output(EFIKA_WLAN_RESET, 0);
+ msleep(10);
+ gpio_set_value(EFIKA_WLAN_RESET, 1);
}
static void __init mx51_efikamx_timer_init(void)
@@ -350,15 +282,16 @@ static void __init mx51_efikamx_timer_init(void)
mx51_clocks_init(32768, 24000000, 22579200, 24576000);
}
-static struct sys_timer mxc_timer = {
- .init = mx51_efikamx_timer_init,
+static struct sys_timer mx51_efikamx_timer = {
+ .init = mx51_efikamx_timer_init,
};
MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
/* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
.boot_params = MX51_PHYS_OFFSET + 0x100,
.map_io = mx51_map_io,
+ .init_early = imx51_init_early,
.init_irq = mx51_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mxc_timer,
+ .timer = &mx51_efikamx_timer,
+ .init_machine = mx51_efikamx_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c
new file mode 100644
index 000000000000..db04ce8462dc
--- /dev/null
+++ b/arch/arm/mach-mx5/board-mx51_efikasb.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * based on code from the following
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
+ * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <mach/ulpi.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+#include "efika.h"
+
+#define EFIKASB_USBH2_STP IMX_GPIO_NR(2, 20)
+#define EFIKASB_GREEN_LED IMX_GPIO_NR(1, 3)
+#define EFIKASB_WHITE_LED IMX_GPIO_NR(2, 25)
+#define EFIKASB_PCBID0 IMX_GPIO_NR(2, 28)
+#define EFIKASB_PCBID1 IMX_GPIO_NR(2, 29)
+#define EFIKASB_PWRKEY IMX_GPIO_NR(2, 31)
+#define EFIKASB_LID IMX_GPIO_NR(3, 14)
+#define EFIKASB_POWEROFF IMX_GPIO_NR(4, 13)
+#define EFIKASB_RFKILL IMX_GPIO_NR(3, 1)
+
+#define MX51_PAD_PWRKEY IOMUX_PAD(0x48c, 0x0f8, 1, 0x0, 0, PAD_CTL_PUS_100K_UP | PAD_CTL_PKE)
+
+static iomux_v3_cfg_t mx51efikasb_pads[] = {
+ /* USB HOST2 */
+ MX51_PAD_EIM_D16__USBH2_DATA0,
+ MX51_PAD_EIM_D17__USBH2_DATA1,
+ MX51_PAD_EIM_D18__USBH2_DATA2,
+ MX51_PAD_EIM_D19__USBH2_DATA3,
+ MX51_PAD_EIM_D20__USBH2_DATA4,
+ MX51_PAD_EIM_D21__USBH2_DATA5,
+ MX51_PAD_EIM_D22__USBH2_DATA6,
+ MX51_PAD_EIM_D23__USBH2_DATA7,
+ MX51_PAD_EIM_A24__USBH2_CLK,
+ MX51_PAD_EIM_A25__USBH2_DIR,
+ MX51_PAD_EIM_A26__USBH2_STP,
+ MX51_PAD_EIM_A27__USBH2_NXT,
+
+ /* leds */
+ MX51_PAD_EIM_CS0__GPIO2_25,
+ MX51_PAD_GPIO1_3__GPIO1_3,
+
+ /* pcb id */
+ MX51_PAD_EIM_CS3__GPIO2_28,
+ MX51_PAD_EIM_CS4__GPIO2_29,
+
+ /* lid */
+ MX51_PAD_CSI1_VSYNC__GPIO3_14,
+
+ /* power key*/
+ MX51_PAD_PWRKEY,
+
+ /* wifi/bt button */
+ MX51_PAD_DI1_PIN12__GPIO3_1,
+
+ /* power off */
+ MX51_PAD_CSI2_VSYNC__GPIO4_13,
+
+ /* wdog reset */
+ MX51_PAD_GPIO1_4__WDOG1_WDOG_B,
+
+ /* BT */
+ MX51_PAD_EIM_A17__GPIO2_11,
+};
+
+static int initialize_usbh2_port(struct platform_device *pdev)
+{
+ iomux_v3_cfg_t usbh2stp = MX51_PAD_EIM_A26__USBH2_STP;
+ iomux_v3_cfg_t usbh2gpio = MX51_PAD_EIM_A26__GPIO2_20;
+
+ mxc_iomux_v3_setup_pad(usbh2gpio);
+ gpio_request(EFIKASB_USBH2_STP, "usbh2_stp");
+ gpio_direction_output(EFIKASB_USBH2_STP, 0);
+ msleep(1);
+ gpio_set_value(EFIKASB_USBH2_STP, 1);
+ msleep(1);
+
+ gpio_free(EFIKASB_USBH2_STP);
+ mxc_iomux_v3_setup_pad(usbh2stp);
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_ITC_NO_THRESHOLD);
+}
+
+static struct mxc_usbh_platform_data usbh2_config = {
+ .init = initialize_usbh2_port,
+ .portsc = MXC_EHCI_MODE_ULPI,
+};
+
+static void __init mx51_efikasb_usb(void)
+{
+ usbh2_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND);
+ if (usbh2_config.otg)
+ mxc_register_device(&mxc_usbh2_device, &usbh2_config);
+}
+
+static struct gpio_led mx51_efikasb_leds[] = {
+ {
+ .name = "efikasb:green",
+ .default_trigger = "default-on",
+ .gpio = EFIKASB_GREEN_LED,
+ .active_low = 1,
+ },
+ {
+ .name = "efikasb:white",
+ .default_trigger = "caps",
+ .gpio = EFIKASB_WHITE_LED,
+ },
+};
+
+static struct gpio_led_platform_data mx51_efikasb_leds_data = {
+ .leds = mx51_efikasb_leds,
+ .num_leds = ARRAY_SIZE(mx51_efikasb_leds),
+};
+
+static struct platform_device mx51_efikasb_leds_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &mx51_efikasb_leds_data,
+ },
+};
+
+static struct gpio_keys_button mx51_efikasb_keys[] = {
+ {
+ .code = KEY_POWER,
+ .gpio = EFIKASB_PWRKEY,
+ .type = EV_PWR,
+ .desc = "Power Button",
+ .wakeup = 1,
+ .debounce_interval = 10, /* ms */
+ },
+ {
+ .code = SW_LID,
+ .gpio = EFIKASB_LID,
+ .type = EV_SW,
+ .desc = "Lid Switch",
+ },
+ {
+ /* SW_RFKILLALL vs KEY_RFKILL ? */
+ .code = SW_RFKILL_ALL,
+ .gpio = EFIKASB_RFKILL,
+ .type = EV_SW,
+ .desc = "rfkill",
+ },
+};
+
+static const struct gpio_keys_platform_data mx51_efikasb_keys_data __initconst = {
+ .buttons = mx51_efikasb_keys,
+ .nbuttons = ARRAY_SIZE(mx51_efikasb_keys),
+};
+
+static struct regulator *pwgt1, *pwgt2;
+
+static void mx51_efikasb_power_off(void)
+{
+ gpio_set_value(EFIKA_USB_PHY_RESET, 0);
+
+ if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) {
+ regulator_disable(pwgt2);
+ regulator_disable(pwgt1);
+ }
+ gpio_direction_output(EFIKASB_POWEROFF, 1);
+}
+
+static int __init mx51_efikasb_power_init(void)
+{
+ if (machine_is_mx51_efikasb()) {
+ pwgt1 = regulator_get(NULL, "pwgt1");
+ pwgt2 = regulator_get(NULL, "pwgt2");
+ if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) {
+ regulator_enable(pwgt1);
+ regulator_enable(pwgt2);
+ }
+ gpio_request(EFIKASB_POWEROFF, "poweroff");
+ pm_power_off = mx51_efikasb_power_off;
+
+ regulator_has_full_constraints();
+ }
+
+ return 0;
+}
+late_initcall(mx51_efikasb_power_init);
+
+/* 01 R1.3 board
+ 10 R2.0 board */
+static void __init mx51_efikasb_board_id(void)
+{
+ int id;
+
+ gpio_request(EFIKASB_PCBID0, "pcb id0");
+ gpio_direction_input(EFIKASB_PCBID0);
+ gpio_request(EFIKASB_PCBID1, "pcb id1");
+ gpio_direction_input(EFIKASB_PCBID1);
+
+ id = gpio_get_value(EFIKASB_PCBID0);
+ id |= gpio_get_value(EFIKASB_PCBID1) << 1;
+
+ switch (id) {
+ default:
+ break;
+ case 1:
+ system_rev = 0x13;
+ break;
+ case 2:
+ system_rev = 0x20;
+ break;
+ }
+}
+
+static void __init efikasb_board_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx51efikasb_pads,
+ ARRAY_SIZE(mx51efikasb_pads));
+ efika_board_common_init();
+
+ mx51_efikasb_board_id();
+ mx51_efikasb_usb();
+ imx51_add_sdhci_esdhc_imx(1, NULL);
+
+ platform_device_register(&mx51_efikasb_leds_device);
+ imx51_add_gpio_keys(&mx51_efikasb_keys_data);
+
+}
+
+static void __init mx51_efikasb_timer_init(void)
+{
+ mx51_clocks_init(32768, 24000000, 22579200, 24576000);
+}
+
+static struct sys_timer mx51_efikasb_timer = {
+ .init = mx51_efikasb_timer_init,
+};
+
+MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook")
+ .boot_params = MX51_PHYS_OFFSET + 0x100,
+ .map_io = mx51_map_io,
+ .init_early = imx51_init_early,
+ .init_irq = mx51_init_irq,
+ .init_machine = efikasb_board_init,
+ .timer = &mx51_efikasb_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-mx5/board-mx53_evk.c
index caee04c08238..7b5735c5ea59 100644
--- a/arch/arm/mach-mx5/board-mx53_evk.c
+++ b/arch/arm/mach-mx5/board-mx53_evk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2010 Yong Shen. <Yong.Shen@linaro.org>
*/
@@ -42,28 +42,24 @@
#include "devices-imx53.h"
static iomux_v3_cfg_t mx53_evk_pads[] = {
- MX53_PAD_CSI0_D10__UART1_TXD,
- MX53_PAD_CSI0_D11__UART1_RXD,
- MX53_PAD_ATA_DIOW__UART1_TXD,
- MX53_PAD_ATA_DMACK__UART1_RXD,
+ MX53_PAD_CSI0_DAT10__UART1_TXD_MUX,
+ MX53_PAD_CSI0_DAT11__UART1_RXD_MUX,
- 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_PATA_BUFFER_EN__UART2_RXD_MUX,
+ MX53_PAD_PATA_DMARQ__UART2_TXD_MUX,
+ MX53_PAD_PATA_DIOR__UART2_RTS,
+ MX53_PAD_PATA_INTRQ__UART2_CTS,
- MX53_PAD_ATA_CS_0__UART3_TXD,
- MX53_PAD_ATA_CS_1__UART3_RXD,
- MX53_PAD_ATA_DA_1__UART3_CTS,
- MX53_PAD_ATA_DA_2__UART3_RTS,
+ MX53_PAD_PATA_CS_0__UART3_TXD_MUX,
+ MX53_PAD_PATA_CS_1__UART3_RXD_MUX,
- MX53_PAD_EIM_D16__CSPI1_SCLK,
- MX53_PAD_EIM_D17__CSPI1_MISO,
- MX53_PAD_EIM_D18__CSPI1_MOSI,
+ MX53_PAD_EIM_D16__ECSPI1_SCLK,
+ MX53_PAD_EIM_D17__ECSPI1_MISO,
+ MX53_PAD_EIM_D18__ECSPI1_MOSI,
/* ecspi chip select lines */
- MX53_PAD_EIM_EB2__GPIO_2_30,
- MX53_PAD_EIM_D19__GPIO_3_19,
+ MX53_PAD_EIM_EB2__GPIO2_30,
+ MX53_PAD_EIM_D19__GPIO3_19,
};
static const struct imxuart_platform_data mx53_evk_uart_pdata __initconst = {
@@ -72,9 +68,9 @@ static const struct imxuart_platform_data mx53_evk_uart_pdata __initconst = {
static inline void mx53_evk_init_uart(void)
{
- imx53_add_imx_uart(0, &mx53_evk_uart_pdata);
+ imx53_add_imx_uart(0, NULL);
imx53_add_imx_uart(1, &mx53_evk_uart_pdata);
- imx53_add_imx_uart(2, &mx53_evk_uart_pdata);
+ imx53_add_imx_uart(2, NULL);
}
static const struct imxi2c_platform_data mx53_evk_i2c_data __initconst = {
@@ -139,6 +135,7 @@ static void __init mx53_evk_board_init(void)
spi_register_board_info(mx53_evk_spi_board_info,
ARRAY_SIZE(mx53_evk_spi_board_info));
imx53_add_ecspi(0, &mx53_evk_spi_data);
+ imx53_add_imx2_wdt(0, NULL);
}
static void __init mx53_evk_timer_init(void)
@@ -152,7 +149,8 @@ static struct sys_timer mx53_evk_timer = {
MACHINE_START(MX53_EVK, "Freescale MX53 EVK Board")
.map_io = mx53_map_io,
+ .init_early = imx53_init_early,
.init_irq = mx53_init_irq,
- .init_machine = mx53_evk_board_init,
.timer = &mx53_evk_timer,
+ .init_machine = mx53_evk_board_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
index d1348e04ace3..0a18f8d23eb0 100644
--- a/arch/arm/mach-mx5/board-mx53_loco.c
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -39,33 +39,147 @@
#define LOCO_FEC_PHY_RST IMX_GPIO_NR(7, 6)
static iomux_v3_cfg_t mx53_loco_pads[] = {
- MX53_PAD_CSI0_D10__UART1_TXD,
- MX53_PAD_CSI0_D11__UART1_RXD,
- MX53_PAD_ATA_DIOW__UART1_TXD,
- MX53_PAD_ATA_DMACK__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_ATA_DA_1__UART3_CTS,
- MX53_PAD_ATA_DA_2__UART3_RTS,
+ /* FEC */
+ MX53_PAD_FEC_MDC__FEC_MDC,
+ MX53_PAD_FEC_MDIO__FEC_MDIO,
+ MX53_PAD_FEC_REF_CLK__FEC_TX_CLK,
+ MX53_PAD_FEC_RX_ER__FEC_RX_ER,
+ MX53_PAD_FEC_CRS_DV__FEC_RX_DV,
+ MX53_PAD_FEC_RXD1__FEC_RDATA_1,
+ MX53_PAD_FEC_RXD0__FEC_RDATA_0,
+ MX53_PAD_FEC_TX_EN__FEC_TX_EN,
+ MX53_PAD_FEC_TXD1__FEC_TDATA_1,
+ MX53_PAD_FEC_TXD0__FEC_TDATA_0,
+ /* FEC_nRST */
+ MX53_PAD_PATA_DA_0__GPIO7_6,
+ /* FEC_nINT */
+ MX53_PAD_PATA_DATA4__GPIO2_4,
+ /* AUDMUX5 */
+ MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC,
+ MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD,
+ MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS,
+ MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD,
+ /* I2C2 */
+ MX53_PAD_KEY_COL3__I2C2_SCL,
+ MX53_PAD_KEY_ROW3__I2C2_SDA,
+ /* SD1 */
+ MX53_PAD_SD1_CMD__ESDHC1_CMD,
+ MX53_PAD_SD1_CLK__ESDHC1_CLK,
+ MX53_PAD_SD1_DATA0__ESDHC1_DAT0,
+ MX53_PAD_SD1_DATA1__ESDHC1_DAT1,
+ MX53_PAD_SD1_DATA2__ESDHC1_DAT2,
+ MX53_PAD_SD1_DATA3__ESDHC1_DAT3,
+ /* SD3 */
+ MX53_PAD_PATA_DATA8__ESDHC3_DAT0,
+ MX53_PAD_PATA_DATA9__ESDHC3_DAT1,
+ MX53_PAD_PATA_DATA10__ESDHC3_DAT2,
+ MX53_PAD_PATA_DATA11__ESDHC3_DAT3,
+ MX53_PAD_PATA_DATA0__ESDHC3_DAT4,
+ MX53_PAD_PATA_DATA1__ESDHC3_DAT5,
+ MX53_PAD_PATA_DATA2__ESDHC3_DAT6,
+ MX53_PAD_PATA_DATA3__ESDHC3_DAT7,
+ MX53_PAD_PATA_IORDY__ESDHC3_CLK,
+ MX53_PAD_PATA_RESET_B__ESDHC3_CMD,
+ /* SD3_CD */
+ MX53_PAD_EIM_DA11__GPIO3_11,
+ /* SD3_WP */
+ MX53_PAD_EIM_DA12__GPIO3_12,
+ /* VGA */
+ MX53_PAD_EIM_OE__IPU_DI1_PIN7,
+ MX53_PAD_EIM_RW__IPU_DI1_PIN8,
+ /* DISPLB */
+ MX53_PAD_EIM_D20__IPU_SER_DISP0_CS,
+ MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK,
+ MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN,
+ MX53_PAD_EIM_D23__IPU_DI0_D0_CS,
+ /* DISP0_POWER_EN */
+ MX53_PAD_EIM_D24__GPIO3_24,
+ /* DISP0 DET INT */
+ MX53_PAD_EIM_D31__GPIO3_31,
+ /* LVDS */
+ MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3,
+ MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK,
+ MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2,
+ MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1,
+ MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0,
+ MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3,
+ MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2,
+ MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK,
+ MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1,
+ MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0,
+ /* I2C1 */
+ MX53_PAD_CSI0_DAT8__I2C1_SDA,
+ MX53_PAD_CSI0_DAT9__I2C1_SCL,
+ /* UART1 */
+ MX53_PAD_CSI0_DAT10__UART1_TXD_MUX,
+ MX53_PAD_CSI0_DAT11__UART1_RXD_MUX,
+ /* CSI0 */
+ MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12,
+ MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13,
+ MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14,
+ MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15,
+ MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16,
+ MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17,
+ MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18,
+ MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19,
+ MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC,
+ MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC,
+ MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK,
+ /* DISPLAY */
+ MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK,
+ MX53_PAD_DI0_PIN15__IPU_DI0_PIN15,
+ MX53_PAD_DI0_PIN2__IPU_DI0_PIN2,
+ MX53_PAD_DI0_PIN3__IPU_DI0_PIN3,
+ MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0,
+ MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1,
+ MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2,
+ MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3,
+ MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4,
+ MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5,
+ MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6,
+ MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7,
+ MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8,
+ MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9,
+ MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10,
+ MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11,
+ MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12,
+ MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13,
+ MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14,
+ MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15,
+ MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16,
+ MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17,
+ MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18,
+ MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19,
+ MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20,
+ MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21,
+ MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22,
+ MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23,
+ /* Audio CLK*/
+ MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK,
+ /* PWM */
+ MX53_PAD_GPIO_1__PWM2_PWMO,
+ /* SPDIF */
+ MX53_PAD_GPIO_7__SPDIF_PLOCK,
+ MX53_PAD_GPIO_17__SPDIF_OUT1,
+ /* GPIO */
+ MX53_PAD_PATA_DA_1__GPIO7_7,
+ MX53_PAD_PATA_DA_2__GPIO7_8,
+ MX53_PAD_PATA_DATA5__GPIO2_5,
+ MX53_PAD_PATA_DATA6__GPIO2_6,
+ MX53_PAD_PATA_DATA14__GPIO2_14,
+ MX53_PAD_PATA_DATA15__GPIO2_15,
+ MX53_PAD_PATA_INTRQ__GPIO7_2,
+ MX53_PAD_EIM_WAIT__GPIO5_0,
+ MX53_PAD_NANDF_WP_B__GPIO6_9,
+ MX53_PAD_NANDF_RB0__GPIO6_10,
+ MX53_PAD_NANDF_CS1__GPIO6_14,
+ MX53_PAD_NANDF_CS2__GPIO6_15,
+ MX53_PAD_NANDF_CS3__GPIO6_16,
+ MX53_PAD_GPIO_5__GPIO1_5,
+ MX53_PAD_GPIO_16__GPIO7_11,
+ MX53_PAD_GPIO_8__GPIO1_8,
};
-static const struct imxuart_platform_data mx53_loco_uart_data __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static inline void mx53_loco_init_uart(void)
-{
- imx53_add_imx_uart(0, &mx53_loco_uart_data);
- imx53_add_imx_uart(1, &mx53_loco_uart_data);
- imx53_add_imx_uart(2, &mx53_loco_uart_data);
-}
-
static inline void mx53_loco_fec_reset(void)
{
int ret;
@@ -85,13 +199,22 @@ static struct fec_platform_data mx53_loco_fec_data = {
.phy = PHY_INTERFACE_MODE_RMII,
};
+static const struct imxi2c_platform_data mx53_loco_i2c_data __initconst = {
+ .bitrate = 100000,
+};
+
static void __init mx53_loco_board_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads,
ARRAY_SIZE(mx53_loco_pads));
- mx53_loco_init_uart();
+ imx53_add_imx_uart(0, NULL);
mx53_loco_fec_reset();
imx53_add_fec(&mx53_loco_fec_data);
+ imx53_add_imx2_wdt(0, NULL);
+ imx53_add_imx_i2c(0, &mx53_loco_i2c_data);
+ imx53_add_imx_i2c(1, &mx53_loco_i2c_data);
+ imx53_add_sdhci_esdhc_imx(0, NULL);
+ imx53_add_sdhci_esdhc_imx(2, NULL);
}
static void __init mx53_loco_timer_init(void)
@@ -105,7 +228,8 @@ static struct sys_timer mx53_loco_timer = {
MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board")
.map_io = mx53_map_io,
+ .init_early = imx53_init_early,
.init_irq = mx53_init_irq,
- .init_machine = mx53_loco_board_init,
.timer = &mx53_loco_timer,
+ .init_machine = mx53_loco_board_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-mx5/board-mx53_smd.c
index 7970f7a48588..31e173267edf 100644
--- a/arch/arm/mach-mx5/board-mx53_smd.c
+++ b/arch/arm/mach-mx5/board-mx53_smd.c
@@ -39,20 +39,19 @@
#define SMD_FEC_PHY_RST IMX_GPIO_NR(7, 6)
static iomux_v3_cfg_t mx53_smd_pads[] = {
- MX53_PAD_CSI0_D10__UART1_TXD,
- MX53_PAD_CSI0_D11__UART1_RXD,
- MX53_PAD_ATA_DIOW__UART1_TXD,
- MX53_PAD_ATA_DMACK__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_ATA_DA_1__UART3_CTS,
- MX53_PAD_ATA_DA_2__UART3_RTS,
+ MX53_PAD_CSI0_DAT10__UART1_TXD_MUX,
+ MX53_PAD_CSI0_DAT11__UART1_RXD_MUX,
+
+ MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX,
+ MX53_PAD_PATA_DMARQ__UART2_TXD_MUX,
+
+ MX53_PAD_PATA_CS_0__UART3_TXD_MUX,
+ MX53_PAD_PATA_CS_1__UART3_RXD_MUX,
+ MX53_PAD_PATA_DA_1__UART3_CTS,
+ MX53_PAD_PATA_DA_2__UART3_RTS,
+ /* I2C1 */
+ MX53_PAD_CSI0_DAT8__I2C1_SDA,
+ MX53_PAD_CSI0_DAT9__I2C1_SCL,
};
static const struct imxuart_platform_data mx53_smd_uart_data __initconst = {
@@ -61,8 +60,8 @@ static const struct imxuart_platform_data mx53_smd_uart_data __initconst = {
static inline void mx53_smd_init_uart(void)
{
- imx53_add_imx_uart(0, &mx53_smd_uart_data);
- imx53_add_imx_uart(1, &mx53_smd_uart_data);
+ imx53_add_imx_uart(0, NULL);
+ imx53_add_imx_uart(1, NULL);
imx53_add_imx_uart(2, &mx53_smd_uart_data);
}
@@ -85,6 +84,10 @@ static struct fec_platform_data mx53_smd_fec_data = {
.phy = PHY_INTERFACE_MODE_RMII,
};
+static const struct imxi2c_platform_data mx53_smd_i2c_data __initconst = {
+ .bitrate = 100000,
+};
+
static void __init mx53_smd_board_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads,
@@ -92,6 +95,8 @@ static void __init mx53_smd_board_init(void)
mx53_smd_init_uart();
mx53_smd_fec_reset();
imx53_add_fec(&mx53_smd_fec_data);
+ imx53_add_imx2_wdt(0, NULL);
+ imx53_add_imx_i2c(0, &mx53_smd_i2c_data);
}
static void __init mx53_smd_timer_init(void)
@@ -105,7 +110,8 @@ static struct sys_timer mx53_smd_timer = {
MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board")
.map_io = mx53_map_io,
+ .init_early = imx53_init_early,
.init_irq = mx53_init_irq,
- .init_machine = mx53_smd_board_init,
.timer = &mx53_smd_timer,
+ .init_machine = mx53_smd_board_init,
MACHINE_END
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 0a19e7567c0b..652ace413825 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -42,6 +42,9 @@ static struct clk usboh3_clk;
static struct clk emi_fast_clk;
static struct clk ipu_clk;
static struct clk mipi_hsc1_clk;
+static struct clk esdhc1_clk;
+static struct clk esdhc2_clk;
+static struct clk esdhc3_mx53_clk;
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
@@ -867,10 +870,6 @@ static struct clk gpt_32k_clk = {
.parent = &ckil_clk,
};
-static struct clk kpp_clk = {
- .id = 0,
-};
-
static struct clk dummy_clk = {
.id = 0,
};
@@ -1147,10 +1146,80 @@ CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1)
CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1)
CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+/* mx51 specific */
CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2)
CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2)
CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+static int clk_esdhc3_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg;
+
+ reg = __raw_readl(MXC_CCM_CSCMR1);
+ if (parent == &esdhc1_clk)
+ reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL;
+ else if (parent == &esdhc2_clk)
+ reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL;
+ else
+ return -EINVAL;
+ __raw_writel(reg, MXC_CCM_CSCMR1);
+
+ return 0;
+}
+
+static int clk_esdhc4_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg;
+
+ reg = __raw_readl(MXC_CCM_CSCMR1);
+ if (parent == &esdhc1_clk)
+ reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL;
+ else if (parent == &esdhc2_clk)
+ reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL;
+ else
+ return -EINVAL;
+ __raw_writel(reg, MXC_CCM_CSCMR1);
+
+ return 0;
+}
+
+/* mx53 specific */
+static int clk_esdhc2_mx53_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg;
+
+ reg = __raw_readl(MXC_CCM_CSCMR1);
+ if (parent == &esdhc1_clk)
+ reg &= ~MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL;
+ else if (parent == &esdhc3_mx53_clk)
+ reg |= MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL;
+ else
+ return -EINVAL;
+ __raw_writel(reg, MXC_CCM_CSCMR1);
+
+ return 0;
+}
+
+CLK_GET_RATE(esdhc3_mx53, 1, ESDHC3_MX53)
+CLK_SET_PARENT(esdhc3_mx53, 1, ESDHC3_MX53)
+CLK_SET_RATE(esdhc3_mx53, 1, ESDHC3_MX53)
+
+static int clk_esdhc4_mx53_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg;
+
+ reg = __raw_readl(MXC_CCM_CSCMR1);
+ if (parent == &esdhc1_clk)
+ reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL;
+ else if (parent == &esdhc3_mx53_clk)
+ reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL;
+ else
+ return -EINVAL;
+ __raw_writel(reg, MXC_CCM_CSCMR1);
+
+ return 0;
+}
+
#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \
static struct clk name = { \
.id = i, \
@@ -1255,9 +1324,62 @@ DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET,
clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk);
DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET,
NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_FULL(esdhc3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG4_OFFSET,
+ NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_FULL(esdhc4_ipg_clk, 3, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG6_OFFSET,
+ NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+
+/* mx51 specific */
DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET,
clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk);
+static struct clk esdhc3_clk = {
+ .id = 2,
+ .parent = &esdhc1_clk,
+ .set_parent = clk_esdhc3_set_parent,
+ .enable_reg = MXC_CCM_CCGR3,
+ .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET,
+ .enable = _clk_max_enable,
+ .disable = _clk_max_disable,
+ .secondary = &esdhc3_ipg_clk,
+};
+static struct clk esdhc4_clk = {
+ .id = 3,
+ .parent = &esdhc1_clk,
+ .set_parent = clk_esdhc4_set_parent,
+ .enable_reg = MXC_CCM_CCGR3,
+ .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET,
+ .enable = _clk_max_enable,
+ .disable = _clk_max_disable,
+ .secondary = &esdhc4_ipg_clk,
+};
+
+/* mx53 specific */
+static struct clk esdhc2_mx53_clk = {
+ .id = 2,
+ .parent = &esdhc1_clk,
+ .set_parent = clk_esdhc2_mx53_set_parent,
+ .enable_reg = MXC_CCM_CCGR3,
+ .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET,
+ .enable = _clk_max_enable,
+ .disable = _clk_max_disable,
+ .secondary = &esdhc3_ipg_clk,
+};
+
+DEFINE_CLOCK_MAX(esdhc3_mx53_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG5_OFFSET,
+ clk_esdhc3_mx53, &pll2_sw_clk, &esdhc2_ipg_clk);
+
+static struct clk esdhc4_mx53_clk = {
+ .id = 3,
+ .parent = &esdhc1_clk,
+ .set_parent = clk_esdhc4_mx53_set_parent,
+ .enable_reg = MXC_CCM_CCGR3,
+ .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET,
+ .enable = _clk_max_enable,
+ .disable = _clk_max_disable,
+ .secondary = &esdhc4_ipg_clk,
+};
+
DEFINE_CLOCK(mipi_esc_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG5_OFFSET, NULL, NULL, NULL, &pll2_sw_clk);
DEFINE_CLOCK(mipi_hsc2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG4_OFFSET, NULL, NULL, &mipi_esc_clk, &pll2_sw_clk);
DEFINE_CLOCK(mipi_hsc1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG3_OFFSET, NULL, NULL, &mipi_hsc2_clk, &pll2_sw_clk);
@@ -1302,7 +1424,7 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
- _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk)
+ _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk)
_REGISTER_CLOCK("mxc_nand", NULL, nfc_clk)
_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
@@ -1316,6 +1438,8 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk)
_REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk)
_REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
@@ -1336,10 +1460,14 @@ static struct clk_lookup mx53_lookups[] = {
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
- _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk)
_REGISTER_CLOCK("imx53-ecspi.0", NULL, ecspi1_clk)
_REGISTER_CLOCK("imx53-ecspi.1", NULL, ecspi2_clk)
_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
+ _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
+ _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
};
static void clk_tree_init(void)
@@ -1427,6 +1555,14 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc,
mx53_revision();
clk_disable(&iim_clk);
+ /* Set SDHC parents to be PLL2 */
+ clk_set_parent(&esdhc1_clk, &pll2_sw_clk);
+ clk_set_parent(&esdhc3_mx53_clk, &pll2_sw_clk);
+
+ /* set SDHC root clock as 200MHZ*/
+ clk_set_rate(&esdhc1_clk, 200000000);
+ clk_set_rate(&esdhc3_mx53_clk, 200000000);
+
/* System timer */
mxc_timer_init(&gpt_clk, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR),
MX53_INT_GPT);
diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c
index d40671da4372..df46b5e60857 100644
--- a/arch/arm/mach-mx5/cpu.c
+++ b/arch/arm/mach-mx5/cpu.c
@@ -78,11 +78,16 @@ static int get_mx53_srev(void)
void __iomem *iim_base = MX51_IO_ADDRESS(MX53_IIM_BASE_ADDR);
u32 rev = readl(iim_base + IIM_SREV) & 0xff;
- if (rev == 0x0)
+ switch (rev) {
+ case 0x0:
return IMX_CHIP_REVISION_1_0;
- else if (rev == 0x10)
+ case 0x2:
return IMX_CHIP_REVISION_2_0;
- return 0;
+ case 0x3:
+ return IMX_CHIP_REVISION_2_1;
+ default:
+ return IMX_CHIP_REVISION_UNKNOWN;
+ }
}
/*
diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-mx5/crm_regs.h
index b462c22f53d8..87c0c58f27a7 100644
--- a/arch/arm/mach-mx5/crm_regs.h
+++ b/arch/arm/mach-mx5/crm_regs.h
@@ -217,9 +217,12 @@
#define MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_OFFSET (20)
#define MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_MASK (0x3 << 20)
#define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL (0x1 << 19)
+#define MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL (0x1 << 19)
#define MXC_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 18)
#define MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_OFFSET (16)
#define MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_MASK (0x3 << 16)
+#define MXC_CCM_CSCMR1_ESDHC3_MX53_CLK_SEL_OFFSET (16)
+#define MXC_CCM_CSCMR1_ESDHC3_MX53_CLK_SEL_MASK (0x3 << 16)
#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (14)
#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK (0x3 << 14)
#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET (12)
@@ -271,6 +274,10 @@
#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK (0x7 << 22)
#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET (19)
#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK (0x7 << 19)
+#define MXC_CCM_CSCDR1_ESDHC3_MX53_CLK_PRED_OFFSET (22)
+#define MXC_CCM_CSCDR1_ESDHC3_MX53_CLK_PRED_MASK (0x7 << 22)
+#define MXC_CCM_CSCDR1_ESDHC3_MX53_CLK_PODF_OFFSET (19)
+#define MXC_CCM_CSCDR1_ESDHC3_MX53_CLK_PODF_MASK (0x7 << 19)
#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_OFFSET (16)
#define MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_MASK (0x7 << 16)
#define MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET (14)
diff --git a/arch/arm/mach-mx5/devices-mx50.h b/arch/arm/mach-mx5/devices-imx50.h
index 98ab07468a0e..c9e42823c7e3 100644
--- a/arch/arm/mach-mx5/devices-mx50.h
+++ b/arch/arm/mach-mx5/devices-imx50.h
@@ -24,3 +24,11 @@
extern const struct imx_imx_uart_1irq_data imx50_imx_uart_data[] __initconst;
#define imx50_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx50_imx_uart_data[id], pdata)
+
+extern const struct imx_fec_data imx50_fec_data __initconst;
+#define imx50_add_fec(pdata) \
+ imx_add_fec(&imx50_fec_data, pdata)
+
+extern const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst;
+#define imx50_add_imx_i2c(id, pdata) \
+ imx_add_imx_i2c(&imx50_imx_i2c_data[id], pdata)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index 8639735a117b..9251008dad1f 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -29,3 +29,7 @@ imx53_sdhci_esdhc_imx_data[] __initconst;
extern const struct imx_spi_imx_data imx53_ecspi_data[] __initconst;
#define imx53_add_ecspi(id, pdata) \
imx_add_spi_imx(&imx53_ecspi_data[id], pdata)
+
+extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[] __initconst;
+#define imx53_add_imx2_wdt(id, pdata) \
+ imx_add_imx2_wdt(&imx53_imx2_wdt_data[id])
diff --git a/arch/arm/mach-mx5/efika.h b/arch/arm/mach-mx5/efika.h
new file mode 100644
index 000000000000..014aa985faae
--- /dev/null
+++ b/arch/arm/mach-mx5/efika.h
@@ -0,0 +1,10 @@
+#ifndef _EFIKA_H
+#define _EFIKA_H
+
+#define EFIKA_WLAN_EN IMX_GPIO_NR(2, 16)
+#define EFIKA_WLAN_RESET IMX_GPIO_NR(2, 10)
+#define EFIKA_USB_PHY_RESET IMX_GPIO_NR(2, 9)
+
+void __init efika_board_common_init(void);
+
+#endif
diff --git a/arch/arm/mach-mx5/ehci.c b/arch/arm/mach-mx5/ehci.c
new file mode 100644
index 000000000000..7ce12c804a32
--- /dev/null
+++ b/arch/arm/mach-mx5/ehci.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/mxc_ehci.h>
+
+#define MXC_OTG_OFFSET 0
+#define MXC_H1_OFFSET 0x200
+#define MXC_H2_OFFSET 0x400
+
+/* USB_CTRL */
+#define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) /* OTG wakeup intr enable */
+#define MXC_OTG_UCTRL_OPM_BIT (1 << 24) /* OTG power mask */
+#define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) /* Host1 ULPI interrupt enable */
+#define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) /* HOST1 wakeup intr enable */
+#define MXC_H1_UCTRL_H1PM_BIT (1 << 8) /* HOST1 power mask */
+
+/* USB_PHY_CTRL_FUNC */
+#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
+#define MXC_H1_OC_DIS_BIT (1 << 5) /* UH1 Disable Overcurrent Event */
+
+/* USBH2CTRL */
+#define MXC_H2_UCTRL_H2UIE_BIT (1 << 8)
+#define MXC_H2_UCTRL_H2WIE_BIT (1 << 7)
+#define MXC_H2_UCTRL_H2PM_BIT (1 << 4)
+
+#define MXC_USBCMD_OFFSET 0x140
+
+/* USBCMD */
+#define MXC_UCMD_ITC_NO_THRESHOLD_MASK (~(0xff << 16)) /* Interrupt Threshold Control */
+
+int mx51_initialize_usb_hw(int port, unsigned int flags)
+{
+ unsigned int v;
+ void __iomem *usb_base;
+ void __iomem *usbotg_base;
+ void __iomem *usbother_base;
+ int ret = 0;
+
+ usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+ if (!usb_base) {
+ printk(KERN_ERR "%s(): ioremap failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ switch (port) {
+ case 0: /* OTG port */
+ usbotg_base = usb_base + MXC_OTG_OFFSET;
+ break;
+ case 1: /* Host 1 port */
+ usbotg_base = usb_base + MXC_H1_OFFSET;
+ break;
+ case 2: /* Host 2 port */
+ usbotg_base = usb_base + MXC_H2_OFFSET;
+ break;
+ default:
+ printk(KERN_ERR"%s no such port %d\n", __func__, port);
+ ret = -ENOENT;
+ goto error;
+ }
+ usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+ switch (port) {
+ case 0: /*OTG port */
+ if (flags & MXC_EHCI_INTERNAL_PHY) {
+ v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+ if (flags & MXC_EHCI_POWER_PINS_ENABLED) {
+ /* OC/USBPWR is not used */
+ v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
+ } else {
+ /* OC/USBPWR is used */
+ v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
+ }
+ __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+ v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+ if (flags & MXC_EHCI_WAKEUP_ENABLED)
+ v |= MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup enable */
+ else
+ v &= ~MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup disable */
+ if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+ v |= MXC_OTG_UCTRL_OPM_BIT;
+ else
+ v &= ~MXC_OTG_UCTRL_OPM_BIT;
+ __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+ }
+ break;
+ case 1: /* Host 1 */
+ /*Host ULPI */
+ v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
+ if (flags & MXC_EHCI_WAKEUP_ENABLED) {
+ /* HOST1 wakeup/ULPI intr enable */
+ v |= (MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);
+ } else {
+ /* HOST1 wakeup/ULPI intr disable */
+ v &= ~(MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);
+ }
+
+ if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+ v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
+ else
+ v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
+ __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
+
+ v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+ if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+ v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
+ else
+ v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
+ __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+
+ v = __raw_readl(usbotg_base + MXC_USBCMD_OFFSET);
+ if (flags & MXC_EHCI_ITC_NO_THRESHOLD)
+ /* Interrupt Threshold Control:Immediate (no threshold) */
+ v &= MXC_UCMD_ITC_NO_THRESHOLD_MASK;
+ __raw_writel(v, usbotg_base + MXC_USBCMD_OFFSET);
+ break;
+ case 2: /* Host 2 ULPI */
+ v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
+ if (flags & MXC_EHCI_WAKEUP_ENABLED) {
+ /* HOST1 wakeup/ULPI intr enable */
+ v |= (MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT);
+ } else {
+ /* HOST1 wakeup/ULPI intr disable */
+ v &= ~(MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT);
+ }
+
+ if (flags & MXC_EHCI_POWER_PINS_ENABLED)
+ v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
+ else
+ v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
+ __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
+ break;
+ }
+
+error:
+ iounmap(usb_base);
+ return ret;
+}
+
diff --git a/arch/arm/mach-mx5/mm-mx50.c b/arch/arm/mach-mx5/mm-mx50.c
index 8c6540e58390..b9c363b514a9 100644
--- a/arch/arm/mach-mx5/mm-mx50.c
+++ b/arch/arm/mach-mx5/mm-mx50.c
@@ -26,6 +26,8 @@
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/iomux-v3.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
/*
* Define the MX50 memory map.
@@ -44,16 +46,27 @@ static struct map_desc mx50_io_desc[] __initdata = {
*/
void __init mx50_map_io(void)
{
+ iotable_init(mx50_io_desc, ARRAY_SIZE(mx50_io_desc));
+}
+
+void __init imx50_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX50);
mxc_iomux_v3_init(MX50_IO_ADDRESS(MX50_IOMUXC_BASE_ADDR));
mxc_arch_reset_init(MX50_IO_ADDRESS(MX50_WDOG_BASE_ADDR));
- iotable_init(mx50_io_desc, ARRAY_SIZE(mx50_io_desc));
}
-int imx50_register_gpios(void);
+static struct mxc_gpio_port imx50_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 0, 1, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH),
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 1, 2, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH),
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 2, 3, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 3, 4, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 4, 5, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 5, 6, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
+};
void __init mx50_init_irq(void)
{
tzic_init_irq(MX50_IO_ADDRESS(MX50_TZIC_BASE_ADDR));
- imx50_register_gpios();
+ mxc_gpio_init(imx50_gpio_ports, ARRAY_SIZE(imx50_gpio_ports));
}
diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c
index 457f9f95204b..ff557301b42b 100644
--- a/arch/arm/mach-mx5/mm.c
+++ b/arch/arm/mach-mx5/mm.c
@@ -47,18 +47,26 @@ static struct map_desc mx53_io_desc[] __initdata = {
*/
void __init mx51_map_io(void)
{
+ iotable_init(mx51_io_desc, ARRAY_SIZE(mx51_io_desc));
+}
+
+void __init imx51_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX51);
mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR));
mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR));
- iotable_init(mx51_io_desc, ARRAY_SIZE(mx51_io_desc));
}
void __init mx53_map_io(void)
{
+ iotable_init(mx53_io_desc, ARRAY_SIZE(mx53_io_desc));
+}
+
+void __init imx53_init_early(void)
+{
mxc_set_cpu_type(MXC_CPU_MX53);
mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR));
- mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG_BASE_ADDR));
- iotable_init(mx53_io_desc, ARRAY_SIZE(mx53_io_desc));
+ mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR));
}
int imx51_register_gpios(void);
diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-mx5/mx51_efika.c
new file mode 100644
index 000000000000..51a67fc7f0ef
--- /dev/null
+++ b/arch/arm/mach-mx5/mx51_efika.c
@@ -0,0 +1,636 @@
+/*
+ * based on code from the following
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
+ * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
+#include <mach/mxc_ehci.h>
+
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <mach/ulpi.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+#include "efika.h"
+#include "cpu_op-mx51.h"
+
+#define MX51_USB_CTRL_1_OFFSET 0x10
+#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
+#define MX51_USB_PLL_DIV_19_2_MHZ 0x01
+
+#define EFIKAMX_USB_HUB_RESET IMX_GPIO_NR(1, 5)
+#define EFIKAMX_USBH1_STP IMX_GPIO_NR(1, 27)
+
+#define EFIKAMX_SPI_CS0 IMX_GPIO_NR(4, 24)
+#define EFIKAMX_SPI_CS1 IMX_GPIO_NR(4, 25)
+
+#define EFIKAMX_PMIC IMX_GPIO_NR(1, 6)
+
+static iomux_v3_cfg_t mx51efika_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,
+
+ /* SD 1 */
+ 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,
+
+ /* SD 2 */
+ 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,
+
+ /* SD/MMC WP/CD */
+ MX51_PAD_GPIO1_0__SD1_CD,
+ MX51_PAD_GPIO1_1__SD1_WP,
+ MX51_PAD_GPIO1_7__SD2_WP,
+ MX51_PAD_GPIO1_8__SD2_CD,
+
+ /* spi */
+ MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
+ MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
+ MX51_PAD_CSPI1_SS0__GPIO4_24,
+ MX51_PAD_CSPI1_SS1__GPIO4_25,
+ MX51_PAD_CSPI1_RDY__ECSPI1_RDY,
+ MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
+ MX51_PAD_GPIO1_6__GPIO1_6,
+
+ /* USB HOST1 */
+ 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,
+
+ /* USB HUB RESET */
+ MX51_PAD_GPIO1_5__GPIO1_5,
+
+ /* WLAN */
+ MX51_PAD_EIM_A22__GPIO2_16,
+ MX51_PAD_EIM_A16__GPIO2_10,
+
+ /* USB PHY RESET */
+ MX51_PAD_EIM_D27__GPIO2_9,
+};
+
+/* Serial ports */
+static const struct imxuart_platform_data uart_pdata = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* This function is board specific as the bit mask for the plldiv will also
+ * be different for other Freescale SoCs, thus a common bitmask is not
+ * possible and cannot get place in /plat-mxc/ehci.c.
+ */
+static int initialize_otg_port(struct platform_device *pdev)
+{
+ u32 v;
+ void __iomem *usb_base;
+ void __iomem *usbother_base;
+ usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+ if (!usb_base)
+ return -ENOMEM;
+ usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET);
+
+ /* Set the PHY clock to 19.2MHz */
+ v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+ v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+ v |= MX51_USB_PLL_DIV_19_2_MHZ;
+ __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+ iounmap(usb_base);
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY);
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+ .init = initialize_otg_port,
+ .portsc = MXC_EHCI_UTMI_16BIT,
+};
+
+static int initialize_usbh1_port(struct platform_device *pdev)
+{
+ iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP;
+ iomux_v3_cfg_t usbh1gpio = MX51_PAD_USBH1_STP__GPIO1_27;
+ u32 v;
+ void __iomem *usb_base;
+ void __iomem *socregs_base;
+
+ mxc_iomux_v3_setup_pad(usbh1gpio);
+ gpio_request(EFIKAMX_USBH1_STP, "usbh1_stp");
+ gpio_direction_output(EFIKAMX_USBH1_STP, 0);
+ msleep(1);
+ gpio_set_value(EFIKAMX_USBH1_STP, 1);
+ msleep(1);
+
+ usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+ socregs_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET);
+
+ /* The clock for the USBH1 ULPI port will come externally */
+ /* from the PHY. */
+ v = __raw_readl(socregs_base + MX51_USB_CTRL_1_OFFSET);
+ __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN,
+ socregs_base + MX51_USB_CTRL_1_OFFSET);
+
+ iounmap(usb_base);
+
+ gpio_free(EFIKAMX_USBH1_STP);
+ mxc_iomux_v3_setup_pad(usbh1stp);
+
+ mdelay(10);
+
+ return mx51_initialize_usb_hw(0, MXC_EHCI_ITC_NO_THRESHOLD);
+}
+
+static struct mxc_usbh_platform_data usbh1_config = {
+ .init = initialize_usbh1_port,
+ .portsc = MXC_EHCI_MODE_ULPI,
+};
+
+static void mx51_efika_hubreset(void)
+{
+ gpio_request(EFIKAMX_USB_HUB_RESET, "usb_hub_rst");
+ gpio_direction_output(EFIKAMX_USB_HUB_RESET, 1);
+ msleep(1);
+ gpio_set_value(EFIKAMX_USB_HUB_RESET, 0);
+ msleep(1);
+ gpio_set_value(EFIKAMX_USB_HUB_RESET, 1);
+}
+
+static void __init mx51_efika_usb(void)
+{
+ mx51_efika_hubreset();
+
+ /* pulling it low, means no USB at all... */
+ gpio_request(EFIKA_USB_PHY_RESET, "usb_phy_reset");
+ gpio_direction_output(EFIKA_USB_PHY_RESET, 0);
+ msleep(1);
+ gpio_set_value(EFIKA_USB_PHY_RESET, 1);
+
+ usbh1_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
+ ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND);
+
+ mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+ if (usbh1_config.otg)
+ mxc_register_device(&mxc_usbh1_device, &usbh1_config);
+}
+
+static struct mtd_partition mx51_efika_spi_nor_partitions[] = {
+ {
+ .name = "u-boot",
+ .offset = 0,
+ .size = SZ_256K,
+ },
+ {
+ .name = "config",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_64K,
+ },
+};
+
+static struct flash_platform_data mx51_efika_spi_flash_data = {
+ .name = "spi_flash",
+ .parts = mx51_efika_spi_nor_partitions,
+ .nr_parts = ARRAY_SIZE(mx51_efika_spi_nor_partitions),
+ .type = "sst25vf032b",
+};
+
+static struct regulator_consumer_supply sw1_consumers[] = {
+ {
+ .supply = "cpu_vcc",
+ }
+};
+
+static struct regulator_consumer_supply vdig_consumers[] = {
+ /* sgtl5000 */
+ REGULATOR_SUPPLY("VDDA", "1-000a"),
+ REGULATOR_SUPPLY("VDDD", "1-000a"),
+};
+
+static struct regulator_consumer_supply vvideo_consumers[] = {
+ /* sgtl5000 */
+ REGULATOR_SUPPLY("VDDIO", "1-000a"),
+};
+
+static struct regulator_consumer_supply vsd_consumers[] = {
+ REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"),
+ REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"),
+};
+
+static struct regulator_consumer_supply pwgt1_consumer[] = {
+ {
+ .supply = "pwgt1",
+ }
+};
+
+static struct regulator_consumer_supply pwgt2_consumer[] = {
+ {
+ .supply = "pwgt2",
+ }
+};
+
+static struct regulator_consumer_supply coincell_consumer[] = {
+ {
+ .supply = "coincell",
+ }
+};
+
+static struct regulator_init_data sw1_init = {
+ .constraints = {
+ .name = "SW1",
+ .min_uV = 600000,
+ .max_uV = 1375000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .valid_modes_mask = 0,
+ .always_on = 1,
+ .boot_on = 1,
+ .state_mem = {
+ .uV = 850000,
+ .mode = REGULATOR_MODE_NORMAL,
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
+ .consumer_supplies = sw1_consumers,
+};
+
+static struct regulator_init_data sw2_init = {
+ .constraints = {
+ .name = "SW2",
+ .min_uV = 900000,
+ .max_uV = 1850000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ .state_mem = {
+ .uV = 950000,
+ .mode = REGULATOR_MODE_NORMAL,
+ .enabled = 1,
+ },
+ }
+};
+
+static struct regulator_init_data sw3_init = {
+ .constraints = {
+ .name = "SW3",
+ .min_uV = 1100000,
+ .max_uV = 1850000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data sw4_init = {
+ .constraints = {
+ .name = "SW4",
+ .min_uV = 1100000,
+ .max_uV = 1850000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data viohi_init = {
+ .constraints = {
+ .name = "VIOHI",
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb_init = {
+ .constraints = {
+ .name = "VUSB",
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data swbst_init = {
+ .constraints = {
+ .name = "SWBST",
+ }
+};
+
+static struct regulator_init_data vdig_init = {
+ .constraints = {
+ .name = "VDIG",
+ .min_uV = 1050000,
+ .max_uV = 1800000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vdig_consumers),
+ .consumer_supplies = vdig_consumers,
+};
+
+static struct regulator_init_data vpll_init = {
+ .constraints = {
+ .name = "VPLL",
+ .min_uV = 1050000,
+ .max_uV = 1800000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb2_init = {
+ .constraints = {
+ .name = "VUSB2",
+ .min_uV = 2400000,
+ .max_uV = 2775000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vvideo_init = {
+ .constraints = {
+ .name = "VVIDEO",
+ .min_uV = 2775000,
+ .max_uV = 2775000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vvideo_consumers),
+ .consumer_supplies = vvideo_consumers,
+};
+
+static struct regulator_init_data vaudio_init = {
+ .constraints = {
+ .name = "VAUDIO",
+ .min_uV = 2300000,
+ .max_uV = 3000000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vsd_init = {
+ .constraints = {
+ .name = "VSD",
+ .min_uV = 1800000,
+ .max_uV = 3150000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vsd_consumers),
+ .consumer_supplies = vsd_consumers,
+};
+
+static struct regulator_init_data vcam_init = {
+ .constraints = {
+ .name = "VCAM",
+ .min_uV = 2500000,
+ .max_uV = 3000000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+ .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen1_init = {
+ .constraints = {
+ .name = "VGEN1",
+ .min_uV = 1200000,
+ .max_uV = 3150000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen2_init = {
+ .constraints = {
+ .name = "VGEN2",
+ .min_uV = 1200000,
+ .max_uV = 3150000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen3_init = {
+ .constraints = {
+ .name = "VGEN3",
+ .min_uV = 1800000,
+ .max_uV = 2900000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data gpo1_init = {
+ .constraints = {
+ .name = "GPO1",
+ }
+};
+
+static struct regulator_init_data gpo2_init = {
+ .constraints = {
+ .name = "GPO2",
+ }
+};
+
+static struct regulator_init_data gpo3_init = {
+ .constraints = {
+ .name = "GPO3",
+ }
+};
+
+static struct regulator_init_data gpo4_init = {
+ .constraints = {
+ .name = "GPO4",
+ }
+};
+
+static struct regulator_init_data pwgt1_init = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(pwgt1_consumer),
+ .consumer_supplies = pwgt1_consumer,
+};
+
+static struct regulator_init_data pwgt2_init = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(pwgt2_consumer),
+ .consumer_supplies = pwgt2_consumer,
+};
+
+static struct regulator_init_data vcoincell_init = {
+ .constraints = {
+ .name = "COINCELL",
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_ops_mask =
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(coincell_consumer),
+ .consumer_supplies = coincell_consumer,
+};
+
+static struct mc13xxx_regulator_init_data mx51_efika_regulators[] = {
+ { .id = MC13892_SW1, .init_data = &sw1_init },
+ { .id = MC13892_SW2, .init_data = &sw2_init },
+ { .id = MC13892_SW3, .init_data = &sw3_init },
+ { .id = MC13892_SW4, .init_data = &sw4_init },
+ { .id = MC13892_SWBST, .init_data = &swbst_init },
+ { .id = MC13892_VIOHI, .init_data = &viohi_init },
+ { .id = MC13892_VPLL, .init_data = &vpll_init },
+ { .id = MC13892_VDIG, .init_data = &vdig_init },
+ { .id = MC13892_VSD, .init_data = &vsd_init },
+ { .id = MC13892_VUSB2, .init_data = &vusb2_init },
+ { .id = MC13892_VVIDEO, .init_data = &vvideo_init },
+ { .id = MC13892_VAUDIO, .init_data = &vaudio_init },
+ { .id = MC13892_VCAM, .init_data = &vcam_init },
+ { .id = MC13892_VGEN1, .init_data = &vgen1_init },
+ { .id = MC13892_VGEN2, .init_data = &vgen2_init },
+ { .id = MC13892_VGEN3, .init_data = &vgen3_init },
+ { .id = MC13892_VUSB, .init_data = &vusb_init },
+ { .id = MC13892_GPO1, .init_data = &gpo1_init },
+ { .id = MC13892_GPO2, .init_data = &gpo2_init },
+ { .id = MC13892_GPO3, .init_data = &gpo3_init },
+ { .id = MC13892_GPO4, .init_data = &gpo4_init },
+ { .id = MC13892_PWGT1SPI, .init_data = &pwgt1_init },
+ { .id = MC13892_PWGT2SPI, .init_data = &pwgt2_init },
+ { .id = MC13892_VCOINCELL, .init_data = &vcoincell_init },
+};
+
+static struct mc13xxx_platform_data mx51_efika_mc13892_data = {
+ .flags = MC13XXX_USE_RTC | MC13XXX_USE_REGULATOR,
+ .num_regulators = ARRAY_SIZE(mx51_efika_regulators),
+ .regulators = mx51_efika_regulators,
+};
+
+static struct spi_board_info mx51_efika_spi_board_info[] __initdata = {
+ {
+ .modalias = "m25p80",
+ .max_speed_hz = 25000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .platform_data = &mx51_efika_spi_flash_data,
+ .irq = -1,
+ },
+ {
+ .modalias = "mc13892",
+ .max_speed_hz = 1000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .platform_data = &mx51_efika_mc13892_data,
+ .irq = gpio_to_irq(EFIKAMX_PMIC),
+ },
+};
+
+static int mx51_efika_spi_cs[] = {
+ EFIKAMX_SPI_CS0,
+ EFIKAMX_SPI_CS1,
+};
+
+static const struct spi_imx_master mx51_efika_spi_pdata __initconst = {
+ .chipselect = mx51_efika_spi_cs,
+ .num_chipselect = ARRAY_SIZE(mx51_efika_spi_cs),
+};
+
+void __init efika_board_common_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx51efika_pads,
+ ARRAY_SIZE(mx51efika_pads));
+ imx51_add_imx_uart(0, &uart_pdata);
+ mx51_efika_usb();
+ imx51_add_sdhci_esdhc_imx(0, NULL);
+
+ /* FIXME: comes from original code. check this. */
+ if (mx51_revision() < IMX_CHIP_REVISION_2_0)
+ sw2_init.constraints.state_mem.uV = 1100000;
+ else if (mx51_revision() == IMX_CHIP_REVISION_2_0) {
+ sw2_init.constraints.state_mem.uV = 1250000;
+ sw1_init.constraints.state_mem.uV = 1000000;
+ }
+ if (machine_is_mx51_efikasb())
+ vgen1_init.constraints.max_uV = 1200000;
+
+ gpio_request(EFIKAMX_PMIC, "pmic irq");
+ gpio_direction_input(EFIKAMX_PMIC);
+ spi_register_board_info(mx51_efika_spi_board_info,
+ ARRAY_SIZE(mx51_efika_spi_board_info));
+ imx51_add_ecspi(0, &mx51_efika_spi_pdata);
+
+#if defined(CONFIG_CPU_FREQ_IMX)
+ get_cpu_op = mx51_get_cpu_op;
+#endif
+}
+
diff --git a/arch/arm/mach-mxc91231/iomux.c b/arch/arm/mach-mxc91231/iomux.c
index 405d9b19d891..66fc41cbf2ca 100644
--- a/arch/arm/mach-mxc91231/iomux.c
+++ b/arch/arm/mach-mxc91231/iomux.c
@@ -50,7 +50,7 @@ unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG];
/*
* set the mode for a IOMUX pin.
*/
-int mxc_iomux_mode(const unsigned int pin_mode)
+int mxc_iomux_mode(unsigned int pin_mode)
{
u32 side, field, l, mode, ret = 0;
void __iomem *reg;
@@ -114,7 +114,7 @@ EXPORT_SYMBOL(mxc_iomux_set_pad);
* - reserves the pin so that it is not claimed by another driver
* - setups the iomux according to the configuration
*/
-int mxc_iomux_alloc_pin(const unsigned int pin_mode, const char *label)
+int mxc_iomux_alloc_pin(unsigned int pin_mode, const char *label)
{
unsigned pad = PIN_GLOBAL_NUM(pin_mode);
if (pad >= (PIN_MAX + 1)) {
@@ -134,10 +134,10 @@ int mxc_iomux_alloc_pin(const unsigned int pin_mode, const char *label)
}
EXPORT_SYMBOL(mxc_iomux_alloc_pin);
-int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
+int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
const char *label)
{
- unsigned int *p = pin_list;
+ const unsigned int *p = pin_list;
int i;
int ret = -EINVAL;
@@ -155,7 +155,7 @@ setup_error:
}
EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins);
-void mxc_iomux_release_pin(const unsigned int pin_mode)
+void mxc_iomux_release_pin(unsigned int pin_mode)
{
unsigned pad = PIN_GLOBAL_NUM(pin_mode);
@@ -164,9 +164,9 @@ void mxc_iomux_release_pin(const unsigned int pin_mode)
}
EXPORT_SYMBOL(mxc_iomux_release_pin);
-void mxc_iomux_release_multiple_pins(unsigned int *pin_list, int count)
+void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count)
{
- unsigned int *p = pin_list;
+ const unsigned int *p = pin_list;
int i;
for (i = 0; i < count; i++) {
diff --git a/arch/arm/mach-mxc91231/magx-zn5.c b/arch/arm/mach-mxc91231/magx-zn5.c
index 395d83be8c98..f31a45e5a0b8 100644
--- a/arch/arm/mach-mxc91231/magx-zn5.c
+++ b/arch/arm/mach-mxc91231/magx-zn5.c
@@ -53,9 +53,10 @@ struct sys_timer zn5_timer = {
};
MACHINE_START(MAGX_ZN5, "Motorola Zn5")
- .boot_params = MXC91231_PHYS_OFFSET + 0x100,
- .map_io = mxc91231_map_io,
- .init_irq = mxc91231_init_irq,
- .timer = &zn5_timer,
- .init_machine = zn5_init,
+ .boot_params = MXC91231_PHYS_OFFSET + 0x100,
+ .map_io = mxc91231_map_io,
+ .init_early = mxc91231_init_early,
+ .init_irq = mxc91231_init_irq,
+ .timer = &zn5_timer,
+ .init_machine = zn5_init,
MACHINE_END
diff --git a/arch/arm/mach-mxc91231/mm.c b/arch/arm/mach-mxc91231/mm.c
index 7652c301da88..a77f6daf6a26 100644
--- a/arch/arm/mach-mxc91231/mm.c
+++ b/arch/arm/mach-mxc91231/mm.c
@@ -45,11 +45,14 @@ static struct map_desc mxc91231_io_desc[] __initdata = {
*/
void __init mxc91231_map_io(void)
{
- mxc_set_cpu_type(MXC_CPU_MXC91231);
-
iotable_init(mxc91231_io_desc, ARRAY_SIZE(mxc91231_io_desc));
}
+void __init mxc91231_init_early(void)
+{
+ mxc_set_cpu_type(MXC_CPU_MXC91231);
+}
+
int mxc91231_register_gpios(void);
void __init mxc91231_init_irq(void)
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 8bfc8df54617..4f6f174af6c8 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -2,13 +2,18 @@ if ARCH_MXS
source "arch/arm/mach-mxs/devices/Kconfig"
+config MXS_OCOTP
+ bool
+
config SOC_IMX23
bool
select CPU_ARM926T
+ select HAVE_PWM
config SOC_IMX28
bool
select CPU_ARM926T
+ select HAVE_PWM
comment "MXS platforms:"
@@ -16,6 +21,8 @@ config MACH_MX23EVK
bool "Support MX23EVK Platform"
select SOC_IMX23
select MXS_HAVE_AMBA_DUART
+ select MXS_HAVE_PLATFORM_AUART
+ select MXS_HAVE_PLATFORM_MXSFB
default y
help
Include support for MX23EVK platform. This includes specific
@@ -25,10 +32,27 @@ config MACH_MX28EVK
bool "Support MX28EVK Platform"
select SOC_IMX28
select MXS_HAVE_AMBA_DUART
+ select MXS_HAVE_PLATFORM_AUART
select MXS_HAVE_PLATFORM_FEC
+ select MXS_HAVE_PLATFORM_FLEXCAN
+ select MXS_HAVE_PLATFORM_MXSFB
+ select MXS_OCOTP
default y
help
Include support for MX28EVK platform. This includes specific
configurations for the board and its peripherals.
+config MODULE_TX28
+ bool
+ select SOC_IMX28
+ select MXS_HAVE_AMBA_DUART
+ select MXS_HAVE_PLATFORM_AUART
+ select MXS_HAVE_PLATFORM_FEC
+ select MXS_HAVE_PLATFORM_MXS_I2C
+ select MXS_HAVE_PLATFORM_MXS_PWM
+
+config MACH_TX28
+ bool "Ka-Ro TX28 module"
+ select MODULE_TX28
+
endif
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index 39d3f9c2a841..2f1f6141ca71 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -1,10 +1,15 @@
# Common support
obj-y := clock.o devices.o gpio.o icoll.o iomux.o system.o timer.o
+obj-$(CONFIG_MXS_OCOTP) += ocotp.o
+obj-$(CONFIG_PM) += pm.o
+
obj-$(CONFIG_SOC_IMX23) += clock-mx23.o mm-mx23.o
obj-$(CONFIG_SOC_IMX28) += clock-mx28.o mm-mx28.o
obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o
obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o
+obj-$(CONFIG_MODULE_TX28) += module-tx28.o
+obj-$(CONFIG_MACH_TX28) += mach-tx28.o
obj-y += devices/
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c
index ca72a05ed9c1..d133c7f30940 100644
--- a/arch/arm/mach-mxs/clock-mx23.c
+++ b/arch/arm/mach-mxs/clock-mx23.c
@@ -442,11 +442,18 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("duart", "apb_pclk", xbus_clk)
/* for amba-pl011 driver */
_REGISTER_CLOCK("duart", NULL, uart_clk)
+ _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk)
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
- _REGISTER_CLOCK(NULL, "hclk", hbus_clk)
+ _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk)
+ _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
_REGISTER_CLOCK(NULL, "usb", usb_clk)
_REGISTER_CLOCK(NULL, "audio", audio_clk)
- _REGISTER_CLOCK(NULL, "pwm", pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk)
+ _REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk)
};
static int clk_misc_init(void)
diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index fd1c4c54b8e5..5e489a2b2023 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -609,17 +609,30 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("duart", NULL, uart_clk)
_REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
_REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
+ _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk)
+ _REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk)
+ _REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk)
+ _REGISTER_CLOCK("mxs-auart.3", NULL, uart_clk)
+ _REGISTER_CLOCK("mxs-auart.4", NULL, uart_clk)
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
_REGISTER_CLOCK("pll2", NULL, pll2_clk)
- _REGISTER_CLOCK(NULL, "hclk", hbus_clk)
- _REGISTER_CLOCK(NULL, "xclk", xbus_clk)
- _REGISTER_CLOCK(NULL, "can0", can0_clk)
- _REGISTER_CLOCK(NULL, "can1", can1_clk)
+ _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk)
+ _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
+ _REGISTER_CLOCK("flexcan.0", NULL, can0_clk)
+ _REGISTER_CLOCK("flexcan.1", NULL, can1_clk)
_REGISTER_CLOCK(NULL, "usb0", usb0_clk)
_REGISTER_CLOCK(NULL, "usb1", usb1_clk)
- _REGISTER_CLOCK(NULL, "pwm", pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.5", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.6", NULL, pwm_clk)
+ _REGISTER_CLOCK("mxs-pwm.7", NULL, pwm_clk)
_REGISTER_CLOCK(NULL, "lradc", lradc_clk)
_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
+ _REGISTER_CLOCK("imx28-fb", NULL, lcdif_clk)
};
static int clk_misc_init(void)
@@ -737,6 +750,8 @@ int __init mx28_clocks_init(void)
clk_enable(&emi_clk);
clk_enable(&uart_clk);
+ clk_set_parent(&lcdif_clk, &ref_pix_clk);
+
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
mxs_timer_init(&clk32k_clk, MX28_INT_TIMER0);
diff --git a/arch/arm/mach-mxs/devices-mx23.h b/arch/arm/mach-mxs/devices-mx23.h
index 1256788561d0..c7e14f4e3669 100644
--- a/arch/arm/mach-mxs/devices-mx23.h
+++ b/arch/arm/mach-mxs/devices-mx23.h
@@ -10,7 +10,18 @@
*/
#include <mach/mx23.h>
#include <mach/devices-common.h>
+#include <mach/mxsfb.h>
extern const struct amba_device mx23_duart_device __initconst;
#define mx23_add_duart() \
mxs_add_duart(&mx23_duart_device)
+
+extern const struct mxs_auart_data mx23_auart_data[] __initconst;
+#define mx23_add_auart(id) mxs_add_auart(&mx23_auart_data[id])
+#define mx23_add_auart0() mx23_add_auart(0)
+#define mx23_add_auart1() mx23_add_auart(1)
+
+#define mx23_add_mxs_pwm(id) mxs_add_mxs_pwm(MX23_PWM_BASE_ADDR, id)
+
+struct platform_device *__init mx23_add_mxsfb(
+ const struct mxsfb_platform_data *pdata);
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index 33773a6333a2..9d08555c4cf0 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -10,11 +10,34 @@
*/
#include <mach/mx28.h>
#include <mach/devices-common.h>
+#include <mach/mxsfb.h>
extern const struct amba_device mx28_duart_device __initconst;
#define mx28_add_duart() \
mxs_add_duart(&mx28_duart_device)
+extern const struct mxs_auart_data mx28_auart_data[] __initconst;
+#define mx28_add_auart(id) mxs_add_auart(&mx28_auart_data[id])
+#define mx28_add_auart0() mx28_add_auart(0)
+#define mx28_add_auart1() mx28_add_auart(1)
+#define mx28_add_auart2() mx28_add_auart(2)
+#define mx28_add_auart3() mx28_add_auart(3)
+#define mx28_add_auart4() mx28_add_auart(4)
+
extern const struct mxs_fec_data mx28_fec_data[] __initconst;
#define mx28_add_fec(id, pdata) \
mxs_add_fec(&mx28_fec_data[id], pdata)
+
+extern const struct mxs_flexcan_data mx28_flexcan_data[] __initconst;
+#define mx28_add_flexcan(id, pdata) \
+ mxs_add_flexcan(&mx28_flexcan_data[id], pdata)
+#define mx28_add_flexcan0(pdata) mx28_add_flexcan(0, pdata)
+#define mx28_add_flexcan1(pdata) mx28_add_flexcan(1, pdata)
+
+extern const struct mxs_i2c_data mx28_mxs_i2c_data[] __initconst;
+#define mx28_add_mxs_i2c(id) mxs_add_mxs_i2c(&mx28_mxs_i2c_data[id])
+
+#define mx28_add_mxs_pwm(id) mxs_add_mxs_pwm(MX28_PWM_BASE_ADDR, id)
+
+struct platform_device *__init mx28_add_mxsfb(
+ const struct mxsfb_platform_data *pdata);
diff --git a/arch/arm/mach-mxs/devices.c b/arch/arm/mach-mxs/devices.c
index c20d54740b0b..cfdb6b284702 100644
--- a/arch/arm/mach-mxs/devices.c
+++ b/arch/arm/mach-mxs/devices.c
@@ -66,6 +66,8 @@ struct platform_device *__init mxs_add_platform_device_dmamask(
ret = platform_device_add(pdev);
if (ret) {
err:
+ if (dmamask)
+ kfree(pdev->dev.dma_mask);
platform_device_put(pdev);
return ERR_PTR(ret);
}
diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig
index cf7dc1ae575b..1451ad060d82 100644
--- a/arch/arm/mach-mxs/devices/Kconfig
+++ b/arch/arm/mach-mxs/devices/Kconfig
@@ -2,5 +2,21 @@ config MXS_HAVE_AMBA_DUART
bool
select ARM_AMBA
+config MXS_HAVE_PLATFORM_AUART
+ bool
+
config MXS_HAVE_PLATFORM_FEC
bool
+
+config MXS_HAVE_PLATFORM_FLEXCAN
+ select HAVE_CAN_FLEXCAN if CAN
+ bool
+
+config MXS_HAVE_PLATFORM_MXS_I2C
+ bool
+
+config MXS_HAVE_PLATFORM_MXS_PWM
+ bool
+
+config MXS_HAVE_PLATFORM_MXSFB
+ bool
diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile
index d0a09f6934b8..0d9bea30b0a2 100644
--- a/arch/arm/mach-mxs/devices/Makefile
+++ b/arch/arm/mach-mxs/devices/Makefile
@@ -1,2 +1,8 @@
obj-$(CONFIG_MXS_HAVE_AMBA_DUART) += amba-duart.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_AUART) += platform-auart.o
+obj-y += platform-dma.o
obj-$(CONFIG_MXS_HAVE_PLATFORM_FEC) += platform-fec.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_I2C) += platform-mxs-i2c.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o
+obj-$(CONFIG_MXS_HAVE_PLATFORM_MXSFB) += platform-mxsfb.o
diff --git a/arch/arm/mach-mxs/devices/platform-auart.c b/arch/arm/mach-mxs/devices/platform-auart.c
new file mode 100644
index 000000000000..796606cce0ce
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-auart.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define mxs_auart_data_entry_single(soc, _id, hwid) \
+ { \
+ .id = _id, \
+ .iobase = soc ## _AUART ## hwid ## _BASE_ADDR, \
+ .irq = soc ## _INT_AUART ## hwid, \
+ }
+
+#define mxs_auart_data_entry(soc, _id, hwid) \
+ [_id] = mxs_auart_data_entry_single(soc, _id, hwid)
+
+#ifdef CONFIG_SOC_IMX23
+const struct mxs_auart_data mx23_auart_data[] __initconst = {
+#define mx23_auart_data_entry(_id, hwid) \
+ mxs_auart_data_entry(MX23, _id, hwid)
+ mx23_auart_data_entry(0, 1),
+ mx23_auart_data_entry(1, 2),
+};
+#endif
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_auart_data mx28_auart_data[] __initconst = {
+#define mx28_auart_data_entry(_id) \
+ mxs_auart_data_entry(MX28, _id, _id)
+ mx28_auart_data_entry(0),
+ mx28_auart_data_entry(1),
+ mx28_auart_data_entry(2),
+ mx28_auart_data_entry(3),
+ mx28_auart_data_entry(4),
+};
+#endif
+
+struct platform_device *__init mxs_add_auart(
+ const struct mxs_auart_data *data)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return mxs_add_platform_device_dmamask("mxs-auart", data->id,
+ res, ARRAY_SIZE(res), NULL, 0,
+ DMA_BIT_MASK(32));
+}
+
diff --git a/arch/arm/mach-mxs/devices/platform-dma.c b/arch/arm/mach-mxs/devices/platform-dma.c
new file mode 100644
index 000000000000..295c4424d5d9
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-dma.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+static struct platform_device *__init mxs_add_dma(const char *devid,
+ resource_size_t base)
+{
+ struct resource res[] = {
+ {
+ .start = base,
+ .end = base + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ }
+ };
+
+ return mxs_add_platform_device_dmamask(devid, -1,
+ res, ARRAY_SIZE(res), NULL, 0,
+ DMA_BIT_MASK(32));
+}
+
+static int __init mxs_add_mxs_dma(void)
+{
+ char *apbh = "mxs-dma-apbh";
+ char *apbx = "mxs-dma-apbx";
+
+ if (cpu_is_mx23()) {
+ mxs_add_dma(apbh, MX23_APBH_DMA_BASE_ADDR);
+ mxs_add_dma(apbx, MX23_APBX_DMA_BASE_ADDR);
+ }
+
+ if (cpu_is_mx28()) {
+ mxs_add_dma(apbh, MX28_APBH_DMA_BASE_ADDR);
+ mxs_add_dma(apbx, MX28_APBX_DMA_BASE_ADDR);
+ }
+
+ return 0;
+}
+arch_initcall(mxs_add_mxs_dma);
diff --git a/arch/arm/mach-mxs/devices/platform-fec.c b/arch/arm/mach-mxs/devices/platform-fec.c
index c42dff72b46c..9859cf283335 100644
--- a/arch/arm/mach-mxs/devices/platform-fec.c
+++ b/arch/arm/mach-mxs/devices/platform-fec.c
@@ -45,6 +45,7 @@ struct platform_device *__init mxs_add_fec(
},
};
- return mxs_add_platform_device("imx28-fec", data->id,
- res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+ return mxs_add_platform_device_dmamask("imx28-fec", data->id,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata),
+ DMA_BIT_MASK(32));
}
diff --git a/arch/arm/mach-mxs/devices/platform-flexcan.c b/arch/arm/mach-mxs/devices/platform-flexcan.c
new file mode 100644
index 000000000000..43a6b4bae6fe
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-flexcan.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010, 2011 Pengutronix,
+ * Marc Kleine-Budde <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define mxs_flexcan_data_entry_single(soc, _id, _hwid, _size) \
+ { \
+ .id = _id, \
+ .iobase = soc ## _CAN ## _hwid ## _BASE_ADDR, \
+ .iosize = _size, \
+ .irq = soc ## _INT_CAN ## _hwid, \
+ }
+
+#define mxs_flexcan_data_entry(soc, _id, _hwid, _size) \
+ [_id] = mxs_flexcan_data_entry_single(soc, _id, _hwid, _size)
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_flexcan_data mx28_flexcan_data[] __initconst = {
+#define mx28_flexcan_data_entry(_id, _hwid) \
+ mxs_flexcan_data_entry_single(MX28, _id, _hwid, SZ_8K)
+ mx28_flexcan_data_entry(0, 0),
+ mx28_flexcan_data_entry(1, 1),
+};
+#endif /* ifdef CONFIG_SOC_IMX28 */
+
+struct platform_device *__init mxs_add_flexcan(
+ const struct mxs_flexcan_data *data,
+ const struct flexcan_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + data->iosize - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return mxs_add_platform_device("flexcan", data->id,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-i2c.c b/arch/arm/mach-mxs/devices/platform-mxs-i2c.c
new file mode 100644
index 000000000000..eab3a06836d6
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-mxs-i2c.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Pengutronix
+ * Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define mxs_i2c_data_entry_single(soc, _id) \
+ { \
+ .id = _id, \
+ .iobase = soc ## _I2C ## _id ## _BASE_ADDR, \
+ .errirq = soc ## _INT_I2C ## _id ## _ERROR, \
+ .dmairq = soc ## _INT_I2C ## _id ## _DMA, \
+ }
+
+#define mxs_i2c_data_entry(soc, _id) \
+ [_id] = mxs_i2c_data_entry_single(soc, _id)
+
+#ifdef CONFIG_SOC_IMX28
+const struct mxs_i2c_data mx28_mxs_i2c_data[] __initconst = {
+ mxs_i2c_data_entry(MX28, 0),
+ mxs_i2c_data_entry(MX28, 1),
+};
+#endif
+
+struct platform_device *__init mxs_add_mxs_i2c(const struct mxs_i2c_data *data)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->errirq,
+ .end = data->errirq,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .start = data->dmairq,
+ .end = data->dmairq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return mxs_add_platform_device("mxs-i2c", data->id, res,
+ ARRAY_SIZE(res), NULL, 0);
+}
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-pwm.c b/arch/arm/mach-mxs/devices/platform-mxs-pwm.c
new file mode 100644
index 000000000000..680f5a902936
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-mxs-pwm.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/devices-common.h>
+
+struct platform_device *__init mxs_add_mxs_pwm(resource_size_t iobase, int id)
+{
+ struct resource res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ res.start = iobase + 0x10 + 0x20 * id;
+ res.end = res.start + 0x1f;
+
+ return mxs_add_platform_device("mxs-pwm", id, &res, 1, NULL, 0);
+}
diff --git a/arch/arm/mach-mxs/devices/platform-mxsfb.c b/arch/arm/mach-mxs/devices/platform-mxsfb.c
new file mode 100644
index 000000000000..bf72c9b8dbdd
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/platform-mxsfb.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+#include <mach/mxsfb.h>
+
+#ifdef CONFIG_SOC_IMX23
+struct platform_device *__init mx23_add_mxsfb(
+ const struct mxsfb_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = MX23_LCDIF_BASE_ADDR,
+ .end = MX23_LCDIF_BASE_ADDR + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ return mxs_add_platform_device_dmamask("imx23-fb", -1,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
+#endif /* ifdef CONFIG_SOC_IMX23 */
+
+#ifdef CONFIG_SOC_IMX28
+struct platform_device *__init mx28_add_mxsfb(
+ const struct mxsfb_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = MX28_LCDIF_BASE_ADDR,
+ .end = MX28_LCDIF_BASE_ADDR + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ return mxs_add_platform_device_dmamask("imx28-fb", -1,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata), DMA_BIT_MASK(32));
+}
+#endif /* ifdef CONFIG_SOC_IMX28 */
diff --git a/arch/arm/mach-mxs/gpio.c b/arch/arm/mach-mxs/gpio.c
index 61991e4dde44..56fa2ed15222 100644
--- a/arch/arm/mach-mxs/gpio.c
+++ b/arch/arm/mach-mxs/gpio.c
@@ -182,6 +182,7 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
}
static struct irq_chip gpio_irq_chip = {
+ .name = "mxs gpio",
.irq_ack = mxs_gpio_ack_irq,
.irq_mask = mxs_gpio_mask_irq,
.irq_unmask = mxs_gpio_unmask_irq,
@@ -289,39 +290,42 @@ int __init mxs_gpio_init(struct mxs_gpio_port *port, int cnt)
return 0;
}
-#define DEFINE_MXS_GPIO_PORT(soc, _id) \
+#define MX23_GPIO_BASE MX23_IO_ADDRESS(MX23_PINCTRL_BASE_ADDR)
+#define MX28_GPIO_BASE MX28_IO_ADDRESS(MX28_PINCTRL_BASE_ADDR)
+
+#define DEFINE_MXS_GPIO_PORT(_base, _irq, _id) \
{ \
.chip.label = "gpio-" #_id, \
.id = _id, \
- .irq = soc ## _INT_GPIO ## _id, \
- .base = soc ## _IO_ADDRESS( \
- soc ## _PINCTRL ## _BASE_ADDR), \
+ .irq = _irq, \
+ .base = _base, \
.virtual_irq_start = MXS_GPIO_IRQ_START + (_id) * 32, \
}
-#define DEFINE_REGISTER_FUNCTION(prefix) \
-int __init prefix ## _register_gpios(void) \
-{ \
- return mxs_gpio_init(prefix ## _gpio_ports, \
- ARRAY_SIZE(prefix ## _gpio_ports)); \
-}
-
#ifdef CONFIG_SOC_IMX23
static struct mxs_gpio_port mx23_gpio_ports[] = {
- DEFINE_MXS_GPIO_PORT(MX23, 0),
- DEFINE_MXS_GPIO_PORT(MX23, 1),
- DEFINE_MXS_GPIO_PORT(MX23, 2),
+ DEFINE_MXS_GPIO_PORT(MX23_GPIO_BASE, MX23_INT_GPIO0, 0),
+ DEFINE_MXS_GPIO_PORT(MX23_GPIO_BASE, MX23_INT_GPIO1, 1),
+ DEFINE_MXS_GPIO_PORT(MX23_GPIO_BASE, MX23_INT_GPIO2, 2),
};
-DEFINE_REGISTER_FUNCTION(mx23)
+
+int __init mx23_register_gpios(void)
+{
+ return mxs_gpio_init(mx23_gpio_ports, ARRAY_SIZE(mx23_gpio_ports));
+}
#endif
#ifdef CONFIG_SOC_IMX28
static struct mxs_gpio_port mx28_gpio_ports[] = {
- DEFINE_MXS_GPIO_PORT(MX28, 0),
- DEFINE_MXS_GPIO_PORT(MX28, 1),
- DEFINE_MXS_GPIO_PORT(MX28, 2),
- DEFINE_MXS_GPIO_PORT(MX28, 3),
- DEFINE_MXS_GPIO_PORT(MX28, 4),
+ DEFINE_MXS_GPIO_PORT(MX28_GPIO_BASE, MX28_INT_GPIO0, 0),
+ DEFINE_MXS_GPIO_PORT(MX28_GPIO_BASE, MX28_INT_GPIO1, 1),
+ DEFINE_MXS_GPIO_PORT(MX28_GPIO_BASE, MX28_INT_GPIO2, 2),
+ DEFINE_MXS_GPIO_PORT(MX28_GPIO_BASE, MX28_INT_GPIO3, 3),
+ DEFINE_MXS_GPIO_PORT(MX28_GPIO_BASE, MX28_INT_GPIO4, 4),
};
-DEFINE_REGISTER_FUNCTION(mx28)
+
+int __init mx28_register_gpios(void)
+{
+ return mxs_gpio_init(mx28_gpio_ports, ARRAY_SIZE(mx28_gpio_ports));
+}
#endif
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h
index 59133eb3cc96..635bb5d9a20a 100644
--- a/arch/arm/mach-mxs/include/mach/common.h
+++ b/arch/arm/mach-mxs/include/mach/common.h
@@ -13,6 +13,7 @@
struct clk;
+extern const u32 *mxs_get_ocotp(void);
extern int mxs_reset_block(void __iomem *);
extern void mxs_timer_init(struct clk *, int);
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index 6c3d1a103433..71f24484b044 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -30,6 +30,16 @@ int __init mxs_add_amba_device(const struct amba_device *dev);
/* duart */
int __init mxs_add_duart(const struct amba_device *dev);
+/* auart */
+struct mxs_auart_data {
+ int id;
+ resource_size_t iobase;
+ resource_size_t iosize;
+ resource_size_t irq;
+};
+struct platform_device *__init mxs_add_auart(
+ const struct mxs_auart_data *data);
+
/* fec */
#include <linux/fec.h>
struct mxs_fec_data {
@@ -41,3 +51,28 @@ struct mxs_fec_data {
struct platform_device *__init mxs_add_fec(
const struct mxs_fec_data *data,
const struct fec_platform_data *pdata);
+
+/* flexcan */
+#include <linux/can/platform/flexcan.h>
+struct mxs_flexcan_data {
+ int id;
+ resource_size_t iobase;
+ resource_size_t iosize;
+ resource_size_t irq;
+};
+struct platform_device *__init mxs_add_flexcan(
+ const struct mxs_flexcan_data *data,
+ const struct flexcan_platform_data *pdata);
+
+/* i2c */
+struct mxs_i2c_data {
+ int id;
+ resource_size_t iobase;
+ resource_size_t errirq;
+ resource_size_t dmairq;
+};
+struct platform_device * __init mxs_add_mxs_i2c(const struct mxs_i2c_data *data);
+
+/* pwm */
+struct platform_device *__init mxs_add_mxs_pwm(
+ resource_size_t iobase, int id);
diff --git a/arch/arm/mach-mxs/include/mach/iomux-mx23.h b/arch/arm/mach-mxs/include/mach/iomux-mx23.h
index 94e5dd83cdb8..b0190a4822f2 100644
--- a/arch/arm/mach-mxs/include/mach/iomux-mx23.h
+++ b/arch/arm/mach-mxs/include/mach/iomux-mx23.h
@@ -254,102 +254,102 @@
#define MX23_PAD_ROTARYB__GPMI_CE3N MXS_IOMUX_PAD_NAKED(2, 8, PAD_MUXSEL_2)
/* MUXSEL_GPIO */
-#define MX23_PAD_GPMI_D00__GPO_0_0 MXS_IOMUX_PAD_NAKED(0, 0, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D01__GPO_0_1 MXS_IOMUX_PAD_NAKED(0, 1, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D02__GPO_0_2 MXS_IOMUX_PAD_NAKED(0, 2, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D03__GPO_0_3 MXS_IOMUX_PAD_NAKED(0, 3, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D04__GPO_0_4 MXS_IOMUX_PAD_NAKED(0, 4, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D05__GPO_0_5 MXS_IOMUX_PAD_NAKED(0, 5, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D06__GPO_0_6 MXS_IOMUX_PAD_NAKED(0, 6, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D07__GPO_0_7 MXS_IOMUX_PAD_NAKED(0, 7, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D08__GPO_0_8 MXS_IOMUX_PAD_NAKED(0, 8, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D09__GPO_0_9 MXS_IOMUX_PAD_NAKED(0, 9, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D10__GPO_0_10 MXS_IOMUX_PAD_NAKED(0, 10, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D11__GPO_0_11 MXS_IOMUX_PAD_NAKED(0, 11, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D12__GPO_0_12 MXS_IOMUX_PAD_NAKED(0, 12, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D13__GPO_0_13 MXS_IOMUX_PAD_NAKED(0, 13, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D14__GPO_0_14 MXS_IOMUX_PAD_NAKED(0, 14, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_D15__GPO_0_15 MXS_IOMUX_PAD_NAKED(0, 15, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_CLE__GPO_0_16 MXS_IOMUX_PAD_NAKED(0, 16, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_ALE__GPO_0_17 MXS_IOMUX_PAD_NAKED(0, 17, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_CE2N__GPO_0_18 MXS_IOMUX_PAD_NAKED(0, 18, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_RDY0__GPO_0_19 MXS_IOMUX_PAD_NAKED(0, 19, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_RDY1__GPO_0_20 MXS_IOMUX_PAD_NAKED(0, 20, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_RDY2__GPO_0_21 MXS_IOMUX_PAD_NAKED(0, 21, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_RDY3__GPO_0_22 MXS_IOMUX_PAD_NAKED(0, 22, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_WPN__GPO_0_23 MXS_IOMUX_PAD_NAKED(0, 23, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_WRN__GPO_0_24 MXS_IOMUX_PAD_NAKED(0, 24, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_RDN__GPO_0_25 MXS_IOMUX_PAD_NAKED(0, 25, PAD_MUXSEL_GPIO)
-#define MX23_PAD_AUART1_CTS__GPO_0_26 MXS_IOMUX_PAD_NAKED(0, 26, PAD_MUXSEL_GPIO)
-#define MX23_PAD_AUART1_RTS__GPO_0_27 MXS_IOMUX_PAD_NAKED(0, 27, PAD_MUXSEL_GPIO)
-#define MX23_PAD_AUART1_RX__GPO_0_28 MXS_IOMUX_PAD_NAKED(0, 28, PAD_MUXSEL_GPIO)
-#define MX23_PAD_AUART1_TX__GPO_0_29 MXS_IOMUX_PAD_NAKED(0, 29, PAD_MUXSEL_GPIO)
-#define MX23_PAD_I2C_SCL__GPO_0_30 MXS_IOMUX_PAD_NAKED(0, 30, PAD_MUXSEL_GPIO)
-#define MX23_PAD_I2C_SDA__GPO_0_31 MXS_IOMUX_PAD_NAKED(0, 31, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D00__GPIO_0_0 MXS_IOMUX_PAD_NAKED(0, 0, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D01__GPIO_0_1 MXS_IOMUX_PAD_NAKED(0, 1, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D02__GPIO_0_2 MXS_IOMUX_PAD_NAKED(0, 2, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D03__GPIO_0_3 MXS_IOMUX_PAD_NAKED(0, 3, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D04__GPIO_0_4 MXS_IOMUX_PAD_NAKED(0, 4, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D05__GPIO_0_5 MXS_IOMUX_PAD_NAKED(0, 5, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D06__GPIO_0_6 MXS_IOMUX_PAD_NAKED(0, 6, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D07__GPIO_0_7 MXS_IOMUX_PAD_NAKED(0, 7, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D08__GPIO_0_8 MXS_IOMUX_PAD_NAKED(0, 8, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D09__GPIO_0_9 MXS_IOMUX_PAD_NAKED(0, 9, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D10__GPIO_0_10 MXS_IOMUX_PAD_NAKED(0, 10, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D11__GPIO_0_11 MXS_IOMUX_PAD_NAKED(0, 11, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D12__GPIO_0_12 MXS_IOMUX_PAD_NAKED(0, 12, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D13__GPIO_0_13 MXS_IOMUX_PAD_NAKED(0, 13, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D14__GPIO_0_14 MXS_IOMUX_PAD_NAKED(0, 14, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_D15__GPIO_0_15 MXS_IOMUX_PAD_NAKED(0, 15, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_CLE__GPIO_0_16 MXS_IOMUX_PAD_NAKED(0, 16, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_ALE__GPIO_0_17 MXS_IOMUX_PAD_NAKED(0, 17, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_CE2N__GPIO_0_18 MXS_IOMUX_PAD_NAKED(0, 18, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_RDY0__GPIO_0_19 MXS_IOMUX_PAD_NAKED(0, 19, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_RDY1__GPIO_0_20 MXS_IOMUX_PAD_NAKED(0, 20, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_RDY2__GPIO_0_21 MXS_IOMUX_PAD_NAKED(0, 21, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_RDY3__GPIO_0_22 MXS_IOMUX_PAD_NAKED(0, 22, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_WPN__GPIO_0_23 MXS_IOMUX_PAD_NAKED(0, 23, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_WRN__GPIO_0_24 MXS_IOMUX_PAD_NAKED(0, 24, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_RDN__GPIO_0_25 MXS_IOMUX_PAD_NAKED(0, 25, PAD_MUXSEL_GPIO)
+#define MX23_PAD_AUART1_CTS__GPIO_0_26 MXS_IOMUX_PAD_NAKED(0, 26, PAD_MUXSEL_GPIO)
+#define MX23_PAD_AUART1_RTS__GPIO_0_27 MXS_IOMUX_PAD_NAKED(0, 27, PAD_MUXSEL_GPIO)
+#define MX23_PAD_AUART1_RX__GPIO_0_28 MXS_IOMUX_PAD_NAKED(0, 28, PAD_MUXSEL_GPIO)
+#define MX23_PAD_AUART1_TX__GPIO_0_29 MXS_IOMUX_PAD_NAKED(0, 29, PAD_MUXSEL_GPIO)
+#define MX23_PAD_I2C_SCL__GPIO_0_30 MXS_IOMUX_PAD_NAKED(0, 30, PAD_MUXSEL_GPIO)
+#define MX23_PAD_I2C_SDA__GPIO_0_31 MXS_IOMUX_PAD_NAKED(0, 31, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D00__GPO_1_0 MXS_IOMUX_PAD_NAKED(1, 0, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D01__GPO_1_1 MXS_IOMUX_PAD_NAKED(1, 1, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D02__GPO_1_2 MXS_IOMUX_PAD_NAKED(1, 2, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D03__GPO_1_3 MXS_IOMUX_PAD_NAKED(1, 3, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D04__GPO_1_4 MXS_IOMUX_PAD_NAKED(1, 4, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D05__GPO_1_5 MXS_IOMUX_PAD_NAKED(1, 5, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D06__GPO_1_6 MXS_IOMUX_PAD_NAKED(1, 6, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D07__GPO_1_7 MXS_IOMUX_PAD_NAKED(1, 7, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D08__GPO_1_8 MXS_IOMUX_PAD_NAKED(1, 8, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D09__GPO_1_9 MXS_IOMUX_PAD_NAKED(1, 9, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D10__GPO_1_10 MXS_IOMUX_PAD_NAKED(1, 10, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D11__GPO_1_11 MXS_IOMUX_PAD_NAKED(1, 11, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D12__GPO_1_12 MXS_IOMUX_PAD_NAKED(1, 12, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D13__GPO_1_13 MXS_IOMUX_PAD_NAKED(1, 13, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D14__GPO_1_14 MXS_IOMUX_PAD_NAKED(1, 14, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D15__GPO_1_15 MXS_IOMUX_PAD_NAKED(1, 15, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D16__GPO_1_16 MXS_IOMUX_PAD_NAKED(1, 16, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_D17__GPO_1_17 MXS_IOMUX_PAD_NAKED(1, 17, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_RESET__GPO_1_18 MXS_IOMUX_PAD_NAKED(1, 18, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_RS__GPO_1_19 MXS_IOMUX_PAD_NAKED(1, 19, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_WR__GPO_1_20 MXS_IOMUX_PAD_NAKED(1, 20, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_CS__GPO_1_21 MXS_IOMUX_PAD_NAKED(1, 21, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_DOTCK__GPO_1_22 MXS_IOMUX_PAD_NAKED(1, 22, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_ENABLE__GPO_1_23 MXS_IOMUX_PAD_NAKED(1, 23, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_HSYNC__GPO_1_24 MXS_IOMUX_PAD_NAKED(1, 24, PAD_MUXSEL_GPIO)
-#define MX23_PAD_LCD_VSYNC__GPO_1_25 MXS_IOMUX_PAD_NAKED(1, 25, PAD_MUXSEL_GPIO)
-#define MX23_PAD_PWM0__GPO_1_26 MXS_IOMUX_PAD_NAKED(1, 26, PAD_MUXSEL_GPIO)
-#define MX23_PAD_PWM1__GPO_1_27 MXS_IOMUX_PAD_NAKED(1, 27, PAD_MUXSEL_GPIO)
-#define MX23_PAD_PWM2__GPO_1_28 MXS_IOMUX_PAD_NAKED(1, 28, PAD_MUXSEL_GPIO)
-#define MX23_PAD_PWM3__GPO_1_29 MXS_IOMUX_PAD_NAKED(1, 29, PAD_MUXSEL_GPIO)
-#define MX23_PAD_PWM4__GPO_1_30 MXS_IOMUX_PAD_NAKED(1, 30, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D00__GPIO_1_0 MXS_IOMUX_PAD_NAKED(1, 0, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D01__GPIO_1_1 MXS_IOMUX_PAD_NAKED(1, 1, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D02__GPIO_1_2 MXS_IOMUX_PAD_NAKED(1, 2, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D03__GPIO_1_3 MXS_IOMUX_PAD_NAKED(1, 3, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D04__GPIO_1_4 MXS_IOMUX_PAD_NAKED(1, 4, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D05__GPIO_1_5 MXS_IOMUX_PAD_NAKED(1, 5, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D06__GPIO_1_6 MXS_IOMUX_PAD_NAKED(1, 6, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D07__GPIO_1_7 MXS_IOMUX_PAD_NAKED(1, 7, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D08__GPIO_1_8 MXS_IOMUX_PAD_NAKED(1, 8, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D09__GPIO_1_9 MXS_IOMUX_PAD_NAKED(1, 9, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D10__GPIO_1_10 MXS_IOMUX_PAD_NAKED(1, 10, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D11__GPIO_1_11 MXS_IOMUX_PAD_NAKED(1, 11, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D12__GPIO_1_12 MXS_IOMUX_PAD_NAKED(1, 12, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D13__GPIO_1_13 MXS_IOMUX_PAD_NAKED(1, 13, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D14__GPIO_1_14 MXS_IOMUX_PAD_NAKED(1, 14, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D15__GPIO_1_15 MXS_IOMUX_PAD_NAKED(1, 15, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D16__GPIO_1_16 MXS_IOMUX_PAD_NAKED(1, 16, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_D17__GPIO_1_17 MXS_IOMUX_PAD_NAKED(1, 17, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_RESET__GPIO_1_18 MXS_IOMUX_PAD_NAKED(1, 18, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_RS__GPIO_1_19 MXS_IOMUX_PAD_NAKED(1, 19, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_WR__GPIO_1_20 MXS_IOMUX_PAD_NAKED(1, 20, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_CS__GPIO_1_21 MXS_IOMUX_PAD_NAKED(1, 21, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_DOTCK__GPIO_1_22 MXS_IOMUX_PAD_NAKED(1, 22, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_ENABLE__GPIO_1_23 MXS_IOMUX_PAD_NAKED(1, 23, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_HSYNC__GPIO_1_24 MXS_IOMUX_PAD_NAKED(1, 24, PAD_MUXSEL_GPIO)
+#define MX23_PAD_LCD_VSYNC__GPIO_1_25 MXS_IOMUX_PAD_NAKED(1, 25, PAD_MUXSEL_GPIO)
+#define MX23_PAD_PWM0__GPIO_1_26 MXS_IOMUX_PAD_NAKED(1, 26, PAD_MUXSEL_GPIO)
+#define MX23_PAD_PWM1__GPIO_1_27 MXS_IOMUX_PAD_NAKED(1, 27, PAD_MUXSEL_GPIO)
+#define MX23_PAD_PWM2__GPIO_1_28 MXS_IOMUX_PAD_NAKED(1, 28, PAD_MUXSEL_GPIO)
+#define MX23_PAD_PWM3__GPIO_1_29 MXS_IOMUX_PAD_NAKED(1, 29, PAD_MUXSEL_GPIO)
+#define MX23_PAD_PWM4__GPIO_1_30 MXS_IOMUX_PAD_NAKED(1, 30, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_CMD__GPO_2_0 MXS_IOMUX_PAD_NAKED(2, 0, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_DETECT__GPO_2_1 MXS_IOMUX_PAD_NAKED(2, 1, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_DATA0__GPO_2_2 MXS_IOMUX_PAD_NAKED(2, 2, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_DATA1__GPO_2_3 MXS_IOMUX_PAD_NAKED(2, 3, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_DATA2__GPO_2_4 MXS_IOMUX_PAD_NAKED(2, 4, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_DATA3__GPO_2_5 MXS_IOMUX_PAD_NAKED(2, 5, PAD_MUXSEL_GPIO)
-#define MX23_PAD_SSP1_SCK__GPO_2_6 MXS_IOMUX_PAD_NAKED(2, 6, PAD_MUXSEL_GPIO)
-#define MX23_PAD_ROTARYA__GPO_2_7 MXS_IOMUX_PAD_NAKED(2, 7, PAD_MUXSEL_GPIO)
-#define MX23_PAD_ROTARYB__GPO_2_8 MXS_IOMUX_PAD_NAKED(2, 8, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A00__GPO_2_9 MXS_IOMUX_PAD_NAKED(2, 9, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A01__GPO_2_10 MXS_IOMUX_PAD_NAKED(2, 10, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A02__GPO_2_11 MXS_IOMUX_PAD_NAKED(2, 11, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A03__GPO_2_12 MXS_IOMUX_PAD_NAKED(2, 12, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A04__GPO_2_13 MXS_IOMUX_PAD_NAKED(2, 13, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A05__GPO_2_14 MXS_IOMUX_PAD_NAKED(2, 14, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A06__GPO_2_15 MXS_IOMUX_PAD_NAKED(2, 15, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A07__GPO_2_16 MXS_IOMUX_PAD_NAKED(2, 16, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A08__GPO_2_17 MXS_IOMUX_PAD_NAKED(2, 17, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A09__GPO_2_18 MXS_IOMUX_PAD_NAKED(2, 18, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A10__GPO_2_19 MXS_IOMUX_PAD_NAKED(2, 19, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A11__GPO_2_20 MXS_IOMUX_PAD_NAKED(2, 20, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_A12__GPO_2_21 MXS_IOMUX_PAD_NAKED(2, 21, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_BA0__GPO_2_22 MXS_IOMUX_PAD_NAKED(2, 22, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_BA1__GPO_2_23 MXS_IOMUX_PAD_NAKED(2, 23, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_CASN__GPO_2_24 MXS_IOMUX_PAD_NAKED(2, 24, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_CE0N__GPO_2_25 MXS_IOMUX_PAD_NAKED(2, 25, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_CE1N__GPO_2_26 MXS_IOMUX_PAD_NAKED(2, 26, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_CE1N__GPO_2_27 MXS_IOMUX_PAD_NAKED(2, 27, PAD_MUXSEL_GPIO)
-#define MX23_PAD_GPMI_CE0N__GPO_2_28 MXS_IOMUX_PAD_NAKED(2, 28, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_CKE__GPO_2_29 MXS_IOMUX_PAD_NAKED(2, 29, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_RASN__GPO_2_30 MXS_IOMUX_PAD_NAKED(2, 30, PAD_MUXSEL_GPIO)
-#define MX23_PAD_EMI_WEN__GPO_2_31 MXS_IOMUX_PAD_NAKED(2, 31, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_CMD__GPIO_2_0 MXS_IOMUX_PAD_NAKED(2, 0, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_DETECT__GPIO_2_1 MXS_IOMUX_PAD_NAKED(2, 1, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_DATA0__GPIO_2_2 MXS_IOMUX_PAD_NAKED(2, 2, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_DATA1__GPIO_2_3 MXS_IOMUX_PAD_NAKED(2, 3, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_DATA2__GPIO_2_4 MXS_IOMUX_PAD_NAKED(2, 4, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_DATA3__GPIO_2_5 MXS_IOMUX_PAD_NAKED(2, 5, PAD_MUXSEL_GPIO)
+#define MX23_PAD_SSP1_SCK__GPIO_2_6 MXS_IOMUX_PAD_NAKED(2, 6, PAD_MUXSEL_GPIO)
+#define MX23_PAD_ROTARYA__GPIO_2_7 MXS_IOMUX_PAD_NAKED(2, 7, PAD_MUXSEL_GPIO)
+#define MX23_PAD_ROTARYB__GPIO_2_8 MXS_IOMUX_PAD_NAKED(2, 8, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A00__GPIO_2_9 MXS_IOMUX_PAD_NAKED(2, 9, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A01__GPIO_2_10 MXS_IOMUX_PAD_NAKED(2, 10, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A02__GPIO_2_11 MXS_IOMUX_PAD_NAKED(2, 11, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A03__GPIO_2_12 MXS_IOMUX_PAD_NAKED(2, 12, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A04__GPIO_2_13 MXS_IOMUX_PAD_NAKED(2, 13, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A05__GPIO_2_14 MXS_IOMUX_PAD_NAKED(2, 14, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A06__GPIO_2_15 MXS_IOMUX_PAD_NAKED(2, 15, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A07__GPIO_2_16 MXS_IOMUX_PAD_NAKED(2, 16, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A08__GPIO_2_17 MXS_IOMUX_PAD_NAKED(2, 17, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A09__GPIO_2_18 MXS_IOMUX_PAD_NAKED(2, 18, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A10__GPIO_2_19 MXS_IOMUX_PAD_NAKED(2, 19, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A11__GPIO_2_20 MXS_IOMUX_PAD_NAKED(2, 20, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_A12__GPIO_2_21 MXS_IOMUX_PAD_NAKED(2, 21, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_BA0__GPIO_2_22 MXS_IOMUX_PAD_NAKED(2, 22, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_BA1__GPIO_2_23 MXS_IOMUX_PAD_NAKED(2, 23, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_CASN__GPIO_2_24 MXS_IOMUX_PAD_NAKED(2, 24, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_CE0N__GPIO_2_25 MXS_IOMUX_PAD_NAKED(2, 25, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_CE1N__GPIO_2_26 MXS_IOMUX_PAD_NAKED(2, 26, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_CE1N__GPIO_2_27 MXS_IOMUX_PAD_NAKED(2, 27, PAD_MUXSEL_GPIO)
+#define MX23_PAD_GPMI_CE0N__GPIO_2_28 MXS_IOMUX_PAD_NAKED(2, 28, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_CKE__GPIO_2_29 MXS_IOMUX_PAD_NAKED(2, 29, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_RASN__GPIO_2_30 MXS_IOMUX_PAD_NAKED(2, 30, PAD_MUXSEL_GPIO)
+#define MX23_PAD_EMI_WEN__GPIO_2_31 MXS_IOMUX_PAD_NAKED(2, 31, PAD_MUXSEL_GPIO)
#endif /* __MACH_IOMUX_MX23_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/iomux.h b/arch/arm/mach-mxs/include/mach/iomux.h
index fe558e3c5a9a..7abdf58b8bb7 100644
--- a/arch/arm/mach-mxs/include/mach/iomux.h
+++ b/arch/arm/mach-mxs/include/mach/iomux.h
@@ -91,6 +91,9 @@ typedef u32 iomux_cfg_t;
#define MXS_PAD_PULLUP ((PAD_PULLUP << MXS_PAD_PULL_SHIFT) | \
MXS_PAD_PULL_VALID_MASK)
+/* generic pad control used in most cases */
+#define MXS_PAD_CTRL (MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL)
+
#define MXS_IOMUX_PAD(_bank, _pin, _muxsel, _ma, _vol, _pull) \
(((iomux_cfg_t)(_bank) << MXS_PAD_BANK_SHIFT) | \
((iomux_cfg_t)(_pin) << MXS_PAD_PIN_SHIFT) | \
diff --git a/arch/arm/mach-mxs/include/mach/mx23.h b/arch/arm/mach-mxs/include/mach/mx23.h
index 9edd02ec8e30..c0a18c23084a 100644
--- a/arch/arm/mach-mxs/include/mach/mx23.h
+++ b/arch/arm/mach-mxs/include/mach/mx23.h
@@ -93,7 +93,7 @@
#define MX23_INT_USB_WAKEUP 12
#define MX23_INT_GPMI_DMA 13
#define MX23_INT_SSP1_DMA 14
-#define MX23_INT_SSP_ERROR 15
+#define MX23_INT_SSP1_ERROR 15
#define MX23_INT_GPIO0 16
#define MX23_INT_GPIO1 17
#define MX23_INT_GPIO2 18
@@ -101,9 +101,9 @@
#define MX23_INT_SSP2_DMA 20
#define MX23_INT_ECC8_IRQ 21
#define MX23_INT_RTC_ALARM 22
-#define MX23_INT_UARTAPP_TX_DMA 23
-#define MX23_INT_UARTAPP_INTERNAL 24
-#define MX23_INT_UARTAPP_RX_DMA 25
+#define MX23_INT_AUART1_TX_DMA 23
+#define MX23_INT_AUART1 24
+#define MX23_INT_AUART1_RX_DMA 25
#define MX23_INT_I2C_DMA 26
#define MX23_INT_I2C_ERROR 27
#define MX23_INT_TIMER0 28
@@ -135,11 +135,35 @@
#define MX23_INT_DCP 54
#define MX23_INT_BCH 56
#define MX23_INT_PXP 57
-#define MX23_INT_UARTAPP2_TX_DMA 58
-#define MX23_INT_UARTAPP2_INTERNAL 59
-#define MX23_INT_UARTAPP2_RX_DMA 60
+#define MX23_INT_AUART2_TX_DMA 58
+#define MX23_INT_AUART2 59
+#define MX23_INT_AUART2_RX_DMA 60
#define MX23_INT_VDAC_DETECT 61
#define MX23_INT_VDD5V_DROOP 64
#define MX23_INT_DCDC4P2_BO 65
+/*
+ * APBH DMA
+ */
+#define MX23_DMA_SSP1 1
+#define MX23_DMA_SSP2 2
+#define MX23_DMA_GPMI0 4
+#define MX23_DMA_GPMI1 5
+#define MX23_DMA_GPMI2 6
+#define MX23_DMA_GPMI3 7
+
+/*
+ * APBX DMA
+ */
+#define MX23_DMA_ADC 0
+#define MX23_DMA_DAC 1
+#define MX23_DMA_SPDIF 2
+#define MX23_DMA_I2C 3
+#define MX23_DMA_SAIF0 4
+#define MX23_DMA_UART0_RX 6
+#define MX23_DMA_UART0_TX 7
+#define MX23_DMA_UART1_RX 8
+#define MX23_DMA_UART1_TX 9
+#define MX23_DMA_SAIF1 10
+
#endif /* __MACH_MX23_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/mx28.h b/arch/arm/mach-mxs/include/mach/mx28.h
index 0716745267ad..75d86118b76a 100644
--- a/arch/arm/mach-mxs/include/mach/mx28.h
+++ b/arch/arm/mach-mxs/include/mach/mx28.h
@@ -163,10 +163,10 @@
#define MX28_INT_USB0 93
#define MX28_INT_USB1_WAKEUP 94
#define MX28_INT_USB0_WAKEUP 95
-#define MX28_INT_SSP0 96
-#define MX28_INT_SSP1 97
-#define MX28_INT_SSP2 98
-#define MX28_INT_SSP3 99
+#define MX28_INT_SSP0_ERROR 96
+#define MX28_INT_SSP1_ERROR 97
+#define MX28_INT_SSP2_ERROR 98
+#define MX28_INT_SSP3_ERROR 99
#define MX28_INT_ENET_SWI 100
#define MX28_INT_ENET_MAC0 101
#define MX28_INT_ENET_MAC1 102
@@ -185,4 +185,41 @@
#define MX28_INT_GPIO1 126
#define MX28_INT_GPIO0 127
+/*
+ * APBH DMA
+ */
+#define MX28_DMA_SSP0 0
+#define MX28_DMA_SSP1 1
+#define MX28_DMA_SSP2 2
+#define MX28_DMA_SSP3 3
+#define MX28_DMA_GPMI0 4
+#define MX28_DMA_GPMI1 5
+#define MX28_DMA_GPMI2 6
+#define MX28_DMA_GPMI3 7
+#define MX28_DMA_GPMI4 8
+#define MX28_DMA_GPMI5 9
+#define MX28_DMA_GPMI6 10
+#define MX28_DMA_GPMI7 11
+#define MX28_DMA_HSADC 12
+#define MX28_DMA_LCDIF 13
+
+/*
+ * APBX DMA
+ */
+#define MX28_DMA_AUART4_RX 0
+#define MX28_DMA_AUART4_TX 1
+#define MX28_DMA_SPDIF_TX 2
+#define MX28_DMA_SAIF0 4
+#define MX28_DMA_SAIF1 5
+#define MX28_DMA_I2C0 6
+#define MX28_DMA_I2C1 7
+#define MX28_DMA_AUART0_RX 8
+#define MX28_DMA_AUART0_TX 9
+#define MX28_DMA_AUART1_RX 10
+#define MX28_DMA_AUART1_TX 11
+#define MX28_DMA_AUART2_RX 12
+#define MX28_DMA_AUART2_TX 13
+#define MX28_DMA_AUART3_RX 14
+#define MX28_DMA_AUART3_TX 15
+
#endif /* __MACH_MX28_H__ */
diff --git a/arch/arm/mach-mxs/include/mach/mxs.h b/arch/arm/mach-mxs/include/mach/mxs.h
index f186c08c2911..35a89dd27242 100644
--- a/arch/arm/mach-mxs/include/mach/mxs.h
+++ b/arch/arm/mach-mxs/include/mach/mxs.h
@@ -28,8 +28,13 @@
/*
* MXS CPU types
*/
-#define cpu_is_mx23() (machine_is_mx23evk())
-#define cpu_is_mx28() (machine_is_mx28evk())
+#define cpu_is_mx23() ( \
+ machine_is_mx23evk() || \
+ 0)
+#define cpu_is_mx28() ( \
+ machine_is_mx28evk() || \
+ machine_is_tx28() || \
+ 0)
/*
* IO addresses common to MXS-based
diff --git a/arch/arm/mach-mxs/include/mach/mxsfb.h b/arch/arm/mach-mxs/include/mach/mxsfb.h
new file mode 100644
index 000000000000..e4d79791515e
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/mxsfb.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MACH_FB_H
+#define __MACH_FB_H
+
+#include <linux/fb.h>
+
+#define STMLCDIF_8BIT 1 /** pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /** pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
+
+#define FB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
+#define FB_SYNC_DOTCLK_FAILING_ACT (1 << 7) /* failing/negtive edge sampling */
+
+struct mxsfb_platform_data {
+ struct fb_videomode *mode_list;
+ unsigned mode_count;
+
+ unsigned default_bpp;
+
+ unsigned dotclk_delay; /* refer manual HW_LCDIF_VDCTRL4 register */
+ unsigned ld_intf_width; /* refer STMLCDIF_* macros */
+
+ unsigned fb_size; /* Size of the video memory. If zero a
+ * default will be used
+ */
+ unsigned long fb_phys; /* physical address for the video memory. If
+ * zero the framebuffer memory will be dynamically
+ * allocated. If specified,fb_size must also be specified.
+ * fb_phys must be unused by Linux.
+ */
+};
+
+#endif /* __MACH_FB_H */
diff --git a/arch/arm/mach-mxs/include/mach/uncompress.h b/arch/arm/mach-mxs/include/mach/uncompress.h
index a005e76f34f9..f12a1732d8b8 100644
--- a/arch/arm/mach-mxs/include/mach/uncompress.h
+++ b/arch/arm/mach-mxs/include/mach/uncompress.h
@@ -63,6 +63,7 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
mxs_duart_base = MX23_DUART_BASE_ADDR;
break;
case MACH_TYPE_MX28EVK:
+ case MACH_TYPE_TX28:
mxs_duart_base = MX28_DUART_BASE_ADDR;
break;
default:
diff --git a/arch/arm/mach-mxs/mach-mx23evk.c b/arch/arm/mach-mxs/mach-mx23evk.c
index aa0640052f58..a66994f0518f 100644
--- a/arch/arm/mach-mxs/mach-mx23evk.c
+++ b/arch/arm/mach-mxs/mach-mx23evk.c
@@ -26,17 +26,103 @@
#include "devices-mx23.h"
+#define MX23EVK_LCD_ENABLE MXS_GPIO_NR(1, 18)
+#define MX23EVK_BL_ENABLE MXS_GPIO_NR(1, 28)
+
static const iomux_cfg_t mx23evk_pads[] __initconst = {
/* duart */
- MX23_PAD_PWM0__DUART_RX | MXS_PAD_4MA,
- MX23_PAD_PWM1__DUART_TX | MXS_PAD_4MA,
+ MX23_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
+ MX23_PAD_PWM1__DUART_TX | MXS_PAD_CTRL,
+
+ /* auart */
+ MX23_PAD_AUART1_RX__AUART1_RX | MXS_PAD_CTRL,
+ MX23_PAD_AUART1_TX__AUART1_TX | MXS_PAD_CTRL,
+ MX23_PAD_AUART1_CTS__AUART1_CTS | MXS_PAD_CTRL,
+ MX23_PAD_AUART1_RTS__AUART1_RTS | MXS_PAD_CTRL,
+
+ /* mxsfb (lcdif) */
+ MX23_PAD_LCD_D00__LCD_D00 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D01__LCD_D01 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D02__LCD_D02 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D03__LCD_D03 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D04__LCD_D04 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D05__LCD_D05 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D06__LCD_D06 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D07__LCD_D07 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D08__LCD_D08 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D09__LCD_D09 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D10__LCD_D10 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D11__LCD_D11 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D12__LCD_D12 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D13__LCD_D13 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D14__LCD_D14 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D15__LCD_D15 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D16__LCD_D16 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_D17__LCD_D17 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D08__LCD_D18 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D09__LCD_D19 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D10__LCD_D20 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D11__LCD_D21 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D12__LCD_D22 | MXS_PAD_CTRL,
+ MX23_PAD_GPMI_D13__LCD_D23 | MXS_PAD_CTRL,
+ MX23_PAD_LCD_VSYNC__LCD_VSYNC | MXS_PAD_CTRL,
+ MX23_PAD_LCD_HSYNC__LCD_HSYNC | MXS_PAD_CTRL,
+ MX23_PAD_LCD_DOTCK__LCD_DOTCK | MXS_PAD_CTRL,
+ MX23_PAD_LCD_ENABLE__LCD_ENABLE | MXS_PAD_CTRL,
+ /* LCD panel enable */
+ MX23_PAD_LCD_RESET__GPIO_1_18 | MXS_PAD_CTRL,
+ /* backlight control */
+ MX23_PAD_PWM2__GPIO_1_28 | MXS_PAD_CTRL,
+};
+
+/* mxsfb (lcdif) */
+static struct fb_videomode mx23evk_video_modes[] = {
+ {
+ .name = "Samsung-LMS430HF02",
+ .refresh = 60,
+ .xres = 480,
+ .yres = 272,
+ .pixclock = 108096, /* picosecond (9.2 MHz) */
+ .left_margin = 15,
+ .right_margin = 8,
+ .upper_margin = 12,
+ .lower_margin = 4,
+ .hsync_len = 1,
+ .vsync_len = 1,
+ .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT |
+ FB_SYNC_DOTCLK_FAILING_ACT,
+ },
+};
+
+static const struct mxsfb_platform_data mx23evk_mxsfb_pdata __initconst = {
+ .mode_list = mx23evk_video_modes,
+ .mode_count = ARRAY_SIZE(mx23evk_video_modes),
+ .default_bpp = 32,
+ .ld_intf_width = STMLCDIF_24BIT,
};
static void __init mx23evk_init(void)
{
+ int ret;
+
mxs_iomux_setup_multiple_pads(mx23evk_pads, ARRAY_SIZE(mx23evk_pads));
mx23_add_duart();
+ mx23_add_auart0();
+
+ ret = gpio_request_one(MX23EVK_LCD_ENABLE, GPIOF_DIR_OUT, "lcd-enable");
+ if (ret)
+ pr_warn("failed to request gpio lcd-enable: %d\n", ret);
+ else
+ gpio_set_value(MX23EVK_LCD_ENABLE, 1);
+
+ ret = gpio_request_one(MX23EVK_BL_ENABLE, GPIOF_DIR_OUT, "bl-enable");
+ if (ret)
+ pr_warn("failed to request gpio bl-enable: %d\n", ret);
+ else
+ gpio_set_value(MX23EVK_BL_ENABLE, 1);
+
+ mx23_add_mxsfb(&mx23evk_mxsfb_pdata);
}
static void __init mx23evk_timer_init(void)
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index 8e2c5975001e..08002d02267a 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -28,54 +28,93 @@
#include "devices-mx28.h"
#include "gpio.h"
+#define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13)
#define MX28EVK_FEC_PHY_POWER MXS_GPIO_NR(2, 15)
+#define MX28EVK_BL_ENABLE MXS_GPIO_NR(3, 18)
+#define MX28EVK_LCD_ENABLE MXS_GPIO_NR(3, 30)
#define MX28EVK_FEC_PHY_RESET MXS_GPIO_NR(4, 13)
static const iomux_cfg_t mx28evk_pads[] __initconst = {
/* duart */
- MX28_PAD_PWM0__DUART_RX |
- (MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
- MX28_PAD_PWM1__DUART_TX |
- (MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX28_PAD_PWM0__DUART_RX | MXS_PAD_CTRL,
+ MX28_PAD_PWM1__DUART_TX | MXS_PAD_CTRL,
+ /* auart0 */
+ MX28_PAD_AUART0_RX__AUART0_RX | MXS_PAD_CTRL,
+ MX28_PAD_AUART0_TX__AUART0_TX | MXS_PAD_CTRL,
+ MX28_PAD_AUART0_CTS__AUART0_CTS | MXS_PAD_CTRL,
+ MX28_PAD_AUART0_RTS__AUART0_RTS | MXS_PAD_CTRL,
+ /* auart3 */
+ MX28_PAD_AUART3_RX__AUART3_RX | MXS_PAD_CTRL,
+ MX28_PAD_AUART3_TX__AUART3_TX | MXS_PAD_CTRL,
+ MX28_PAD_AUART3_CTS__AUART3_CTS | MXS_PAD_CTRL,
+ MX28_PAD_AUART3_RTS__AUART3_RTS | MXS_PAD_CTRL,
+
+#define MXS_PAD_FEC (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP)
/* fec0 */
- MX28_PAD_ENET0_MDC__ENET0_MDC |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_MDIO__ENET0_MDIO |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_RX_EN__ENET0_RX_EN |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_RXD0__ENET0_RXD0 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_RXD1__ENET0_RXD1 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_TX_EN__ENET0_TX_EN |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_TXD0__ENET0_TXD0 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_TXD1__ENET0_TXD1 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET_CLK__CLKCTRL_ENET |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_MDC__ENET0_MDC | MXS_PAD_FEC,
+ MX28_PAD_ENET0_MDIO__ENET0_MDIO | MXS_PAD_FEC,
+ MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MXS_PAD_FEC,
+ MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MXS_PAD_FEC,
+ MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MXS_PAD_FEC,
+ MX28_PAD_ENET_CLK__CLKCTRL_ENET | MXS_PAD_FEC,
/* fec1 */
- MX28_PAD_ENET0_CRS__ENET1_RX_EN |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_RXD2__ENET1_RXD0 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_RXD3__ENET1_RXD1 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_COL__ENET1_TX_EN |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_TXD2__ENET1_TXD0 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
- MX28_PAD_ENET0_TXD3__ENET1_TXD1 |
- (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_CRS__ENET1_RX_EN | MXS_PAD_FEC,
+ MX28_PAD_ENET0_RXD2__ENET1_RXD0 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_RXD3__ENET1_RXD1 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_COL__ENET1_TX_EN | MXS_PAD_FEC,
+ MX28_PAD_ENET0_TXD2__ENET1_TXD0 | MXS_PAD_FEC,
+ MX28_PAD_ENET0_TXD3__ENET1_TXD1 | MXS_PAD_FEC,
/* phy power line */
- MX28_PAD_SSP1_DATA3__GPIO_2_15 |
- (MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX28_PAD_SSP1_DATA3__GPIO_2_15 | MXS_PAD_CTRL,
/* phy reset line */
- MX28_PAD_ENET0_RX_CLK__GPIO_4_13 |
- (MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX28_PAD_ENET0_RX_CLK__GPIO_4_13 | MXS_PAD_CTRL,
+
+ /* flexcan0 */
+ MX28_PAD_GPMI_RDY2__CAN0_TX,
+ MX28_PAD_GPMI_RDY3__CAN0_RX,
+ /* flexcan1 */
+ MX28_PAD_GPMI_CE2N__CAN1_TX,
+ MX28_PAD_GPMI_CE3N__CAN1_RX,
+ /* transceiver power control */
+ MX28_PAD_SSP1_CMD__GPIO_2_13,
+
+ /* mxsfb (lcdif) */
+ MX28_PAD_LCD_D00__LCD_D0 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D01__LCD_D1 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D02__LCD_D2 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D03__LCD_D3 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D04__LCD_D4 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D05__LCD_D5 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D06__LCD_D6 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D07__LCD_D7 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D08__LCD_D8 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D09__LCD_D9 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D10__LCD_D10 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D11__LCD_D11 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D12__LCD_D12 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D13__LCD_D13 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D14__LCD_D14 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D15__LCD_D15 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D16__LCD_D16 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D17__LCD_D17 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D18__LCD_D18 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D19__LCD_D19 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D20__LCD_D20 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D21__LCD_D21 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D22__LCD_D22 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_D23__LCD_D23 | MXS_PAD_CTRL,
+ MX28_PAD_LCD_RD_E__LCD_VSYNC | MXS_PAD_CTRL,
+ MX28_PAD_LCD_WR_RWN__LCD_HSYNC | MXS_PAD_CTRL,
+ MX28_PAD_LCD_RS__LCD_DOTCLK | MXS_PAD_CTRL,
+ MX28_PAD_LCD_CS__LCD_ENABLE | MXS_PAD_CTRL,
+ /* LCD panel enable */
+ MX28_PAD_LCD_RESET__GPIO_3_30 | MXS_PAD_CTRL,
+ /* backlight control */
+ MX28_PAD_PWM2__GPIO_3_18 | MXS_PAD_CTRL,
};
/* fec */
@@ -119,7 +158,7 @@ static void __init mx28evk_fec_reset(void)
gpio_set_value(MX28EVK_FEC_PHY_RESET, 1);
}
-static struct fec_platform_data mx28_fec_pdata[] = {
+static struct fec_platform_data mx28_fec_pdata[] __initdata = {
{
/* fec0 */
.phy = PHY_INTERFACE_MODE_RMII,
@@ -129,15 +168,135 @@ static struct fec_platform_data mx28_fec_pdata[] = {
},
};
+static int __init mx28evk_fec_get_mac(void)
+{
+ int i;
+ u32 val;
+ const u32 *ocotp = mxs_get_ocotp();
+
+ if (!ocotp)
+ goto error;
+
+ /*
+ * OCOTP only stores the last 4 octets for each mac address,
+ * so hard-code Freescale OUI (00:04:9f) here.
+ */
+ for (i = 0; i < 2; i++) {
+ val = ocotp[i * 4];
+ mx28_fec_pdata[i].mac[0] = 0x00;
+ mx28_fec_pdata[i].mac[1] = 0x04;
+ mx28_fec_pdata[i].mac[2] = 0x9f;
+ mx28_fec_pdata[i].mac[3] = (val >> 16) & 0xff;
+ mx28_fec_pdata[i].mac[4] = (val >> 8) & 0xff;
+ mx28_fec_pdata[i].mac[5] = (val >> 0) & 0xff;
+ }
+
+ return 0;
+
+error:
+ pr_err("%s: timeout when reading fec mac from OCOTP\n", __func__);
+ return -ETIMEDOUT;
+}
+
+/*
+ * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers
+ */
+static int flexcan0_en, flexcan1_en;
+
+static void mx28evk_flexcan_switch(void)
+{
+ if (flexcan0_en || flexcan1_en)
+ gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1);
+ else
+ gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0);
+}
+
+static void mx28evk_flexcan0_switch(int enable)
+{
+ flexcan0_en = enable;
+ mx28evk_flexcan_switch();
+}
+
+static void mx28evk_flexcan1_switch(int enable)
+{
+ flexcan1_en = enable;
+ mx28evk_flexcan_switch();
+}
+
+static const struct flexcan_platform_data
+ mx28evk_flexcan_pdata[] __initconst = {
+ {
+ .transceiver_switch = mx28evk_flexcan0_switch,
+ }, {
+ .transceiver_switch = mx28evk_flexcan1_switch,
+ }
+};
+
+/* mxsfb (lcdif) */
+static struct fb_videomode mx28evk_video_modes[] = {
+ {
+ .name = "Seiko-43WVF1G",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = 29851, /* picosecond (33.5 MHz) */
+ .left_margin = 89,
+ .right_margin = 164,
+ .upper_margin = 23,
+ .lower_margin = 10,
+ .hsync_len = 10,
+ .vsync_len = 10,
+ .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT |
+ FB_SYNC_DOTCLK_FAILING_ACT,
+ },
+};
+
+static const struct mxsfb_platform_data mx28evk_mxsfb_pdata __initconst = {
+ .mode_list = mx28evk_video_modes,
+ .mode_count = ARRAY_SIZE(mx28evk_video_modes),
+ .default_bpp = 32,
+ .ld_intf_width = STMLCDIF_24BIT,
+};
+
static void __init mx28evk_init(void)
{
+ int ret;
+
mxs_iomux_setup_multiple_pads(mx28evk_pads, ARRAY_SIZE(mx28evk_pads));
mx28_add_duart();
+ mx28_add_auart0();
+ mx28_add_auart3();
+
+ if (mx28evk_fec_get_mac())
+ pr_warn("%s: failed on fec mac setup\n", __func__);
mx28evk_fec_reset();
mx28_add_fec(0, &mx28_fec_pdata[0]);
mx28_add_fec(1, &mx28_fec_pdata[1]);
+
+ ret = gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
+ "flexcan-switch");
+ if (ret) {
+ pr_err("failed to request gpio flexcan-switch: %d\n", ret);
+ } else {
+ mx28_add_flexcan(0, &mx28evk_flexcan_pdata[0]);
+ mx28_add_flexcan(1, &mx28evk_flexcan_pdata[1]);
+ }
+
+ ret = gpio_request_one(MX28EVK_LCD_ENABLE, GPIOF_DIR_OUT, "lcd-enable");
+ if (ret)
+ pr_warn("failed to request gpio lcd-enable: %d\n", ret);
+ else
+ gpio_set_value(MX28EVK_LCD_ENABLE, 1);
+
+ ret = gpio_request_one(MX28EVK_BL_ENABLE, GPIOF_DIR_OUT, "bl-enable");
+ if (ret)
+ pr_warn("failed to request gpio bl-enable: %d\n", ret);
+ else
+ gpio_set_value(MX28EVK_BL_ENABLE, 1);
+
+ mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
}
static void __init mx28evk_timer_init(void)
diff --git a/arch/arm/mach-mxs/mach-tx28.c b/arch/arm/mach-mxs/mach-tx28.c
new file mode 100644
index 000000000000..b65e3719cbc4
--- /dev/null
+++ b/arch/arm/mach-mxs/mach-tx28.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2010 <LW@KARO-electronics.de>
+ *
+ * based on: mach-mx28_evk.c
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/i2c.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/iomux-mx28.h>
+
+#include "devices-mx28.h"
+#include "module-tx28.h"
+
+#define TX28_STK5_GPIO_LED MXS_GPIO_NR(4, 10)
+
+static const iomux_cfg_t tx28_stk5v3_pads[] __initconst = {
+ /* LED */
+ MX28_PAD_ENET0_RXD3__GPIO_4_10 |
+ MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL,
+
+ /* framebuffer */
+#define LCD_MODE (MXS_PAD_3V3 | MXS_PAD_4MA)
+ MX28_PAD_LCD_D00__LCD_D0 | LCD_MODE,
+ MX28_PAD_LCD_D01__LCD_D1 | LCD_MODE,
+ MX28_PAD_LCD_D02__LCD_D2 | LCD_MODE,
+ MX28_PAD_LCD_D03__LCD_D3 | LCD_MODE,
+ MX28_PAD_LCD_D04__LCD_D4 | LCD_MODE,
+ MX28_PAD_LCD_D05__LCD_D5 | LCD_MODE,
+ MX28_PAD_LCD_D06__LCD_D6 | LCD_MODE,
+ MX28_PAD_LCD_D07__LCD_D7 | LCD_MODE,
+ MX28_PAD_LCD_D08__LCD_D8 | LCD_MODE,
+ MX28_PAD_LCD_D09__LCD_D9 | LCD_MODE,
+ MX28_PAD_LCD_D10__LCD_D10 | LCD_MODE,
+ MX28_PAD_LCD_D11__LCD_D11 | LCD_MODE,
+ MX28_PAD_LCD_D12__LCD_D12 | LCD_MODE,
+ MX28_PAD_LCD_D13__LCD_D13 | LCD_MODE,
+ MX28_PAD_LCD_D14__LCD_D14 | LCD_MODE,
+ MX28_PAD_LCD_D15__LCD_D15 | LCD_MODE,
+ MX28_PAD_LCD_D16__LCD_D16 | LCD_MODE,
+ MX28_PAD_LCD_D17__LCD_D17 | LCD_MODE,
+ MX28_PAD_LCD_D18__LCD_D18 | LCD_MODE,
+ MX28_PAD_LCD_D19__LCD_D19 | LCD_MODE,
+ MX28_PAD_LCD_D20__LCD_D20 | LCD_MODE,
+ MX28_PAD_LCD_D21__LCD_D21 | LCD_MODE,
+ MX28_PAD_LCD_D22__LCD_D22 | LCD_MODE,
+ MX28_PAD_LCD_D23__LCD_D23 | LCD_MODE,
+ MX28_PAD_LCD_RD_E__LCD_VSYNC | LCD_MODE,
+ MX28_PAD_LCD_WR_RWN__LCD_HSYNC | LCD_MODE,
+ MX28_PAD_LCD_RS__LCD_DOTCLK | LCD_MODE,
+ MX28_PAD_LCD_CS__LCD_CS | LCD_MODE,
+ MX28_PAD_LCD_VSYNC__LCD_VSYNC | LCD_MODE,
+ MX28_PAD_LCD_HSYNC__LCD_HSYNC | LCD_MODE,
+ MX28_PAD_LCD_DOTCLK__LCD_DOTCLK | LCD_MODE,
+ MX28_PAD_LCD_ENABLE__GPIO_1_31 | LCD_MODE,
+ MX28_PAD_LCD_RESET__GPIO_3_30 | LCD_MODE,
+ MX28_PAD_PWM0__PWM_0 | LCD_MODE,
+
+ /* UART1 */
+ MX28_PAD_AUART0_CTS__DUART_RX,
+ MX28_PAD_AUART0_RTS__DUART_TX,
+ MX28_PAD_AUART0_TX__DUART_RTS,
+ MX28_PAD_AUART0_RX__DUART_CTS,
+
+ /* UART2 */
+ MX28_PAD_AUART1_RX__AUART1_RX,
+ MX28_PAD_AUART1_TX__AUART1_TX,
+ MX28_PAD_AUART1_RTS__AUART1_RTS,
+ MX28_PAD_AUART1_CTS__AUART1_CTS,
+
+ /* CAN */
+ MX28_PAD_GPMI_RDY2__CAN0_TX,
+ MX28_PAD_GPMI_RDY3__CAN0_RX,
+
+ /* I2C */
+ MX28_PAD_I2C0_SCL__I2C0_SCL,
+ MX28_PAD_I2C0_SDA__I2C0_SDA,
+
+ /* TSC2007 */
+ MX28_PAD_SAIF0_MCLK__GPIO_3_20 | MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_PULLUP,
+
+ /* MMC0 */
+ MX28_PAD_SSP0_DATA0__SSP0_D0 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA1__SSP0_D1 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA2__SSP0_D2 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA3__SSP0_D3 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA4__SSP0_D4 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA5__SSP0_D5 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA6__SSP0_D6 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DATA7__SSP0_D7 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_CMD__SSP0_CMD |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX28_PAD_SSP0_SCK__SSP0_SCK |
+ (MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+};
+
+static struct gpio_led tx28_stk5v3_leds[] = {
+ {
+ .name = "GPIO-LED",
+ .default_trigger = "heartbeat",
+ .gpio = TX28_STK5_GPIO_LED,
+ },
+};
+
+static const struct gpio_led_platform_data tx28_stk5v3_led_data __initconst = {
+ .leds = tx28_stk5v3_leds,
+ .num_leds = ARRAY_SIZE(tx28_stk5v3_leds),
+};
+
+static struct spi_board_info tx28_spi_board_info[] = {
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .controller_data = (void *)SPI_GPIO_NO_CHIPSELECT,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static struct i2c_board_info tx28_stk5v3_i2c_boardinfo[] __initdata = {
+ {
+ I2C_BOARD_INFO("ds1339", 0x68),
+ },
+};
+
+static void __init tx28_stk5v3_init(void)
+{
+ mxs_iomux_setup_multiple_pads(tx28_stk5v3_pads,
+ ARRAY_SIZE(tx28_stk5v3_pads));
+
+ mx28_add_duart(); /* UART1 */
+ mx28_add_auart(1); /* UART2 */
+
+ tx28_add_fec0();
+ /* spi via ssp will be added when available */
+ spi_register_board_info(tx28_spi_board_info,
+ ARRAY_SIZE(tx28_spi_board_info));
+ mxs_add_platform_device("leds-gpio", 0, NULL, 0,
+ &tx28_stk5v3_led_data, sizeof(tx28_stk5v3_led_data));
+ mx28_add_mxs_i2c(0);
+ i2c_register_board_info(0, tx28_stk5v3_i2c_boardinfo,
+ ARRAY_SIZE(tx28_stk5v3_i2c_boardinfo));
+}
+
+static void __init tx28_timer_init(void)
+{
+ mx28_clocks_init();
+}
+
+static struct sys_timer tx28_timer = {
+ .init = tx28_timer_init,
+};
+
+MACHINE_START(TX28, "Ka-Ro electronics TX28 module")
+ .map_io = mx28_map_io,
+ .init_irq = mx28_init_irq,
+ .init_machine = tx28_stk5v3_init,
+ .timer = &tx28_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mxs/module-tx28.c b/arch/arm/mach-mxs/module-tx28.c
new file mode 100644
index 000000000000..fa0b154da67b
--- /dev/null
+++ b/arch/arm/mach-mxs/module-tx28.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2010 <LW@KARO-electronics.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/fec.h>
+#include <linux/gpio.h>
+
+#include <mach/iomux-mx28.h>
+#include "../devices-mx28.h"
+
+#include "module-tx28.h"
+
+#define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29)
+#define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13)
+
+static const iomux_cfg_t tx28_fec_gpio_pads[] __initconst = {
+ /* PHY POWER */
+ MX28_PAD_PWM4__GPIO_3_29 |
+ MXS_PAD_4MA | MXS_PAD_NOPULL | MXS_PAD_3V3,
+ /* PHY RESET */
+ MX28_PAD_ENET0_RX_CLK__GPIO_4_13 |
+ MXS_PAD_4MA | MXS_PAD_NOPULL | MXS_PAD_3V3,
+ /* Mode strap pins 0-2 */
+ MX28_PAD_ENET0_RXD0__GPIO_4_3 |
+ MXS_PAD_8MA | MXS_PAD_PULLUP | MXS_PAD_3V3,
+ MX28_PAD_ENET0_RXD1__GPIO_4_4 |
+ MXS_PAD_8MA | MXS_PAD_PULLUP | MXS_PAD_3V3,
+ MX28_PAD_ENET0_RX_EN__GPIO_4_2 |
+ MXS_PAD_8MA | MXS_PAD_PULLUP | MXS_PAD_3V3,
+ /* nINT */
+ MX28_PAD_ENET0_TX_CLK__GPIO_4_5 |
+ MXS_PAD_4MA | MXS_PAD_NOPULL | MXS_PAD_3V3,
+
+ MX28_PAD_ENET0_MDC__GPIO_4_0,
+ MX28_PAD_ENET0_MDIO__GPIO_4_1,
+ MX28_PAD_ENET0_TX_EN__GPIO_4_6,
+ MX28_PAD_ENET0_TXD0__GPIO_4_7,
+ MX28_PAD_ENET0_TXD1__GPIO_4_8,
+ MX28_PAD_ENET_CLK__GPIO_4_16,
+};
+
+#define FEC_MODE (MXS_PAD_8MA | MXS_PAD_PULLUP | MXS_PAD_3V3)
+static const iomux_cfg_t tx28_fec_pads[] __initconst = {
+ MX28_PAD_ENET0_MDC__ENET0_MDC | FEC_MODE,
+ MX28_PAD_ENET0_MDIO__ENET0_MDIO | FEC_MODE,
+ MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | FEC_MODE,
+ MX28_PAD_ENET0_RXD0__ENET0_RXD0 | FEC_MODE,
+ MX28_PAD_ENET0_RXD1__ENET0_RXD1 | FEC_MODE,
+ MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | FEC_MODE,
+ MX28_PAD_ENET0_TXD0__ENET0_TXD0 | FEC_MODE,
+ MX28_PAD_ENET0_TXD1__ENET0_TXD1 | FEC_MODE,
+ MX28_PAD_ENET_CLK__CLKCTRL_ENET | FEC_MODE,
+};
+
+static const struct fec_platform_data tx28_fec_data __initconst = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+int __init tx28_add_fec0(void)
+{
+ int i, ret;
+
+ pr_debug("%s: Switching FEC PHY power off\n", __func__);
+ ret = mxs_iomux_setup_multiple_pads(tx28_fec_gpio_pads,
+ ARRAY_SIZE(tx28_fec_gpio_pads));
+ for (i = 0; i < ARRAY_SIZE(tx28_fec_gpio_pads); i++) {
+ unsigned int gpio = MXS_GPIO_NR(PAD_BANK(tx28_fec_gpio_pads[i]),
+ PAD_PIN(tx28_fec_gpio_pads[i]));
+
+ ret = gpio_request(gpio, "FEC");
+ if (ret) {
+ pr_err("Failed to request GPIO_%d_%d: %d\n",
+ PAD_BANK(tx28_fec_gpio_pads[i]),
+ PAD_PIN(tx28_fec_gpio_pads[i]), ret);
+ goto free_gpios;
+ }
+ ret = gpio_direction_output(gpio, 0);
+ if (ret) {
+ pr_err("Failed to set direction of GPIO_%d_%d to output: %d\n",
+ gpio / 32 + 1, gpio % 32, ret);
+ goto free_gpios;
+ }
+ }
+
+ /* Power up fec phy */
+ pr_debug("%s: Switching FEC PHY power on\n", __func__);
+ ret = gpio_direction_output(TX28_FEC_PHY_POWER, 1);
+ if (ret) {
+ pr_err("Failed to power on PHY: %d\n", ret);
+ goto free_gpios;
+ }
+ mdelay(26); /* 25ms according to data sheet */
+
+ /* nINT */
+ gpio_direction_input(MXS_GPIO_NR(4, 5));
+ /* Mode strap pins */
+ gpio_direction_output(MXS_GPIO_NR(4, 2), 1);
+ gpio_direction_output(MXS_GPIO_NR(4, 3), 1);
+ gpio_direction_output(MXS_GPIO_NR(4, 4), 1);
+
+ udelay(100); /* minimum assertion time for nRST */
+
+ pr_debug("%s: Deasserting FEC PHY RESET\n", __func__);
+ gpio_set_value(TX28_FEC_PHY_RESET, 1);
+
+ ret = mxs_iomux_setup_multiple_pads(tx28_fec_pads,
+ ARRAY_SIZE(tx28_fec_pads));
+ if (ret) {
+ pr_debug("%s: mxs_iomux_setup_multiple_pads() failed with rc: %d\n",
+ __func__, ret);
+ goto free_gpios;
+ }
+ pr_debug("%s: Registering FEC device\n", __func__);
+ mx28_add_fec(0, &tx28_fec_data);
+ return 0;
+
+free_gpios:
+ while (--i >= 0) {
+ unsigned int gpio = MXS_GPIO_NR(PAD_BANK(tx28_fec_gpio_pads[i]),
+ PAD_PIN(tx28_fec_gpio_pads[i]));
+
+ gpio_free(gpio);
+ }
+
+ return ret;
+}
diff --git a/arch/arm/mach-mxs/module-tx28.h b/arch/arm/mach-mxs/module-tx28.h
new file mode 100644
index 000000000000..df9e1b6e81bf
--- /dev/null
+++ b/arch/arm/mach-mxs/module-tx28.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+int __init tx28_add_fec0(void);
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
new file mode 100644
index 000000000000..65157a35dbba
--- /dev/null
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#include <mach/mxs.h>
+
+#define OCOTP_WORD_OFFSET 0x20
+#define OCOTP_WORD_COUNT 0x20
+
+#define BM_OCOTP_CTRL_BUSY (1 << 8)
+#define BM_OCOTP_CTRL_ERROR (1 << 9)
+#define BM_OCOTP_CTRL_RD_BANK_OPEN (1 << 12)
+
+static DEFINE_MUTEX(ocotp_mutex);
+static u32 ocotp_words[OCOTP_WORD_COUNT];
+
+const u32 *mxs_get_ocotp(void)
+{
+ void __iomem *ocotp_base = MXS_IO_ADDRESS(MXS_OCOTP_BASE_ADDR);
+ int timeout = 0x400;
+ size_t i;
+ static int once = 0;
+
+ if (once)
+ return ocotp_words;
+
+ mutex_lock(&ocotp_mutex);
+
+ /*
+ * clk_enable(hbus_clk) for ocotp can be skipped
+ * as it must be on when system is running.
+ */
+
+ /* try to clear ERROR bit */
+ __mxs_clrl(BM_OCOTP_CTRL_ERROR, ocotp_base);
+
+ /* check both BUSY and ERROR cleared */
+ while ((__raw_readl(ocotp_base) &
+ (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR)) && --timeout)
+ cpu_relax();
+
+ if (unlikely(!timeout))
+ goto error_unlock;
+
+ /* open OCOTP banks for read */
+ __mxs_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base);
+
+ /* approximately wait 32 hclk cycles */
+ udelay(1);
+
+ /* poll BUSY bit becoming cleared */
+ timeout = 0x400;
+ while ((__raw_readl(ocotp_base) & BM_OCOTP_CTRL_BUSY) && --timeout)
+ cpu_relax();
+
+ if (unlikely(!timeout))
+ goto error_unlock;
+
+ for (i = 0; i < OCOTP_WORD_COUNT; i++)
+ ocotp_words[i] = __raw_readl(ocotp_base + OCOTP_WORD_OFFSET +
+ i * 0x10);
+
+ /* close banks for power saving */
+ __mxs_clrl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base);
+
+ once = 1;
+
+ mutex_unlock(&ocotp_mutex);
+
+ return ocotp_words;
+
+error_unlock:
+ mutex_unlock(&ocotp_mutex);
+ pr_err("%s: timeout in reading OCOTP\n", __func__);
+ return NULL;
+}
diff --git a/arch/arm/mach-mxs/pm.c b/arch/arm/mach-mxs/pm.c
new file mode 100644
index 000000000000..fb042da29bda
--- /dev/null
+++ b/arch/arm/mach-mxs/pm.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/io.h>
+#include <mach/system.h>
+
+static int mxs_suspend_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_MEM:
+ arch_idle();
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct platform_suspend_ops mxs_suspend_ops = {
+ .enter = mxs_suspend_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static int __init mxs_pm_init(void)
+{
+ suspend_set_ops(&mxs_suspend_ops);
+ return 0;
+}
+device_initcall(mxs_pm_init);
diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx23.h b/arch/arm/mach-mxs/regs-clkctrl-mx23.h
index dbc04747b691..0ea5c9d0e2b2 100644
--- a/arch/arm/mach-mxs/regs-clkctrl-mx23.h
+++ b/arch/arm/mach-mxs/regs-clkctrl-mx23.h
@@ -33,10 +33,6 @@
#define HW_CLKCTRL_PLLCTRL0_CLR (0x00000008)
#define HW_CLKCTRL_PLLCTRL0_TOG (0x0000000c)
-#define BP_CLKCTRL_PLLCTRL0_RSRVD6 30
-#define BM_CLKCTRL_PLLCTRL0_RSRVD6 0xC0000000
-#define BF_CLKCTRL_PLLCTRL0_RSRVD6(v) \
- (((v) << 30) & BM_CLKCTRL_PLLCTRL0_RSRVD6)
#define BP_CLKCTRL_PLLCTRL0_LFR_SEL 28
#define BM_CLKCTRL_PLLCTRL0_LFR_SEL 0x30000000
#define BF_CLKCTRL_PLLCTRL0_LFR_SEL(v) \
@@ -45,10 +41,6 @@
#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLLCTRL0_RSRVD5 26
-#define BM_CLKCTRL_PLLCTRL0_RSRVD5 0x0C000000
-#define BF_CLKCTRL_PLLCTRL0_RSRVD5(v) \
- (((v) << 26) & BM_CLKCTRL_PLLCTRL0_RSRVD5)
#define BP_CLKCTRL_PLLCTRL0_CP_SEL 24
#define BM_CLKCTRL_PLLCTRL0_CP_SEL 0x03000000
#define BF_CLKCTRL_PLLCTRL0_CP_SEL(v) \
@@ -57,10 +49,6 @@
#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLLCTRL0_CP_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLLCTRL0_RSRVD4 22
-#define BM_CLKCTRL_PLLCTRL0_RSRVD4 0x00C00000
-#define BF_CLKCTRL_PLLCTRL0_RSRVD4(v) \
- (((v) << 22) & BM_CLKCTRL_PLLCTRL0_RSRVD4)
#define BP_CLKCTRL_PLLCTRL0_DIV_SEL 20
#define BM_CLKCTRL_PLLCTRL0_DIV_SEL 0x00300000
#define BF_CLKCTRL_PLLCTRL0_DIV_SEL(v) \
@@ -69,23 +57,13 @@
#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWER 0x1
#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWEST 0x2
#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__UNDEFINED 0x3
-#define BM_CLKCTRL_PLLCTRL0_RSRVD3 0x00080000
#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000
-#define BM_CLKCTRL_PLLCTRL0_RSRVD2 0x00020000
#define BM_CLKCTRL_PLLCTRL0_POWER 0x00010000
-#define BP_CLKCTRL_PLLCTRL0_RSRVD1 0
-#define BM_CLKCTRL_PLLCTRL0_RSRVD1 0x0000FFFF
-#define BF_CLKCTRL_PLLCTRL0_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_PLLCTRL0_RSRVD1)
#define HW_CLKCTRL_PLLCTRL1 (0x00000010)
#define BM_CLKCTRL_PLLCTRL1_LOCK 0x80000000
#define BM_CLKCTRL_PLLCTRL1_FORCE_LOCK 0x40000000
-#define BP_CLKCTRL_PLLCTRL1_RSRVD1 16
-#define BM_CLKCTRL_PLLCTRL1_RSRVD1 0x3FFF0000
-#define BF_CLKCTRL_PLLCTRL1_RSRVD1(v) \
- (((v) << 16) & BM_CLKCTRL_PLLCTRL1_RSRVD1)
#define BP_CLKCTRL_PLLCTRL1_LOCK_COUNT 0
#define BM_CLKCTRL_PLLCTRL1_LOCK_COUNT 0x0000FFFF
#define BF_CLKCTRL_PLLCTRL1_LOCK_COUNT(v) \
@@ -96,29 +74,15 @@
#define HW_CLKCTRL_CPU_CLR (0x00000028)
#define HW_CLKCTRL_CPU_TOG (0x0000002c)
-#define BP_CLKCTRL_CPU_RSRVD5 30
-#define BM_CLKCTRL_CPU_RSRVD5 0xC0000000
-#define BF_CLKCTRL_CPU_RSRVD5(v) \
- (((v) << 30) & BM_CLKCTRL_CPU_RSRVD5)
#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000
#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000
-#define BM_CLKCTRL_CPU_RSRVD4 0x08000000
#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000
#define BP_CLKCTRL_CPU_DIV_XTAL 16
#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000
#define BF_CLKCTRL_CPU_DIV_XTAL(v) \
(((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL)
-#define BP_CLKCTRL_CPU_RSRVD3 13
-#define BM_CLKCTRL_CPU_RSRVD3 0x0000E000
-#define BF_CLKCTRL_CPU_RSRVD3(v) \
- (((v) << 13) & BM_CLKCTRL_CPU_RSRVD3)
#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000
-#define BM_CLKCTRL_CPU_RSRVD2 0x00000800
#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400
-#define BP_CLKCTRL_CPU_RSRVD1 6
-#define BM_CLKCTRL_CPU_RSRVD1 0x000003C0
-#define BF_CLKCTRL_CPU_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_CPU_RSRVD1)
#define BP_CLKCTRL_CPU_DIV_CPU 0
#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
#define BF_CLKCTRL_CPU_DIV_CPU(v) \
@@ -129,10 +93,6 @@
#define HW_CLKCTRL_HBUS_CLR (0x00000038)
#define HW_CLKCTRL_HBUS_TOG (0x0000003c)
-#define BP_CLKCTRL_HBUS_RSRVD4 30
-#define BM_CLKCTRL_HBUS_RSRVD4 0xC0000000
-#define BF_CLKCTRL_HBUS_RSRVD4(v) \
- (((v) << 30) & BM_CLKCTRL_HBUS_RSRVD4)
#define BM_CLKCTRL_HBUS_BUSY 0x20000000
#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x10000000
#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x08000000
@@ -143,7 +103,6 @@
#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000
#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000
#define BM_CLKCTRL_HBUS_AUTO_SLOW_MODE 0x00100000
-#define BM_CLKCTRL_HBUS_RSRVD2 0x00080000
#define BP_CLKCTRL_HBUS_SLOW_DIV 16
#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000
#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \
@@ -154,10 +113,6 @@
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5
-#define BP_CLKCTRL_HBUS_RSRVD1 6
-#define BM_CLKCTRL_HBUS_RSRVD1 0x0000FFC0
-#define BF_CLKCTRL_HBUS_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_HBUS_RSRVD1)
#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020
#define BP_CLKCTRL_HBUS_DIV 0
#define BM_CLKCTRL_HBUS_DIV 0x0000001F
@@ -167,10 +122,6 @@
#define HW_CLKCTRL_XBUS (0x00000040)
#define BM_CLKCTRL_XBUS_BUSY 0x80000000
-#define BP_CLKCTRL_XBUS_RSRVD1 11
-#define BM_CLKCTRL_XBUS_RSRVD1 0x7FFFF800
-#define BF_CLKCTRL_XBUS_RSRVD1(v) \
- (((v) << 11) & BM_CLKCTRL_XBUS_RSRVD1)
#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400
#define BP_CLKCTRL_XBUS_DIV 0
#define BM_CLKCTRL_XBUS_DIV 0x000003FF
@@ -192,10 +143,6 @@
#define BM_CLKCTRL_XTAL_DIGCTRL_CLK1M_GATE 0x08000000
#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26
#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000
-#define BP_CLKCTRL_XTAL_RSRVD1 2
-#define BM_CLKCTRL_XTAL_RSRVD1 0x03FFFFFC
-#define BF_CLKCTRL_XTAL_RSRVD1(v) \
- (((v) << 2) & BM_CLKCTRL_XTAL_RSRVD1)
#define BP_CLKCTRL_XTAL_DIV_UART 0
#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003
#define BF_CLKCTRL_XTAL_DIV_UART(v) \
@@ -205,12 +152,7 @@
#define BP_CLKCTRL_PIX_CLKGATE 31
#define BM_CLKCTRL_PIX_CLKGATE 0x80000000
-#define BM_CLKCTRL_PIX_RSRVD2 0x40000000
#define BM_CLKCTRL_PIX_BUSY 0x20000000
-#define BP_CLKCTRL_PIX_RSRVD1 13
-#define BM_CLKCTRL_PIX_RSRVD1 0x1FFFE000
-#define BF_CLKCTRL_PIX_RSRVD1(v) \
- (((v) << 13) & BM_CLKCTRL_PIX_RSRVD1)
#define BM_CLKCTRL_PIX_DIV_FRAC_EN 0x00001000
#define BP_CLKCTRL_PIX_DIV 0
#define BM_CLKCTRL_PIX_DIV 0x00000FFF
@@ -221,12 +163,7 @@
#define BP_CLKCTRL_SSP_CLKGATE 31
#define BM_CLKCTRL_SSP_CLKGATE 0x80000000
-#define BM_CLKCTRL_SSP_RSRVD2 0x40000000
#define BM_CLKCTRL_SSP_BUSY 0x20000000
-#define BP_CLKCTRL_SSP_RSRVD1 10
-#define BM_CLKCTRL_SSP_RSRVD1 0x1FFFFC00
-#define BF_CLKCTRL_SSP_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_SSP_RSRVD1)
#define BM_CLKCTRL_SSP_DIV_FRAC_EN 0x00000200
#define BP_CLKCTRL_SSP_DIV 0
#define BM_CLKCTRL_SSP_DIV 0x000001FF
@@ -237,12 +174,7 @@
#define BP_CLKCTRL_GPMI_CLKGATE 31
#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000
-#define BM_CLKCTRL_GPMI_RSRVD2 0x40000000
#define BM_CLKCTRL_GPMI_BUSY 0x20000000
-#define BP_CLKCTRL_GPMI_RSRVD1 11
-#define BM_CLKCTRL_GPMI_RSRVD1 0x1FFFF800
-#define BF_CLKCTRL_GPMI_RSRVD1(v) \
- (((v) << 11) & BM_CLKCTRL_GPMI_RSRVD1)
#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400
#define BP_CLKCTRL_GPMI_DIV 0
#define BM_CLKCTRL_GPMI_DIV 0x000003FF
@@ -252,10 +184,6 @@
#define HW_CLKCTRL_SPDIF (0x00000090)
#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000
-#define BP_CLKCTRL_SPDIF_RSRVD 0
-#define BM_CLKCTRL_SPDIF_RSRVD 0x7FFFFFFF
-#define BF_CLKCTRL_SPDIF_RSRVD(v) \
- (((v) << 0) & BM_CLKCTRL_SPDIF_RSRVD)
#define HW_CLKCTRL_EMI (0x000000a0)
@@ -266,24 +194,12 @@
#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000
#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000
#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000
-#define BP_CLKCTRL_EMI_RSRVD3 18
-#define BM_CLKCTRL_EMI_RSRVD3 0x03FC0000
-#define BF_CLKCTRL_EMI_RSRVD3(v) \
- (((v) << 18) & BM_CLKCTRL_EMI_RSRVD3)
#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000
#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000
-#define BP_CLKCTRL_EMI_RSRVD2 12
-#define BM_CLKCTRL_EMI_RSRVD2 0x0000F000
-#define BF_CLKCTRL_EMI_RSRVD2(v) \
- (((v) << 12) & BM_CLKCTRL_EMI_RSRVD2)
#define BP_CLKCTRL_EMI_DIV_XTAL 8
#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00
#define BF_CLKCTRL_EMI_DIV_XTAL(v) \
(((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL)
-#define BP_CLKCTRL_EMI_RSRVD1 6
-#define BM_CLKCTRL_EMI_RSRVD1 0x000000C0
-#define BF_CLKCTRL_EMI_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_EMI_RSRVD1)
#define BP_CLKCTRL_EMI_DIV_EMI 0
#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F
#define BF_CLKCTRL_EMI_DIV_EMI(v) \
@@ -292,22 +208,13 @@
#define HW_CLKCTRL_IR (0x000000b0)
#define BM_CLKCTRL_IR_CLKGATE 0x80000000
-#define BM_CLKCTRL_IR_RSRVD3 0x40000000
#define BM_CLKCTRL_IR_AUTO_DIV 0x20000000
#define BM_CLKCTRL_IR_IR_BUSY 0x10000000
#define BM_CLKCTRL_IR_IROV_BUSY 0x08000000
-#define BP_CLKCTRL_IR_RSRVD2 25
-#define BM_CLKCTRL_IR_RSRVD2 0x06000000
-#define BF_CLKCTRL_IR_RSRVD2(v) \
- (((v) << 25) & BM_CLKCTRL_IR_RSRVD2)
#define BP_CLKCTRL_IR_IROV_DIV 16
#define BM_CLKCTRL_IR_IROV_DIV 0x01FF0000
#define BF_CLKCTRL_IR_IROV_DIV(v) \
(((v) << 16) & BM_CLKCTRL_IR_IROV_DIV)
-#define BP_CLKCTRL_IR_RSRVD1 10
-#define BM_CLKCTRL_IR_RSRVD1 0x0000FC00
-#define BF_CLKCTRL_IR_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_IR_RSRVD1)
#define BP_CLKCTRL_IR_IR_DIV 0
#define BM_CLKCTRL_IR_IR_DIV 0x000003FF
#define BF_CLKCTRL_IR_IR_DIV(v) \
@@ -316,12 +223,7 @@
#define HW_CLKCTRL_SAIF (0x000000c0)
#define BM_CLKCTRL_SAIF_CLKGATE 0x80000000
-#define BM_CLKCTRL_SAIF_RSRVD2 0x40000000
#define BM_CLKCTRL_SAIF_BUSY 0x20000000
-#define BP_CLKCTRL_SAIF_RSRVD1 17
-#define BM_CLKCTRL_SAIF_RSRVD1 0x1FFE0000
-#define BF_CLKCTRL_SAIF_RSRVD1(v) \
- (((v) << 17) & BM_CLKCTRL_SAIF_RSRVD1)
#define BM_CLKCTRL_SAIF_DIV_FRAC_EN 0x00010000
#define BP_CLKCTRL_SAIF_DIV 0
#define BM_CLKCTRL_SAIF_DIV 0x0000FFFF
@@ -332,20 +234,11 @@
#define BM_CLKCTRL_TV_CLK_TV108M_GATE 0x80000000
#define BM_CLKCTRL_TV_CLK_TV_GATE 0x40000000
-#define BP_CLKCTRL_TV_RSRVD 0
-#define BM_CLKCTRL_TV_RSRVD 0x3FFFFFFF
-#define BF_CLKCTRL_TV_RSRVD(v) \
- (((v) << 0) & BM_CLKCTRL_TV_RSRVD)
#define HW_CLKCTRL_ETM (0x000000e0)
#define BM_CLKCTRL_ETM_CLKGATE 0x80000000
-#define BM_CLKCTRL_ETM_RSRVD2 0x40000000
#define BM_CLKCTRL_ETM_BUSY 0x20000000
-#define BP_CLKCTRL_ETM_RSRVD1 7
-#define BM_CLKCTRL_ETM_RSRVD1 0x1FFFFF80
-#define BF_CLKCTRL_ETM_RSRVD1(v) \
- (((v) << 7) & BM_CLKCTRL_ETM_RSRVD1)
#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000040
#define BP_CLKCTRL_ETM_DIV 0
#define BM_CLKCTRL_ETM_DIV 0x0000003F
@@ -393,36 +286,23 @@
#define BM_CLKCTRL_FRAC1_CLKGATEVID 0x80000000
#define BM_CLKCTRL_FRAC1_VID_STABLE 0x40000000
-#define BP_CLKCTRL_FRAC1_RSRVD1 0
-#define BM_CLKCTRL_FRAC1_RSRVD1 0x3FFFFFFF
-#define BF_CLKCTRL_FRAC1_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_FRAC1_RSRVD1)
#define HW_CLKCTRL_CLKSEQ (0x00000110)
#define HW_CLKCTRL_CLKSEQ_SET (0x00000114)
#define HW_CLKCTRL_CLKSEQ_CLR (0x00000118)
#define HW_CLKCTRL_CLKSEQ_TOG (0x0000011c)
-#define BP_CLKCTRL_CLKSEQ_RSRVD1 9
-#define BM_CLKCTRL_CLKSEQ_RSRVD1 0xFFFFFE00
-#define BF_CLKCTRL_CLKSEQ_RSRVD1(v) \
- (((v) << 9) & BM_CLKCTRL_CLKSEQ_RSRVD1)
#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100
#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00000080
#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000040
#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP 0x00000020
#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000010
#define BM_CLKCTRL_CLKSEQ_BYPASS_IR 0x00000008
-#define BM_CLKCTRL_CLKSEQ_RSRVD0 0x00000004
#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002
#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF 0x00000001
#define HW_CLKCTRL_RESET (0x00000120)
-#define BP_CLKCTRL_RESET_RSRVD 2
-#define BM_CLKCTRL_RESET_RSRVD 0xFFFFFFFC
-#define BF_CLKCTRL_RESET_RSRVD(v) \
- (((v) << 2) & BM_CLKCTRL_RESET_RSRVD)
#define BM_CLKCTRL_RESET_CHIP 0x00000002
#define BM_CLKCTRL_RESET_DIG 0x00000001
@@ -432,10 +312,6 @@
#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000
#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \
(((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT)
-#define BP_CLKCTRL_STATUS_RSRVD 0
-#define BM_CLKCTRL_STATUS_RSRVD 0x3FFFFFFF
-#define BF_CLKCTRL_STATUS_RSRVD(v) \
- (((v) << 0) & BM_CLKCTRL_STATUS_RSRVD)
#define HW_CLKCTRL_VERSION (0x00000140)
diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx28.h b/arch/arm/mach-mxs/regs-clkctrl-mx28.h
index 661df18755f7..7d1b061d7943 100644
--- a/arch/arm/mach-mxs/regs-clkctrl-mx28.h
+++ b/arch/arm/mach-mxs/regs-clkctrl-mx28.h
@@ -31,10 +31,6 @@
#define HW_CLKCTRL_PLL0CTRL0_CLR (0x00000008)
#define HW_CLKCTRL_PLL0CTRL0_TOG (0x0000000c)
-#define BP_CLKCTRL_PLL0CTRL0_RSRVD6 30
-#define BM_CLKCTRL_PLL0CTRL0_RSRVD6 0xC0000000
-#define BF_CLKCTRL_PLL0CTRL0_RSRVD6(v) \
- (((v) << 30) & BM_CLKCTRL_PLL0CTRL0_RSRVD6)
#define BP_CLKCTRL_PLL0CTRL0_LFR_SEL 28
#define BM_CLKCTRL_PLL0CTRL0_LFR_SEL 0x30000000
#define BF_CLKCTRL_PLL0CTRL0_LFR_SEL(v) \
@@ -43,10 +39,6 @@
#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLL0CTRL0_RSRVD5 26
-#define BM_CLKCTRL_PLL0CTRL0_RSRVD5 0x0C000000
-#define BF_CLKCTRL_PLL0CTRL0_RSRVD5(v) \
- (((v) << 26) & BM_CLKCTRL_PLL0CTRL0_RSRVD5)
#define BP_CLKCTRL_PLL0CTRL0_CP_SEL 24
#define BM_CLKCTRL_PLL0CTRL0_CP_SEL 0x03000000
#define BF_CLKCTRL_PLL0CTRL0_CP_SEL(v) \
@@ -55,10 +47,6 @@
#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLL0CTRL0_RSRVD4 22
-#define BM_CLKCTRL_PLL0CTRL0_RSRVD4 0x00C00000
-#define BF_CLKCTRL_PLL0CTRL0_RSRVD4(v) \
- (((v) << 22) & BM_CLKCTRL_PLL0CTRL0_RSRVD4)
#define BP_CLKCTRL_PLL0CTRL0_DIV_SEL 20
#define BM_CLKCTRL_PLL0CTRL0_DIV_SEL 0x00300000
#define BF_CLKCTRL_PLL0CTRL0_DIV_SEL(v) \
@@ -67,22 +55,13 @@
#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWER 0x1
#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWEST 0x2
#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__UNDEFINED 0x3
-#define BM_CLKCTRL_PLL0CTRL0_RSRVD3 0x00080000
#define BM_CLKCTRL_PLL0CTRL0_EN_USB_CLKS 0x00040000
#define BM_CLKCTRL_PLL0CTRL0_POWER 0x00020000
-#define BP_CLKCTRL_PLL0CTRL0_RSRVD1 0
-#define BM_CLKCTRL_PLL0CTRL0_RSRVD1 0x0001FFFF
-#define BF_CLKCTRL_PLL0CTRL0_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_PLL0CTRL0_RSRVD1)
#define HW_CLKCTRL_PLL0CTRL1 (0x00000010)
#define BM_CLKCTRL_PLL0CTRL1_LOCK 0x80000000
#define BM_CLKCTRL_PLL0CTRL1_FORCE_LOCK 0x40000000
-#define BP_CLKCTRL_PLL0CTRL1_RSRVD1 16
-#define BM_CLKCTRL_PLL0CTRL1_RSRVD1 0x3FFF0000
-#define BF_CLKCTRL_PLL0CTRL1_RSRVD1(v) \
- (((v) << 16) & BM_CLKCTRL_PLL0CTRL1_RSRVD1)
#define BP_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0
#define BM_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0x0000FFFF
#define BF_CLKCTRL_PLL0CTRL1_LOCK_COUNT(v) \
@@ -94,7 +73,6 @@
#define HW_CLKCTRL_PLL1CTRL0_TOG (0x0000002c)
#define BM_CLKCTRL_PLL1CTRL0_CLKGATEEMI 0x80000000
-#define BM_CLKCTRL_PLL1CTRL0_RSRVD6 0x40000000
#define BP_CLKCTRL_PLL1CTRL0_LFR_SEL 28
#define BM_CLKCTRL_PLL1CTRL0_LFR_SEL 0x30000000
#define BF_CLKCTRL_PLL1CTRL0_LFR_SEL(v) \
@@ -103,10 +81,6 @@
#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLL1CTRL0_RSRVD5 26
-#define BM_CLKCTRL_PLL1CTRL0_RSRVD5 0x0C000000
-#define BF_CLKCTRL_PLL1CTRL0_RSRVD5(v) \
- (((v) << 26) & BM_CLKCTRL_PLL1CTRL0_RSRVD5)
#define BP_CLKCTRL_PLL1CTRL0_CP_SEL 24
#define BM_CLKCTRL_PLL1CTRL0_CP_SEL 0x03000000
#define BF_CLKCTRL_PLL1CTRL0_CP_SEL(v) \
@@ -115,10 +89,6 @@
#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_2 0x1
#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_05 0x2
#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__UNDEFINED 0x3
-#define BP_CLKCTRL_PLL1CTRL0_RSRVD4 22
-#define BM_CLKCTRL_PLL1CTRL0_RSRVD4 0x00C00000
-#define BF_CLKCTRL_PLL1CTRL0_RSRVD4(v) \
- (((v) << 22) & BM_CLKCTRL_PLL1CTRL0_RSRVD4)
#define BP_CLKCTRL_PLL1CTRL0_DIV_SEL 20
#define BM_CLKCTRL_PLL1CTRL0_DIV_SEL 0x00300000
#define BF_CLKCTRL_PLL1CTRL0_DIV_SEL(v) \
@@ -127,22 +97,13 @@
#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWER 0x1
#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWEST 0x2
#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__UNDEFINED 0x3
-#define BM_CLKCTRL_PLL1CTRL0_RSRVD3 0x00080000
#define BM_CLKCTRL_PLL1CTRL0_EN_USB_CLKS 0x00040000
#define BM_CLKCTRL_PLL1CTRL0_POWER 0x00020000
-#define BP_CLKCTRL_PLL1CTRL0_RSRVD1 0
-#define BM_CLKCTRL_PLL1CTRL0_RSRVD1 0x0001FFFF
-#define BF_CLKCTRL_PLL1CTRL0_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_PLL1CTRL0_RSRVD1)
#define HW_CLKCTRL_PLL1CTRL1 (0x00000030)
#define BM_CLKCTRL_PLL1CTRL1_LOCK 0x80000000
#define BM_CLKCTRL_PLL1CTRL1_FORCE_LOCK 0x40000000
-#define BP_CLKCTRL_PLL1CTRL1_RSRVD1 16
-#define BM_CLKCTRL_PLL1CTRL1_RSRVD1 0x3FFF0000
-#define BF_CLKCTRL_PLL1CTRL1_RSRVD1(v) \
- (((v) << 16) & BM_CLKCTRL_PLL1CTRL1_RSRVD1)
#define BP_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0
#define BM_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0x0000FFFF
#define BF_CLKCTRL_PLL1CTRL1_LOCK_COUNT(v) \
@@ -154,51 +115,31 @@
#define HW_CLKCTRL_PLL2CTRL0_TOG (0x0000004c)
#define BM_CLKCTRL_PLL2CTRL0_CLKGATE 0x80000000
-#define BM_CLKCTRL_PLL2CTRL0_RSRVD3 0x40000000
#define BP_CLKCTRL_PLL2CTRL0_LFR_SEL 28
#define BM_CLKCTRL_PLL2CTRL0_LFR_SEL 0x30000000
#define BF_CLKCTRL_PLL2CTRL0_LFR_SEL(v) \
(((v) << 28) & BM_CLKCTRL_PLL2CTRL0_LFR_SEL)
-#define BM_CLKCTRL_PLL2CTRL0_RSRVD2 0x08000000
#define BM_CLKCTRL_PLL2CTRL0_HOLD_RING_OFF_B 0x04000000
#define BP_CLKCTRL_PLL2CTRL0_CP_SEL 24
#define BM_CLKCTRL_PLL2CTRL0_CP_SEL 0x03000000
#define BF_CLKCTRL_PLL2CTRL0_CP_SEL(v) \
(((v) << 24) & BM_CLKCTRL_PLL2CTRL0_CP_SEL)
#define BM_CLKCTRL_PLL2CTRL0_POWER 0x00800000
-#define BP_CLKCTRL_PLL2CTRL0_RSRVD1 0
-#define BM_CLKCTRL_PLL2CTRL0_RSRVD1 0x007FFFFF
-#define BF_CLKCTRL_PLL2CTRL0_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_PLL2CTRL0_RSRVD1)
#define HW_CLKCTRL_CPU (0x00000050)
#define HW_CLKCTRL_CPU_SET (0x00000054)
#define HW_CLKCTRL_CPU_CLR (0x00000058)
#define HW_CLKCTRL_CPU_TOG (0x0000005c)
-#define BP_CLKCTRL_CPU_RSRVD5 30
-#define BM_CLKCTRL_CPU_RSRVD5 0xC0000000
-#define BF_CLKCTRL_CPU_RSRVD5(v) \
- (((v) << 30) & BM_CLKCTRL_CPU_RSRVD5)
#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000
#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000
-#define BM_CLKCTRL_CPU_RSRVD4 0x08000000
#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000
#define BP_CLKCTRL_CPU_DIV_XTAL 16
#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000
#define BF_CLKCTRL_CPU_DIV_XTAL(v) \
(((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL)
-#define BP_CLKCTRL_CPU_RSRVD3 13
-#define BM_CLKCTRL_CPU_RSRVD3 0x0000E000
-#define BF_CLKCTRL_CPU_RSRVD3(v) \
- (((v) << 13) & BM_CLKCTRL_CPU_RSRVD3)
#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000
-#define BM_CLKCTRL_CPU_RSRVD2 0x00000800
#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400
-#define BP_CLKCTRL_CPU_RSRVD1 6
-#define BM_CLKCTRL_CPU_RSRVD1 0x000003C0
-#define BF_CLKCTRL_CPU_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_CPU_RSRVD1)
#define BP_CLKCTRL_CPU_DIV_CPU 0
#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
#define BF_CLKCTRL_CPU_DIV_CPU(v) \
@@ -212,7 +153,6 @@
#define BM_CLKCTRL_HBUS_ASM_BUSY 0x80000000
#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x40000000
#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x20000000
-#define BM_CLKCTRL_HBUS_RSRVD2 0x10000000
#define BM_CLKCTRL_HBUS_ASM_EMIPORT_AS_ENABLE 0x08000000
#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000
#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000
@@ -232,10 +172,6 @@
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4
#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5
-#define BP_CLKCTRL_HBUS_RSRVD1 6
-#define BM_CLKCTRL_HBUS_RSRVD1 0x0000FFC0
-#define BF_CLKCTRL_HBUS_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_HBUS_RSRVD1)
#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020
#define BP_CLKCTRL_HBUS_DIV 0
#define BM_CLKCTRL_HBUS_DIV 0x0000001F
@@ -245,10 +181,6 @@
#define HW_CLKCTRL_XBUS (0x00000070)
#define BM_CLKCTRL_XBUS_BUSY 0x80000000
-#define BP_CLKCTRL_XBUS_RSRVD1 12
-#define BM_CLKCTRL_XBUS_RSRVD1 0x7FFFF000
-#define BF_CLKCTRL_XBUS_RSRVD1(v) \
- (((v) << 12) & BM_CLKCTRL_XBUS_RSRVD1)
#define BM_CLKCTRL_XBUS_AUTO_CLEAR_DIV_ENABLE 0x00000800
#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400
#define BP_CLKCTRL_XBUS_DIV 0
@@ -263,19 +195,10 @@
#define BP_CLKCTRL_XTAL_UART_CLK_GATE 31
#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000
-#define BM_CLKCTRL_XTAL_RSRVD3 0x40000000
#define BP_CLKCTRL_XTAL_PWM_CLK24M_GATE 29
#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000
-#define BP_CLKCTRL_XTAL_RSRVD2 27
-#define BM_CLKCTRL_XTAL_RSRVD2 0x18000000
-#define BF_CLKCTRL_XTAL_RSRVD2(v) \
- (((v) << 27) & BM_CLKCTRL_XTAL_RSRVD2)
#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26
#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000
-#define BP_CLKCTRL_XTAL_RSRVD1 2
-#define BM_CLKCTRL_XTAL_RSRVD1 0x03FFFFFC
-#define BF_CLKCTRL_XTAL_RSRVD1(v) \
- (((v) << 2) & BM_CLKCTRL_XTAL_RSRVD1)
#define BP_CLKCTRL_XTAL_DIV_UART 0
#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003
#define BF_CLKCTRL_XTAL_DIV_UART(v) \
@@ -285,12 +208,7 @@
#define BP_CLKCTRL_SSP0_CLKGATE 31
#define BM_CLKCTRL_SSP0_CLKGATE 0x80000000
-#define BM_CLKCTRL_SSP0_RSRVD2 0x40000000
#define BM_CLKCTRL_SSP0_BUSY 0x20000000
-#define BP_CLKCTRL_SSP0_RSRVD1 10
-#define BM_CLKCTRL_SSP0_RSRVD1 0x1FFFFC00
-#define BF_CLKCTRL_SSP0_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_SSP0_RSRVD1)
#define BM_CLKCTRL_SSP0_DIV_FRAC_EN 0x00000200
#define BP_CLKCTRL_SSP0_DIV 0
#define BM_CLKCTRL_SSP0_DIV 0x000001FF
@@ -301,12 +219,7 @@
#define BP_CLKCTRL_SSP1_CLKGATE 31
#define BM_CLKCTRL_SSP1_CLKGATE 0x80000000
-#define BM_CLKCTRL_SSP1_RSRVD2 0x40000000
#define BM_CLKCTRL_SSP1_BUSY 0x20000000
-#define BP_CLKCTRL_SSP1_RSRVD1 10
-#define BM_CLKCTRL_SSP1_RSRVD1 0x1FFFFC00
-#define BF_CLKCTRL_SSP1_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_SSP1_RSRVD1)
#define BM_CLKCTRL_SSP1_DIV_FRAC_EN 0x00000200
#define BP_CLKCTRL_SSP1_DIV 0
#define BM_CLKCTRL_SSP1_DIV 0x000001FF
@@ -317,12 +230,7 @@
#define BP_CLKCTRL_SSP2_CLKGATE 31
#define BM_CLKCTRL_SSP2_CLKGATE 0x80000000
-#define BM_CLKCTRL_SSP2_RSRVD2 0x40000000
#define BM_CLKCTRL_SSP2_BUSY 0x20000000
-#define BP_CLKCTRL_SSP2_RSRVD1 10
-#define BM_CLKCTRL_SSP2_RSRVD1 0x1FFFFC00
-#define BF_CLKCTRL_SSP2_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_SSP2_RSRVD1)
#define BM_CLKCTRL_SSP2_DIV_FRAC_EN 0x00000200
#define BP_CLKCTRL_SSP2_DIV 0
#define BM_CLKCTRL_SSP2_DIV 0x000001FF
@@ -333,12 +241,7 @@
#define BP_CLKCTRL_SSP3_CLKGATE 31
#define BM_CLKCTRL_SSP3_CLKGATE 0x80000000
-#define BM_CLKCTRL_SSP3_RSRVD2 0x40000000
#define BM_CLKCTRL_SSP3_BUSY 0x20000000
-#define BP_CLKCTRL_SSP3_RSRVD1 10
-#define BM_CLKCTRL_SSP3_RSRVD1 0x1FFFFC00
-#define BF_CLKCTRL_SSP3_RSRVD1(v) \
- (((v) << 10) & BM_CLKCTRL_SSP3_RSRVD1)
#define BM_CLKCTRL_SSP3_DIV_FRAC_EN 0x00000200
#define BP_CLKCTRL_SSP3_DIV 0
#define BM_CLKCTRL_SSP3_DIV 0x000001FF
@@ -349,12 +252,7 @@
#define BP_CLKCTRL_GPMI_CLKGATE 31
#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000
-#define BM_CLKCTRL_GPMI_RSRVD2 0x40000000
#define BM_CLKCTRL_GPMI_BUSY 0x20000000
-#define BP_CLKCTRL_GPMI_RSRVD1 11
-#define BM_CLKCTRL_GPMI_RSRVD1 0x1FFFF800
-#define BF_CLKCTRL_GPMI_RSRVD1(v) \
- (((v) << 11) & BM_CLKCTRL_GPMI_RSRVD1)
#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400
#define BP_CLKCTRL_GPMI_DIV 0
#define BM_CLKCTRL_GPMI_DIV 0x000003FF
@@ -365,10 +263,6 @@
#define BP_CLKCTRL_SPDIF_CLKGATE 31
#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000
-#define BP_CLKCTRL_SPDIF_RSRVD 0
-#define BM_CLKCTRL_SPDIF_RSRVD 0x7FFFFFFF
-#define BF_CLKCTRL_SPDIF_RSRVD(v) \
- (((v) << 0) & BM_CLKCTRL_SPDIF_RSRVD)
#define HW_CLKCTRL_EMI (0x000000f0)
@@ -379,24 +273,12 @@
#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000
#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000
#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000
-#define BP_CLKCTRL_EMI_RSRVD3 18
-#define BM_CLKCTRL_EMI_RSRVD3 0x03FC0000
-#define BF_CLKCTRL_EMI_RSRVD3(v) \
- (((v) << 18) & BM_CLKCTRL_EMI_RSRVD3)
#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000
#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000
-#define BP_CLKCTRL_EMI_RSRVD2 12
-#define BM_CLKCTRL_EMI_RSRVD2 0x0000F000
-#define BF_CLKCTRL_EMI_RSRVD2(v) \
- (((v) << 12) & BM_CLKCTRL_EMI_RSRVD2)
#define BP_CLKCTRL_EMI_DIV_XTAL 8
#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00
#define BF_CLKCTRL_EMI_DIV_XTAL(v) \
(((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL)
-#define BP_CLKCTRL_EMI_RSRVD1 6
-#define BM_CLKCTRL_EMI_RSRVD1 0x000000C0
-#define BF_CLKCTRL_EMI_RSRVD1(v) \
- (((v) << 6) & BM_CLKCTRL_EMI_RSRVD1)
#define BP_CLKCTRL_EMI_DIV_EMI 0
#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F
#define BF_CLKCTRL_EMI_DIV_EMI(v) \
@@ -406,12 +288,7 @@
#define BP_CLKCTRL_SAIF0_CLKGATE 31
#define BM_CLKCTRL_SAIF0_CLKGATE 0x80000000
-#define BM_CLKCTRL_SAIF0_RSRVD2 0x40000000
#define BM_CLKCTRL_SAIF0_BUSY 0x20000000
-#define BP_CLKCTRL_SAIF0_RSRVD1 17
-#define BM_CLKCTRL_SAIF0_RSRVD1 0x1FFE0000
-#define BF_CLKCTRL_SAIF0_RSRVD1(v) \
- (((v) << 17) & BM_CLKCTRL_SAIF0_RSRVD1)
#define BM_CLKCTRL_SAIF0_DIV_FRAC_EN 0x00010000
#define BP_CLKCTRL_SAIF0_DIV 0
#define BM_CLKCTRL_SAIF0_DIV 0x0000FFFF
@@ -422,12 +299,7 @@
#define BP_CLKCTRL_SAIF1_CLKGATE 31
#define BM_CLKCTRL_SAIF1_CLKGATE 0x80000000
-#define BM_CLKCTRL_SAIF1_RSRVD2 0x40000000
#define BM_CLKCTRL_SAIF1_BUSY 0x20000000
-#define BP_CLKCTRL_SAIF1_RSRVD1 17
-#define BM_CLKCTRL_SAIF1_RSRVD1 0x1FFE0000
-#define BF_CLKCTRL_SAIF1_RSRVD1(v) \
- (((v) << 17) & BM_CLKCTRL_SAIF1_RSRVD1)
#define BM_CLKCTRL_SAIF1_DIV_FRAC_EN 0x00010000
#define BP_CLKCTRL_SAIF1_DIV 0
#define BM_CLKCTRL_SAIF1_DIV 0x0000FFFF
@@ -438,12 +310,7 @@
#define BP_CLKCTRL_DIS_LCDIF_CLKGATE 31
#define BM_CLKCTRL_DIS_LCDIF_CLKGATE 0x80000000
-#define BM_CLKCTRL_DIS_LCDIF_RSRVD2 0x40000000
#define BM_CLKCTRL_DIS_LCDIF_BUSY 0x20000000
-#define BP_CLKCTRL_DIS_LCDIF_RSRVD1 14
-#define BM_CLKCTRL_DIS_LCDIF_RSRVD1 0x1FFFC000
-#define BF_CLKCTRL_DIS_LCDIF_RSRVD1(v) \
- (((v) << 14) & BM_CLKCTRL_DIS_LCDIF_RSRVD1)
#define BM_CLKCTRL_DIS_LCDIF_DIV_FRAC_EN 0x00002000
#define BP_CLKCTRL_DIS_LCDIF_DIV 0
#define BM_CLKCTRL_DIS_LCDIF_DIV 0x00001FFF
@@ -453,12 +320,7 @@
#define HW_CLKCTRL_ETM (0x00000130)
#define BM_CLKCTRL_ETM_CLKGATE 0x80000000
-#define BM_CLKCTRL_ETM_RSRVD2 0x40000000
#define BM_CLKCTRL_ETM_BUSY 0x20000000
-#define BP_CLKCTRL_ETM_RSRVD1 8
-#define BM_CLKCTRL_ETM_RSRVD1 0x1FFFFF00
-#define BF_CLKCTRL_ETM_RSRVD1(v) \
- (((v) << 8) & BM_CLKCTRL_ETM_RSRVD1)
#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000080
#define BP_CLKCTRL_ETM_DIV 0
#define BM_CLKCTRL_ETM_DIV 0x0000007F
@@ -471,7 +333,6 @@
#define BP_CLKCTRL_ENET_DISABLE 30
#define BM_CLKCTRL_ENET_DISABLE 0x40000000
#define BM_CLKCTRL_ENET_STATUS 0x20000000
-#define BM_CLKCTRL_ENET_RSRVD1 0x10000000
#define BM_CLKCTRL_ENET_BUSY_TIME 0x08000000
#define BP_CLKCTRL_ENET_DIV_TIME 21
#define BM_CLKCTRL_ENET_DIV_TIME 0x07E00000
@@ -493,37 +354,23 @@
#define BM_CLKCTRL_ENET_CLK_OUT_EN 0x00040000
#define BM_CLKCTRL_ENET_RESET_BY_SW_CHIP 0x00020000
#define BM_CLKCTRL_ENET_RESET_BY_SW 0x00010000
-#define BP_CLKCTRL_ENET_RSRVD0 0
-#define BM_CLKCTRL_ENET_RSRVD0 0x0000FFFF
-#define BF_CLKCTRL_ENET_RSRVD0(v) \
- (((v) << 0) & BM_CLKCTRL_ENET_RSRVD0)
#define HW_CLKCTRL_HSADC (0x00000150)
-#define BM_CLKCTRL_HSADC_RSRVD2 0x80000000
#define BM_CLKCTRL_HSADC_RESETB 0x40000000
#define BP_CLKCTRL_HSADC_FREQDIV 28
#define BM_CLKCTRL_HSADC_FREQDIV 0x30000000
#define BF_CLKCTRL_HSADC_FREQDIV(v) \
(((v) << 28) & BM_CLKCTRL_HSADC_FREQDIV)
-#define BP_CLKCTRL_HSADC_RSRVD1 0
-#define BM_CLKCTRL_HSADC_RSRVD1 0x0FFFFFFF
-#define BF_CLKCTRL_HSADC_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_HSADC_RSRVD1)
#define HW_CLKCTRL_FLEXCAN (0x00000160)
-#define BM_CLKCTRL_FLEXCAN_RSRVD2 0x80000000
#define BP_CLKCTRL_FLEXCAN_STOP_CAN0 30
#define BM_CLKCTRL_FLEXCAN_STOP_CAN0 0x40000000
#define BM_CLKCTRL_FLEXCAN_CAN0_STATUS 0x20000000
#define BP_CLKCTRL_FLEXCAN_STOP_CAN1 28
#define BM_CLKCTRL_FLEXCAN_STOP_CAN1 0x10000000
#define BM_CLKCTRL_FLEXCAN_CAN1_STATUS 0x08000000
-#define BP_CLKCTRL_FLEXCAN_RSRVD1 0
-#define BM_CLKCTRL_FLEXCAN_RSRVD1 0x07FFFFFF
-#define BF_CLKCTRL_FLEXCAN_RSRVD1(v) \
- (((v) << 0) & BM_CLKCTRL_FLEXCAN_RSRVD1)
#define HW_CLKCTRL_FRAC0 (0x000001b0)
#define HW_CLKCTRL_FRAC0_SET (0x000001b4)
@@ -564,10 +411,6 @@
#define HW_CLKCTRL_FRAC1_CLR (0x000001c8)
#define HW_CLKCTRL_FRAC1_TOG (0x000001cc)
-#define BP_CLKCTRL_FRAC1_RSRVD2 24
-#define BM_CLKCTRL_FRAC1_RSRVD2 0xFF000000
-#define BF_CLKCTRL_FRAC1_RSRVD2(v) \
- (((v) << 24) & BM_CLKCTRL_FRAC1_RSRVD2)
#define BP_CLKCTRL_FRAC1_CLKGATEGPMI 23
#define BM_CLKCTRL_FRAC1_CLKGATEGPMI 0x00800000
#define BM_CLKCTRL_FRAC1_GPMI_STABLE 0x00400000
@@ -595,22 +438,10 @@
#define HW_CLKCTRL_CLKSEQ_CLR (0x000001d8)
#define HW_CLKCTRL_CLKSEQ_TOG (0x000001dc)
-#define BP_CLKCTRL_CLKSEQ_RSRVD0 19
-#define BM_CLKCTRL_CLKSEQ_RSRVD0 0xFFF80000
-#define BF_CLKCTRL_CLKSEQ_RSRVD0(v) \
- (((v) << 19) & BM_CLKCTRL_CLKSEQ_RSRVD0)
#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00040000
-#define BP_CLKCTRL_CLKSEQ_RSRVD1 15
-#define BM_CLKCTRL_CLKSEQ_RSRVD1 0x00038000
-#define BF_CLKCTRL_CLKSEQ_RSRVD1(v) \
- (((v) << 15) & BM_CLKCTRL_CLKSEQ_RSRVD1)
#define BM_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF 0x00004000
#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__BYPASS 0x1
#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__PFD 0x0
-#define BP_CLKCTRL_CLKSEQ_RSRVD2 9
-#define BM_CLKCTRL_CLKSEQ_RSRVD2 0x00003E00
-#define BF_CLKCTRL_CLKSEQ_RSRVD2(v) \
- (((v) << 9) & BM_CLKCTRL_CLKSEQ_RSRVD2)
#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100
#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000080
#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP3 0x00000040
@@ -623,10 +454,6 @@
#define HW_CLKCTRL_RESET (0x000001e0)
-#define BP_CLKCTRL_RESET_RSRVD 6
-#define BM_CLKCTRL_RESET_RSRVD 0xFFFFFFC0
-#define BF_CLKCTRL_RESET_RSRVD(v) \
- (((v) << 6) & BM_CLKCTRL_RESET_RSRVD)
#define BM_CLKCTRL_RESET_WDOG_POR_DISABLE 0x00000020
#define BM_CLKCTRL_RESET_EXTERNAL_RESET_ENABLE 0x00000010
#define BM_CLKCTRL_RESET_THERMAL_RESET_ENABLE 0x00000008
@@ -640,10 +467,6 @@
#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000
#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \
(((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT)
-#define BP_CLKCTRL_STATUS_RSRVD 0
-#define BM_CLKCTRL_STATUS_RSRVD 0x3FFFFFFF
-#define BF_CLKCTRL_STATUS_RSRVD(v) \
- (((v) << 0) & BM_CLKCTRL_STATUS_RSRVD)
#define HW_CLKCTRL_VERSION (0x00000200)
diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c
index 9343d7edd4f6..20ec3bddf7cd 100644
--- a/arch/arm/mach-mxs/system.c
+++ b/arch/arm/mach-mxs/system.c
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/proc-fns.h>
#include <asm/system.h>
@@ -135,3 +136,4 @@ error:
pr_err("%s(%p): module reset timeout\n", __func__, reset_addr);
return -ETIMEDOUT;
}
+EXPORT_SYMBOL(mxs_reset_block);
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index ba6009f27677..af98117043d2 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -4,7 +4,7 @@
# Common support
obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
-obj-y += clock.o clock_data.o opp_data.o
+obj-y += clock.o clock_data.o opp_data.o reset.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index 22cc8c8df6cb..de88c9297b68 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -165,7 +165,7 @@ static struct map_desc ams_delta_io_desc[] __initdata = {
}
};
-static struct omap_lcd_config ams_delta_lcd_config __initdata = {
+static struct omap_lcd_config ams_delta_lcd_config = {
.ctrl_name = "internal",
};
@@ -175,7 +175,7 @@ static struct omap_usb_config ams_delta_usb_config __initdata = {
.pins[0] = 2,
};
-static struct omap_board_config_kernel ams_delta_config[] = {
+static struct omap_board_config_kernel ams_delta_config[] __initdata = {
{ OMAP_TAG_LCD, &ams_delta_lcd_config },
};
@@ -208,14 +208,14 @@ static const struct matrix_keymap_data ams_delta_keymap_data = {
.keymap_size = ARRAY_SIZE(ams_delta_keymap),
};
-static struct omap_kp_platform_data ams_delta_kp_data = {
+static struct omap_kp_platform_data ams_delta_kp_data __initdata = {
.rows = 8,
.cols = 8,
.keymap_data = &ams_delta_keymap_data,
.delay = 9,
};
-static struct platform_device ams_delta_kp_device = {
+static struct platform_device ams_delta_kp_device __initdata = {
.name = "omap-keypad",
.id = -1,
.dev = {
@@ -225,12 +225,12 @@ static struct platform_device ams_delta_kp_device = {
.resource = ams_delta_kp_resources,
};
-static struct platform_device ams_delta_lcd_device = {
+static struct platform_device ams_delta_lcd_device __initdata = {
.name = "lcd_ams_delta",
.id = -1,
};
-static struct platform_device ams_delta_led_device = {
+static struct platform_device ams_delta_led_device __initdata = {
.name = "ams-delta-led",
.id = -1
};
@@ -259,7 +259,7 @@ static int ams_delta_camera_power(struct device *dev, int power)
#define ams_delta_camera_power NULL
#endif
-static struct soc_camera_link __initdata ams_delta_iclink = {
+static struct soc_camera_link ams_delta_iclink = {
.bus_id = 0, /* OMAP1 SoC camera bus */
.i2c_adapter_id = 1,
.board_info = &ams_delta_camera_board_info[0],
@@ -267,7 +267,7 @@ static struct soc_camera_link __initdata ams_delta_iclink = {
.power = ams_delta_camera_power,
};
-static struct platform_device ams_delta_camera_device = {
+static struct platform_device ams_delta_camera_device __initdata = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 0efb9dbae44c..87f173d93557 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -287,11 +287,11 @@ static struct platform_device *devices[] __initdata = {
&lcd_device,
};
-static struct omap_lcd_config fsample_lcd_config __initdata = {
+static struct omap_lcd_config fsample_lcd_config = {
.ctrl_name = "internal",
};
-static struct omap_board_config_kernel fsample_config[] = {
+static struct omap_board_config_kernel fsample_config[] __initdata = {
{ OMAP_TAG_LCD, &fsample_lcd_config },
};
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 28b84aa9bdba..ba3bd09c4754 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -202,7 +202,7 @@ static int h2_nand_dev_ready(struct mtd_info *mtd)
static const char *h2_part_probes[] = { "cmdlinepart", NULL };
-struct platform_nand_data h2_nand_platdata = {
+static struct platform_nand_data h2_nand_platdata = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index dbc8b8d882ba..ac48677672ee 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -204,7 +204,7 @@ static int nand_dev_ready(struct mtd_info *mtd)
static const char *part_probes[] = { "cmdlinepart", NULL };
-struct platform_nand_data nand_platdata = {
+static struct platform_nand_data nand_platdata = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c
index f2c5c585bc83..ba05a51f9408 100644
--- a/arch/arm/mach-omap1/board-htcherald.c
+++ b/arch/arm/mach-omap1/board-htcherald.c
@@ -331,7 +331,7 @@ static struct resource htcpld_resources[] = {
},
};
-struct htcpld_chip_platform_data htcpld_chips[] = {
+static struct htcpld_chip_platform_data htcpld_chips[] = {
[0] = {
.addr = 0x03,
.reset = 0x04,
@@ -366,7 +366,7 @@ struct htcpld_chip_platform_data htcpld_chips[] = {
},
};
-struct htcpld_core_platform_data htcpld_pfdata = {
+static struct htcpld_core_platform_data htcpld_pfdata = {
.int_reset_gpio_hi = HTCPLD_GPIO_INT_RESET_HI,
.int_reset_gpio_lo = HTCPLD_GPIO_INT_RESET_LO,
.i2c_adapter_id = 1,
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index a36e6742bf9b..2d9b8cbd7a14 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -365,7 +365,7 @@ static struct omap_mmc_platform_data mmc1_data = {
static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC];
-void __init innovator_mmc_init(void)
+static void __init innovator_mmc_init(void)
{
mmc_data[0] = &mmc1_data;
omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC);
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index d21f09dc78f4..cfd084926146 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -115,7 +115,7 @@ static struct mipid_platform_data nokia770_mipid_platform_data = {
.shutdown = mipid_shutdown,
};
-static void mipid_dev_init(void)
+static void __init mipid_dev_init(void)
{
const struct omap_lcd_config *conf;
@@ -126,7 +126,7 @@ static void mipid_dev_init(void)
}
}
-static void ads7846_dev_init(void)
+static void __init ads7846_dev_init(void)
{
if (gpio_request(ADS7846_PENDOWN_GPIO, "ADS7846 pendown") < 0)
printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
@@ -170,7 +170,7 @@ static struct hwa742_platform_data nokia770_hwa742_platform_data = {
.te_connected = 1,
};
-static void hwa742_dev_init(void)
+static void __init hwa742_dev_init(void)
{
clk_add_alias("hwa_sys_ck", NULL, "bclk", NULL);
omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index fb51ce6123d8..c9d38f47845f 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -230,19 +230,6 @@ static struct spi_board_info palmte_spi_info[] __initdata = {
},
};
-static void palmte_headphones_detect(void *data, int state)
-{
- if (state) {
- /* Headphones connected, disable speaker */
- gpio_set_value(PALMTE_SPEAKER_GPIO, 0);
- printk(KERN_INFO "PM: speaker off\n");
- } else {
- /* Headphones unplugged, re-enable speaker */
- gpio_set_value(PALMTE_SPEAKER_GPIO, 1);
- printk(KERN_INFO "PM: speaker on\n");
- }
-}
-
static void __init palmte_misc_gpio_setup(void)
{
/* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 815a69ce821d..bdc0ac8dc21f 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -26,10 +26,12 @@
#include <linux/smc91x.h>
#include <mach/hardware.h>
+#include <mach/system.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <plat/board-voiceblue.h>
#include <plat/common.h>
#include <mach/gpio.h>
#include <plat/flash.h>
@@ -163,52 +165,6 @@ static void __init voiceblue_init_irq(void)
omap_init_irq();
}
-static void __init voiceblue_init(void)
-{
- /* mux pins for uarts */
- omap_cfg_reg(UART1_TX);
- omap_cfg_reg(UART1_RTS);
- omap_cfg_reg(UART2_TX);
- omap_cfg_reg(UART2_RTS);
- omap_cfg_reg(UART3_TX);
- omap_cfg_reg(UART3_RX);
-
- /* Watchdog */
- gpio_request(0, "Watchdog");
- /* smc91x reset */
- gpio_request(7, "SMC91x reset");
- gpio_direction_output(7, 1);
- udelay(2); /* wait at least 100ns */
- gpio_set_value(7, 0);
- mdelay(50); /* 50ms until PHY ready */
- /* smc91x interrupt pin */
- gpio_request(8, "SMC91x irq");
- /* 16C554 reset*/
- gpio_request(6, "16C554 reset");
- gpio_direction_output(6, 0);
- /* 16C554 interrupt pins */
- gpio_request(12, "16C554 irq");
- gpio_request(13, "16C554 irq");
- gpio_request(14, "16C554 irq");
- gpio_request(15, "16C554 irq");
- set_irq_type(gpio_to_irq(12), IRQ_TYPE_EDGE_RISING);
- set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
- set_irq_type(gpio_to_irq(14), IRQ_TYPE_EDGE_RISING);
- set_irq_type(gpio_to_irq(15), IRQ_TYPE_EDGE_RISING);
-
- platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
- omap_board_config = voiceblue_config;
- omap_board_config_size = ARRAY_SIZE(voiceblue_config);
- omap_serial_init();
- omap1_usb_init(&voiceblue_usb_config);
- omap_register_i2c_bus(1, 100, NULL, 0);
-
- /* There is a good chance board is going up, so enable power LED
- * (it is connected through invertor) */
- omap_writeb(0x00, OMAP_LPG1_LCR);
- omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */
-}
-
static void __init voiceblue_map_io(void)
{
omap1_map_common_io();
@@ -275,8 +231,17 @@ void voiceblue_wdt_ping(void)
gpio_set_value(0, wdt_gpio_state);
}
-void voiceblue_reset(void)
+static void voiceblue_reset(char mode, const char *cmd)
{
+ /*
+ * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
+ * "Global Software Reset Affects Traffic Controller Frequency".
+ */
+ if (cpu_is_omap5912()) {
+ omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4), DPLL_CTL);
+ omap_writew(0x8, ARM_RSTCT1);
+ }
+
set_bit(MACHINE_REBOOT, &machine_state);
voiceblue_wdt_enable();
while (1) ;
@@ -286,6 +251,54 @@ EXPORT_SYMBOL(voiceblue_wdt_enable);
EXPORT_SYMBOL(voiceblue_wdt_disable);
EXPORT_SYMBOL(voiceblue_wdt_ping);
+static void __init voiceblue_init(void)
+{
+ /* mux pins for uarts */
+ omap_cfg_reg(UART1_TX);
+ omap_cfg_reg(UART1_RTS);
+ omap_cfg_reg(UART2_TX);
+ omap_cfg_reg(UART2_RTS);
+ omap_cfg_reg(UART3_TX);
+ omap_cfg_reg(UART3_RX);
+
+ /* Watchdog */
+ gpio_request(0, "Watchdog");
+ /* smc91x reset */
+ gpio_request(7, "SMC91x reset");
+ gpio_direction_output(7, 1);
+ udelay(2); /* wait at least 100ns */
+ gpio_set_value(7, 0);
+ mdelay(50); /* 50ms until PHY ready */
+ /* smc91x interrupt pin */
+ gpio_request(8, "SMC91x irq");
+ /* 16C554 reset*/
+ gpio_request(6, "16C554 reset");
+ gpio_direction_output(6, 0);
+ /* 16C554 interrupt pins */
+ gpio_request(12, "16C554 irq");
+ gpio_request(13, "16C554 irq");
+ gpio_request(14, "16C554 irq");
+ gpio_request(15, "16C554 irq");
+ set_irq_type(gpio_to_irq(12), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(gpio_to_irq(14), IRQ_TYPE_EDGE_RISING);
+ set_irq_type(gpio_to_irq(15), IRQ_TYPE_EDGE_RISING);
+
+ platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
+ omap_board_config = voiceblue_config;
+ omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+ omap_serial_init();
+ omap1_usb_init(&voiceblue_usb_config);
+ omap_register_i2c_bus(1, 100, NULL, 0);
+
+ /* There is a good chance board is going up, so enable power LED
+ * (it is connected through invertor) */
+ omap_writeb(0x00, OMAP_LPG1_LCR);
+ omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */
+
+ arch_reset = voiceblue_reset;
+}
+
MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
/* Maintainer: Ladislav Michl <michl@2n.cz> */
.boot_params = 0x10000100,
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
index 820973666f34..d9af9811dedd 100644
--- a/arch/arm/mach-omap1/mcbsp.c
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -10,6 +10,7 @@
*
* Multichannel mode not supported.
*/
+#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
@@ -78,100 +79,294 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
};
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+struct resource omap7xx_mcbsp_res[][6] = {
+ {
+ {
+ .start = OMAP7XX_MCBSP1_BASE,
+ .end = OMAP7XX_MCBSP1_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_7XX_McBSP1RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_7XX_McBSP1TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP7XX_MCBSP2_BASE,
+ .end = OMAP7XX_MCBSP2_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_7XX_McBSP2RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_7XX_McBSP2TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP3_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP3_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+};
+
+#define omap7xx_mcbsp_res_0 omap7xx_mcbsp_res[0]
+
static struct omap_mcbsp_platform_data omap7xx_mcbsp_pdata[] = {
{
- .phys_base = OMAP7XX_MCBSP1_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
- .rx_irq = INT_7XX_McBSP1RX,
- .tx_irq = INT_7XX_McBSP1TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP7XX_MCBSP2_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
- .rx_irq = INT_7XX_McBSP2RX,
- .tx_irq = INT_7XX_McBSP2TX,
.ops = &omap1_mcbsp_ops,
},
};
-#define OMAP7XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap7xx_mcbsp_pdata)
-#define OMAP7XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1)
+#define OMAP7XX_MCBSP_RES_SZ ARRAY_SIZE(omap7xx_mcbsp_res[1])
+#define OMAP7XX_MCBSP_COUNT ARRAY_SIZE(omap7xx_mcbsp_res)
#else
+#define omap7xx_mcbsp_res_0 NULL
#define omap7xx_mcbsp_pdata NULL
-#define OMAP7XX_MCBSP_PDATA_SZ 0
-#define OMAP7XX_MCBSP_REG_NUM 0
+#define OMAP7XX_MCBSP_RES_SZ 0
+#define OMAP7XX_MCBSP_COUNT 0
#endif
#ifdef CONFIG_ARCH_OMAP15XX
+struct resource omap15xx_mcbsp_res[][6] = {
+ {
+ {
+ .start = OMAP1510_MCBSP1_BASE,
+ .end = OMAP1510_MCBSP1_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP1RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP1TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1510_MCBSP2_BASE,
+ .end = OMAP1510_MCBSP2_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_1510_SPI_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_1510_SPI_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP2_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1510_MCBSP3_BASE,
+ .end = OMAP1510_MCBSP3_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP3RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP3TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP3_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP3_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+};
+
+#define omap15xx_mcbsp_res_0 omap15xx_mcbsp_res[0]
+
static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
{
- .phys_base = OMAP1510_MCBSP1_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
- .rx_irq = INT_McBSP1RX,
- .tx_irq = INT_McBSP1TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP1510_MCBSP2_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
- .rx_irq = INT_1510_SPI_RX,
- .tx_irq = INT_1510_SPI_TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP1510_MCBSP3_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
- .rx_irq = INT_McBSP3RX,
- .tx_irq = INT_McBSP3TX,
.ops = &omap1_mcbsp_ops,
},
};
-#define OMAP15XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap15xx_mcbsp_pdata)
-#define OMAP15XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1)
+#define OMAP15XX_MCBSP_RES_SZ ARRAY_SIZE(omap15xx_mcbsp_res[1])
+#define OMAP15XX_MCBSP_COUNT ARRAY_SIZE(omap15xx_mcbsp_res)
#else
+#define omap15xx_mcbsp_res_0 NULL
#define omap15xx_mcbsp_pdata NULL
-#define OMAP15XX_MCBSP_PDATA_SZ 0
-#define OMAP15XX_MCBSP_REG_NUM 0
+#define OMAP15XX_MCBSP_RES_SZ 0
+#define OMAP15XX_MCBSP_COUNT 0
#endif
#ifdef CONFIG_ARCH_OMAP16XX
+struct resource omap16xx_mcbsp_res[][6] = {
+ {
+ {
+ .start = OMAP1610_MCBSP1_BASE,
+ .end = OMAP1610_MCBSP1_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP1RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP1TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1610_MCBSP2_BASE,
+ .end = OMAP1610_MCBSP2_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_1610_McBSP2_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_1610_McBSP2_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP2_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1610_MCBSP3_BASE,
+ .end = OMAP1610_MCBSP3_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP3RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP3TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = OMAP_DMA_MCBSP3_RX,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = OMAP_DMA_MCBSP3_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+};
+
+#define omap16xx_mcbsp_res_0 omap16xx_mcbsp_res[0]
+
static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
{
- .phys_base = OMAP1610_MCBSP1_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
- .rx_irq = INT_McBSP1RX,
- .tx_irq = INT_McBSP1TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP1610_MCBSP2_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
- .rx_irq = INT_1610_McBSP2_RX,
- .tx_irq = INT_1610_McBSP2_TX,
.ops = &omap1_mcbsp_ops,
},
{
- .phys_base = OMAP1610_MCBSP3_BASE,
- .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
- .rx_irq = INT_McBSP3RX,
- .tx_irq = INT_McBSP3TX,
.ops = &omap1_mcbsp_ops,
},
};
-#define OMAP16XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap16xx_mcbsp_pdata)
-#define OMAP16XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_XCERH / sizeof(u16) + 1)
+#define OMAP16XX_MCBSP_RES_SZ ARRAY_SIZE(omap16xx_mcbsp_res[1])
+#define OMAP16XX_MCBSP_COUNT ARRAY_SIZE(omap16xx_mcbsp_res)
#else
+#define omap16xx_mcbsp_res_0 NULL
#define omap16xx_mcbsp_pdata NULL
-#define OMAP16XX_MCBSP_PDATA_SZ 0
-#define OMAP16XX_MCBSP_REG_NUM 0
+#define OMAP16XX_MCBSP_RES_SZ 0
+#define OMAP16XX_MCBSP_COUNT 0
#endif
static int __init omap1_mcbsp_init(void)
@@ -179,16 +374,12 @@ static int __init omap1_mcbsp_init(void)
if (!cpu_class_is_omap1())
return -ENODEV;
- if (cpu_is_omap7xx()) {
- omap_mcbsp_count = OMAP7XX_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP7XX_MCBSP_REG_NUM * sizeof(u16);
- } else if (cpu_is_omap15xx()) {
- omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP15XX_MCBSP_REG_NUM * sizeof(u16);
- } else if (cpu_is_omap16xx()) {
- omap_mcbsp_count = OMAP16XX_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP16XX_MCBSP_REG_NUM * sizeof(u16);
- }
+ if (cpu_is_omap7xx())
+ omap_mcbsp_count = OMAP7XX_MCBSP_COUNT;
+ else if (cpu_is_omap15xx())
+ omap_mcbsp_count = OMAP15XX_MCBSP_COUNT;
+ else if (cpu_is_omap16xx())
+ omap_mcbsp_count = OMAP16XX_MCBSP_COUNT;
mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
GFP_KERNEL);
@@ -196,16 +387,22 @@ static int __init omap1_mcbsp_init(void)
return -ENOMEM;
if (cpu_is_omap7xx())
- omap_mcbsp_register_board_cfg(omap7xx_mcbsp_pdata,
- OMAP7XX_MCBSP_PDATA_SZ);
+ omap_mcbsp_register_board_cfg(omap7xx_mcbsp_res_0,
+ OMAP7XX_MCBSP_RES_SZ,
+ omap7xx_mcbsp_pdata,
+ OMAP7XX_MCBSP_COUNT);
if (cpu_is_omap15xx())
- omap_mcbsp_register_board_cfg(omap15xx_mcbsp_pdata,
- OMAP15XX_MCBSP_PDATA_SZ);
+ omap_mcbsp_register_board_cfg(omap15xx_mcbsp_res_0,
+ OMAP15XX_MCBSP_RES_SZ,
+ omap15xx_mcbsp_pdata,
+ OMAP15XX_MCBSP_COUNT);
if (cpu_is_omap16xx())
- omap_mcbsp_register_board_cfg(omap16xx_mcbsp_pdata,
- OMAP16XX_MCBSP_PDATA_SZ);
+ omap_mcbsp_register_board_cfg(omap16xx_mcbsp_res_0,
+ OMAP16XX_MCBSP_RES_SZ,
+ omap16xx_mcbsp_pdata,
+ OMAP16XX_MCBSP_COUNT);
return omap_mcbsp_init();
}
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
new file mode 100644
index 000000000000..ad951ee69205
--- /dev/null
+++ b/arch/arm/mach-omap1/reset.c
@@ -0,0 +1,25 @@
+/*
+ * OMAP1 reset support
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/system.h>
+#include <plat/prcm.h>
+
+void omap1_arch_reset(char mode, const char *cmd)
+{
+ /*
+ * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
+ * "Global Software Reset Affects Traffic Controller Frequency".
+ */
+ if (cpu_is_omap5912()) {
+ omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4), DPLL_CTL);
+ omap_writew(0x8, ARM_RSTCT1);
+ }
+
+ omap_writew(1, ARM_RSTCT1);
+}
+
+void (*arch_reset)(char, const char *) = omap1_arch_reset;
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index b69fa0a0299e..eeab35dea07e 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -54,25 +54,30 @@ config ARCH_OMAP4
comment "OMAP Core Type"
depends on ARCH_OMAP2
-config ARCH_OMAP2420
+config SOC_OMAP2420
bool "OMAP2420 support"
depends on ARCH_OMAP2
default y
select OMAP_DM_TIMER
select ARCH_OMAP_OTG
-config ARCH_OMAP2430
+config SOC_OMAP2430
bool "OMAP2430 support"
depends on ARCH_OMAP2
default y
select ARCH_OMAP_OTG
-config ARCH_OMAP3430
+config SOC_OMAP3430
bool "OMAP3430 support"
depends on ARCH_OMAP3
default y
select ARCH_OMAP_OTG
+config SOC_OMAPTI816X
+ bool "TI816X support"
+ depends on ARCH_OMAP3
+ default y
+
config OMAP_PACKAGE_ZAF
bool
@@ -107,25 +112,25 @@ config MACH_OMAP_GENERIC
config MACH_OMAP2_TUSB6010
bool
- depends on ARCH_OMAP2 && ARCH_OMAP2420
+ depends on ARCH_OMAP2 && SOC_OMAP2420
default y if MACH_NOKIA_N8X0
config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
- depends on ARCH_OMAP2420
+ depends on SOC_OMAP2420
default y
select OMAP_PACKAGE_ZAF
select OMAP_DEBUG_DEVICES
config MACH_OMAP_APOLLON
bool "OMAP 2420 Apollon board"
- depends on ARCH_OMAP2420
+ depends on SOC_OMAP2420
default y
select OMAP_PACKAGE_ZAC
config MACH_OMAP_2430SDP
bool "OMAP 2430 SDP board"
- depends on ARCH_OMAP2430
+ depends on SOC_OMAP2430
default y
select OMAP_PACKAGE_ZAC
@@ -220,7 +225,7 @@ config MACH_NOKIA_N810_WIMAX
config MACH_NOKIA_N8X0
bool "Nokia N800/N810"
- depends on ARCH_OMAP2420
+ depends on SOC_OMAP2420
default y
select OMAP_PACKAGE_ZAC
select MACH_NOKIA_N800
@@ -295,12 +300,18 @@ config MACH_OMAP_3630SDP
default y
select OMAP_PACKAGE_CBP
+config MACH_TI8168EVM
+ bool "TI8168 Evaluation Module"
+ depends on SOC_OMAPTI816X
+ default y
+
config MACH_OMAP_4430SDP
bool "OMAP 4430 SDP board"
default y
depends on ARCH_OMAP4
select OMAP_PACKAGE_CBL
select OMAP_PACKAGE_CBS
+ select REGULATOR_FIXED_VOLTAGE
config MACH_OMAP4_PANDA
bool "OMAP4 Panda Board"
@@ -308,6 +319,7 @@ config MACH_OMAP4_PANDA
depends on ARCH_OMAP4
select OMAP_PACKAGE_CBL
select OMAP_PACKAGE_CBS
+ select REGULATOR_FIXED_VOLTAGE
config OMAP3_EMU
bool "OMAP3 debugging peripherals"
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 64dc4176407b..a45cd6409686 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -31,8 +31,8 @@ AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec)
AFLAGS_omap44xx-smc.o :=-Wa,-march=armv7-a$(plus_sec)
# Functions loaded to SRAM
-obj-$(CONFIG_ARCH_OMAP2420) += sram242x.o
-obj-$(CONFIG_ARCH_OMAP2430) += sram243x.o
+obj-$(CONFIG_SOC_OMAP2420) += sram242x.o
+obj-$(CONFIG_SOC_OMAP2430) += sram243x.o
obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o
AFLAGS_sram242x.o :=-Wa,-march=armv6
@@ -40,8 +40,8 @@ AFLAGS_sram243x.o :=-Wa,-march=armv6
AFLAGS_sram34xx.o :=-Wa,-march=armv7-a
# Pin multiplexing
-obj-$(CONFIG_ARCH_OMAP2420) += mux2420.o
-obj-$(CONFIG_ARCH_OMAP2430) += mux2430.o
+obj-$(CONFIG_SOC_OMAP2420) += mux2420.o
+obj-$(CONFIG_SOC_OMAP2430) += mux2430.o
obj-$(CONFIG_ARCH_OMAP3) += mux34xx.o
obj-$(CONFIG_ARCH_OMAP4) += mux44xx.o
@@ -59,10 +59,10 @@ endif
# Power Management
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o voltage.o
-obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o voltage.o \
+obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \
cpuidle34xx.o pm_bus.o
-obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o voltage.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o
obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
@@ -78,13 +78,25 @@ endif
# PRCM
obj-$(CONFIG_ARCH_OMAP2) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
-obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o
+obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \
+ vc3xxx_data.o vp3xxx_data.o
# XXX The presence of cm2xxx_3xxx.o on the line below is temporary and
# will be removed once the OMAP4 part of the codebase is converted to
# use OMAP4-specific PRCM functions.
obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \
cm44xx.o prcm_mpu44xx.o \
- prminst44xx.o
+ prminst44xx.o vc44xx_data.o \
+ vp44xx_data.o
+
+# OMAP voltage domains
+ifeq ($(CONFIG_PM),y)
+voltagedomain-common := voltage.o
+obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common)
+obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \
+ voltagedomains3xxx_data.o
+obj-$(CONFIG_ARCH_OMAP4) += $(voltagedomain-common) \
+ voltagedomains44xx_data.o
+endif
# OMAP powerdomain framework
powerdomain-common += powerdomain.o powerdomain-common.o
@@ -102,39 +114,49 @@ obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \
# PRCM clockdomain control
obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \
+ clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \
+ clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \
+ clockdomain44xx.o \
clockdomains44xx_data.o
+
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \
clkt2xxx_sys.o \
clkt2xxx_dpllcore.o \
clkt2xxx_virt_prcm_set.o \
- clkt2xxx_apll.o clkt2xxx_osc.o
-obj-$(CONFIG_ARCH_OMAP2420) += clock2420_data.o
-obj-$(CONFIG_ARCH_OMAP2430) += clock2430.o clock2430_data.o
+ clkt2xxx_apll.o clkt2xxx_osc.o \
+ clkt2xxx_dpll.o clkt_iclk.o
+obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o
+obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \
clock34xx.o clkt34xx_dpll3m2.o \
clock3517.o clock36xx.o \
- dpll3xxx.o clock3xxx_data.o
+ dpll3xxx.o clock3xxx_data.o \
+ clkt_iclk.o
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \
- dpll3xxx.o
+ dpll3xxx.o dpll44xx.o
# OMAP2 clock rate set data (old "OPP" data)
-obj-$(CONFIG_ARCH_OMAP2420) += opp2420_data.o
-obj-$(CONFIG_ARCH_OMAP2430) += opp2430_data.o
+obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o
+obj-$(CONFIG_SOC_OMAP2430) += opp2430_data.o
# hwmod data
-obj-$(CONFIG_ARCH_OMAP2420) += omap_hwmod_2420_data.o
-obj-$(CONFIG_ARCH_OMAP2430) += omap_hwmod_2430_data.o
+obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2420_data.o
+obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2430_data.o
obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
# EMU peripherals
obj-$(CONFIG_OMAP3_EMU) += emu.o
+# L3 interconnect
+obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o
+obj-$(CONFIG_ARCH_OMAP4) += omap_l3_noc.o
+
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
mailbox_mach-objs := mailbox.o
@@ -218,12 +240,14 @@ obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \
hsmmc.o \
omap_phy_internal.o
-obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
+obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \
+ omap_phy_internal.o \
obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o
obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o \
hsmmc.o
+obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o
# Platform specific device init code
usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o
obj-y += $(usbfs-m) $(usbfs-y)
@@ -242,3 +266,7 @@ obj-y += $(smc91x-m) $(smc91x-y)
smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
obj-y += $(smsc911x-m) $(smsc911x-y)
+obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o
+
+disp-$(CONFIG_OMAP2_DSS) := display.o
+obj-y += $(disp-m) $(disp-y)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index e0661777f599..1fa6bb896f41 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -22,6 +22,7 @@
#include <linux/mmc/host.h>
#include <linux/delay.h>
#include <linux/i2c/twl.h>
+#include <linux/regulator/machine.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -139,15 +140,31 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
{OMAP_TAG_LCD, &sdp2430_lcd_config},
};
-static void __init omap_2430sdp_init_irq(void)
+static void __init omap_2430sdp_init_early(void)
{
- omap_board_config = sdp2430_config;
- omap_board_config_size = ARRAY_SIZE(sdp2430_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
+static struct regulator_consumer_supply sdp2430_vmmc1_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data sdp2430_vmmc1 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(sdp2430_vmmc1_supplies),
+ .consumer_supplies = &sdp2430_vmmc1_supplies[0],
+};
+
static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
@@ -160,6 +177,7 @@ static struct twl4030_platform_data sdp2430_twldata = {
/* platform_data for children goes here */
.gpio = &sdp2430_gpio_data,
+ .vmmc1 = &sdp2430_vmmc1,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
@@ -226,6 +244,9 @@ static void __init omap_2430sdp_init(void)
omap2430_mux_init(board_mux, OMAP_PACKAGE_ZAC);
+ omap_board_config = sdp2430_config;
+ omap_board_config_size = ARRAY_SIZE(sdp2430_config);
+
omap2430_i2c_init();
platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices));
@@ -253,9 +274,10 @@ static void __init omap_2430sdp_map_io(void)
MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.boot_params = 0x80000100,
- .map_io = omap_2430sdp_map_io,
.reserve = omap_reserve,
- .init_irq = omap_2430sdp_init_irq,
+ .map_io = omap_2430sdp_map_io,
+ .init_early = omap_2430sdp_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_2430sdp_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 7542ba59f2b8..c06eb423c4e4 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -307,34 +307,16 @@ static struct omap_dss_board_info sdp3430_dss_data = {
.default_device = &sdp3430_lcd_device,
};
-static struct platform_device sdp3430_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &sdp3430_dss_data,
- },
-};
-
-static struct regulator_consumer_supply sdp3430_vdda_dac_supply = {
- .supply = "vdda_dac",
- .dev = &sdp3430_dss_device.dev,
-};
-
-static struct platform_device *sdp3430_devices[] __initdata = {
- &sdp3430_dss_device,
-};
+static struct regulator_consumer_supply sdp3430_vdda_dac_supply =
+ REGULATOR_SUPPLY("vdda_dac", "omapdss");
static struct omap_board_config_kernel sdp3430_config[] __initdata = {
};
-static void __init omap_3430sdp_init_irq(void)
+static void __init omap_3430sdp_init_early(void)
{
- omap_board_config = sdp3430_config;
- omap_board_config_size = ARRAY_SIZE(sdp3430_config);
- omap3_pm_init_cpuidle(omap3_cpuidle_params_table);
omap2_init_common_infrastructure();
omap2_init_common_devices(hyb18m512160af6_sdrc_params, NULL);
- omap_init_irq();
}
static int sdp3430_batt_table[] = {
@@ -370,18 +352,6 @@ static struct omap2_hsmmc_info mmc[] = {
{} /* Terminator */
};
-static struct regulator_consumer_supply sdp3430_vmmc1_supply = {
- .supply = "vmmc",
-};
-
-static struct regulator_consumer_supply sdp3430_vsim_supply = {
- .supply = "vmmc_aux",
-};
-
-static struct regulator_consumer_supply sdp3430_vmmc2_supply = {
- .supply = "vmmc",
-};
-
static int sdp3430_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
@@ -392,13 +362,6 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
mmc[1].gpio_cd = gpio + 1;
omap2_hsmmc_init(mmc);
- /* link regulators to MMC adapters ... we "know" the
- * regulators will be set up only *after* we return.
- */
- sdp3430_vmmc1_supply.dev = mmc[0].dev;
- sdp3430_vsim_supply.dev = mmc[0].dev;
- sdp3430_vmmc2_supply.dev = mmc[1].dev;
-
/* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
gpio_request(gpio + 7, "sub_lcd_en_bkl");
gpio_direction_output(gpio + 7, 0);
@@ -427,6 +390,34 @@ static struct twl4030_madc_platform_data sdp3430_madc_data = {
.irq_line = 1,
};
+/* regulator consumer mappings */
+
+/* ads7846 on SPI */
+static struct regulator_consumer_supply sdp3430_vaux3_supplies[] = {
+ REGULATOR_SUPPLY("vcc", "spi1.0"),
+};
+
+static struct regulator_consumer_supply sdp3430_vdda_dac_supplies[] = {
+ REGULATOR_SUPPLY("vdda_dac", "omapdss"),
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss"),
+};
+
+static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
+};
+
+static struct regulator_consumer_supply sdp3430_vsim_supplies[] = {
+ REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
+};
+
+static struct regulator_consumer_supply sdp3430_vmmc2_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
+};
+
/*
* Apply all the fixed voltages since most versions of U-Boot
* don't bother with that initialization.
@@ -469,6 +460,8 @@ static struct regulator_init_data sdp3430_vaux3 = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(sdp3430_vaux3_supplies),
+ .consumer_supplies = sdp3430_vaux3_supplies,
};
/* VAUX4 for OMAP VDD_CSI2 (camera) */
@@ -495,8 +488,8 @@ static struct regulator_init_data sdp3430_vmmc1 = {
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = 1,
- .consumer_supplies = &sdp3430_vmmc1_supply,
+ .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc1_supplies),
+ .consumer_supplies = sdp3430_vmmc1_supplies,
};
/* VMMC2 for MMC2 card */
@@ -510,8 +503,8 @@ static struct regulator_init_data sdp3430_vmmc2 = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = 1,
- .consumer_supplies = &sdp3430_vmmc2_supply,
+ .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc2_supplies),
+ .consumer_supplies = sdp3430_vmmc2_supplies,
};
/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
@@ -525,8 +518,8 @@ static struct regulator_init_data sdp3430_vsim = {
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = 1,
- .consumer_supplies = &sdp3430_vsim_supply,
+ .num_consumer_supplies = ARRAY_SIZE(sdp3430_vsim_supplies),
+ .consumer_supplies = sdp3430_vsim_supplies,
};
/* VDAC for DSS driving S-Video */
@@ -540,16 +533,8 @@ static struct regulator_init_data sdp3430_vdac = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = 1,
- .consumer_supplies = &sdp3430_vdda_dac_supply,
-};
-
-/* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
- {
- .supply = "vdds_dsi",
- .dev = &sdp3430_dss_device.dev,
- }
+ .num_consumer_supplies = ARRAY_SIZE(sdp3430_vdda_dac_supplies),
+ .consumer_supplies = sdp3430_vdda_dac_supplies,
};
static struct regulator_init_data sdp3430_vpll2 = {
@@ -567,9 +552,7 @@ static struct regulator_init_data sdp3430_vpll2 = {
.consumer_supplies = sdp3430_vpll2_supplies,
};
-static struct twl4030_codec_audio_data sdp3430_audio = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data sdp3430_audio;
static struct twl4030_codec_data sdp3430_codec = {
.audio_mclk = 26000000,
@@ -669,6 +652,106 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+
+static struct omap_device_pad serial1_pads[] __initdata = {
+ /*
+ * Note that off output enable is an active low
+ * signal. So setting this means pin is a
+ * input enabled in off mode
+ */
+ OMAP_MUX_STATIC("uart1_cts.uart1_cts",
+ OMAP_PIN_INPUT |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart1_rts.uart1_rts",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart1_rx.uart1_rx",
+ OMAP_PIN_INPUT |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart1_tx.uart1_tx",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial2_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart2_cts.uart2_cts",
+ OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rts.uart2_rts",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rx.uart2_rx",
+ OMAP_PIN_INPUT |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_tx.uart2_tx",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial3_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx",
+ OMAP_PIN_INPUT_PULLDOWN |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx",
+ OMAP_PIN_INPUT |
+ OMAP_PIN_OFF_INPUT_PULLDOWN |
+ OMAP_OFFOUT_EN |
+ OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx",
+ OMAP_PIN_OUTPUT |
+ OMAP_OFF_EN |
+ OMAP_MUX_MODE0),
+};
+
+static struct omap_board_data serial1_data = {
+ .id = 0,
+ .pads = serial1_pads,
+ .pads_cnt = ARRAY_SIZE(serial1_pads),
+};
+
+static struct omap_board_data serial2_data = {
+ .id = 1,
+ .pads = serial2_pads,
+ .pads_cnt = ARRAY_SIZE(serial2_pads),
+};
+
+static struct omap_board_data serial3_data = {
+ .id = 2,
+ .pads = serial3_pads,
+ .pads_cnt = ARRAY_SIZE(serial3_pads),
+};
+
+static inline void board_serial_init(void)
+{
+ omap_serial_init_port(&serial1_data);
+ omap_serial_init_port(&serial2_data);
+ omap_serial_init_port(&serial3_data);
+}
+#else
+#define board_mux NULL
+
+static inline void board_serial_init(void)
+{
+ omap_serial_init();
+}
#endif
/*
@@ -800,8 +883,11 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap_3430sdp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_board_config = sdp3430_config;
+ omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+ omap3_pm_init_cpuidle(omap3_cpuidle_params_table);
omap3430_i2c_init();
- platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices));
+ omap_display_init(&sdp3430_dss_data);
if (omap_rev() > OMAP3430_REV_ES1_0)
ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV2;
else
@@ -810,10 +896,10 @@ static void __init omap_3430sdp_init(void)
spi_register_board_info(sdp3430_spi_board_info,
ARRAY_SIZE(sdp3430_spi_board_info));
ads7846_dev_init();
- omap_serial_init();
+ board_serial_init();
usb_musb_init(&musb_board_data);
board_smc91x_init();
- board_flash_init(sdp_flash_partitions, chip_sel_3430);
+ board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
sdp3430_display_init();
enable_board_wakeup_source();
usbhs_init(&usbhs_bdata);
@@ -822,9 +908,10 @@ static void __init omap_3430sdp_init(void)
MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
/* Maintainer: Syed Khasim - Texas Instruments Inc */
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap_3430sdp_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap_3430sdp_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_3430sdp_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index deed2db32c53..a5933cc15caa 100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio.h>
+#include <linux/mtd/nand.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -69,14 +70,11 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
static struct omap_board_config_kernel sdp_config[] __initdata = {
};
-static void __init omap_sdp_init_irq(void)
+static void __init omap_sdp_init_early(void)
{
- omap_board_config = sdp_config;
- omap_board_config_size = ARRAY_SIZE(sdp_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(h8mbx00u0mer0em_sdrc_params,
h8mbx00u0mer0em_sdrc_params);
- omap_init_irq();
}
#ifdef CONFIG_OMAP_MUX
@@ -206,19 +204,22 @@ static struct flash_partitions sdp_flash_partitions[] = {
static void __init omap_sdp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
+ omap_board_config = sdp_config;
+ omap_board_config_size = ARRAY_SIZE(sdp_config);
zoom_peripherals_init();
zoom_display_init();
board_smc91x_init();
- board_flash_init(sdp_flash_partitions, chip_sel_sdp);
+ board_flash_init(sdp_flash_partitions, chip_sel_sdp, NAND_BUSWIDTH_16);
enable_board_wakeup_source();
usbhs_init(&usbhs_bdata);
}
MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap_sdp_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap_sdp_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_sdp_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index f603f3b04cb8..333ceb2c8fb0 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -35,6 +35,7 @@
#include <plat/common.h>
#include <plat/usb.h>
#include <plat/mmc.h>
+#include <plat/omap4-keypad.h>
#include "mux.h"
#include "hsmmc.h"
@@ -47,6 +48,90 @@
#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184
#define OMAP4_SFH7741_ENABLE_GPIO 188
+static const int sdp4430_keymap[] = {
+ KEY(0, 0, KEY_E),
+ KEY(0, 1, KEY_R),
+ KEY(0, 2, KEY_T),
+ KEY(0, 3, KEY_HOME),
+ KEY(0, 4, KEY_F5),
+ KEY(0, 5, KEY_UNKNOWN),
+ KEY(0, 6, KEY_I),
+ KEY(0, 7, KEY_LEFTSHIFT),
+
+ KEY(1, 0, KEY_D),
+ KEY(1, 1, KEY_F),
+ KEY(1, 2, KEY_G),
+ KEY(1, 3, KEY_SEND),
+ KEY(1, 4, KEY_F6),
+ KEY(1, 5, KEY_UNKNOWN),
+ KEY(1, 6, KEY_K),
+ KEY(1, 7, KEY_ENTER),
+
+ KEY(2, 0, KEY_X),
+ KEY(2, 1, KEY_C),
+ KEY(2, 2, KEY_V),
+ KEY(2, 3, KEY_END),
+ KEY(2, 4, KEY_F7),
+ KEY(2, 5, KEY_UNKNOWN),
+ KEY(2, 6, KEY_DOT),
+ KEY(2, 7, KEY_CAPSLOCK),
+
+ KEY(3, 0, KEY_Z),
+ KEY(3, 1, KEY_KPPLUS),
+ KEY(3, 2, KEY_B),
+ KEY(3, 3, KEY_F1),
+ KEY(3, 4, KEY_F8),
+ KEY(3, 5, KEY_UNKNOWN),
+ KEY(3, 6, KEY_O),
+ KEY(3, 7, KEY_SPACE),
+
+ KEY(4, 0, KEY_W),
+ KEY(4, 1, KEY_Y),
+ KEY(4, 2, KEY_U),
+ KEY(4, 3, KEY_F2),
+ KEY(4, 4, KEY_VOLUMEUP),
+ KEY(4, 5, KEY_UNKNOWN),
+ KEY(4, 6, KEY_L),
+ KEY(4, 7, KEY_LEFT),
+
+ KEY(5, 0, KEY_S),
+ KEY(5, 1, KEY_H),
+ KEY(5, 2, KEY_J),
+ KEY(5, 3, KEY_F3),
+ KEY(5, 4, KEY_F9),
+ KEY(5, 5, KEY_VOLUMEDOWN),
+ KEY(5, 6, KEY_M),
+ KEY(5, 7, KEY_RIGHT),
+
+ KEY(6, 0, KEY_Q),
+ KEY(6, 1, KEY_A),
+ KEY(6, 2, KEY_N),
+ KEY(6, 3, KEY_BACK),
+ KEY(6, 4, KEY_BACKSPACE),
+ KEY(6, 5, KEY_UNKNOWN),
+ KEY(6, 6, KEY_P),
+ KEY(6, 7, KEY_UP),
+
+ KEY(7, 0, KEY_PROG1),
+ KEY(7, 1, KEY_PROG2),
+ KEY(7, 2, KEY_PROG3),
+ KEY(7, 3, KEY_PROG4),
+ KEY(7, 4, KEY_F4),
+ KEY(7, 5, KEY_UNKNOWN),
+ KEY(7, 6, KEY_OK),
+ KEY(7, 7, KEY_DOWN),
+};
+
+static struct matrix_keymap_data sdp4430_keymap_data = {
+ .keymap = sdp4430_keymap,
+ .keymap_size = ARRAY_SIZE(sdp4430_keymap),
+};
+
+static struct omap4_keypad_platform_data sdp4430_keypad_data = {
+ .keymap_data = &sdp4430_keymap_data,
+ .rows = 8,
+ .cols = 8,
+};
static struct gpio_led sdp4430_gpio_leds[] = {
{
.name = "omap4:green:debug0",
@@ -238,16 +323,13 @@ static struct omap_board_config_kernel sdp4430_config[] __initdata = {
{ OMAP_TAG_LCD, &sdp4430_lcd_config },
};
-static void __init omap_4430sdp_init_irq(void)
+static void __init omap_4430sdp_init_early(void)
{
- omap_board_config = sdp4430_config;
- omap_board_config_size = ARRAY_SIZE(sdp4430_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(1);
#endif
- gic_init_irq();
}
static struct omap_musb_board_data musb_board_data = {
@@ -266,11 +348,6 @@ static struct twl4030_usb_data omap4_usbphy_data = {
static struct omap2_hsmmc_info mmc[] = {
{
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
- .gpio_wp = -EINVAL,
- },
- {
.mmc = 2,
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_cd = -EINVAL,
@@ -278,19 +355,24 @@ static struct omap2_hsmmc_info mmc[] = {
.nonremovable = true,
.ocr_mask = MMC_VDD_29_30,
},
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = -EINVAL,
+ },
{} /* Terminator */
};
static struct regulator_consumer_supply sdp4430_vaux_supply[] = {
{
.supply = "vmmc",
- .dev_name = "mmci-omap-hs.1",
+ .dev_name = "omap_hsmmc.1",
},
};
static struct regulator_consumer_supply sdp4430_vmmc_supply[] = {
{
.supply = "vmmc",
- .dev_name = "mmci-omap-hs.0",
+ .dev_name = "omap_hsmmc.0",
},
};
@@ -424,7 +506,6 @@ static struct regulator_init_data sdp4430_vana = {
.constraints = {
.min_uV = 2100000,
.max_uV = 2100000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -436,7 +517,6 @@ static struct regulator_init_data sdp4430_vcxio = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -448,7 +528,6 @@ static struct regulator_init_data sdp4430_vdac = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -547,9 +626,76 @@ static struct omap_board_mux board_mux[] __initdata = {
OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+
+static struct omap_device_pad serial2_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart2_cts.uart2_cts",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rts.uart2_rts",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rx.uart2_rx",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_tx.uart2_tx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial3_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx",
+ OMAP_PIN_INPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial4_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart4_rx.uart4_rx",
+ OMAP_PIN_INPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart4_tx.uart4_tx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_board_data serial2_data = {
+ .id = 1,
+ .pads = serial2_pads,
+ .pads_cnt = ARRAY_SIZE(serial2_pads),
+};
+
+static struct omap_board_data serial3_data = {
+ .id = 2,
+ .pads = serial3_pads,
+ .pads_cnt = ARRAY_SIZE(serial3_pads),
+};
+
+static struct omap_board_data serial4_data = {
+ .id = 3,
+ .pads = serial4_pads,
+ .pads_cnt = ARRAY_SIZE(serial4_pads),
+};
+
+static inline void board_serial_init(void)
+{
+ struct omap_board_data bdata;
+ bdata.flags = 0;
+ bdata.pads = NULL;
+ bdata.pads_cnt = 0;
+ bdata.id = 0;
+ /* pass dummy data for UART1 */
+ omap_serial_init_port(&bdata);
+
+ omap_serial_init_port(&serial2_data);
+ omap_serial_init_port(&serial3_data);
+ omap_serial_init_port(&serial4_data);
+}
#else
#define board_mux NULL
-#endif
+
+static inline void board_serial_init(void)
+{
+ omap_serial_init();
+}
+ #endif
static void __init omap_4430sdp_init(void)
{
@@ -560,10 +706,13 @@ static void __init omap_4430sdp_init(void)
package = OMAP_PACKAGE_CBL;
omap4_mux_init(board_mux, package);
+ omap_board_config = sdp4430_config;
+ omap_board_config_size = ARRAY_SIZE(sdp4430_config);
+
omap4_i2c_init();
omap_sfh7741prox_init();
platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
- omap_serial_init();
+ board_serial_init();
omap4_twl6030_hsmmc_init(mmc);
usb_musb_init(&musb_board_data);
@@ -576,6 +725,10 @@ static void __init omap_4430sdp_init(void)
spi_register_board_info(sdp4430_spi_board_info,
ARRAY_SIZE(sdp4430_spi_board_info));
}
+
+ status = omap4_keyboard_init(&sdp4430_keypad_data);
+ if (status)
+ pr_err("Keypad initialization failed: %d\n", status);
}
static void __init omap_4430sdp_map_io(void)
@@ -587,9 +740,10 @@ static void __init omap_4430sdp_map_io(void)
MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
/* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
.boot_params = 0x80000100,
- .map_io = omap_4430sdp_map_io,
.reserve = omap_reserve,
- .init_irq = omap_4430sdp_init_irq,
+ .map_io = omap_4430sdp_map_io,
+ .init_early = omap_4430sdp_init_early,
+ .init_irq = gic_init_irq,
.init_machine = omap_4430sdp_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index e3a194f6b13f..a890d244fec6 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -49,14 +49,10 @@ static struct omap_board_mux board_mux[] __initdata = {
#define board_mux NULL
#endif
-static void __init am3517_crane_init_irq(void)
+static void __init am3517_crane_init_early(void)
{
- omap_board_config = am3517_crane_config;
- omap_board_config_size = ARRAY_SIZE(am3517_crane_config);
-
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
static struct usbhs_omap_board_data usbhs_bdata __initdata = {
@@ -77,6 +73,9 @@ static void __init am3517_crane_init(void)
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_serial_init();
+ omap_board_config = am3517_crane_config;
+ omap_board_config_size = ARRAY_SIZE(am3517_crane_config);
+
/* Configure GPIO for EHCI port */
if (omap_mux_init_gpio(GPIO_USB_NRESET, OMAP_PIN_OUTPUT)) {
pr_err("Can not configure mux for GPIO_USB_NRESET %d\n",
@@ -108,9 +107,10 @@ static void __init am3517_crane_init(void)
MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = am3517_crane_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = am3517_crane_init_early,
+ .init_irq = omap_init_irq,
.init_machine = am3517_crane_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 913538ad17d8..ce7d5e6e4150 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -200,6 +200,9 @@ static struct pca953x_platform_data am3517evm_gpio_expander_info_0 = {
};
static struct i2c_board_info __initdata am3517evm_i2c2_boardinfo[] = {
{
+ I2C_BOARD_INFO("tlv320aic23", 0x1A),
+ },
+ {
I2C_BOARD_INFO("tca6416", 0x21),
.platform_data = &am3517evm_gpio_expander_info_0,
},
@@ -378,37 +381,23 @@ static struct omap_dss_board_info am3517_evm_dss_data = {
.default_device = &am3517_evm_lcd_device,
};
-static struct platform_device am3517_evm_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &am3517_evm_dss_data,
- },
-};
-
/*
* Board initialization
*/
-static struct omap_board_config_kernel am3517_evm_config[] __initdata = {
-};
-
-static struct platform_device *am3517_evm_devices[] __initdata = {
- &am3517_evm_dss_device,
-};
-
-static void __init am3517_evm_init_irq(void)
+static void __init am3517_evm_init_early(void)
{
- omap_board_config = am3517_evm_config;
- omap_board_config_size = ARRAY_SIZE(am3517_evm_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
.mode = MUSB_OTG,
.power = 500,
+ .set_phy_power = am35x_musb_phy_power,
+ .clear_irq = am35x_musb_clear_irq,
+ .set_mode = am35x_musb_set_mode,
+ .reset = am35x_musb_reset,
};
static __init void am3517_evm_musb_init(void)
@@ -490,14 +479,17 @@ static void am3517_evm_hecc_init(struct ti_hecc_platform_data *pdata)
platform_device_register(&am3517_hecc_device);
}
+static struct omap_board_config_kernel am3517_evm_config[] __initdata = {
+};
+
static void __init am3517_evm_init(void)
{
+ omap_board_config = am3517_evm_config;
+ omap_board_config_size = ARRAY_SIZE(am3517_evm_config);
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
am3517_evm_i2c_init();
- platform_add_devices(am3517_evm_devices,
- ARRAY_SIZE(am3517_evm_devices));
-
+ omap_display_init(&am3517_evm_dss_data);
omap_serial_init();
/* Configure GPIO for EHCI port */
@@ -521,9 +513,10 @@ static void __init am3517_evm_init(void)
MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = am3517_evm_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = am3517_evm_init_early,
+ .init_irq = omap_init_irq,
.init_machine = am3517_evm_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index 9f55b68687f7..f4f8374a0298 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -274,13 +274,10 @@ static struct omap_board_config_kernel apollon_config[] __initdata = {
{ OMAP_TAG_LCD, &apollon_lcd_config },
};
-static void __init omap_apollon_init_irq(void)
+static void __init omap_apollon_init_early(void)
{
- omap_board_config = apollon_config;
- omap_board_config_size = ARRAY_SIZE(apollon_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
static void __init apollon_led_init(void)
@@ -320,6 +317,8 @@ static void __init omap_apollon_init(void)
u32 v;
omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
+ omap_board_config = apollon_config;
+ omap_board_config_size = ARRAY_SIZE(apollon_config);
apollon_init_smc91x();
apollon_led_init();
@@ -355,9 +354,10 @@ static void __init omap_apollon_map_io(void)
MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
/* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
.boot_params = 0x80000100,
- .map_io = omap_apollon_map_io,
.reserve = omap_reserve,
- .init_irq = omap_apollon_init_irq,
+ .map_io = omap_apollon_map_io,
+ .init_early = omap_apollon_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_apollon_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 9be7289cbb56..7b5647954c13 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -401,14 +401,6 @@ static struct omap_dss_board_info cm_t35_dss_data = {
.default_device = &cm_t35_dvi_device,
};
-static struct platform_device cm_t35_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &cm_t35_dss_data,
- },
-};
-
static struct omap2_mcspi_device_config tdo24m_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
@@ -468,7 +460,7 @@ static void __init cm_t35_init_display(void)
msleep(50);
gpio_set_value(lcd_en_gpio, 1);
- err = platform_device_register(&cm_t35_dss_device);
+ err = omap_display_init(&cm_t35_dss_data);
if (err) {
pr_err("CM-T35: failed to register DSS device\n");
goto err_dev_reg;
@@ -495,15 +487,11 @@ static struct regulator_consumer_supply cm_t35_vsim_supply = {
.supply = "vmmc_aux",
};
-static struct regulator_consumer_supply cm_t35_vdac_supply = {
- .supply = "vdda_dac",
- .dev = &cm_t35_dss_device.dev,
-};
+static struct regulator_consumer_supply cm_t35_vdac_supply =
+ REGULATOR_SUPPLY("vdda_dac", "omapdss");
-static struct regulator_consumer_supply cm_t35_vdvi_supply = {
- .supply = "vdvi",
- .dev = &cm_t35_dss_device.dev,
-};
+static struct regulator_consumer_supply cm_t35_vdvi_supply =
+ REGULATOR_SUPPLY("vdvi", "omapdss");
/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
static struct regulator_init_data cm_t35_vmmc1 = {
@@ -680,20 +668,14 @@ static void __init cm_t35_init_i2c(void)
ARRAY_SIZE(cm_t35_i2c_boardinfo));
}
-static struct omap_board_config_kernel cm_t35_config[] __initdata = {
-};
-
-static void __init cm_t35_init_irq(void)
+static void __init cm_t35_init_early(void)
{
- omap_board_config = cm_t35_config;
- omap_board_config_size = ARRAY_SIZE(cm_t35_config);
-
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
- omap_init_irq();
}
+#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* nCS and IRQ for CM-T35 ethernet */
OMAP3_MUX(GPMC_NCS5, OMAP_MUX_MODE0),
@@ -791,6 +773,7 @@ static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+#endif
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
@@ -798,8 +781,13 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
+static struct omap_board_config_kernel cm_t35_config[] __initdata = {
+};
+
static void __init cm_t35_init(void)
{
+ omap_board_config = cm_t35_config;
+ omap_board_config_size = ARRAY_SIZE(cm_t35_config);
omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
omap_serial_init();
cm_t35_init_i2c();
@@ -815,9 +803,10 @@ static void __init cm_t35_init(void)
MACHINE_START(CM_T35, "Compulab CM-T35")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = cm_t35_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = cm_t35_init_early,
+ .init_irq = omap_init_irq,
.init_machine = cm_t35_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index 8e18dc76b11e..a27e3eee8292 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -254,16 +254,13 @@ static inline void cm_t3517_init_nand(void) {}
static struct omap_board_config_kernel cm_t3517_config[] __initdata = {
};
-static void __init cm_t3517_init_irq(void)
+static void __init cm_t3517_init_early(void)
{
- omap_board_config = cm_t3517_config;
- omap_board_config_size = ARRAY_SIZE(cm_t3517_config);
-
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
+#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* GPIO186 - Green LED */
OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
@@ -289,11 +286,14 @@ static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+#endif
static void __init cm_t3517_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_serial_init();
+ omap_board_config = cm_t3517_config;
+ omap_board_config_size = ARRAY_SIZE(cm_t3517_config);
cm_t3517_init_leds();
cm_t3517_init_nand();
cm_t3517_init_rtc();
@@ -303,9 +303,10 @@ static void __init cm_t3517_init(void)
MACHINE_START(CM_T3517, "Compulab CM-T3517")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = cm_t3517_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = cm_t3517_init_early,
+ .init_irq = omap_init_irq,
.init_machine = cm_t3517_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index bc0141b98694..aa27483c493e 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -140,7 +140,7 @@ static void devkit8000_panel_disable_dvi(struct omap_dss_device *dssdev)
}
static struct regulator_consumer_supply devkit8000_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
/* ads7846 on SPI */
@@ -195,14 +195,6 @@ static struct omap_dss_board_info devkit8000_dss_data = {
.default_device = &devkit8000_lcd_device,
};
-static struct platform_device devkit8000_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &devkit8000_dss_data,
- },
-};
-
static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
@@ -350,9 +342,7 @@ static struct twl4030_usb_data devkit8000_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static struct twl4030_codec_audio_data devkit8000_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data devkit8000_audio_data;
static struct twl4030_codec_data devkit8000_codec_data = {
.audio_mclk = 26000000,
@@ -456,11 +446,15 @@ static struct platform_device keys_gpio = {
};
-static void __init devkit8000_init_irq(void)
+static void __init devkit8000_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
+}
+
+static void __init devkit8000_init_irq(void)
+{
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(12);
@@ -575,7 +569,6 @@ static void __init omap_dm9000_init(void)
}
static struct platform_device *devkit8000_devices[] __initdata = {
- &devkit8000_dss_device,
&leds_gpio,
&keys_gpio,
&omap_dm9000_dev,
@@ -632,6 +625,7 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.reset_gpio_port[2] = -EINVAL
};
+#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* nCS and IRQ for Devkit8000 ethernet */
OMAP3_MUX(GPMC_NCS6, OMAP_MUX_MODE0),
@@ -785,6 +779,7 @@ static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+#endif
static void __init devkit8000_init(void)
{
@@ -797,6 +792,7 @@ static void __init devkit8000_init(void)
platform_add_devices(devkit8000_devices,
ARRAY_SIZE(devkit8000_devices));
+ omap_display_init(&devkit8000_dss_data);
spi_register_board_info(devkit8000_spi_board_info,
ARRAY_SIZE(devkit8000_spi_board_info));
@@ -813,8 +809,9 @@ static void __init devkit8000_init(void)
MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = devkit8000_init_early,
.init_irq = devkit8000_init_irq,
.init_machine = devkit8000_init,
.timer = &omap_timer,
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index fd38c05bb47f..729892fdcf2e 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -1,5 +1,5 @@
/*
- * board-sdp-flash.c
+ * board-flash.c
* Modified from mach-omap2/board-3430sdp-flash.c
*
* Copyright (C) 2009 Nokia Corporation
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/io.h>
+#include <plat/irqs.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
@@ -73,11 +74,11 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
+ FLASH_SIZE_SDPV1 - 1;
}
if (err < 0) {
- printk(KERN_ERR "NOR: Can't request GPMC CS\n");
+ pr_err("NOR: Can't request GPMC CS\n");
return;
}
if (platform_device_register(&board_nor_device) < 0)
- printk(KERN_ERR "Unable to register NOR device\n");
+ pr_err("Unable to register NOR device\n");
}
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
@@ -139,17 +140,21 @@ static struct omap_nand_platform_data board_nand_data = {
};
void
-__init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs)
+__init board_nand_init(struct mtd_partition *nand_parts,
+ u8 nr_parts, u8 cs, int nand_type)
{
board_nand_data.cs = cs;
board_nand_data.parts = nand_parts;
- board_nand_data.nr_parts = nr_parts;
+ board_nand_data.nr_parts = nr_parts;
+ board_nand_data.devsize = nand_type;
+ board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_DEFAULT;
+ board_nand_data.gpmc_irq = OMAP_GPMC_IRQ_BASE + cs;
gpmc_nand_init(&board_nand_data);
}
#else
void
-__init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs)
+__init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs, int nand_type)
{
}
#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */
@@ -189,12 +194,12 @@ unmap:
}
/**
- * sdp3430_flash_init - Identify devices connected to GPMC and register.
+ * board_flash_init - Identify devices connected to GPMC and register.
*
* @return - void.
*/
void board_flash_init(struct flash_partitions partition_info[],
- char chip_sel_board[][GPMC_CS_NUM])
+ char chip_sel_board[][GPMC_CS_NUM], int nand_type)
{
u8 cs = 0;
u8 norcs = GPMC_CS_NUM + 1;
@@ -208,7 +213,7 @@ void board_flash_init(struct flash_partitions partition_info[],
*/
idx = get_gpmc0_type();
if (idx >= MAX_SUPPORTED_GPMC_CONFIG) {
- printk(KERN_ERR "%s: Invalid chip select: %d\n", __func__, cs);
+ pr_err("%s: Invalid chip select: %d\n", __func__, cs);
return;
}
config_sel = (unsigned char *)(chip_sel_board[idx]);
@@ -232,23 +237,20 @@ void board_flash_init(struct flash_partitions partition_info[],
}
if (norcs > GPMC_CS_NUM)
- printk(KERN_INFO "NOR: Unable to find configuration "
- "in GPMC\n");
+ pr_err("NOR: Unable to find configuration in GPMC\n");
else
board_nor_init(partition_info[0].parts,
partition_info[0].nr_parts, norcs);
if (onenandcs > GPMC_CS_NUM)
- printk(KERN_INFO "OneNAND: Unable to find configuration "
- "in GPMC\n");
+ pr_err("OneNAND: Unable to find configuration in GPMC\n");
else
board_onenand_init(partition_info[1].parts,
partition_info[1].nr_parts, onenandcs);
if (nandcs > GPMC_CS_NUM)
- printk(KERN_INFO "NAND: Unable to find configuration "
- "in GPMC\n");
+ pr_err("NAND: Unable to find configuration in GPMC\n");
else
board_nand_init(partition_info[2].parts,
- partition_info[2].nr_parts, nandcs);
+ partition_info[2].nr_parts, nandcs, nand_type);
}
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index 69befe00dd2f..c240a3f8d163 100644
--- a/arch/arm/mach-omap2/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -25,6 +25,6 @@ struct flash_partitions {
};
extern void board_flash_init(struct flash_partitions [],
- char chip_sel[][GPMC_CS_NUM]);
+ char chip_sel[][GPMC_CS_NUM], int nand_type);
extern void board_nand_init(struct mtd_partition *nand_parts,
- u8 nr_parts, u8 cs);
+ u8 nr_parts, u8 cs, int nand_type);
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 0e3d81e09f89..73e3c31e8508 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -33,18 +33,17 @@
static struct omap_board_config_kernel generic_config[] = {
};
-static void __init omap_generic_init_irq(void)
+static void __init omap_generic_init_early(void)
{
- omap_board_config = generic_config;
- omap_board_config_size = ARRAY_SIZE(generic_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
static void __init omap_generic_init(void)
{
omap_serial_init();
+ omap_board_config = generic_config;
+ omap_board_config_size = ARRAY_SIZE(generic_config);
}
static void __init omap_generic_map_io(void)
@@ -68,9 +67,10 @@ static void __init omap_generic_map_io(void)
MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.boot_params = 0x80000100,
- .map_io = omap_generic_map_io,
.reserve = omap_reserve,
- .init_irq = omap_generic_init_irq,
+ .map_io = omap_generic_map_io,
+ .init_early = omap_generic_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_generic_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 25cc9dad4b02..bac7933b8cbb 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -290,14 +290,15 @@ static struct omap_board_config_kernel h4_config[] __initdata = {
{ OMAP_TAG_LCD, &h4_lcd_config },
};
-static void __init omap_h4_init_irq(void)
+static void __init omap_h4_init_early(void)
{
- omap_board_config = h4_config;
- omap_board_config_size = ARRAY_SIZE(h4_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
+}
+
+static void __init omap_h4_init_irq(void)
+{
omap_init_irq();
- h4_init_flash();
}
static struct at24_platform_data m24c01 = {
@@ -330,6 +331,9 @@ static void __init omap_h4_init(void)
{
omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAF);
+ omap_board_config = h4_config;
+ omap_board_config_size = ARRAY_SIZE(h4_config);
+
/*
* Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on
@@ -367,6 +371,7 @@ static void __init omap_h4_init(void)
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap2_usbfs_init(&h4_usb_config);
omap_serial_init();
+ h4_init_flash();
}
static void __init omap_h4_map_io(void)
@@ -378,8 +383,9 @@ static void __init omap_h4_map_io(void)
MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
.boot_params = 0x80000100,
- .map_io = omap_h4_map_io,
.reserve = omap_reserve,
+ .map_io = omap_h4_map_io,
+ .init_early = omap_h4_init_early,
.init_irq = omap_h4_init_irq,
.init_machine = omap_h4_init,
.timer = &omap_timer,
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index f9f534419311..d3199b4ecdb6 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -250,7 +250,7 @@ static inline void __init igep2_init_smsc911x(void) { }
#endif
static struct regulator_consumer_supply igep2_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data igep2_vmmc1 = {
@@ -268,7 +268,7 @@ static struct regulator_init_data igep2_vmmc1 = {
};
static struct regulator_consumer_supply igep2_vio_supply =
- REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
static struct regulator_init_data igep2_vio = {
.constraints = {
@@ -286,7 +286,7 @@ static struct regulator_init_data igep2_vio = {
};
static struct regulator_consumer_supply igep2_vmmc2_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
static struct regulator_init_data igep2_vmmc2 = {
.constraints = {
@@ -485,18 +485,8 @@ static struct omap_dss_board_info igep2_dss_data = {
.default_device = &igep2_dvi_device,
};
-static struct platform_device igep2_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &igep2_dss_data,
- },
-};
-
-static struct regulator_consumer_supply igep2_vpll2_supply = {
- .supply = "vdds_dsi",
- .dev = &igep2_dss_device.dev,
-};
+static struct regulator_consumer_supply igep2_vpll2_supply =
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
static struct regulator_init_data igep2_vpll2 = {
.constraints = {
@@ -521,21 +511,17 @@ static void __init igep2_display_init(void)
}
static struct platform_device *igep2_devices[] __initdata = {
- &igep2_dss_device,
&igep2_vwlan_device,
};
-static void __init igep2_init_irq(void)
+static void __init igep2_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(m65kxxxxam_sdrc_params,
m65kxxxxam_sdrc_params);
- omap_init_irq();
}
-static struct twl4030_codec_audio_data igep2_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data igep2_audio_data;
static struct twl4030_codec_data igep2_codec_data = {
.audio_mclk = 26000000,
@@ -697,6 +683,7 @@ static void __init igep2_init(void)
/* Register I2C busses and drivers */
igep2_i2c_init();
platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
+ omap_display_init(&igep2_dss_data);
omap_serial_init();
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
@@ -716,9 +703,10 @@ static void __init igep2_init(void)
MACHINE_START(IGEP0020, "IGEP v2 board")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = igep2_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = igep2_init_early,
+ .init_irq = omap_init_irq,
.init_machine = igep2_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
index 579fc2d2525f..b10db0e6ee62 100644
--- a/arch/arm/mach-omap2/board-igep0030.c
+++ b/arch/arm/mach-omap2/board-igep0030.c
@@ -142,7 +142,7 @@ static void __init igep3_flash_init(void) {}
#endif
static struct regulator_consumer_supply igep3_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data igep3_vmmc1 = {
@@ -160,7 +160,7 @@ static struct regulator_init_data igep3_vmmc1 = {
};
static struct regulator_consumer_supply igep3_vio_supply =
- REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
static struct regulator_init_data igep3_vio = {
.constraints = {
@@ -178,7 +178,7 @@ static struct regulator_init_data igep3_vio = {
};
static struct regulator_consumer_supply igep3_vmmc2_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
static struct regulator_init_data igep3_vmmc2 = {
.constraints = {
@@ -331,12 +331,11 @@ static struct platform_device *igep3_devices[] __initdata = {
&igep3_vwlan_device,
};
-static void __init igep3_init_irq(void)
+static void __init igep3_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(m65kxxxxam_sdrc_params,
m65kxxxxam_sdrc_params);
- omap_init_irq();
}
static struct twl4030_platform_data igep3_twl4030_pdata = {
@@ -452,7 +451,8 @@ MACHINE_START(IGEP0030, "IGEP OMAP3 module")
.boot_params = 0x80000100,
.reserve = omap_reserve,
.map_io = omap3_map_io,
- .init_irq = igep3_init_irq,
+ .init_early = igep3_init_early,
+ .init_irq = omap_init_irq,
.init_machine = igep3_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index e5dc74875f9d..e2ba77957a8c 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -288,13 +288,10 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_LCD, &ldp_lcd_config },
};
-static void __init omap_ldp_init_irq(void)
+static void __init omap_ldp_init_early(void)
{
- omap_board_config = ldp_config;
- omap_board_config_size = ARRAY_SIZE(ldp_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
static struct twl4030_usb_data ldp_usb_data = {
@@ -330,6 +327,26 @@ static struct regulator_init_data ldp_vmmc1 = {
.consumer_supplies = &ldp_vmmc1_supply,
};
+/* ads7846 on SPI */
+static struct regulator_consumer_supply ldp_vaux1_supplies[] = {
+ REGULATOR_SUPPLY("vcc", "spi1.0"),
+};
+
+/* VAUX1 */
+static struct regulator_init_data ldp_vaux1 = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldp_vaux1_supplies),
+ .consumer_supplies = ldp_vaux1_supplies,
+};
+
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -338,6 +355,7 @@ static struct twl4030_platform_data ldp_twldata = {
.madc = &ldp_madc_data,
.usb = &ldp_usb_data,
.vmmc1 = &ldp_vmmc1,
+ .vaux1 = &ldp_vaux1,
.gpio = &ldp_gpio_data,
.keypad = &ldp_kp_twl4030_data,
};
@@ -423,6 +441,8 @@ static struct mtd_partition ldp_nand_partitions[] = {
static void __init omap_ldp_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_board_config = ldp_config;
+ omap_board_config_size = ARRAY_SIZE(ldp_config);
ldp_init_smsc911x();
omap_i2c_init();
platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
@@ -434,7 +454,7 @@ static void __init omap_ldp_init(void)
omap_serial_init();
usb_musb_init(&musb_board_data);
board_nand_init(ldp_nand_partitions,
- ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS);
+ ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
omap2_hsmmc_init(mmc);
/* link regulators to MMC adapters */
@@ -443,9 +463,10 @@ static void __init omap_ldp_init(void)
MACHINE_START(OMAP_LDP, "OMAP LDP board")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap_ldp_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap_ldp_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_ldp_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index f396756872b7..e710cd9e079b 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -536,7 +536,7 @@ static void __init n8x0_mmc_init(void)
}
mmc_data[0] = &mmc1_data;
- omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+ omap242x_init_mmc(mmc_data);
}
#else
@@ -628,11 +628,10 @@ static void __init n8x0_map_io(void)
omap242x_map_common_io();
}
-static void __init n8x0_init_irq(void)
+static void __init n8x0_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
#ifdef CONFIG_OMAP_MUX
@@ -703,27 +702,30 @@ static void __init n8x0_init_machine(void)
MACHINE_START(NOKIA_N800, "Nokia N800")
.boot_params = 0x80000100,
- .map_io = n8x0_map_io,
.reserve = omap_reserve,
- .init_irq = n8x0_init_irq,
+ .map_io = n8x0_map_io,
+ .init_early = n8x0_init_early,
+ .init_irq = omap_init_irq,
.init_machine = n8x0_init_machine,
.timer = &omap_timer,
MACHINE_END
MACHINE_START(NOKIA_N810, "Nokia N810")
.boot_params = 0x80000100,
- .map_io = n8x0_map_io,
.reserve = omap_reserve,
- .init_irq = n8x0_init_irq,
+ .map_io = n8x0_map_io,
+ .init_early = n8x0_init_early,
+ .init_irq = omap_init_irq,
.init_machine = n8x0_init_machine,
.timer = &omap_timer,
MACHINE_END
MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
.boot_params = 0x80000100,
- .map_io = n8x0_map_io,
.reserve = omap_reserve,
- .init_irq = n8x0_init_irq,
+ .map_io = n8x0_map_io,
+ .init_early = n8x0_init_early,
+ .init_irq = omap_init_irq,
.init_machine = n8x0_init_machine,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index f0963b6e4627..7640c054f43b 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
+#include <linux/opp.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -45,10 +46,12 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
+#include <plat/omap_device.h>
#include "mux.h"
#include "hsmmc.h"
#include "timer-gp.h"
+#include "pm.h"
#define NAND_BLOCK_SIZE SZ_128K
@@ -228,14 +231,6 @@ static struct omap_dss_board_info beagle_dss_data = {
.default_device = &beagle_dvi_device,
};
-static struct platform_device beagle_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &beagle_dss_data,
- },
-};
-
static struct regulator_consumer_supply beagle_vdac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
@@ -435,9 +430,7 @@ static struct twl4030_usb_data beagle_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static struct twl4030_codec_audio_data beagle_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data beagle_audio_data;
static struct twl4030_codec_data beagle_codec_data = {
.audio_mclk = 26000000,
@@ -536,11 +529,15 @@ static struct platform_device keys_gpio = {
},
};
-static void __init omap3_beagle_init_irq(void)
+static void __init omap3_beagle_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
+}
+
+static void __init omap3_beagle_init_irq(void)
+{
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(12);
@@ -550,7 +547,6 @@ static void __init omap3_beagle_init_irq(void)
static struct platform_device *omap3_beagle_devices[] __initdata = {
&leds_gpio,
&keys_gpio,
- &beagle_dss_device,
};
static void __init omap3beagle_flash_init(void)
@@ -610,6 +606,52 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
+static void __init beagle_opp_init(void)
+{
+ int r = 0;
+
+ /* Initialize the omap3 opp table */
+ if (omap3_opp_init()) {
+ pr_err("%s: opp default init failed\n", __func__);
+ return;
+ }
+
+ /* Custom OPP enabled for XM */
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
+ struct omap_hwmod *dh = omap_hwmod_lookup("iva");
+ struct device *dev;
+
+ if (!mh || !dh) {
+ pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
+ __func__, mh, dh);
+ return;
+ }
+ /* Enable MPU 1GHz and lower opps */
+ dev = &mh->od->pdev.dev;
+ r = opp_enable(dev, 800000000);
+ /* TODO: MPU 1GHz needs SR and ABB */
+
+ /* Enable IVA 800MHz and lower opps */
+ dev = &dh->od->pdev.dev;
+ r |= opp_enable(dev, 660000000);
+ /* TODO: DSP 800MHz needs SR and ABB */
+ if (r) {
+ pr_err("%s: failed to enable higher opp %d\n",
+ __func__, r);
+ /*
+ * Cleanup - disable the higher freqs - we dont care
+ * about the results
+ */
+ dev = &mh->od->pdev.dev;
+ opp_disable(dev, 800000000);
+ dev = &dh->od->pdev.dev;
+ opp_disable(dev, 660000000);
+ }
+ }
+ return;
+}
+
static void __init omap3_beagle_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -617,6 +659,7 @@ static void __init omap3_beagle_init(void)
omap3_beagle_i2c_init();
platform_add_devices(omap3_beagle_devices,
ARRAY_SIZE(omap3_beagle_devices));
+ omap_display_init(&beagle_dss_data);
omap_serial_init();
omap_mux_init_gpio(170, OMAP_PIN_INPUT);
@@ -633,13 +676,15 @@ static void __init omap3_beagle_init(void)
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
beagle_display_init();
+ beagle_opp_init();
}
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
/* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = omap3_beagle_init_early,
.init_irq = omap3_beagle_init_irq,
.init_machine = omap3_beagle_init,
.timer = &omap_timer,
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 38a2d91790c0..0fa2c7b208b1 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -30,6 +30,8 @@
#include <linux/usb/otg.h>
#include <linux/smsc911x.h>
+#include <linux/wl12xx.h>
+#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/mmc/host.h>
@@ -58,6 +60,13 @@
#define OMAP3EVM_ETHR_ID_REV 0x50
#define OMAP3EVM_ETHR_GPIO_IRQ 176
#define OMAP3EVM_SMSC911X_CS 5
+/*
+ * Eth Reset signal
+ * 64 = Generation 1 (<=RevD)
+ * 7 = Generation 2 (>=RevE)
+ */
+#define OMAP3EVM_GEN1_ETHR_GPIO_RST 64
+#define OMAP3EVM_GEN2_ETHR_GPIO_RST 7
static u8 omap3_evm_version;
@@ -124,10 +133,15 @@ static struct platform_device omap3evm_smsc911x_device = {
static inline void __init omap3evm_init_smsc911x(void)
{
- int eth_cs;
+ int eth_cs, eth_rst;
struct clk *l3ck;
unsigned int rate;
+ if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
+ eth_rst = OMAP3EVM_GEN1_ETHR_GPIO_RST;
+ else
+ eth_rst = OMAP3EVM_GEN2_ETHR_GPIO_RST;
+
eth_cs = OMAP3EVM_SMSC911X_CS;
l3ck = clk_get(NULL, "l3_ck");
@@ -136,6 +150,27 @@ static inline void __init omap3evm_init_smsc911x(void)
else
rate = clk_get_rate(l3ck);
+ /* Configure ethernet controller reset gpio */
+ if (cpu_is_omap3430()) {
+ if (gpio_request(eth_rst, "SMSC911x gpio") < 0) {
+ pr_err(KERN_ERR "Failed to request %d for smsc911x\n",
+ eth_rst);
+ return;
+ }
+
+ if (gpio_direction_output(eth_rst, 1) < 0) {
+ pr_err(KERN_ERR "Failed to set direction of %d for" \
+ " smsc911x\n", eth_rst);
+ return;
+ }
+ /* reset pulse to ethernet controller*/
+ usleep_range(150, 220);
+ gpio_set_value(eth_rst, 0);
+ usleep_range(150, 220);
+ gpio_set_value(eth_rst, 1);
+ usleep_range(1, 2);
+ }
+
if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMSC911x irq") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
OMAP3EVM_ETHR_GPIO_IRQ);
@@ -235,9 +270,9 @@ static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev)
gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 0);
if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2)
- gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0);
+ gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0);
else
- gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1);
+ gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1);
lcd_enabled = 1;
return 0;
@@ -248,9 +283,9 @@ static void omap3_evm_disable_lcd(struct omap_dss_device *dssdev)
gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 1);
if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2)
- gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1);
+ gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1);
else
- gpio_set_value(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0);
+ gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0);
lcd_enabled = 0;
}
@@ -289,7 +324,7 @@ static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev)
return -EINVAL;
}
- gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 1);
+ gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 1);
dvi_enabled = 1;
return 0;
@@ -297,7 +332,7 @@ static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev)
static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
{
- gpio_set_value(OMAP3EVM_DVI_PANEL_EN_GPIO, 0);
+ gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 0);
dvi_enabled = 0;
}
@@ -328,14 +363,6 @@ static struct omap_dss_board_info omap3_evm_dss_data = {
.default_device = &omap3_evm_lcd_device,
};
-static struct platform_device omap3_evm_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &omap3_evm_dss_data,
- },
-};
-
static struct regulator_consumer_supply omap3evm_vmmc1_supply = {
.supply = "vmmc",
};
@@ -381,6 +408,16 @@ static struct omap2_hsmmc_info mmc[] = {
.gpio_cd = -EINVAL,
.gpio_wp = 63,
},
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+ {
+ .name = "wl1271",
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .nonremovable = true,
+ },
+#endif
{} /* Terminator */
};
@@ -411,6 +448,8 @@ static struct platform_device leds_gpio = {
static int omap3evm_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
+ int r;
+
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
omap_mux_init_gpio(63, OMAP_PIN_INPUT);
mmc[0].gpio_cd = gpio + 0;
@@ -426,8 +465,12 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
*/
/* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
- gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ r = gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
+ if (!r)
+ r = gpio_direction_output(gpio + TWL4030_GPIO_MAX,
+ (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) ? 1 : 0);
+ if (r)
+ printk(KERN_ERR "failed to get/set lcd_bkl gpio\n");
/* gpio + 7 == DVI Enable */
gpio_request(gpio + 7, "EN_DVI");
@@ -491,19 +534,15 @@ static struct twl4030_madc_platform_data omap3evm_madc_data = {
.irq_line = 1,
};
-static struct twl4030_codec_audio_data omap3evm_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data omap3evm_audio_data;
static struct twl4030_codec_data omap3evm_codec_data = {
.audio_mclk = 26000000,
.audio = &omap3evm_audio_data,
};
-static struct regulator_consumer_supply omap3_evm_vdda_dac_supply = {
- .supply = "vdda_dac",
- .dev = &omap3_evm_dss_device.dev,
-};
+static struct regulator_consumer_supply omap3_evm_vdda_dac_supply =
+ REGULATOR_SUPPLY("vdda_dac", "omapdss");
/* VDAC for DSS driving S-Video */
static struct regulator_init_data omap3_evm_vdac = {
@@ -538,6 +577,66 @@ static struct regulator_init_data omap3_evm_vpll2 = {
.consumer_supplies = &omap3_evm_vpll2_supply,
};
+/* ads7846 on SPI */
+static struct regulator_consumer_supply omap3evm_vio_supply =
+ REGULATOR_SUPPLY("vcc", "spi1.0");
+
+/* VIO for ads7846 */
+static struct regulator_init_data omap3evm_vio = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap3evm_vio_supply,
+};
+
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+
+#define OMAP3EVM_WLAN_PMENA_GPIO (150)
+#define OMAP3EVM_WLAN_IRQ_GPIO (149)
+
+static struct regulator_consumer_supply omap3evm_vmmc2_supply =
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
+
+/* VMMC2 for driving the WL12xx module */
+static struct regulator_init_data omap3evm_vmmc2 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap3evm_vmmc2_supply,
+};
+
+static struct fixed_voltage_config omap3evm_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.80V */
+ .gpio = OMAP3EVM_WLAN_PMENA_GPIO,
+ .startup_delay = 70000, /* 70ms */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &omap3evm_vmmc2,
+};
+
+static struct platform_device omap3evm_wlan_regulator = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &omap3evm_vwlan,
+ },
+};
+
+struct wl12xx_platform_data omap3evm_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(OMAP3EVM_WLAN_IRQ_GPIO),
+ .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
+};
+#endif
+
static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -550,6 +649,7 @@ static struct twl4030_platform_data omap3evm_twldata = {
.codec = &omap3evm_codec_data,
.vdac = &omap3_evm_vdac,
.vpll2 = &omap3_evm_vpll2,
+ .vio = &omap3evm_vio,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
@@ -625,19 +725,12 @@ static struct spi_board_info omap3evm_spi_board_info[] = {
static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
};
-static void __init omap3_evm_init_irq(void)
+static void __init omap3_evm_init_early(void)
{
- omap_board_config = omap3_evm_config;
- omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params, NULL);
- omap_init_irq();
}
-static struct platform_device *omap3_evm_devices[] __initdata = {
- &omap3_evm_dss_device,
-};
-
static struct usbhs_omap_board_data usbhs_bdata __initdata = {
.port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -652,14 +745,76 @@ static struct usbhs_omap_board_data usbhs_bdata __initdata = {
};
#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
+static struct omap_board_mux omap35x_board_mux[] __initdata = {
+ OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW |
+ OMAP_PIN_OFF_WAKEUPENABLE),
+ OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW |
+ OMAP_PIN_OFF_WAKEUPENABLE),
+ OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_NONE),
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+ /* WLAN IRQ - GPIO 149 */
+ OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+
+ /* WLAN POWER ENABLE - GPIO 150 */
+ OMAP3_MUX(UART1_CTS, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+ /* MMC2 SDIO pin muxes for WL12xx */
+ OMAP3_MUX(SDMMC2_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+#endif
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static struct omap_board_mux omap36x_board_mux[] __initdata = {
OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP |
OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW |
OMAP_PIN_OFF_WAKEUPENABLE),
OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP |
- OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW),
+ OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW |
+ OMAP_PIN_OFF_WAKEUPENABLE),
+ /* AM/DM37x EVM: DSS data bus muxed with sys_boot */
+ OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT0, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT1, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT3, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+ OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE),
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+ /* WLAN IRQ - GPIO 149 */
+ OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+
+ /* WLAN POWER ENABLE - GPIO 150 */
+ OMAP3_MUX(UART1_CTS, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+ /* MMC2 SDIO pin muxes for WL12xx */
+ OMAP3_MUX(SDMMC2_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(SDMMC2_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+#endif
+
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+#else
+#define omap35x_board_mux NULL
+#define omap36x_board_mux NULL
#endif
static struct omap_musb_board_data musb_board_data = {
@@ -671,11 +826,18 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap3_evm_init(void)
{
omap3_evm_get_revision();
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+ if (cpu_is_omap3630())
+ omap3_mux_init(omap36x_board_mux, OMAP_PACKAGE_CBB);
+ else
+ omap3_mux_init(omap35x_board_mux, OMAP_PACKAGE_CBB);
+
+ omap_board_config = omap3_evm_config;
+ omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
omap3_evm_i2c_init();
- platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
+ omap_display_init(&omap3_evm_dss_data);
spi_register_board_info(omap3evm_spi_board_info,
ARRAY_SIZE(omap3evm_spi_board_info));
@@ -715,14 +877,22 @@ static void __init omap3_evm_init(void)
ads7846_dev_init();
omap3evm_init_smsc911x();
omap3_evm_display_init();
+
+#ifdef CONFIG_WL12XX_PLATFORM_DATA
+ /* WL12xx WLAN Init */
+ if (wl12xx_set_platform_data(&omap3evm_wlan_data))
+ pr_err("error setting wl12xx data\n");
+ platform_device_register(&omap3evm_wlan_regulator);
+#endif
}
MACHINE_START(OMAP3EVM, "OMAP3 EVM")
/* Maintainer: Syed Mohammed Khasim - Texas Instruments */
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap3_evm_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap3_evm_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap3_evm_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 15e4b08e99ba..b726943d7c93 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -195,11 +195,10 @@ static inline void __init board_smsc911x_init(void)
gpmc_smsc911x_init(&board_smsc911x_data);
}
-static void __init omap3logic_init_irq(void)
+static void __init omap3logic_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- omap_init_irq();
}
#ifdef CONFIG_OMAP_MUX
@@ -225,7 +224,8 @@ static void __init omap3logic_init(void)
MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
.boot_params = 0x80000100,
.map_io = omap3_map_io,
- .init_irq = omap3logic_init_irq,
+ .init_early = omap3logic_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap3logic_init,
.timer = &omap_timer,
MACHINE_END
@@ -233,7 +233,8 @@ MACHINE_END
MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
.boot_params = 0x80000100,
.map_io = omap3_map_io,
- .init_irq = omap3logic_init_irq,
+ .init_early = omap3logic_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap3logic_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index aa05f2e46a61..2e5dc21e3477 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -253,14 +253,6 @@ static struct omap_dss_board_info pandora_dss_data = {
.default_device = &pandora_lcd_device,
};
-static struct platform_device pandora_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &pandora_dss_data,
- },
-};
-
static void pandora_wl1251_init_card(struct mmc_card *card)
{
/*
@@ -341,13 +333,13 @@ static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
};
static struct regulator_consumer_supply pandora_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
static struct regulator_consumer_supply pandora_vmmc2_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
static struct regulator_consumer_supply pandora_vmmc3_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.2");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2");
static struct regulator_consumer_supply pandora_vdda_dac_supply =
REGULATOR_SUPPLY("vdda_dac", "omapdss");
@@ -524,9 +516,7 @@ static struct twl4030_usb_data omap3pandora_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static struct twl4030_codec_audio_data omap3pandora_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data omap3pandora_audio_data;
static struct twl4030_codec_data omap3pandora_codec_data = {
.audio_mclk = 26000000,
@@ -634,12 +624,11 @@ static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
}
};
-static void __init omap3pandora_init_irq(void)
+static void __init omap3pandora_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
- omap_init_irq();
}
static void __init pandora_wl1251_init(void)
@@ -677,7 +666,6 @@ fail:
static struct platform_device *omap3pandora_devices[] __initdata = {
&pandora_leds_gpio,
&pandora_keys_gpio,
- &pandora_dss_device,
&pandora_vwlan_device,
};
@@ -712,6 +700,7 @@ static void __init omap3pandora_init(void)
pandora_wl1251_init();
platform_add_devices(omap3pandora_devices,
ARRAY_SIZE(omap3pandora_devices));
+ omap_display_init(&pandora_dss_data);
omap_serial_init();
spi_register_board_info(omap3pandora_spi_board_info,
ARRAY_SIZE(omap3pandora_spi_board_info));
@@ -727,9 +716,10 @@ static void __init omap3pandora_init(void)
MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap3pandora_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap3pandora_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap3pandora_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index f6c87787cd4f..8ebdbc38b9de 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -240,14 +240,6 @@ static struct omap_dss_board_info omap3_stalker_dss_data = {
.default_device = &omap3_stalker_dvi_device,
};
-static struct platform_device omap3_stalker_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &omap3_stalker_dss_data,
- },
-};
-
static struct regulator_consumer_supply omap3stalker_vmmc1_supply = {
.supply = "vmmc",
};
@@ -439,19 +431,15 @@ static struct twl4030_madc_platform_data omap3stalker_madc_data = {
.irq_line = 1,
};
-static struct twl4030_codec_audio_data omap3stalker_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data omap3stalker_audio_data;
static struct twl4030_codec_data omap3stalker_codec_data = {
.audio_mclk = 26000000,
.audio = &omap3stalker_audio_data,
};
-static struct regulator_consumer_supply omap3_stalker_vdda_dac_supply = {
- .supply = "vdda_dac",
- .dev = &omap3_stalker_dss_device.dev,
-};
+static struct regulator_consumer_supply omap3_stalker_vdda_dac_supply =
+ REGULATOR_SUPPLY("vdda_dac", "omapdss");
/* VDAC for DSS driving S-Video */
static struct regulator_init_data omap3_stalker_vdac = {
@@ -469,10 +457,8 @@ static struct regulator_init_data omap3_stalker_vdac = {
};
/* VPLL2 for digital video outputs */
-static struct regulator_consumer_supply omap3_stalker_vpll2_supply = {
- .supply = "vdds_dsi",
- .dev = &omap3_stalker_lcd_device.dev,
-};
+static struct regulator_consumer_supply omap3_stalker_vpll2_supply =
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
static struct regulator_init_data omap3_stalker_vpll2 = {
.constraints = {
@@ -591,12 +577,14 @@ static struct spi_board_info omap3stalker_spi_board_info[] = {
static struct omap_board_config_kernel omap3_stalker_config[] __initdata = {
};
-static void __init omap3_stalker_init_irq(void)
+static void __init omap3_stalker_init_early(void)
{
- omap_board_config = omap3_stalker_config;
- omap_board_config_size = ARRAY_SIZE(omap3_stalker_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params, NULL);
+}
+
+static void __init omap3_stalker_init_irq(void)
+{
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(12);
@@ -604,7 +592,6 @@ static void __init omap3_stalker_init_irq(void)
}
static struct platform_device *omap3_stalker_devices[] __initdata = {
- &omap3_stalker_dss_device,
&keys_gpio,
};
@@ -638,12 +625,15 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap3_stalker_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
+ omap_board_config = omap3_stalker_config;
+ omap_board_config_size = ARRAY_SIZE(omap3_stalker_config);
omap3_stalker_i2c_init();
platform_add_devices(omap3_stalker_devices,
ARRAY_SIZE(omap3_stalker_devices));
+ omap_display_init(&omap3_stalker_dss_data);
spi_register_board_info(omap3stalker_spi_board_info,
ARRAY_SIZE(omap3stalker_spi_board_info));
@@ -666,6 +656,7 @@ MACHINE_START(SBC3530, "OMAP3 STALKER")
/* Maintainer: Jason Lam -lzg@ema-tech.com */
.boot_params = 0x80000100,
.map_io = omap3_map_io,
+ .init_early = omap3_stalker_init_early,
.init_irq = omap3_stalker_init_irq,
.init_machine = omap3_stalker_init,
.timer = &omap_timer,
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 84cfddb19a74..127cb1752bdd 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -252,9 +252,7 @@ static struct twl4030_usb_data touchbook_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
-static struct twl4030_codec_audio_data touchbook_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data touchbook_audio_data;
static struct twl4030_codec_data touchbook_codec_data = {
.audio_mclk = 26000000,
@@ -415,14 +413,15 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static void __init omap3_touchbook_init_irq(void)
+static void __init omap3_touchbook_init_early(void)
{
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap_board_config = omap3_touchbook_config;
- omap_board_config_size = ARRAY_SIZE(omap3_touchbook_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
+}
+
+static void __init omap3_touchbook_init_irq(void)
+{
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
omap2_gp_clockevent_set_gptimer(12);
@@ -510,6 +509,10 @@ static struct omap_musb_board_data musb_board_data = {
static void __init omap3_touchbook_init(void)
{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_board_config = omap3_touchbook_config;
+ omap_board_config_size = ARRAY_SIZE(omap3_touchbook_config);
+
pm_power_off = omap3_touchbook_poweroff;
omap3_touchbook_i2c_init();
@@ -538,8 +541,9 @@ static void __init omap3_touchbook_init(void)
MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
/* Maintainer: Gregoire Gentil - http://www.alwaysinnovating.com */
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = omap3_touchbook_init_early,
.init_irq = omap3_touchbook_init_irq,
.init_machine = omap3_touchbook_init,
.timer = &omap_timer,
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index ed61c1f5d5e6..0f4d8a762a70 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -26,6 +26,8 @@
#include <linux/usb/otg.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -45,6 +47,18 @@
#define GPIO_HUB_POWER 1
#define GPIO_HUB_NRESET 62
+#define GPIO_WIFI_PMENA 43
+#define GPIO_WIFI_IRQ 53
+
+/* wl127x BT, FM, GPS connectivity chip */
+static int wl1271_gpios[] = {46, -1, -1};
+static struct platform_device wl1271_device = {
+ .name = "kim",
+ .id = -1,
+ .dev = {
+ .platform_data = &wl1271_gpios,
+ },
+};
static struct gpio_led gpio_leds[] = {
{
@@ -74,13 +88,13 @@ static struct platform_device leds_gpio = {
static struct platform_device *panda_devices[] __initdata = {
&leds_gpio,
+ &wl1271_device,
};
-static void __init omap4_panda_init_irq(void)
+static void __init omap4_panda_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(NULL, NULL);
- gic_init_irq();
}
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
@@ -163,16 +177,62 @@ static struct omap2_hsmmc_info mmc[] = {
.gpio_wp = -EINVAL,
.gpio_cd = -EINVAL,
},
+ {
+ .name = "wl1271",
+ .mmc = 5,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .ocr_mask = MMC_VDD_165_195,
+ .nonremovable = true,
+ },
{} /* Terminator */
};
static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
{
.supply = "vmmc",
- .dev_name = "mmci-omap-hs.0",
+ .dev_name = "omap_hsmmc.0",
},
};
+static struct regulator_consumer_supply omap4_panda_vmmc5_supply = {
+ .supply = "vmmc",
+ .dev_name = "omap_hsmmc.4",
+};
+
+static struct regulator_init_data panda_vmmc5 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap4_panda_vmmc5_supply,
+};
+
+static struct fixed_voltage_config panda_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = GPIO_WIFI_PMENA,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &panda_vmmc5,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &panda_vwlan,
+ },
+};
+
+struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
+ /* PANDA ref clock is 38.4 MHz */
+ .board_ref_clock = 2,
+};
+
static int omap4_twl6030_hsmmc_late_init(struct device *dev)
{
int ret = 0;
@@ -306,7 +366,6 @@ static struct regulator_init_data omap4_panda_vana = {
.constraints = {
.min_uV = 2100000,
.max_uV = 2100000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -318,7 +377,6 @@ static struct regulator_init_data omap4_panda_vcxio = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -330,7 +388,6 @@ static struct regulator_init_data omap4_panda_vdac = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
- .apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
@@ -392,10 +449,90 @@ static int __init omap4_panda_i2c_init(void)
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ /* WLAN IRQ - GPIO 53 */
+ OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT),
+ /* WLAN POWER ENABLE - GPIO 43 */
+ OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* WLAN SDIO: MMC5 CMD */
+ OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 CLK */
+ OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 DAT[0-3] */
+ OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
+
+static struct omap_device_pad serial2_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart2_cts.uart2_cts",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rts.uart2_rts",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_rx.uart2_rx",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart2_tx.uart2_tx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial3_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart3_cts_rctx.uart3_cts_rctx",
+ OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rts_sd.uart3_rts_sd",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_rx_irrx.uart3_rx_irrx",
+ OMAP_PIN_INPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart3_tx_irtx.uart3_tx_irtx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_device_pad serial4_pads[] __initdata = {
+ OMAP_MUX_STATIC("uart4_rx.uart4_rx",
+ OMAP_PIN_INPUT | OMAP_MUX_MODE0),
+ OMAP_MUX_STATIC("uart4_tx.uart4_tx",
+ OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+};
+
+static struct omap_board_data serial2_data = {
+ .id = 1,
+ .pads = serial2_pads,
+ .pads_cnt = ARRAY_SIZE(serial2_pads),
+};
+
+static struct omap_board_data serial3_data = {
+ .id = 2,
+ .pads = serial3_pads,
+ .pads_cnt = ARRAY_SIZE(serial3_pads),
+};
+
+static struct omap_board_data serial4_data = {
+ .id = 3,
+ .pads = serial4_pads,
+ .pads_cnt = ARRAY_SIZE(serial4_pads),
+};
+
+static inline void board_serial_init(void)
+{
+ struct omap_board_data bdata;
+ bdata.flags = 0;
+ bdata.pads = NULL;
+ bdata.pads_cnt = 0;
+ bdata.id = 0;
+ /* pass dummy data for UART1 */
+ omap_serial_init_port(&bdata);
+
+ omap_serial_init_port(&serial2_data);
+ omap_serial_init_port(&serial3_data);
+ omap_serial_init_port(&serial4_data);
+}
#else
#define board_mux NULL
+
+static inline void board_serial_init(void)
+{
+ omap_serial_init();
+}
#endif
static void __init omap4_panda_init(void)
@@ -406,9 +543,13 @@ static void __init omap4_panda_init(void)
package = OMAP_PACKAGE_CBL;
omap4_mux_init(board_mux, package);
+ if (wl12xx_set_platform_data(&omap_panda_wlan_data))
+ pr_err("error setting wl12xx data\n");
+
omap4_panda_i2c_init();
platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
- omap_serial_init();
+ platform_device_register(&omap_vwlan_device);
+ board_serial_init();
omap4_twl6030_hsmmc_init(mmc);
omap4_ehci_init();
usb_musb_init(&musb_board_data);
@@ -425,7 +566,8 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
.boot_params = 0x80000100,
.reserve = omap_reserve,
.map_io = omap4_panda_map_io,
- .init_irq = omap4_panda_init_irq,
+ .init_early = omap4_panda_init_early,
+ .init_irq = gic_init_irq,
.init_machine = omap4_panda_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 08770ccec0f3..d0961945c65a 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -358,9 +358,7 @@ static struct regulator_init_data overo_vmmc1 = {
.consumer_supplies = &overo_vmmc1_supply,
};
-static struct twl4030_codec_audio_data overo_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data overo_audio_data;
static struct twl4030_codec_data overo_codec_data = {
.audio_mclk = 26000000,
@@ -409,14 +407,11 @@ static struct omap_board_config_kernel overo_config[] __initdata = {
{ OMAP_TAG_LCD, &overo_lcd_config },
};
-static void __init overo_init_irq(void)
+static void __init overo_init_early(void)
{
- omap_board_config = overo_config;
- omap_board_config_size = ARRAY_SIZE(overo_config);
omap2_init_common_infrastructure();
omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
mt46h32m32lf6_sdrc_params);
- omap_init_irq();
}
static struct platform_device *overo_devices[] __initdata = {
@@ -449,6 +444,8 @@ static struct omap_musb_board_data musb_board_data = {
static void __init overo_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_board_config = overo_config;
+ omap_board_config_size = ARRAY_SIZE(overo_config);
overo_i2c_init();
platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices));
omap_serial_init();
@@ -501,9 +498,10 @@ static void __init overo_init(void)
MACHINE_START(OVERO, "Gumstix Overo")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = overo_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = overo_init_early,
+ .init_irq = omap_init_irq,
.init_machine = overo_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index 39a71bb8a308..2af8b05e786d 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -33,7 +33,7 @@
#include "sdram-nokia.h"
static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1"),
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
};
/* Fixed regulator for internal eMMC */
@@ -138,14 +138,13 @@ static void __init rm680_peripherals_init(void)
omap2_hsmmc_init(mmc);
}
-static void __init rm680_init_irq(void)
+static void __init rm680_init_early(void)
{
struct omap_sdrc_params *sdrc_params;
omap2_init_common_infrastructure();
sdrc_params = nokia_get_sdram_timings();
omap2_init_common_devices(sdrc_params, sdrc_params);
- omap_init_irq();
}
#ifdef CONFIG_OMAP_MUX
@@ -176,9 +175,10 @@ static void __init rm680_map_io(void)
MACHINE_START(NOKIA_RM680, "Nokia RM-680 board")
.boot_params = 0x80000100,
- .map_io = rm680_map_io,
.reserve = omap_reserve,
- .init_irq = rm680_init_irq,
+ .map_io = rm680_map_io,
+ .init_early = rm680_init_early,
+ .init_irq = omap_init_irq,
.init_machine = rm680_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index e75e240cad67..5f1900c532ec 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -36,6 +36,8 @@
#include <sound/tlv320aic3x.h>
#include <sound/tpa6130a2-plat.h>
+#include <media/radio-si4713.h>
+#include <media/si4713.h>
#include <../drivers/staging/iio/light/tsl2563.h>
@@ -47,6 +49,8 @@
#define RX51_WL1251_POWER_GPIO 87
#define RX51_WL1251_IRQ_GPIO 42
+#define RX51_FMTX_RESET_GPIO 163
+#define RX51_FMTX_IRQ 53
/* list all spi devices here */
enum {
@@ -331,13 +335,13 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
};
static struct regulator_consumer_supply rx51_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
static struct regulator_consumer_supply rx51_vaux3_supply =
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
static struct regulator_consumer_supply rx51_vsim_supply =
- REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
+ REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
static struct regulator_consumer_supply rx51_vmmc2_supplies[] = {
/* tlv320aic3x analog supplies */
@@ -348,7 +352,7 @@ static struct regulator_consumer_supply rx51_vmmc2_supplies[] = {
/* tpa6130a2 */
REGULATOR_SUPPLY("Vdd", "2-0060"),
/* Keep vmmc as last item. It is not iterated for newer boards */
- REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1"),
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
};
static struct regulator_consumer_supply rx51_vio_supplies[] = {
@@ -357,10 +361,14 @@ static struct regulator_consumer_supply rx51_vio_supplies[] = {
REGULATOR_SUPPLY("DVDD", "2-0018"),
REGULATOR_SUPPLY("IOVDD", "2-0019"),
REGULATOR_SUPPLY("DVDD", "2-0019"),
+ /* Si4713 IO supply */
+ REGULATOR_SUPPLY("vio", "2-0063"),
};
static struct regulator_consumer_supply rx51_vaux1_consumers[] = {
REGULATOR_SUPPLY("vdds_sdi", "omapdss"),
+ /* Si4713 supply */
+ REGULATOR_SUPPLY("vdd", "2-0063"),
};
static struct regulator_consumer_supply rx51_vdac_supply[] = {
@@ -511,6 +519,41 @@ static struct regulator_init_data rx51_vio = {
.consumer_supplies = rx51_vio_supplies,
};
+static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = {
+ .gpio_reset = RX51_FMTX_RESET_GPIO,
+};
+
+static struct i2c_board_info rx51_si4713_board_info __initdata_or_module = {
+ I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
+ .platform_data = &rx51_si4713_i2c_data,
+};
+
+static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = {
+ .i2c_bus = 2,
+ .subdev_board_info = &rx51_si4713_board_info,
+};
+
+static struct platform_device rx51_si4713_dev __initdata_or_module = {
+ .name = "radio-si4713",
+ .id = -1,
+ .dev = {
+ .platform_data = &rx51_si4713_data,
+ },
+};
+
+static __init void rx51_init_si4713(void)
+{
+ int err;
+
+ err = gpio_request_one(RX51_FMTX_IRQ, GPIOF_DIR_IN, "si4713 irq");
+ if (err) {
+ printk(KERN_ERR "Cannot request si4713 irq gpio. %d\n", err);
+ return;
+ }
+ rx51_si4713_board_info.irq = gpio_to_irq(RX51_FMTX_IRQ);
+ platform_device_register(&rx51_si4713_dev);
+}
+
static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
{
/* FIXME this gpio setup is just a placeholder for now */
@@ -699,6 +742,14 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
.resource_config = twl4030_rconfig,
};
+struct twl4030_codec_vibra_data rx51_vibra_data __initdata = {
+ .coexist = 0,
+};
+
+struct twl4030_codec_data rx51_codec_data __initdata = {
+ .audio_mclk = 26000000,
+ .vibra = &rx51_vibra_data,
+};
static struct twl4030_platform_data rx51_twldata __initdata = {
.irq_base = TWL4030_IRQ_BASE,
@@ -710,6 +761,7 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
.madc = &rx51_madc_data,
.usb = &rx51_usb_data,
.power = &rx51_t2scripts_data,
+ .codec = &rx51_codec_data,
.vaux1 = &rx51_vaux1,
.vaux2 = &rx51_vaux2,
@@ -921,6 +973,7 @@ void __init rx51_peripherals_init(void)
board_smc91x_init();
rx51_add_gpio_keys();
rx51_init_wl1251();
+ rx51_init_si4713();
spi_register_board_info(rx51_peripherals_spi_board_info,
ARRAY_SIZE(rx51_peripherals_spi_board_info));
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
index acd670054d9a..89a66db8b77d 100644
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -66,18 +66,6 @@ static struct omap_dss_board_info rx51_dss_board_info = {
.default_device = &rx51_lcd_device,
};
-struct platform_device rx51_display_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &rx51_dss_board_info,
- },
-};
-
-static struct platform_device *rx51_video_devices[] __initdata = {
- &rx51_display_device,
-};
-
static int __init rx51_video_init(void)
{
if (!machine_is_nokia_rx51())
@@ -95,8 +83,7 @@ static int __init rx51_video_init(void)
gpio_direction_output(RX51_LCD_RESET_GPIO, 1);
- platform_add_devices(rx51_video_devices,
- ARRAY_SIZE(rx51_video_devices));
+ omap_display_init(&rx51_dss_board_info);
return 0;
}
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index f53fc551c58f..e964895b80e8 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -98,17 +98,13 @@ static struct omap_board_config_kernel rx51_config[] = {
{ OMAP_TAG_LCD, &rx51_lcd_config },
};
-static void __init rx51_init_irq(void)
+static void __init rx51_init_early(void)
{
struct omap_sdrc_params *sdrc_params;
- omap_board_config = rx51_config;
- omap_board_config_size = ARRAY_SIZE(rx51_config);
- omap3_pm_init_cpuidle(rx51_cpuidle_params);
omap2_init_common_infrastructure();
sdrc_params = nokia_get_sdram_timings();
omap2_init_common_devices(sdrc_params, sdrc_params);
- omap_init_irq();
}
extern void __init rx51_peripherals_init(void);
@@ -128,6 +124,9 @@ static struct omap_musb_board_data musb_board_data = {
static void __init rx51_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap_board_config = rx51_config;
+ omap_board_config_size = ARRAY_SIZE(rx51_config);
+ omap3_pm_init_cpuidle(rx51_cpuidle_params);
omap_serial_init();
usb_musb_init(&musb_board_data);
rx51_peripherals_init();
@@ -149,9 +148,10 @@ static void __init rx51_map_io(void)
MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
/* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
.boot_params = 0x80000100,
- .map_io = rx51_map_io,
.reserve = omap_reserve,
- .init_irq = rx51_init_irq,
+ .map_io = rx51_map_io,
+ .init_early = rx51_init_early,
+ .init_irq = omap_init_irq,
.init_machine = rx51_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c
new file mode 100644
index 000000000000..09fa7bfff8d6
--- /dev/null
+++ b/arch/arm/mach-omap2/board-ti8168evm.c
@@ -0,0 +1,62 @@
+/*
+ * Code for TI8168 EVM.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/irqs.h>
+#include <plat/board.h>
+#include <plat/common.h>
+
+static struct omap_board_config_kernel ti8168_evm_config[] __initdata = {
+};
+
+static void __init ti8168_init_early(void)
+{
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(NULL, NULL);
+}
+
+static void __init ti8168_evm_init_irq(void)
+{
+ omap_init_irq();
+}
+
+static void __init ti8168_evm_init(void)
+{
+ omap_serial_init();
+ omap_board_config = ti8168_evm_config;
+ omap_board_config_size = ARRAY_SIZE(ti8168_evm_config);
+}
+
+static void __init ti8168_evm_map_io(void)
+{
+ omap2_set_globals_ti816x();
+ omapti816x_map_common_io();
+}
+
+MACHINE_START(TI8168EVM, "ti8168evm")
+ /* Maintainer: Texas Instruments */
+ .boot_params = 0x80000100,
+ .map_io = ti8168_evm_map_io,
+ .init_early = ti8168_init_early,
+ .init_irq = ti8168_evm_init_irq,
+ .timer = &omap_timer,
+ .init_machine = ti8168_evm_init,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index 6bcd43657aed..37b84c2b850f 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -130,14 +130,6 @@ static struct omap_dss_board_info zoom_dss_data = {
.default_device = &zoom_lcd_device,
};
-static struct platform_device zoom_dss_device = {
- .name = "omapdss",
- .id = -1,
- .dev = {
- .platform_data = &zoom_dss_data,
- },
-};
-
static struct omap2_mcspi_device_config dss_lcd_mcspi_config = {
.turbo_mode = 1,
.single_channel = 1, /* 0: slave, 1: master */
@@ -153,14 +145,9 @@ static struct spi_board_info nec_8048_spi_board_info[] __initdata = {
},
};
-static struct platform_device *zoom_display_devices[] __initdata = {
- &zoom_dss_device,
-};
-
void __init zoom_display_init(void)
{
- platform_add_devices(zoom_display_devices,
- ARRAY_SIZE(zoom_display_devices));
+ omap_display_init(&zoom_dss_data);
spi_register_board_info(nec_8048_spi_board_info,
ARRAY_SIZE(nec_8048_spi_board_info));
zoom_lcd_panel_init();
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index e0e040f34c68..448ab60195d5 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -118,7 +118,7 @@ static struct regulator_consumer_supply zoom_vmmc2_supply = {
static struct regulator_consumer_supply zoom_vmmc3_supply = {
.supply = "vmmc",
- .dev_name = "mmci-omap-hs.2",
+ .dev_name = "omap_hsmmc.2",
};
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
@@ -322,9 +322,7 @@ static struct twl4030_madc_platform_data zoom_madc_data = {
.irq_line = 1,
};
-static struct twl4030_codec_audio_data zoom_audio_data = {
- .audio_mclk = 26000000,
-};
+static struct twl4030_codec_audio_data zoom_audio_data;
static struct twl4030_codec_data zoom_codec_data = {
.audio_mclk = 26000000,
diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c
index 1dd195afa396..4b133d75c935 100644
--- a/arch/arm/mach-omap2/board-zoom.c
+++ b/arch/arm/mach-omap2/board-zoom.c
@@ -16,6 +16,7 @@
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
+#include <linux/mtd/nand.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -33,7 +34,7 @@
#define ZOOM3_EHCI_RESET_GPIO 64
-static void __init omap_zoom_init_irq(void)
+static void __init omap_zoom_init_early(void)
{
omap2_init_common_infrastructure();
if (machine_is_omap_zoom2())
@@ -42,14 +43,12 @@ static void __init omap_zoom_init_irq(void)
else if (machine_is_omap_zoom3())
omap2_init_common_devices(h8mbx00u0mer0em_sdrc_params,
h8mbx00u0mer0em_sdrc_params);
-
- omap_init_irq();
}
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
/* WLAN IRQ - GPIO 162 */
- OMAP3_MUX(MCBSP1_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
+ OMAP3_MUX(MCBSP1_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
/* WLAN POWER ENABLE - GPIO 101 */
OMAP3_MUX(CAM_D2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
/* WLAN SDIO: MMC3 CMD */
@@ -126,8 +125,8 @@ static void __init omap_zoom_init(void)
usbhs_init(&usbhs_bdata);
}
- board_nand_init(zoom_nand_partitions,
- ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS);
+ board_nand_init(zoom_nand_partitions, ARRAY_SIZE(zoom_nand_partitions),
+ ZOOM_NAND_CS, NAND_BUSWIDTH_16);
zoom_debugboard_init();
zoom_peripherals_init();
zoom_display_init();
@@ -135,18 +134,20 @@ static void __init omap_zoom_init(void)
MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap_zoom_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap_zoom_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_zoom_init,
.timer = &omap_timer,
MACHINE_END
MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
.boot_params = 0x80000100,
- .map_io = omap3_map_io,
.reserve = omap_reserve,
- .init_irq = omap_zoom_init_irq,
+ .map_io = omap3_map_io,
+ .init_early = omap_zoom_init_early,
+ .init_irq = omap_init_irq,
.init_machine = omap_zoom_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/clkt2xxx_apll.c b/arch/arm/mach-omap2/clkt2xxx_apll.c
index f51cffd1fc53..b19a1f7234ae 100644
--- a/arch/arm/mach-omap2/clkt2xxx_apll.c
+++ b/arch/arm/mach-omap2/clkt2xxx_apll.c
@@ -78,6 +78,26 @@ static int omap2_clk_apll54_enable(struct clk *clk)
return omap2_clk_apll_enable(clk, OMAP24XX_ST_54M_APLL_MASK);
}
+static void _apll96_allow_idle(struct clk *clk)
+{
+ omap2xxx_cm_set_apll96_auto_low_power_stop();
+}
+
+static void _apll96_deny_idle(struct clk *clk)
+{
+ omap2xxx_cm_set_apll96_disable_autoidle();
+}
+
+static void _apll54_allow_idle(struct clk *clk)
+{
+ omap2xxx_cm_set_apll54_auto_low_power_stop();
+}
+
+static void _apll54_deny_idle(struct clk *clk)
+{
+ omap2xxx_cm_set_apll54_disable_autoidle();
+}
+
/* Stop APLL */
static void omap2_clk_apll_disable(struct clk *clk)
{
@@ -93,11 +113,15 @@ static void omap2_clk_apll_disable(struct clk *clk)
const struct clkops clkops_apll96 = {
.enable = omap2_clk_apll96_enable,
.disable = omap2_clk_apll_disable,
+ .allow_idle = _apll96_allow_idle,
+ .deny_idle = _apll96_deny_idle,
};
const struct clkops clkops_apll54 = {
.enable = omap2_clk_apll54_enable,
.disable = omap2_clk_apll_disable,
+ .allow_idle = _apll54_allow_idle,
+ .deny_idle = _apll54_deny_idle,
};
/* Public functions */
diff --git a/arch/arm/mach-omap2/clkt2xxx_dpll.c b/arch/arm/mach-omap2/clkt2xxx_dpll.c
new file mode 100644
index 000000000000..1502a7bc20bb
--- /dev/null
+++ b/arch/arm/mach-omap2/clkt2xxx_dpll.c
@@ -0,0 +1,63 @@
+/*
+ * OMAP2-specific DPLL control functions
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/clock.h>
+
+#include "clock.h"
+#include "cm2xxx_3xxx.h"
+#include "cm-regbits-24xx.h"
+
+/* Private functions */
+
+/**
+ * _allow_idle - enable DPLL autoidle bits
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Enable DPLL automatic idle control. The DPLL will enter low-power
+ * stop when its downstream clocks are gated. No return value.
+ * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1
+ * instead. Add some mechanism to optionally enter this mode.
+ */
+static void _allow_idle(struct clk *clk)
+{
+ if (!clk || !clk->dpll_data)
+ return;
+
+ omap2xxx_cm_set_dpll_auto_low_power_stop();
+}
+
+/**
+ * _deny_idle - prevent DPLL from automatically idling
+ * @clk: struct clk * of the DPLL to operate on
+ *
+ * Disable DPLL automatic idle control. No return value.
+ */
+static void _deny_idle(struct clk *clk)
+{
+ if (!clk || !clk->dpll_data)
+ return;
+
+ omap2xxx_cm_set_dpll_disable_autoidle();
+}
+
+
+/* Public data */
+
+const struct clkops clkops_omap2xxx_dpll_ops = {
+ .allow_idle = _allow_idle,
+ .deny_idle = _deny_idle,
+};
+
diff --git a/arch/arm/mach-omap2/clkt2xxx_osc.c b/arch/arm/mach-omap2/clkt2xxx_osc.c
index df7b80506483..c3460928b5e0 100644
--- a/arch/arm/mach-omap2/clkt2xxx_osc.c
+++ b/arch/arm/mach-omap2/clkt2xxx_osc.c
@@ -30,6 +30,13 @@
#include "prm2xxx_3xxx.h"
#include "prm-regbits-24xx.h"
+/*
+ * XXX This does not actually enable the osc_ck, since the osc_ck must
+ * be running for this function to be called. Instead, this function
+ * is used to disable an autoidle mode on the osc_ck. The existing
+ * clk_enable/clk_disable()-based usecounting for osc_ck should be
+ * replaced with autoidle-based usecounting.
+ */
static int omap2_enable_osc_ck(struct clk *clk)
{
u32 pcc;
@@ -41,6 +48,13 @@ static int omap2_enable_osc_ck(struct clk *clk)
return 0;
}
+/*
+ * XXX This does not actually disable the osc_ck, since doing so would
+ * immediately halt the system. Instead, this function is used to
+ * enable an autoidle mode on the osc_ck. The existing
+ * clk_enable/clk_disable()-based usecounting for osc_ck should be
+ * replaced with autoidle-based usecounting.
+ */
static void omap2_disable_osc_ck(struct clk *clk)
{
u32 pcc;
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index a781cd6795a4..e25364de028a 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -97,7 +97,7 @@ static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
u32 *field_val)
{
const struct clksel *clks;
- const struct clksel_rate *clkr, *max_clkr;
+ const struct clksel_rate *clkr, *max_clkr = NULL;
u8 max_div = 0;
clks = _get_clksel_by_parent(clk, src_clk);
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index acb7ae5b0a25..bcffee001bfa 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -178,12 +178,11 @@ void omap2_init_dpll_parent(struct clk *clk)
if (!dd)
return;
- /* Return bypass rate if DPLL is bypassed */
v = __raw_readl(dd->control_reg);
v &= dd->enable_mask;
v >>= __ffs(dd->enable_mask);
- /* Reparent in case the dpll is in bypass */
+ /* Reparent the struct clk in case the dpll is in bypass */
if (cpu_is_omap24xx()) {
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
@@ -260,50 +259,22 @@ u32 omap2_get_dpll_rate(struct clk *clk)
/* DPLL rate rounding code */
/**
- * omap2_dpll_set_rate_tolerance: set the error tolerance during rate rounding
- * @clk: struct clk * of the DPLL
- * @tolerance: maximum rate error tolerance
- *
- * Set the maximum DPLL rate error tolerance for the rate rounding
- * algorithm. The rate tolerance is an attempt to balance DPLL power
- * saving (the least divider value "n") vs. rate fidelity (the least
- * difference between the desired DPLL target rate and the rounded
- * rate out of the algorithm). So, increasing the tolerance is likely
- * to decrease DPLL power consumption and increase DPLL rate error.
- * Returns -EINVAL if provided a null clock ptr or a clk that is not a
- * DPLL; or 0 upon success.
- */
-int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance)
-{
- if (!clk || !clk->dpll_data)
- return -EINVAL;
-
- clk->dpll_data->rate_tolerance = tolerance;
-
- return 0;
-}
-
-/**
* omap2_dpll_round_rate - round a target rate for an OMAP DPLL
* @clk: struct clk * for a DPLL
* @target_rate: desired DPLL clock rate
*
- * Given a DPLL, a desired target rate, and a rate tolerance, round
- * the target rate to a possible, programmable rate for this DPLL.
- * Rate tolerance is assumed to be set by the caller before this
- * function is called. Attempts to select the minimum possible n
- * within the tolerance to reduce power consumption. Stores the
- * computed (m, n) in the DPLL's dpll_data structure so set_rate()
- * will not need to call this (expensive) function again. Returns ~0
- * if the target rate cannot be rounded, either because the rate is
- * too low or because the rate tolerance is set too tightly; or the
- * rounded rate upon success.
+ * Given a DPLL and a desired target rate, round the target rate to a
+ * possible, programmable rate for this DPLL. Attempts to select the
+ * minimum possible n. Stores the computed (m, n) in the DPLL's
+ * dpll_data structure so set_rate() will not need to call this
+ * (expensive) function again. Returns ~0 if the target rate cannot
+ * be rounded, or the rounded rate upon success.
*/
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
{
- int m, n, r, e, scaled_max_m;
- unsigned long scaled_rt_rp, new_rate;
- int min_e = -1, min_e_m = -1, min_e_n = -1;
+ int m, n, r, scaled_max_m;
+ unsigned long scaled_rt_rp;
+ unsigned long new_rate = 0;
struct dpll_data *dd;
if (!clk || !clk->dpll_data)
@@ -311,8 +282,8 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
dd = clk->dpll_data;
- pr_debug("clock: starting DPLL round_rate for clock %s, target rate "
- "%ld\n", clk->name, target_rate);
+ pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n",
+ clk->name, target_rate);
scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR);
scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
@@ -347,39 +318,23 @@ long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate)
if (r == DPLL_MULT_UNDERFLOW)
continue;
- e = target_rate - new_rate;
- pr_debug("clock: n = %d: m = %d: rate error is %d "
- "(new_rate = %ld)\n", n, m, e, new_rate);
-
- if (min_e == -1 ||
- min_e >= (int)(abs(e) - dd->rate_tolerance)) {
- min_e = e;
- min_e_m = m;
- min_e_n = n;
-
- pr_debug("clock: found new least error %d\n", min_e);
+ pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n",
+ clk->name, m, n, new_rate);
- /* We found good settings -- bail out now */
- if (min_e <= dd->rate_tolerance)
- break;
+ if (target_rate == new_rate) {
+ dd->last_rounded_m = m;
+ dd->last_rounded_n = n;
+ dd->last_rounded_rate = target_rate;
+ break;
}
}
- if (min_e < 0) {
- pr_debug("clock: error: target rate or tolerance too low\n");
+ if (target_rate != new_rate) {
+ pr_debug("clock: %s: cannot round to rate %ld\n", clk->name,
+ target_rate);
return ~0;
}
- dd->last_rounded_m = min_e_m;
- dd->last_rounded_n = min_e_n;
- dd->last_rounded_rate = _dpll_compute_new_rate(dd->clk_ref->rate,
- min_e_m, min_e_n);
-
- pr_debug("clock: final least error: e = %d, m = %d, n = %d\n",
- min_e, min_e_m, min_e_n);
- pr_debug("clock: final rate: %ld (target rate: %ld)\n",
- dd->last_rounded_rate, target_rate);
-
- return dd->last_rounded_rate;
+ return target_rate;
}
diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c
new file mode 100644
index 000000000000..3d43fba2542f
--- /dev/null
+++ b/arch/arm/mach-omap2/clkt_iclk.c
@@ -0,0 +1,82 @@
+/*
+ * OMAP2/3 interface clock control
+ *
+ * Copyright (C) 2011 Nokia Corporation
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/clock.h>
+#include <plat/prcm.h>
+
+#include "clock.h"
+#include "clock2xxx.h"
+#include "cm2xxx_3xxx.h"
+#include "cm-regbits-24xx.h"
+
+/* Private functions */
+
+/* XXX */
+void omap2_clkt_iclk_allow_idle(struct clk *clk)
+{
+ u32 v, r;
+
+ r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+
+ v = __raw_readl((__force void __iomem *)r);
+ v |= (1 << clk->enable_bit);
+ __raw_writel(v, (__force void __iomem *)r);
+}
+
+/* XXX */
+void omap2_clkt_iclk_deny_idle(struct clk *clk)
+{
+ u32 v, r;
+
+ r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+
+ v = __raw_readl((__force void __iomem *)r);
+ v &= ~(1 << clk->enable_bit);
+ __raw_writel(v, (__force void __iomem *)r);
+}
+
+/* Public data */
+
+const struct clkops clkops_omap2_iclk_dflt_wait = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .find_companion = omap2_clk_dflt_find_companion,
+ .find_idlest = omap2_clk_dflt_find_idlest,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
+const struct clkops clkops_omap2_iclk_dflt = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
+const struct clkops clkops_omap2_iclk_idle_only = {
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
+const struct clkops clkops_omap2_mdmclk_dflt_wait = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .find_companion = omap2_clk_dflt_find_companion,
+ .find_idlest = omap2_clk_dflt_find_idlest,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 2a2f15213add..180299e4a838 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -22,7 +22,9 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/bitops.h>
+#include <trace/events/power.h>
+#include <asm/cpu.h>
#include <plat/clock.h>
#include "clockdomain.h"
#include <plat/cpu.h>
@@ -261,10 +263,13 @@ void omap2_clk_disable(struct clk *clk)
pr_debug("clock: %s: disabling in hardware\n", clk->name);
- clk->ops->disable(clk);
+ if (clk->ops && clk->ops->disable) {
+ trace_clock_disable(clk->name, 0, smp_processor_id());
+ clk->ops->disable(clk);
+ }
if (clk->clkdm)
- omap2_clkdm_clk_disable(clk->clkdm, clk);
+ clkdm_clk_disable(clk->clkdm, clk);
if (clk->parent)
omap2_clk_disable(clk->parent);
@@ -304,7 +309,7 @@ int omap2_clk_enable(struct clk *clk)
}
if (clk->clkdm) {
- ret = omap2_clkdm_clk_enable(clk->clkdm, clk);
+ ret = clkdm_clk_enable(clk->clkdm, clk);
if (ret) {
WARN(1, "clock: %s: could not enable clockdomain %s: "
"%d\n", clk->name, clk->clkdm->name, ret);
@@ -312,17 +317,21 @@ int omap2_clk_enable(struct clk *clk)
}
}
- ret = clk->ops->enable(clk);
- if (ret) {
- WARN(1, "clock: %s: could not enable: %d\n", clk->name, ret);
- goto oce_err3;
+ if (clk->ops && clk->ops->enable) {
+ trace_clock_enable(clk->name, 1, smp_processor_id());
+ ret = clk->ops->enable(clk);
+ if (ret) {
+ WARN(1, "clock: %s: could not enable: %d\n",
+ clk->name, ret);
+ goto oce_err3;
+ }
}
return 0;
oce_err3:
if (clk->clkdm)
- omap2_clkdm_clk_disable(clk->clkdm, clk);
+ clkdm_clk_disable(clk->clkdm, clk);
oce_err2:
if (clk->parent)
omap2_clk_disable(clk->parent);
@@ -349,8 +358,10 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);
/* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
- if (clk->set_rate)
+ if (clk->set_rate) {
+ trace_clock_set_rate(clk->name, rate, smp_processor_id());
ret = clk->set_rate(clk, rate);
+ }
return ret;
}
@@ -373,10 +384,16 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
const struct clkops clkops_omap3_noncore_dpll_ops = {
.enable = omap3_noncore_dpll_enable,
.disable = omap3_noncore_dpll_disable,
+ .allow_idle = omap3_dpll_allow_idle,
+ .deny_idle = omap3_dpll_deny_idle,
};
-#endif
+const struct clkops clkops_omap3_core_dpll_ops = {
+ .allow_idle = omap3_dpll_allow_idle,
+ .deny_idle = omap3_dpll_deny_idle,
+};
+#endif
/*
* OMAP2+ clock reset and init functions
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 896584e3c4ab..e10ff2b54844 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -2,7 +2,7 @@
* linux/arch/arm/mach-omap2/clock.h
*
* Copyright (C) 2005-2009 Texas Instruments, Inc.
- * Copyright (C) 2004-2009 Nokia Corporation
+ * Copyright (C) 2004-2011 Nokia Corporation
*
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
@@ -18,9 +18,6 @@
#include <plat/clock.h>
-/* The maximum error between a target DPLL rate and the rounded rate in Hz */
-#define DEFAULT_DPLL_RATE_TOLERANCE 50000
-
/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
#define CORE_CLK_SRC_32K 0x0
#define CORE_CLK_SRC_DPLL 0x1
@@ -55,7 +52,6 @@ void omap2_clk_disable(struct clk *clk);
long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
int omap2_clk_set_rate(struct clk *clk, unsigned long rate);
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
-int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
unsigned long omap3_dpll_recalc(struct clk *clk);
unsigned long omap3_clkoutx2_recalc(struct clk *clk);
@@ -65,6 +61,9 @@ u32 omap3_dpll_autoidle_read(struct clk *clk);
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
int omap3_noncore_dpll_enable(struct clk *clk);
void omap3_noncore_dpll_disable(struct clk *clk);
+int omap4_dpllmx_gatectrl_read(struct clk *clk);
+void omap4_dpllmx_allow_gatectrl(struct clk *clk);
+void omap4_dpllmx_deny_gatectrl(struct clk *clk);
#ifdef CONFIG_OMAP_RESET_CLOCKS
void omap2_clk_disable_unused(struct clk *clk);
@@ -83,6 +82,10 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
+/* clkt_iclk.c public functions */
+extern void omap2_clkt_iclk_allow_idle(struct clk *clk);
+extern void omap2_clkt_iclk_deny_idle(struct clk *clk);
+
u32 omap2_get_dpll_rate(struct clk *clk);
void omap2_init_dpll_parent(struct clk *clk);
@@ -136,6 +139,7 @@ extern struct clk *vclk, *sclk;
extern const struct clksel_rate gpt_32k_rates[];
extern const struct clksel_rate gpt_sys_rates[];
extern const struct clksel_rate gfx_l3_rates[];
+extern const struct clksel_rate dsp_ick_rates[];
#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ)
extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
@@ -145,6 +149,13 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
#define omap2_clk_exit_cpufreq_table 0
#endif
+extern const struct clkops clkops_omap2_iclk_dflt_wait;
+extern const struct clkops clkops_omap2_iclk_dflt;
+extern const struct clkops clkops_omap2_iclk_idle_only;
+extern const struct clkops clkops_omap2_mdmclk_dflt_wait;
+extern const struct clkops clkops_omap2xxx_dpll_ops;
extern const struct clkops clkops_omap3_noncore_dpll_ops;
+extern const struct clkops clkops_omap3_core_dpll_ops;
+extern const struct clkops clkops_omap4_dpllmx_ops;
#endif
diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c
index 0a992bc8d0d8..b6f65d4ac97d 100644
--- a/arch/arm/mach-omap2/clock2420_data.c
+++ b/arch/arm/mach-omap2/clock2420_data.c
@@ -1,12 +1,12 @@
/*
- * linux/arch/arm/mach-omap2/clock2420_data.c
+ * OMAP2420 clock data
*
- * Copyright (C) 2005-2009 Texas Instruments, Inc.
- * Copyright (C) 2004-2010 Nokia Corporation
+ * Copyright (C) 2005-2009 Texas Instruments, Inc.
+ * Copyright (C) 2004-2011 Nokia Corporation
*
- * Contacts:
- * Richard Woodruff <r-woodruff2@ti.com>
- * Paul Walmsley
+ * Contacts:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -34,18 +34,15 @@
/*
* 2420 clock tree.
*
- * NOTE:In many cases here we are assigning a 'default' parent. In many
- * cases the parent is selectable. The get/set parent calls will also
- * switch sources.
- *
- * Many some clocks say always_enabled, but they can be auto idled for
- * power savings. They will always be available upon clock request.
+ * NOTE:In many cases here we are assigning a 'default' parent. In
+ * many cases the parent is selectable. The set parent calls will
+ * also switch sources.
*
* Several sources are given initial rates which may be wrong, this will
* be fixed up in the init func.
*
* Things are broadly separated below by clock domains. It is
- * noteworthy that most periferals have dependencies on multiple clock
+ * noteworthy that most peripherals have dependencies on multiple clock
* domains. Many get their interface clocks from the L4 domain, but get
* functional clocks from fixed sources or other core domain derived
* clocks.
@@ -55,7 +52,7 @@
static struct clk func_32k_ck = {
.name = "func_32k_ck",
.ops = &clkops_null,
- .rate = 32000,
+ .rate = 32768,
.clkdm_name = "wkup_clkdm",
};
@@ -116,7 +113,6 @@ static struct dpll_data dpll_dd = {
.max_multiplier = 1023,
.min_divider = 1,
.max_divider = 16,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
/*
@@ -125,7 +121,7 @@ static struct dpll_data dpll_dd = {
*/
static struct clk dpll_ck = {
.name = "dpll_ck",
- .ops = &clkops_null,
+ .ops = &clkops_omap2xxx_dpll_ops,
.parent = &sys_ck, /* Can be func_32k also */
.dpll_data = &dpll_dd,
.clkdm_name = "wkup_clkdm",
@@ -455,36 +451,22 @@ static struct clk dsp_fck = {
.recalc = &omap2_clksel_recalc,
};
-/* DSP interface clock */
-static const struct clksel_rate dsp_irate_ick_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_24XX },
- { .div = 2, .val = 2, .flags = RATE_IN_24XX },
- { .div = 0 },
-};
-
-static const struct clksel dsp_irate_ick_clksel[] = {
- { .parent = &dsp_fck, .rates = dsp_irate_ick_rates },
+static const struct clksel dsp_ick_clksel[] = {
+ { .parent = &dsp_fck, .rates = dsp_ick_rates },
{ .parent = NULL }
};
-/* This clock does not exist as such in the TRM. */
-static struct clk dsp_irate_ick = {
- .name = "dsp_irate_ick",
- .ops = &clkops_null,
- .parent = &dsp_fck,
- .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
- .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK,
- .clksel = dsp_irate_ick_clksel,
- .recalc = &omap2_clksel_recalc,
-};
-
-/* 2420 only */
static struct clk dsp_ick = {
.name = "dsp_ick", /* apparently ipi and isp */
- .ops = &clkops_omap2_dflt_wait,
- .parent = &dsp_irate_ick,
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &dsp_fck,
+ .clkdm_name = "dsp_clkdm",
.enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN),
.enable_bit = OMAP2420_EN_DSP_IPI_SHIFT, /* for ipi */
+ .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+ .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK,
+ .clksel = dsp_ick_clksel,
+ .recalc = &omap2_clksel_recalc,
};
/*
@@ -579,7 +561,7 @@ static const struct clksel usb_l4_ick_clksel[] = {
/* It is unclear from TRM whether usb_l4_ick is really in L3 or L4 clkdm */
static struct clk usb_l4_ick = { /* FS-USB interface clock */
.name = "usb_l4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l3_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -661,7 +643,7 @@ static struct clk ssi_ssr_sst_fck = {
*/
static struct clk ssi_l4_ick = {
.name = "ssi_l4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -716,6 +698,7 @@ static struct clk gfx_2d_fck = {
.recalc = &omap2_clksel_recalc,
};
+/* This interface clock does not have a CM_AUTOIDLE bit */
static struct clk gfx_ick = {
.name = "gfx_ick", /* From l3 */
.ops = &clkops_omap2_dflt_wait,
@@ -763,7 +746,7 @@ static const struct clksel dss1_fck_clksel[] = {
static struct clk dss_ick = { /* Enables both L3,L4 ICLK's */
.name = "dss_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ck, /* really both l3 and l4 */
.clkdm_name = "dss_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -825,6 +808,14 @@ static struct clk dss_54m_fck = { /* Alt clk used in power management */
.recalc = &followparent_recalc,
};
+static struct clk wu_l4_ick = {
+ .name = "wu_l4_ick",
+ .ops = &clkops_null,
+ .parent = &sys_ck,
+ .clkdm_name = "wkup_clkdm",
+ .recalc = &followparent_recalc,
+};
+
/*
* CORE power domain ICLK & FCLK defines.
* Many of the these can have more than one possible parent. Entries
@@ -845,9 +836,9 @@ static const struct clksel omap24xx_gpt_clksel[] = {
static struct clk gpt1_ick = {
.name = "gpt1_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_GPT1_SHIFT,
.recalc = &followparent_recalc,
@@ -871,7 +862,7 @@ static struct clk gpt1_fck = {
static struct clk gpt2_ick = {
.name = "gpt2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -895,7 +886,7 @@ static struct clk gpt2_fck = {
static struct clk gpt3_ick = {
.name = "gpt3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -919,7 +910,7 @@ static struct clk gpt3_fck = {
static struct clk gpt4_ick = {
.name = "gpt4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -943,7 +934,7 @@ static struct clk gpt4_fck = {
static struct clk gpt5_ick = {
.name = "gpt5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -967,7 +958,7 @@ static struct clk gpt5_fck = {
static struct clk gpt6_ick = {
.name = "gpt6_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -991,8 +982,9 @@ static struct clk gpt6_fck = {
static struct clk gpt7_ick = {
.name = "gpt7_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
+ .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP24XX_EN_GPT7_SHIFT,
.recalc = &followparent_recalc,
@@ -1014,7 +1006,7 @@ static struct clk gpt7_fck = {
static struct clk gpt8_ick = {
.name = "gpt8_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1038,7 +1030,7 @@ static struct clk gpt8_fck = {
static struct clk gpt9_ick = {
.name = "gpt9_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1062,7 +1054,7 @@ static struct clk gpt9_fck = {
static struct clk gpt10_ick = {
.name = "gpt10_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1086,7 +1078,7 @@ static struct clk gpt10_fck = {
static struct clk gpt11_ick = {
.name = "gpt11_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1110,7 +1102,7 @@ static struct clk gpt11_fck = {
static struct clk gpt12_ick = {
.name = "gpt12_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1134,7 +1126,7 @@ static struct clk gpt12_fck = {
static struct clk mcbsp1_ick = {
.name = "mcbsp1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1174,7 +1166,7 @@ static struct clk mcbsp1_fck = {
static struct clk mcbsp2_ick = {
.name = "mcbsp2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1198,7 +1190,7 @@ static struct clk mcbsp2_fck = {
static struct clk mcspi1_ick = {
.name = "mcspi1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1218,7 +1210,7 @@ static struct clk mcspi1_fck = {
static struct clk mcspi2_ick = {
.name = "mcspi2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1238,7 +1230,7 @@ static struct clk mcspi2_fck = {
static struct clk uart1_ick = {
.name = "uart1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1258,7 +1250,7 @@ static struct clk uart1_fck = {
static struct clk uart2_ick = {
.name = "uart2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1278,7 +1270,7 @@ static struct clk uart2_fck = {
static struct clk uart3_ick = {
.name = "uart3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1298,9 +1290,9 @@ static struct clk uart3_fck = {
static struct clk gpios_ick = {
.name = "gpios_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_GPIOS_SHIFT,
.recalc = &followparent_recalc,
@@ -1318,9 +1310,9 @@ static struct clk gpios_fck = {
static struct clk mpu_wdt_ick = {
.name = "mpu_wdt_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
.recalc = &followparent_recalc,
@@ -1338,10 +1330,10 @@ static struct clk mpu_wdt_fck = {
static struct clk sync_32k_ick = {
.name = "sync_32k_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_32KSYNC_SHIFT,
.recalc = &followparent_recalc,
@@ -1349,9 +1341,9 @@ static struct clk sync_32k_ick = {
static struct clk wdt1_ick = {
.name = "wdt1_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_WDT1_SHIFT,
.recalc = &followparent_recalc,
@@ -1359,10 +1351,10 @@ static struct clk wdt1_ick = {
static struct clk omapctrl_ick = {
.name = "omapctrl_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_OMAPCTRL_SHIFT,
.recalc = &followparent_recalc,
@@ -1370,7 +1362,7 @@ static struct clk omapctrl_ick = {
static struct clk cam_ick = {
.name = "cam_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1395,7 +1387,7 @@ static struct clk cam_fck = {
static struct clk mailboxes_ick = {
.name = "mailboxes_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1405,7 +1397,7 @@ static struct clk mailboxes_ick = {
static struct clk wdt4_ick = {
.name = "wdt4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1425,7 +1417,7 @@ static struct clk wdt4_fck = {
static struct clk wdt3_ick = {
.name = "wdt3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1445,7 +1437,7 @@ static struct clk wdt3_fck = {
static struct clk mspro_ick = {
.name = "mspro_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1465,7 +1457,7 @@ static struct clk mspro_fck = {
static struct clk mmc_ick = {
.name = "mmc_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1485,7 +1477,7 @@ static struct clk mmc_fck = {
static struct clk fac_ick = {
.name = "fac_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1505,7 +1497,7 @@ static struct clk fac_fck = {
static struct clk eac_ick = {
.name = "eac_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1525,7 +1517,7 @@ static struct clk eac_fck = {
static struct clk hdq_ick = {
.name = "hdq_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1545,7 +1537,7 @@ static struct clk hdq_fck = {
static struct clk i2c2_ick = {
.name = "i2c2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1565,7 +1557,7 @@ static struct clk i2c2_fck = {
static struct clk i2c1_ick = {
.name = "i2c1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1583,12 +1575,18 @@ static struct clk i2c1_fck = {
.recalc = &followparent_recalc,
};
+/*
+ * The enable_reg/enable_bit in this clock is only used for CM_AUTOIDLE
+ * accesses derived from this data.
+ */
static struct clk gpmc_fck = {
.name = "gpmc_fck",
- .ops = &clkops_null, /* RMK: missing? */
+ .ops = &clkops_omap2_iclk_idle_only,
.parent = &core_l3_ck,
.flags = ENABLE_ON_INIT,
.clkdm_name = "core_l3_clkdm",
+ .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .enable_bit = OMAP24XX_AUTO_GPMC_SHIFT,
.recalc = &followparent_recalc,
};
@@ -1600,17 +1598,38 @@ static struct clk sdma_fck = {
.recalc = &followparent_recalc,
};
+/*
+ * The enable_reg/enable_bit in this clock is only used for CM_AUTOIDLE
+ * accesses derived from this data.
+ */
static struct clk sdma_ick = {
.name = "sdma_ick",
- .ops = &clkops_null, /* RMK: missing? */
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_idle_only,
+ .parent = &core_l3_ck,
+ .clkdm_name = "core_l3_clkdm",
+ .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .enable_bit = OMAP24XX_AUTO_SDMA_SHIFT,
+ .recalc = &followparent_recalc,
+};
+
+/*
+ * The enable_reg/enable_bit in this clock is only used for CM_AUTOIDLE
+ * accesses derived from this data.
+ */
+static struct clk sdrc_ick = {
+ .name = "sdrc_ick",
+ .ops = &clkops_omap2_iclk_idle_only,
+ .parent = &core_l3_ck,
+ .flags = ENABLE_ON_INIT,
.clkdm_name = "core_l3_clkdm",
+ .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .enable_bit = OMAP24XX_AUTO_SDRC_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk vlynq_ick = {
.name = "vlynq_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l3_ck,
.clkdm_name = "core_l3_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1659,7 +1678,7 @@ static struct clk vlynq_fck = {
static struct clk des_ick = {
.name = "des_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1669,7 +1688,7 @@ static struct clk des_ick = {
static struct clk sha_ick = {
.name = "sha_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1679,7 +1698,7 @@ static struct clk sha_ick = {
static struct clk rng_ick = {
.name = "rng_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1689,7 +1708,7 @@ static struct clk rng_ick = {
static struct clk aes_ick = {
.name = "aes_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1699,7 +1718,7 @@ static struct clk aes_ick = {
static struct clk pka_ick = {
.name = "pka_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1777,7 +1796,6 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "mpu_ck", &mpu_ck, CK_242X),
/* dsp domain clocks */
CLK(NULL, "dsp_fck", &dsp_fck, CK_242X),
- CLK(NULL, "dsp_irate_ick", &dsp_irate_ick, CK_242X),
CLK(NULL, "dsp_ick", &dsp_ick, CK_242X),
CLK(NULL, "iva1_ifck", &iva1_ifck, CK_242X),
CLK(NULL, "iva1_mpu_int_ifck", &iva1_mpu_int_ifck, CK_242X),
@@ -1797,6 +1815,7 @@ static struct omap_clk omap2420_clks[] = {
/* L4 domain clocks */
CLK(NULL, "l4_ck", &l4_ck, CK_242X),
CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_242X),
+ CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_242X),
/* virtual meta-group clock */
CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X),
/* general l4 interface ck, multi-parent functional clk */
@@ -1869,6 +1888,7 @@ static struct omap_clk omap2420_clks[] = {
CLK(NULL, "gpmc_fck", &gpmc_fck, CK_242X),
CLK(NULL, "sdma_fck", &sdma_fck, CK_242X),
CLK(NULL, "sdma_ick", &sdma_ick, CK_242X),
+ CLK(NULL, "sdrc_ick", &sdrc_ick, CK_242X),
CLK(NULL, "vlynq_ick", &vlynq_ick, CK_242X),
CLK(NULL, "vlynq_fck", &vlynq_fck, CK_242X),
CLK(NULL, "des_ick", &des_ick, CK_242X),
@@ -1913,6 +1933,9 @@ int __init omap2420_clk_init(void)
omap2_init_clk_clkdm(c->lk.clk);
}
+ /* Disable autoidle on all clocks; let the PM code enable it later */
+ omap_clk_disable_autoidle_all();
+
/* Check the MPU rate set by bootloader */
clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c
index c047dcd007e5..bba018331a71 100644
--- a/arch/arm/mach-omap2/clock2430_data.c
+++ b/arch/arm/mach-omap2/clock2430_data.c
@@ -1,12 +1,12 @@
/*
- * linux/arch/arm/mach-omap2/clock2430_data.c
+ * OMAP2430 clock data
*
- * Copyright (C) 2005-2009 Texas Instruments, Inc.
- * Copyright (C) 2004-2010 Nokia Corporation
+ * Copyright (C) 2005-2009 Texas Instruments, Inc.
+ * Copyright (C) 2004-2011 Nokia Corporation
*
- * Contacts:
- * Richard Woodruff <r-woodruff2@ti.com>
- * Paul Walmsley
+ * Contacts:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -34,18 +34,15 @@
/*
* 2430 clock tree.
*
- * NOTE:In many cases here we are assigning a 'default' parent. In many
- * cases the parent is selectable. The get/set parent calls will also
- * switch sources.
- *
- * Many some clocks say always_enabled, but they can be auto idled for
- * power savings. They will always be available upon clock request.
+ * NOTE:In many cases here we are assigning a 'default' parent. In
+ * many cases the parent is selectable. The set parent calls will
+ * also switch sources.
*
* Several sources are given initial rates which may be wrong, this will
* be fixed up in the init func.
*
* Things are broadly separated below by clock domains. It is
- * noteworthy that most periferals have dependencies on multiple clock
+ * noteworthy that most peripherals have dependencies on multiple clock
* domains. Many get their interface clocks from the L4 domain, but get
* functional clocks from fixed sources or other core domain derived
* clocks.
@@ -55,7 +52,7 @@
static struct clk func_32k_ck = {
.name = "func_32k_ck",
.ops = &clkops_null,
- .rate = 32000,
+ .rate = 32768,
.clkdm_name = "wkup_clkdm",
};
@@ -116,7 +113,6 @@ static struct dpll_data dpll_dd = {
.max_multiplier = 1023,
.min_divider = 1,
.max_divider = 16,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
/*
@@ -125,7 +121,7 @@ static struct dpll_data dpll_dd = {
*/
static struct clk dpll_ck = {
.name = "dpll_ck",
- .ops = &clkops_null,
+ .ops = &clkops_omap2xxx_dpll_ops,
.parent = &sys_ck, /* Can be func_32k also */
.dpll_data = &dpll_dd,
.clkdm_name = "wkup_clkdm",
@@ -434,37 +430,23 @@ static struct clk dsp_fck = {
.recalc = &omap2_clksel_recalc,
};
-/* DSP interface clock */
-static const struct clksel_rate dsp_irate_ick_rates[] = {
- { .div = 1, .val = 1, .flags = RATE_IN_24XX },
- { .div = 2, .val = 2, .flags = RATE_IN_24XX },
- { .div = 3, .val = 3, .flags = RATE_IN_243X },
- { .div = 0 },
-};
-
-static const struct clksel dsp_irate_ick_clksel[] = {
- { .parent = &dsp_fck, .rates = dsp_irate_ick_rates },
+static const struct clksel dsp_ick_clksel[] = {
+ { .parent = &dsp_fck, .rates = dsp_ick_rates },
{ .parent = NULL }
};
-/* This clock does not exist as such in the TRM. */
-static struct clk dsp_irate_ick = {
- .name = "dsp_irate_ick",
- .ops = &clkops_null,
- .parent = &dsp_fck,
- .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
- .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK,
- .clksel = dsp_irate_ick_clksel,
- .recalc = &omap2_clksel_recalc,
-};
-
/* 2430 only - EN_DSP controls both dsp fclk and iclk on 2430 */
static struct clk iva2_1_ick = {
.name = "iva2_1_ick",
.ops = &clkops_omap2_dflt_wait,
- .parent = &dsp_irate_ick,
+ .parent = &dsp_fck,
+ .clkdm_name = "dsp_clkdm",
.enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
.enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
+ .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+ .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK,
+ .clksel = dsp_ick_clksel,
+ .recalc = &omap2_clksel_recalc,
};
/*
@@ -525,7 +507,7 @@ static const struct clksel usb_l4_ick_clksel[] = {
/* It is unclear from TRM whether usb_l4_ick is really in L3 or L4 clkdm */
static struct clk usb_l4_ick = { /* FS-USB interface clock */
.name = "usb_l4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l3_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -606,7 +588,7 @@ static struct clk ssi_ssr_sst_fck = {
*/
static struct clk ssi_l4_ick = {
.name = "ssi_l4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -661,6 +643,7 @@ static struct clk gfx_2d_fck = {
.recalc = &omap2_clksel_recalc,
};
+/* This interface clock does not have a CM_AUTOIDLE bit */
static struct clk gfx_ick = {
.name = "gfx_ick", /* From l3 */
.ops = &clkops_omap2_dflt_wait,
@@ -693,7 +676,7 @@ static const struct clksel mdm_ick_clksel[] = {
static struct clk mdm_ick = { /* used both as a ick and fck */
.name = "mdm_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_ck,
.clkdm_name = "mdm_clkdm",
.enable_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
@@ -706,7 +689,7 @@ static struct clk mdm_ick = { /* used both as a ick and fck */
static struct clk mdm_osc_ck = {
.name = "mdm_osc_ck",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_mdmclk_dflt_wait,
.parent = &osc_ck,
.clkdm_name = "mdm_clkdm",
.enable_reg = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_FCLKEN),
@@ -751,7 +734,7 @@ static const struct clksel dss1_fck_clksel[] = {
static struct clk dss_ick = { /* Enables both L3,L4 ICLK's */
.name = "dss_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ck, /* really both l3 and l4 */
.clkdm_name = "dss_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -813,6 +796,14 @@ static struct clk dss_54m_fck = { /* Alt clk used in power management */
.recalc = &followparent_recalc,
};
+static struct clk wu_l4_ick = {
+ .name = "wu_l4_ick",
+ .ops = &clkops_null,
+ .parent = &sys_ck,
+ .clkdm_name = "wkup_clkdm",
+ .recalc = &followparent_recalc,
+};
+
/*
* CORE power domain ICLK & FCLK defines.
* Many of the these can have more than one possible parent. Entries
@@ -833,9 +824,9 @@ static const struct clksel omap24xx_gpt_clksel[] = {
static struct clk gpt1_ick = {
.name = "gpt1_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_GPT1_SHIFT,
.recalc = &followparent_recalc,
@@ -859,7 +850,7 @@ static struct clk gpt1_fck = {
static struct clk gpt2_ick = {
.name = "gpt2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -883,7 +874,7 @@ static struct clk gpt2_fck = {
static struct clk gpt3_ick = {
.name = "gpt3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -907,7 +898,7 @@ static struct clk gpt3_fck = {
static struct clk gpt4_ick = {
.name = "gpt4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -931,7 +922,7 @@ static struct clk gpt4_fck = {
static struct clk gpt5_ick = {
.name = "gpt5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -955,7 +946,7 @@ static struct clk gpt5_fck = {
static struct clk gpt6_ick = {
.name = "gpt6_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -979,8 +970,9 @@ static struct clk gpt6_fck = {
static struct clk gpt7_ick = {
.name = "gpt7_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
+ .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP24XX_EN_GPT7_SHIFT,
.recalc = &followparent_recalc,
@@ -1002,7 +994,7 @@ static struct clk gpt7_fck = {
static struct clk gpt8_ick = {
.name = "gpt8_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1026,7 +1018,7 @@ static struct clk gpt8_fck = {
static struct clk gpt9_ick = {
.name = "gpt9_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1050,7 +1042,7 @@ static struct clk gpt9_fck = {
static struct clk gpt10_ick = {
.name = "gpt10_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1074,7 +1066,7 @@ static struct clk gpt10_fck = {
static struct clk gpt11_ick = {
.name = "gpt11_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1098,7 +1090,7 @@ static struct clk gpt11_fck = {
static struct clk gpt12_ick = {
.name = "gpt12_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1122,7 +1114,7 @@ static struct clk gpt12_fck = {
static struct clk mcbsp1_ick = {
.name = "mcbsp1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1162,7 +1154,7 @@ static struct clk mcbsp1_fck = {
static struct clk mcbsp2_ick = {
.name = "mcbsp2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1186,7 +1178,7 @@ static struct clk mcbsp2_fck = {
static struct clk mcbsp3_ick = {
.name = "mcbsp3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1210,7 +1202,7 @@ static struct clk mcbsp3_fck = {
static struct clk mcbsp4_ick = {
.name = "mcbsp4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1234,7 +1226,7 @@ static struct clk mcbsp4_fck = {
static struct clk mcbsp5_ick = {
.name = "mcbsp5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1258,7 +1250,7 @@ static struct clk mcbsp5_fck = {
static struct clk mcspi1_ick = {
.name = "mcspi1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1278,7 +1270,7 @@ static struct clk mcspi1_fck = {
static struct clk mcspi2_ick = {
.name = "mcspi2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1298,7 +1290,7 @@ static struct clk mcspi2_fck = {
static struct clk mcspi3_ick = {
.name = "mcspi3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1318,7 +1310,7 @@ static struct clk mcspi3_fck = {
static struct clk uart1_ick = {
.name = "uart1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1338,7 +1330,7 @@ static struct clk uart1_fck = {
static struct clk uart2_ick = {
.name = "uart2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1358,7 +1350,7 @@ static struct clk uart2_fck = {
static struct clk uart3_ick = {
.name = "uart3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1378,9 +1370,9 @@ static struct clk uart3_fck = {
static struct clk gpios_ick = {
.name = "gpios_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_GPIOS_SHIFT,
.recalc = &followparent_recalc,
@@ -1398,9 +1390,9 @@ static struct clk gpios_fck = {
static struct clk mpu_wdt_ick = {
.name = "mpu_wdt_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
.recalc = &followparent_recalc,
@@ -1418,10 +1410,10 @@ static struct clk mpu_wdt_fck = {
static struct clk sync_32k_ick = {
.name = "sync_32k_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_32KSYNC_SHIFT,
.recalc = &followparent_recalc,
@@ -1429,9 +1421,9 @@ static struct clk sync_32k_ick = {
static struct clk wdt1_ick = {
.name = "wdt1_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_WDT1_SHIFT,
.recalc = &followparent_recalc,
@@ -1439,10 +1431,10 @@ static struct clk wdt1_ick = {
static struct clk omapctrl_ick = {
.name = "omapctrl_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP24XX_EN_OMAPCTRL_SHIFT,
.recalc = &followparent_recalc,
@@ -1450,9 +1442,9 @@ static struct clk omapctrl_ick = {
static struct clk icr_ick = {
.name = "icr_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
- .clkdm_name = "core_l4_clkdm",
+ .ops = &clkops_omap2_iclk_dflt_wait,
+ .parent = &wu_l4_ick,
+ .clkdm_name = "wkup_clkdm",
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP2430_EN_ICR_SHIFT,
.recalc = &followparent_recalc,
@@ -1460,7 +1452,7 @@ static struct clk icr_ick = {
static struct clk cam_ick = {
.name = "cam_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1485,7 +1477,7 @@ static struct clk cam_fck = {
static struct clk mailboxes_ick = {
.name = "mailboxes_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1495,7 +1487,7 @@ static struct clk mailboxes_ick = {
static struct clk wdt4_ick = {
.name = "wdt4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1515,7 +1507,7 @@ static struct clk wdt4_fck = {
static struct clk mspro_ick = {
.name = "mspro_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1535,7 +1527,7 @@ static struct clk mspro_fck = {
static struct clk fac_ick = {
.name = "fac_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1555,7 +1547,7 @@ static struct clk fac_fck = {
static struct clk hdq_ick = {
.name = "hdq_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1579,7 +1571,7 @@ static struct clk hdq_fck = {
*/
static struct clk i2c2_ick = {
.name = "i2c2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1603,7 +1595,7 @@ static struct clk i2chs2_fck = {
*/
static struct clk i2c1_ick = {
.name = "i2c1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -1621,12 +1613,18 @@ static struct clk i2chs1_fck = {
.recalc = &followparent_recalc,
};
+/*
+ * The enable_reg/enable_bit in this clock is only used for CM_AUTOIDLE
+ * accesses derived from this data.
+ */
static struct clk gpmc_fck = {
.name = "gpmc_fck",
- .ops = &clkops_null, /* RMK: missing? */
+ .ops = &clkops_omap2_iclk_idle_only,
.parent = &core_l3_ck,
.flags = ENABLE_ON_INIT,
.clkdm_name = "core_l3_clkdm",
+ .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .enable_bit = OMAP24XX_AUTO_GPMC_SHIFT,
.recalc = &followparent_recalc,
};
@@ -1638,20 +1636,26 @@ static struct clk sdma_fck = {
.recalc = &followparent_recalc,
};
+/*
+ * The enable_reg/enable_bit in this clock is only used for CM_AUTOIDLE
+ * accesses derived from this data.
+ */
static struct clk sdma_ick = {
.name = "sdma_ick",
- .ops = &clkops_null, /* RMK: missing? */
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_idle_only,
+ .parent = &core_l3_ck,
.clkdm_name = "core_l3_clkdm",
+ .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+ .enable_bit = OMAP24XX_AUTO_SDMA_SHIFT,
.recalc = &followparent_recalc,
};
static struct clk sdrc_ick = {
.name = "sdrc_ick",
- .ops = &clkops_omap2_dflt_wait,
- .parent = &l4_ck,
+ .ops = &clkops_omap2_iclk_idle_only,
+ .parent = &core_l3_ck,
.flags = ENABLE_ON_INIT,
- .clkdm_name = "core_l4_clkdm",
+ .clkdm_name = "core_l3_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
.enable_bit = OMAP2430_EN_SDRC_SHIFT,
.recalc = &followparent_recalc,
@@ -1659,7 +1663,7 @@ static struct clk sdrc_ick = {
static struct clk des_ick = {
.name = "des_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1669,7 +1673,7 @@ static struct clk des_ick = {
static struct clk sha_ick = {
.name = "sha_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1679,7 +1683,7 @@ static struct clk sha_ick = {
static struct clk rng_ick = {
.name = "rng_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1689,7 +1693,7 @@ static struct clk rng_ick = {
static struct clk aes_ick = {
.name = "aes_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1699,7 +1703,7 @@ static struct clk aes_ick = {
static struct clk pka_ick = {
.name = "pka_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
@@ -1719,7 +1723,7 @@ static struct clk usb_fck = {
static struct clk usbhs_ick = {
.name = "usbhs_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l3_ck,
.clkdm_name = "core_l3_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1729,7 +1733,7 @@ static struct clk usbhs_ick = {
static struct clk mmchs1_ick = {
.name = "mmchs1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1741,7 +1745,7 @@ static struct clk mmchs1_fck = {
.name = "mmchs1_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
- .clkdm_name = "core_l3_clkdm",
+ .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
.enable_bit = OMAP2430_EN_MMCHS1_SHIFT,
.recalc = &followparent_recalc,
@@ -1749,7 +1753,7 @@ static struct clk mmchs1_fck = {
static struct clk mmchs2_ick = {
.name = "mmchs2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1761,6 +1765,7 @@ static struct clk mmchs2_fck = {
.name = "mmchs2_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &func_96m_ck,
+ .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
.enable_bit = OMAP2430_EN_MMCHS2_SHIFT,
.recalc = &followparent_recalc,
@@ -1768,7 +1773,7 @@ static struct clk mmchs2_fck = {
static struct clk gpio5_ick = {
.name = "gpio5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1788,7 +1793,7 @@ static struct clk gpio5_fck = {
static struct clk mdm_intc_ick = {
.name = "mdm_intc_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ck,
.clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
@@ -1880,7 +1885,6 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "mpu_ck", &mpu_ck, CK_243X),
/* dsp domain clocks */
CLK(NULL, "dsp_fck", &dsp_fck, CK_243X),
- CLK(NULL, "dsp_irate_ick", &dsp_irate_ick, CK_243X),
CLK(NULL, "iva2_1_ick", &iva2_1_ick, CK_243X),
/* GFX domain clocks */
CLK(NULL, "gfx_3d_fck", &gfx_3d_fck, CK_243X),
@@ -1901,6 +1905,7 @@ static struct omap_clk omap2430_clks[] = {
/* L4 domain clocks */
CLK(NULL, "l4_ck", &l4_ck, CK_243X),
CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_243X),
+ CLK(NULL, "wu_l4_ick", &wu_l4_ick, CK_243X),
/* virtual meta-group clock */
CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X),
/* general l4 interface ck, multi-parent functional clk */
@@ -1984,15 +1989,15 @@ static struct omap_clk omap2430_clks[] = {
CLK(NULL, "pka_ick", &pka_ick, CK_243X),
CLK(NULL, "usb_fck", &usb_fck, CK_243X),
CLK("musb-omap2430", "ick", &usbhs_ick, CK_243X),
- CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_243X),
- CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_243X),
- CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_243X),
- CLK("mmci-omap-hs.1", "fck", &mmchs2_fck, CK_243X),
+ CLK("omap_hsmmc.0", "ick", &mmchs1_ick, CK_243X),
+ CLK("omap_hsmmc.0", "fck", &mmchs1_fck, CK_243X),
+ CLK("omap_hsmmc.1", "ick", &mmchs2_ick, CK_243X),
+ CLK("omap_hsmmc.1", "fck", &mmchs2_fck, CK_243X),
CLK(NULL, "gpio5_ick", &gpio5_ick, CK_243X),
CLK(NULL, "gpio5_fck", &gpio5_fck, CK_243X),
CLK(NULL, "mdm_intc_ick", &mdm_intc_ick, CK_243X),
- CLK("mmci-omap-hs.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X),
- CLK("mmci-omap-hs.1", "mmchsdb_fck", &mmchsdb2_fck, CK_243X),
+ CLK("omap_hsmmc.0", "mmchsdb_fck", &mmchsdb1_fck, CK_243X),
+ CLK("omap_hsmmc.1", "mmchsdb_fck", &mmchsdb2_fck, CK_243X),
};
/*
@@ -2028,6 +2033,9 @@ int __init omap2430_clk_init(void)
omap2_init_clk_clkdm(c->lk.clk);
}
+ /* Disable autoidle on all clocks; let the PM code enable it later */
+ omap_clk_disable_autoidle_all();
+
/* Check the MPU rate set by bootloader */
clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
diff --git a/arch/arm/mach-omap2/clock2xxx.h b/arch/arm/mach-omap2/clock2xxx.h
index 6a658b890c17..cb6df8ca9e4a 100644
--- a/arch/arm/mach-omap2/clock2xxx.h
+++ b/arch/arm/mach-omap2/clock2xxx.h
@@ -20,16 +20,16 @@ u32 omap2xxx_get_apll_clkin(void);
u32 omap2xxx_get_sysclkdiv(void);
void omap2xxx_clk_prepare_for_reboot(void);
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
int omap2420_clk_init(void);
#else
-#define omap2420_clk_init() 0
+#define omap2420_clk_init() do { } while(0)
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
int omap2430_clk_init(void);
#else
-#define omap2430_clk_init() 0
+#define omap2430_clk_init() do { } while(0)
#endif
extern void __iomem *prcm_clksrc_ctrl, *cm_idlest_pll;
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 287abc480924..1fc96b9ee330 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -2,7 +2,7 @@
* OMAP3-specific clock framework functions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley
* Jouni Högander
@@ -59,6 +59,15 @@ const struct clkops clkops_omap3430es2_ssi_wait = {
.find_companion = omap2_clk_dflt_find_companion,
};
+const struct clkops clkops_omap3430es2_iclk_ssi_wait = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .find_idlest = omap3430es2_clk_ssi_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
/**
* omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST
* @clk: struct clk * being enabled
@@ -94,6 +103,15 @@ const struct clkops clkops_omap3430es2_dss_usbhost_wait = {
.find_companion = omap2_clk_dflt_find_companion,
};
+const struct clkops clkops_omap3430es2_iclk_dss_usbhost_wait = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
+
/**
* omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB
* @clk: struct clk * being enabled
@@ -124,3 +142,12 @@ const struct clkops clkops_omap3430es2_hsotgusb_wait = {
.find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
+
+const struct clkops clkops_omap3430es2_iclk_hsotgusb_wait = {
+ .enable = omap2_dflt_clk_enable,
+ .disable = omap2_dflt_clk_disable,
+ .find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
+ .find_companion = omap2_clk_dflt_find_companion,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
+};
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index 628e8de57680..084ba71b2b31 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -2,14 +2,17 @@
* OMAP34xx clock function prototypes and macros
*
* Copyright (C) 2007-2010 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
extern const struct clkops clkops_omap3430es2_ssi_wait;
+extern const struct clkops clkops_omap3430es2_iclk_ssi_wait;
extern const struct clkops clkops_omap3430es2_hsotgusb_wait;
+extern const struct clkops clkops_omap3430es2_iclk_hsotgusb_wait;
extern const struct clkops clkops_omap3430es2_dss_usbhost_wait;
+extern const struct clkops clkops_omap3430es2_iclk_dss_usbhost_wait;
#endif
diff --git a/arch/arm/mach-omap2/clock3517.c b/arch/arm/mach-omap2/clock3517.c
index 74116a3cf099..2e97d08f0e56 100644
--- a/arch/arm/mach-omap2/clock3517.c
+++ b/arch/arm/mach-omap2/clock3517.c
@@ -2,7 +2,7 @@
* OMAP3517/3505-specific clock framework functions
*
* Copyright (C) 2010 Texas Instruments, Inc.
- * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2011 Nokia Corporation
*
* Ranjith Lohithakshan
* Paul Walmsley
@@ -119,6 +119,8 @@ const struct clkops clkops_am35xx_ipss_wait = {
.disable = omap2_dflt_clk_disable,
.find_idlest = am35xx_clk_ipss_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
+ .allow_idle = omap2_clkt_iclk_allow_idle,
+ .deny_idle = omap2_clkt_iclk_deny_idle,
};
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index e9f66b6dec18..952c3e01c9eb 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -65,9 +65,6 @@ void __init omap3_clk_lock_dpll5(void)
clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
clk_enable(dpll5_clk);
- /* Enable autoidle to allow it to enter low power bypass */
- omap3_dpll_allow_idle(dpll5_clk);
-
/* Program dpll5_m2_clk divider for no division */
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
clk_enable(dpll5_m2_clk);
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index fbb1e30a73dc..fcb321a64f13 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -2,7 +2,7 @@
* OMAP3 clock data
*
* Copyright (C) 2007-2010 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Written by Paul Walmsley
* With many device clock fixes by Kevin Hilman and Jouni Högander
@@ -291,12 +291,11 @@ static struct dpll_data dpll1_dd = {
.max_multiplier = OMAP3_MAX_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll1_ck = {
.name = "dpll1_ck",
- .ops = &clkops_null,
+ .ops = &clkops_omap3_noncore_dpll_ops,
.parent = &sys_ck,
.dpll_data = &dpll1_dd,
.round_rate = &omap2_dpll_round_rate,
@@ -364,7 +363,6 @@ static struct dpll_data dpll2_dd = {
.max_multiplier = OMAP3_MAX_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll2_ck = {
@@ -424,12 +422,11 @@ static struct dpll_data dpll3_dd = {
.max_multiplier = OMAP3_MAX_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll3_ck = {
.name = "dpll3_ck",
- .ops = &clkops_null,
+ .ops = &clkops_omap3_core_dpll_ops,
.parent = &sys_ck,
.dpll_data = &dpll3_dd,
.round_rate = &omap2_dpll_round_rate,
@@ -583,7 +580,6 @@ static struct dpll_data dpll4_dd_34xx __initdata = {
.max_multiplier = OMAP3_MAX_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct dpll_data dpll4_dd_3630 __initdata = {
@@ -607,7 +603,6 @@ static struct dpll_data dpll4_dd_3630 __initdata = {
.max_multiplier = OMAP3630_MAX_JTYPE_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE,
.flags = DPLL_J_TYPE
};
@@ -939,7 +934,6 @@ static struct dpll_data dpll5_dd = {
.max_multiplier = OMAP3_MAX_DPLL_MULT,
.min_divider = 1,
.max_divider = OMAP3_MAX_DPLL_DIV,
- .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
};
static struct clk dpll5_ck = {
@@ -1205,7 +1199,10 @@ static const struct clksel gfx_l3_clksel[] = {
{ .parent = NULL }
};
-/* Virtual parent clock for gfx_l3_ick and gfx_l3_fck */
+/*
+ * Virtual parent clock for gfx_l3_ick and gfx_l3_fck
+ * This interface clock does not have a CM_AUTOIDLE bit
+ */
static struct clk gfx_l3_ck = {
.name = "gfx_l3_ck",
.ops = &clkops_omap2_dflt_wait,
@@ -1304,6 +1301,7 @@ static struct clk sgx_fck = {
.round_rate = &omap2_clksel_round_rate
};
+/* This interface clock does not have a CM_AUTOIDLE bit */
static struct clk sgx_ick = {
.name = "sgx_ick",
.ops = &clkops_omap2_dflt_wait,
@@ -1328,7 +1326,7 @@ static struct clk d2d_26m_fck = {
static struct clk modem_fck = {
.name = "modem_fck",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_mdmclk_dflt_wait,
.parent = &sys_ck,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_MODEM_SHIFT,
@@ -1338,7 +1336,7 @@ static struct clk modem_fck = {
static struct clk sad2d_ick = {
.name = "sad2d_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SAD2D_SHIFT,
@@ -1348,7 +1346,7 @@ static struct clk sad2d_ick = {
static struct clk mad2d_ick = {
.name = "mad2d_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
.enable_bit = OMAP3430_EN_MAD2D_SHIFT,
@@ -1718,7 +1716,7 @@ static struct clk core_l3_ick = {
static struct clk hsotgusb_ick_3430es1 = {
.name = "hsotgusb_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &core_l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
@@ -1728,7 +1726,7 @@ static struct clk hsotgusb_ick_3430es1 = {
static struct clk hsotgusb_ick_3430es2 = {
.name = "hsotgusb_ick",
- .ops = &clkops_omap3430es2_hsotgusb_wait,
+ .ops = &clkops_omap3430es2_iclk_hsotgusb_wait,
.parent = &core_l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
@@ -1736,6 +1734,7 @@ static struct clk hsotgusb_ick_3430es2 = {
.recalc = &followparent_recalc,
};
+/* This interface clock does not have a CM_AUTOIDLE bit */
static struct clk sdrc_ick = {
.name = "sdrc_ick",
.ops = &clkops_omap2_dflt_wait,
@@ -1767,7 +1766,7 @@ static struct clk security_l3_ick = {
static struct clk pka_ick = {
.name = "pka_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &security_l3_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
.enable_bit = OMAP3430_EN_PKA_SHIFT,
@@ -1786,7 +1785,7 @@ static struct clk core_l4_ick = {
static struct clk usbtll_ick = {
.name = "usbtll_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
.enable_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
@@ -1796,7 +1795,7 @@ static struct clk usbtll_ick = {
static struct clk mmchs3_ick = {
.name = "mmchs3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430ES2_EN_MMC3_SHIFT,
@@ -1807,7 +1806,7 @@ static struct clk mmchs3_ick = {
/* Intersystem Communication Registers - chassis mode only */
static struct clk icr_ick = {
.name = "icr_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_ICR_SHIFT,
@@ -1817,7 +1816,7 @@ static struct clk icr_ick = {
static struct clk aes2_ick = {
.name = "aes2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_AES2_SHIFT,
@@ -1827,7 +1826,7 @@ static struct clk aes2_ick = {
static struct clk sha12_ick = {
.name = "sha12_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SHA12_SHIFT,
@@ -1837,7 +1836,7 @@ static struct clk sha12_ick = {
static struct clk des2_ick = {
.name = "des2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_DES2_SHIFT,
@@ -1847,7 +1846,7 @@ static struct clk des2_ick = {
static struct clk mmchs2_ick = {
.name = "mmchs2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MMC2_SHIFT,
@@ -1857,7 +1856,7 @@ static struct clk mmchs2_ick = {
static struct clk mmchs1_ick = {
.name = "mmchs1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MMC1_SHIFT,
@@ -1867,7 +1866,7 @@ static struct clk mmchs1_ick = {
static struct clk mspro_ick = {
.name = "mspro_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MSPRO_SHIFT,
@@ -1877,7 +1876,7 @@ static struct clk mspro_ick = {
static struct clk hdq_ick = {
.name = "hdq_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_HDQ_SHIFT,
@@ -1887,7 +1886,7 @@ static struct clk hdq_ick = {
static struct clk mcspi4_ick = {
.name = "mcspi4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI4_SHIFT,
@@ -1897,7 +1896,7 @@ static struct clk mcspi4_ick = {
static struct clk mcspi3_ick = {
.name = "mcspi3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI3_SHIFT,
@@ -1907,7 +1906,7 @@ static struct clk mcspi3_ick = {
static struct clk mcspi2_ick = {
.name = "mcspi2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI2_SHIFT,
@@ -1917,7 +1916,7 @@ static struct clk mcspi2_ick = {
static struct clk mcspi1_ick = {
.name = "mcspi1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCSPI1_SHIFT,
@@ -1927,7 +1926,7 @@ static struct clk mcspi1_ick = {
static struct clk i2c3_ick = {
.name = "i2c3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C3_SHIFT,
@@ -1937,7 +1936,7 @@ static struct clk i2c3_ick = {
static struct clk i2c2_ick = {
.name = "i2c2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C2_SHIFT,
@@ -1947,7 +1946,7 @@ static struct clk i2c2_ick = {
static struct clk i2c1_ick = {
.name = "i2c1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_I2C1_SHIFT,
@@ -1957,7 +1956,7 @@ static struct clk i2c1_ick = {
static struct clk uart2_ick = {
.name = "uart2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_UART2_SHIFT,
@@ -1967,7 +1966,7 @@ static struct clk uart2_ick = {
static struct clk uart1_ick = {
.name = "uart1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_UART1_SHIFT,
@@ -1977,7 +1976,7 @@ static struct clk uart1_ick = {
static struct clk gpt11_ick = {
.name = "gpt11_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_GPT11_SHIFT,
@@ -1987,7 +1986,7 @@ static struct clk gpt11_ick = {
static struct clk gpt10_ick = {
.name = "gpt10_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_GPT10_SHIFT,
@@ -1997,7 +1996,7 @@ static struct clk gpt10_ick = {
static struct clk mcbsp5_ick = {
.name = "mcbsp5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCBSP5_SHIFT,
@@ -2007,7 +2006,7 @@ static struct clk mcbsp5_ick = {
static struct clk mcbsp1_ick = {
.name = "mcbsp1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MCBSP1_SHIFT,
@@ -2017,7 +2016,7 @@ static struct clk mcbsp1_ick = {
static struct clk fac_ick = {
.name = "fac_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430ES1_EN_FAC_SHIFT,
@@ -2027,7 +2026,7 @@ static struct clk fac_ick = {
static struct clk mailboxes_ick = {
.name = "mailboxes_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_MAILBOXES_SHIFT,
@@ -2037,7 +2036,7 @@ static struct clk mailboxes_ick = {
static struct clk omapctrl_ick = {
.name = "omapctrl_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_OMAPCTRL_SHIFT,
@@ -2057,7 +2056,7 @@ static struct clk ssi_l4_ick = {
static struct clk ssi_ick_3430es1 = {
.name = "ssi_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &ssi_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SSI_SHIFT,
@@ -2067,7 +2066,7 @@ static struct clk ssi_ick_3430es1 = {
static struct clk ssi_ick_3430es2 = {
.name = "ssi_ick",
- .ops = &clkops_omap3430es2_ssi_wait,
+ .ops = &clkops_omap3430es2_iclk_ssi_wait,
.parent = &ssi_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = OMAP3430_EN_SSI_SHIFT,
@@ -2085,7 +2084,7 @@ static const struct clksel usb_l4_clksel[] = {
static struct clk usb_l4_ick = {
.name = "usb_l4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &l4_ick,
.init = &omap2_init_clksel_parent,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
@@ -2107,7 +2106,7 @@ static struct clk security_l4_ick2 = {
static struct clk aes1_ick = {
.name = "aes1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &security_l4_ick2,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
.enable_bit = OMAP3430_EN_AES1_SHIFT,
@@ -2116,7 +2115,7 @@ static struct clk aes1_ick = {
static struct clk rng_ick = {
.name = "rng_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &security_l4_ick2,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
.enable_bit = OMAP3430_EN_RNG_SHIFT,
@@ -2125,7 +2124,7 @@ static struct clk rng_ick = {
static struct clk sha11_ick = {
.name = "sha11_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &security_l4_ick2,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
.enable_bit = OMAP3430_EN_SHA11_SHIFT,
@@ -2134,7 +2133,7 @@ static struct clk sha11_ick = {
static struct clk des1_ick = {
.name = "des1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &security_l4_ick2,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
.enable_bit = OMAP3430_EN_DES1_SHIFT,
@@ -2195,7 +2194,7 @@ static struct clk dss2_alwon_fck = {
static struct clk dss_ick_3430es1 = {
/* Handles both L3 and L4 clocks */
.name = "dss_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
@@ -2206,7 +2205,7 @@ static struct clk dss_ick_3430es1 = {
static struct clk dss_ick_3430es2 = {
/* Handles both L3 and L4 clocks */
.name = "dss_ick",
- .ops = &clkops_omap3430es2_dss_usbhost_wait,
+ .ops = &clkops_omap3430es2_iclk_dss_usbhost_wait,
.parent = &l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
@@ -2229,7 +2228,7 @@ static struct clk cam_mclk = {
static struct clk cam_ick = {
/* Handles both L3 and L4 clocks */
.name = "cam_ick",
- .ops = &clkops_omap2_dflt,
+ .ops = &clkops_omap2_iclk_dflt,
.parent = &l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_CAM_SHIFT,
@@ -2272,7 +2271,7 @@ static struct clk usbhost_48m_fck = {
static struct clk usbhost_ick = {
/* Handles both L3 and L4 clocks */
.name = "usbhost_ick",
- .ops = &clkops_omap3430es2_dss_usbhost_wait,
+ .ops = &clkops_omap3430es2_iclk_dss_usbhost_wait,
.parent = &l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
.enable_bit = OMAP3430ES2_EN_USBHOST_SHIFT,
@@ -2372,7 +2371,7 @@ static struct clk wkup_l4_ick = {
/* Never specifically named in the TRM, so we have to infer a likely name */
static struct clk usim_ick = {
.name = "usim_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430ES2_EN_USIMOCP_SHIFT,
@@ -2382,7 +2381,7 @@ static struct clk usim_ick = {
static struct clk wdt2_ick = {
.name = "wdt2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT2_SHIFT,
@@ -2392,7 +2391,7 @@ static struct clk wdt2_ick = {
static struct clk wdt1_ick = {
.name = "wdt1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT1_SHIFT,
@@ -2402,7 +2401,7 @@ static struct clk wdt1_ick = {
static struct clk gpio1_ick = {
.name = "gpio1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO1_SHIFT,
@@ -2412,7 +2411,7 @@ static struct clk gpio1_ick = {
static struct clk omap_32ksync_ick = {
.name = "omap_32ksync_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_32KSYNC_SHIFT,
@@ -2423,7 +2422,7 @@ static struct clk omap_32ksync_ick = {
/* XXX This clock no longer exists in 3430 TRM rev F */
static struct clk gpt12_ick = {
.name = "gpt12_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT12_SHIFT,
@@ -2433,7 +2432,7 @@ static struct clk gpt12_ick = {
static struct clk gpt1_ick = {
.name = "gpt1_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &wkup_l4_ick,
.enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT1_SHIFT,
@@ -2663,7 +2662,7 @@ static struct clk per_l4_ick = {
static struct clk gpio6_ick = {
.name = "gpio6_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO6_SHIFT,
@@ -2673,7 +2672,7 @@ static struct clk gpio6_ick = {
static struct clk gpio5_ick = {
.name = "gpio5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO5_SHIFT,
@@ -2683,7 +2682,7 @@ static struct clk gpio5_ick = {
static struct clk gpio4_ick = {
.name = "gpio4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO4_SHIFT,
@@ -2693,7 +2692,7 @@ static struct clk gpio4_ick = {
static struct clk gpio3_ick = {
.name = "gpio3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO3_SHIFT,
@@ -2703,7 +2702,7 @@ static struct clk gpio3_ick = {
static struct clk gpio2_ick = {
.name = "gpio2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPIO2_SHIFT,
@@ -2713,7 +2712,7 @@ static struct clk gpio2_ick = {
static struct clk wdt3_ick = {
.name = "wdt3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_WDT3_SHIFT,
@@ -2723,7 +2722,7 @@ static struct clk wdt3_ick = {
static struct clk uart3_ick = {
.name = "uart3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_UART3_SHIFT,
@@ -2733,7 +2732,7 @@ static struct clk uart3_ick = {
static struct clk uart4_ick = {
.name = "uart4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3630_EN_UART4_SHIFT,
@@ -2743,7 +2742,7 @@ static struct clk uart4_ick = {
static struct clk gpt9_ick = {
.name = "gpt9_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT9_SHIFT,
@@ -2753,7 +2752,7 @@ static struct clk gpt9_ick = {
static struct clk gpt8_ick = {
.name = "gpt8_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT8_SHIFT,
@@ -2763,7 +2762,7 @@ static struct clk gpt8_ick = {
static struct clk gpt7_ick = {
.name = "gpt7_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT7_SHIFT,
@@ -2773,7 +2772,7 @@ static struct clk gpt7_ick = {
static struct clk gpt6_ick = {
.name = "gpt6_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT6_SHIFT,
@@ -2783,7 +2782,7 @@ static struct clk gpt6_ick = {
static struct clk gpt5_ick = {
.name = "gpt5_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT5_SHIFT,
@@ -2793,7 +2792,7 @@ static struct clk gpt5_ick = {
static struct clk gpt4_ick = {
.name = "gpt4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT4_SHIFT,
@@ -2803,7 +2802,7 @@ static struct clk gpt4_ick = {
static struct clk gpt3_ick = {
.name = "gpt3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT3_SHIFT,
@@ -2813,7 +2812,7 @@ static struct clk gpt3_ick = {
static struct clk gpt2_ick = {
.name = "gpt2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_GPT2_SHIFT,
@@ -2823,7 +2822,7 @@ static struct clk gpt2_ick = {
static struct clk mcbsp2_ick = {
.name = "mcbsp2_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP2_SHIFT,
@@ -2833,7 +2832,7 @@ static struct clk mcbsp2_ick = {
static struct clk mcbsp3_ick = {
.name = "mcbsp3_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP3_SHIFT,
@@ -2843,7 +2842,7 @@ static struct clk mcbsp3_ick = {
static struct clk mcbsp4_ick = {
.name = "mcbsp4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &per_l4_ick,
.enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
.enable_bit = OMAP3430_EN_MCBSP4_SHIFT,
@@ -3186,7 +3185,7 @@ static struct clk vpfe_fck = {
*/
static struct clk uart4_ick_am35xx = {
.name = "uart4_ick",
- .ops = &clkops_omap2_dflt_wait,
+ .ops = &clkops_omap2_iclk_dflt_wait,
.parent = &core_l4_ick,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
.enable_bit = AM35XX_EN_UART4_SHIFT,
@@ -3290,10 +3289,10 @@ static struct omap_clk omap3xxx_clks[] = {
CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX),
- CLK("mmci-omap-hs.2", "fck", &mmchs3_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("mmci-omap-hs.1", "fck", &mmchs2_fck, CK_3XXX),
+ CLK("omap_hsmmc.2", "fck", &mmchs3_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("omap_hsmmc.1", "fck", &mmchs2_fck, CK_3XXX),
CLK(NULL, "mspro_fck", &mspro_fck, CK_34XX | CK_36XX),
- CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_3XXX),
+ CLK("omap_hsmmc.0", "fck", &mmchs1_fck, CK_3XXX),
CLK("omap_i2c.3", "fck", &i2c3_fck, CK_3XXX),
CLK("omap_i2c.2", "fck", &i2c2_fck, CK_3XXX),
CLK("omap_i2c.1", "fck", &i2c1_fck, CK_3XXX),
@@ -3323,13 +3322,13 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX),
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("usbhs-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("mmci-omap-hs.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("omap_hsmmc.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "icr_ick", &icr_ick, CK_34XX | CK_36XX),
CLK("omap-aes", "ick", &aes2_ick, CK_34XX | CK_36XX),
CLK("omap-sham", "ick", &sha12_ick, CK_34XX | CK_36XX),
CLK(NULL, "des2_ick", &des2_ick, CK_34XX | CK_36XX),
- CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_3XXX),
- CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_3XXX),
+ CLK("omap_hsmmc.1", "ick", &mmchs2_ick, CK_3XXX),
+ CLK("omap_hsmmc.0", "ick", &mmchs1_ick, CK_3XXX),
CLK(NULL, "mspro_ick", &mspro_ick, CK_34XX | CK_36XX),
CLK("omap_hdq.0", "ick", &hdq_ick, CK_3XXX),
CLK("omap2_mcspi.4", "ick", &mcspi4_ick, CK_3XXX),
@@ -3480,6 +3479,9 @@ int __init omap3xxx_clk_init(void)
} else if (cpu_is_omap3630()) {
cpu_mask = (RATE_IN_34XX | RATE_IN_36XX);
cpu_clkflg = CK_36XX;
+ } else if (cpu_is_ti816x()) {
+ cpu_mask = RATE_IN_TI816X;
+ cpu_clkflg = CK_TI816X;
} else if (cpu_is_omap34xx()) {
if (omap_rev() == OMAP3430_REV_ES1_0) {
cpu_mask = RATE_IN_3430ES1;
@@ -3544,6 +3546,9 @@ int __init omap3xxx_clk_init(void)
omap2_init_clk_clkdm(c->lk.clk);
}
+ /* Disable autoidle on all clocks; let the PM code enable it later */
+ omap_clk_disable_autoidle_all();
+
recalculate_root_clocks();
pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
@@ -3557,9 +3562,10 @@ int __init omap3xxx_clk_init(void)
clk_enable_init_clocks();
/*
- * Lock DPLL5 and put it in autoidle.
+ * Lock DPLL5 -- here only until other device init code can
+ * handle this
*/
- if (omap_rev() >= OMAP3430_REV_ES2_0)
+ if (!cpu_is_ti816x() && (omap_rev() >= OMAP3430_REV_ES2_0))
omap3_clk_lock_dpll5();
/* Avoid sleeping during omap3_core_dpll_m2_set_rate() */
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 46fd3f674cac..d32ed979a8da 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -278,8 +278,10 @@ static struct clk dpll_abe_ck = {
static struct clk dpll_abe_x2_ck = {
.name = "dpll_abe_x2_ck",
.parent = &dpll_abe_ck,
- .ops = &clkops_null,
+ .flags = CLOCK_CLKOUTX2,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap3_clkoutx2_recalc,
+ .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_ABE,
};
static const struct clksel_rate div31_1to31_rates[] = {
@@ -328,7 +330,7 @@ static struct clk dpll_abe_m2x2_ck = {
.clksel = dpll_abe_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_ABE,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -395,7 +397,7 @@ static struct clk dpll_abe_m3x2_ck = {
.clksel = dpll_abe_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M3_DPLL_ABE,
.clksel_mask = OMAP4430_DPLL_CLKOUTHIF_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -443,13 +445,14 @@ static struct clk dpll_core_ck = {
.parent = &sys_clkin_ck,
.dpll_data = &dpll_core_dd,
.init = &omap2_init_dpll_parent,
- .ops = &clkops_null,
+ .ops = &clkops_omap3_core_dpll_ops,
.recalc = &omap3_dpll_recalc,
};
static struct clk dpll_core_x2_ck = {
.name = "dpll_core_x2_ck",
.parent = &dpll_core_ck,
+ .flags = CLOCK_CLKOUTX2,
.ops = &clkops_null,
.recalc = &omap3_clkoutx2_recalc,
};
@@ -465,7 +468,7 @@ static struct clk dpll_core_m6x2_ck = {
.clksel = dpll_core_m6x2_div,
.clksel_reg = OMAP4430_CM_DIV_M6_DPLL_CORE,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -495,7 +498,7 @@ static struct clk dpll_core_m2_ck = {
.clksel = dpll_core_m2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_CORE,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -515,7 +518,7 @@ static struct clk dpll_core_m5x2_ck = {
.clksel = dpll_core_m6x2_div,
.clksel_reg = OMAP4430_CM_DIV_M5_DPLL_CORE,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -581,7 +584,7 @@ static struct clk dpll_core_m4x2_ck = {
.clksel = dpll_core_m6x2_div,
.clksel_reg = OMAP4430_CM_DIV_M4_DPLL_CORE,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -606,7 +609,7 @@ static struct clk dpll_abe_m2_ck = {
.clksel = dpll_abe_m2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_ABE,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -632,7 +635,7 @@ static struct clk dpll_core_m7x2_ck = {
.clksel = dpll_core_m6x2_div,
.clksel_reg = OMAP4430_CM_DIV_M7_DPLL_CORE,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -689,6 +692,7 @@ static struct clk dpll_iva_ck = {
static struct clk dpll_iva_x2_ck = {
.name = "dpll_iva_x2_ck",
.parent = &dpll_iva_ck,
+ .flags = CLOCK_CLKOUTX2,
.ops = &clkops_null,
.recalc = &omap3_clkoutx2_recalc,
};
@@ -704,7 +708,7 @@ static struct clk dpll_iva_m4x2_ck = {
.clksel = dpll_iva_m4x2_div,
.clksel_reg = OMAP4430_CM_DIV_M4_DPLL_IVA,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -716,7 +720,7 @@ static struct clk dpll_iva_m5x2_ck = {
.clksel = dpll_iva_m4x2_div,
.clksel_reg = OMAP4430_CM_DIV_M5_DPLL_IVA,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -764,7 +768,7 @@ static struct clk dpll_mpu_m2_ck = {
.clksel = dpll_mpu_m2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_MPU,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -837,7 +841,7 @@ static struct clk dpll_per_m2_ck = {
.clksel = dpll_per_m2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_PER,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -846,8 +850,10 @@ static struct clk dpll_per_m2_ck = {
static struct clk dpll_per_x2_ck = {
.name = "dpll_per_x2_ck",
.parent = &dpll_per_ck,
- .ops = &clkops_null,
+ .flags = CLOCK_CLKOUTX2,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap3_clkoutx2_recalc,
+ .clksel_reg = OMAP4430_CM_DIV_M2_DPLL_PER,
};
static const struct clksel dpll_per_m2x2_div[] = {
@@ -861,7 +867,7 @@ static struct clk dpll_per_m2x2_ck = {
.clksel = dpll_per_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_PER,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -887,7 +893,7 @@ static struct clk dpll_per_m4x2_ck = {
.clksel = dpll_per_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M4_DPLL_PER,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -899,7 +905,7 @@ static struct clk dpll_per_m5x2_ck = {
.clksel = dpll_per_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M5_DPLL_PER,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -911,7 +917,7 @@ static struct clk dpll_per_m6x2_ck = {
.clksel = dpll_per_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M6_DPLL_PER,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -923,7 +929,7 @@ static struct clk dpll_per_m7x2_ck = {
.clksel = dpll_per_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M7_DPLL_PER,
.clksel_mask = OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -964,6 +970,7 @@ static struct clk dpll_unipro_ck = {
static struct clk dpll_unipro_x2_ck = {
.name = "dpll_unipro_x2_ck",
.parent = &dpll_unipro_ck,
+ .flags = CLOCK_CLKOUTX2,
.ops = &clkops_null,
.recalc = &omap3_clkoutx2_recalc,
};
@@ -979,7 +986,7 @@ static struct clk dpll_unipro_m2x2_ck = {
.clksel = dpll_unipro_m2x2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_UNIPRO,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -1028,7 +1035,8 @@ static struct clk dpll_usb_ck = {
static struct clk dpll_usb_clkdcoldo_ck = {
.name = "dpll_usb_clkdcoldo_ck",
.parent = &dpll_usb_ck,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
+ .clksel_reg = OMAP4430_CM_CLKDCOLDO_DPLL_USB,
.recalc = &followparent_recalc,
};
@@ -1043,7 +1051,7 @@ static struct clk dpll_usb_m2_ck = {
.clksel = dpll_usb_m2_div,
.clksel_reg = OMAP4430_CM_DIV_M2_DPLL_USB,
.clksel_mask = OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK,
- .ops = &clkops_null,
+ .ops = &clkops_omap4_dpllmx_ops,
.recalc = &omap2_clksel_recalc,
.round_rate = &omap2_clksel_round_rate,
.set_rate = &omap2_clksel_set_rate,
@@ -3158,11 +3166,11 @@ static struct omap_clk omap44xx_clks[] = {
CLK("omap2_mcspi.2", "fck", &mcspi2_fck, CK_443X),
CLK("omap2_mcspi.3", "fck", &mcspi3_fck, CK_443X),
CLK("omap2_mcspi.4", "fck", &mcspi4_fck, CK_443X),
- CLK("mmci-omap-hs.0", "fck", &mmc1_fck, CK_443X),
- CLK("mmci-omap-hs.1", "fck", &mmc2_fck, CK_443X),
- CLK("mmci-omap-hs.2", "fck", &mmc3_fck, CK_443X),
- CLK("mmci-omap-hs.3", "fck", &mmc4_fck, CK_443X),
- CLK("mmci-omap-hs.4", "fck", &mmc5_fck, CK_443X),
+ CLK("omap_hsmmc.0", "fck", &mmc1_fck, CK_443X),
+ CLK("omap_hsmmc.1", "fck", &mmc2_fck, CK_443X),
+ CLK("omap_hsmmc.2", "fck", &mmc3_fck, CK_443X),
+ CLK("omap_hsmmc.3", "fck", &mmc4_fck, CK_443X),
+ CLK("omap_hsmmc.4", "fck", &mmc5_fck, CK_443X),
CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X),
CLK(NULL, "ocp2scp_usb_phy_ick", &ocp2scp_usb_phy_ick, CK_443X),
CLK(NULL, "ocp_wp_noc_ick", &ocp_wp_noc_ick, CK_443X),
@@ -3245,11 +3253,11 @@ static struct omap_clk omap44xx_clks[] = {
CLK("omap_i2c.2", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.3", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.4", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.0", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.1", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.2", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.3", "ick", &dummy_ck, CK_443X),
- CLK("mmci-omap-hs.4", "ick", &dummy_ck, CK_443X),
+ CLK("omap_hsmmc.0", "ick", &dummy_ck, CK_443X),
+ CLK("omap_hsmmc.1", "ick", &dummy_ck, CK_443X),
+ CLK("omap_hsmmc.2", "ick", &dummy_ck, CK_443X),
+ CLK("omap_hsmmc.3", "ick", &dummy_ck, CK_443X),
+ CLK("omap_hsmmc.4", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.2", "ick", &dummy_ck, CK_443X),
CLK("omap-mcbsp.3", "ick", &dummy_ck, CK_443X),
@@ -3301,6 +3309,9 @@ int __init omap4xxx_clk_init(void)
omap2_init_clk_clkdm(c->lk.clk);
}
+ /* Disable autoidle on all clocks; let the PM code enable it later */
+ omap_clk_disable_autoidle_all();
+
recalculate_root_clocks();
/*
diff --git a/arch/arm/mach-omap2/clock_common_data.c b/arch/arm/mach-omap2/clock_common_data.c
index 1cf8131205fa..6424d46be14a 100644
--- a/arch/arm/mach-omap2/clock_common_data.c
+++ b/arch/arm/mach-omap2/clock_common_data.c
@@ -37,3 +37,9 @@ const struct clksel_rate gfx_l3_rates[] = {
{ .div = 0 }
};
+const struct clksel_rate dsp_ick_rates[] = {
+ { .div = 1, .val = 1, .flags = RATE_IN_24XX },
+ { .div = 2, .val = 2, .flags = RATE_IN_24XX },
+ { .div = 3, .val = 3, .flags = RATE_IN_243X },
+ { .div = 0 },
+};
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 58e42f76603f..ab878545bd9b 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -26,17 +26,8 @@
#include <linux/bitops.h>
-#include "prm2xxx_3xxx.h"
-#include "prm-regbits-24xx.h"
-#include "cm2xxx_3xxx.h"
-#include "cm-regbits-24xx.h"
-#include "cminst44xx.h"
-#include "prcm44xx.h"
-
#include <plat/clock.h>
-#include "powerdomain.h"
#include "clockdomain.h"
-#include <plat/prcm.h>
/* clkdm_list contains all registered struct clockdomains */
static LIST_HEAD(clkdm_list);
@@ -44,6 +35,7 @@ static LIST_HEAD(clkdm_list);
/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
static struct clkdm_autodep *autodeps;
+static struct clkdm_ops *arch_clkdm;
/* Private functions */
@@ -177,11 +169,11 @@ static void _autodep_lookup(struct clkdm_autodep *autodep)
* XXX autodeps are deprecated and should be removed at the earliest
* opportunity
*/
-static void _clkdm_add_autodeps(struct clockdomain *clkdm)
+void _clkdm_add_autodeps(struct clockdomain *clkdm)
{
struct clkdm_autodep *autodep;
- if (!autodeps)
+ if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
return;
for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
@@ -211,11 +203,11 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm)
* XXX autodeps are deprecated and should be removed at the earliest
* opportunity
*/
-static void _clkdm_del_autodeps(struct clockdomain *clkdm)
+void _clkdm_del_autodeps(struct clockdomain *clkdm)
{
struct clkdm_autodep *autodep;
- if (!autodeps)
+ if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
return;
for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
@@ -235,55 +227,29 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm)
}
/**
- * _enable_hwsup - place a clockdomain into hardware-supervised idle
- * @clkdm: struct clockdomain *
- *
- * Place the clockdomain into hardware-supervised idle mode. No return
- * value.
+ * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
+ * @clkdm: clockdomain that we are resolving dependencies for
+ * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
*
- * XXX Should this return an error if the clockdomain does not support
- * hardware-supervised idle mode?
- */
-static void _enable_hwsup(struct clockdomain *clkdm)
-{
- if (cpu_is_omap24xx())
- omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- else if (cpu_is_omap34xx())
- omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- else if (cpu_is_omap44xx())
- return omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
- else
- BUG();
-}
-
-/**
- * _disable_hwsup - place a clockdomain into software-supervised idle
- * @clkdm: struct clockdomain *
- *
- * Place the clockdomain @clkdm into software-supervised idle mode.
+ * Iterates through @clkdm_deps, looking up the struct clockdomain named by
+ * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
* No return value.
- *
- * XXX Should this return an error if the clockdomain does not support
- * software-supervised idle mode?
*/
-static void _disable_hwsup(struct clockdomain *clkdm)
+static void _resolve_clkdm_deps(struct clockdomain *clkdm,
+ struct clkdm_dep *clkdm_deps)
{
- if (cpu_is_omap24xx())
- omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- else if (cpu_is_omap34xx())
- omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
- else if (cpu_is_omap44xx())
- return omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
- else
- BUG();
+ struct clkdm_dep *cd;
+
+ for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (cd->clkdm)
+ continue;
+ cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
+ WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
+ clkdm->name, cd->clkdm_name);
+ }
}
/* Public functions */
@@ -292,6 +258,7 @@ static void _disable_hwsup(struct clockdomain *clkdm)
* clkdm_init - set up the clockdomain layer
* @clkdms: optional pointer to an array of clockdomains to register
* @init_autodeps: optional pointer to an array of autodeps to register
+ * @custom_funcs: func pointers for arch specfic implementations
*
* Set up internal state. If a pointer to an array of clockdomains
* @clkdms was supplied, loop through the list of clockdomains,
@@ -300,12 +267,18 @@ static void _disable_hwsup(struct clockdomain *clkdm)
* @init_autodeps was provided, register those. No return value.
*/
void clkdm_init(struct clockdomain **clkdms,
- struct clkdm_autodep *init_autodeps)
+ struct clkdm_autodep *init_autodeps,
+ struct clkdm_ops *custom_funcs)
{
struct clockdomain **c = NULL;
struct clockdomain *clkdm;
struct clkdm_autodep *autodep = NULL;
+ if (!custom_funcs)
+ WARN(1, "No custom clkdm functions registered\n");
+ else
+ arch_clkdm = custom_funcs;
+
if (clkdms)
for (c = clkdms; *c; c++)
_clkdm_register(*c);
@@ -321,11 +294,14 @@ void clkdm_init(struct clockdomain **clkdms,
*/
list_for_each_entry(clkdm, &clkdm_list, node) {
if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
- omap2_clkdm_wakeup(clkdm);
+ clkdm_wakeup(clkdm);
else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
- omap2_clkdm_deny_idle(clkdm);
+ clkdm_deny_idle(clkdm);
+ _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
clkdm_clear_all_wkdeps(clkdm);
+
+ _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
clkdm_clear_all_sleepdeps(clkdm);
}
}
@@ -422,32 +398,32 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
- pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
- clkdm1->name, clkdm2->name, __func__);
- return -EINVAL;
- }
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
pr_debug("clockdomain: hardware will wake up %s when %s wakes "
"up\n", clkdm1->name, clkdm2->name);
- omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -463,32 +439,32 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
- pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
- clkdm1->name, clkdm2->name, __func__);
- return -EINVAL;
- }
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
pr_debug("clockdomain: hardware will no longer wake up %s "
"after %s wakes up\n", clkdm1->name, clkdm2->name);
- omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -508,26 +484,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
- if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
- pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
- clkdm1->name, clkdm2->name, __func__);
- return -EINVAL;
- }
-
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
"%s when %s wakes up\n", clkdm1->name, clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
/* XXX It's faster to return the atomic wkdep_usecount */
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
- (1 << clkdm2->dep_bit));
+ return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
}
/**
@@ -542,33 +518,13 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
*/
int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
{
- struct clkdm_dep *cd;
- u32 mask = 0;
-
- if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
- pr_err("clockdomain: %s: %s: not yet implemented\n",
- clkdm->name, __func__);
- return -EINVAL;
- }
-
if (!clkdm)
return -EINVAL;
- for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- /* PRM accesses are slow, so minimize them */
- mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->wkdep_usecount, 0);
- }
-
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
+ return -EINVAL;
- return 0;
+ return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
}
/**
@@ -586,31 +542,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
pr_debug("clockdomain: will prevent %s from sleeping if %s "
"is active\n", clkdm1->name, clkdm2->name);
- omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -628,19 +586,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
@@ -648,12 +610,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
"sleeping if %s is active\n", clkdm1->name,
clkdm2->name);
- omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
- clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
}
- return 0;
+ return ret;
}
/**
@@ -675,25 +635,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
+ int ret = 0;
if (!clkdm1 || !clkdm2)
return -EINVAL;
cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
- if (IS_ERR(cd)) {
+ if (IS_ERR(cd))
+ ret = PTR_ERR(cd);
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
+ ret = -EINVAL;
+
+ if (ret) {
pr_debug("clockdomain: hardware cannot set/clear sleep "
"dependency affecting %s from %s\n", clkdm1->name,
clkdm2->name);
- return PTR_ERR(cd);
+ return ret;
}
/* XXX It's faster to return the atomic sleepdep_usecount */
- return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP,
- (1 << clkdm2->dep_bit));
+ return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
}
/**
@@ -708,35 +670,17 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
*/
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
{
- struct clkdm_dep *cd;
- u32 mask = 0;
-
- if (!cpu_is_omap34xx())
- return -EINVAL;
-
if (!clkdm)
return -EINVAL;
- for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
- if (!omap_chip_is(cd->omap_chip))
- continue;
-
- if (!cd->clkdm && cd->clkdm_name)
- cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
- /* PRM accesses are slow, so minimize them */
- mask |= 1 << cd->clkdm->dep_bit;
- atomic_set(&cd->sleepdep_usecount, 0);
- }
-
- omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
- OMAP3430_CM_SLEEPDEP);
+ if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
+ return -EINVAL;
- return 0;
+ return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
}
/**
- * omap2_clkdm_sleep - force clockdomain sleep transition
+ * clkdm_sleep - force clockdomain sleep transition
* @clkdm: struct clockdomain *
*
* Instruct the CM to force a sleep transition on the specified
@@ -744,7 +688,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
* clockdomain does not support software-initiated sleep; 0 upon
* success.
*/
-int omap2_clkdm_sleep(struct clockdomain *clkdm)
+int clkdm_sleep(struct clockdomain *clkdm)
{
if (!clkdm)
return -EINVAL;
@@ -755,33 +699,16 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm)
return -EINVAL;
}
- pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
-
- if (cpu_is_omap24xx()) {
-
- omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
- clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
-
- } else if (cpu_is_omap34xx()) {
-
- omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- } else if (cpu_is_omap44xx()) {
-
- omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
+ if (!arch_clkdm || !arch_clkdm->clkdm_sleep)
+ return -EINVAL;
- } else {
- BUG();
- };
+ pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
- return 0;
+ return arch_clkdm->clkdm_sleep(clkdm);
}
/**
- * omap2_clkdm_wakeup - force clockdomain wakeup transition
+ * clkdm_wakeup - force clockdomain wakeup transition
* @clkdm: struct clockdomain *
*
* Instruct the CM to force a wakeup transition on the specified
@@ -789,7 +716,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm)
* clockdomain does not support software-controlled wakeup; 0 upon
* success.
*/
-int omap2_clkdm_wakeup(struct clockdomain *clkdm)
+int clkdm_wakeup(struct clockdomain *clkdm)
{
if (!clkdm)
return -EINVAL;
@@ -800,33 +727,16 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
return -EINVAL;
}
- pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
-
- if (cpu_is_omap24xx()) {
-
- omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
- clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
-
- } else if (cpu_is_omap34xx()) {
-
- omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- } else if (cpu_is_omap44xx()) {
-
- omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
+ if (!arch_clkdm || !arch_clkdm->clkdm_wakeup)
+ return -EINVAL;
- } else {
- BUG();
- };
+ pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
- return 0;
+ return arch_clkdm->clkdm_wakeup(clkdm);
}
/**
- * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * clkdm_allow_idle - enable hwsup idle transitions for clkdm
* @clkdm: struct clockdomain *
*
* Allow the hardware to automatically switch the clockdomain @clkdm into
@@ -835,7 +745,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
* framework, wkdep/sleepdep autodependencies are added; this is so
* device drivers can read and write to the device. No return value.
*/
-void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
+void clkdm_allow_idle(struct clockdomain *clkdm)
{
if (!clkdm)
return;
@@ -846,27 +756,18 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
return;
}
+ if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
+ return;
+
pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
clkdm->name);
- /*
- * XXX This should be removed once TI adds wakeup/sleep
- * dependency code and data for OMAP4.
- */
- if (cpu_is_omap44xx()) {
- pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
- } else {
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_add_autodeps(clkdm);
- }
-
- _enable_hwsup(clkdm);
-
+ arch_clkdm->clkdm_allow_idle(clkdm);
pwrdm_clkdm_state_switch(clkdm);
}
/**
- * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * clkdm_deny_idle - disable hwsup idle transitions for clkdm
* @clkdm: struct clockdomain *
*
* Prevent the hardware from automatically switching the clockdomain
@@ -874,7 +775,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
* downstream clocks enabled in the clock framework, wkdep/sleepdep
* autodependencies are removed. No return value.
*/
-void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
+void clkdm_deny_idle(struct clockdomain *clkdm)
{
if (!clkdm)
return;
@@ -885,28 +786,20 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
return;
}
+ if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
+ return;
+
pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
clkdm->name);
- _disable_hwsup(clkdm);
-
- /*
- * XXX This should be removed once TI adds wakeup/sleep
- * dependency code and data for OMAP4.
- */
- if (cpu_is_omap44xx()) {
- pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
- } else {
- if (atomic_read(&clkdm->usecount) > 0)
- _clkdm_del_autodeps(clkdm);
- }
+ arch_clkdm->clkdm_deny_idle(clkdm);
}
/* Clockdomain-to-clock framework interface code */
/**
- * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
+ * clkdm_clk_enable - add an enabled downstream clock to this clkdm
* @clkdm: struct clockdomain *
* @clk: struct clk * of the enabled downstream clock
*
@@ -919,10 +812,8 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
* by on-chip processors. Returns -EINVAL if passed null pointers;
* returns 0 upon success or if the clockdomain is in hwsup idle mode.
*/
-int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
+int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
{
- bool hwsup = false;
-
/*
* XXX Rewrite this code to maintain a list of enabled
* downstream clocks for debugging purposes?
@@ -931,6 +822,9 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
if (!clkdm || !clk)
return -EINVAL;
+ if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable)
+ return -EINVAL;
+
if (atomic_inc_return(&clkdm->usecount) > 1)
return 0;
@@ -939,31 +833,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
clk->name);
- if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-
- if (!clkdm->clktrctrl_mask)
- return 0;
-
- hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- } else if (cpu_is_omap44xx()) {
-
- hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
-
- }
-
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- _disable_hwsup(clkdm);
- _clkdm_add_autodeps(clkdm);
- _enable_hwsup(clkdm);
- } else {
- omap2_clkdm_wakeup(clkdm);
- }
-
+ arch_clkdm->clkdm_clk_enable(clkdm);
pwrdm_wait_transition(clkdm->pwrdm.ptr);
pwrdm_clkdm_state_switch(clkdm);
@@ -971,7 +841,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
}
/**
- * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
+ * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
* @clkdm: struct clockdomain *
* @clk: struct clk * of the disabled downstream clock
*
@@ -984,10 +854,8 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
* is enabled; or returns 0 upon success or if the clockdomain is in
* hwsup idle mode.
*/
-int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
+int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
{
- bool hwsup = false;
-
/*
* XXX Rewrite this code to maintain a list of enabled
* downstream clocks for debugging purposes?
@@ -996,6 +864,9 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
if (!clkdm || !clk)
return -EINVAL;
+ if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable)
+ return -EINVAL;
+
#ifdef DEBUG
if (atomic_read(&clkdm->usecount) == 0) {
WARN_ON(1); /* underflow */
@@ -1011,31 +882,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
clk->name);
- if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-
- if (!clkdm->clktrctrl_mask)
- return 0;
-
- hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
- clkdm->clktrctrl_mask);
-
- } else if (cpu_is_omap44xx()) {
-
- hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
- clkdm->cm_inst,
- clkdm->clkdm_offs);
-
- }
-
- if (hwsup) {
- /* Disable HW transitions when we are changing deps */
- _disable_hwsup(clkdm);
- _clkdm_del_autodeps(clkdm);
- _enable_hwsup(clkdm);
- } else {
- omap2_clkdm_sleep(clkdm);
- }
-
+ arch_clkdm->clkdm_clk_disable(clkdm);
pwrdm_clkdm_state_switch(clkdm);
return 0;
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 9b459c26fb85..85b3dce65640 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -4,7 +4,7 @@
* OMAP2/3 clockdomain framework functions
*
* Copyright (C) 2008 Texas Instruments, Inc.
- * Copyright (C) 2008-2010 Nokia Corporation
+ * Copyright (C) 2008-2011 Nokia Corporation
*
* Paul Walmsley
*
@@ -22,11 +22,19 @@
#include <plat/clock.h>
#include <plat/cpu.h>
-/* Clockdomain capability flags */
+/*
+ * Clockdomain flags
+ *
+ * XXX Document CLKDM_CAN_* flags
+ *
+ * CLKDM_NO_AUTODEPS: Prevent "autodeps" from being added/removed from this
+ * clockdomain. (Currently, this applies to OMAP3 clockdomains only.)
+ */
#define CLKDM_CAN_FORCE_SLEEP (1 << 0)
#define CLKDM_CAN_FORCE_WAKEUP (1 << 1)
#define CLKDM_CAN_ENABLE_AUTO (1 << 2)
#define CLKDM_CAN_DISABLE_AUTO (1 << 3)
+#define CLKDM_NO_AUTODEPS (1 << 4)
#define CLKDM_CAN_HWSUP (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
#define CLKDM_CAN_SWSUP (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
@@ -116,7 +124,42 @@ struct clockdomain {
struct list_head node;
};
-void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *autodeps);
+/**
+ * struct clkdm_ops - Arch specfic function implementations
+ * @clkdm_add_wkdep: Add a wakeup dependency between clk domains
+ * @clkdm_del_wkdep: Delete a wakeup dependency between clk domains
+ * @clkdm_read_wkdep: Read wakeup dependency state between clk domains
+ * @clkdm_clear_all_wkdeps: Remove all wakeup dependencies from the clk domain
+ * @clkdm_add_sleepdep: Add a sleep dependency between clk domains
+ * @clkdm_del_sleepdep: Delete a sleep dependency between clk domains
+ * @clkdm_read_sleepdep: Read sleep dependency state between clk domains
+ * @clkdm_clear_all_sleepdeps: Remove all sleep dependencies from the clk domain
+ * @clkdm_sleep: Force a clockdomain to sleep
+ * @clkdm_wakeup: Force a clockdomain to wakeup
+ * @clkdm_allow_idle: Enable hw supervised idle transitions for clock domain
+ * @clkdm_deny_idle: Disable hw supervised idle transitions for clock domain
+ * @clkdm_clk_enable: Put the clkdm in right state for a clock enable
+ * @clkdm_clk_disable: Put the clkdm in right state for a clock disable
+ */
+struct clkdm_ops {
+ int (*clkdm_add_wkdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_del_wkdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_read_wkdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_clear_all_wkdeps)(struct clockdomain *clkdm);
+ int (*clkdm_add_sleepdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_del_sleepdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_read_sleepdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
+ int (*clkdm_clear_all_sleepdeps)(struct clockdomain *clkdm);
+ int (*clkdm_sleep)(struct clockdomain *clkdm);
+ int (*clkdm_wakeup)(struct clockdomain *clkdm);
+ void (*clkdm_allow_idle)(struct clockdomain *clkdm);
+ void (*clkdm_deny_idle)(struct clockdomain *clkdm);
+ int (*clkdm_clk_enable)(struct clockdomain *clkdm);
+ int (*clkdm_clk_disable)(struct clockdomain *clkdm);
+};
+
+void clkdm_init(struct clockdomain **clkdms, struct clkdm_autodep *autodeps,
+ struct clkdm_ops *custom_funcs);
struct clockdomain *clkdm_lookup(const char *name);
int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
@@ -132,16 +175,23 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
-void omap2_clkdm_allow_idle(struct clockdomain *clkdm);
-void omap2_clkdm_deny_idle(struct clockdomain *clkdm);
+void clkdm_allow_idle(struct clockdomain *clkdm);
+void clkdm_deny_idle(struct clockdomain *clkdm);
-int omap2_clkdm_wakeup(struct clockdomain *clkdm);
-int omap2_clkdm_sleep(struct clockdomain *clkdm);
+int clkdm_wakeup(struct clockdomain *clkdm);
+int clkdm_sleep(struct clockdomain *clkdm);
-int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
-int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
+int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
+int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
-extern void __init omap2_clockdomains_init(void);
+extern void __init omap2xxx_clockdomains_init(void);
+extern void __init omap3xxx_clockdomains_init(void);
extern void __init omap44xx_clockdomains_init(void);
+extern void _clkdm_add_autodeps(struct clockdomain *clkdm);
+extern void _clkdm_del_autodeps(struct clockdomain *clkdm);
+
+extern struct clkdm_ops omap2_clkdm_operations;
+extern struct clkdm_ops omap3_clkdm_operations;
+extern struct clkdm_ops omap4_clkdm_operations;
#endif
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
new file mode 100644
index 000000000000..48d0db7e6069
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -0,0 +1,274 @@
+/*
+ * OMAP2 and OMAP3 clockdomain control
+ *
+ * Copyright (C) 2008-2010 Texas Instruments, Inc.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <plat/prcm.h>
+#include "prm.h"
+#include "prm2xxx_3xxx.h"
+#include "cm.h"
+#include "cm2xxx_3xxx.h"
+#include "cm-regbits-24xx.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-24xx.h"
+#include "clockdomain.h"
+
+static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ return 0;
+}
+
+static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
+ return 0;
+}
+
+static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
+ PM_WKDEP, (1 << clkdm2->dep_bit));
+}
+
+static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ /* PRM accesses are slow, so minimize them */
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->wkdep_usecount, 0);
+ }
+
+ omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
+ PM_WKDEP);
+ return 0;
+}
+
+static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit));
+}
+
+static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ /* PRM accesses are slow, so minimize them */
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->sleepdep_usecount, 0);
+ }
+ omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
+ OMAP3430_CM_SLEEPDEP);
+ return 0;
+}
+
+static int omap2_clkdm_sleep(struct clockdomain *clkdm)
+{
+ omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
+ clkdm->pwrdm.ptr->prcm_offs,
+ OMAP2_PM_PWSTCTRL);
+ return 0;
+}
+
+static int omap2_clkdm_wakeup(struct clockdomain *clkdm)
+{
+ omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
+ clkdm->pwrdm.ptr->prcm_offs,
+ OMAP2_PM_PWSTCTRL);
+ return 0;
+}
+
+static void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_add_autodeps(clkdm);
+
+ omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+}
+
+static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+ omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_del_autodeps(clkdm);
+}
+
+static void _enable_hwsup(struct clockdomain *clkdm)
+{
+ if (cpu_is_omap24xx())
+ omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+ else if (cpu_is_omap34xx())
+ omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+}
+
+static void _disable_hwsup(struct clockdomain *clkdm)
+{
+ if (cpu_is_omap24xx())
+ omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+ else if (cpu_is_omap34xx())
+ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+}
+
+
+static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
+{
+ bool hwsup = false;
+
+ if (!clkdm->clktrctrl_mask)
+ return 0;
+
+ hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+
+ if (hwsup) {
+ /* Disable HW transitions when we are changing deps */
+ _disable_hwsup(clkdm);
+ _clkdm_add_autodeps(clkdm);
+ _enable_hwsup(clkdm);
+ } else {
+ clkdm_wakeup(clkdm);
+ }
+
+ return 0;
+}
+
+static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
+{
+ bool hwsup = false;
+
+ if (!clkdm->clktrctrl_mask)
+ return 0;
+
+ hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+
+ if (hwsup) {
+ /* Disable HW transitions when we are changing deps */
+ _disable_hwsup(clkdm);
+ _clkdm_del_autodeps(clkdm);
+ _enable_hwsup(clkdm);
+ } else {
+ clkdm_sleep(clkdm);
+ }
+
+ return 0;
+}
+
+static int omap3_clkdm_sleep(struct clockdomain *clkdm)
+{
+ omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+ return 0;
+}
+
+static int omap3_clkdm_wakeup(struct clockdomain *clkdm)
+{
+ omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+ return 0;
+}
+
+static void omap3_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_add_autodeps(clkdm);
+
+ omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+}
+
+static void omap3_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+ omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+
+ if (atomic_read(&clkdm->usecount) > 0)
+ _clkdm_del_autodeps(clkdm);
+}
+
+struct clkdm_ops omap2_clkdm_operations = {
+ .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
+ .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
+ .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
+ .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
+ .clkdm_sleep = omap2_clkdm_sleep,
+ .clkdm_wakeup = omap2_clkdm_wakeup,
+ .clkdm_allow_idle = omap2_clkdm_allow_idle,
+ .clkdm_deny_idle = omap2_clkdm_deny_idle,
+ .clkdm_clk_enable = omap2_clkdm_clk_enable,
+ .clkdm_clk_disable = omap2_clkdm_clk_disable,
+};
+
+struct clkdm_ops omap3_clkdm_operations = {
+ .clkdm_add_wkdep = omap2_clkdm_add_wkdep,
+ .clkdm_del_wkdep = omap2_clkdm_del_wkdep,
+ .clkdm_read_wkdep = omap2_clkdm_read_wkdep,
+ .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
+ .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep,
+ .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep,
+ .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep,
+ .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps,
+ .clkdm_sleep = omap3_clkdm_sleep,
+ .clkdm_wakeup = omap3_clkdm_wakeup,
+ .clkdm_allow_idle = omap3_clkdm_allow_idle,
+ .clkdm_deny_idle = omap3_clkdm_deny_idle,
+ .clkdm_clk_enable = omap2_clkdm_clk_enable,
+ .clkdm_clk_disable = omap2_clkdm_clk_disable,
+};
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
new file mode 100644
index 000000000000..a1a4ecd26544
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -0,0 +1,137 @@
+/*
+ * OMAP4 clockdomain control
+ *
+ * Copyright (C) 2008-2010 Texas Instruments, Inc.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Derived from mach-omap2/clockdomain.c written by Paul Walmsley
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include "clockdomain.h"
+#include "cminst44xx.h"
+#include "cm44xx.h"
+
+static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
+
+static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
+ clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
+
+static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
+ struct clockdomain *clkdm2)
+{
+ return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
+ clkdm1->cm_inst, clkdm1->clkdm_offs +
+ OMAP4_CM_STATICDEP,
+ (1 << clkdm2->dep_bit));
+}
+
+static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
+{
+ struct clkdm_dep *cd;
+ u32 mask = 0;
+
+ for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
+ if (!omap_chip_is(cd->omap_chip))
+ continue;
+ if (!cd->clkdm)
+ continue; /* only happens if data is erroneous */
+
+ mask |= 1 << cd->clkdm->dep_bit;
+ atomic_set(&cd->wkdep_usecount, 0);
+ }
+
+ omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs +
+ OMAP4_CM_STATICDEP);
+ return 0;
+}
+
+static int omap4_clkdm_sleep(struct clockdomain *clkdm)
+{
+ omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+ return 0;
+}
+
+static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
+{
+ omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+ return 0;
+}
+
+static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+ omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+}
+
+static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+ omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+}
+
+static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
+{
+ bool hwsup = false;
+
+ hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+
+ if (!hwsup)
+ clkdm_wakeup(clkdm);
+
+ return 0;
+}
+
+static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
+{
+ bool hwsup = false;
+
+ hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+
+ if (!hwsup)
+ clkdm_sleep(clkdm);
+
+ return 0;
+}
+
+struct clkdm_ops omap4_clkdm_operations = {
+ .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
+ .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
+ .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
+ .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
+ .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
+ .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
+ .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
+ .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
+ .clkdm_sleep = omap4_clkdm_sleep,
+ .clkdm_wakeup = omap4_clkdm_wakeup,
+ .clkdm_allow_idle = omap4_clkdm_allow_idle,
+ .clkdm_deny_idle = omap4_clkdm_deny_idle,
+ .clkdm_clk_enable = omap4_clkdm_clk_enable,
+ .clkdm_clk_disable = omap4_clkdm_clk_disable,
+};
diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
index e4a7133ea3b3..13bde95b6790 100644
--- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
@@ -89,6 +89,8 @@ static struct clkdm_dep gfx_sgx_wkdeps[] = {
/* 24XX-specific possible dependencies */
+#ifdef CONFIG_ARCH_OMAP2
+
/* Wakeup dependency source arrays */
/* 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP */
@@ -168,10 +170,11 @@ static struct clkdm_dep core_24xx_wkdeps[] = {
{ NULL },
};
+#endif /* CONFIG_ARCH_OMAP2 */
/* 2430-specific possible wakeup dependencies */
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
/* 2430 PM_WKDEP_MDM: CORE, MPU, WKUP */
static struct clkdm_dep mdm_2430_wkdeps[] = {
@@ -194,7 +197,7 @@ static struct clkdm_dep mdm_2430_wkdeps[] = {
{ NULL },
};
-#endif /* CONFIG_ARCH_OMAP2430 */
+#endif /* CONFIG_SOC_OMAP2430 */
/* OMAP3-specific possible dependencies */
@@ -450,7 +453,7 @@ static struct clockdomain cm_clkdm = {
* 2420-only clockdomains
*/
-#if defined(CONFIG_ARCH_OMAP2420)
+#if defined(CONFIG_SOC_OMAP2420)
static struct clockdomain mpu_2420_clkdm = {
.name = "mpu_clkdm",
@@ -514,14 +517,14 @@ static struct clockdomain dss_2420_clkdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
};
-#endif /* CONFIG_ARCH_OMAP2420 */
+#endif /* CONFIG_SOC_OMAP2420 */
/*
* 2430-only clockdomains
*/
-#if defined(CONFIG_ARCH_OMAP2430)
+#if defined(CONFIG_SOC_OMAP2430)
static struct clockdomain mpu_2430_clkdm = {
.name = "mpu_clkdm",
@@ -600,7 +603,7 @@ static struct clockdomain dss_2430_clkdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
};
-#endif /* CONFIG_ARCH_OMAP2430 */
+#endif /* CONFIG_SOC_OMAP2430 */
/*
@@ -811,7 +814,7 @@ static struct clockdomain *clockdomains_omap2[] __initdata = {
&cm_clkdm,
&prm_clkdm,
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
&mpu_2420_clkdm,
&iva1_2420_clkdm,
&dsp_2420_clkdm,
@@ -821,7 +824,7 @@ static struct clockdomain *clockdomains_omap2[] __initdata = {
&dss_2420_clkdm,
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
&mpu_2430_clkdm,
&mdm_clkdm,
&dsp_2430_clkdm,
@@ -854,7 +857,12 @@ static struct clockdomain *clockdomains_omap2[] __initdata = {
NULL,
};
-void __init omap2_clockdomains_init(void)
+void __init omap2xxx_clockdomains_init(void)
+{
+ clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap2_clkdm_operations);
+}
+
+void __init omap3xxx_clockdomains_init(void)
{
- clkdm_init(clockdomains_omap2, clkdm_autodeps);
+ clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap3_clkdm_operations);
}
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index 10622c914abc..a607ec196e8b 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -18,11 +18,6 @@
* published by the Free Software Foundation.
*/
-/*
- * To-Do List
- * -> Populate the Sleep/Wakeup dependencies for the domains
- */
-
#include <linux/kernel.h>
#include <linux/io.h>
@@ -35,6 +30,355 @@
#include "prcm44xx.h"
#include "prcm_mpu44xx.h"
+/* Static Dependencies for OMAP4 Clock Domains */
+
+static struct clkdm_dep ducati_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_2_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_dss_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_gfx_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_init_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_secure_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_wkup_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "tesla_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep iss_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep ivahd_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l3_d2d_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_2_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_init_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l3_dma_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ducati_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_dss_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_init_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_secure_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_wkup_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l3_dss_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_2_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l3_gfx_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l3_init_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_secure_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_wkup_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep l4_secure_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep mpuss_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ducati_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_2_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_dss_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_gfx_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_init_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_secure_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_wkup_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "tesla_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
+
+static struct clkdm_dep tesla_wkup_sleep_deps[] = {
+ {
+ .clkdm_name = "abe_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "ivahd_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_1_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_2_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_emif_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l3_init_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_cfg_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_per_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ {
+ .clkdm_name = "l4_wkup_clkdm",
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430)
+ },
+ { NULL },
+};
static struct clockdomain l4_cefuse_44xx_clkdm = {
.name = "l4_cefuse_clkdm",
@@ -52,6 +396,7 @@ static struct clockdomain l4_cfg_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_L4CFG_CDOFFS,
+ .dep_bit = OMAP4430_L4CFG_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -62,6 +407,9 @@ static struct clockdomain tesla_44xx_clkdm = {
.prcm_partition = OMAP4430_CM1_PARTITION,
.cm_inst = OMAP4430_CM1_TESLA_INST,
.clkdm_offs = OMAP4430_CM1_TESLA_TESLA_CDOFFS,
+ .dep_bit = OMAP4430_TESLA_STATDEP_SHIFT,
+ .wkdep_srcs = tesla_wkup_sleep_deps,
+ .sleepdep_srcs = tesla_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -72,6 +420,9 @@ static struct clockdomain l3_gfx_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_GFX_INST,
.clkdm_offs = OMAP4430_CM2_GFX_GFX_CDOFFS,
+ .dep_bit = OMAP4430_GFX_STATDEP_SHIFT,
+ .wkdep_srcs = l3_gfx_wkup_sleep_deps,
+ .sleepdep_srcs = l3_gfx_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -82,6 +433,9 @@ static struct clockdomain ivahd_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_IVAHD_INST,
.clkdm_offs = OMAP4430_CM2_IVAHD_IVAHD_CDOFFS,
+ .dep_bit = OMAP4430_IVAHD_STATDEP_SHIFT,
+ .wkdep_srcs = ivahd_wkup_sleep_deps,
+ .sleepdep_srcs = ivahd_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -92,6 +446,9 @@ static struct clockdomain l4_secure_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_L4PER_INST,
.clkdm_offs = OMAP4430_CM2_L4PER_L4SEC_CDOFFS,
+ .dep_bit = OMAP4430_L4SEC_STATDEP_SHIFT,
+ .wkdep_srcs = l4_secure_wkup_sleep_deps,
+ .sleepdep_srcs = l4_secure_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -102,6 +459,7 @@ static struct clockdomain l4_per_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_L4PER_INST,
.clkdm_offs = OMAP4430_CM2_L4PER_L4PER_CDOFFS,
+ .dep_bit = OMAP4430_L4PER_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -112,6 +470,7 @@ static struct clockdomain abe_44xx_clkdm = {
.prcm_partition = OMAP4430_CM1_PARTITION,
.cm_inst = OMAP4430_CM1_ABE_INST,
.clkdm_offs = OMAP4430_CM1_ABE_ABE_CDOFFS,
+ .dep_bit = OMAP4430_ABE_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -131,6 +490,9 @@ static struct clockdomain l3_init_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_L3INIT_INST,
.clkdm_offs = OMAP4430_CM2_L3INIT_L3INIT_CDOFFS,
+ .dep_bit = OMAP4430_L3INIT_STATDEP_SHIFT,
+ .wkdep_srcs = l3_init_wkup_sleep_deps,
+ .sleepdep_srcs = l3_init_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -141,6 +503,8 @@ static struct clockdomain mpuss_44xx_clkdm = {
.prcm_partition = OMAP4430_CM1_PARTITION,
.cm_inst = OMAP4430_CM1_MPU_INST,
.clkdm_offs = OMAP4430_CM1_MPU_MPU_CDOFFS,
+ .wkdep_srcs = mpuss_wkup_sleep_deps,
+ .sleepdep_srcs = mpuss_wkup_sleep_deps,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -150,7 +514,7 @@ static struct clockdomain mpu0_44xx_clkdm = {
.pwrdm = { .name = "cpu0_pwrdm" },
.prcm_partition = OMAP4430_PRCM_MPU_PARTITION,
.cm_inst = OMAP4430_PRCM_MPU_CPU0_INST,
- .clkdm_offs = OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS,
+ .clkdm_offs = OMAP4430_PRCM_MPU_CPU0_CPU0_CDOFFS,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -160,7 +524,7 @@ static struct clockdomain mpu1_44xx_clkdm = {
.pwrdm = { .name = "cpu1_pwrdm" },
.prcm_partition = OMAP4430_PRCM_MPU_PARTITION,
.cm_inst = OMAP4430_PRCM_MPU_CPU1_INST,
- .clkdm_offs = OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS,
+ .clkdm_offs = OMAP4430_PRCM_MPU_CPU1_CPU1_CDOFFS,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -171,6 +535,7 @@ static struct clockdomain l3_emif_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_MEMIF_CDOFFS,
+ .dep_bit = OMAP4430_MEMIF_STATDEP_SHIFT,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -191,6 +556,9 @@ static struct clockdomain ducati_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_DUCATI_CDOFFS,
+ .dep_bit = OMAP4430_DUCATI_STATDEP_SHIFT,
+ .wkdep_srcs = ducati_wkup_sleep_deps,
+ .sleepdep_srcs = ducati_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -201,6 +569,7 @@ static struct clockdomain l3_2_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_L3_2_CDOFFS,
+ .dep_bit = OMAP4430_L3_2_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -211,6 +580,7 @@ static struct clockdomain l3_1_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_L3_1_CDOFFS,
+ .dep_bit = OMAP4430_L3_1_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -221,6 +591,8 @@ static struct clockdomain l3_d2d_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_D2D_CDOFFS,
+ .wkdep_srcs = l3_d2d_wkup_sleep_deps,
+ .sleepdep_srcs = l3_d2d_wkup_sleep_deps,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -231,6 +603,8 @@ static struct clockdomain iss_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CAM_INST,
.clkdm_offs = OMAP4430_CM2_CAM_CAM_CDOFFS,
+ .wkdep_srcs = iss_wkup_sleep_deps,
+ .sleepdep_srcs = iss_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -241,6 +615,9 @@ static struct clockdomain l3_dss_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_DSS_INST,
.clkdm_offs = OMAP4430_CM2_DSS_DSS_CDOFFS,
+ .dep_bit = OMAP4430_DSS_STATDEP_SHIFT,
+ .wkdep_srcs = l3_dss_wkup_sleep_deps,
+ .sleepdep_srcs = l3_dss_wkup_sleep_deps,
.flags = CLKDM_CAN_HWSUP_SWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -251,6 +628,7 @@ static struct clockdomain l4_wkup_44xx_clkdm = {
.prcm_partition = OMAP4430_PRM_PARTITION,
.cm_inst = OMAP4430_PRM_WKUP_CM_INST,
.clkdm_offs = OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS,
+ .dep_bit = OMAP4430_L4WKUP_STATDEP_SHIFT,
.flags = CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -271,6 +649,8 @@ static struct clockdomain l3_dma_44xx_clkdm = {
.prcm_partition = OMAP4430_CM2_PARTITION,
.cm_inst = OMAP4430_CM2_CORE_INST,
.clkdm_offs = OMAP4430_CM2_CORE_SDMA_CDOFFS,
+ .wkdep_srcs = l3_dma_wkup_sleep_deps,
+ .sleepdep_srcs = l3_dma_wkup_sleep_deps,
.flags = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
@@ -305,5 +685,5 @@ static struct clockdomain *clockdomains_omap44xx[] __initdata = {
void __init omap44xx_clockdomains_init(void)
{
- clkdm_init(clockdomains_omap44xx, NULL);
+ clkdm_init(clockdomains_omap44xx, NULL, &omap4_clkdm_operations);
}
diff --git a/arch/arm/mach-omap2/cm-regbits-24xx.h b/arch/arm/mach-omap2/cm-regbits-24xx.h
index d70660e82fe6..686290437568 100644
--- a/arch/arm/mach-omap2/cm-regbits-24xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-24xx.h
@@ -210,8 +210,11 @@
#define OMAP24XX_AUTO_USB_MASK (1 << 0)
/* CM_AUTOIDLE3_CORE */
+#define OMAP24XX_AUTO_SDRC_SHIFT 2
#define OMAP24XX_AUTO_SDRC_MASK (1 << 2)
+#define OMAP24XX_AUTO_GPMC_SHIFT 1
#define OMAP24XX_AUTO_GPMC_MASK (1 << 1)
+#define OMAP24XX_AUTO_SDMA_SHIFT 0
#define OMAP24XX_AUTO_SDMA_MASK (1 << 0)
/* CM_AUTOIDLE4_CORE */
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.c b/arch/arm/mach-omap2/cm2xxx_3xxx.c
index 96954aa48671..9d0dec806e92 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.c
@@ -25,6 +25,14 @@
#include "cm-regbits-24xx.h"
#include "cm-regbits-34xx.h"
+/* CM_AUTOIDLE_PLL.AUTO_* bit values for DPLLs */
+#define DPLL_AUTOIDLE_DISABLE 0x0
+#define OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP 0x3
+
+/* CM_AUTOIDLE_PLL.AUTO_* bit values for APLLs (OMAP2xxx only) */
+#define OMAP2XXX_APLL_AUTOIDLE_DISABLE 0x0
+#define OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP 0x3
+
static const u8 cm_idlest_offs[] = {
CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
};
@@ -125,6 +133,67 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
_write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
}
+/*
+ * DPLL autoidle control
+ */
+
+static void _omap2xxx_set_dpll_autoidle(u8 m)
+{
+ u32 v;
+
+ v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
+ v &= ~OMAP24XX_AUTO_DPLL_MASK;
+ v |= m << OMAP24XX_AUTO_DPLL_SHIFT;
+ omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
+}
+
+void omap2xxx_cm_set_dpll_disable_autoidle(void)
+{
+ _omap2xxx_set_dpll_autoidle(OMAP2XXX_DPLL_AUTOIDLE_LOW_POWER_STOP);
+}
+
+void omap2xxx_cm_set_dpll_auto_low_power_stop(void)
+{
+ _omap2xxx_set_dpll_autoidle(DPLL_AUTOIDLE_DISABLE);
+}
+
+/*
+ * APLL autoidle control
+ */
+
+static void _omap2xxx_set_apll_autoidle(u8 m, u32 mask)
+{
+ u32 v;
+
+ v = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
+ v &= ~mask;
+ v |= m << __ffs(mask);
+ omap2_cm_write_mod_reg(v, PLL_MOD, CM_AUTOIDLE);
+}
+
+void omap2xxx_cm_set_apll54_disable_autoidle(void)
+{
+ _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP,
+ OMAP24XX_AUTO_54M_MASK);
+}
+
+void omap2xxx_cm_set_apll54_auto_low_power_stop(void)
+{
+ _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_DISABLE,
+ OMAP24XX_AUTO_54M_MASK);
+}
+
+void omap2xxx_cm_set_apll96_disable_autoidle(void)
+{
+ _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_LOW_POWER_STOP,
+ OMAP24XX_AUTO_96M_MASK);
+}
+
+void omap2xxx_cm_set_apll96_auto_low_power_stop(void)
+{
+ _omap2xxx_set_apll_autoidle(OMAP2XXX_APLL_AUTOIDLE_DISABLE,
+ OMAP24XX_AUTO_96M_MASK);
+}
/*
*
diff --git a/arch/arm/mach-omap2/cm2xxx_3xxx.h b/arch/arm/mach-omap2/cm2xxx_3xxx.h
index 5e9ea5bd60b9..088bbad73db5 100644
--- a/arch/arm/mach-omap2/cm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx_3xxx.h
@@ -122,6 +122,14 @@ extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask);
extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask);
+extern void omap2xxx_cm_set_dpll_disable_autoidle(void);
+extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void);
+
+extern void omap2xxx_cm_set_apll54_disable_autoidle(void);
+extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void);
+extern void omap2xxx_cm_set_apll96_disable_autoidle(void);
+extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void);
+
#endif
/* CM register bits shared between 24XX and 3430 */
diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 48fc3f426fbd..0b87ec82b41c 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -21,6 +21,7 @@
#include "cm.h"
#define OMAP4_CM_CLKSTCTRL 0x0000
+#define OMAP4_CM_STATICDEP 0x0004
/* Function prototypes */
# ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index c04bbbea17a5..a482bfa0a954 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -73,6 +73,27 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
return v;
}
+u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx)
+{
+ return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
+}
+
+u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, s16 inst, s16 idx)
+{
+ return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
+}
+
+u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
+{
+ u32 v;
+
+ v = omap4_cminst_read_inst_reg(part, inst, idx);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
/*
*
*/
diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h
index a6abd0a8cb82..2b32c181a2ee 100644
--- a/arch/arm/mach-omap2/cminst44xx.h
+++ b/arch/arm/mach-omap2/cminst44xx.h
@@ -25,6 +25,12 @@ extern u32 omap4_cminst_read_inst_reg(u8 part, s16 inst, u16 idx);
extern void omap4_cminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx);
extern u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part,
s16 inst, s16 idx);
+extern u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, s16 inst,
+ s16 idx);
+extern u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, s16 inst,
+ s16 idx);
+extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx,
+ u32 mask);
extern int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg);
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
index 778929f7e92d..3f20cbb9967b 100644
--- a/arch/arm/mach-omap2/common.c
+++ b/arch/arm/mach-omap2/common.c
@@ -40,7 +40,7 @@ static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
#endif
-#if defined(CONFIG_ARCH_OMAP2420)
+#if defined(CONFIG_SOC_OMAP2420)
static struct omap_globals omap242x_globals = {
.class = OMAP242X_CLASS,
@@ -50,9 +50,6 @@ static struct omap_globals omap242x_globals = {
.ctrl = OMAP242X_CTRL_BASE,
.prm = OMAP2420_PRM_BASE,
.cm = OMAP2420_CM_BASE,
- .uart1_phys = OMAP2_UART1_BASE,
- .uart2_phys = OMAP2_UART2_BASE,
- .uart3_phys = OMAP2_UART3_BASE,
};
void __init omap2_set_globals_242x(void)
@@ -61,7 +58,7 @@ void __init omap2_set_globals_242x(void)
}
#endif
-#if defined(CONFIG_ARCH_OMAP2430)
+#if defined(CONFIG_SOC_OMAP2430)
static struct omap_globals omap243x_globals = {
.class = OMAP243X_CLASS,
@@ -71,9 +68,6 @@ static struct omap_globals omap243x_globals = {
.ctrl = OMAP243X_CTRL_BASE,
.prm = OMAP2430_PRM_BASE,
.cm = OMAP2430_CM_BASE,
- .uart1_phys = OMAP2_UART1_BASE,
- .uart2_phys = OMAP2_UART2_BASE,
- .uart3_phys = OMAP2_UART3_BASE,
};
void __init omap2_set_globals_243x(void)
@@ -92,10 +86,6 @@ static struct omap_globals omap3_globals = {
.ctrl = OMAP343X_CTRL_BASE,
.prm = OMAP3430_PRM_BASE,
.cm = OMAP3430_CM_BASE,
- .uart1_phys = OMAP3_UART1_BASE,
- .uart2_phys = OMAP3_UART2_BASE,
- .uart3_phys = OMAP3_UART3_BASE,
- .uart4_phys = OMAP3_UART4_BASE, /* Only on 3630 */
};
void __init omap2_set_globals_3xxx(void)
@@ -108,6 +98,27 @@ void __init omap3_map_io(void)
omap2_set_globals_3xxx();
omap34xx_map_common_io();
}
+
+/*
+ * Adjust TAP register base such that omap3_check_revision accesses the correct
+ * TI816X register for checking device ID (it adds 0x204 to tap base while
+ * TI816X DEVICE ID register is at offset 0x600 from control base).
+ */
+#define TI816X_TAP_BASE (TI816X_CTRL_BASE + \
+ TI816X_CONTROL_DEVICE_ID - 0x204)
+
+static struct omap_globals ti816x_globals = {
+ .class = OMAP343X_CLASS,
+ .tap = OMAP2_L4_IO_ADDRESS(TI816X_TAP_BASE),
+ .ctrl = TI816X_CTRL_BASE,
+ .prm = TI816X_PRCM_BASE,
+ .cm = TI816X_PRCM_BASE,
+};
+
+void __init omap2_set_globals_ti816x(void)
+{
+ __omap2_set_globals(&ti816x_globals);
+}
#endif
#if defined(CONFIG_ARCH_OMAP4)
@@ -119,10 +130,6 @@ static struct omap_globals omap4_globals = {
.prm = OMAP4430_PRM_BASE,
.cm = OMAP4430_CM_BASE,
.cm2 = OMAP4430_CM2_BASE,
- .uart1_phys = OMAP4_UART1_BASE,
- .uart2_phys = OMAP4_UART2_BASE,
- .uart3_phys = OMAP4_UART3_BASE,
- .uart4_phys = OMAP4_UART4_BASE,
};
void __init omap2_set_globals_443x(void)
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index f0629ae04102..c2804c1c4efd 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -52,6 +52,9 @@
#define OMAP343X_CONTROL_PADCONFS_WKUP 0xa00
#define OMAP343X_CONTROL_GENERAL_WKUP 0xa60
+/* TI816X spefic control submodules */
+#define TI816X_CONTROL_DEVCONF 0x600
+
/* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
#define OMAP2_CONTROL_SYSCONFIG (OMAP2_CONTROL_INTERFACE + 0x10)
@@ -241,6 +244,9 @@
#define OMAP3_PADCONF_SAD2D_MSTANDBY 0x250
#define OMAP3_PADCONF_SAD2D_IDLEACK 0x254
+/* TI816X CONTROL_DEVCONF register offsets */
+#define TI816X_CONTROL_DEVICE_ID (TI816X_CONTROL_DEVCONF + 0x000)
+
/*
* REVISIT: This list of registers is not comprehensive - there are more
* that should be added.
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index f7b22a16f385..a44c52303405 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -58,6 +58,7 @@ struct omap3_processor_cx {
u32 core_state;
u32 threshold;
u32 flags;
+ const char *desc;
};
struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
@@ -99,14 +100,14 @@ static int omap3_idle_bm_check(void)
static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
{
- omap2_clkdm_allow_idle(clkdm);
+ clkdm_allow_idle(clkdm);
return 0;
}
static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
{
- omap2_clkdm_deny_idle(clkdm);
+ clkdm_deny_idle(clkdm);
return 0;
}
@@ -365,6 +366,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID;
+ omap3_power_states[OMAP3_STATE_C1].desc = "MPU ON + CORE ON";
/* C2 . MPU WFI + Core inactive */
omap3_power_states[OMAP3_STATE_C2].valid =
@@ -380,6 +382,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C2].desc = "MPU ON + CORE ON";
/* C3 . MPU CSWR + Core inactive */
omap3_power_states[OMAP3_STATE_C3].valid =
@@ -395,6 +398,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C3].desc = "MPU RET + CORE ON";
/* C4 . MPU OFF + Core inactive */
omap3_power_states[OMAP3_STATE_C4].valid =
@@ -410,6 +414,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON;
omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C4].desc = "MPU OFF + CORE ON";
/* C5 . MPU CSWR + Core CSWR*/
omap3_power_states[OMAP3_STATE_C5].valid =
@@ -425,6 +430,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C5].desc = "MPU RET + CORE RET";
/* C6 . MPU OFF + Core CSWR */
omap3_power_states[OMAP3_STATE_C6].valid =
@@ -440,6 +446,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C6].desc = "MPU OFF + CORE RET";
/* C7 . MPU OFF + Core OFF */
omap3_power_states[OMAP3_STATE_C7].valid =
@@ -455,6 +462,7 @@ void omap_init_power_states(void)
omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
CPUIDLE_FLAG_CHECK_BM;
+ omap3_power_states[OMAP3_STATE_C7].desc = "MPU OFF + CORE OFF";
/*
* Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
@@ -464,7 +472,7 @@ void omap_init_power_states(void)
if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
omap3_power_states[OMAP3_STATE_C7].valid = 0;
cpuidle_params_table[OMAP3_STATE_C7].valid = 0;
- WARN_ONCE(1, "%s: core off state C7 disabled due to i583\n",
+ pr_warn("%s: core off state C7 disabled due to i583\n",
__func__);
}
}
@@ -512,6 +520,7 @@ int __init omap3_idle_init(void)
if (cx->type == OMAP3_STATE_C1)
dev->safe_state = state;
sprintf(state->name, "C%d", count+1);
+ strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
count++;
}
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 2c9c912f2c42..0d2d6a9c303c 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
@@ -30,10 +31,75 @@
#include <plat/dma.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
+#include <plat/omap4-keypad.h>
#include "mux.h"
#include "control.h"
+#define L3_MODULES_MAX_LEN 12
+#define L3_MODULES 3
+
+static int __init omap3_l3_init(void)
+{
+ int l;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ char oh_name[L3_MODULES_MAX_LEN];
+
+ /*
+ * To avoid code running on other OMAPs in
+ * multi-omap builds
+ */
+ if (!(cpu_is_omap34xx()))
+ return -ENODEV;
+
+ l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
+
+ oh = omap_hwmod_lookup(oh_name);
+
+ if (!oh)
+ pr_err("could not look up %s\n", oh_name);
+
+ od = omap_device_build("omap_l3_smx", 0, oh, NULL, 0,
+ NULL, 0, 0);
+
+ WARN(IS_ERR(od), "could not build omap_device for %s\n", oh_name);
+
+ return PTR_ERR(od);
+}
+postcore_initcall(omap3_l3_init);
+
+static int __init omap4_l3_init(void)
+{
+ int l, i;
+ struct omap_hwmod *oh[3];
+ struct omap_device *od;
+ char oh_name[L3_MODULES_MAX_LEN];
+
+ /*
+ * To avoid code running on other OMAPs in
+ * multi-omap builds
+ */
+ if (!(cpu_is_omap44xx()))
+ return -ENODEV;
+
+ for (i = 0; i < L3_MODULES; i++) {
+ l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
+
+ oh[i] = omap_hwmod_lookup(oh_name);
+ if (!(oh[i]))
+ pr_err("could not look up %s\n", oh_name);
+ }
+
+ od = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL,
+ 0, NULL, 0, 0);
+
+ WARN(IS_ERR(od), "could not build omap_device for %s\n", oh_name);
+
+ return PTR_ERR(od);
+}
+postcore_initcall(omap4_l3_init);
+
#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
static struct resource cam_resources[] = {
@@ -141,96 +207,70 @@ static inline void omap_init_camera(void)
}
#endif
-#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
-
-#define MBOX_REG_SIZE 0x120
-
-#ifdef CONFIG_ARCH_OMAP2
-static struct resource omap2_mbox_resources[] = {
- {
- .start = OMAP24XX_MAILBOX_BASE,
- .end = OMAP24XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = INT_24XX_MAIL_U0_MPU,
- .flags = IORESOURCE_IRQ,
- .name = "dsp",
- },
+struct omap_device_pm_latency omap_keyboard_latency[] = {
{
- .start = INT_24XX_MAIL_U3_MPU,
- .flags = IORESOURCE_IRQ,
- .name = "iva",
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
};
-static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources);
-#else
-#define omap2_mbox_resources NULL
-#define omap2_mbox_resources_sz 0
-#endif
-#ifdef CONFIG_ARCH_OMAP3
-static struct resource omap3_mbox_resources[] = {
- {
- .start = OMAP34XX_MAILBOX_BASE,
- .end = OMAP34XX_MAILBOX_BASE + MBOX_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = INT_24XX_MAIL_U0_MPU,
- .flags = IORESOURCE_IRQ,
- .name = "dsp",
- },
-};
-static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources);
-#else
-#define omap3_mbox_resources NULL
-#define omap3_mbox_resources_sz 0
-#endif
+int __init omap4_keyboard_init(struct omap4_keypad_platform_data
+ *sdp4430_keypad_data)
+{
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ struct omap4_keypad_platform_data *keypad_data;
+ unsigned int id = -1;
+ char *oh_name = "kbd";
+ char *name = "omap4-keypad";
-#ifdef CONFIG_ARCH_OMAP4
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ return -ENODEV;
+ }
-#define OMAP4_MBOX_REG_SIZE 0x130
-static struct resource omap4_mbox_resources[] = {
- {
- .start = OMAP44XX_MAILBOX_BASE,
- .end = OMAP44XX_MAILBOX_BASE +
- OMAP4_MBOX_REG_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP44XX_IRQ_MAIL_U0,
- .flags = IORESOURCE_IRQ,
- .name = "mbox",
- },
-};
-static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources);
-#else
-#define omap4_mbox_resources NULL
-#define omap4_mbox_resources_sz 0
-#endif
+ keypad_data = sdp4430_keypad_data;
-static struct platform_device mbox_device = {
- .name = "omap-mailbox",
- .id = -1,
+ od = omap_device_build(name, id, oh, keypad_data,
+ sizeof(struct omap4_keypad_platform_data),
+ omap_keyboard_latency,
+ ARRAY_SIZE(omap_keyboard_latency), 0);
+
+ if (IS_ERR(od)) {
+ WARN(1, "Cant build omap_device for %s:%s.\n",
+ name, oh->name);
+ return PTR_ERR(od);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_OMAP_MBOX_FWK) || defined(CONFIG_OMAP_MBOX_FWK_MODULE)
+static struct omap_device_pm_latency mbox_latencies[] = {
+ [0] = {
+ .activate_func = omap_device_enable_hwmods,
+ .deactivate_func = omap_device_idle_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
};
static inline void omap_init_mbox(void)
{
- if (cpu_is_omap24xx()) {
- mbox_device.resource = omap2_mbox_resources;
- mbox_device.num_resources = omap2_mbox_resources_sz;
- } else if (cpu_is_omap34xx()) {
- mbox_device.resource = omap3_mbox_resources;
- mbox_device.num_resources = omap3_mbox_resources_sz;
- } else if (cpu_is_omap44xx()) {
- mbox_device.resource = omap4_mbox_resources;
- mbox_device.num_resources = omap4_mbox_resources_sz;
- } else {
- pr_err("%s: platform not supported\n", __func__);
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+
+ oh = omap_hwmod_lookup("mailbox");
+ if (!oh) {
+ pr_err("%s: unable to find hwmod\n", __func__);
return;
}
- platform_device_register(&mbox_device);
+
+ od = omap_device_build("omap-mailbox", -1, oh, NULL, 0,
+ mbox_latencies, ARRAY_SIZE(mbox_latencies), 0);
+ WARN(IS_ERR(od), "%s: could not build device, err %ld\n",
+ __func__, PTR_ERR(od));
}
#else
static inline void omap_init_mbox(void) { }
@@ -279,163 +319,55 @@ static inline void omap_init_audio(void) {}
#include <plat/mcspi.h>
-#define OMAP2_MCSPI1_BASE 0x48098000
-#define OMAP2_MCSPI2_BASE 0x4809a000
-#define OMAP2_MCSPI3_BASE 0x480b8000
-#define OMAP2_MCSPI4_BASE 0x480ba000
-
-#define OMAP4_MCSPI1_BASE 0x48098100
-#define OMAP4_MCSPI2_BASE 0x4809a100
-#define OMAP4_MCSPI3_BASE 0x480b8100
-#define OMAP4_MCSPI4_BASE 0x480ba100
-
-static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
- .num_cs = 4,
-};
-
-static struct resource omap2_mcspi1_resources[] = {
- {
- .start = OMAP2_MCSPI1_BASE,
- .end = OMAP2_MCSPI1_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device omap2_mcspi1 = {
- .name = "omap2_mcspi",
- .id = 1,
- .num_resources = ARRAY_SIZE(omap2_mcspi1_resources),
- .resource = omap2_mcspi1_resources,
- .dev = {
- .platform_data = &omap2_mcspi1_config,
- },
-};
-
-static struct omap2_mcspi_platform_config omap2_mcspi2_config = {
- .num_cs = 2,
-};
-
-static struct resource omap2_mcspi2_resources[] = {
- {
- .start = OMAP2_MCSPI2_BASE,
- .end = OMAP2_MCSPI2_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device omap2_mcspi2 = {
- .name = "omap2_mcspi",
- .id = 2,
- .num_resources = ARRAY_SIZE(omap2_mcspi2_resources),
- .resource = omap2_mcspi2_resources,
- .dev = {
- .platform_data = &omap2_mcspi2_config,
- },
-};
-
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
-static struct omap2_mcspi_platform_config omap2_mcspi3_config = {
- .num_cs = 2,
-};
-
-static struct resource omap2_mcspi3_resources[] = {
- {
- .start = OMAP2_MCSPI3_BASE,
- .end = OMAP2_MCSPI3_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device omap2_mcspi3 = {
- .name = "omap2_mcspi",
- .id = 3,
- .num_resources = ARRAY_SIZE(omap2_mcspi3_resources),
- .resource = omap2_mcspi3_resources,
- .dev = {
- .platform_data = &omap2_mcspi3_config,
- },
-};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-static struct omap2_mcspi_platform_config omap2_mcspi4_config = {
- .num_cs = 1,
-};
-
-static struct resource omap2_mcspi4_resources[] = {
- {
- .start = OMAP2_MCSPI4_BASE,
- .end = OMAP2_MCSPI4_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device omap2_mcspi4 = {
- .name = "omap2_mcspi",
- .id = 4,
- .num_resources = ARRAY_SIZE(omap2_mcspi4_resources),
- .resource = omap2_mcspi4_resources,
- .dev = {
- .platform_data = &omap2_mcspi4_config,
+struct omap_device_pm_latency omap_mcspi_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
};
-#endif
-#ifdef CONFIG_ARCH_OMAP4
-static inline void omap4_mcspi_fixup(void)
+static int omap_mcspi_init(struct omap_hwmod *oh, void *unused)
{
- omap2_mcspi1_resources[0].start = OMAP4_MCSPI1_BASE;
- omap2_mcspi1_resources[0].end = OMAP4_MCSPI1_BASE + 0xff;
- omap2_mcspi2_resources[0].start = OMAP4_MCSPI2_BASE;
- omap2_mcspi2_resources[0].end = OMAP4_MCSPI2_BASE + 0xff;
- omap2_mcspi3_resources[0].start = OMAP4_MCSPI3_BASE;
- omap2_mcspi3_resources[0].end = OMAP4_MCSPI3_BASE + 0xff;
- omap2_mcspi4_resources[0].start = OMAP4_MCSPI4_BASE;
- omap2_mcspi4_resources[0].end = OMAP4_MCSPI4_BASE + 0xff;
-}
-#else
-static inline void omap4_mcspi_fixup(void)
-{
-}
-#endif
+ struct omap_device *od;
+ char *name = "omap2_mcspi";
+ struct omap2_mcspi_platform_config *pdata;
+ static int spi_num;
+ struct omap2_mcspi_dev_attr *mcspi_attrib = oh->dev_attr;
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("Memory allocation for McSPI device failed\n");
+ return -ENOMEM;
+ }
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
- defined(CONFIG_ARCH_OMAP4)
-static inline void omap2_mcspi3_init(void)
-{
- platform_device_register(&omap2_mcspi3);
-}
-#else
-static inline void omap2_mcspi3_init(void)
-{
-}
-#endif
+ pdata->num_cs = mcspi_attrib->num_chipselect;
+ switch (oh->class->rev) {
+ case OMAP2_MCSPI_REV:
+ case OMAP3_MCSPI_REV:
+ pdata->regs_offset = 0;
+ break;
+ case OMAP4_MCSPI_REV:
+ pdata->regs_offset = OMAP4_MCSPI_REG_OFFSET;
+ break;
+ default:
+ pr_err("Invalid McSPI Revision value\n");
+ return -EINVAL;
+ }
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-static inline void omap2_mcspi4_init(void)
-{
- platform_device_register(&omap2_mcspi4);
-}
-#else
-static inline void omap2_mcspi4_init(void)
-{
+ spi_num++;
+ od = omap_device_build(name, spi_num, oh, pdata,
+ sizeof(*pdata), omap_mcspi_latency,
+ ARRAY_SIZE(omap_mcspi_latency), 0);
+ WARN(IS_ERR(od), "Cant build omap_device for %s:%s\n",
+ name, oh->name);
+ kfree(pdata);
+ return 0;
}
-#endif
static void omap_init_mcspi(void)
{
- if (cpu_is_omap44xx())
- omap4_mcspi_fixup();
-
- platform_device_register(&omap2_mcspi1);
- platform_device_register(&omap2_mcspi2);
-
- if (cpu_is_omap2430() || cpu_is_omap343x() || cpu_is_omap44xx())
- omap2_mcspi3_init();
-
- if (cpu_is_omap343x() || cpu_is_omap44xx())
- omap2_mcspi4_init();
+ omap_hwmod_for_each_by_class("mcspi", omap_mcspi_init, NULL);
}
#else
@@ -610,117 +542,10 @@ static inline void omap_init_aes(void) { }
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-
-#define MMCHS_SYSCONFIG 0x0010
-#define MMCHS_SYSCONFIG_SWRESET (1 << 1)
-#define MMCHS_SYSSTATUS 0x0014
-#define MMCHS_SYSSTATUS_RESETDONE (1 << 0)
-
-static struct platform_device dummy_pdev = {
- .dev = {
- .bus = &platform_bus_type,
- },
-};
-
-/**
- * omap_hsmmc_reset() - Full reset of each HS-MMC controller
- *
- * Ensure that each MMC controller is fully reset. Controllers
- * left in an unknown state (by bootloader) may prevent retention
- * or OFF-mode. This is especially important in cases where the
- * MMC driver is not enabled, _or_ built as a module.
- *
- * In order for reset to work, interface, functional and debounce
- * clocks must be enabled. The debounce clock comes from func_32k_clk
- * and is not under SW control, so we only enable i- and f-clocks.
- **/
-static void __init omap_hsmmc_reset(void)
-{
- u32 i, nr_controllers;
- struct clk *iclk, *fclk;
-
- if (cpu_is_omap242x())
- return;
-
- nr_controllers = cpu_is_omap44xx() ? OMAP44XX_NR_MMC :
- (cpu_is_omap34xx() ? OMAP34XX_NR_MMC : OMAP24XX_NR_MMC);
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
- for (i = 0; i < nr_controllers; i++) {
- u32 v, base = 0;
- struct device *dev = &dummy_pdev.dev;
-
- switch (i) {
- case 0:
- base = OMAP2_MMC1_BASE;
- break;
- case 1:
- base = OMAP2_MMC2_BASE;
- break;
- case 2:
- base = OMAP3_MMC3_BASE;
- break;
- case 3:
- if (!cpu_is_omap44xx())
- return;
- base = OMAP4_MMC4_BASE;
- break;
- case 4:
- if (!cpu_is_omap44xx())
- return;
- base = OMAP4_MMC5_BASE;
- break;
- }
-
- if (cpu_is_omap44xx())
- base += OMAP4_MMC_REG_OFFSET;
-
- dummy_pdev.id = i;
- dev_set_name(&dummy_pdev.dev, "mmci-omap-hs.%d", i);
- iclk = clk_get(dev, "ick");
- if (IS_ERR(iclk))
- goto err1;
- if (clk_enable(iclk))
- goto err2;
-
- fclk = clk_get(dev, "fck");
- if (IS_ERR(fclk))
- goto err3;
- if (clk_enable(fclk))
- goto err4;
-
- omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG);
- v = omap_readl(base + MMCHS_SYSSTATUS);
- while (!(omap_readl(base + MMCHS_SYSSTATUS) &
- MMCHS_SYSSTATUS_RESETDONE))
- cpu_relax();
-
- clk_disable(fclk);
- clk_put(fclk);
- clk_disable(iclk);
- clk_put(iclk);
- }
- return;
-
-err4:
- clk_put(fclk);
-err3:
- clk_disable(iclk);
-err2:
- clk_put(iclk);
-err1:
- printk(KERN_WARNING "%s: Unable to enable clocks for MMC%d, "
- "cannot reset.\n", __func__, i);
-}
-#else
-static inline void omap_hsmmc_reset(void) {}
-#endif
-
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
- defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
-
-static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
- int controller_nr)
+static inline void omap242x_mmc_mux(struct omap_mmc_platform_data
+ *mmc_controller)
{
if ((mmc_controller->slots[0].switch_pin > 0) && \
(mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
@@ -731,163 +556,44 @@ static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
OMAP_PIN_INPUT_PULLUP);
- if (cpu_is_omap2420() && controller_nr == 0) {
- omap_mux_init_signal("sdmmc_cmd", 0);
- omap_mux_init_signal("sdmmc_clki", 0);
- omap_mux_init_signal("sdmmc_clko", 0);
- omap_mux_init_signal("sdmmc_dat0", 0);
- omap_mux_init_signal("sdmmc_dat_dir0", 0);
- omap_mux_init_signal("sdmmc_cmd_dir", 0);
- if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
- omap_mux_init_signal("sdmmc_dat1", 0);
- omap_mux_init_signal("sdmmc_dat2", 0);
- omap_mux_init_signal("sdmmc_dat3", 0);
- omap_mux_init_signal("sdmmc_dat_dir1", 0);
- omap_mux_init_signal("sdmmc_dat_dir2", 0);
- omap_mux_init_signal("sdmmc_dat_dir3", 0);
- }
-
- /*
- * Use internal loop-back in MMC/SDIO Module Input Clock
- * selection
- */
- if (mmc_controller->slots[0].internal_clock) {
- u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
- v |= (1 << 24);
- omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
- }
+ omap_mux_init_signal("sdmmc_cmd", 0);
+ omap_mux_init_signal("sdmmc_clki", 0);
+ omap_mux_init_signal("sdmmc_clko", 0);
+ omap_mux_init_signal("sdmmc_dat0", 0);
+ omap_mux_init_signal("sdmmc_dat_dir0", 0);
+ omap_mux_init_signal("sdmmc_cmd_dir", 0);
+ if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
+ omap_mux_init_signal("sdmmc_dat1", 0);
+ omap_mux_init_signal("sdmmc_dat2", 0);
+ omap_mux_init_signal("sdmmc_dat3", 0);
+ omap_mux_init_signal("sdmmc_dat_dir1", 0);
+ omap_mux_init_signal("sdmmc_dat_dir2", 0);
+ omap_mux_init_signal("sdmmc_dat_dir3", 0);
}
- if (cpu_is_omap34xx()) {
- if (controller_nr == 0) {
- omap_mux_init_signal("sdmmc1_clk",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_cmd",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat0",
- OMAP_PIN_INPUT_PULLUP);
- if (mmc_controller->slots[0].caps &
- (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
- omap_mux_init_signal("sdmmc1_dat1",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat2",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat3",
- OMAP_PIN_INPUT_PULLUP);
- }
- if (mmc_controller->slots[0].caps &
- MMC_CAP_8_BIT_DATA) {
- omap_mux_init_signal("sdmmc1_dat4",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat5",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat6",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc1_dat7",
- OMAP_PIN_INPUT_PULLUP);
- }
- }
- if (controller_nr == 1) {
- /* MMC2 */
- omap_mux_init_signal("sdmmc2_clk",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_cmd",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat0",
- OMAP_PIN_INPUT_PULLUP);
-
- /*
- * For 8 wire configurations, Lines DAT4, 5, 6 and 7 need to be muxed
- * in the board-*.c files
- */
- if (mmc_controller->slots[0].caps &
- (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
- omap_mux_init_signal("sdmmc2_dat1",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat2",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat3",
- OMAP_PIN_INPUT_PULLUP);
- }
- if (mmc_controller->slots[0].caps &
- MMC_CAP_8_BIT_DATA) {
- omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat6.sdmmc2_dat6",
- OMAP_PIN_INPUT_PULLUP);
- omap_mux_init_signal("sdmmc2_dat7.sdmmc2_dat7",
- OMAP_PIN_INPUT_PULLUP);
- }
- }
-
- /*
- * For MMC3 the pins need to be muxed in the board-*.c files
- */
+ /*
+ * Use internal loop-back in MMC/SDIO Module Input Clock
+ * selection
+ */
+ if (mmc_controller->slots[0].internal_clock) {
+ u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+ v |= (1 << 24);
+ omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
}
}
-void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
- int nr_controllers)
+void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
{
- int i;
- char *name;
+ char *name = "mmci-omap";
- for (i = 0; i < nr_controllers; i++) {
- unsigned long base, size;
- unsigned int irq = 0;
-
- if (!mmc_data[i])
- continue;
-
- omap2_mmc_mux(mmc_data[i], i);
+ if (!mmc_data[0]) {
+ pr_err("%s fails: Incomplete platform data\n", __func__);
+ return;
+ }
- switch (i) {
- case 0:
- base = OMAP2_MMC1_BASE;
- irq = INT_24XX_MMC_IRQ;
- break;
- case 1:
- base = OMAP2_MMC2_BASE;
- irq = INT_24XX_MMC2_IRQ;
- break;
- case 2:
- if (!cpu_is_omap44xx() && !cpu_is_omap34xx())
- return;
- base = OMAP3_MMC3_BASE;
- irq = INT_34XX_MMC3_IRQ;
- break;
- case 3:
- if (!cpu_is_omap44xx())
- return;
- base = OMAP4_MMC4_BASE;
- irq = OMAP44XX_IRQ_MMC4;
- break;
- case 4:
- if (!cpu_is_omap44xx())
- return;
- base = OMAP4_MMC5_BASE;
- irq = OMAP44XX_IRQ_MMC5;
- break;
- default:
- continue;
- }
-
- if (cpu_is_omap2420()) {
- size = OMAP2420_MMC_SIZE;
- name = "mmci-omap";
- } else if (cpu_is_omap44xx()) {
- if (i < 3)
- irq += OMAP44XX_IRQ_GIC_START;
- size = OMAP4_HSMMC_SIZE;
- name = "mmci-omap-hs";
- } else {
- size = OMAP3_HSMMC_SIZE;
- name = "mmci-omap-hs";
- }
- omap_mmc_add(name, i, base, size, irq, mmc_data[i]);
- };
+ omap242x_mmc_mux(mmc_data[0]);
+ omap_mmc_add(name, 0, OMAP2_MMC1_BASE, OMAP2420_MMC_SIZE,
+ INT_24XX_MMC_IRQ, mmc_data[0]);
}
#endif
@@ -895,7 +601,7 @@ void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
#define OMAP_HDQ_BASE 0x480B2000
#endif
static struct resource omap_hdq_resources[] = {
@@ -961,7 +667,6 @@ static int __init omap2_init_devices(void)
* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
- omap_hsmmc_reset();
omap_init_audio();
omap_init_camera();
omap_init_mbox();
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
new file mode 100644
index 000000000000..b18db84b0349
--- /dev/null
+++ b/arch/arm/mach-omap2/display.c
@@ -0,0 +1,45 @@
+/*
+ * OMAP2plus display device setup / initialization.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Senthilvadivu Guruswamy
+ * Sumit Semwal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/display.h>
+
+static struct platform_device omap_display_device = {
+ .name = "omapdss",
+ .id = -1,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+int __init omap_display_init(struct omap_dss_board_info *board_data)
+{
+ int r = 0;
+ omap_display_device.dev.platform_data = board_data;
+
+ r = platform_device_register(&omap_display_device);
+ if (r < 0)
+ printk(KERN_ERR "Unable to register OMAP-Display device\n");
+
+ return r;
+}
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
new file mode 100644
index 000000000000..4e4da6160d05
--- /dev/null
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -0,0 +1,84 @@
+/*
+ * OMAP4-specific DPLL control functions
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Rajendra Nayak
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <plat/cpu.h>
+#include <plat/clock.h>
+
+#include "clock.h"
+#include "cm-regbits-44xx.h"
+
+/* Supported only on OMAP4 */
+int omap4_dpllmx_gatectrl_read(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return -EINVAL;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
+void omap4_dpllmx_allow_gatectrl(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ /* Clear the bit to allow gatectrl */
+ v &= ~mask;
+ __raw_writel(v, clk->clksel_reg);
+}
+
+void omap4_dpllmx_deny_gatectrl(struct clk *clk)
+{
+ u32 v;
+ u32 mask;
+
+ if (!clk || !clk->clksel_reg || !cpu_is_omap44xx())
+ return;
+
+ mask = clk->flags & CLOCK_CLKOUTX2 ?
+ OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
+ OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
+
+ v = __raw_readl(clk->clksel_reg);
+ /* Set the bit to deny gatectrl */
+ v |= mask;
+ __raw_writel(v, clk->clksel_reg);
+}
+
+const struct clkops clkops_omap4_dpllmx_ops = {
+ .allow_idle = omap4_dpllmx_allow_gatectrl,
+ .deny_idle = omap4_dpllmx_deny_gatectrl,
+};
+
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index 2bb29c160702..c1791d08ae56 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/mtd/nand.h>
#include <asm/mach/flash.h>
@@ -69,8 +70,10 @@ static int omap2_nand_gpmc_retime(void)
t.wr_cycle = gpmc_round_ns_to_ticks(gpmc_nand_data->gpmc_t->wr_cycle);
/* Configure GPMC */
- gpmc_cs_configure(gpmc_nand_data->cs,
- GPMC_CONFIG_DEV_SIZE, gpmc_nand_data->devsize);
+ if (gpmc_nand_data->devsize == NAND_BUSWIDTH_16)
+ gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 1);
+ else
+ gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0);
gpmc_cs_configure(gpmc_nand_data->cs,
GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND);
err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t);
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 3a7d25fb00ef..d776ded9830d 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -94,7 +94,7 @@ static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
}
static void set_onenand_cfg(void __iomem *onenand_base, int latency,
- int sync_read, int sync_write, int hf)
+ int sync_read, int sync_write, int hf, int vhf)
{
u32 reg;
@@ -114,12 +114,57 @@ static void set_onenand_cfg(void __iomem *onenand_base, int latency,
reg |= ONENAND_SYS_CFG1_HF;
else
reg &= ~ONENAND_SYS_CFG1_HF;
+ if (vhf)
+ reg |= ONENAND_SYS_CFG1_VHF;
+ else
+ reg &= ~ONENAND_SYS_CFG1_VHF;
writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}
+static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
+ void __iomem *onenand_base, bool *clk_dep)
+{
+ u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
+ int freq = 0;
+
+ if (cfg->get_freq) {
+ struct onenand_freq_info fi;
+
+ fi.maf_id = readw(onenand_base + ONENAND_REG_MANUFACTURER_ID);
+ fi.dev_id = readw(onenand_base + ONENAND_REG_DEVICE_ID);
+ fi.ver_id = ver;
+ freq = cfg->get_freq(&fi, clk_dep);
+ if (freq)
+ return freq;
+ }
+
+ switch ((ver >> 4) & 0xf) {
+ case 0:
+ freq = 40;
+ break;
+ case 1:
+ freq = 54;
+ break;
+ case 2:
+ freq = 66;
+ break;
+ case 3:
+ freq = 83;
+ break;
+ case 4:
+ freq = 104;
+ break;
+ default:
+ freq = 54;
+ break;
+ }
+
+ return freq;
+}
+
static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
void __iomem *onenand_base,
- int freq)
+ int *freq_ptr)
{
struct gpmc_timings t;
const int t_cer = 15;
@@ -130,10 +175,11 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
- int first_time = 0, hf = 0, sync_read = 0, sync_write = 0;
+ int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
int err, ticks_cez;
- int cs = cfg->cs;
+ int cs = cfg->cs, freq = *freq_ptr;
u32 reg;
+ bool clk_dep = false;
if (cfg->flags & ONENAND_SYNC_READ) {
sync_read = 1;
@@ -148,27 +194,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
err = omap2_onenand_set_async_mode(cs, onenand_base);
if (err)
return err;
- reg = readw(onenand_base + ONENAND_REG_VERSION_ID);
- switch ((reg >> 4) & 0xf) {
- case 0:
- freq = 40;
- break;
- case 1:
- freq = 54;
- break;
- case 2:
- freq = 66;
- break;
- case 3:
- freq = 83;
- break;
- case 4:
- freq = 104;
- break;
- default:
- freq = 54;
- break;
- }
+ freq = omap2_onenand_get_freq(cfg, onenand_base, &clk_dep);
first_time = 1;
}
@@ -180,7 +206,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
t_avdh = 2;
t_ach = 3;
t_aavdh = 6;
- t_rdyo = 9;
+ t_rdyo = 6;
break;
case 83:
min_gpmc_clk_period = 12000; /* 83 MHz */
@@ -217,16 +243,36 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
gpmc_clk_ns = gpmc_ticks_to_ns(div);
if (gpmc_clk_ns < 15) /* >66Mhz */
hf = 1;
- if (hf)
+ if (gpmc_clk_ns < 12) /* >83Mhz */
+ vhf = 1;
+ if (vhf)
+ latency = 8;
+ else if (hf)
latency = 6;
else if (gpmc_clk_ns >= 25) /* 40 MHz*/
latency = 3;
else
latency = 4;
+ if (clk_dep) {
+ if (gpmc_clk_ns < 12) { /* >83Mhz */
+ t_ces = 3;
+ t_avds = 4;
+ } else if (gpmc_clk_ns < 15) { /* >66Mhz */
+ t_ces = 5;
+ t_avds = 4;
+ } else if (gpmc_clk_ns < 25) { /* >40Mhz */
+ t_ces = 6;
+ t_avds = 5;
+ } else {
+ t_ces = 7;
+ t_avds = 7;
+ }
+ }
+
if (first_time)
set_onenand_cfg(onenand_base, latency,
- sync_read, sync_write, hf);
+ sync_read, sync_write, hf, vhf);
if (div == 1) {
reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
@@ -264,6 +310,9 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
/* Read */
t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
+ /* Force at least 1 clk between AVD High to OE Low */
+ if (t.oe_on <= t.adv_rd_off)
+ t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
t.cs_rd_off = t.oe_off;
@@ -317,18 +366,20 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
if (err)
return err;
- set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf);
+ set_onenand_cfg(onenand_base, latency, sync_read, sync_write, hf, vhf);
+
+ *freq_ptr = freq;
return 0;
}
-static int gpmc_onenand_setup(void __iomem *onenand_base, int freq)
+static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
{
struct device *dev = &gpmc_onenand_device.dev;
/* Set sync timings in GPMC */
if (omap2_onenand_set_sync_mode(gpmc_onenand_data, onenand_base,
- freq) < 0) {
+ freq_ptr) < 0) {
dev_err(dev, "Unable to set synchronous mode\n");
return -EINVAL;
}
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1b7b3e7d02f7..674174365f78 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -14,6 +14,7 @@
*/
#undef DEBUG
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
@@ -22,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <asm/mach-types.h>
#include <plat/gpmc.h>
@@ -58,7 +60,6 @@
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
-#define PREFETCH_FIFOTHRESHOLD (0x40 << 8)
#define CS_NUM_SHIFT 24
#define ENABLE_PREFETCH (0x1 << 7)
#define DMA_MPU_MODE 2
@@ -100,6 +101,8 @@ static void __iomem *gpmc_base;
static struct clk *gpmc_l3_clk;
+static irqreturn_t gpmc_handle_irq(int irq, void *dev);
+
static void gpmc_write_reg(int idx, u32 val)
{
__raw_writel(val, gpmc_base + idx);
@@ -497,6 +500,10 @@ int gpmc_cs_configure(int cs, int cmd, int wval)
u32 regval = 0;
switch (cmd) {
+ case GPMC_ENABLE_IRQ:
+ gpmc_write_reg(GPMC_IRQENABLE, wval);
+ break;
+
case GPMC_SET_IRQ_STATUS:
gpmc_write_reg(GPMC_IRQSTATUS, wval);
break;
@@ -598,15 +605,19 @@ EXPORT_SYMBOL(gpmc_nand_write);
/**
* gpmc_prefetch_enable - configures and starts prefetch transfer
* @cs: cs (chip select) number
+ * @fifo_th: fifo threshold to be used for read/ write
* @dma_mode: dma mode enable (1) or disable (0)
* @u32_count: number of bytes to be transferred
* @is_write: prefetch read(0) or write post(1) mode
*/
-int gpmc_prefetch_enable(int cs, int dma_mode,
+int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
unsigned int u32_count, int is_write)
{
- if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+ if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) {
+ pr_err("gpmc: fifo threshold is not supported\n");
+ return -1;
+ } else if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
/* Set the amount of bytes to be prefetched */
gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
@@ -614,7 +625,7 @@ int gpmc_prefetch_enable(int cs, int dma_mode,
* enable the engine. Set which cs is has requested for.
*/
gpmc_write_reg(GPMC_PREFETCH_CONFIG1, ((cs << CS_NUM_SHIFT) |
- PREFETCH_FIFOTHRESHOLD |
+ PREFETCH_FIFOTHRESHOLD(fifo_th) |
ENABLE_PREFETCH |
(dma_mode << DMA_MPU_MODE) |
(0x1 & is_write)));
@@ -678,9 +689,10 @@ static void __init gpmc_mem_init(void)
}
}
-void __init gpmc_init(void)
+static int __init gpmc_init(void)
{
- u32 l;
+ u32 l, irq;
+ int cs, ret = -EINVAL;
char *ck = NULL;
if (cpu_is_omap24xx()) {
@@ -698,7 +710,7 @@ void __init gpmc_init(void)
}
if (WARN_ON(!ck))
- return;
+ return ret;
gpmc_l3_clk = clk_get(NULL, ck);
if (IS_ERR(gpmc_l3_clk)) {
@@ -723,6 +735,36 @@ void __init gpmc_init(void)
l |= (0x02 << 3) | (1 << 0);
gpmc_write_reg(GPMC_SYSCONFIG, l);
gpmc_mem_init();
+
+ /* initalize the irq_chained */
+ irq = OMAP_GPMC_IRQ_BASE;
+ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+ set_irq_handler(irq, handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ irq++;
+ }
+
+ ret = request_irq(INT_34XX_GPMC_IRQ,
+ gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base);
+ if (ret)
+ pr_err("gpmc: irq-%d could not claim: err %d\n",
+ INT_34XX_GPMC_IRQ, ret);
+ return ret;
+}
+postcore_initcall(gpmc_init);
+
+static irqreturn_t gpmc_handle_irq(int irq, void *dev)
+{
+ u8 cs;
+
+ if (irq != INT_34XX_GPMC_IRQ)
+ return IRQ_HANDLED;
+ /* check cs to invoke the irq */
+ cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7;
+ if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END)
+ generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs);
+
+ return IRQ_HANDLED;
}
#ifdef CONFIG_ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 34272e4863fd..137e1a5f3d85 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -16,7 +16,10 @@
#include <mach/hardware.h>
#include <plat/mmc.h>
#include <plat/omap-pm.h>
+#include <plat/mux.h>
+#include <plat/omap_device.h>
+#include "mux.h"
#include "hsmmc.h"
#include "control.h"
@@ -28,10 +31,6 @@ static u16 control_mmc1;
#define HSMMC_NAME_LEN 9
-static struct hsmmc_controller {
- char name[HSMMC_NAME_LEN + 1];
-} hsmmc[OMAP34XX_NR_MMC];
-
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
static int hsmmc_get_context_loss(struct device *dev)
@@ -204,174 +203,312 @@ static int nop_mmc_set_power(struct device *dev, int slot, int power_on,
return 0;
}
-static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
-
-void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
+static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
+ int controller_nr)
{
- struct omap2_hsmmc_info *c;
- int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
- int i;
- u32 reg;
-
- if (!cpu_is_omap44xx()) {
- if (cpu_is_omap2430()) {
- control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
- control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1;
- } else {
- control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
- control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
- }
- } else {
- control_pbias_offset =
- OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE;
- control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1;
- reg = omap4_ctrl_pad_readl(control_mmc1);
- reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK |
- OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK);
- reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK |
- OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK);
- reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK|
- OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK |
- OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK);
- omap4_ctrl_pad_writel(reg, control_mmc1);
- }
-
- for (c = controllers; c->mmc; c++) {
- struct hsmmc_controller *hc = hsmmc + c->mmc - 1;
- struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
-
- if (!c->mmc || c->mmc > nr_hsmmc) {
- pr_debug("MMC%d: no such controller\n", c->mmc);
- continue;
- }
- if (mmc) {
- pr_debug("MMC%d: already configured\n", c->mmc);
- continue;
+ if ((mmc_controller->slots[0].switch_pin > 0) && \
+ (mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
+ omap_mux_init_gpio(mmc_controller->slots[0].switch_pin,
+ OMAP_PIN_INPUT_PULLUP);
+ if ((mmc_controller->slots[0].gpio_wp > 0) && \
+ (mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES))
+ omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
+ OMAP_PIN_INPUT_PULLUP);
+ if (cpu_is_omap34xx()) {
+ if (controller_nr == 0) {
+ omap_mux_init_signal("sdmmc1_clk",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_cmd",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat0",
+ OMAP_PIN_INPUT_PULLUP);
+ if (mmc_controller->slots[0].caps &
+ (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
+ omap_mux_init_signal("sdmmc1_dat1",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat2",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat3",
+ OMAP_PIN_INPUT_PULLUP);
+ }
+ if (mmc_controller->slots[0].caps &
+ MMC_CAP_8_BIT_DATA) {
+ omap_mux_init_signal("sdmmc1_dat4",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat5",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat6",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc1_dat7",
+ OMAP_PIN_INPUT_PULLUP);
+ }
}
-
- mmc = kzalloc(sizeof(struct omap_mmc_platform_data),
- GFP_KERNEL);
- if (!mmc) {
- pr_err("Cannot allocate memory for mmc device!\n");
- goto done;
+ if (controller_nr == 1) {
+ /* MMC2 */
+ omap_mux_init_signal("sdmmc2_clk",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_cmd",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat0",
+ OMAP_PIN_INPUT_PULLUP);
+
+ /*
+ * For 8 wire configurations, Lines DAT4, 5, 6 and 7
+ * need to be muxed in the board-*.c files
+ */
+ if (mmc_controller->slots[0].caps &
+ (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
+ omap_mux_init_signal("sdmmc2_dat1",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat2",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat3",
+ OMAP_PIN_INPUT_PULLUP);
+ }
+ if (mmc_controller->slots[0].caps &
+ MMC_CAP_8_BIT_DATA) {
+ omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat6.sdmmc2_dat6",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("sdmmc2_dat7.sdmmc2_dat7",
+ OMAP_PIN_INPUT_PULLUP);
+ }
}
- if (c->name)
- strncpy(hc->name, c->name, HSMMC_NAME_LEN);
- else
- snprintf(hc->name, ARRAY_SIZE(hc->name),
- "mmc%islot%i", c->mmc, 1);
- mmc->slots[0].name = hc->name;
- mmc->nr_slots = 1;
- mmc->slots[0].caps = c->caps;
- mmc->slots[0].internal_clock = !c->ext_clock;
- mmc->dma_mask = 0xffffffff;
- if (cpu_is_omap44xx())
- mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
- else
- mmc->reg_offset = 0;
+ /*
+ * For MMC3 the pins need to be muxed in the board-*.c files
+ */
+ }
+}
- mmc->get_context_loss_count = hsmmc_get_context_loss;
+static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
+ struct omap_mmc_platform_data *mmc)
+{
+ char *hc_name;
- mmc->slots[0].switch_pin = c->gpio_cd;
- mmc->slots[0].gpio_wp = c->gpio_wp;
+ hc_name = kzalloc(sizeof(char) * (HSMMC_NAME_LEN + 1), GFP_KERNEL);
+ if (!hc_name) {
+ pr_err("Cannot allocate memory for controller slot name\n");
+ kfree(hc_name);
+ return -ENOMEM;
+ }
- mmc->slots[0].remux = c->remux;
- mmc->slots[0].init_card = c->init_card;
+ if (c->name)
+ strncpy(hc_name, c->name, HSMMC_NAME_LEN);
+ else
+ snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i",
+ c->mmc, 1);
+ mmc->slots[0].name = hc_name;
+ mmc->nr_slots = 1;
+ mmc->slots[0].caps = c->caps;
+ mmc->slots[0].internal_clock = !c->ext_clock;
+ mmc->dma_mask = 0xffffffff;
+ if (cpu_is_omap44xx())
+ mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
+ else
+ mmc->reg_offset = 0;
- if (c->cover_only)
- mmc->slots[0].cover = 1;
+ mmc->get_context_loss_count = hsmmc_get_context_loss;
- if (c->nonremovable)
- mmc->slots[0].nonremovable = 1;
+ mmc->slots[0].switch_pin = c->gpio_cd;
+ mmc->slots[0].gpio_wp = c->gpio_wp;
- if (c->power_saving)
- mmc->slots[0].power_saving = 1;
+ mmc->slots[0].remux = c->remux;
+ mmc->slots[0].init_card = c->init_card;
- if (c->no_off)
- mmc->slots[0].no_off = 1;
+ if (c->cover_only)
+ mmc->slots[0].cover = 1;
- if (c->vcc_aux_disable_is_sleep)
- mmc->slots[0].vcc_aux_disable_is_sleep = 1;
+ if (c->nonremovable)
+ mmc->slots[0].nonremovable = 1;
- /* NOTE: MMC slots should have a Vcc regulator set up.
- * This may be from a TWL4030-family chip, another
- * controllable regulator, or a fixed supply.
- *
- * temporary HACK: ocr_mask instead of fixed supply
- */
- mmc->slots[0].ocr_mask = c->ocr_mask;
+ if (c->power_saving)
+ mmc->slots[0].power_saving = 1;
- if (cpu_is_omap3517() || cpu_is_omap3505())
- mmc->slots[0].set_power = nop_mmc_set_power;
- else
- mmc->slots[0].features |= HSMMC_HAS_PBIAS;
+ if (c->no_off)
+ mmc->slots[0].no_off = 1;
- if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
- mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+ if (c->vcc_aux_disable_is_sleep)
+ mmc->slots[0].vcc_aux_disable_is_sleep = 1;
- switch (c->mmc) {
- case 1:
- if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
- /* on-chip level shifting via PBIAS0/PBIAS1 */
- if (cpu_is_omap44xx()) {
- mmc->slots[0].before_set_reg =
+ /*
+ * NOTE: MMC slots should have a Vcc regulator set up.
+ * This may be from a TWL4030-family chip, another
+ * controllable regulator, or a fixed supply.
+ *
+ * temporary HACK: ocr_mask instead of fixed supply
+ */
+ mmc->slots[0].ocr_mask = c->ocr_mask;
+
+ if (cpu_is_omap3517() || cpu_is_omap3505())
+ mmc->slots[0].set_power = nop_mmc_set_power;
+ else
+ mmc->slots[0].features |= HSMMC_HAS_PBIAS;
+
+ if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
+ mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
+ switch (c->mmc) {
+ case 1:
+ if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+ /* on-chip level shifting via PBIAS0/PBIAS1 */
+ if (cpu_is_omap44xx()) {
+ mmc->slots[0].before_set_reg =
omap4_hsmmc1_before_set_reg;
- mmc->slots[0].after_set_reg =
+ mmc->slots[0].after_set_reg =
omap4_hsmmc1_after_set_reg;
- } else {
- mmc->slots[0].before_set_reg =
+ } else {
+ mmc->slots[0].before_set_reg =
omap_hsmmc1_before_set_reg;
- mmc->slots[0].after_set_reg =
+ mmc->slots[0].after_set_reg =
omap_hsmmc1_after_set_reg;
- }
}
+ }
- /* Omap3630 HSMMC1 supports only 4-bit */
- if (cpu_is_omap3630() &&
- (c->caps & MMC_CAP_8_BIT_DATA)) {
- c->caps &= ~MMC_CAP_8_BIT_DATA;
- c->caps |= MMC_CAP_4_BIT_DATA;
- mmc->slots[0].caps = c->caps;
- }
- break;
- case 2:
- if (c->ext_clock)
- c->transceiver = 1;
- if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
- c->caps &= ~MMC_CAP_8_BIT_DATA;
- c->caps |= MMC_CAP_4_BIT_DATA;
- }
- /* FALLTHROUGH */
- case 3:
- if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
- /* off-chip level shifting, or none */
- mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
- mmc->slots[0].after_set_reg = NULL;
- }
- break;
- default:
- pr_err("MMC%d configuration not supported!\n", c->mmc);
- kfree(mmc);
- continue;
+ /* OMAP3630 HSMMC1 supports only 4-bit */
+ if (cpu_is_omap3630() &&
+ (c->caps & MMC_CAP_8_BIT_DATA)) {
+ c->caps &= ~MMC_CAP_8_BIT_DATA;
+ c->caps |= MMC_CAP_4_BIT_DATA;
+ mmc->slots[0].caps = c->caps;
+ }
+ break;
+ case 2:
+ if (c->ext_clock)
+ c->transceiver = 1;
+ if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
+ c->caps &= ~MMC_CAP_8_BIT_DATA;
+ c->caps |= MMC_CAP_4_BIT_DATA;
}
- hsmmc_data[c->mmc - 1] = mmc;
+ /* FALLTHROUGH */
+ case 3:
+ if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+ /* off-chip level shifting, or none */
+ mmc->slots[0].before_set_reg = hsmmc23_before_set_reg;
+ mmc->slots[0].after_set_reg = NULL;
+ }
+ break;
+ case 4:
+ case 5:
+ mmc->slots[0].before_set_reg = NULL;
+ mmc->slots[0].after_set_reg = NULL;
+ break;
+ default:
+ pr_err("MMC%d configuration not supported!\n", c->mmc);
+ kfree(hc_name);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static struct omap_device_pm_latency omap_hsmmc_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+ /*
+ * XXX There should also be an entry here to power off/on the
+ * MMC regulators/PBIAS cells, etc.
+ */
+};
+
+#define MAX_OMAP_MMC_HWMOD_NAME_LEN 16
+
+void __init omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)
+{
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ struct omap_device_pm_latency *ohl;
+ char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
+ struct omap_mmc_platform_data *mmc_data;
+ struct omap_mmc_dev_attr *mmc_dev_attr;
+ char *name;
+ int l;
+ int ohl_cnt = 0;
+
+ mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
+ if (!mmc_data) {
+ pr_err("Cannot allocate memory for mmc device!\n");
+ goto done;
}
- omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
+ if (omap_hsmmc_pdata_init(hsmmcinfo, mmc_data) < 0) {
+ pr_err("%s fails!\n", __func__);
+ goto done;
+ }
+ omap_hsmmc_mux(mmc_data, (ctrl_nr - 1));
+
+ name = "omap_hsmmc";
+ ohl = omap_hsmmc_latency;
+ ohl_cnt = ARRAY_SIZE(omap_hsmmc_latency);
+
+ l = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN,
+ "mmc%d", ctrl_nr);
+ WARN(l >= MAX_OMAP_MMC_HWMOD_NAME_LEN,
+ "String buffer overflow in MMC%d device setup\n", ctrl_nr);
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ kfree(mmc_data->slots[0].name);
+ goto done;
+ }
- /* pass the device nodes back to board setup code */
- for (c = controllers; c->mmc; c++) {
- struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
+ if (oh->dev_attr != NULL) {
+ mmc_dev_attr = oh->dev_attr;
+ mmc_data->controller_flags = mmc_dev_attr->flags;
+ }
- if (!c->mmc || c->mmc > nr_hsmmc)
- continue;
- c->dev = mmc->dev;
+ od = omap_device_build(name, ctrl_nr - 1, oh, mmc_data,
+ sizeof(struct omap_mmc_platform_data), ohl, ohl_cnt, false);
+ if (IS_ERR(od)) {
+ WARN(1, "Cant build omap_device for %s:%s.\n", name, oh->name);
+ kfree(mmc_data->slots[0].name);
+ goto done;
}
+ /*
+ * return device handle to board setup code
+ * required to populate for regulator framework structure
+ */
+ hsmmcinfo->dev = &od->pdev.dev;
done:
- for (i = 0; i < nr_hsmmc; i++)
- kfree(hsmmc_data[i]);
+ kfree(mmc_data);
+}
+
+void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+ u32 reg;
+
+ if (!cpu_is_omap44xx()) {
+ if (cpu_is_omap2430()) {
+ control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
+ control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1;
+ } else {
+ control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
+ control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
+ }
+ } else {
+ control_pbias_offset =
+ OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE;
+ control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1;
+ reg = omap4_ctrl_pad_readl(control_mmc1);
+ reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK |
+ OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK);
+ reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK |
+ OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK);
+ reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK|
+ OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK |
+ OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK);
+ omap4_ctrl_pad_writel(reg, control_mmc1);
+ }
+
+ for (; controllers->mmc; controllers++)
+ omap_init_hsmmc(controllers, controllers->mmc);
+
}
#endif
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
new file mode 100644
index 000000000000..06d4a80660a5
--- /dev/null
+++ b/arch/arm/mach-omap2/hwspinlock.c
@@ -0,0 +1,63 @@
+/*
+ * OMAP hardware spinlock device initialization
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Contact: Simon Que <sque@ti.com>
+ * Hari Kanigeri <h-kanigeri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+
+struct omap_device_pm_latency omap_spinlock_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ }
+};
+
+int __init hwspinlocks_init(void)
+{
+ int retval = 0;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ const char *oh_name = "spinlock";
+ const char *dev_name = "omap_hwspinlock";
+
+ /*
+ * Hwmod lookup will fail in case our platform doesn't support the
+ * hardware spinlock module, so it is safe to run this initcall
+ * on all omaps
+ */
+ oh = omap_hwmod_lookup(oh_name);
+ if (oh == NULL)
+ return -EINVAL;
+
+ od = omap_device_build(dev_name, 0, oh, NULL, 0,
+ omap_spinlock_latency,
+ ARRAY_SIZE(omap_spinlock_latency), false);
+ if (IS_ERR(od)) {
+ pr_err("Can't build omap_device for %s:%s\n", dev_name,
+ oh_name);
+ retval = PTR_ERR(od);
+ }
+
+ return retval;
+}
+/* early board code might need to reserve specific hwspinlock instances */
+postcore_initcall(hwspinlocks_init);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 5f9086c65e48..2537090aa33a 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -6,7 +6,7 @@
* Copyright (C) 2005 Nokia Corporation
* Written by Tony Lindgren <tony@atomide.com>
*
- * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2009-11 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -84,6 +84,11 @@ EXPORT_SYMBOL(omap_type);
#define OMAP_TAP_DIE_ID_2 0x0220
#define OMAP_TAP_DIE_ID_3 0x0224
+#define OMAP_TAP_DIE_ID_44XX_0 0x0200
+#define OMAP_TAP_DIE_ID_44XX_1 0x0208
+#define OMAP_TAP_DIE_ID_44XX_2 0x020c
+#define OMAP_TAP_DIE_ID_44XX_3 0x0210
+
#define read_tap_reg(reg) __raw_readl(tap_base + (reg))
struct omap_id {
@@ -107,6 +112,14 @@ static u16 tap_prod_id;
void omap_get_die_id(struct omap_die_id *odi)
{
+ if (cpu_is_omap44xx()) {
+ odi->id_0 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_0);
+ odi->id_1 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_1);
+ odi->id_2 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_2);
+ odi->id_3 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_3);
+
+ return;
+ }
odi->id_0 = read_tap_reg(OMAP_TAP_DIE_ID_0);
odi->id_1 = read_tap_reg(OMAP_TAP_DIE_ID_1);
odi->id_2 = read_tap_reg(OMAP_TAP_DIE_ID_2);
@@ -191,12 +204,19 @@ static void __init omap3_check_features(void)
if (!cpu_is_omap3505() && !cpu_is_omap3517())
omap3_features |= OMAP3_HAS_IO_WAKEUP;
+ omap3_features |= OMAP3_HAS_SDRC;
+
/*
* TODO: Get additional info (where applicable)
* e.g. Size of L2 cache.
*/
}
+static void __init ti816x_check_features(void)
+{
+ omap3_features = OMAP3_HAS_NEON;
+}
+
static void __init omap3_check_revision(void)
{
u32 cpuid, idcode;
@@ -287,6 +307,20 @@ static void __init omap3_check_revision(void)
omap_chip.oc |= CHIP_IS_OMAP3630ES1_2;
}
break;
+ case 0xb81e:
+ omap_chip.oc = CHIP_IS_TI816X;
+
+ switch (rev) {
+ case 0:
+ omap_revision = TI8168_REV_ES1_0;
+ break;
+ case 1:
+ omap_revision = TI8168_REV_ES1_1;
+ break;
+ default:
+ omap_revision = TI8168_REV_ES1_1;
+ }
+ break;
default:
/* Unknown default to latest silicon rev as default*/
omap_revision = OMAP3630_REV_ES1_2;
@@ -307,7 +341,7 @@ static void __init omap4_check_revision(void)
*/
idcode = read_tap_reg(OMAP_TAP_IDCODE);
hawkeye = (idcode >> 12) & 0xffff;
- rev = (idcode >> 28) & 0xff;
+ rev = (idcode >> 28) & 0xf;
/*
* Few initial ES2.0 samples IDCODE is same as ES1.0
@@ -326,22 +360,31 @@ static void __init omap4_check_revision(void)
omap_chip.oc |= CHIP_IS_OMAP4430ES1;
break;
case 1:
+ default:
omap_revision = OMAP4430_REV_ES2_0;
omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+ }
+ break;
+ case 0xb95c:
+ switch (rev) {
+ case 3:
+ omap_revision = OMAP4430_REV_ES2_1;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2_1;
break;
+ case 4:
default:
- omap_revision = OMAP4430_REV_ES2_0;
- omap_chip.oc |= CHIP_IS_OMAP4430ES2;
- }
- break;
+ omap_revision = OMAP4430_REV_ES2_2;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2_2;
+ }
+ break;
default:
- /* Unknown default to latest silicon rev as default*/
- omap_revision = OMAP4430_REV_ES2_0;
- omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+ /* Unknown default to latest silicon rev as default */
+ omap_revision = OMAP4430_REV_ES2_2;
+ omap_chip.oc |= CHIP_IS_OMAP4430ES2_2;
}
- pr_info("OMAP%04x ES%d.0\n",
- omap_rev() >> 16, ((omap_rev() >> 12) & 0xf) + 1);
+ pr_info("OMAP%04x ES%d.%d\n", omap_rev() >> 16,
+ ((omap_rev() >> 12) & 0xf), ((omap_rev() >> 8) & 0xf));
}
#define OMAP3_SHOW_FEATURE(feat) \
@@ -372,6 +415,8 @@ static void __init omap3_cpuinfo(void)
/* Already set in omap3_check_revision() */
strcpy(cpu_name, "AM3505");
}
+ } else if (cpu_is_ti816x()) {
+ strcpy(cpu_name, "TI816X");
} else if (omap3_has_iva() && omap3_has_sgx()) {
/* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
strcpy(cpu_name, "OMAP3430/3530");
@@ -386,7 +431,7 @@ static void __init omap3_cpuinfo(void)
strcpy(cpu_name, "OMAP3503");
}
- if (cpu_is_omap3630()) {
+ if (cpu_is_omap3630() || cpu_is_ti816x()) {
switch (rev) {
case OMAP_REVBITS_00:
strcpy(cpu_rev, "1.0");
@@ -462,7 +507,13 @@ void __init omap2_check_revision(void)
omap24xx_check_revision();
} else if (cpu_is_omap34xx()) {
omap3_check_revision();
- omap3_check_features();
+
+ /* TI816X doesn't have feature register */
+ if (!cpu_is_ti816x())
+ omap3_check_features();
+ else
+ ti816x_check_features();
+
omap3_cpuinfo();
return;
} else if (cpu_is_omap44xx()) {
diff --git a/arch/arm/mach-omap2/include/mach/debug-macro.S b/arch/arm/mach-omap2/include/mach/debug-macro.S
index 6049f465ec84..48adfe9fe4f3 100644
--- a/arch/arm/mach-omap2/include/mach/debug-macro.S
+++ b/arch/arm/mach-omap2/include/mach/debug-macro.S
@@ -72,6 +72,12 @@ omap_uart_lsr: .word 0
beq 34f @ configure OMAP3UART4
cmp \rp, #OMAP4UART4 @ only on 44xx
beq 44f @ configure OMAP4UART4
+ cmp \rp, #TI816XUART1 @ ti816x UART offsets different
+ beq 81f @ configure UART1
+ cmp \rp, #TI816XUART2 @ ti816x UART offsets different
+ beq 82f @ configure UART2
+ cmp \rp, #TI816XUART3 @ ti816x UART offsets different
+ beq 83f @ configure UART3
cmp \rp, #ZOOM_UART @ only on zoom2/3
beq 95f @ configure ZOOM_UART
@@ -94,6 +100,12 @@ omap_uart_lsr: .word 0
b 98f
44: mov \rp, #UART_OFFSET(OMAP4_UART4_BASE)
b 98f
+81: mov \rp, #UART_OFFSET(TI816X_UART1_BASE)
+ b 98f
+82: mov \rp, #UART_OFFSET(TI816X_UART2_BASE)
+ b 98f
+83: mov \rp, #UART_OFFSET(TI816X_UART3_BASE)
+ b 98f
95: ldr \rp, =ZOOM_UART_BASE
mrc p15, 0, \rv, c1, c0
tst \rv, #1 @ MMU enabled?
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
index 81985a665cb3..a48690b90990 100644
--- a/arch/arm/mach-omap2/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap2/include/mach/entry-macro.S
@@ -61,6 +61,14 @@
bne 9998f
ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
cmp \irqnr, #0x0
+ bne 9998f
+
+ /*
+ * ti816x has additional IRQ pending register. Checking this
+ * register on omap2 & omap3 has no effect (read as 0).
+ */
+ ldr \irqnr, [\base, #0xf8] /* IRQ pending reg 4 */
+ cmp \irqnr, #0x0
9998:
ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET]
and \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */
@@ -133,6 +141,11 @@
bne 9999f
ldr \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
cmp \irqnr, #0x0
+#ifdef CONFIG_SOC_OMAPTI816X
+ bne 9999f
+ ldr \irqnr, [\base, #0xf8] /* IRQ pending reg 4 */
+ cmp \irqnr, #0x0
+#endif
9999:
ldrne \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET]
and \irqnr, \irqnr, #ACTIVEIRQ_MASK /* Clear spurious bits */
diff --git a/arch/arm/mach-omap2/include/mach/omap4-common.h b/arch/arm/mach-omap2/include/mach/omap4-common.h
index 5b0270b28934..de441c05a6a6 100644
--- a/arch/arm/mach-omap2/include/mach/omap4-common.h
+++ b/arch/arm/mach-omap2/include/mach/omap4-common.h
@@ -17,8 +17,12 @@
* wfi used in low power code. Directly opcode is used instead
* of instruction to avoid mulit-omap build break
*/
+#ifdef CONFIG_THUMB2_KERNEL
+#define do_wfi() __asm__ __volatile__ ("wfi" : : : "memory")
+#else
#define do_wfi() \
__asm__ __volatile__ (".word 0xe320f003" : : : "memory")
+#endif
#ifdef CONFIG_CACHE_L2X0
extern void __iomem *l2cache_base;
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index c2032041d26f..441e79d043a7 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -30,7 +30,6 @@
#include <plat/sram.h>
#include <plat/sdrc.h>
-#include <plat/gpmc.h>
#include <plat/serial.h>
#include "clock2xxx.h"
@@ -66,7 +65,7 @@ static struct map_desc omap24xx_io_desc[] __initdata = {
},
};
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
static struct map_desc omap242x_io_desc[] __initdata = {
{
.virtual = DSP_MEM_2420_VIRT,
@@ -90,7 +89,7 @@ static struct map_desc omap242x_io_desc[] __initdata = {
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
static struct map_desc omap243x_io_desc[] __initdata = {
{
.virtual = L4_WK_243X_VIRT,
@@ -175,6 +174,18 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
#endif
};
#endif
+
+#ifdef CONFIG_SOC_OMAPTI816X
+static struct map_desc omapti816x_io_desc[] __initdata = {
+ {
+ .virtual = L4_34XX_VIRT,
+ .pfn = __phys_to_pfn(L4_34XX_PHYS),
+ .length = L4_34XX_SIZE,
+ .type = MT_DEVICE
+ },
+};
+#endif
+
#ifdef CONFIG_ARCH_OMAP4
static struct map_desc omap44xx_io_desc[] __initdata = {
{
@@ -241,7 +252,7 @@ static void __init _omap2_map_common_io(void)
omap_sram_init();
}
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
void __init omap242x_map_common_io(void)
{
iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
@@ -250,7 +261,7 @@ void __init omap242x_map_common_io(void)
}
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
void __init omap243x_map_common_io(void)
{
iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
@@ -267,6 +278,14 @@ void __init omap34xx_map_common_io(void)
}
#endif
+#ifdef CONFIG_SOC_OMAPTI816X
+void __init omapti816x_map_common_io(void)
+{
+ iotable_init(omapti816x_io_desc, ARRAY_SIZE(omapti816x_io_desc));
+ _omap2_map_common_io();
+}
+#endif
+
#ifdef CONFIG_ARCH_OMAP4
void __init omap44xx_map_common_io(void)
{
@@ -337,15 +356,15 @@ void __init omap2_init_common_infrastructure(void)
if (cpu_is_omap242x()) {
omap2xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap2xxx_clockdomains_init();
omap2420_hwmod_init();
} else if (cpu_is_omap243x()) {
omap2xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap2xxx_clockdomains_init();
omap2430_hwmod_init();
} else if (cpu_is_omap34xx()) {
omap3xxx_powerdomains_init();
- omap2_clockdomains_init();
+ omap3xxx_clockdomains_init();
omap3xxx_hwmod_init();
} else if (cpu_is_omap44xx()) {
omap44xx_powerdomains_init();
@@ -398,15 +417,10 @@ void __init omap2_init_common_infrastructure(void)
void __init omap2_init_common_devices(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1)
{
- omap_serial_early_init();
-
- omap_hwmod_late_init();
-
- if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ if (cpu_is_omap24xx() || omap3_has_sdrc()) {
omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
_omap2_init_reprogram_sdrc();
}
- gpmc_init();
omap_irq_base_init();
}
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 14ee686b6492..adb083e41acd 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -145,35 +145,32 @@ static void omap2_iommu_set_twl(struct iommu *obj, bool on)
static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
{
- int i;
u32 stat, da;
- const char *err_msg[] = {
- "tlb miss",
- "translation fault",
- "emulation miss",
- "table walk fault",
- "multi hit fault",
- };
+ u32 errs = 0;
stat = iommu_read_reg(obj, MMU_IRQSTATUS);
stat &= MMU_IRQ_MASK;
- if (!stat)
+ if (!stat) {
+ *ra = 0;
return 0;
+ }
da = iommu_read_reg(obj, MMU_FAULT_AD);
*ra = da;
- dev_err(obj->dev, "%s:\tda:%08x ", __func__, da);
-
- for (i = 0; i < ARRAY_SIZE(err_msg); i++) {
- if (stat & (1 << i))
- printk("%s ", err_msg[i]);
- }
- printk("\n");
-
+ if (stat & MMU_IRQ_TLBMISS)
+ errs |= OMAP_IOMMU_ERR_TLB_MISS;
+ if (stat & MMU_IRQ_TRANSLATIONFAULT)
+ errs |= OMAP_IOMMU_ERR_TRANS_FAULT;
+ if (stat & MMU_IRQ_EMUMISS)
+ errs |= OMAP_IOMMU_ERR_EMU_MISS;
+ if (stat & MMU_IRQ_TABLEWALKFAULT)
+ errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT;
+ if (stat & MMU_IRQ_MULTIHITFAULT)
+ errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT;
iommu_write_reg(obj, stat, MMU_IRQSTATUS);
- return stat;
+ return errs;
}
static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr)
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 23049c487c47..bc524b94fd59 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -61,8 +61,6 @@ struct omap3_intc_regs {
u32 mir[INTCPS_NR_MIR_REGS];
};
-static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
-
/* INTC bank register get/set */
static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg)
@@ -110,7 +108,7 @@ static void omap_mask_irq(struct irq_data *d)
unsigned int irq = d->irq;
int offset = irq & (~(IRQ_BITS_PER_REG - 1));
- if (cpu_is_omap34xx()) {
+ if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
int spurious = 0;
/*
@@ -205,6 +203,9 @@ void __init omap_init_irq(void)
BUG_ON(!base);
+ if (cpu_is_ti816x())
+ bank->nr_irqs = 128;
+
/* Static mapping, never released */
bank->base_reg = ioremap(base, SZ_4K);
if (!bank->base_reg) {
@@ -229,6 +230,8 @@ void __init omap_init_irq(void)
}
#ifdef CONFIG_ARCH_OMAP3
+static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
+
void omap_intc_save_context(void)
{
int ind = 0, i = 0;
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 24b88504df0f..86d564a640bb 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -14,12 +14,11 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
#include <plat/mailbox.h>
#include <mach/irqs.h>
#define MAILBOX_REVISION 0x000
-#define MAILBOX_SYSCONFIG 0x010
-#define MAILBOX_SYSSTATUS 0x014
#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
#define MAILBOX_FIFOSTATUS(m) (0x080 + 4 * (m))
#define MAILBOX_MSGSTATUS(m) (0x0c0 + 4 * (m))
@@ -33,17 +32,6 @@
#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
-/* SYSCONFIG: register bit definition */
-#define AUTOIDLE (1 << 0)
-#define SOFTRESET (1 << 1)
-#define SMARTIDLE (2 << 3)
-#define OMAP4_SOFTRESET (1 << 0)
-#define OMAP4_NOIDLE (1 << 2)
-#define OMAP4_SMARTIDLE (2 << 2)
-
-/* SYSSTATUS: register bit definition */
-#define RESETDONE (1 << 0)
-
#define MBOX_REG_SIZE 0x120
#define OMAP4_MBOX_REG_SIZE 0x130
@@ -70,8 +58,6 @@ struct omap_mbox2_priv {
unsigned long irqdisable;
};
-static struct clk *mbox_ick_handle;
-
static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
omap_mbox_type_t irq);
@@ -89,53 +75,13 @@ static inline void mbox_write_reg(u32 val, size_t ofs)
static int omap2_mbox_startup(struct omap_mbox *mbox)
{
u32 l;
- unsigned long timeout;
- mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
- if (IS_ERR(mbox_ick_handle)) {
- printk(KERN_ERR "Could not get mailboxes_ick: %ld\n",
- PTR_ERR(mbox_ick_handle));
- return PTR_ERR(mbox_ick_handle);
- }
- clk_enable(mbox_ick_handle);
-
- if (cpu_is_omap44xx()) {
- mbox_write_reg(OMAP4_SOFTRESET, MAILBOX_SYSCONFIG);
- timeout = jiffies + msecs_to_jiffies(20);
- do {
- l = mbox_read_reg(MAILBOX_SYSCONFIG);
- if (!(l & OMAP4_SOFTRESET))
- break;
- } while (!time_after(jiffies, timeout));
-
- if (l & OMAP4_SOFTRESET) {
- pr_err("Can't take mailbox out of reset\n");
- return -ENODEV;
- }
- } else {
- mbox_write_reg(SOFTRESET, MAILBOX_SYSCONFIG);
- timeout = jiffies + msecs_to_jiffies(20);
- do {
- l = mbox_read_reg(MAILBOX_SYSSTATUS);
- if (l & RESETDONE)
- break;
- } while (!time_after(jiffies, timeout));
-
- if (!(l & RESETDONE)) {
- pr_err("Can't take mailbox out of reset\n");
- return -ENODEV;
- }
- }
+ pm_runtime_enable(mbox->dev->parent);
+ pm_runtime_get_sync(mbox->dev->parent);
l = mbox_read_reg(MAILBOX_REVISION);
pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
- if (cpu_is_omap44xx())
- l = OMAP4_SMARTIDLE;
- else
- l = SMARTIDLE | AUTOIDLE;
- mbox_write_reg(l, MAILBOX_SYSCONFIG);
-
omap2_mbox_enable_irq(mbox, IRQ_RX);
return 0;
@@ -143,9 +89,8 @@ static int omap2_mbox_startup(struct omap_mbox *mbox)
static void omap2_mbox_shutdown(struct omap_mbox *mbox)
{
- clk_disable(mbox_ick_handle);
- clk_put(mbox_ick_handle);
- mbox_ick_handle = NULL;
+ pm_runtime_put_sync(mbox->dev->parent);
+ pm_runtime_disable(mbox->dev->parent);
}
/* Mailbox FIFO handle functions */
@@ -312,7 +257,7 @@ struct omap_mbox mbox_dsp_info = {
struct omap_mbox *omap3_mboxes[] = { &mbox_dsp_info, NULL };
#endif
-#if defined(CONFIG_ARCH_OMAP2420)
+#if defined(CONFIG_SOC_OMAP2420)
/* IVA */
static struct omap_mbox2_priv omap2_mbox_iva_priv = {
.tx_fifo = {
@@ -400,14 +345,14 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
else if (cpu_is_omap34xx()) {
list = omap3_mboxes;
- list[0]->irq = platform_get_irq_byname(pdev, "dsp");
+ list[0]->irq = platform_get_irq(pdev, 0);
}
#endif
#if defined(CONFIG_ARCH_OMAP2)
else if (cpu_is_omap2430()) {
list = omap2_mboxes;
- list[0]->irq = platform_get_irq_byname(pdev, "dsp");
+ list[0]->irq = platform_get_irq(pdev, 0);
} else if (cpu_is_omap2420()) {
list = omap2_mboxes;
@@ -419,8 +364,7 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
else if (cpu_is_omap44xx()) {
list = omap4_mboxes;
- list[0]->irq = list[1]->irq =
- platform_get_irq_byname(pdev, "mbox");
+ list[0]->irq = list[1]->irq = platform_get_irq(pdev, 0);
}
#endif
else {
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index f9c9df5b5ff1..565b9064a328 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -22,10 +22,11 @@
#include <plat/dma.h>
#include <plat/cpu.h>
#include <plat/mcbsp.h>
+#include <plat/omap_device.h>
+#include <linux/pm_runtime.h>
#include "control.h"
-
/* McBSP internal signal muxing functions */
void omap2_mcbsp1_mux_clkr_src(u8 mux)
@@ -83,7 +84,7 @@ int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
return -EINVAL;
}
- clk_disable(mcbsp->fclk);
+ pm_runtime_put_sync(mcbsp->dev);
r = clk_set_parent(mcbsp->fclk, fck_src);
if (IS_ERR_VALUE(r)) {
@@ -93,7 +94,7 @@ int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
return -EINVAL;
}
- clk_enable(mcbsp->fclk);
+ pm_runtime_get_sync(mcbsp->dev);
clk_put(fck_src);
@@ -101,196 +102,70 @@ int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
}
EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
-
-/* Platform data */
-
-#ifdef CONFIG_ARCH_OMAP2420
-static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
+struct omap_device_pm_latency omap2_mcbsp_latency[] = {
{
- .phys_base = OMAP24XX_MCBSP1_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
- .rx_irq = INT_24XX_MCBSP1_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- },
- {
- .phys_base = OMAP24XX_MCBSP2_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
- .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP2_IRQ_TX,
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
};
-#define OMAP2420_MCBSP_PDATA_SZ ARRAY_SIZE(omap2420_mcbsp_pdata)
-#define OMAP2420_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
-#else
-#define omap2420_mcbsp_pdata NULL
-#define OMAP2420_MCBSP_PDATA_SZ 0
-#define OMAP2420_MCBSP_REG_NUM 0
-#endif
-#ifdef CONFIG_ARCH_OMAP2430
-static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
- {
- .phys_base = OMAP24XX_MCBSP1_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
- .rx_irq = INT_24XX_MCBSP1_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- },
- {
- .phys_base = OMAP24XX_MCBSP2_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
- .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP2_IRQ_TX,
- },
- {
- .phys_base = OMAP2430_MCBSP3_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX,
- .rx_irq = INT_24XX_MCBSP3_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP3_IRQ_TX,
- },
- {
- .phys_base = OMAP2430_MCBSP4_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP4_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP4_TX,
- .rx_irq = INT_24XX_MCBSP4_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP4_IRQ_TX,
- },
- {
- .phys_base = OMAP2430_MCBSP5_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP5_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP5_TX,
- .rx_irq = INT_24XX_MCBSP5_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP5_IRQ_TX,
- },
-};
-#define OMAP2430_MCBSP_PDATA_SZ ARRAY_SIZE(omap2430_mcbsp_pdata)
-#define OMAP2430_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
-#else
-#define omap2430_mcbsp_pdata NULL
-#define OMAP2430_MCBSP_PDATA_SZ 0
-#define OMAP2430_MCBSP_REG_NUM 0
-#endif
+static int omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
+{
+ int id, count = 1;
+ char *name = "omap-mcbsp";
+ struct omap_hwmod *oh_device[2];
+ struct omap_mcbsp_platform_data *pdata = NULL;
+ struct omap_device *od;
-#ifdef CONFIG_ARCH_OMAP3
-static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
- {
- .phys_base = OMAP34XX_MCBSP1_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX,
- .rx_irq = INT_24XX_MCBSP1_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP1_IRQ_TX,
- .buffer_size = 0x80, /* The FIFO has 128 locations */
- },
- {
- .phys_base = OMAP34XX_MCBSP2_BASE,
- .phys_base_st = OMAP34XX_MCBSP2_ST_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX,
- .rx_irq = INT_24XX_MCBSP2_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP2_IRQ_TX,
- .buffer_size = 0x500, /* The FIFO has 1024 + 256 locations */
- },
- {
- .phys_base = OMAP34XX_MCBSP3_BASE,
- .phys_base_st = OMAP34XX_MCBSP3_ST_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP3_TX,
- .rx_irq = INT_24XX_MCBSP3_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP3_IRQ_TX,
- .buffer_size = 0x80, /* The FIFO has 128 locations */
- },
- {
- .phys_base = OMAP34XX_MCBSP4_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP4_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP4_TX,
- .rx_irq = INT_24XX_MCBSP4_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP4_IRQ_TX,
- .buffer_size = 0x80, /* The FIFO has 128 locations */
- },
- {
- .phys_base = OMAP34XX_MCBSP5_BASE,
- .dma_rx_sync = OMAP24XX_DMA_MCBSP5_RX,
- .dma_tx_sync = OMAP24XX_DMA_MCBSP5_TX,
- .rx_irq = INT_24XX_MCBSP5_IRQ_RX,
- .tx_irq = INT_24XX_MCBSP5_IRQ_TX,
- .buffer_size = 0x80, /* The FIFO has 128 locations */
- },
-};
-#define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata)
-#define OMAP34XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
-#else
-#define omap34xx_mcbsp_pdata NULL
-#define OMAP34XX_MCBSP_PDATA_SZ 0
-#define OMAP34XX_MCBSP_REG_NUM 0
-#endif
+ sscanf(oh->name, "mcbsp%d", &id);
-static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
- {
- .phys_base = OMAP44XX_MCBSP1_BASE,
- .dma_rx_sync = OMAP44XX_DMA_MCBSP1_RX,
- .dma_tx_sync = OMAP44XX_DMA_MCBSP1_TX,
- .tx_irq = OMAP44XX_IRQ_MCBSP1,
- },
- {
- .phys_base = OMAP44XX_MCBSP2_BASE,
- .dma_rx_sync = OMAP44XX_DMA_MCBSP2_RX,
- .dma_tx_sync = OMAP44XX_DMA_MCBSP2_TX,
- .tx_irq = OMAP44XX_IRQ_MCBSP2,
- },
- {
- .phys_base = OMAP44XX_MCBSP3_BASE,
- .dma_rx_sync = OMAP44XX_DMA_MCBSP3_RX,
- .dma_tx_sync = OMAP44XX_DMA_MCBSP3_TX,
- .tx_irq = OMAP44XX_IRQ_MCBSP3,
- },
- {
- .phys_base = OMAP44XX_MCBSP4_BASE,
- .dma_rx_sync = OMAP44XX_DMA_MCBSP4_RX,
- .dma_tx_sync = OMAP44XX_DMA_MCBSP4_TX,
- .tx_irq = OMAP44XX_IRQ_MCBSP4,
- },
-};
-#define OMAP44XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap44xx_mcbsp_pdata)
-#define OMAP44XX_MCBSP_REG_NUM (OMAP_MCBSP_REG_RCCR / sizeof(u32) + 1)
+ pdata = kzalloc(sizeof(struct omap_mcbsp_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: No memory for mcbsp\n", __func__);
+ return -ENOMEM;
+ }
+
+ pdata->mcbsp_config_type = oh->class->rev;
+
+ if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
+ if (id == 2)
+ /* The FIFO has 1024 + 256 locations */
+ pdata->buffer_size = 0x500;
+ else
+ /* The FIFO has 128 locations */
+ pdata->buffer_size = 0x80;
+ }
+
+ oh_device[0] = oh;
+
+ if (oh->dev_attr) {
+ oh_device[1] = omap_hwmod_lookup((
+ (struct omap_mcbsp_dev_attr *)(oh->dev_attr))->sidetone);
+ count++;
+ }
+ od = omap_device_build_ss(name, id, oh_device, count, pdata,
+ sizeof(*pdata), omap2_mcbsp_latency,
+ ARRAY_SIZE(omap2_mcbsp_latency), false);
+ kfree(pdata);
+ if (IS_ERR(od)) {
+ pr_err("%s: Cant build omap_device for %s:%s.\n", __func__,
+ name, oh->name);
+ return PTR_ERR(od);
+ }
+ omap_mcbsp_count++;
+ return 0;
+}
static int __init omap2_mcbsp_init(void)
{
- if (cpu_is_omap2420()) {
- omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP2420_MCBSP_REG_NUM * sizeof(u16);
- } else if (cpu_is_omap2430()) {
- omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP2430_MCBSP_REG_NUM * sizeof(u32);
- } else if (cpu_is_omap34xx()) {
- omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP34XX_MCBSP_REG_NUM * sizeof(u32);
- } else if (cpu_is_omap44xx()) {
- omap_mcbsp_count = OMAP44XX_MCBSP_PDATA_SZ;
- omap_mcbsp_cache_size = OMAP44XX_MCBSP_REG_NUM * sizeof(u32);
- }
+ omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
GFP_KERNEL);
if (!mcbsp_ptr)
return -ENOMEM;
- if (cpu_is_omap2420())
- omap_mcbsp_register_board_cfg(omap2420_mcbsp_pdata,
- OMAP2420_MCBSP_PDATA_SZ);
- if (cpu_is_omap2430())
- omap_mcbsp_register_board_cfg(omap2430_mcbsp_pdata,
- OMAP2430_MCBSP_PDATA_SZ);
- if (cpu_is_omap34xx())
- omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata,
- OMAP34XX_MCBSP_PDATA_SZ);
- if (cpu_is_omap44xx())
- omap_mcbsp_register_board_cfg(omap44xx_mcbsp_pdata,
- OMAP44XX_MCBSP_PDATA_SZ);
-
return omap_mcbsp_init();
}
arch_initcall(omap2_mcbsp_init);
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 6c84659cf846..bb043cbb3886 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -258,7 +258,7 @@ struct omap_hwmod_mux_info * __init
omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
{
struct omap_hwmod_mux_info *hmux;
- int i;
+ int i, nr_pads_dynamic = 0;
if (!bpads || nr_pads < 1)
return NULL;
@@ -302,9 +302,40 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
pad->enable = bpad->enable;
pad->idle = bpad->idle;
pad->off = bpad->off;
+
+ if (pad->flags & OMAP_DEVICE_PAD_REMUX)
+ nr_pads_dynamic++;
+
pr_debug("%s: Initialized %s\n", __func__, pad->name);
}
+ if (!nr_pads_dynamic)
+ return hmux;
+
+ /*
+ * Add pads that need dynamic muxing into a separate list
+ */
+
+ hmux->nr_pads_dynamic = nr_pads_dynamic;
+ hmux->pads_dynamic = kzalloc(sizeof(struct omap_device_pad *) *
+ nr_pads_dynamic, GFP_KERNEL);
+ if (!hmux->pads_dynamic) {
+ pr_err("%s: Could not allocate dynamic pads\n", __func__);
+ return hmux;
+ }
+
+ nr_pads_dynamic = 0;
+ for (i = 0; i < hmux->nr_pads; i++) {
+ struct omap_device_pad *pad = &hmux->pads[i];
+
+ if (pad->flags & OMAP_DEVICE_PAD_REMUX) {
+ pr_debug("%s: pad %s tagged dynamic\n",
+ __func__, pad->name);
+ hmux->pads_dynamic[nr_pads_dynamic] = pad;
+ nr_pads_dynamic++;
+ }
+ }
+
return hmux;
err3:
@@ -322,6 +353,36 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
{
int i;
+ /* Runtime idling of dynamic pads */
+ if (state == _HWMOD_STATE_IDLE && hmux->enabled) {
+ for (i = 0; i < hmux->nr_pads_dynamic; i++) {
+ struct omap_device_pad *pad = hmux->pads_dynamic[i];
+ int val = -EINVAL;
+
+ val = pad->idle;
+ omap_mux_write(pad->partition, val,
+ pad->mux->reg_offset);
+ }
+
+ return;
+ }
+
+ /* Runtime enabling of dynamic pads */
+ if ((state == _HWMOD_STATE_ENABLED) && hmux->pads_dynamic
+ && hmux->enabled) {
+ for (i = 0; i < hmux->nr_pads_dynamic; i++) {
+ struct omap_device_pad *pad = hmux->pads_dynamic[i];
+ int val = -EINVAL;
+
+ val = pad->enable;
+ omap_mux_write(pad->partition, val,
+ pad->mux->reg_offset);
+ }
+
+ return;
+ }
+
+ /* Enabling or disabling of all pads */
for (i = 0; i < hmux->nr_pads; i++) {
struct omap_device_pad *pad = &hmux->pads[i];
int flags, val = -EINVAL;
@@ -330,31 +391,22 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
switch (state) {
case _HWMOD_STATE_ENABLED:
- if (flags & OMAP_DEVICE_PAD_ENABLED)
- break;
- flags |= OMAP_DEVICE_PAD_ENABLED;
val = pad->enable;
pr_debug("%s: Enabling %s %x\n", __func__,
pad->name, val);
break;
- case _HWMOD_STATE_IDLE:
- if (!(flags & OMAP_DEVICE_PAD_REMUX))
- break;
- flags &= ~OMAP_DEVICE_PAD_ENABLED;
- val = pad->idle;
- pr_debug("%s: Idling %s %x\n", __func__,
- pad->name, val);
- break;
case _HWMOD_STATE_DISABLED:
- default:
/* Use safe mode unless OMAP_DEVICE_PAD_REMUX */
if (flags & OMAP_DEVICE_PAD_REMUX)
val = pad->off;
else
val = OMAP_MUX_MODE7;
- flags &= ~OMAP_DEVICE_PAD_ENABLED;
pr_debug("%s: Disabling %s %x\n", __func__,
pad->name, val);
+ break;
+ default:
+ /* Nothing to be done */
+ break;
};
if (val >= 0) {
@@ -363,6 +415,11 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
pad->flags = flags;
}
}
+
+ if (state == _HWMOD_STATE_ENABLED)
+ hmux->enabled = true;
+ else
+ hmux->enabled = false;
}
#ifdef CONFIG_DEBUG_FS
diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h
index a4ab17a737a6..137f321c029f 100644
--- a/arch/arm/mach-omap2/mux.h
+++ b/arch/arm/mach-omap2/mux.h
@@ -159,7 +159,6 @@ struct omap_board_mux {
u16 value;
};
-#define OMAP_DEVICE_PAD_ENABLED BIT(7) /* Not needed for board-*.c */
#define OMAP_DEVICE_PAD_REMUX BIT(1) /* Dynamically remux a pad,
needs enable, idle and off
values */
@@ -187,6 +186,12 @@ struct omap_device_pad {
struct omap_hwmod_mux_info;
+#define OMAP_MUX_STATIC(signal, mode) \
+{ \
+ .name = (signal), \
+ .enable = (mode), \
+}
+
#if defined(CONFIG_OMAP_MUX)
/**
diff --git a/arch/arm/mach-omap2/mux44xx.c b/arch/arm/mach-omap2/mux44xx.c
index c322e7bdaa17..9a66445112ae 100644
--- a/arch/arm/mach-omap2/mux44xx.c
+++ b/arch/arm/mach-omap2/mux44xx.c
@@ -755,25 +755,9 @@ static struct omap_ball __initdata omap4_core_cbl_ball[] = {
#endif
/*
- * Superset of all mux modes for omap4 ES2.0
+ * Signals different on ES2.0 compared to superset
*/
-static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
- _OMAP4_MUXENTRY(GPMC_AD0, 0, "gpmc_ad0", "sdmmc2_dat0", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD1, 0, "gpmc_ad1", "sdmmc2_dat1", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD2, 0, "gpmc_ad2", "sdmmc2_dat2", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD3, 0, "gpmc_ad3", "sdmmc2_dat3", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD4, 0, "gpmc_ad4", "sdmmc2_dat4",
- "sdmmc2_dir_dat0", NULL, NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD5, 0, "gpmc_ad5", "sdmmc2_dat5",
- "sdmmc2_dir_dat1", NULL, NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD6, 0, "gpmc_ad6", "sdmmc2_dat6",
- "sdmmc2_dir_cmd", NULL, NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_AD7, 0, "gpmc_ad7", "sdmmc2_dat7",
- "sdmmc2_clk_fdbk", NULL, NULL, NULL, NULL, NULL),
+static struct omap_mux __initdata omap4_es2_core_subset[] = {
_OMAP4_MUXENTRY(GPMC_AD8, 32, "gpmc_ad8", "kpd_row0", "c2c_data15",
"gpio_32", NULL, "sdmmc1_dat0", NULL, NULL),
_OMAP4_MUXENTRY(GPMC_AD9, 33, "gpmc_ad9", "kpd_row1", "c2c_data14",
@@ -792,52 +776,15 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
"gpio_39", NULL, "sdmmc1_dat7", NULL, NULL),
_OMAP4_MUXENTRY(GPMC_A16, 40, "gpmc_a16", "kpd_row4", "c2c_datain0",
"gpio_40", "venc_656_data0", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A17, 41, "gpmc_a17", "kpd_row5", "c2c_datain1",
- "gpio_41", "venc_656_data1", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A18, 42, "gpmc_a18", "kpd_row6", "c2c_datain2",
- "gpio_42", "venc_656_data2", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A19, 43, "gpmc_a19", "kpd_row7", "c2c_datain3",
- "gpio_43", "venc_656_data3", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A20, 44, "gpmc_a20", "kpd_col4", "c2c_datain4",
- "gpio_44", "venc_656_data4", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A21, 45, "gpmc_a21", "kpd_col5", "c2c_datain5",
- "gpio_45", "venc_656_data5", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A22, 46, "gpmc_a22", "kpd_col6", "c2c_datain6",
- "gpio_46", "venc_656_data6", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A23, 47, "gpmc_a23", "kpd_col7", "c2c_datain7",
- "gpio_47", "venc_656_data7", NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(GPMC_A24, 48, "gpmc_a24", "kpd_col8", "c2c_clkout0",
"gpio_48", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_A25, 49, "gpmc_a25", NULL, "c2c_clkout1",
- "gpio_49", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_NCS0, 50, "gpmc_ncs0", NULL, NULL, "gpio_50",
- "sys_ndmareq0", NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_NCS1, 51, "gpmc_ncs1", NULL, "c2c_dataout6",
- "gpio_51", NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(GPMC_NCS2, 52, "gpmc_ncs2", "kpd_row8",
"c2c_dataout7", "gpio_52", NULL, NULL, NULL,
"safe_mode"),
- _OMAP4_MUXENTRY(GPMC_NCS3, 53, "gpmc_ncs3", "gpmc_dir",
- "c2c_dataout4", "gpio_53", NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_NWP, 54, "gpmc_nwp", "dsi1_te0", NULL, "gpio_54",
- "sys_ndmareq1", NULL, NULL, NULL),
_OMAP4_MUXENTRY(GPMC_CLK, 55, "gpmc_clk", NULL, NULL, "gpio_55",
"sys_ndmareq2", "sdmmc1_cmd", NULL, NULL),
_OMAP4_MUXENTRY(GPMC_NADV_ALE, 56, "gpmc_nadv_ale", "dsi1_te1", NULL,
"gpio_56", "sys_ndmareq3", "sdmmc1_clk", NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_NOE, 0, "gpmc_noe", "sdmmc2_clk", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_NWE, 0, "gpmc_nwe", "sdmmc2_cmd", NULL, NULL,
- NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_NBE0_CLE, 59, "gpmc_nbe0_cle", "dsi2_te0", NULL,
- "gpio_59", NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_NBE1, 60, "gpmc_nbe1", NULL, "c2c_dataout5",
- "gpio_60", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(GPMC_WAIT0, 61, "gpmc_wait0", "dsi2_te1", NULL,
- "gpio_61", NULL, NULL, NULL, NULL),
- _OMAP4_MUXENTRY(GPMC_WAIT1, 62, "gpmc_wait1", NULL, "c2c_dataout2",
- "gpio_62", NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(GPMC_WAIT2, 100, "gpmc_wait2", "usbc1_icusb_txen",
"c2c_dataout3", "gpio_100", "sys_ndmareq0", NULL,
NULL, "safe_mode"),
@@ -851,62 +798,6 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
_OMAP4_MUXENTRY(GPMC_NCS7, 104, "gpmc_ncs7", "dsi2_te1",
"c2c_dataout1", "gpio_104", NULL, NULL, NULL,
"safe_mode"),
- _OMAP4_MUXENTRY(HDMI_HPD, 63, "hdmi_hpd", NULL, NULL, "gpio_63", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(HDMI_CEC, 64, "hdmi_cec", NULL, NULL, "gpio_64", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(HDMI_DDC_SCL, 65, "hdmi_ddc_scl", NULL, NULL,
- "gpio_65", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(HDMI_DDC_SDA, 66, "hdmi_ddc_sda", NULL, NULL,
- "gpio_66", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DX0, 0, "csi21_dx0", NULL, NULL, "gpi_67", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DY0, 0, "csi21_dy0", NULL, NULL, "gpi_68", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DX1, 0, "csi21_dx1", NULL, NULL, "gpi_69", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DY1, 0, "csi21_dy1", NULL, NULL, "gpi_70", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DX2, 0, "csi21_dx2", NULL, NULL, "gpi_71", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DY2, 0, "csi21_dy2", NULL, NULL, "gpi_72", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DX3, 0, "csi21_dx3", NULL, NULL, "gpi_73", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DY3, 0, "csi21_dy3", NULL, NULL, "gpi_74", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DX4, 0, "csi21_dx4", NULL, NULL, "gpi_75", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI21_DY4, 0, "csi21_dy4", NULL, NULL, "gpi_76", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI22_DX0, 0, "csi22_dx0", NULL, NULL, "gpi_77", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI22_DY0, 0, "csi22_dy0", NULL, NULL, "gpi_78", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI22_DX1, 0, "csi22_dx1", NULL, NULL, "gpi_79", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CSI22_DY1, 0, "csi22_dy1", NULL, NULL, "gpi_80", NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CAM_SHUTTER, 81, "cam_shutter", NULL, NULL, "gpio_81",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CAM_STROBE, 82, "cam_strobe", NULL, NULL, "gpio_82",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(CAM_GLOBALRESET, 83, "cam_globalreset", NULL, NULL,
- "gpio_83", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_CLK, 84, "usbb1_ulpitll_clk",
- "hsi1_cawake", NULL, "gpio_84", "usbb1_ulpiphy_clk",
- NULL, "hw_dbg20", "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_STP, 85, "usbb1_ulpitll_stp",
- "hsi1_cadata", "mcbsp4_clkr", "gpio_85",
- "usbb1_ulpiphy_stp", "usbb1_mm_rxdp", "hw_dbg21",
- "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_DIR, 86, "usbb1_ulpitll_dir",
- "hsi1_caflag", "mcbsp4_fsr", "gpio_86",
- "usbb1_ulpiphy_dir", NULL, "hw_dbg22", "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_NXT, 87, "usbb1_ulpitll_nxt",
- "hsi1_acready", "mcbsp4_fsx", "gpio_87",
- "usbb1_ulpiphy_nxt", "usbb1_mm_rxdm", "hw_dbg23",
- "safe_mode"),
_OMAP4_MUXENTRY(USBB1_ULPITLL_DAT0, 88, "usbb1_ulpitll_dat0",
"hsi1_acwake", "mcbsp4_clkx", "gpio_88",
"usbb1_ulpiphy_dat0", "usbb1_mm_txen", "hw_dbg24",
@@ -922,84 +813,6 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
_OMAP4_MUXENTRY(USBB1_ULPITLL_DAT3, 91, "usbb1_ulpitll_dat3",
"hsi1_caready", NULL, "gpio_91", "usbb1_ulpiphy_dat3",
"usbb1_mm_rxrcv", "hw_dbg27", "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_DAT4, 92, "usbb1_ulpitll_dat4",
- "dmtimer8_pwm_evt", "abe_mcbsp3_dr", "gpio_92",
- "usbb1_ulpiphy_dat4", NULL, "hw_dbg28", "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_DAT5, 93, "usbb1_ulpitll_dat5",
- "dmtimer9_pwm_evt", "abe_mcbsp3_dx", "gpio_93",
- "usbb1_ulpiphy_dat5", NULL, "hw_dbg29", "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_DAT6, 94, "usbb1_ulpitll_dat6",
- "dmtimer10_pwm_evt", "abe_mcbsp3_clkx", "gpio_94",
- "usbb1_ulpiphy_dat6", "abe_dmic_din3", "hw_dbg30",
- "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_ULPITLL_DAT7, 95, "usbb1_ulpitll_dat7",
- "dmtimer11_pwm_evt", "abe_mcbsp3_fsx", "gpio_95",
- "usbb1_ulpiphy_dat7", "abe_dmic_clk3", "hw_dbg31",
- "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_HSIC_DATA, 96, "usbb1_hsic_data", NULL, NULL,
- "gpio_96", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBB1_HSIC_STROBE, 97, "usbb1_hsic_strobe", NULL,
- NULL, "gpio_97", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBC1_ICUSB_DP, 98, "usbc1_icusb_dp", NULL, NULL,
- "gpio_98", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBC1_ICUSB_DM, 99, "usbc1_icusb_dm", NULL, NULL,
- "gpio_99", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_CLK, 100, "sdmmc1_clk", NULL, "dpm_emu19",
- "gpio_100", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_CMD, 101, "sdmmc1_cmd", NULL, "uart1_rx",
- "gpio_101", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT0, 102, "sdmmc1_dat0", NULL, "dpm_emu18",
- "gpio_102", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT1, 103, "sdmmc1_dat1", NULL, "dpm_emu17",
- "gpio_103", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT2, 104, "sdmmc1_dat2", NULL, "dpm_emu16",
- "gpio_104", "jtag_tms_tmsc", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT3, 105, "sdmmc1_dat3", NULL, "dpm_emu15",
- "gpio_105", "jtag_tck", NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT4, 106, "sdmmc1_dat4", NULL, NULL,
- "gpio_106", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT5, 107, "sdmmc1_dat5", NULL, NULL,
- "gpio_107", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT6, 108, "sdmmc1_dat6", NULL, NULL,
- "gpio_108", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SDMMC1_DAT7, 109, "sdmmc1_dat7", NULL, NULL,
- "gpio_109", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP2_CLKX, 110, "abe_mcbsp2_clkx", "mcspi2_clk",
- "abe_mcasp_ahclkx", "gpio_110", "usbb2_mm_rxdm",
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP2_DR, 111, "abe_mcbsp2_dr", "mcspi2_somi",
- "abe_mcasp_axr", "gpio_111", "usbb2_mm_rxdp", NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP2_DX, 112, "abe_mcbsp2_dx", "mcspi2_simo",
- "abe_mcasp_amute", "gpio_112", "usbb2_mm_rxrcv", NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP2_FSX, 113, "abe_mcbsp2_fsx", "mcspi2_cs0",
- "abe_mcasp_afsx", "gpio_113", "usbb2_mm_txen", NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP1_CLKX, 114, "abe_mcbsp1_clkx",
- "abe_slimbus1_clock", NULL, "gpio_114", NULL, NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP1_DR, 115, "abe_mcbsp1_dr",
- "abe_slimbus1_data", NULL, "gpio_115", NULL, NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP1_DX, 116, "abe_mcbsp1_dx", "sdmmc3_dat2",
- "abe_mcasp_aclkx", "gpio_116", NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(ABE_MCBSP1_FSX, 117, "abe_mcbsp1_fsx", "sdmmc3_dat3",
- "abe_mcasp_amutein", "gpio_117", NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(ABE_PDM_UL_DATA, 0, "abe_pdm_ul_data",
- "abe_mcbsp3_dr", NULL, NULL, NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(ABE_PDM_DL_DATA, 0, "abe_pdm_dl_data",
- "abe_mcbsp3_dx", NULL, NULL, NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(ABE_PDM_FRAME, 0, "abe_pdm_frame", "abe_mcbsp3_clkx",
- NULL, NULL, NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_PDM_LB_CLK, 0, "abe_pdm_lb_clk", "abe_mcbsp3_fsx",
- NULL, NULL, NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(ABE_CLKS, 118, "abe_clks", NULL, NULL, "gpio_118",
- NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(ABE_DMIC_CLK1, 119, "abe_dmic_clk1", NULL, NULL,
"gpio_119", "usbb2_mm_txse0", "uart4_cts", NULL,
"safe_mode"),
@@ -1012,58 +825,6 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
_OMAP4_MUXENTRY(ABE_DMIC_DIN3, 122, "abe_dmic_din3", "slimbus2_data",
"abe_dmic_clk2", "gpio_122", NULL, "dmtimer9_pwm_evt",
NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART2_CTS, 123, "uart2_cts", "sdmmc3_clk", NULL,
- "gpio_123", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART2_RTS, 124, "uart2_rts", "sdmmc3_cmd", NULL,
- "gpio_124", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART2_RX, 125, "uart2_rx", "sdmmc3_dat0", NULL,
- "gpio_125", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART2_TX, 126, "uart2_tx", "sdmmc3_dat1", NULL,
- "gpio_126", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(HDQ_SIO, 127, "hdq_sio", "i2c3_sccb", "i2c2_sccb",
- "gpio_127", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C1_SCL, 0, "i2c1_scl", NULL, NULL, NULL, NULL, NULL,
- NULL, NULL),
- _OMAP4_MUXENTRY(I2C1_SDA, 0, "i2c1_sda", NULL, NULL, NULL, NULL, NULL,
- NULL, NULL),
- _OMAP4_MUXENTRY(I2C2_SCL, 128, "i2c2_scl", "uart1_rx", NULL,
- "gpio_128", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C2_SDA, 129, "i2c2_sda", "uart1_tx", NULL,
- "gpio_129", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C3_SCL, 130, "i2c3_scl", NULL, NULL, "gpio_130",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C3_SDA, 131, "i2c3_sda", NULL, NULL, "gpio_131",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C4_SCL, 132, "i2c4_scl", NULL, NULL, "gpio_132",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(I2C4_SDA, 133, "i2c4_sda", NULL, NULL, "gpio_133",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_CLK, 134, "mcspi1_clk", NULL, NULL, "gpio_134",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_SOMI, 135, "mcspi1_somi", NULL, NULL,
- "gpio_135", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_SIMO, 136, "mcspi1_simo", NULL, NULL,
- "gpio_136", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_CS0, 137, "mcspi1_cs0", NULL, NULL, "gpio_137",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_CS1, 138, "mcspi1_cs1", "uart1_rx", NULL,
- "gpio_138", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_CS2, 139, "mcspi1_cs2", "uart1_cts",
- "slimbus2_clock", "gpio_139", NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(MCSPI1_CS3, 140, "mcspi1_cs3", "uart1_rts",
- "slimbus2_data", "gpio_140", NULL, NULL, NULL,
- "safe_mode"),
- _OMAP4_MUXENTRY(UART3_CTS_RCTX, 141, "uart3_cts_rctx", "uart1_tx",
- NULL, "gpio_141", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART3_RTS_SD, 142, "uart3_rts_sd", NULL, NULL,
- "gpio_142", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART3_RX_IRRX, 143, "uart3_rx_irrx",
- "dmtimer8_pwm_evt", NULL, "gpio_143", NULL, NULL,
- NULL, "safe_mode"),
- _OMAP4_MUXENTRY(UART3_TX_IRTX, 144, "uart3_tx_irtx",
- "dmtimer9_pwm_evt", NULL, "gpio_144", NULL, NULL,
- NULL, "safe_mode"),
_OMAP4_MUXENTRY(SDMMC5_CLK, 145, "sdmmc5_clk", "mcspi2_clk",
"usbc1_icusb_dp", "gpio_145", NULL, "sdmmc2_clk",
NULL, "safe_mode"),
@@ -1096,9 +857,6 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
"gpio_155", NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(UART4_TX, 156, "uart4_tx", "sdmmc4_dat1", "kpd_col8",
"gpio_156", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBB2_ULPITLL_CLK, 157, "usbb2_ulpitll_clk",
- "usbb2_ulpiphy_clk", "sdmmc4_cmd", "gpio_157",
- "hsi2_cawake", NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(USBB2_ULPITLL_STP, 158, "usbb2_ulpitll_stp",
"usbb2_ulpiphy_stp", "sdmmc4_clk", "gpio_158",
"hsi2_cadata", "dispc2_data23", NULL, "safe_mode"),
@@ -1140,10 +898,6 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
"usbb2_ulpiphy_dat7", "sdmmc3_clk", "gpio_168",
"mcspi3_clk", "dispc2_data11", "rfbi_data11",
"safe_mode"),
- _OMAP4_MUXENTRY(USBB2_HSIC_DATA, 169, "usbb2_hsic_data", NULL, NULL,
- "gpio_169", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBB2_HSIC_STROBE, 170, "usbb2_hsic_strobe", NULL,
- NULL, "gpio_170", NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(KPD_COL3, 171, "kpd_col3", "kpd_col0", NULL,
"gpio_171", NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(KPD_COL4, 172, "kpd_col4", "kpd_col1", NULL,
@@ -1168,36 +922,10 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(KPD_ROW2, 3, "kpd_row2", "kpd_row5", NULL, "gpio_3",
NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(USBA0_OTG_CE, 0, "usba0_otg_ce", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL),
_OMAP4_MUXENTRY(USBA0_OTG_DP, 0, "usba0_otg_dp", "uart3_rx_irrx",
"uart2_rx", NULL, NULL, NULL, NULL, "safe_mode"),
_OMAP4_MUXENTRY(USBA0_OTG_DM, 0, "usba0_otg_dm", "uart3_tx_irtx",
"uart2_tx", NULL, NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(FREF_CLK1_OUT, 181, "fref_clk1_out", NULL, NULL,
- "gpio_181", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(FREF_CLK2_OUT, 182, "fref_clk2_out", NULL, NULL,
- "gpio_182", NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_NIRQ1, 0, "sys_nirq1", NULL, NULL, NULL, NULL,
- NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_NIRQ2, 183, "sys_nirq2", NULL, NULL, "gpio_183",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT0, 184, "sys_boot0", NULL, NULL, "gpio_184",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT1, 185, "sys_boot1", NULL, NULL, "gpio_185",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT2, 186, "sys_boot2", NULL, NULL, "gpio_186",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT3, 187, "sys_boot3", NULL, NULL, "gpio_187",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT4, 188, "sys_boot4", NULL, NULL, "gpio_188",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(SYS_BOOT5, 189, "sys_boot5", NULL, NULL, "gpio_189",
- NULL, NULL, NULL, "safe_mode"),
- _OMAP4_MUXENTRY(DPM_EMU0, 11, "dpm_emu0", NULL, NULL, "gpio_11", NULL,
- NULL, "hw_dbg0", "safe_mode"),
- _OMAP4_MUXENTRY(DPM_EMU1, 12, "dpm_emu1", NULL, NULL, "gpio_12", NULL,
- NULL, "hw_dbg1", "safe_mode"),
_OMAP4_MUXENTRY(DPM_EMU2, 13, "dpm_emu2", "usba0_ulpiphy_clk", NULL,
"gpio_13", NULL, "dispc2_fid", "hw_dbg2",
"safe_mode"),
@@ -1586,6 +1314,7 @@ int __init omap4_mux_init(struct omap_board_mux *board_subset, int flags)
struct omap_ball *package_balls_core;
struct omap_ball *package_balls_wkup = omap4_wkup_cbl_cbs_ball;
struct omap_mux *core_muxmodes;
+ struct omap_mux *core_subset = NULL;
int ret;
switch (flags & OMAP_PACKAGE_MASK) {
@@ -1597,7 +1326,8 @@ int __init omap4_mux_init(struct omap_board_mux *board_subset, int flags)
case OMAP_PACKAGE_CBS:
pr_debug("%s: OMAP4430 ES2.X -> OMAP_PACKAGE_CBS\n", __func__);
package_balls_core = omap4_core_cbs_ball;
- core_muxmodes = omap4_es2_core_muxmodes;
+ core_muxmodes = omap4_core_muxmodes;
+ core_subset = omap4_es2_core_subset;
break;
default:
pr_err("%s: Unknown omap package, mux disabled\n", __func__);
@@ -1608,7 +1338,7 @@ int __init omap4_mux_init(struct omap_board_mux *board_subset, int flags)
OMAP_MUX_GPIO_IN_MODE3,
OMAP4_CTRL_MODULE_PAD_CORE_MUX_PBASE,
OMAP4_CTRL_MODULE_PAD_CORE_MUX_SIZE,
- core_muxmodes, NULL, board_subset,
+ core_muxmodes, core_subset, board_subset,
package_balls_core);
if (ret)
return ret;
diff --git a/arch/arm/mach-omap2/omap-headsmp.S b/arch/arm/mach-omap2/omap-headsmp.S
index 6ae937a06cc1..4ee6aeca885a 100644
--- a/arch/arm/mach-omap2/omap-headsmp.S
+++ b/arch/arm/mach-omap2/omap-headsmp.S
@@ -45,5 +45,5 @@ hold: ldr r12,=0x103
* should now contain the SVC stack for this core
*/
b secondary_startup
-END(omap_secondary_startup)
+ENDPROC(omap_secondary_startup)
diff --git a/arch/arm/mach-omap2/omap44xx-smc.S b/arch/arm/mach-omap2/omap44xx-smc.S
index 1980dc31a1a2..e69d37d95204 100644
--- a/arch/arm/mach-omap2/omap44xx-smc.S
+++ b/arch/arm/mach-omap2/omap44xx-smc.S
@@ -29,7 +29,7 @@ ENTRY(omap_smc1)
dsb
smc #0
ldmfd sp!, {r2-r12, pc}
-END(omap_smc1)
+ENDPROC(omap_smc1)
ENTRY(omap_modify_auxcoreboot0)
stmfd sp!, {r1-r12, lr}
@@ -37,7 +37,7 @@ ENTRY(omap_modify_auxcoreboot0)
dsb
smc #0
ldmfd sp!, {r1-r12, pc}
-END(omap_modify_auxcoreboot0)
+ENDPROC(omap_modify_auxcoreboot0)
ENTRY(omap_auxcoreboot_addr)
stmfd sp!, {r2-r12, lr}
@@ -45,7 +45,7 @@ ENTRY(omap_auxcoreboot_addr)
dsb
smc #0
ldmfd sp!, {r2-r12, pc}
-END(omap_auxcoreboot_addr)
+ENDPROC(omap_auxcoreboot_addr)
ENTRY(omap_read_auxcoreboot0)
stmfd sp!, {r2-r12, lr}
@@ -54,4 +54,4 @@ ENTRY(omap_read_auxcoreboot0)
smc #0
mov r0, r0, lsr #9
ldmfd sp!, {r2-r12, pc}
-END(omap_read_auxcoreboot0)
+ENDPROC(omap_read_auxcoreboot0)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e282e35769fd..e03429453ce7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1,7 +1,7 @@
/*
* omap_hwmod implementation for OMAP2/3/4
*
- * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009-2011 Nokia Corporation
*
* Paul Walmsley, Benoît Cousson, Kevin Hilman
*
@@ -162,9 +162,6 @@ static LIST_HEAD(omap_hwmod_list);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;
-/* inited: 0 if omap_hwmod_init() has not yet been called; 1 otherwise */
-static u8 inited;
-
/* Private functions */
@@ -373,7 +370,7 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
}
autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift;
- autoidle_mask = (0x3 << autoidle_shift);
+ autoidle_mask = (0x1 << autoidle_shift);
*v &= ~autoidle_mask;
*v |= autoidle << autoidle_shift;
@@ -460,14 +457,18 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
* will be accessed by a particular initiator (e.g., if a module will
* be accessed by the IVA, there should be a sleepdep between the IVA
* initiator and the module). Only applies to modules in smart-idle
- * mode. Returns -EINVAL upon error or passes along
- * clkdm_add_sleepdep() value upon success.
+ * mode. If the clockdomain is marked as not needing autodeps, return
+ * 0 without doing anything. Otherwise, returns -EINVAL upon error or
+ * passes along clkdm_add_sleepdep() value upon success.
*/
static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
{
if (!oh->_clk)
return -EINVAL;
+ if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS)
+ return 0;
+
return clkdm_add_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm);
}
@@ -480,14 +481,18 @@ static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
* be accessed by a particular initiator (e.g., if a module will not
* be accessed by the IVA, there should be no sleepdep between the IVA
* initiator and the module). Only applies to modules in smart-idle
- * mode. Returns -EINVAL upon error or passes along
- * clkdm_del_sleepdep() value upon success.
+ * mode. If the clockdomain is marked as not needing autodeps, return
+ * 0 without doing anything. Returns -EINVAL upon error or passes
+ * along clkdm_del_sleepdep() value upon success.
*/
static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh)
{
if (!oh->_clk)
return -EINVAL;
+ if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS)
+ return 0;
+
return clkdm_del_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm);
}
@@ -904,18 +909,16 @@ static struct omap_hwmod *_lookup(const char *name)
* @oh: struct omap_hwmod *
* @data: not used; pass NULL
*
- * Called by omap_hwmod_late_init() (after omap2_clk_init()).
- * Resolves all clock names embedded in the hwmod. Returns -EINVAL if
- * the omap_hwmod has not yet been registered or if the clocks have
- * already been initialized, 0 on success, or a non-zero error on
- * failure.
+ * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
+ * Resolves all clock names embedded in the hwmod. Returns 0 on
+ * success, or a negative error code on failure.
*/
static int _init_clocks(struct omap_hwmod *oh, void *data)
{
int ret = 0;
- if (!oh || (oh->_state != _HWMOD_STATE_REGISTERED))
- return -EINVAL;
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
+ return 0;
pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name);
@@ -926,7 +929,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data)
if (!ret)
oh->_state = _HWMOD_STATE_CLKS_INITED;
- return 0;
+ return ret;
}
/**
@@ -972,25 +975,29 @@ static int _wait_target_ready(struct omap_hwmod *oh)
}
/**
- * _lookup_hardreset - return the register bit shift for this hwmod/reset line
+ * _lookup_hardreset - fill register bit info for this hwmod/reset line
* @oh: struct omap_hwmod *
* @name: name of the reset line in the context of this hwmod
+ * @ohri: struct omap_hwmod_rst_info * that this function will fill in
*
* Return the bit position of the reset line that match the
* input name. Return -ENOENT if not found.
*/
-static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
+static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name,
+ struct omap_hwmod_rst_info *ohri)
{
int i;
for (i = 0; i < oh->rst_lines_cnt; i++) {
const char *rst_line = oh->rst_lines[i].name;
if (!strcmp(rst_line, name)) {
- u8 shift = oh->rst_lines[i].rst_shift;
- pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n",
- oh->name, rst_line, shift);
+ ohri->rst_shift = oh->rst_lines[i].rst_shift;
+ ohri->st_shift = oh->rst_lines[i].st_shift;
+ pr_debug("omap_hwmod: %s: %s: %s: rst %d st %d\n",
+ oh->name, __func__, rst_line, ohri->rst_shift,
+ ohri->st_shift);
- return shift;
+ return 0;
}
}
@@ -1009,21 +1016,22 @@ static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
*/
static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
{
- u8 shift;
+ struct omap_hwmod_rst_info ohri;
+ u8 ret;
if (!oh)
return -EINVAL;
- shift = _lookup_hardreset(oh, name);
- if (IS_ERR_VALUE(shift))
- return shift;
+ ret = _lookup_hardreset(oh, name, &ohri);
+ if (IS_ERR_VALUE(ret))
+ return ret;
if (cpu_is_omap24xx() || cpu_is_omap34xx())
return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
- shift);
+ ohri.rst_shift);
else if (cpu_is_omap44xx())
return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
- shift);
+ ohri.rst_shift);
else
return -EINVAL;
}
@@ -1040,29 +1048,34 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
*/
static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
{
- u8 shift;
- int r;
+ struct omap_hwmod_rst_info ohri;
+ int ret;
if (!oh)
return -EINVAL;
- shift = _lookup_hardreset(oh, name);
- if (IS_ERR_VALUE(shift))
- return shift;
+ ret = _lookup_hardreset(oh, name, &ohri);
+ if (IS_ERR_VALUE(ret))
+ return ret;
- if (cpu_is_omap24xx() || cpu_is_omap34xx())
- r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
- shift);
- else if (cpu_is_omap44xx())
- r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
- shift);
- else
+ if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ ret = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
+ ohri.rst_shift,
+ ohri.st_shift);
+ } else if (cpu_is_omap44xx()) {
+ if (ohri.st_shift)
+ pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
+ oh->name, name);
+ ret = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
+ ohri.rst_shift);
+ } else {
return -EINVAL;
+ }
- if (r == -EBUSY)
+ if (ret == -EBUSY)
pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
- return r;
+ return ret;
}
/**
@@ -1075,21 +1088,22 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
*/
static int _read_hardreset(struct omap_hwmod *oh, const char *name)
{
- u8 shift;
+ struct omap_hwmod_rst_info ohri;
+ u8 ret;
if (!oh)
return -EINVAL;
- shift = _lookup_hardreset(oh, name);
- if (IS_ERR_VALUE(shift))
- return shift;
+ ret = _lookup_hardreset(oh, name, &ohri);
+ if (IS_ERR_VALUE(ret))
+ return ret;
if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
- shift);
+ ohri.st_shift);
} else if (cpu_is_omap44xx()) {
return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
- shift);
+ ohri.rst_shift);
} else {
return -EINVAL;
}
@@ -1230,7 +1244,9 @@ static int _enable(struct omap_hwmod *oh)
_deassert_hardreset(oh, oh->rst_lines[0].name);
/* Mux pins for device runtime if populated */
- if (oh->mux)
+ if (oh->mux && (!oh->mux->enabled ||
+ ((oh->_state == _HWMOD_STATE_IDLE) &&
+ oh->mux->pads_dynamic)))
omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
_add_initiator_dep(oh, mpu_oh);
@@ -1279,7 +1295,7 @@ static int _idle(struct omap_hwmod *oh)
_disable_clocks(oh);
/* Mux pins for device idle if populated */
- if (oh->mux)
+ if (oh->mux && oh->mux->pads_dynamic)
omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
oh->_state = _HWMOD_STATE_IDLE;
@@ -1288,6 +1304,42 @@ static int _idle(struct omap_hwmod *oh)
}
/**
+ * omap_hwmod_set_ocp_autoidle - set the hwmod's OCP autoidle bit
+ * @oh: struct omap_hwmod *
+ * @autoidle: desired AUTOIDLE bitfield value (0 or 1)
+ *
+ * Sets the IP block's OCP autoidle bit in hardware, and updates our
+ * local copy. Intended to be used by drivers that require
+ * direct manipulation of the AUTOIDLE bits.
+ * Returns -EINVAL if @oh is null or is not in the ENABLED state, or passes
+ * along the return value from _set_module_autoidle().
+ *
+ * Any users of this function should be scrutinized carefully.
+ */
+int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle)
+{
+ u32 v;
+ int retval = 0;
+ unsigned long flags;
+
+ if (!oh || oh->_state != _HWMOD_STATE_ENABLED)
+ return -EINVAL;
+
+ spin_lock_irqsave(&oh->_lock, flags);
+
+ v = oh->_sysc_cache;
+
+ retval = _set_module_autoidle(oh, autoidle, &v);
+
+ if (!retval)
+ _write_sysconfig(v, oh);
+
+ spin_unlock_irqrestore(&oh->_lock, flags);
+
+ return retval;
+}
+
+/**
* _shutdown - shutdown an omap_hwmod
* @oh: struct omap_hwmod *
*
@@ -1354,14 +1406,16 @@ static int _shutdown(struct omap_hwmod *oh)
* @oh: struct omap_hwmod *
*
* Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the
- * wrong state or returns 0.
+ * OCP_SYSCONFIG register. Returns 0.
*/
static int _setup(struct omap_hwmod *oh, void *data)
{
int i, r;
u8 postsetup_state;
+ if (oh->_state != _HWMOD_STATE_CLKS_INITED)
+ return 0;
+
/* Set iclk autoidle mode */
if (oh->slaves_cnt > 0) {
for (i = 0; i < oh->slaves_cnt; i++) {
@@ -1455,7 +1509,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
*/
static int __init _register(struct omap_hwmod *oh)
{
- int ret, ms_id;
+ int ms_id;
if (!oh || !oh->name || !oh->class || !oh->class->name ||
(oh->_state != _HWMOD_STATE_UNKNOWN))
@@ -1467,12 +1521,10 @@ static int __init _register(struct omap_hwmod *oh)
return -EEXIST;
ms_id = _find_mpu_port_index(oh);
- if (!IS_ERR_VALUE(ms_id)) {
+ if (!IS_ERR_VALUE(ms_id))
oh->_mpu_port_index = ms_id;
- oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
- } else {
+ else
oh->_int_flags |= _HWMOD_NO_MPU_PORT;
- }
list_add_tail(&oh->node, &omap_hwmod_list);
@@ -1480,9 +1532,14 @@ static int __init _register(struct omap_hwmod *oh)
oh->_state = _HWMOD_STATE_REGISTERED;
- ret = 0;
+ /*
+ * XXX Rather than doing a strcmp(), this should test a flag
+ * set in the hwmod data, inserted by the autogenerator code.
+ */
+ if (!strcmp(oh->name, MPU_INITIATOR_NAME))
+ mpu_oh = oh;
- return ret;
+ return 0;
}
@@ -1585,65 +1642,132 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
return ret;
}
-
/**
- * omap_hwmod_init - init omap_hwmod code and register hwmods
+ * omap_hwmod_register - register an array of hwmods
* @ohs: pointer to an array of omap_hwmods to register
*
* Intended to be called early in boot before the clock framework is
* initialized. If @ohs is not null, will register all omap_hwmods
- * listed in @ohs that are valid for this chip. Returns -EINVAL if
- * omap_hwmod_init() has already been called or 0 otherwise.
+ * listed in @ohs that are valid for this chip. Returns 0.
*/
-int __init omap_hwmod_init(struct omap_hwmod **ohs)
+int __init omap_hwmod_register(struct omap_hwmod **ohs)
+{
+ int r, i;
+
+ if (!ohs)
+ return 0;
+
+ i = 0;
+ do {
+ if (!omap_chip_is(ohs[i]->omap_chip))
+ continue;
+
+ r = _register(ohs[i]);
+ WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name,
+ r);
+ } while (ohs[++i]);
+
+ return 0;
+}
+
+/*
+ * _populate_mpu_rt_base - populate the virtual address for a hwmod
+ *
+ * Must be called only from omap_hwmod_setup_*() so ioremap works properly.
+ * Assumes the caller takes care of locking if needed.
+ */
+static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data)
+{
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
+ return 0;
+
+ if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+ return 0;
+
+ oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
+ if (!oh->_mpu_rt_va)
+ pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n",
+ __func__, oh->name);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_setup_one - set up a single hwmod
+ * @oh_name: const char * name of the already-registered hwmod to set up
+ *
+ * Must be called after omap2_clk_init(). Resolves the struct clk
+ * names to struct clk pointers for each registered omap_hwmod. Also
+ * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon
+ * success.
+ */
+int __init omap_hwmod_setup_one(const char *oh_name)
{
struct omap_hwmod *oh;
int r;
- if (inited)
+ pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
+
+ if (!mpu_oh) {
+ pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n",
+ oh_name, MPU_INITIATOR_NAME);
return -EINVAL;
+ }
- inited = 1;
+ oh = _lookup(oh_name);
+ if (!oh) {
+ WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
+ return -EINVAL;
+ }
- if (!ohs)
- return 0;
+ if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
+ omap_hwmod_setup_one(MPU_INITIATOR_NAME);
- oh = *ohs;
- while (oh) {
- if (omap_chip_is(oh->omap_chip)) {
- r = _register(oh);
- WARN(r, "omap_hwmod: %s: _register returned "
- "%d\n", oh->name, r);
- }
- oh = *++ohs;
+ r = _populate_mpu_rt_base(oh, NULL);
+ if (IS_ERR_VALUE(r)) {
+ WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name);
+ return -EINVAL;
}
+ r = _init_clocks(oh, NULL);
+ if (IS_ERR_VALUE(r)) {
+ WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name);
+ return -EINVAL;
+ }
+
+ _setup(oh, NULL);
+
return 0;
}
/**
- * omap_hwmod_late_init - do some post-clock framework initialization
+ * omap_hwmod_setup - do some post-clock framework initialization
*
* Must be called after omap2_clk_init(). Resolves the struct clk names
* to struct clk pointers for each registered omap_hwmod. Also calls
- * _setup() on each hwmod. Returns 0.
+ * _setup() on each hwmod. Returns 0 upon success.
*/
-int omap_hwmod_late_init(void)
+static int __init omap_hwmod_setup_all(void)
{
int r;
- /* XXX check return value */
- r = omap_hwmod_for_each(_init_clocks, NULL);
- WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n");
+ if (!mpu_oh) {
+ pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
+ __func__, MPU_INITIATOR_NAME);
+ return -EINVAL;
+ }
- mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME);
- WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n",
- MPU_INITIATOR_NAME);
+ r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL);
+
+ r = omap_hwmod_for_each(_init_clocks, NULL);
+ WARN(IS_ERR_VALUE(r),
+ "omap_hwmod: %s: _init_clocks failed\n", __func__);
omap_hwmod_for_each(_setup, NULL);
return 0;
}
+core_initcall(omap_hwmod_setup_all);
/**
* omap_hwmod_enable - enable an omap_hwmod
@@ -1862,6 +1986,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
os = oh->slaves[i];
for (j = 0; j < os->addr_cnt; j++) {
+ (res + r)->name = (os->addr + j)->name;
(res + r)->start = (os->addr + j)->pa_start;
(res + r)->end = (os->addr + j)->pa_end;
(res + r)->flags = IORESOURCE_MEM;
@@ -2162,11 +2287,11 @@ int omap_hwmod_for_each_by_class(const char *classname,
* @oh: struct omap_hwmod *
* @state: state that _setup() should leave the hwmod in
*
- * Sets the hwmod state that @oh will enter at the end of _setup() (called by
- * omap_hwmod_late_init()). Only valid to call between calls to
- * omap_hwmod_init() and omap_hwmod_late_init(). Returns 0 upon success or
- * -EINVAL if there is a problem with the arguments or if the hwmod is
- * in the wrong state.
+ * Sets the hwmod state that @oh will enter at the end of _setup()
+ * (called by omap_hwmod_setup_*()). Only valid to call between
+ * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns
+ * 0 upon success or -EINVAL if there is a problem with the arguments
+ * or if the hwmod is in the wrong state.
*/
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
{
@@ -2218,3 +2343,29 @@ u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
return ret;
}
+
+/**
+ * omap_hwmod_no_setup_reset - prevent a hwmod from being reset upon setup
+ * @oh: struct omap_hwmod *
+ *
+ * Prevent the hwmod @oh from being reset during the setup process.
+ * Intended for use by board-*.c files on boards with devices that
+ * cannot tolerate being reset. Must be called before the hwmod has
+ * been set up. Returns 0 upon success or negative error code upon
+ * failure.
+ */
+int omap_hwmod_no_setup_reset(struct omap_hwmod *oh)
+{
+ if (!oh)
+ return -EINVAL;
+
+ if (oh->_state != _HWMOD_STATE_REGISTERED) {
+ pr_err("omap_hwmod: %s: cannot prevent setup reset; in wrong state\n",
+ oh->name);
+ return -EINVAL;
+ }
+
+ oh->flags |= HWMOD_INIT_NO_RESET;
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index b85c630b64d6..62823467163b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -18,6 +18,10 @@
#include <plat/serial.h>
#include <plat/i2c.h>
#include <plat/gpio.h>
+#include <plat/mcspi.h>
+#include <plat/dmtimer.h>
+#include <plat/l3_2xxx.h>
+#include <plat/l4_2xxx.h>
#include "omap_hwmod_common_data.h"
@@ -38,12 +42,18 @@ static struct omap_hwmod omap2420_mpu_hwmod;
static struct omap_hwmod omap2420_iva_hwmod;
static struct omap_hwmod omap2420_l3_main_hwmod;
static struct omap_hwmod omap2420_l4_core_hwmod;
+static struct omap_hwmod omap2420_dss_core_hwmod;
+static struct omap_hwmod omap2420_dss_dispc_hwmod;
+static struct omap_hwmod omap2420_dss_rfbi_hwmod;
+static struct omap_hwmod omap2420_dss_venc_hwmod;
static struct omap_hwmod omap2420_wd_timer2_hwmod;
static struct omap_hwmod omap2420_gpio1_hwmod;
static struct omap_hwmod omap2420_gpio2_hwmod;
static struct omap_hwmod omap2420_gpio3_hwmod;
static struct omap_hwmod omap2420_gpio4_hwmod;
static struct omap_hwmod omap2420_dma_system_hwmod;
+static struct omap_hwmod omap2420_mcspi1_hwmod;
+static struct omap_hwmod omap2420_mcspi2_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -64,6 +74,19 @@ static struct omap_hwmod_ocp_if *omap2420_l3_main_slaves[] = {
&omap2420_mpu__l3_main,
};
+/* DSS -> l3 */
+static struct omap_hwmod_ocp_if omap2420_dss__l3 = {
+ .master = &omap2420_dss_core_hwmod,
+ .slave = &omap2420_l3_main_hwmod,
+ .fw = {
+ .omap2 = {
+ .l3_perm_bit = OMAP2_L3_CORE_FW_CONNID_DSS,
+ .flags = OMAP_FIREWALL_L3,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Master interfaces on the L3 interconnect */
static struct omap_hwmod_ocp_if *omap2420_l3_main_masters[] = {
&omap2420_l3_main__l4_core,
@@ -87,6 +110,44 @@ static struct omap_hwmod omap2420_uart2_hwmod;
static struct omap_hwmod omap2420_uart3_hwmod;
static struct omap_hwmod omap2420_i2c1_hwmod;
static struct omap_hwmod omap2420_i2c2_hwmod;
+static struct omap_hwmod omap2420_mcbsp1_hwmod;
+static struct omap_hwmod omap2420_mcbsp2_hwmod;
+
+/* l4 core -> mcspi1 interface */
+static struct omap_hwmod_addr_space omap2420_mcspi1_addr_space[] = {
+ {
+ .pa_start = 0x48098000,
+ .pa_end = 0x480980ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi1 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mcspi1_hwmod,
+ .clk = "mcspi1_ick",
+ .addr = omap2420_mcspi1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_mcspi1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+static struct omap_hwmod_addr_space omap2420_mcspi2_addr_space[] = {
+ {
+ .pa_start = 0x4809a000,
+ .pa_end = 0x4809a0ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi2 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mcspi2_hwmod,
+ .clk = "mcspi2_ick",
+ .addr = omap2420_mcspi2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2420_mcspi2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
/* L4_CORE -> L4_WKUP interface */
static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
@@ -279,6 +340,625 @@ static struct omap_hwmod omap2420_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
};
+/* Timer Common */
+static struct omap_hwmod_class_sysconfig omap2420_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_timer_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap2420_timer_sysc,
+ .rev = OMAP_TIMER_IP_VERSION_1,
+};
+
+/* timer1 */
+static struct omap_hwmod omap2420_timer1_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer1_mpu_irqs[] = {
+ { .irq = 37, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer1_addrs[] = {
+ {
+ .pa_start = 0x48028000,
+ .pa_end = 0x48028000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__timer1 = {
+ .master = &omap2420_l4_wkup_hwmod,
+ .slave = &omap2420_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap2420_timer1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer1 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer1_slaves[] = {
+ &omap2420_l4_wkup__timer1,
+};
+
+/* timer1 hwmod */
+static struct omap_hwmod omap2420_timer1_hwmod = {
+ .name = "timer1",
+ .mpu_irqs = omap2420_timer1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer1_mpu_irqs),
+ .main_clk = "gpt1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT1_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer1_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer2 */
+static struct omap_hwmod omap2420_timer2_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer2_mpu_irqs[] = {
+ { .irq = 38, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer2_addrs[] = {
+ {
+ .pa_start = 0x4802a000,
+ .pa_end = 0x4802a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer2 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer2 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer2_hwmod,
+ .clk = "gpt2_ick",
+ .addr = omap2420_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer2 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer2_slaves[] = {
+ &omap2420_l4_core__timer2,
+};
+
+/* timer2 hwmod */
+static struct omap_hwmod omap2420_timer2_hwmod = {
+ .name = "timer2",
+ .mpu_irqs = omap2420_timer2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer2_mpu_irqs),
+ .main_clk = "gpt2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT2_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer2_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer3 */
+static struct omap_hwmod omap2420_timer3_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer3_mpu_irqs[] = {
+ { .irq = 39, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer3_addrs[] = {
+ {
+ .pa_start = 0x48078000,
+ .pa_end = 0x48078000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer3 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer3 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer3_hwmod,
+ .clk = "gpt3_ick",
+ .addr = omap2420_timer3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer3 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer3_slaves[] = {
+ &omap2420_l4_core__timer3,
+};
+
+/* timer3 hwmod */
+static struct omap_hwmod omap2420_timer3_hwmod = {
+ .name = "timer3",
+ .mpu_irqs = omap2420_timer3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer3_mpu_irqs),
+ .main_clk = "gpt3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT3_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer3_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer4 */
+static struct omap_hwmod omap2420_timer4_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer4_mpu_irqs[] = {
+ { .irq = 40, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer4_addrs[] = {
+ {
+ .pa_start = 0x4807a000,
+ .pa_end = 0x4807a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer4 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer4 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer4_hwmod,
+ .clk = "gpt4_ick",
+ .addr = omap2420_timer4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer4 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer4_slaves[] = {
+ &omap2420_l4_core__timer4,
+};
+
+/* timer4 hwmod */
+static struct omap_hwmod omap2420_timer4_hwmod = {
+ .name = "timer4",
+ .mpu_irqs = omap2420_timer4_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer4_mpu_irqs),
+ .main_clk = "gpt4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT4_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer4_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer5 */
+static struct omap_hwmod omap2420_timer5_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer5_mpu_irqs[] = {
+ { .irq = 41, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer5_addrs[] = {
+ {
+ .pa_start = 0x4807c000,
+ .pa_end = 0x4807c000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer5 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer5 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer5_hwmod,
+ .clk = "gpt5_ick",
+ .addr = omap2420_timer5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer5 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer5_slaves[] = {
+ &omap2420_l4_core__timer5,
+};
+
+/* timer5 hwmod */
+static struct omap_hwmod omap2420_timer5_hwmod = {
+ .name = "timer5",
+ .mpu_irqs = omap2420_timer5_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer5_mpu_irqs),
+ .main_clk = "gpt5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT5_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer5_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+
+/* timer6 */
+static struct omap_hwmod omap2420_timer6_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer6_mpu_irqs[] = {
+ { .irq = 42, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer6_addrs[] = {
+ {
+ .pa_start = 0x4807e000,
+ .pa_end = 0x4807e000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer6 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer6 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer6_hwmod,
+ .clk = "gpt6_ick",
+ .addr = omap2420_timer6_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer6_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer6 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer6_slaves[] = {
+ &omap2420_l4_core__timer6,
+};
+
+/* timer6 hwmod */
+static struct omap_hwmod omap2420_timer6_hwmod = {
+ .name = "timer6",
+ .mpu_irqs = omap2420_timer6_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer6_mpu_irqs),
+ .main_clk = "gpt6_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT6_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer6_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer6_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer7 */
+static struct omap_hwmod omap2420_timer7_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer7_mpu_irqs[] = {
+ { .irq = 43, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer7_addrs[] = {
+ {
+ .pa_start = 0x48080000,
+ .pa_end = 0x48080000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer7 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer7 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer7_hwmod,
+ .clk = "gpt7_ick",
+ .addr = omap2420_timer7_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer7_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer7 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer7_slaves[] = {
+ &omap2420_l4_core__timer7,
+};
+
+/* timer7 hwmod */
+static struct omap_hwmod omap2420_timer7_hwmod = {
+ .name = "timer7",
+ .mpu_irqs = omap2420_timer7_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer7_mpu_irqs),
+ .main_clk = "gpt7_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT7_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer7_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer7_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer8 */
+static struct omap_hwmod omap2420_timer8_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer8_mpu_irqs[] = {
+ { .irq = 44, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer8_addrs[] = {
+ {
+ .pa_start = 0x48082000,
+ .pa_end = 0x48082000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer8 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer8 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer8_hwmod,
+ .clk = "gpt8_ick",
+ .addr = omap2420_timer8_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer8_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer8 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer8_slaves[] = {
+ &omap2420_l4_core__timer8,
+};
+
+/* timer8 hwmod */
+static struct omap_hwmod omap2420_timer8_hwmod = {
+ .name = "timer8",
+ .mpu_irqs = omap2420_timer8_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer8_mpu_irqs),
+ .main_clk = "gpt8_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT8_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer8_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer8_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer9 */
+static struct omap_hwmod omap2420_timer9_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer9_mpu_irqs[] = {
+ { .irq = 45, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer9_addrs[] = {
+ {
+ .pa_start = 0x48084000,
+ .pa_end = 0x48084000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer9 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer9 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer9_hwmod,
+ .clk = "gpt9_ick",
+ .addr = omap2420_timer9_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer9_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer9 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer9_slaves[] = {
+ &omap2420_l4_core__timer9,
+};
+
+/* timer9 hwmod */
+static struct omap_hwmod omap2420_timer9_hwmod = {
+ .name = "timer9",
+ .mpu_irqs = omap2420_timer9_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer9_mpu_irqs),
+ .main_clk = "gpt9_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT9_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer9_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer9_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer10 */
+static struct omap_hwmod omap2420_timer10_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer10_mpu_irqs[] = {
+ { .irq = 46, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer10_addrs[] = {
+ {
+ .pa_start = 0x48086000,
+ .pa_end = 0x48086000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer10 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer10 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer10_hwmod,
+ .clk = "gpt10_ick",
+ .addr = omap2420_timer10_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer10_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer10 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer10_slaves[] = {
+ &omap2420_l4_core__timer10,
+};
+
+/* timer10 hwmod */
+static struct omap_hwmod omap2420_timer10_hwmod = {
+ .name = "timer10",
+ .mpu_irqs = omap2420_timer10_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer10_mpu_irqs),
+ .main_clk = "gpt10_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT10_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer10_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer10_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer11 */
+static struct omap_hwmod omap2420_timer11_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer11_mpu_irqs[] = {
+ { .irq = 47, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer11_addrs[] = {
+ {
+ .pa_start = 0x48088000,
+ .pa_end = 0x48088000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer11 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer11 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer11_hwmod,
+ .clk = "gpt11_ick",
+ .addr = omap2420_timer11_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer11_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer11 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer11_slaves[] = {
+ &omap2420_l4_core__timer11,
+};
+
+/* timer11 hwmod */
+static struct omap_hwmod omap2420_timer11_hwmod = {
+ .name = "timer11",
+ .mpu_irqs = omap2420_timer11_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer11_mpu_irqs),
+ .main_clk = "gpt11_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT11_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer11_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer11_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
+/* timer12 */
+static struct omap_hwmod omap2420_timer12_hwmod;
+static struct omap_hwmod_irq_info omap2420_timer12_mpu_irqs[] = {
+ { .irq = 48, },
+};
+
+static struct omap_hwmod_addr_space omap2420_timer12_addrs[] = {
+ {
+ .pa_start = 0x4808a000,
+ .pa_end = 0x4808a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer12 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__timer12 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_timer12_hwmod,
+ .clk = "gpt12_ick",
+ .addr = omap2420_timer12_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_timer12_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer12 slave port */
+static struct omap_hwmod_ocp_if *omap2420_timer12_slaves[] = {
+ &omap2420_l4_core__timer12,
+};
+
+/* timer12 hwmod */
+static struct omap_hwmod omap2420_timer12_hwmod = {
+ .name = "timer12",
+ .mpu_irqs = omap2420_timer12_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_timer12_mpu_irqs),
+ .main_clk = "gpt12_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT12_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
+ },
+ },
+ .slaves = omap2420_timer12_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_timer12_slaves),
+ .class = &omap2420_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
+};
+
/* l4_wkup -> wd_timer2 */
static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
{
@@ -308,7 +988,7 @@ static struct omap_hwmod_class_sysconfig omap2420_wd_timer_sysc = {
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -349,7 +1029,7 @@ static struct omap_hwmod_class_sysconfig uart_sysc = {
.syss_offs = 0x58,
.sysc_flags = (SYSC_HAS_SIDLEMODE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -470,12 +1150,298 @@ static struct omap_hwmod omap2420_uart3_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
};
+/*
+ * 'dss' class
+ * display sub-system
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_dss_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_dss_hwmod_class = {
+ .name = "dss",
+ .sysc = &omap2420_dss_sysc,
+};
+
+/* dss */
+static struct omap_hwmod_irq_info omap2420_dss_irqs[] = {
+ { .irq = 25 },
+};
+
+static struct omap_hwmod_dma_info omap2420_dss_sdma_chs[] = {
+ { .name = "dispc", .dma_req = 5 },
+};
+
+/* dss */
+/* dss master ports */
+static struct omap_hwmod_ocp_if *omap2420_dss_masters[] = {
+ &omap2420_dss__l3,
+};
+
+static struct omap_hwmod_addr_space omap2420_dss_addrs[] = {
+ {
+ .pa_start = 0x48050000,
+ .pa_end = 0x480503FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss */
+static struct omap_hwmod_ocp_if omap2420_l4_core__dss = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2420_dss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_dss_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss slave ports */
+static struct omap_hwmod_ocp_if *omap2420_dss_slaves[] = {
+ &omap2420_l4_core__dss,
+};
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+ { .role = "tv_clk", .clk = "dss_54m_fck" },
+ { .role = "sys_clk", .clk = "dss2_fck" },
+};
+
+static struct omap_hwmod omap2420_dss_core_hwmod = {
+ .name = "dss_core",
+ .class = &omap2420_dss_hwmod_class,
+ .main_clk = "dss1_fck", /* instead of dss_fck */
+ .mpu_irqs = omap2420_dss_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_dss_irqs),
+ .sdma_reqs = omap2420_dss_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2420_dss_sdma_chs),
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .slaves = omap2420_dss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_dss_slaves),
+ .masters = omap2420_dss_masters,
+ .masters_cnt = ARRAY_SIZE(omap2420_dss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_dispc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_dispc_hwmod_class = {
+ .name = "dispc",
+ .sysc = &omap2420_dispc_sysc,
+};
+
+static struct omap_hwmod_addr_space omap2420_dss_dispc_addrs[] = {
+ {
+ .pa_start = 0x48050400,
+ .pa_end = 0x480507FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_dispc */
+static struct omap_hwmod_ocp_if omap2420_l4_core__dss_dispc = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_dss_dispc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2420_dss_dispc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_dss_dispc_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_DISPC_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_dispc slave ports */
+static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = {
+ &omap2420_l4_core__dss_dispc,
+};
+
+static struct omap_hwmod omap2420_dss_dispc_hwmod = {
+ .name = "dss_dispc",
+ .class = &omap2420_dispc_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .slaves = omap2420_dss_dispc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_dss_dispc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'rfbi' class
+ * remote frame buffer interface
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_rfbi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_rfbi_hwmod_class = {
+ .name = "rfbi",
+ .sysc = &omap2420_rfbi_sysc,
+};
+
+static struct omap_hwmod_addr_space omap2420_dss_rfbi_addrs[] = {
+ {
+ .pa_start = 0x48050800,
+ .pa_end = 0x48050BFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap2420_l4_core__dss_rfbi = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_dss_rfbi_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2420_dss_rfbi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_dss_rfbi_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_rfbi slave ports */
+static struct omap_hwmod_ocp_if *omap2420_dss_rfbi_slaves[] = {
+ &omap2420_l4_core__dss_rfbi,
+};
+
+static struct omap_hwmod omap2420_dss_rfbi_hwmod = {
+ .name = "dss_rfbi",
+ .class = &omap2420_rfbi_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .slaves = omap2420_dss_rfbi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_dss_rfbi_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'venc' class
+ * video encoder
+ */
+
+static struct omap_hwmod_class omap2420_venc_hwmod_class = {
+ .name = "venc",
+};
+
+/* dss_venc */
+static struct omap_hwmod_addr_space omap2420_dss_venc_addrs[] = {
+ {
+ .pa_start = 0x48050C00,
+ .pa_end = 0x48050FFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_venc */
+static struct omap_hwmod_ocp_if omap2420_l4_core__dss_venc = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_dss_venc_hwmod,
+ .clk = "dss_54m_fck",
+ .addr = omap2420_dss_venc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_dss_venc_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_VENC_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .flags = OCPIF_SWSUP_IDLE,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_venc slave ports */
+static struct omap_hwmod_ocp_if *omap2420_dss_venc_slaves[] = {
+ &omap2420_l4_core__dss_venc,
+};
+
+static struct omap_hwmod omap2420_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap2420_venc_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .slaves = omap2420_dss_venc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_dss_venc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+ .flags = HWMOD_NO_IDLEST,
+};
+
/* I2C common */
static struct omap_hwmod_class_sysconfig i2c_sysc = {
.rev_offs = 0x00,
.sysc_offs = 0x20,
.syss_offs = 0x10,
- .sysc_flags = SYSC_HAS_SOFTRESET,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -647,7 +1613,8 @@ static struct omap_hwmod_class_sysconfig omap242x_gpio_sysc = {
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -789,7 +1756,7 @@ static struct omap_hwmod_class_sysconfig omap2420_dma_sysc = {
.syss_offs = 0x0028,
.sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_MIDLEMODE |
SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_EMUFREE |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -864,16 +1831,342 @@ static struct omap_hwmod omap2420_dma_system_hwmod = {
.flags = HWMOD_NO_IDLEST,
};
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors
+ * using a queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_mailbox_sysc = {
+ .rev_offs = 0x000,
+ .sysc_offs = 0x010,
+ .syss_offs = 0x014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_mailbox_hwmod_class = {
+ .name = "mailbox",
+ .sysc = &omap2420_mailbox_sysc,
+};
+
+/* mailbox */
+static struct omap_hwmod omap2420_mailbox_hwmod;
+static struct omap_hwmod_irq_info omap2420_mailbox_irqs[] = {
+ { .name = "dsp", .irq = 26 },
+ { .name = "iva", .irq = 34 },
+};
+
+static struct omap_hwmod_addr_space omap2420_mailbox_addrs[] = {
+ {
+ .pa_start = 0x48094000,
+ .pa_end = 0x480941ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mailbox = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mailbox_hwmod,
+ .addr = omap2420_mailbox_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_mailbox_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mailbox slave ports */
+static struct omap_hwmod_ocp_if *omap2420_mailbox_slaves[] = {
+ &omap2420_l4_core__mailbox,
+};
+
+static struct omap_hwmod omap2420_mailbox_hwmod = {
+ .name = "mailbox",
+ .class = &omap2420_mailbox_hwmod_class,
+ .mpu_irqs = omap2420_mailbox_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_mailbox_irqs),
+ .main_clk = "mailboxes_ick",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MAILBOXES_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
+ },
+ },
+ .slaves = omap2420_mailbox_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mailbox_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_mcspi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_mcspi_class = {
+ .name = "mcspi",
+ .sysc = &omap2420_mcspi_sysc,
+ .rev = OMAP2_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap_hwmod_irq_info omap2420_mcspi1_mpu_irqs[] = {
+ { .irq = 65 },
+};
+
+static struct omap_hwmod_dma_info omap2420_mcspi1_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 35 }, /* DMA_SPI1_TX0 */
+ { .name = "rx0", .dma_req = 36 }, /* DMA_SPI1_RX0 */
+ { .name = "tx1", .dma_req = 37 }, /* DMA_SPI1_TX1 */
+ { .name = "rx1", .dma_req = 38 }, /* DMA_SPI1_RX1 */
+ { .name = "tx2", .dma_req = 39 }, /* DMA_SPI1_TX2 */
+ { .name = "rx2", .dma_req = 40 }, /* DMA_SPI1_RX2 */
+ { .name = "tx3", .dma_req = 41 }, /* DMA_SPI1_TX3 */
+ { .name = "rx3", .dma_req = 42 }, /* DMA_SPI1_RX3 */
+};
+
+static struct omap_hwmod_ocp_if *omap2420_mcspi1_slaves[] = {
+ &omap2420_l4_core__mcspi1,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+ .num_chipselect = 4,
+};
+
+static struct omap_hwmod omap2420_mcspi1_hwmod = {
+ .name = "mcspi1_hwmod",
+ .mpu_irqs = omap2420_mcspi1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_mcspi1_mpu_irqs),
+ .sdma_reqs = omap2420_mcspi1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2420_mcspi1_sdma_reqs),
+ .main_clk = "mcspi1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
+ },
+ },
+ .slaves = omap2420_mcspi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mcspi1_slaves),
+ .class = &omap2420_mcspi_class,
+ .dev_attr = &omap_mcspi1_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* mcspi2 */
+static struct omap_hwmod_irq_info omap2420_mcspi2_mpu_irqs[] = {
+ { .irq = 66 },
+};
+
+static struct omap_hwmod_dma_info omap2420_mcspi2_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 43 }, /* DMA_SPI2_TX0 */
+ { .name = "rx0", .dma_req = 44 }, /* DMA_SPI2_RX0 */
+ { .name = "tx1", .dma_req = 45 }, /* DMA_SPI2_TX1 */
+ { .name = "rx1", .dma_req = 46 }, /* DMA_SPI2_RX1 */
+};
+
+static struct omap_hwmod_ocp_if *omap2420_mcspi2_slaves[] = {
+ &omap2420_l4_core__mcspi2,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap2420_mcspi2_hwmod = {
+ .name = "mcspi2_hwmod",
+ .mpu_irqs = omap2420_mcspi2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_mcspi2_mpu_irqs),
+ .sdma_reqs = omap2420_mcspi2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2420_mcspi2_sdma_reqs),
+ .main_clk = "mcspi2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
+ },
+ },
+ .slaves = omap2420_mcspi2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mcspi2_slaves),
+ .class = &omap2420_mcspi_class,
+ .dev_attr = &omap_mcspi2_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class omap2420_mcbsp_hwmod_class = {
+ .name = "mcbsp",
+};
+
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap2420_mcbsp1_irqs[] = {
+ { .name = "tx", .irq = 59 },
+ { .name = "rx", .irq = 60 },
+};
+
+static struct omap_hwmod_dma_info omap2420_mcbsp1_sdma_chs[] = {
+ { .name = "rx", .dma_req = 32 },
+ { .name = "tx", .dma_req = 31 },
+};
+
+static struct omap_hwmod_addr_space omap2420_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48074000,
+ .pa_end = 0x480740ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp1 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mcbsp1_hwmod,
+ .clk = "mcbsp1_ick",
+ .addr = omap2420_mcbsp1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_mcbsp1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp1 slave ports */
+static struct omap_hwmod_ocp_if *omap2420_mcbsp1_slaves[] = {
+ &omap2420_l4_core__mcbsp1,
+};
+
+static struct omap_hwmod omap2420_mcbsp1_hwmod = {
+ .name = "mcbsp1",
+ .class = &omap2420_mcbsp_hwmod_class,
+ .mpu_irqs = omap2420_mcbsp1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_mcbsp1_irqs),
+ .sdma_reqs = omap2420_mcbsp1_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2420_mcbsp1_sdma_chs),
+ .main_clk = "mcbsp1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCBSP1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
+ },
+ },
+ .slaves = omap2420_mcbsp1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mcbsp1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap2420_mcbsp2_irqs[] = {
+ { .name = "tx", .irq = 62 },
+ { .name = "rx", .irq = 63 },
+};
+
+static struct omap_hwmod_dma_info omap2420_mcbsp2_sdma_chs[] = {
+ { .name = "rx", .dma_req = 34 },
+ { .name = "tx", .dma_req = 33 },
+};
+
+static struct omap_hwmod_addr_space omap2420_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48076000,
+ .pa_end = 0x480760ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = {
+ .master = &omap2420_l4_core_hwmod,
+ .slave = &omap2420_mcbsp2_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap2420_mcbsp2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2420_mcbsp2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp2 slave ports */
+static struct omap_hwmod_ocp_if *omap2420_mcbsp2_slaves[] = {
+ &omap2420_l4_core__mcbsp2,
+};
+
+static struct omap_hwmod omap2420_mcbsp2_hwmod = {
+ .name = "mcbsp2",
+ .class = &omap2420_mcbsp_hwmod_class,
+ .mpu_irqs = omap2420_mcbsp2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2420_mcbsp2_irqs),
+ .sdma_reqs = omap2420_mcbsp2_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2420_mcbsp2_sdma_chs),
+ .main_clk = "mcbsp2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCBSP2_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
+ },
+ },
+ .slaves = omap2420_mcbsp2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2420_mcbsp2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
static __initdata struct omap_hwmod *omap2420_hwmods[] = {
&omap2420_l3_main_hwmod,
&omap2420_l4_core_hwmod,
&omap2420_l4_wkup_hwmod,
&omap2420_mpu_hwmod,
&omap2420_iva_hwmod,
+
+ &omap2420_timer1_hwmod,
+ &omap2420_timer2_hwmod,
+ &omap2420_timer3_hwmod,
+ &omap2420_timer4_hwmod,
+ &omap2420_timer5_hwmod,
+ &omap2420_timer6_hwmod,
+ &omap2420_timer7_hwmod,
+ &omap2420_timer8_hwmod,
+ &omap2420_timer9_hwmod,
+ &omap2420_timer10_hwmod,
+ &omap2420_timer11_hwmod,
+ &omap2420_timer12_hwmod,
+
&omap2420_wd_timer2_hwmod,
&omap2420_uart1_hwmod,
&omap2420_uart2_hwmod,
&omap2420_uart3_hwmod,
+ /* dss class */
+ &omap2420_dss_core_hwmod,
+ &omap2420_dss_dispc_hwmod,
+ &omap2420_dss_rfbi_hwmod,
+ &omap2420_dss_venc_hwmod,
+ /* i2c class */
&omap2420_i2c1_hwmod,
&omap2420_i2c2_hwmod,
@@ -885,10 +2178,21 @@ static __initdata struct omap_hwmod *omap2420_hwmods[] = {
/* dma_system class*/
&omap2420_dma_system_hwmod,
+
+ /* mailbox class */
+ &omap2420_mailbox_hwmod,
+
+ /* mcbsp class */
+ &omap2420_mcbsp1_hwmod,
+ &omap2420_mcbsp2_hwmod,
+
+ /* mcspi class */
+ &omap2420_mcspi1_hwmod,
+ &omap2420_mcspi2_hwmod,
NULL,
};
int __init omap2420_hwmod_init(void)
{
- return omap_hwmod_init(omap2420_hwmods);
+ return omap_hwmod_register(omap2420_hwmods);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 8ecfbcde13ba..0fdf2cabfb12 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -18,6 +18,11 @@
#include <plat/serial.h>
#include <plat/i2c.h>
#include <plat/gpio.h>
+#include <plat/mcbsp.h>
+#include <plat/mcspi.h>
+#include <plat/dmtimer.h>
+#include <plat/mmc.h>
+#include <plat/l3_2xxx.h>
#include "omap_hwmod_common_data.h"
@@ -38,6 +43,10 @@ static struct omap_hwmod omap2430_mpu_hwmod;
static struct omap_hwmod omap2430_iva_hwmod;
static struct omap_hwmod omap2430_l3_main_hwmod;
static struct omap_hwmod omap2430_l4_core_hwmod;
+static struct omap_hwmod omap2430_dss_core_hwmod;
+static struct omap_hwmod omap2430_dss_dispc_hwmod;
+static struct omap_hwmod omap2430_dss_rfbi_hwmod;
+static struct omap_hwmod omap2430_dss_venc_hwmod;
static struct omap_hwmod omap2430_wd_timer2_hwmod;
static struct omap_hwmod omap2430_gpio1_hwmod;
static struct omap_hwmod omap2430_gpio2_hwmod;
@@ -45,6 +54,16 @@ static struct omap_hwmod omap2430_gpio3_hwmod;
static struct omap_hwmod omap2430_gpio4_hwmod;
static struct omap_hwmod omap2430_gpio5_hwmod;
static struct omap_hwmod omap2430_dma_system_hwmod;
+static struct omap_hwmod omap2430_mcbsp1_hwmod;
+static struct omap_hwmod omap2430_mcbsp2_hwmod;
+static struct omap_hwmod omap2430_mcbsp3_hwmod;
+static struct omap_hwmod omap2430_mcbsp4_hwmod;
+static struct omap_hwmod omap2430_mcbsp5_hwmod;
+static struct omap_hwmod omap2430_mcspi1_hwmod;
+static struct omap_hwmod omap2430_mcspi2_hwmod;
+static struct omap_hwmod omap2430_mcspi3_hwmod;
+static struct omap_hwmod omap2430_mmc1_hwmod;
+static struct omap_hwmod omap2430_mmc2_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
@@ -65,6 +84,19 @@ static struct omap_hwmod_ocp_if *omap2430_l3_main_slaves[] = {
&omap2430_mpu__l3_main,
};
+/* DSS -> l3 */
+static struct omap_hwmod_ocp_if omap2430_dss__l3 = {
+ .master = &omap2430_dss_core_hwmod,
+ .slave = &omap2430_l3_main_hwmod,
+ .fw = {
+ .omap2 = {
+ .l3_perm_bit = OMAP2_L3_CORE_FW_CONNID_DSS,
+ .flags = OMAP_FIREWALL_L3,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Master interfaces on the L3 interconnect */
static struct omap_hwmod_ocp_if *omap2430_l3_main_masters[] = {
&omap2430_l3_main__l4_core,
@@ -89,6 +121,16 @@ static struct omap_hwmod omap2430_uart3_hwmod;
static struct omap_hwmod omap2430_i2c1_hwmod;
static struct omap_hwmod omap2430_i2c2_hwmod;
+static struct omap_hwmod omap2430_usbhsotg_hwmod;
+
+/* l3_core -> usbhsotg interface */
+static struct omap_hwmod_ocp_if omap2430_usbhsotg__l3 = {
+ .master = &omap2430_usbhsotg_hwmod,
+ .slave = &omap2430_l3_main_hwmod,
+ .clk = "core_l3_ck",
+ .user = OCP_USER_MPU,
+};
+
/* I2C IP block address space length (in bytes) */
#define OMAP2_I2C_AS_LEN 128
@@ -189,6 +231,71 @@ static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/*
+* usbhsotg interface data
+*/
+static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
+ {
+ .pa_start = OMAP243X_HS_BASE,
+ .pa_end = OMAP243X_HS_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core ->usbhsotg interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__usbhsotg = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_usbhsotg_hwmod,
+ .clk = "usb_l4_ick",
+ .addr = omap2430_usbhsotg_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_usbhsotg_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if *omap2430_usbhsotg_masters[] = {
+ &omap2430_usbhsotg__l3,
+};
+
+static struct omap_hwmod_ocp_if *omap2430_usbhsotg_slaves[] = {
+ &omap2430_l4_core__usbhsotg,
+};
+
+/* L4 CORE -> MMC1 interface */
+static struct omap_hwmod_addr_space omap2430_mmc1_addr_space[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c1ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc1 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mmc1_hwmod,
+ .clk = "mmchs1_ick",
+ .addr = omap2430_mmc1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_mmc1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> MMC2 interface */
+static struct omap_hwmod_addr_space omap2430_mmc2_addr_space[] = {
+ {
+ .pa_start = 0x480b4000,
+ .pa_end = 0x480b41ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc2 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mmc2_hwmod,
+ .addr = omap2430_mmc2_addr_space,
+ .clk = "mmchs2_ick",
+ .addr_cnt = ARRAY_SIZE(omap2430_mmc2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Slave interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
&omap2430_l3_main__l4_core,
@@ -197,6 +304,8 @@ static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
/* Master interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap2430_l4_core_masters[] = {
&omap2430_l4_core__l4_wkup,
+ &omap2430_l4_core__mmc1,
+ &omap2430_l4_core__mmc2,
};
/* L4 CORE */
@@ -223,6 +332,60 @@ static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
static struct omap_hwmod_ocp_if *omap2430_l4_wkup_masters[] = {
};
+/* l4 core -> mcspi1 interface */
+static struct omap_hwmod_addr_space omap2430_mcspi1_addr_space[] = {
+ {
+ .pa_start = 0x48098000,
+ .pa_end = 0x480980ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi1 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcspi1_hwmod,
+ .clk = "mcspi1_ick",
+ .addr = omap2430_mcspi1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcspi1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+static struct omap_hwmod_addr_space omap2430_mcspi2_addr_space[] = {
+ {
+ .pa_start = 0x4809a000,
+ .pa_end = 0x4809a0ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi2 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcspi2_hwmod,
+ .clk = "mcspi2_ick",
+ .addr = omap2430_mcspi2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcspi2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi3 interface */
+static struct omap_hwmod_addr_space omap2430_mcspi3_addr_space[] = {
+ {
+ .pa_start = 0x480b8000,
+ .pa_end = 0x480b80ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi3 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcspi3_hwmod,
+ .clk = "mcspi3_ick",
+ .addr = omap2430_mcspi3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcspi3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* L4 WKUP */
static struct omap_hwmod omap2430_l4_wkup_hwmod = {
.name = "l4_wkup",
@@ -278,6 +441,624 @@ static struct omap_hwmod omap2430_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
};
+/* Timer Common */
+static struct omap_hwmod_class_sysconfig omap2430_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_timer_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap2430_timer_sysc,
+ .rev = OMAP_TIMER_IP_VERSION_1,
+};
+
+/* timer1 */
+static struct omap_hwmod omap2430_timer1_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer1_mpu_irqs[] = {
+ { .irq = 37, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer1_addrs[] = {
+ {
+ .pa_start = 0x49018000,
+ .pa_end = 0x49018000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__timer1 = {
+ .master = &omap2430_l4_wkup_hwmod,
+ .slave = &omap2430_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap2430_timer1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer1 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer1_slaves[] = {
+ &omap2430_l4_wkup__timer1,
+};
+
+/* timer1 hwmod */
+static struct omap_hwmod omap2430_timer1_hwmod = {
+ .name = "timer1",
+ .mpu_irqs = omap2430_timer1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer1_mpu_irqs),
+ .main_clk = "gpt1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT1_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer1_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer2 */
+static struct omap_hwmod omap2430_timer2_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer2_mpu_irqs[] = {
+ { .irq = 38, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer2_addrs[] = {
+ {
+ .pa_start = 0x4802a000,
+ .pa_end = 0x4802a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer2 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer2 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer2_hwmod,
+ .clk = "gpt2_ick",
+ .addr = omap2430_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer2 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer2_slaves[] = {
+ &omap2430_l4_core__timer2,
+};
+
+/* timer2 hwmod */
+static struct omap_hwmod omap2430_timer2_hwmod = {
+ .name = "timer2",
+ .mpu_irqs = omap2430_timer2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer2_mpu_irqs),
+ .main_clk = "gpt2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT2_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer2_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer3 */
+static struct omap_hwmod omap2430_timer3_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer3_mpu_irqs[] = {
+ { .irq = 39, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer3_addrs[] = {
+ {
+ .pa_start = 0x48078000,
+ .pa_end = 0x48078000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer3 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer3 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer3_hwmod,
+ .clk = "gpt3_ick",
+ .addr = omap2430_timer3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer3 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer3_slaves[] = {
+ &omap2430_l4_core__timer3,
+};
+
+/* timer3 hwmod */
+static struct omap_hwmod omap2430_timer3_hwmod = {
+ .name = "timer3",
+ .mpu_irqs = omap2430_timer3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer3_mpu_irqs),
+ .main_clk = "gpt3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT3_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer3_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer4 */
+static struct omap_hwmod omap2430_timer4_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer4_mpu_irqs[] = {
+ { .irq = 40, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer4_addrs[] = {
+ {
+ .pa_start = 0x4807a000,
+ .pa_end = 0x4807a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer4 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer4 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer4_hwmod,
+ .clk = "gpt4_ick",
+ .addr = omap2430_timer4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer4 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer4_slaves[] = {
+ &omap2430_l4_core__timer4,
+};
+
+/* timer4 hwmod */
+static struct omap_hwmod omap2430_timer4_hwmod = {
+ .name = "timer4",
+ .mpu_irqs = omap2430_timer4_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer4_mpu_irqs),
+ .main_clk = "gpt4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT4_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer4_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer5 */
+static struct omap_hwmod omap2430_timer5_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer5_mpu_irqs[] = {
+ { .irq = 41, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer5_addrs[] = {
+ {
+ .pa_start = 0x4807c000,
+ .pa_end = 0x4807c000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer5 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer5 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer5_hwmod,
+ .clk = "gpt5_ick",
+ .addr = omap2430_timer5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer5 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer5_slaves[] = {
+ &omap2430_l4_core__timer5,
+};
+
+/* timer5 hwmod */
+static struct omap_hwmod omap2430_timer5_hwmod = {
+ .name = "timer5",
+ .mpu_irqs = omap2430_timer5_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer5_mpu_irqs),
+ .main_clk = "gpt5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT5_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer5_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer6 */
+static struct omap_hwmod omap2430_timer6_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer6_mpu_irqs[] = {
+ { .irq = 42, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer6_addrs[] = {
+ {
+ .pa_start = 0x4807e000,
+ .pa_end = 0x4807e000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer6 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer6 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer6_hwmod,
+ .clk = "gpt6_ick",
+ .addr = omap2430_timer6_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer6_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer6 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer6_slaves[] = {
+ &omap2430_l4_core__timer6,
+};
+
+/* timer6 hwmod */
+static struct omap_hwmod omap2430_timer6_hwmod = {
+ .name = "timer6",
+ .mpu_irqs = omap2430_timer6_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer6_mpu_irqs),
+ .main_clk = "gpt6_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT6_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer6_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer6_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer7 */
+static struct omap_hwmod omap2430_timer7_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer7_mpu_irqs[] = {
+ { .irq = 43, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer7_addrs[] = {
+ {
+ .pa_start = 0x48080000,
+ .pa_end = 0x48080000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer7 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer7 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer7_hwmod,
+ .clk = "gpt7_ick",
+ .addr = omap2430_timer7_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer7_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer7 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer7_slaves[] = {
+ &omap2430_l4_core__timer7,
+};
+
+/* timer7 hwmod */
+static struct omap_hwmod omap2430_timer7_hwmod = {
+ .name = "timer7",
+ .mpu_irqs = omap2430_timer7_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer7_mpu_irqs),
+ .main_clk = "gpt7_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT7_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer7_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer7_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer8 */
+static struct omap_hwmod omap2430_timer8_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer8_mpu_irqs[] = {
+ { .irq = 44, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer8_addrs[] = {
+ {
+ .pa_start = 0x48082000,
+ .pa_end = 0x48082000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer8 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer8 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer8_hwmod,
+ .clk = "gpt8_ick",
+ .addr = omap2430_timer8_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer8_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer8 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer8_slaves[] = {
+ &omap2430_l4_core__timer8,
+};
+
+/* timer8 hwmod */
+static struct omap_hwmod omap2430_timer8_hwmod = {
+ .name = "timer8",
+ .mpu_irqs = omap2430_timer8_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer8_mpu_irqs),
+ .main_clk = "gpt8_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT8_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer8_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer8_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer9 */
+static struct omap_hwmod omap2430_timer9_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer9_mpu_irqs[] = {
+ { .irq = 45, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer9_addrs[] = {
+ {
+ .pa_start = 0x48084000,
+ .pa_end = 0x48084000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer9 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer9 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer9_hwmod,
+ .clk = "gpt9_ick",
+ .addr = omap2430_timer9_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer9_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer9 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer9_slaves[] = {
+ &omap2430_l4_core__timer9,
+};
+
+/* timer9 hwmod */
+static struct omap_hwmod omap2430_timer9_hwmod = {
+ .name = "timer9",
+ .mpu_irqs = omap2430_timer9_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer9_mpu_irqs),
+ .main_clk = "gpt9_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT9_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer9_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer9_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer10 */
+static struct omap_hwmod omap2430_timer10_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer10_mpu_irqs[] = {
+ { .irq = 46, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer10_addrs[] = {
+ {
+ .pa_start = 0x48086000,
+ .pa_end = 0x48086000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer10 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer10 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer10_hwmod,
+ .clk = "gpt10_ick",
+ .addr = omap2430_timer10_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer10_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer10 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer10_slaves[] = {
+ &omap2430_l4_core__timer10,
+};
+
+/* timer10 hwmod */
+static struct omap_hwmod omap2430_timer10_hwmod = {
+ .name = "timer10",
+ .mpu_irqs = omap2430_timer10_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer10_mpu_irqs),
+ .main_clk = "gpt10_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT10_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer10_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer10_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer11 */
+static struct omap_hwmod omap2430_timer11_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer11_mpu_irqs[] = {
+ { .irq = 47, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer11_addrs[] = {
+ {
+ .pa_start = 0x48088000,
+ .pa_end = 0x48088000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer11 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer11 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer11_hwmod,
+ .clk = "gpt11_ick",
+ .addr = omap2430_timer11_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer11_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer11 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer11_slaves[] = {
+ &omap2430_l4_core__timer11,
+};
+
+/* timer11 hwmod */
+static struct omap_hwmod omap2430_timer11_hwmod = {
+ .name = "timer11",
+ .mpu_irqs = omap2430_timer11_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer11_mpu_irqs),
+ .main_clk = "gpt11_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT11_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer11_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer11_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/* timer12 */
+static struct omap_hwmod omap2430_timer12_hwmod;
+static struct omap_hwmod_irq_info omap2430_timer12_mpu_irqs[] = {
+ { .irq = 48, },
+};
+
+static struct omap_hwmod_addr_space omap2430_timer12_addrs[] = {
+ {
+ .pa_start = 0x4808a000,
+ .pa_end = 0x4808a000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer12 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__timer12 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_timer12_hwmod,
+ .clk = "gpt12_ick",
+ .addr = omap2430_timer12_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_timer12_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer12 slave port */
+static struct omap_hwmod_ocp_if *omap2430_timer12_slaves[] = {
+ &omap2430_l4_core__timer12,
+};
+
+/* timer12 hwmod */
+static struct omap_hwmod omap2430_timer12_hwmod = {
+ .name = "timer12",
+ .mpu_irqs = omap2430_timer12_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_timer12_mpu_irqs),
+ .main_clk = "gpt12_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT12_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
+ },
+ },
+ .slaves = omap2430_timer12_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_timer12_slaves),
+ .class = &omap2430_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
/* l4_wkup -> wd_timer2 */
static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
{
@@ -307,7 +1088,7 @@ static struct omap_hwmod_class_sysconfig omap2430_wd_timer_sysc = {
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -348,7 +1129,7 @@ static struct omap_hwmod_class_sysconfig uart_sysc = {
.syss_offs = 0x58,
.sysc_flags = (SYSC_HAS_SIDLEMODE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -469,12 +1250,274 @@ static struct omap_hwmod omap2430_uart3_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
};
+/*
+ * 'dss' class
+ * display sub-system
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_dss_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_dss_hwmod_class = {
+ .name = "dss",
+ .sysc = &omap2430_dss_sysc,
+};
+
+/* dss */
+static struct omap_hwmod_irq_info omap2430_dss_irqs[] = {
+ { .irq = 25 },
+};
+static struct omap_hwmod_dma_info omap2430_dss_sdma_chs[] = {
+ { .name = "dispc", .dma_req = 5 },
+};
+
+/* dss */
+/* dss master ports */
+static struct omap_hwmod_ocp_if *omap2430_dss_masters[] = {
+ &omap2430_dss__l3,
+};
+
+static struct omap_hwmod_addr_space omap2430_dss_addrs[] = {
+ {
+ .pa_start = 0x48050000,
+ .pa_end = 0x480503FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dss = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2430_dss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_dss_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss slave ports */
+static struct omap_hwmod_ocp_if *omap2430_dss_slaves[] = {
+ &omap2430_l4_core__dss,
+};
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+ { .role = "tv_clk", .clk = "dss_54m_fck" },
+ { .role = "sys_clk", .clk = "dss2_fck" },
+};
+
+static struct omap_hwmod omap2430_dss_core_hwmod = {
+ .name = "dss_core",
+ .class = &omap2430_dss_hwmod_class,
+ .main_clk = "dss1_fck", /* instead of dss_fck */
+ .mpu_irqs = omap2430_dss_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_dss_irqs),
+ .sdma_reqs = omap2430_dss_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_dss_sdma_chs),
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .slaves = omap2430_dss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_dss_slaves),
+ .masters = omap2430_dss_masters,
+ .masters_cnt = ARRAY_SIZE(omap2430_dss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_dispc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_dispc_hwmod_class = {
+ .name = "dispc",
+ .sysc = &omap2430_dispc_sysc,
+};
+
+static struct omap_hwmod_addr_space omap2430_dss_dispc_addrs[] = {
+ {
+ .pa_start = 0x48050400,
+ .pa_end = 0x480507FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_dispc */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dss_dispc = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_dss_dispc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2430_dss_dispc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_dss_dispc_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_dispc slave ports */
+static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = {
+ &omap2430_l4_core__dss_dispc,
+};
+
+static struct omap_hwmod omap2430_dss_dispc_hwmod = {
+ .name = "dss_dispc",
+ .class = &omap2430_dispc_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .slaves = omap2430_dss_dispc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_dss_dispc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'rfbi' class
+ * remote frame buffer interface
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_rfbi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_rfbi_hwmod_class = {
+ .name = "rfbi",
+ .sysc = &omap2430_rfbi_sysc,
+};
+
+static struct omap_hwmod_addr_space omap2430_dss_rfbi_addrs[] = {
+ {
+ .pa_start = 0x48050800,
+ .pa_end = 0x48050BFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dss_rfbi = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_dss_rfbi_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2430_dss_rfbi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_dss_rfbi_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_rfbi slave ports */
+static struct omap_hwmod_ocp_if *omap2430_dss_rfbi_slaves[] = {
+ &omap2430_l4_core__dss_rfbi,
+};
+
+static struct omap_hwmod omap2430_dss_rfbi_hwmod = {
+ .name = "dss_rfbi",
+ .class = &omap2430_rfbi_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .slaves = omap2430_dss_rfbi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_dss_rfbi_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'venc' class
+ * video encoder
+ */
+
+static struct omap_hwmod_class omap2430_venc_hwmod_class = {
+ .name = "venc",
+};
+
+/* dss_venc */
+static struct omap_hwmod_addr_space omap2430_dss_venc_addrs[] = {
+ {
+ .pa_start = 0x48050C00,
+ .pa_end = 0x48050FFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_venc */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dss_venc = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_dss_venc_hwmod,
+ .clk = "dss_54m_fck",
+ .addr = omap2430_dss_venc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_dss_venc_addrs),
+ .flags = OCPIF_SWSUP_IDLE,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_venc slave ports */
+static struct omap_hwmod_ocp_if *omap2430_dss_venc_slaves[] = {
+ &omap2430_l4_core__dss_venc,
+};
+
+static struct omap_hwmod omap2430_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap2430_venc_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .slaves = omap2430_dss_venc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_dss_venc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+ .flags = HWMOD_NO_IDLEST,
+};
+
/* I2C common */
static struct omap_hwmod_class_sysconfig i2c_sysc = {
.rev_offs = 0x00,
.sysc_offs = 0x20,
.syss_offs = 0x10,
- .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -672,7 +1715,8 @@ static struct omap_hwmod_class_sysconfig omap243x_gpio_sysc = {
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -844,7 +1888,7 @@ static struct omap_hwmod_class_sysconfig omap2430_dma_sysc = {
.syss_offs = 0x0028,
.sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_MIDLEMODE |
SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_EMUFREE |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -919,18 +1963,741 @@ static struct omap_hwmod omap2430_dma_system_hwmod = {
.flags = HWMOD_NO_IDLEST,
};
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors
+ * using a queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_mailbox_sysc = {
+ .rev_offs = 0x000,
+ .sysc_offs = 0x010,
+ .syss_offs = 0x014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_mailbox_hwmod_class = {
+ .name = "mailbox",
+ .sysc = &omap2430_mailbox_sysc,
+};
+
+/* mailbox */
+static struct omap_hwmod omap2430_mailbox_hwmod;
+static struct omap_hwmod_irq_info omap2430_mailbox_irqs[] = {
+ { .irq = 26 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mailbox_addrs[] = {
+ {
+ .pa_start = 0x48094000,
+ .pa_end = 0x480941ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mailbox = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mailbox_hwmod,
+ .addr = omap2430_mailbox_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mailbox_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mailbox slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mailbox_slaves[] = {
+ &omap2430_l4_core__mailbox,
+};
+
+static struct omap_hwmod omap2430_mailbox_hwmod = {
+ .name = "mailbox",
+ .class = &omap2430_mailbox_hwmod_class,
+ .mpu_irqs = omap2430_mailbox_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mailbox_irqs),
+ .main_clk = "mailboxes_ick",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MAILBOXES_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
+ },
+ },
+ .slaves = omap2430_mailbox_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mailbox_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_mcspi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_mcspi_class = {
+ .name = "mcspi",
+ .sysc = &omap2430_mcspi_sysc,
+ .rev = OMAP2_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap_hwmod_irq_info omap2430_mcspi1_mpu_irqs[] = {
+ { .irq = 65 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcspi1_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 35 }, /* DMA_SPI1_TX0 */
+ { .name = "rx0", .dma_req = 36 }, /* DMA_SPI1_RX0 */
+ { .name = "tx1", .dma_req = 37 }, /* DMA_SPI1_TX1 */
+ { .name = "rx1", .dma_req = 38 }, /* DMA_SPI1_RX1 */
+ { .name = "tx2", .dma_req = 39 }, /* DMA_SPI1_TX2 */
+ { .name = "rx2", .dma_req = 40 }, /* DMA_SPI1_RX2 */
+ { .name = "tx3", .dma_req = 41 }, /* DMA_SPI1_TX3 */
+ { .name = "rx3", .dma_req = 42 }, /* DMA_SPI1_RX3 */
+};
+
+static struct omap_hwmod_ocp_if *omap2430_mcspi1_slaves[] = {
+ &omap2430_l4_core__mcspi1,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+ .num_chipselect = 4,
+};
+
+static struct omap_hwmod omap2430_mcspi1_hwmod = {
+ .name = "mcspi1_hwmod",
+ .mpu_irqs = omap2430_mcspi1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcspi1_mpu_irqs),
+ .sdma_reqs = omap2430_mcspi1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcspi1_sdma_reqs),
+ .main_clk = "mcspi1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcspi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcspi1_slaves),
+ .class = &omap2430_mcspi_class,
+ .dev_attr = &omap_mcspi1_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcspi2 */
+static struct omap_hwmod_irq_info omap2430_mcspi2_mpu_irqs[] = {
+ { .irq = 66 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcspi2_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 43 }, /* DMA_SPI2_TX0 */
+ { .name = "rx0", .dma_req = 44 }, /* DMA_SPI2_RX0 */
+ { .name = "tx1", .dma_req = 45 }, /* DMA_SPI2_TX1 */
+ { .name = "rx1", .dma_req = 46 }, /* DMA_SPI2_RX1 */
+};
+
+static struct omap_hwmod_ocp_if *omap2430_mcspi2_slaves[] = {
+ &omap2430_l4_core__mcspi2,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap2430_mcspi2_hwmod = {
+ .name = "mcspi2_hwmod",
+ .mpu_irqs = omap2430_mcspi2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcspi2_mpu_irqs),
+ .sdma_reqs = omap2430_mcspi2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcspi2_sdma_reqs),
+ .main_clk = "mcspi2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcspi2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcspi2_slaves),
+ .class = &omap2430_mcspi_class,
+ .dev_attr = &omap_mcspi2_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcspi3 */
+static struct omap_hwmod_irq_info omap2430_mcspi3_mpu_irqs[] = {
+ { .irq = 91 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcspi3_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 15 }, /* DMA_SPI3_TX0 */
+ { .name = "rx0", .dma_req = 16 }, /* DMA_SPI3_RX0 */
+ { .name = "tx1", .dma_req = 23 }, /* DMA_SPI3_TX1 */
+ { .name = "rx1", .dma_req = 24 }, /* DMA_SPI3_RX1 */
+};
+
+static struct omap_hwmod_ocp_if *omap2430_mcspi3_slaves[] = {
+ &omap2430_l4_core__mcspi3,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap2430_mcspi3_hwmod = {
+ .name = "mcspi3_hwmod",
+ .mpu_irqs = omap2430_mcspi3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcspi3_mpu_irqs),
+ .sdma_reqs = omap2430_mcspi3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcspi3_sdma_reqs),
+ .main_clk = "mcspi3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP2430_EN_MCSPI3_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MCSPI3_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcspi3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcspi3_slaves),
+ .class = &omap2430_mcspi_class,
+ .dev_attr = &omap_mcspi3_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/*
+ * usbhsotg
+ */
+static struct omap_hwmod_class_sysconfig omap2430_usbhsotg_sysc = {
+ .rev_offs = 0x0400,
+ .sysc_offs = 0x0404,
+ .syss_offs = 0x0408,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE|
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class usbotg_class = {
+ .name = "usbotg",
+ .sysc = &omap2430_usbhsotg_sysc,
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info omap2430_usbhsotg_mpu_irqs[] = {
+
+ { .name = "mc", .irq = 92 },
+ { .name = "dma", .irq = 93 },
+};
+
+static struct omap_hwmod omap2430_usbhsotg_hwmod = {
+ .name = "usb_otg_hs",
+ .mpu_irqs = omap2430_usbhsotg_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_usbhsotg_mpu_irqs),
+ .main_clk = "usbhs_ick",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2430_EN_USBHS_MASK,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP2430_ST_USBHS_SHIFT,
+ },
+ },
+ .masters = omap2430_usbhsotg_masters,
+ .masters_cnt = ARRAY_SIZE(omap2430_usbhsotg_masters),
+ .slaves = omap2430_usbhsotg_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_usbhsotg_slaves),
+ .class = &usbotg_class,
+ /*
+ * Erratum ID: i479 idle_req / idle_ack mechanism potentially
+ * broken when autoidle is enabled
+ * workaround is to disable the autoidle bit at module level.
+ */
+ .flags = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
+ | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+};
+
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_mcbsp_sysc = {
+ .rev_offs = 0x007C,
+ .sysc_offs = 0x008C,
+ .sysc_flags = (SYSC_HAS_SOFTRESET),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_mcbsp_hwmod_class = {
+ .name = "mcbsp",
+ .sysc = &omap2430_mcbsp_sysc,
+ .rev = MCBSP_CONFIG_TYPE2,
+};
+
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap2430_mcbsp1_irqs[] = {
+ { .name = "tx", .irq = 59 },
+ { .name = "rx", .irq = 60 },
+ { .name = "ovr", .irq = 61 },
+ { .name = "common", .irq = 64 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcbsp1_sdma_chs[] = {
+ { .name = "rx", .dma_req = 32 },
+ { .name = "tx", .dma_req = 31 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48074000,
+ .pa_end = 0x480740ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp1 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcbsp1_hwmod,
+ .clk = "mcbsp1_ick",
+ .addr = omap2430_mcbsp1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcbsp1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp1 slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mcbsp1_slaves[] = {
+ &omap2430_l4_core__mcbsp1,
+};
+
+static struct omap_hwmod omap2430_mcbsp1_hwmod = {
+ .name = "mcbsp1",
+ .class = &omap2430_mcbsp_hwmod_class,
+ .mpu_irqs = omap2430_mcbsp1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcbsp1_irqs),
+ .sdma_reqs = omap2430_mcbsp1_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcbsp1_sdma_chs),
+ .main_clk = "mcbsp1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCBSP1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcbsp1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap2430_mcbsp2_irqs[] = {
+ { .name = "tx", .irq = 62 },
+ { .name = "rx", .irq = 63 },
+ { .name = "common", .irq = 16 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcbsp2_sdma_chs[] = {
+ { .name = "rx", .dma_req = 34 },
+ { .name = "tx", .dma_req = 33 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48076000,
+ .pa_end = 0x480760ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp2 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcbsp2_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap2430_mcbsp2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcbsp2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp2 slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mcbsp2_slaves[] = {
+ &omap2430_l4_core__mcbsp2,
+};
+
+static struct omap_hwmod omap2430_mcbsp2_hwmod = {
+ .name = "mcbsp2",
+ .class = &omap2430_mcbsp_hwmod_class,
+ .mpu_irqs = omap2430_mcbsp2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcbsp2_irqs),
+ .sdma_reqs = omap2430_mcbsp2_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcbsp2_sdma_chs),
+ .main_clk = "mcbsp2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCBSP2_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcbsp2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcbsp3 */
+static struct omap_hwmod_irq_info omap2430_mcbsp3_irqs[] = {
+ { .name = "tx", .irq = 89 },
+ { .name = "rx", .irq = 90 },
+ { .name = "common", .irq = 17 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcbsp3_sdma_chs[] = {
+ { .name = "rx", .dma_req = 18 },
+ { .name = "tx", .dma_req = 17 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x4808C000,
+ .pa_end = 0x4808C0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp3 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcbsp3_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap2430_mcbsp3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcbsp3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp3 slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mcbsp3_slaves[] = {
+ &omap2430_l4_core__mcbsp3,
+};
+
+static struct omap_hwmod omap2430_mcbsp3_hwmod = {
+ .name = "mcbsp3",
+ .class = &omap2430_mcbsp_hwmod_class,
+ .mpu_irqs = omap2430_mcbsp3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcbsp3_irqs),
+ .sdma_reqs = omap2430_mcbsp3_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcbsp3_sdma_chs),
+ .main_clk = "mcbsp3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2430_EN_MCBSP3_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MCBSP3_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcbsp3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcbsp4 */
+static struct omap_hwmod_irq_info omap2430_mcbsp4_irqs[] = {
+ { .name = "tx", .irq = 54 },
+ { .name = "rx", .irq = 55 },
+ { .name = "common", .irq = 18 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcbsp4_sdma_chs[] = {
+ { .name = "rx", .dma_req = 20 },
+ { .name = "tx", .dma_req = 19 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp4_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x4808E000,
+ .pa_end = 0x4808E0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp4 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcbsp4_hwmod,
+ .clk = "mcbsp4_ick",
+ .addr = omap2430_mcbsp4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcbsp4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp4 slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mcbsp4_slaves[] = {
+ &omap2430_l4_core__mcbsp4,
+};
+
+static struct omap_hwmod omap2430_mcbsp4_hwmod = {
+ .name = "mcbsp4",
+ .class = &omap2430_mcbsp_hwmod_class,
+ .mpu_irqs = omap2430_mcbsp4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcbsp4_irqs),
+ .sdma_reqs = omap2430_mcbsp4_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcbsp4_sdma_chs),
+ .main_clk = "mcbsp4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2430_EN_MCBSP4_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MCBSP4_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcbsp4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* mcbsp5 */
+static struct omap_hwmod_irq_info omap2430_mcbsp5_irqs[] = {
+ { .name = "tx", .irq = 81 },
+ { .name = "rx", .irq = 82 },
+ { .name = "common", .irq = 19 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mcbsp5_sdma_chs[] = {
+ { .name = "rx", .dma_req = 22 },
+ { .name = "tx", .dma_req = 21 },
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp5_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp5 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = {
+ .master = &omap2430_l4_core_hwmod,
+ .slave = &omap2430_mcbsp5_hwmod,
+ .clk = "mcbsp5_ick",
+ .addr = omap2430_mcbsp5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap2430_mcbsp5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp5 slave ports */
+static struct omap_hwmod_ocp_if *omap2430_mcbsp5_slaves[] = {
+ &omap2430_l4_core__mcbsp5,
+};
+
+static struct omap_hwmod omap2430_mcbsp5_hwmod = {
+ .name = "mcbsp5",
+ .class = &omap2430_mcbsp_hwmod_class,
+ .mpu_irqs = omap2430_mcbsp5_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mcbsp5_irqs),
+ .sdma_reqs = omap2430_mcbsp5_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mcbsp5_sdma_chs),
+ .main_clk = "mcbsp5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2430_EN_MCBSP5_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MCBSP5_SHIFT,
+ },
+ },
+ .slaves = omap2430_mcbsp5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp5_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* MMC/SD/SDIO common */
+
+static struct omap_hwmod_class_sysconfig omap2430_mmc_sysc = {
+ .rev_offs = 0x1fc,
+ .sysc_offs = 0x10,
+ .syss_offs = 0x14,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_mmc_class = {
+ .name = "mmc",
+ .sysc = &omap2430_mmc_sysc,
+};
+
+/* MMC/SD/SDIO1 */
+
+static struct omap_hwmod_irq_info omap2430_mmc1_mpu_irqs[] = {
+ { .irq = 83 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mmc1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 61 }, /* DMA_MMC1_TX */
+ { .name = "rx", .dma_req = 62 }, /* DMA_MMC1_RX */
+};
+
+static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = {
+ { .role = "dbck", .clk = "mmchsdb1_fck" },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_mmc1_slaves[] = {
+ &omap2430_l4_core__mmc1,
+};
+
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+ .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod omap2430_mmc1_hwmod = {
+ .name = "mmc1",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2430_mmc1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mmc1_mpu_irqs),
+ .sdma_reqs = omap2430_mmc1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mmc1_sdma_reqs),
+ .opt_clks = omap2430_mmc1_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(omap2430_mmc1_opt_clks),
+ .main_clk = "mmchs1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP2430_EN_MMCHS1_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MMCHS1_SHIFT,
+ },
+ },
+ .dev_attr = &mmc1_dev_attr,
+ .slaves = omap2430_mmc1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mmc1_slaves),
+ .class = &omap2430_mmc_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* MMC/SD/SDIO2 */
+
+static struct omap_hwmod_irq_info omap2430_mmc2_mpu_irqs[] = {
+ { .irq = 86 },
+};
+
+static struct omap_hwmod_dma_info omap2430_mmc2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 47 }, /* DMA_MMC2_TX */
+ { .name = "rx", .dma_req = 48 }, /* DMA_MMC2_RX */
+};
+
+static struct omap_hwmod_opt_clk omap2430_mmc2_opt_clks[] = {
+ { .role = "dbck", .clk = "mmchsdb2_fck" },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_mmc2_slaves[] = {
+ &omap2430_l4_core__mmc2,
+};
+
+static struct omap_hwmod omap2430_mmc2_hwmod = {
+ .name = "mmc2",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2430_mmc2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap2430_mmc2_mpu_irqs),
+ .sdma_reqs = omap2430_mmc2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap2430_mmc2_sdma_reqs),
+ .opt_clks = omap2430_mmc2_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(omap2430_mmc2_opt_clks),
+ .main_clk = "mmchs2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP2430_EN_MMCHS2_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP2430_ST_MMCHS2_SHIFT,
+ },
+ },
+ .slaves = omap2430_mmc2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap2430_mmc2_slaves),
+ .class = &omap2430_mmc_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
static __initdata struct omap_hwmod *omap2430_hwmods[] = {
&omap2430_l3_main_hwmod,
&omap2430_l4_core_hwmod,
&omap2430_l4_wkup_hwmod,
&omap2430_mpu_hwmod,
&omap2430_iva_hwmod,
+
+ &omap2430_timer1_hwmod,
+ &omap2430_timer2_hwmod,
+ &omap2430_timer3_hwmod,
+ &omap2430_timer4_hwmod,
+ &omap2430_timer5_hwmod,
+ &omap2430_timer6_hwmod,
+ &omap2430_timer7_hwmod,
+ &omap2430_timer8_hwmod,
+ &omap2430_timer9_hwmod,
+ &omap2430_timer10_hwmod,
+ &omap2430_timer11_hwmod,
+ &omap2430_timer12_hwmod,
+
&omap2430_wd_timer2_hwmod,
&omap2430_uart1_hwmod,
&omap2430_uart2_hwmod,
&omap2430_uart3_hwmod,
+ /* dss class */
+ &omap2430_dss_core_hwmod,
+ &omap2430_dss_dispc_hwmod,
+ &omap2430_dss_rfbi_hwmod,
+ &omap2430_dss_venc_hwmod,
+ /* i2c class */
&omap2430_i2c1_hwmod,
&omap2430_i2c2_hwmod,
+ &omap2430_mmc1_hwmod,
+ &omap2430_mmc2_hwmod,
/* gpio class */
&omap2430_gpio1_hwmod,
@@ -941,10 +2708,29 @@ static __initdata struct omap_hwmod *omap2430_hwmods[] = {
/* dma_system class*/
&omap2430_dma_system_hwmod,
+
+ /* mcbsp class */
+ &omap2430_mcbsp1_hwmod,
+ &omap2430_mcbsp2_hwmod,
+ &omap2430_mcbsp3_hwmod,
+ &omap2430_mcbsp4_hwmod,
+ &omap2430_mcbsp5_hwmod,
+
+ /* mailbox class */
+ &omap2430_mailbox_hwmod,
+
+ /* mcspi class */
+ &omap2430_mcspi1_hwmod,
+ &omap2430_mcspi2_hwmod,
+ &omap2430_mcspi3_hwmod,
+
+ /* usbotg class*/
+ &omap2430_usbhsotg_hwmod,
+
NULL,
};
int __init omap2430_hwmod_init(void)
{
- return omap_hwmod_init(omap2430_hwmods);
+ return omap_hwmod_register(omap2430_hwmods);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 8d8181334f86..c819c306693a 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -18,16 +18,21 @@
#include <plat/cpu.h>
#include <plat/dma.h>
#include <plat/serial.h>
+#include <plat/l3_3xxx.h>
#include <plat/l4_3xxx.h>
#include <plat/i2c.h>
#include <plat/gpio.h>
-#include <plat/smartreflex.h>
+#include <plat/mmc.h>
+#include <plat/mcbsp.h>
+#include <plat/mcspi.h>
+#include <plat/dmtimer.h>
#include "omap_hwmod_common_data.h"
#include "prm-regbits-34xx.h"
#include "cm-regbits-34xx.h"
#include "wd_timer.h"
+#include <mach/am35xx.h>
/*
* OMAP3xxx hardware module integration data
@@ -44,6 +49,12 @@ static struct omap_hwmod omap3xxx_l3_main_hwmod;
static struct omap_hwmod omap3xxx_l4_core_hwmod;
static struct omap_hwmod omap3xxx_l4_per_hwmod;
static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
+static struct omap_hwmod omap3430es1_dss_core_hwmod;
+static struct omap_hwmod omap3xxx_dss_core_hwmod;
+static struct omap_hwmod omap3xxx_dss_dispc_hwmod;
+static struct omap_hwmod omap3xxx_dss_dsi1_hwmod;
+static struct omap_hwmod omap3xxx_dss_rfbi_hwmod;
+static struct omap_hwmod omap3xxx_dss_venc_hwmod;
static struct omap_hwmod omap3xxx_i2c1_hwmod;
static struct omap_hwmod omap3xxx_i2c2_hwmod;
static struct omap_hwmod omap3xxx_i2c3_hwmod;
@@ -55,9 +66,25 @@ static struct omap_hwmod omap3xxx_gpio5_hwmod;
static struct omap_hwmod omap3xxx_gpio6_hwmod;
static struct omap_hwmod omap34xx_sr1_hwmod;
static struct omap_hwmod omap34xx_sr2_hwmod;
+static struct omap_hwmod omap34xx_mcspi1;
+static struct omap_hwmod omap34xx_mcspi2;
+static struct omap_hwmod omap34xx_mcspi3;
+static struct omap_hwmod omap34xx_mcspi4;
+static struct omap_hwmod omap3xxx_mmc1_hwmod;
+static struct omap_hwmod omap3xxx_mmc2_hwmod;
+static struct omap_hwmod omap3xxx_mmc3_hwmod;
+static struct omap_hwmod am35xx_usbhsotg_hwmod;
static struct omap_hwmod omap3xxx_dma_system_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp1_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp2_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp3_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp4_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp5_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod;
+static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod;
+
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
.master = &omap3xxx_l3_main_hwmod,
@@ -72,10 +99,26 @@ static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_per = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L3 taret configuration and error log registers */
+static struct omap_hwmod_irq_info omap3xxx_l3_main_irqs[] = {
+ { .irq = INT_34XX_L3_DBG_IRQ },
+ { .irq = INT_34XX_L3_APP_IRQ },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_l3_main_addrs[] = {
+ {
+ .pa_start = 0x68000000,
+ .pa_end = 0x6800ffff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
/* MPU -> L3 interface */
static struct omap_hwmod_ocp_if omap3xxx_mpu__l3_main = {
- .master = &omap3xxx_mpu_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
+ .master = &omap3xxx_mpu_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .addr = omap3xxx_l3_main_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_l3_main_addrs),
.user = OCP_USER_MPU,
};
@@ -84,6 +127,19 @@ static struct omap_hwmod_ocp_if *omap3xxx_l3_main_slaves[] = {
&omap3xxx_mpu__l3_main,
};
+/* DSS -> l3 */
+static struct omap_hwmod_ocp_if omap3xxx_dss__l3 = {
+ .master = &omap3xxx_dss_core_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .fw = {
+ .omap2 = {
+ .l3_perm_bit = OMAP3_L3_CORE_FW_INIT_ID_DSS,
+ .flags = OMAP_FIREWALL_L3,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* Master interfaces on the L3 interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = {
&omap3xxx_l3_main__l4_core,
@@ -94,6 +150,8 @@ static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = {
static struct omap_hwmod omap3xxx_l3_main_hwmod = {
.name = "l3_main",
.class = &l3_hwmod_class,
+ .mpu_irqs = omap3xxx_l3_main_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_l3_main_irqs),
.masters = omap3xxx_l3_main_masters,
.masters_cnt = ARRAY_SIZE(omap3xxx_l3_main_masters),
.slaves = omap3xxx_l3_main_slaves,
@@ -107,7 +165,23 @@ static struct omap_hwmod omap3xxx_uart1_hwmod;
static struct omap_hwmod omap3xxx_uart2_hwmod;
static struct omap_hwmod omap3xxx_uart3_hwmod;
static struct omap_hwmod omap3xxx_uart4_hwmod;
+static struct omap_hwmod omap3xxx_usbhsotg_hwmod;
+/* l3_core -> usbhsotg interface */
+static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
+ .master = &omap3xxx_usbhsotg_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
+
+/* l3_core -> am35xx_usbhsotg interface */
+static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
+ .master = &am35xx_usbhsotg_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
/* L4_CORE -> L4_WKUP interface */
static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
.master = &omap3xxx_l4_core_hwmod,
@@ -115,6 +189,63 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* L4 CORE -> MMC1 interface */
+static struct omap_hwmod_addr_space omap3xxx_mmc1_addr_space[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c1ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mmc1_hwmod,
+ .clk = "mmchs1_ick",
+ .addr = omap3xxx_mmc1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mmc1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+/* L4 CORE -> MMC2 interface */
+static struct omap_hwmod_addr_space omap3xxx_mmc2_addr_space[] = {
+ {
+ .pa_start = 0x480b4000,
+ .pa_end = 0x480b41ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mmc2_hwmod,
+ .clk = "mmchs2_ick",
+ .addr = omap3xxx_mmc2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mmc2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+/* L4 CORE -> MMC3 interface */
+static struct omap_hwmod_addr_space omap3xxx_mmc3_addr_space[] = {
+ {
+ .pa_start = 0x480ad000,
+ .pa_end = 0x480ad1ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc3 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mmc3_hwmod,
+ .clk = "mmchs3_ick",
+ .addr = omap3xxx_mmc3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mmc3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
/* L4 CORE -> UART1 interface */
static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
{
@@ -301,29 +432,70 @@ static struct omap_hwmod_ocp_if omap3_l4_core__sr2 = {
.user = OCP_USER_MPU,
};
+/*
+* usbhsotg interface data
+*/
+
+static struct omap_hwmod_addr_space omap3xxx_usbhsotg_addrs[] = {
+ {
+ .pa_start = OMAP34XX_HSUSB_OTG_BASE,
+ .pa_end = OMAP34XX_HSUSB_OTG_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> usbhsotg */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__usbhsotg = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_usbhsotg_hwmod,
+ .clk = "l4_ick",
+ .addr = omap3xxx_usbhsotg_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_masters[] = {
+ &omap3xxx_usbhsotg__l3,
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_slaves[] = {
+ &omap3xxx_l4_core__usbhsotg,
+};
+
+static struct omap_hwmod_addr_space am35xx_usbhsotg_addrs[] = {
+ {
+ .pa_start = AM35XX_IPSS_USBOTGSS_BASE,
+ .pa_end = AM35XX_IPSS_USBOTGSS_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> usbhsotg */
+static struct omap_hwmod_ocp_if am35xx_l4_core__usbhsotg = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &am35xx_usbhsotg_hwmod,
+ .clk = "l4_ick",
+ .addr = am35xx_usbhsotg_addrs,
+ .addr_cnt = ARRAY_SIZE(am35xx_usbhsotg_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if *am35xx_usbhsotg_masters[] = {
+ &am35xx_usbhsotg__l3,
+};
+
+static struct omap_hwmod_ocp_if *am35xx_usbhsotg_slaves[] = {
+ &am35xx_l4_core__usbhsotg,
+};
/* Slave interfaces on the L4_CORE interconnect */
static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
&omap3xxx_l3_main__l4_core,
- &omap3_l4_core__sr1,
- &omap3_l4_core__sr2,
-};
-
-/* Master interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
- &omap3xxx_l4_core__l4_wkup,
- &omap3_l4_core__uart1,
- &omap3_l4_core__uart2,
- &omap3_l4_core__i2c1,
- &omap3_l4_core__i2c2,
- &omap3_l4_core__i2c3,
};
/* L4 CORE */
static struct omap_hwmod omap3xxx_l4_core_hwmod = {
.name = "l4_core",
.class = &l4_hwmod_class,
- .masters = omap3xxx_l4_core_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_l4_core_masters),
.slaves = omap3xxx_l4_core_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_l4_core_slaves),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -335,18 +507,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_per_slaves[] = {
&omap3xxx_l3_main__l4_per,
};
-/* Master interfaces on the L4_PER interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
- &omap3_l4_per__uart3,
- &omap3_l4_per__uart4,
-};
-
/* L4 PER */
static struct omap_hwmod omap3xxx_l4_per_hwmod = {
.name = "l4_per",
.class = &l4_hwmod_class,
- .masters = omap3xxx_l4_per_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_l4_per_masters),
.slaves = omap3xxx_l4_per_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_l4_per_slaves),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -358,16 +522,10 @@ static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
&omap3xxx_l4_core__l4_wkup,
};
-/* Master interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_masters[] = {
-};
-
/* L4 WKUP */
static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
.name = "l4_wkup",
.class = &l4_hwmod_class,
- .masters = omap3xxx_l4_wkup_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_l4_wkup_masters),
.slaves = omap3xxx_l4_wkup_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_l4_wkup_slaves),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
@@ -417,6 +575,640 @@ static struct omap_hwmod omap3xxx_iva_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
};
+/* timer class */
+static struct omap_hwmod_class_sysconfig omap3xxx_timer_1ms_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_timer_1ms_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap3xxx_timer_1ms_sysc,
+ .rev = OMAP_TIMER_IP_VERSION_1,
+};
+
+static struct omap_hwmod_class_sysconfig omap3xxx_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap3xxx_timer_sysc,
+ .rev = OMAP_TIMER_IP_VERSION_1,
+};
+
+/* timer1 */
+static struct omap_hwmod omap3xxx_timer1_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer1_mpu_irqs[] = {
+ { .irq = 37, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer1_addrs[] = {
+ {
+ .pa_start = 0x48318000,
+ .pa_end = 0x48318000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__timer1 = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap3xxx_timer1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer1 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer1_slaves[] = {
+ &omap3xxx_l4_wkup__timer1,
+};
+
+/* timer1 hwmod */
+static struct omap_hwmod omap3xxx_timer1_hwmod = {
+ .name = "timer1",
+ .mpu_irqs = omap3xxx_timer1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer1_mpu_irqs),
+ .main_clk = "gpt1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT1_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT1_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer1_slaves),
+ .class = &omap3xxx_timer_1ms_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer2 */
+static struct omap_hwmod omap3xxx_timer2_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer2_mpu_irqs[] = {
+ { .irq = 38, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer2_addrs[] = {
+ {
+ .pa_start = 0x49032000,
+ .pa_end = 0x49032000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer2 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer2 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer2_hwmod,
+ .clk = "gpt2_ick",
+ .addr = omap3xxx_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer2 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer2_slaves[] = {
+ &omap3xxx_l4_per__timer2,
+};
+
+/* timer2 hwmod */
+static struct omap_hwmod omap3xxx_timer2_hwmod = {
+ .name = "timer2",
+ .mpu_irqs = omap3xxx_timer2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer2_mpu_irqs),
+ .main_clk = "gpt2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT2_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer2_slaves),
+ .class = &omap3xxx_timer_1ms_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer3 */
+static struct omap_hwmod omap3xxx_timer3_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer3_mpu_irqs[] = {
+ { .irq = 39, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer3_addrs[] = {
+ {
+ .pa_start = 0x49034000,
+ .pa_end = 0x49034000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer3 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer3_hwmod,
+ .clk = "gpt3_ick",
+ .addr = omap3xxx_timer3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer3 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer3_slaves[] = {
+ &omap3xxx_l4_per__timer3,
+};
+
+/* timer3 hwmod */
+static struct omap_hwmod omap3xxx_timer3_hwmod = {
+ .name = "timer3",
+ .mpu_irqs = omap3xxx_timer3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer3_mpu_irqs),
+ .main_clk = "gpt3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT3_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT3_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer3_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer4 */
+static struct omap_hwmod omap3xxx_timer4_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer4_mpu_irqs[] = {
+ { .irq = 40, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer4_addrs[] = {
+ {
+ .pa_start = 0x49036000,
+ .pa_end = 0x49036000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer4 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer4_hwmod,
+ .clk = "gpt4_ick",
+ .addr = omap3xxx_timer4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer4 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer4_slaves[] = {
+ &omap3xxx_l4_per__timer4,
+};
+
+/* timer4 hwmod */
+static struct omap_hwmod omap3xxx_timer4_hwmod = {
+ .name = "timer4",
+ .mpu_irqs = omap3xxx_timer4_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer4_mpu_irqs),
+ .main_clk = "gpt4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT4_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT4_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer4_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer5 */
+static struct omap_hwmod omap3xxx_timer5_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer5_mpu_irqs[] = {
+ { .irq = 41, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer5_addrs[] = {
+ {
+ .pa_start = 0x49038000,
+ .pa_end = 0x49038000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer5 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer5 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer5_hwmod,
+ .clk = "gpt5_ick",
+ .addr = omap3xxx_timer5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer5 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer5_slaves[] = {
+ &omap3xxx_l4_per__timer5,
+};
+
+/* timer5 hwmod */
+static struct omap_hwmod omap3xxx_timer5_hwmod = {
+ .name = "timer5",
+ .mpu_irqs = omap3xxx_timer5_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer5_mpu_irqs),
+ .main_clk = "gpt5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT5_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT5_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer5_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer6 */
+static struct omap_hwmod omap3xxx_timer6_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer6_mpu_irqs[] = {
+ { .irq = 42, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer6_addrs[] = {
+ {
+ .pa_start = 0x4903A000,
+ .pa_end = 0x4903A000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer6 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer6 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer6_hwmod,
+ .clk = "gpt6_ick",
+ .addr = omap3xxx_timer6_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer6_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer6 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer6_slaves[] = {
+ &omap3xxx_l4_per__timer6,
+};
+
+/* timer6 hwmod */
+static struct omap_hwmod omap3xxx_timer6_hwmod = {
+ .name = "timer6",
+ .mpu_irqs = omap3xxx_timer6_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer6_mpu_irqs),
+ .main_clk = "gpt6_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT6_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT6_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer6_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer6_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer7 */
+static struct omap_hwmod omap3xxx_timer7_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer7_mpu_irqs[] = {
+ { .irq = 43, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer7_addrs[] = {
+ {
+ .pa_start = 0x4903C000,
+ .pa_end = 0x4903C000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer7 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer7 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer7_hwmod,
+ .clk = "gpt7_ick",
+ .addr = omap3xxx_timer7_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer7_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer7 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer7_slaves[] = {
+ &omap3xxx_l4_per__timer7,
+};
+
+/* timer7 hwmod */
+static struct omap_hwmod omap3xxx_timer7_hwmod = {
+ .name = "timer7",
+ .mpu_irqs = omap3xxx_timer7_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer7_mpu_irqs),
+ .main_clk = "gpt7_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT7_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT7_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer7_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer7_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer8 */
+static struct omap_hwmod omap3xxx_timer8_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer8_mpu_irqs[] = {
+ { .irq = 44, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer8_addrs[] = {
+ {
+ .pa_start = 0x4903E000,
+ .pa_end = 0x4903E000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer8 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer8 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer8_hwmod,
+ .clk = "gpt8_ick",
+ .addr = omap3xxx_timer8_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer8_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer8 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer8_slaves[] = {
+ &omap3xxx_l4_per__timer8,
+};
+
+/* timer8 hwmod */
+static struct omap_hwmod omap3xxx_timer8_hwmod = {
+ .name = "timer8",
+ .mpu_irqs = omap3xxx_timer8_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer8_mpu_irqs),
+ .main_clk = "gpt8_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT8_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT8_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer8_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer8_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer9 */
+static struct omap_hwmod omap3xxx_timer9_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer9_mpu_irqs[] = {
+ { .irq = 45, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer9_addrs[] = {
+ {
+ .pa_start = 0x49040000,
+ .pa_end = 0x49040000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer9 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer9 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer9_hwmod,
+ .clk = "gpt9_ick",
+ .addr = omap3xxx_timer9_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer9_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer9 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer9_slaves[] = {
+ &omap3xxx_l4_per__timer9,
+};
+
+/* timer9 hwmod */
+static struct omap_hwmod omap3xxx_timer9_hwmod = {
+ .name = "timer9",
+ .mpu_irqs = omap3xxx_timer9_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer9_mpu_irqs),
+ .main_clk = "gpt9_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT9_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT9_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer9_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer9_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer10 */
+static struct omap_hwmod omap3xxx_timer10_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer10_mpu_irqs[] = {
+ { .irq = 46, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer10_addrs[] = {
+ {
+ .pa_start = 0x48086000,
+ .pa_end = 0x48086000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer10 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer10 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_timer10_hwmod,
+ .clk = "gpt10_ick",
+ .addr = omap3xxx_timer10_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer10_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer10 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer10_slaves[] = {
+ &omap3xxx_l4_core__timer10,
+};
+
+/* timer10 hwmod */
+static struct omap_hwmod omap3xxx_timer10_hwmod = {
+ .name = "timer10",
+ .mpu_irqs = omap3xxx_timer10_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer10_mpu_irqs),
+ .main_clk = "gpt10_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT10_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT10_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer10_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer10_slaves),
+ .class = &omap3xxx_timer_1ms_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer11 */
+static struct omap_hwmod omap3xxx_timer11_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer11_mpu_irqs[] = {
+ { .irq = 47, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer11_addrs[] = {
+ {
+ .pa_start = 0x48088000,
+ .pa_end = 0x48088000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer11 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer11 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_timer11_hwmod,
+ .clk = "gpt11_ick",
+ .addr = omap3xxx_timer11_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer11_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer11 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer11_slaves[] = {
+ &omap3xxx_l4_core__timer11,
+};
+
+/* timer11 hwmod */
+static struct omap_hwmod omap3xxx_timer11_hwmod = {
+ .name = "timer11",
+ .mpu_irqs = omap3xxx_timer11_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer11_mpu_irqs),
+ .main_clk = "gpt11_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT11_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT11_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer11_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer11_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* timer12*/
+static struct omap_hwmod omap3xxx_timer12_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_timer12_mpu_irqs[] = {
+ { .irq = 95, },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer12_addrs[] = {
+ {
+ .pa_start = 0x48304000,
+ .pa_end = 0x48304000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> timer12 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer12 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_timer12_hwmod,
+ .clk = "gpt12_ick",
+ .addr = omap3xxx_timer12_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_timer12_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer12 slave port */
+static struct omap_hwmod_ocp_if *omap3xxx_timer12_slaves[] = {
+ &omap3xxx_l4_core__timer12,
+};
+
+/* timer12 hwmod */
+static struct omap_hwmod omap3xxx_timer12_hwmod = {
+ .name = "timer12",
+ .mpu_irqs = omap3xxx_timer12_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_timer12_mpu_irqs),
+ .main_clk = "gpt12_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_GPT12_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_GPT12_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_timer12_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_timer12_slaves),
+ .class = &omap3xxx_timer_hwmod_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
/* l4_wkup -> wd_timer2 */
static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
{
@@ -447,7 +1239,8 @@ static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY),
+ SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -459,7 +1252,7 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {
.syss_offs = 0x10,
.sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -491,6 +1284,11 @@ static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
.slaves = omap3xxx_wd_timer2_slaves,
.slaves_cnt = ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+ /*
+ * XXX: Use software supervised mode, HW supervised smartidle seems to
+ * block CORE power domain idle transitions. Maybe a HW bug in wdt2?
+ */
+ .flags = HWMOD_SWSUP_SIDLE,
};
/* UART common */
@@ -501,7 +1299,7 @@ static struct omap_hwmod_class_sysconfig uart_sysc = {
.syss_offs = 0x58,
.sysc_flags = (SYSC_HAS_SIDLEMODE |
SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -664,6 +1462,411 @@ static struct omap_hwmod_class i2c_class = {
.sysc = &i2c_sysc,
};
+/*
+ * 'dss' class
+ * display sub-system
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_dss_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_dss_hwmod_class = {
+ .name = "dss",
+ .sysc = &omap3xxx_dss_sysc,
+};
+
+/* dss */
+static struct omap_hwmod_irq_info omap3xxx_dss_irqs[] = {
+ { .irq = 25 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
+ { .name = "dispc", .dma_req = 5 },
+ { .name = "dsi1", .dma_req = 74 },
+};
+
+/* dss */
+/* dss master ports */
+static struct omap_hwmod_ocp_if *omap3xxx_dss_masters[] = {
+ &omap3xxx_dss__l3,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_dss_addrs[] = {
+ {
+ .pa_start = 0x48050000,
+ .pa_end = 0x480503FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss */
+static struct omap_hwmod_ocp_if omap3430es1_l4_core__dss = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3430es1_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap3xxx_dss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3ES1_L4_CORE_FW_DSS_CORE_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap3xxx_dss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_CORE_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss slave ports */
+static struct omap_hwmod_ocp_if *omap3430es1_dss_slaves[] = {
+ &omap3430es1_l4_core__dss,
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = {
+ &omap3xxx_l4_core__dss,
+};
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+ { .role = "tv_clk", .clk = "dss_tv_fck" },
+ { .role = "dssclk", .clk = "dss_96m_fck" },
+ { .role = "sys_clk", .clk = "dss2_alwon_fck" },
+};
+
+static struct omap_hwmod omap3430es1_dss_core_hwmod = {
+ .name = "dss_core",
+ .class = &omap3xxx_dss_hwmod_class,
+ .main_clk = "dss1_alwon_fck", /* instead of dss_fck */
+ .mpu_irqs = omap3xxx_dss_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_dss_irqs),
+ .sdma_reqs = omap3xxx_dss_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_dss_sdma_chs),
+
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP3430ES1_ST_DSS_SHIFT,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .slaves = omap3430es1_dss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3430es1_dss_slaves),
+ .masters = omap3xxx_dss_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_dss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+static struct omap_hwmod omap3xxx_dss_core_hwmod = {
+ .name = "dss_core",
+ .class = &omap3xxx_dss_hwmod_class,
+ .main_clk = "dss1_alwon_fck", /* instead of dss_fck */
+ .mpu_irqs = omap3xxx_dss_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_dss_irqs),
+ .sdma_reqs = omap3xxx_dss_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_dss_sdma_chs),
+
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+ .idlest_stdby_bit = OMAP3430ES2_ST_DSS_STDBY_SHIFT,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .slaves = omap3xxx_dss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_slaves),
+ .masters = omap3xxx_dss_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_dss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2 |
+ CHIP_IS_OMAP3630ES1 | CHIP_GE_OMAP3630ES1_1),
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_dispc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_MIDLEMODE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_dispc_hwmod_class = {
+ .name = "dispc",
+ .sysc = &omap3xxx_dispc_sysc,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_dss_dispc_addrs[] = {
+ {
+ .pa_start = 0x48050400,
+ .pa_end = 0x480507FF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_dispc */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dispc = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_dispc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap3xxx_dss_dispc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_dispc_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DISPC_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_dispc slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = {
+ &omap3xxx_l4_core__dss_dispc,
+};
+
+static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
+ .name = "dss_dispc",
+ .class = &omap3xxx_dispc_hwmod_class,
+ .main_clk = "dss1_alwon_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ },
+ },
+ .slaves = omap3xxx_dss_dispc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dispc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
+ CHIP_GE_OMAP3430ES2 | CHIP_IS_OMAP3630ES1 |
+ CHIP_GE_OMAP3630ES1_1),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'dsi' class
+ * display serial interface controller
+ */
+
+static struct omap_hwmod_class omap3xxx_dsi_hwmod_class = {
+ .name = "dsi",
+};
+
+/* dss_dsi1 */
+static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
+ {
+ .pa_start = 0x4804FC00,
+ .pa_end = 0x4804FFFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dsi1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_dsi1_hwmod,
+ .addr = omap3xxx_dss_dsi1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_dsi1_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DSI_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_dsi1 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = {
+ &omap3xxx_l4_core__dss_dsi1,
+};
+
+static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
+ .name = "dss_dsi1",
+ .class = &omap3xxx_dsi_hwmod_class,
+ .main_clk = "dss1_alwon_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ },
+ },
+ .slaves = omap3xxx_dss_dsi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dsi1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
+ CHIP_GE_OMAP3430ES2 | CHIP_IS_OMAP3630ES1 |
+ CHIP_GE_OMAP3630ES1_1),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'rfbi' class
+ * remote frame buffer interface
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_rfbi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_rfbi_hwmod_class = {
+ .name = "rfbi",
+ .sysc = &omap3xxx_rfbi_sysc,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_dss_rfbi_addrs[] = {
+ {
+ .pa_start = 0x48050800,
+ .pa_end = 0x48050BFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_rfbi = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_rfbi_hwmod,
+ .clk = "dss_ick",
+ .addr = omap3xxx_dss_rfbi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_rfbi_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_RFBI_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP ,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_rfbi slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_dss_rfbi_slaves[] = {
+ &omap3xxx_l4_core__dss_rfbi,
+};
+
+static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = {
+ .name = "dss_rfbi",
+ .class = &omap3xxx_rfbi_hwmod_class,
+ .main_clk = "dss1_alwon_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ },
+ },
+ .slaves = omap3xxx_dss_rfbi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_rfbi_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
+ CHIP_GE_OMAP3430ES2 | CHIP_IS_OMAP3630ES1 |
+ CHIP_GE_OMAP3630ES1_1),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/*
+ * 'venc' class
+ * video encoder
+ */
+
+static struct omap_hwmod_class omap3xxx_venc_hwmod_class = {
+ .name = "venc",
+};
+
+/* dss_venc */
+static struct omap_hwmod_addr_space omap3xxx_dss_venc_addrs[] = {
+ {
+ .pa_start = 0x48050C00,
+ .pa_end = 0x48050FFF,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> dss_venc */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_venc = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_venc_hwmod,
+ .clk = "dss_tv_fck",
+ .addr = omap3xxx_dss_venc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_dss_venc_addrs),
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_VENC_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .flags = OCPIF_SWSUP_IDLE,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss_venc slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_dss_venc_slaves[] = {
+ &omap3xxx_l4_core__dss_venc,
+};
+
+static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap3xxx_venc_hwmod_class,
+ .main_clk = "dss1_alwon_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_DSS1_SHIFT,
+ .module_offs = OMAP3430_DSS_MOD,
+ },
+ },
+ .slaves = omap3xxx_dss_venc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_venc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
+ CHIP_GE_OMAP3430ES2 | CHIP_IS_OMAP3630ES1 |
+ CHIP_GE_OMAP3630ES1_1),
+ .flags = HWMOD_NO_IDLEST,
+};
+
/* I2C1 */
static struct omap_i2c_dev_attr i2c1_dev_attr = {
@@ -902,7 +2105,8 @@ static struct omap_hwmod_class_sysconfig omap3xxx_gpio_sysc = {
.sysc_offs = 0x0010,
.syss_offs = 0x0014,
.sysc_flags = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
};
@@ -1156,7 +2360,8 @@ static struct omap_hwmod_class_sysconfig omap3xxx_dma_sysc = {
.syss_offs = 0x0028,
.sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
SYSC_HAS_MIDLEMODE | SYSC_HAS_CLOCKACTIVITY |
- SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE),
+ SYSC_HAS_EMUFREE | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
.sysc_fields = &omap_hwmod_sysc_type1,
@@ -1227,6 +2432,437 @@ static struct omap_hwmod omap3xxx_dma_system_hwmod = {
.flags = HWMOD_NO_IDLEST,
};
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sysc = {
+ .sysc_offs = 0x008c,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+ .clockact = 0x2,
+};
+
+static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = {
+ .name = "mcbsp",
+ .sysc = &omap3xxx_mcbsp_sysc,
+ .rev = MCBSP_CONFIG_TYPE3,
+};
+
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp1_irqs[] = {
+ { .name = "irq", .irq = 16 },
+ { .name = "tx", .irq = 59 },
+ { .name = "rx", .irq = 60 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp1_sdma_chs[] = {
+ { .name = "rx", .dma_req = 32 },
+ { .name = "tx", .dma_req = 31 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48074000,
+ .pa_end = 0x480740ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mcbsp1_hwmod,
+ .clk = "mcbsp1_ick",
+ .addr = omap3xxx_mcbsp1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp1 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp1_slaves[] = {
+ &omap3xxx_l4_core__mcbsp1,
+};
+
+static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
+ .name = "mcbsp1",
+ .class = &omap3xxx_mcbsp_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp1_irqs),
+ .sdma_reqs = omap3xxx_mcbsp1_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp1_sdma_chs),
+ .main_clk = "mcbsp1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP1_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp2_irqs[] = {
+ { .name = "irq", .irq = 17 },
+ { .name = "tx", .irq = 62 },
+ { .name = "rx", .irq = 63 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp2_sdma_chs[] = {
+ { .name = "rx", .dma_req = 34 },
+ { .name = "tx", .dma_req = 33 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49022000,
+ .pa_end = 0x490220ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp2_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap3xxx_mcbsp2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp2 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_slaves[] = {
+ &omap3xxx_l4_per__mcbsp2,
+};
+
+static struct omap_mcbsp_dev_attr omap34xx_mcbsp2_dev_attr = {
+ .sidetone = "mcbsp2_sidetone",
+};
+
+static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
+ .name = "mcbsp2",
+ .class = &omap3xxx_mcbsp_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_irqs),
+ .sdma_reqs = omap3xxx_mcbsp2_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_sdma_chs),
+ .main_clk = "mcbsp2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP2_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_slaves),
+ .dev_attr = &omap34xx_mcbsp2_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcbsp3 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp3_irqs[] = {
+ { .name = "irq", .irq = 22 },
+ { .name = "tx", .irq = 89 },
+ { .name = "rx", .irq = 90 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp3_sdma_chs[] = {
+ { .name = "rx", .dma_req = 18 },
+ { .name = "tx", .dma_req = 17 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49024000,
+ .pa_end = 0x490240ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp3_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap3xxx_mcbsp3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp3 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_slaves[] = {
+ &omap3xxx_l4_per__mcbsp3,
+};
+
+static struct omap_mcbsp_dev_attr omap34xx_mcbsp3_dev_attr = {
+ .sidetone = "mcbsp3_sidetone",
+};
+
+static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
+ .name = "mcbsp3",
+ .class = &omap3xxx_mcbsp_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_irqs),
+ .sdma_reqs = omap3xxx_mcbsp3_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_sdma_chs),
+ .main_clk = "mcbsp3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP3_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_slaves),
+ .dev_attr = &omap34xx_mcbsp3_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcbsp4 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp4_irqs[] = {
+ { .name = "irq", .irq = 23 },
+ { .name = "tx", .irq = 54 },
+ { .name = "rx", .irq = 55 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp4_sdma_chs[] = {
+ { .name = "rx", .dma_req = 20 },
+ { .name = "tx", .dma_req = 19 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp4_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49026000,
+ .pa_end = 0x490260ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp4_hwmod,
+ .clk = "mcbsp4_ick",
+ .addr = omap3xxx_mcbsp4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp4 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp4_slaves[] = {
+ &omap3xxx_l4_per__mcbsp4,
+};
+
+static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
+ .name = "mcbsp4",
+ .class = &omap3xxx_mcbsp_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp4_irqs),
+ .sdma_reqs = omap3xxx_mcbsp4_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp4_sdma_chs),
+ .main_clk = "mcbsp4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP4_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP4_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcbsp5 */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp5_irqs[] = {
+ { .name = "irq", .irq = 27 },
+ { .name = "tx", .irq = 81 },
+ { .name = "rx", .irq = 82 },
+};
+
+static struct omap_hwmod_dma_info omap3xxx_mcbsp5_sdma_chs[] = {
+ { .name = "rx", .dma_req = 22 },
+ { .name = "tx", .dma_req = 21 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp5_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_core -> mcbsp5 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp5 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mcbsp5_hwmod,
+ .clk = "mcbsp5_ick",
+ .addr = omap3xxx_mcbsp5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp5 slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp5_slaves[] = {
+ &omap3xxx_l4_core__mcbsp5,
+};
+
+static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
+ .name = "mcbsp5",
+ .class = &omap3xxx_mcbsp_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp5_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp5_irqs),
+ .sdma_reqs = omap3xxx_mcbsp5_sdma_chs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp5_sdma_chs),
+ .main_clk = "mcbsp5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP5_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP5_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp5_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+/* 'mcbsp sidetone' class */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sidetone_sysc = {
+ .sysc_offs = 0x0010,
+ .sysc_flags = SYSC_HAS_AUTOIDLE,
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_mcbsp_sidetone_hwmod_class = {
+ .name = "mcbsp_sidetone",
+ .sysc = &omap3xxx_mcbsp_sidetone_sysc,
+};
+
+/* mcbsp2_sidetone */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp2_sidetone_irqs[] = {
+ { .name = "irq", .irq = 4 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp2_sidetone_addrs[] = {
+ {
+ .name = "sidetone",
+ .pa_start = 0x49028000,
+ .pa_end = 0x490280ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp2_sidetone */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2_sidetone = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp2_sidetone_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap3xxx_mcbsp2_sidetone_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_sidetone_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* mcbsp2_sidetone slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_sidetone_slaves[] = {
+ &omap3xxx_l4_per__mcbsp2_sidetone,
+};
+
+static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
+ .name = "mcbsp2_sidetone",
+ .class = &omap3xxx_mcbsp_sidetone_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp2_sidetone_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_sidetone_irqs),
+ .main_clk = "mcbsp2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP2_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp2_sidetone_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_sidetone_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcbsp3_sidetone */
+static struct omap_hwmod_irq_info omap3xxx_mcbsp3_sidetone_irqs[] = {
+ { .name = "irq", .irq = 5 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp3_sidetone_addrs[] = {
+ {
+ .name = "sidetone",
+ .pa_start = 0x4902A000,
+ .pa_end = 0x4902A0ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp3_sidetone */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3_sidetone = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp3_sidetone_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap3xxx_mcbsp3_sidetone_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_sidetone_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* mcbsp3_sidetone slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_sidetone_slaves[] = {
+ &omap3xxx_l4_per__mcbsp3_sidetone,
+};
+
+static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
+ .name = "mcbsp3_sidetone",
+ .class = &omap3xxx_mcbsp_sidetone_hwmod_class,
+ .mpu_irqs = omap3xxx_mcbsp3_sidetone_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_sidetone_irqs),
+ .main_clk = "mcbsp3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCBSP3_SHIFT,
+ .module_offs = OMAP3430_PER_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mcbsp3_sidetone_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_sidetone_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+
/* SR common */
static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = {
.clkact_shift = 20,
@@ -1356,18 +2992,617 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
};
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors
+ * using a queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_mailbox_sysc = {
+ .rev_offs = 0x000,
+ .sysc_offs = 0x010,
+ .syss_offs = 0x014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = {
+ .name = "mailbox",
+ .sysc = &omap3xxx_mailbox_sysc,
+};
+
+static struct omap_hwmod omap3xxx_mailbox_hwmod;
+static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = {
+ { .irq = 26 },
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mailbox_addrs[] = {
+ {
+ .pa_start = 0x48094000,
+ .pa_end = 0x480941ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mailbox = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mailbox_hwmod,
+ .addr = omap3xxx_mailbox_addrs,
+ .addr_cnt = ARRAY_SIZE(omap3xxx_mailbox_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mailbox slave ports */
+static struct omap_hwmod_ocp_if *omap3xxx_mailbox_slaves[] = {
+ &omap3xxx_l4_core__mailbox,
+};
+
+static struct omap_hwmod omap3xxx_mailbox_hwmod = {
+ .name = "mailbox",
+ .class = &omap3xxx_mailbox_hwmod_class,
+ .mpu_irqs = omap3xxx_mailbox_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_mailbox_irqs),
+ .main_clk = "mailboxes_ick",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MAILBOXES_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mailbox_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mailbox_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* l4 core -> mcspi1 interface */
+static struct omap_hwmod_addr_space omap34xx_mcspi1_addr_space[] = {
+ {
+ .pa_start = 0x48098000,
+ .pa_end = 0x480980ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi1,
+ .clk = "mcspi1_ick",
+ .addr = omap34xx_mcspi1_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap34xx_mcspi1_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+static struct omap_hwmod_addr_space omap34xx_mcspi2_addr_space[] = {
+ {
+ .pa_start = 0x4809a000,
+ .pa_end = 0x4809a0ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi2,
+ .clk = "mcspi2_ick",
+ .addr = omap34xx_mcspi2_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap34xx_mcspi2_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi3 interface */
+static struct omap_hwmod_addr_space omap34xx_mcspi3_addr_space[] = {
+ {
+ .pa_start = 0x480b8000,
+ .pa_end = 0x480b80ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi3 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi3,
+ .clk = "mcspi3_ick",
+ .addr = omap34xx_mcspi3_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap34xx_mcspi3_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi4 interface */
+static struct omap_hwmod_addr_space omap34xx_mcspi4_addr_space[] = {
+ {
+ .pa_start = 0x480ba000,
+ .pa_end = 0x480ba0ff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi4 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi4,
+ .clk = "mcspi4_ick",
+ .addr = omap34xx_mcspi4_addr_space,
+ .addr_cnt = ARRAY_SIZE(omap34xx_mcspi4_addr_space),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap34xx_mcspi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_mcspi_class = {
+ .name = "mcspi",
+ .sysc = &omap34xx_mcspi_sysc,
+ .rev = OMAP3_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap_hwmod_irq_info omap34xx_mcspi1_mpu_irqs[] = {
+ { .name = "irq", .irq = 65 },
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi1_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 35 },
+ { .name = "rx0", .dma_req = 36 },
+ { .name = "tx1", .dma_req = 37 },
+ { .name = "rx1", .dma_req = 38 },
+ { .name = "tx2", .dma_req = 39 },
+ { .name = "rx2", .dma_req = 40 },
+ { .name = "tx3", .dma_req = 41 },
+ { .name = "rx3", .dma_req = 42 },
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_mcspi1_slaves[] = {
+ &omap34xx_l4_core__mcspi1,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+ .num_chipselect = 4,
+};
+
+static struct omap_hwmod omap34xx_mcspi1 = {
+ .name = "mcspi1",
+ .mpu_irqs = omap34xx_mcspi1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mcspi1_mpu_irqs),
+ .sdma_reqs = omap34xx_mcspi1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mcspi1_sdma_reqs),
+ .main_clk = "mcspi1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCSPI1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCSPI1_SHIFT,
+ },
+ },
+ .slaves = omap34xx_mcspi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi1_slaves),
+ .class = &omap34xx_mcspi_class,
+ .dev_attr = &omap_mcspi1_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcspi2 */
+static struct omap_hwmod_irq_info omap34xx_mcspi2_mpu_irqs[] = {
+ { .name = "irq", .irq = 66 },
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi2_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 43 },
+ { .name = "rx0", .dma_req = 44 },
+ { .name = "tx1", .dma_req = 45 },
+ { .name = "rx1", .dma_req = 46 },
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_mcspi2_slaves[] = {
+ &omap34xx_l4_core__mcspi2,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap34xx_mcspi2 = {
+ .name = "mcspi2",
+ .mpu_irqs = omap34xx_mcspi2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mcspi2_mpu_irqs),
+ .sdma_reqs = omap34xx_mcspi2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mcspi2_sdma_reqs),
+ .main_clk = "mcspi2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCSPI2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCSPI2_SHIFT,
+ },
+ },
+ .slaves = omap34xx_mcspi2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi2_slaves),
+ .class = &omap34xx_mcspi_class,
+ .dev_attr = &omap_mcspi2_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* mcspi3 */
+static struct omap_hwmod_irq_info omap34xx_mcspi3_mpu_irqs[] = {
+ { .name = "irq", .irq = 91 }, /* 91 */
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi3_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 15 },
+ { .name = "rx0", .dma_req = 16 },
+ { .name = "tx1", .dma_req = 23 },
+ { .name = "rx1", .dma_req = 24 },
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_mcspi3_slaves[] = {
+ &omap34xx_l4_core__mcspi3,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap34xx_mcspi3 = {
+ .name = "mcspi3",
+ .mpu_irqs = omap34xx_mcspi3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mcspi3_mpu_irqs),
+ .sdma_reqs = omap34xx_mcspi3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mcspi3_sdma_reqs),
+ .main_clk = "mcspi3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCSPI3_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCSPI3_SHIFT,
+ },
+ },
+ .slaves = omap34xx_mcspi3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi3_slaves),
+ .class = &omap34xx_mcspi_class,
+ .dev_attr = &omap_mcspi3_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* SPI4 */
+static struct omap_hwmod_irq_info omap34xx_mcspi4_mpu_irqs[] = {
+ { .name = "irq", .irq = INT_34XX_SPI4_IRQ }, /* 48 */
+};
+
+static struct omap_hwmod_dma_info omap34xx_mcspi4_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 70 }, /* DMA_SPI4_TX0 */
+ { .name = "rx0", .dma_req = 71 }, /* DMA_SPI4_RX0 */
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_mcspi4_slaves[] = {
+ &omap34xx_l4_core__mcspi4,
+};
+
+static struct omap2_mcspi_dev_attr omap_mcspi4_dev_attr = {
+ .num_chipselect = 1,
+};
+
+static struct omap_hwmod omap34xx_mcspi4 = {
+ .name = "mcspi4",
+ .mpu_irqs = omap34xx_mcspi4_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mcspi4_mpu_irqs),
+ .sdma_reqs = omap34xx_mcspi4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mcspi4_sdma_reqs),
+ .main_clk = "mcspi4_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MCSPI4_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MCSPI4_SHIFT,
+ },
+ },
+ .slaves = omap34xx_mcspi4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi4_slaves),
+ .class = &omap34xx_mcspi_class,
+ .dev_attr = &omap_mcspi4_dev_attr,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/*
+ * usbhsotg
+ */
+static struct omap_hwmod_class_sysconfig omap3xxx_usbhsotg_sysc = {
+ .rev_offs = 0x0400,
+ .sysc_offs = 0x0404,
+ .syss_offs = 0x0408,
+ .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_MIDLEMODE|
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class usbotg_class = {
+ .name = "usbotg",
+ .sysc = &omap3xxx_usbhsotg_sysc,
+};
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info omap3xxx_usbhsotg_mpu_irqs[] = {
+
+ { .name = "mc", .irq = 92 },
+ { .name = "dma", .irq = 93 },
+};
+
+static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
+ .name = "usb_otg_hs",
+ .mpu_irqs = omap3xxx_usbhsotg_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_mpu_irqs),
+ .main_clk = "hsotgusb_ick",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_HSOTGUSB_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
+ .idlest_stdby_bit = OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT
+ },
+ },
+ .masters = omap3xxx_usbhsotg_masters,
+ .masters_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_masters),
+ .slaves = omap3xxx_usbhsotg_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_slaves),
+ .class = &usbotg_class,
+
+ /*
+ * Erratum ID: i479 idle_req / idle_ack mechanism potentially
+ * broken when autoidle is enabled
+ * workaround is to disable the autoidle bit at module level.
+ */
+ .flags = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
+ | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info am35xx_usbhsotg_mpu_irqs[] = {
+
+ { .name = "mc", .irq = 71 },
+};
+
+static struct omap_hwmod_class am35xx_usbotg_class = {
+ .name = "am35xx_usbotg",
+ .sysc = NULL,
+};
+
+static struct omap_hwmod am35xx_usbhsotg_hwmod = {
+ .name = "am35x_otg_hs",
+ .mpu_irqs = am35xx_usbhsotg_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(am35xx_usbhsotg_mpu_irqs),
+ .main_clk = NULL,
+ .prcm = {
+ .omap2 = {
+ },
+ },
+ .masters = am35xx_usbhsotg_masters,
+ .masters_cnt = ARRAY_SIZE(am35xx_usbhsotg_masters),
+ .slaves = am35xx_usbhsotg_slaves,
+ .slaves_cnt = ARRAY_SIZE(am35xx_usbhsotg_slaves),
+ .class = &am35xx_usbotg_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES3_1)
+};
+
+/* MMC/SD/SDIO common */
+
+static struct omap_hwmod_class_sysconfig omap34xx_mmc_sysc = {
+ .rev_offs = 0x1fc,
+ .sysc_offs = 0x10,
+ .syss_offs = 0x14,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_mmc_class = {
+ .name = "mmc",
+ .sysc = &omap34xx_mmc_sysc,
+};
+
+/* MMC/SD/SDIO1 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc1_mpu_irqs[] = {
+ { .irq = 83, },
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 61, },
+ { .name = "rx", .dma_req = 62, },
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
+ { .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_mmc1_slaves[] = {
+ &omap3xxx_l4_core__mmc1,
+};
+
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+ .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod omap3xxx_mmc1_hwmod = {
+ .name = "mmc1",
+ .mpu_irqs = omap34xx_mmc1_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mmc1_mpu_irqs),
+ .sdma_reqs = omap34xx_mmc1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mmc1_sdma_reqs),
+ .opt_clks = omap34xx_mmc1_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(omap34xx_mmc1_opt_clks),
+ .main_clk = "mmchs1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MMC1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MMC1_SHIFT,
+ },
+ },
+ .dev_attr = &mmc1_dev_attr,
+ .slaves = omap3xxx_mmc1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc1_slaves),
+ .class = &omap34xx_mmc_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* MMC/SD/SDIO2 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc2_mpu_irqs[] = {
+ { .irq = INT_24XX_MMC2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 47, },
+ { .name = "rx", .dma_req = 48, },
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
+ { .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_mmc2_slaves[] = {
+ &omap3xxx_l4_core__mmc2,
+};
+
+static struct omap_hwmod omap3xxx_mmc2_hwmod = {
+ .name = "mmc2",
+ .mpu_irqs = omap34xx_mmc2_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mmc2_mpu_irqs),
+ .sdma_reqs = omap34xx_mmc2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mmc2_sdma_reqs),
+ .opt_clks = omap34xx_mmc2_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(omap34xx_mmc2_opt_clks),
+ .main_clk = "mmchs2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MMC2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mmc2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc2_slaves),
+ .class = &omap34xx_mmc_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* MMC/SD/SDIO3 */
+
+static struct omap_hwmod_irq_info omap34xx_mmc3_mpu_irqs[] = {
+ { .irq = 94, },
+};
+
+static struct omap_hwmod_dma_info omap34xx_mmc3_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 77, },
+ { .name = "rx", .dma_req = 78, },
+};
+
+static struct omap_hwmod_opt_clk omap34xx_mmc3_opt_clks[] = {
+ { .role = "dbck", .clk = "omap_32k_fck", },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_mmc3_slaves[] = {
+ &omap3xxx_l4_core__mmc3,
+};
+
+static struct omap_hwmod omap3xxx_mmc3_hwmod = {
+ .name = "mmc3",
+ .mpu_irqs = omap34xx_mmc3_mpu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_mmc3_mpu_irqs),
+ .sdma_reqs = omap34xx_mmc3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap34xx_mmc3_sdma_reqs),
+ .opt_clks = omap34xx_mmc3_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(omap34xx_mmc3_opt_clks),
+ .main_clk = "mmchs3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_MMC3_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_MMC3_SHIFT,
+ },
+ },
+ .slaves = omap3xxx_mmc3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc3_slaves),
+ .class = &omap34xx_mmc_class,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
&omap3xxx_l3_main_hwmod,
&omap3xxx_l4_core_hwmod,
&omap3xxx_l4_per_hwmod,
&omap3xxx_l4_wkup_hwmod,
+ &omap3xxx_mmc1_hwmod,
+ &omap3xxx_mmc2_hwmod,
+ &omap3xxx_mmc3_hwmod,
&omap3xxx_mpu_hwmod,
&omap3xxx_iva_hwmod,
+
+ &omap3xxx_timer1_hwmod,
+ &omap3xxx_timer2_hwmod,
+ &omap3xxx_timer3_hwmod,
+ &omap3xxx_timer4_hwmod,
+ &omap3xxx_timer5_hwmod,
+ &omap3xxx_timer6_hwmod,
+ &omap3xxx_timer7_hwmod,
+ &omap3xxx_timer8_hwmod,
+ &omap3xxx_timer9_hwmod,
+ &omap3xxx_timer10_hwmod,
+ &omap3xxx_timer11_hwmod,
+ &omap3xxx_timer12_hwmod,
+
&omap3xxx_wd_timer2_hwmod,
&omap3xxx_uart1_hwmod,
&omap3xxx_uart2_hwmod,
&omap3xxx_uart3_hwmod,
&omap3xxx_uart4_hwmod,
+ /* dss class */
+ &omap3430es1_dss_core_hwmod,
+ &omap3xxx_dss_core_hwmod,
+ &omap3xxx_dss_dispc_hwmod,
+ &omap3xxx_dss_dsi1_hwmod,
+ &omap3xxx_dss_rfbi_hwmod,
+ &omap3xxx_dss_venc_hwmod,
+
+ /* i2c class */
&omap3xxx_i2c1_hwmod,
&omap3xxx_i2c2_hwmod,
&omap3xxx_i2c3_hwmod,
@@ -1387,10 +3622,35 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
/* dma_system class*/
&omap3xxx_dma_system_hwmod,
+
+ /* mcbsp class */
+ &omap3xxx_mcbsp1_hwmod,
+ &omap3xxx_mcbsp2_hwmod,
+ &omap3xxx_mcbsp3_hwmod,
+ &omap3xxx_mcbsp4_hwmod,
+ &omap3xxx_mcbsp5_hwmod,
+ &omap3xxx_mcbsp2_sidetone_hwmod,
+ &omap3xxx_mcbsp3_sidetone_hwmod,
+
+ /* mailbox class */
+ &omap3xxx_mailbox_hwmod,
+
+ /* mcspi class */
+ &omap34xx_mcspi1,
+ &omap34xx_mcspi2,
+ &omap34xx_mcspi3,
+ &omap34xx_mcspi4,
+
+ /* usbotg class */
+ &omap3xxx_usbhsotg_hwmod,
+
+ /* usbotg for am35x */
+ &am35xx_usbhsotg_hwmod,
+
NULL,
};
int __init omap3xxx_hwmod_init(void)
{
- return omap_hwmod_init(omap3xxx_hwmods);
+ return omap_hwmod_register(omap3xxx_hwmods);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index c2806bd11fbf..3e88dd3f8ef3 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -1,7 +1,7 @@
/*
* Hardware modules present on the OMAP44xx chips
*
- * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2011 Texas Instruments, Inc.
* Copyright (C) 2009-2010 Nokia Corporation
*
* Paul Walmsley
@@ -24,6 +24,9 @@
#include <plat/cpu.h>
#include <plat/gpio.h>
#include <plat/dma.h>
+#include <plat/mcspi.h>
+#include <plat/mcbsp.h>
+#include <plat/mmc.h>
#include "omap_hwmod_common_data.h"
@@ -40,10 +43,15 @@
#define OMAP44XX_DMA_REQ_START 1
/* Backward references (IPs with Bus Master capability) */
+static struct omap_hwmod omap44xx_aess_hwmod;
static struct omap_hwmod omap44xx_dma_system_hwmod;
static struct omap_hwmod omap44xx_dmm_hwmod;
static struct omap_hwmod omap44xx_dsp_hwmod;
+static struct omap_hwmod omap44xx_dss_hwmod;
static struct omap_hwmod omap44xx_emif_fw_hwmod;
+static struct omap_hwmod omap44xx_hsi_hwmod;
+static struct omap_hwmod omap44xx_ipu_hwmod;
+static struct omap_hwmod omap44xx_iss_hwmod;
static struct omap_hwmod omap44xx_iva_hwmod;
static struct omap_hwmod omap44xx_l3_instr_hwmod;
static struct omap_hwmod omap44xx_l3_main_1_hwmod;
@@ -53,8 +61,11 @@ static struct omap_hwmod omap44xx_l4_abe_hwmod;
static struct omap_hwmod omap44xx_l4_cfg_hwmod;
static struct omap_hwmod omap44xx_l4_per_hwmod;
static struct omap_hwmod omap44xx_l4_wkup_hwmod;
+static struct omap_hwmod omap44xx_mmc1_hwmod;
+static struct omap_hwmod omap44xx_mmc2_hwmod;
static struct omap_hwmod omap44xx_mpu_hwmod;
static struct omap_hwmod omap44xx_mpu_private_hwmod;
+static struct omap_hwmod omap44xx_usb_otg_hs_hwmod;
/*
* Interconnects omap_hwmod structures
@@ -213,6 +224,14 @@ static struct omap_hwmod_ocp_if omap44xx_dsp__l3_main_1 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* dss -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_dss__l3_main_1 = {
+ .master = &omap44xx_dss_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* l3_main_2 -> l3_main_1 */
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
.master = &omap44xx_l3_main_2_hwmod,
@@ -229,25 +248,62 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* mmc1 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mmc1__l3_main_1 = {
+ .master = &omap44xx_mmc1_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mmc2__l3_main_1 = {
+ .master = &omap44xx_mmc2_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L3 target configuration and error log registers */
+static struct omap_hwmod_irq_info omap44xx_l3_targ_irqs[] = {
+ { .irq = 9 + OMAP44XX_IRQ_GIC_START },
+ { .irq = 10 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_l3_main_1_addrs[] = {
+ {
+ .pa_start = 0x44000000,
+ .pa_end = 0x44000fff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
/* mpu -> l3_main_1 */
static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
.master = &omap44xx_mpu_hwmod,
.slave = &omap44xx_l3_main_1_hwmod,
.clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_l3_main_1_addrs),
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l3_main_1 slave ports */
static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
&omap44xx_dsp__l3_main_1,
+ &omap44xx_dss__l3_main_1,
&omap44xx_l3_main_2__l3_main_1,
&omap44xx_l4_cfg__l3_main_1,
+ &omap44xx_mmc1__l3_main_1,
+ &omap44xx_mmc2__l3_main_1,
&omap44xx_mpu__l3_main_1,
};
static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
.name = "l3_main_1",
.class = &omap44xx_l3_hwmod_class,
+ .mpu_irqs = omap44xx_l3_targ_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_l3_targ_irqs),
.slaves = omap44xx_l3_main_1_slaves,
.slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_1_slaves),
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -262,6 +318,30 @@ static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* hsi -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
+ .master = &omap44xx_hsi_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* ipu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = {
+ .master = &omap44xx_ipu_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* iss -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = {
+ .master = &omap44xx_iss_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* iva -> l3_main_2 */
static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
.master = &omap44xx_iva_hwmod,
@@ -270,11 +350,21 @@ static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+static struct omap_hwmod_addr_space omap44xx_l3_main_2_addrs[] = {
+ {
+ .pa_start = 0x44800000,
+ .pa_end = 0x44801fff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
/* l3_main_1 -> l3_main_2 */
static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
.master = &omap44xx_l3_main_1_hwmod,
.slave = &omap44xx_l3_main_2_hwmod,
.clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_l3_main_2_addrs),
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -286,12 +376,24 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* usb_otg_hs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_otg_hs__l3_main_2 = {
+ .master = &omap44xx_usb_otg_hs_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* l3_main_2 slave ports */
static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
&omap44xx_dma_system__l3_main_2,
+ &omap44xx_hsi__l3_main_2,
+ &omap44xx_ipu__l3_main_2,
+ &omap44xx_iss__l3_main_2,
&omap44xx_iva__l3_main_2,
&omap44xx_l3_main_1__l3_main_2,
&omap44xx_l4_cfg__l3_main_2,
+ &omap44xx_usb_otg_hs__l3_main_2,
};
static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
@@ -303,11 +405,21 @@ static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
};
/* l3_main_3 interface data */
+static struct omap_hwmod_addr_space omap44xx_l3_main_3_addrs[] = {
+ {
+ .pa_start = 0x45000000,
+ .pa_end = 0x45000fff,
+ .flags = ADDR_TYPE_RT,
+ },
+};
+
/* l3_main_1 -> l3_main_3 */
static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
.master = &omap44xx_l3_main_1_hwmod,
.slave = &omap44xx_l3_main_3_hwmod,
.clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_l3_main_3_addrs),
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -351,6 +463,14 @@ static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
};
/* l4_abe interface data */
+/* aess -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
+ .master = &omap44xx_aess_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "ocp_abe_iclk",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* dsp -> l4_abe */
static struct omap_hwmod_ocp_if omap44xx_dsp__l4_abe = {
.master = &omap44xx_dsp_hwmod,
@@ -377,6 +497,7 @@ static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
/* l4_abe slave ports */
static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
+ &omap44xx_aess__l4_abe,
&omap44xx_dsp__l4_abe,
&omap44xx_l3_main_1__l4_abe,
&omap44xx_mpu__l4_abe,
@@ -494,26 +615,15 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = {
* - They still need to be validated with the driver
* properly adapted to omap_hwmod / omap_device
*
- * aess
- * bandgap
* c2c
* c2c_target_fw
* cm_core
* cm_core_aon
- * counter_32k
* ctrl_module_core
* ctrl_module_pad_core
* ctrl_module_pad_wkup
* ctrl_module_wkup
* debugss
- * dmic
- * dss
- * dss_dispc
- * dss_dsi1
- * dss_dsi2
- * dss_hdmi
- * dss_rfbi
- * dss_venc
* efuse_ctrl_cust
* efuse_ctrl_std
* elm
@@ -524,58 +634,211 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = {
* gpu
* hdq1w
* hsi
- * ipu
- * iss
- * kbd
- * mailbox
- * mcasp
- * mcbsp1
- * mcbsp2
- * mcbsp3
- * mcbsp4
- * mcpdm
- * mcspi1
- * mcspi2
- * mcspi3
- * mcspi4
- * mmc1
- * mmc2
- * mmc3
- * mmc4
- * mmc5
- * mpu_c0
- * mpu_c1
* ocmc_ram
* ocp2scp_usb_phy
* ocp_wp_noc
- * prcm
* prcm_mpu
* prm
* scrm
* sl2if
* slimbus1
* slimbus2
- * spinlock
- * timer1
- * timer10
- * timer11
- * timer2
- * timer3
- * timer4
- * timer5
- * timer6
- * timer7
- * timer8
- * timer9
* usb_host_fs
* usb_host_hs
- * usb_otg_hs
* usb_phy_cm
* usb_tll_hs
* usim
*/
/*
+ * 'aess' class
+ * audio engine sub system
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_aess_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_aess_hwmod_class = {
+ .name = "aess",
+ .sysc = &omap44xx_aess_sysc,
+};
+
+/* aess */
+static struct omap_hwmod_irq_info omap44xx_aess_irqs[] = {
+ { .irq = 99 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_aess_sdma_reqs[] = {
+ { .name = "fifo0", .dma_req = 100 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo1", .dma_req = 101 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo2", .dma_req = 102 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo3", .dma_req = 103 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo4", .dma_req = 104 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo5", .dma_req = 105 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo6", .dma_req = 106 + OMAP44XX_DMA_REQ_START },
+ { .name = "fifo7", .dma_req = 107 + OMAP44XX_DMA_REQ_START },
+};
+
+/* aess master ports */
+static struct omap_hwmod_ocp_if *omap44xx_aess_masters[] = {
+ &omap44xx_aess__l4_abe,
+};
+
+static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
+ {
+ .pa_start = 0x401f1000,
+ .pa_end = 0x401f13ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> aess */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_aess_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_aess_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_aess_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
+ {
+ .pa_start = 0x490f1000,
+ .pa_end = 0x490f13ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> aess (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_aess_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_aess_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_aess_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* aess slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_aess_slaves[] = {
+ &omap44xx_l4_abe__aess,
+ &omap44xx_l4_abe__aess_dma,
+};
+
+static struct omap_hwmod omap44xx_aess_hwmod = {
+ .name = "aess",
+ .class = &omap44xx_aess_hwmod_class,
+ .mpu_irqs = omap44xx_aess_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_aess_irqs),
+ .sdma_reqs = omap44xx_aess_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_aess_sdma_reqs),
+ .main_clk = "aess_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_AESS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_aess_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_aess_slaves),
+ .masters = omap44xx_aess_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_aess_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'bandgap' class
+ * bangap reference for ldo regulators
+ */
+
+static struct omap_hwmod_class omap44xx_bandgap_hwmod_class = {
+ .name = "bandgap",
+};
+
+/* bandgap */
+static struct omap_hwmod_opt_clk bandgap_opt_clks[] = {
+ { .role = "fclk", .clk = "bandgap_fclk" },
+};
+
+static struct omap_hwmod omap44xx_bandgap_hwmod = {
+ .name = "bandgap",
+ .class = &omap44xx_bandgap_hwmod_class,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
+ },
+ },
+ .opt_clks = bandgap_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(bandgap_opt_clks),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'counter' class
+ * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_counter_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0004,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_counter_hwmod_class = {
+ .name = "counter",
+ .sysc = &omap44xx_counter_sysc,
+};
+
+/* counter_32k */
+static struct omap_hwmod omap44xx_counter_32k_hwmod;
+static struct omap_hwmod_addr_space omap44xx_counter_32k_addrs[] = {
+ {
+ .pa_start = 0x4a304000,
+ .pa_end = 0x4a30401f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> counter_32k */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__counter_32k = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_counter_32k_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_counter_32k_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_counter_32k_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* counter_32k slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_counter_32k_slaves[] = {
+ &omap44xx_l4_wkup__counter_32k,
+};
+
+static struct omap_hwmod omap44xx_counter_32k_hwmod = {
+ .name = "counter_32k",
+ .class = &omap44xx_counter_hwmod_class,
+ .flags = HWMOD_SWSUP_SIDLE,
+ .main_clk = "sys_32k_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_WKUP_SYNCTIMER_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_counter_32k_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_counter_32k_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'dma' class
* dma controller for data exchange between memory to memory (i.e. internal or
* external memory) and gp peripherals to memory or memory to gp peripherals
@@ -662,6 +925,96 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = {
};
/*
+ * 'dmic' class
+ * digital microphone controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dmic_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_dmic_hwmod_class = {
+ .name = "dmic",
+ .sysc = &omap44xx_dmic_sysc,
+};
+
+/* dmic */
+static struct omap_hwmod omap44xx_dmic_hwmod;
+static struct omap_hwmod_irq_info omap44xx_dmic_irqs[] = {
+ { .irq = 114 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_dmic_sdma_reqs[] = {
+ { .dma_req = 66 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dmic_addrs[] = {
+ {
+ .pa_start = 0x4012e000,
+ .pa_end = 0x4012e07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> dmic */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_dmic_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_dmic_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dmic_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dmic_dma_addrs[] = {
+ {
+ .pa_start = 0x4902e000,
+ .pa_end = 0x4902e07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> dmic (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_dmic_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_dmic_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dmic_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* dmic slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dmic_slaves[] = {
+ &omap44xx_l4_abe__dmic,
+ &omap44xx_l4_abe__dmic_dma,
+};
+
+static struct omap_hwmod omap44xx_dmic_hwmod = {
+ .name = "dmic",
+ .class = &omap44xx_dmic_hwmod_class,
+ .mpu_irqs = omap44xx_dmic_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dmic_irqs),
+ .sdma_reqs = omap44xx_dmic_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dmic_sdma_reqs),
+ .main_clk = "dmic_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_DMIC_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dmic_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dmic_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'dsp' class
* dsp sub-system
*/
@@ -747,6 +1100,590 @@ static struct omap_hwmod omap44xx_dsp_hwmod = {
};
/*
+ * 'dss' class
+ * display sub-system
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dss_sysc = {
+ .rev_offs = 0x0000,
+ .syss_offs = 0x0014,
+ .sysc_flags = SYSS_HAS_RESET_STATUS,
+};
+
+static struct omap_hwmod_class omap44xx_dss_hwmod_class = {
+ .name = "dss",
+ .sysc = &omap44xx_dss_sysc,
+};
+
+/* dss */
+/* dss master ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_masters[] = {
+ &omap44xx_dss__l3_main_1,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
+ {
+ .pa_start = 0x58000000,
+ .pa_end = 0x5800007f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_addrs[] = {
+ {
+ .pa_start = 0x48040000,
+ .pa_end = 0x4804007f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_slaves[] = {
+ &omap44xx_l3_main_2__dss,
+ &omap44xx_l4_per__dss,
+};
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+ { .role = "sys_clk", .clk = "dss_sys_clk" },
+ { .role = "tv_clk", .clk = "dss_tv_clk" },
+ { .role = "dss_clk", .clk = "dss_dss_clk" },
+ { .role = "video_clk", .clk = "dss_48mhz_clk" },
+};
+
+static struct omap_hwmod omap44xx_dss_hwmod = {
+ .name = "dss_core",
+ .class = &omap44xx_dss_hwmod_class,
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .slaves = omap44xx_dss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_slaves),
+ .masters = omap44xx_dss_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_dss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dispc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_MIDLEMODE |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_dispc_hwmod_class = {
+ .name = "dispc",
+ .sysc = &omap44xx_dispc_sysc,
+};
+
+/* dss_dispc */
+static struct omap_hwmod omap44xx_dss_dispc_hwmod;
+static struct omap_hwmod_irq_info omap44xx_dss_dispc_irqs[] = {
+ { .irq = 25 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dispc_sdma_reqs[] = {
+ { .dma_req = 5 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
+ {
+ .pa_start = 0x58001000,
+ .pa_end = 0x58001fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_dispc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dispc_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_dispc_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dispc_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dispc_addrs[] = {
+ {
+ .pa_start = 0x48041000,
+ .pa_end = 0x48041fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_dispc */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dispc = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dispc_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dispc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dispc_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_dispc slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_dispc_slaves[] = {
+ &omap44xx_l3_main_2__dss_dispc,
+ &omap44xx_l4_per__dss_dispc,
+};
+
+static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
+ .name = "dss_dispc",
+ .class = &omap44xx_dispc_hwmod_class,
+ .mpu_irqs = omap44xx_dss_dispc_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dispc_irqs),
+ .sdma_reqs = omap44xx_dss_dispc_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_dispc_sdma_reqs),
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_dispc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dispc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'dsi' class
+ * display serial interface controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_dsi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_dsi_hwmod_class = {
+ .name = "dsi",
+ .sysc = &omap44xx_dsi_sysc,
+};
+
+/* dss_dsi1 */
+static struct omap_hwmod omap44xx_dss_dsi1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_dss_dsi1_irqs[] = {
+ { .irq = 53 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dsi1_sdma_reqs[] = {
+ { .dma_req = 74 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
+ {
+ .pa_start = 0x58004000,
+ .pa_end = 0x580041ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dsi1_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_dsi1_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi1_addrs[] = {
+ {
+ .pa_start = 0x48044000,
+ .pa_end = 0x480441ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dsi1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dsi1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_dsi1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_dsi1_slaves[] = {
+ &omap44xx_l3_main_2__dss_dsi1,
+ &omap44xx_l4_per__dss_dsi1,
+};
+
+static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
+ .name = "dss_dsi1",
+ .class = &omap44xx_dsi_hwmod_class,
+ .mpu_irqs = omap44xx_dss_dsi1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_irqs),
+ .sdma_reqs = omap44xx_dss_dsi1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_sdma_reqs),
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_dsi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* dss_dsi2 */
+static struct omap_hwmod omap44xx_dss_dsi2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_dss_dsi2_irqs[] = {
+ { .irq = 84 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_dsi2_sdma_reqs[] = {
+ { .dma_req = 83 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
+ {
+ .pa_start = 0x58005000,
+ .pa_end = 0x580051ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_dsi2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dsi2_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_dsi2_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi2_addrs[] = {
+ {
+ .pa_start = 0x48045000,
+ .pa_end = 0x480451ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_dsi2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dsi2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dsi2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_dsi2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_dsi2_slaves[] = {
+ &omap44xx_l3_main_2__dss_dsi2,
+ &omap44xx_l4_per__dss_dsi2,
+};
+
+static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
+ .name = "dss_dsi2",
+ .class = &omap44xx_dsi_hwmod_class,
+ .mpu_irqs = omap44xx_dss_dsi2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_irqs),
+ .sdma_reqs = omap44xx_dss_dsi2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_sdma_reqs),
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_dsi2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'hdmi' class
+ * hdmi controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hdmi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_hdmi_hwmod_class = {
+ .name = "hdmi",
+ .sysc = &omap44xx_hdmi_sysc,
+};
+
+/* dss_hdmi */
+static struct omap_hwmod omap44xx_dss_hdmi_hwmod;
+static struct omap_hwmod_irq_info omap44xx_dss_hdmi_irqs[] = {
+ { .irq = 101 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_dss_hdmi_sdma_reqs[] = {
+ { .dma_req = 75 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
+ {
+ .pa_start = 0x58006000,
+ .pa_end = 0x58006fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_hdmi */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_hdmi_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_hdmi_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_hdmi_addrs[] = {
+ {
+ .pa_start = 0x48046000,
+ .pa_end = 0x48046fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_hdmi */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_hdmi = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_hdmi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_hdmi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_hdmi slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_hdmi_slaves[] = {
+ &omap44xx_l3_main_2__dss_hdmi,
+ &omap44xx_l4_per__dss_hdmi,
+};
+
+static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
+ .name = "dss_hdmi",
+ .class = &omap44xx_hdmi_hwmod_class,
+ .mpu_irqs = omap44xx_dss_hdmi_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_irqs),
+ .sdma_reqs = omap44xx_dss_hdmi_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_sdma_reqs),
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_hdmi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'rfbi' class
+ * remote frame buffer interface
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_rfbi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_rfbi_hwmod_class = {
+ .name = "rfbi",
+ .sysc = &omap44xx_rfbi_sysc,
+};
+
+/* dss_rfbi */
+static struct omap_hwmod omap44xx_dss_rfbi_hwmod;
+static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
+ { .dma_req = 13 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
+ {
+ .pa_start = 0x58002000,
+ .pa_end = 0x580020ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_rfbi_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_rfbi_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_rfbi_addrs[] = {
+ {
+ .pa_start = 0x48042000,
+ .pa_end = 0x480420ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_rfbi = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_rfbi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_rfbi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_rfbi slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_rfbi_slaves[] = {
+ &omap44xx_l3_main_2__dss_rfbi,
+ &omap44xx_l4_per__dss_rfbi,
+};
+
+static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
+ .name = "dss_rfbi",
+ .class = &omap44xx_rfbi_hwmod_class,
+ .sdma_reqs = omap44xx_dss_rfbi_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_sdma_reqs),
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_rfbi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'venc' class
+ * video encoder
+ */
+
+static struct omap_hwmod_class omap44xx_venc_hwmod_class = {
+ .name = "venc",
+};
+
+/* dss_venc */
+static struct omap_hwmod omap44xx_dss_venc_hwmod;
+static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
+ {
+ .pa_start = 0x58003000,
+ .pa_end = 0x580030ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> dss_venc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_venc_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dss_venc_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_venc_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_venc_addrs[] = {
+ {
+ .pa_start = 0x48043000,
+ .pa_end = 0x480430ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> dss_venc */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_venc = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_venc_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_venc_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_dss_venc_addrs),
+ .user = OCP_USER_MPU,
+};
+
+/* dss_venc slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = {
+ &omap44xx_l3_main_2__dss_venc,
+ &omap44xx_l4_per__dss_venc,
+};
+
+static struct omap_hwmod omap44xx_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap44xx_venc_hwmod_class,
+ .main_clk = "dss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DSS_DSS_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_dss_venc_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_dss_venc_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'gpio' class
* general purpose io module
*/
@@ -1093,6 +2030,83 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = {
};
/*
+ * 'hsi' class
+ * mipi high-speed synchronous serial interface (multichannel and full-duplex
+ * serial if)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hsi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_EMUFREE |
+ SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_hsi_hwmod_class = {
+ .name = "hsi",
+ .sysc = &omap44xx_hsi_sysc,
+};
+
+/* hsi */
+static struct omap_hwmod_irq_info omap44xx_hsi_irqs[] = {
+ { .name = "mpu_p1", .irq = 67 + OMAP44XX_IRQ_GIC_START },
+ { .name = "mpu_p2", .irq = 68 + OMAP44XX_IRQ_GIC_START },
+ { .name = "mpu_dma", .irq = 71 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* hsi master ports */
+static struct omap_hwmod_ocp_if *omap44xx_hsi_masters[] = {
+ &omap44xx_hsi__l3_main_2,
+};
+
+static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = {
+ {
+ .pa_start = 0x4a058000,
+ .pa_end = 0x4a05bfff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_cfg -> hsi */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__hsi = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_hsi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_hsi_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_hsi_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* hsi slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_hsi_slaves[] = {
+ &omap44xx_l4_cfg__hsi,
+};
+
+static struct omap_hwmod omap44xx_hsi_hwmod = {
+ .name = "hsi",
+ .class = &omap44xx_hsi_hwmod_class,
+ .mpu_irqs = omap44xx_hsi_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_hsi_irqs),
+ .main_clk = "hsi_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_HSI_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_hsi_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_hsi_slaves),
+ .masters = omap44xx_hsi_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_hsi_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'i2c' class
* multimaster high-speed i2c controller
*/
@@ -1326,6 +2340,188 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = {
};
/*
+ * 'ipu' class
+ * imaging processor unit
+ */
+
+static struct omap_hwmod_class omap44xx_ipu_hwmod_class = {
+ .name = "ipu",
+};
+
+/* ipu */
+static struct omap_hwmod_irq_info omap44xx_ipu_irqs[] = {
+ { .irq = 100 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_rst_info omap44xx_ipu_c0_resets[] = {
+ { .name = "cpu0", .rst_shift = 0 },
+};
+
+static struct omap_hwmod_rst_info omap44xx_ipu_c1_resets[] = {
+ { .name = "cpu1", .rst_shift = 1 },
+};
+
+static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = {
+ { .name = "mmu_cache", .rst_shift = 2 },
+};
+
+/* ipu master ports */
+static struct omap_hwmod_ocp_if *omap44xx_ipu_masters[] = {
+ &omap44xx_ipu__l3_main_2,
+};
+
+/* l3_main_2 -> ipu */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_ipu_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* ipu slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_ipu_slaves[] = {
+ &omap44xx_l3_main_2__ipu,
+};
+
+/* Pseudo hwmod for reset control purpose only */
+static struct omap_hwmod omap44xx_ipu_c0_hwmod = {
+ .name = "ipu_c0",
+ .class = &omap44xx_ipu_hwmod_class,
+ .flags = HWMOD_INIT_NO_RESET,
+ .rst_lines = omap44xx_ipu_c0_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_c0_resets),
+ .prcm = {
+ .omap4 = {
+ .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+ },
+ },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* Pseudo hwmod for reset control purpose only */
+static struct omap_hwmod omap44xx_ipu_c1_hwmod = {
+ .name = "ipu_c1",
+ .class = &omap44xx_ipu_hwmod_class,
+ .flags = HWMOD_INIT_NO_RESET,
+ .rst_lines = omap44xx_ipu_c1_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_c1_resets),
+ .prcm = {
+ .omap4 = {
+ .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+ },
+ },
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+static struct omap_hwmod omap44xx_ipu_hwmod = {
+ .name = "ipu",
+ .class = &omap44xx_ipu_hwmod_class,
+ .mpu_irqs = omap44xx_ipu_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_ipu_irqs),
+ .rst_lines = omap44xx_ipu_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_resets),
+ .main_clk = "ipu_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
+ .rstctrl_reg = OMAP4430_RM_DUCATI_RSTCTRL,
+ },
+ },
+ .slaves = omap44xx_ipu_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_ipu_slaves),
+ .masters = omap44xx_ipu_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_ipu_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'iss' class
+ * external images sensor pixel data processor
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_iss_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_iss_hwmod_class = {
+ .name = "iss",
+ .sysc = &omap44xx_iss_sysc,
+};
+
+/* iss */
+static struct omap_hwmod_irq_info omap44xx_iss_irqs[] = {
+ { .irq = 24 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_iss_sdma_reqs[] = {
+ { .name = "1", .dma_req = 8 + OMAP44XX_DMA_REQ_START },
+ { .name = "2", .dma_req = 9 + OMAP44XX_DMA_REQ_START },
+ { .name = "3", .dma_req = 11 + OMAP44XX_DMA_REQ_START },
+ { .name = "4", .dma_req = 12 + OMAP44XX_DMA_REQ_START },
+};
+
+/* iss master ports */
+static struct omap_hwmod_ocp_if *omap44xx_iss_masters[] = {
+ &omap44xx_iss__l3_main_2,
+};
+
+static struct omap_hwmod_addr_space omap44xx_iss_addrs[] = {
+ {
+ .pa_start = 0x52000000,
+ .pa_end = 0x520000ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l3_main_2 -> iss */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_iss_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_iss_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_iss_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* iss slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_iss_slaves[] = {
+ &omap44xx_l3_main_2__iss,
+};
+
+static struct omap_hwmod_opt_clk iss_opt_clks[] = {
+ { .role = "ctrlclk", .clk = "iss_ctrlclk" },
+};
+
+static struct omap_hwmod omap44xx_iss_hwmod = {
+ .name = "iss",
+ .class = &omap44xx_iss_hwmod_class,
+ .mpu_irqs = omap44xx_iss_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_iss_irqs),
+ .sdma_reqs = omap44xx_iss_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_iss_sdma_reqs),
+ .main_clk = "iss_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_CAM_ISS_CLKCTRL,
+ },
+ },
+ .opt_clks = iss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(iss_opt_clks),
+ .slaves = omap44xx_iss_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_iss_slaves),
+ .masters = omap44xx_iss_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_iss_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'iva' class
* multi-standard video encoder/decoder hardware accelerator
*/
@@ -1435,6 +2631,1084 @@ static struct omap_hwmod omap44xx_iva_hwmod = {
};
/*
+ * 'kbd' class
+ * keyboard controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_kbd_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_kbd_hwmod_class = {
+ .name = "kbd",
+ .sysc = &omap44xx_kbd_sysc,
+};
+
+/* kbd */
+static struct omap_hwmod omap44xx_kbd_hwmod;
+static struct omap_hwmod_irq_info omap44xx_kbd_irqs[] = {
+ { .irq = 120 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_kbd_addrs[] = {
+ {
+ .pa_start = 0x4a31c000,
+ .pa_end = 0x4a31c07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> kbd */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__kbd = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_kbd_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_kbd_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_kbd_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* kbd slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_kbd_slaves[] = {
+ &omap44xx_l4_wkup__kbd,
+};
+
+static struct omap_hwmod omap44xx_kbd_hwmod = {
+ .name = "kbd",
+ .class = &omap44xx_kbd_hwmod_class,
+ .mpu_irqs = omap44xx_kbd_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_kbd_irqs),
+ .main_clk = "kbd_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_kbd_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_kbd_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors using a
+ * queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mailbox_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mailbox_hwmod_class = {
+ .name = "mailbox",
+ .sysc = &omap44xx_mailbox_sysc,
+};
+
+/* mailbox */
+static struct omap_hwmod omap44xx_mailbox_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mailbox_irqs[] = {
+ { .irq = 26 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mailbox_addrs[] = {
+ {
+ .pa_start = 0x4a0f4000,
+ .pa_end = 0x4a0f41ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_cfg -> mailbox */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__mailbox = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_mailbox_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mailbox_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mailbox_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mailbox slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mailbox_slaves[] = {
+ &omap44xx_l4_cfg__mailbox,
+};
+
+static struct omap_hwmod omap44xx_mailbox_hwmod = {
+ .name = "mailbox",
+ .class = &omap44xx_mailbox_hwmod_class,
+ .mpu_irqs = omap44xx_mailbox_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mailbox_irqs),
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4CFG_MAILBOX_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mailbox_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mailbox_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcbsp_sysc = {
+ .sysc_offs = 0x008c,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
+ .name = "mcbsp",
+ .sysc = &omap44xx_mcbsp_sysc,
+ .rev = MCBSP_CONFIG_TYPE4,
+};
+
+/* mcbsp1 */
+static struct omap_hwmod omap44xx_mcbsp1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = {
+ { .irq = 17 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 32 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 33 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40122000,
+ .pa_end = 0x401220ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp1_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp1_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49022000,
+ .pa_end = 0x490220ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp1 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp1_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp1_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* mcbsp1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcbsp1_slaves[] = {
+ &omap44xx_l4_abe__mcbsp1,
+ &omap44xx_l4_abe__mcbsp1_dma,
+};
+
+static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
+ .name = "mcbsp1",
+ .class = &omap44xx_mcbsp_hwmod_class,
+ .mpu_irqs = omap44xx_mcbsp1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcbsp1_irqs),
+ .sdma_reqs = omap44xx_mcbsp1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcbsp1_sdma_reqs),
+ .main_clk = "mcbsp1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcbsp1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcbsp2 */
+static struct omap_hwmod omap44xx_mcbsp2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = {
+ { .irq = 22 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 16 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 17 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40124000,
+ .pa_end = 0x401240ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp2_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp2_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp2_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49024000,
+ .pa_end = 0x490240ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp2 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp2_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp2_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp2_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* mcbsp2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcbsp2_slaves[] = {
+ &omap44xx_l4_abe__mcbsp2,
+ &omap44xx_l4_abe__mcbsp2_dma,
+};
+
+static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
+ .name = "mcbsp2",
+ .class = &omap44xx_mcbsp_hwmod_class,
+ .mpu_irqs = omap44xx_mcbsp2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcbsp2_irqs),
+ .sdma_reqs = omap44xx_mcbsp2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcbsp2_sdma_reqs),
+ .main_clk = "mcbsp2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcbsp2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcbsp3 */
+static struct omap_hwmod omap44xx_mcbsp3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = {
+ { .irq = 23 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 18 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 19 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40126000,
+ .pa_end = 0x401260ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp3_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp3_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49026000,
+ .pa_end = 0x490260ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcbsp3 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp3_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp3_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* mcbsp3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcbsp3_slaves[] = {
+ &omap44xx_l4_abe__mcbsp3,
+ &omap44xx_l4_abe__mcbsp3_dma,
+};
+
+static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
+ .name = "mcbsp3",
+ .class = &omap44xx_mcbsp_hwmod_class,
+ .mpu_irqs = omap44xx_mcbsp3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcbsp3_irqs),
+ .sdma_reqs = omap44xx_mcbsp3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcbsp3_sdma_reqs),
+ .main_clk = "mcbsp3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcbsp3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcbsp4 */
+static struct omap_hwmod omap44xx_mcbsp4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = {
+ { .irq = 16 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 30 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 31 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp4_addrs[] = {
+ {
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcbsp4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcbsp4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcbsp4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcbsp4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcbsp4_slaves[] = {
+ &omap44xx_l4_per__mcbsp4,
+};
+
+static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
+ .name = "mcbsp4",
+ .class = &omap44xx_mcbsp_hwmod_class,
+ .mpu_irqs = omap44xx_mcbsp4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcbsp4_irqs),
+ .sdma_reqs = omap44xx_mcbsp4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcbsp4_sdma_reqs),
+ .main_clk = "mcbsp4_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcbsp4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mcpdm' class
+ * multi channel pdm controller (proprietary interface with phoenix power
+ * ic)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcpdm_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
+ .name = "mcpdm",
+ .sysc = &omap44xx_mcpdm_sysc,
+};
+
+/* mcpdm */
+static struct omap_hwmod omap44xx_mcpdm_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
+ { .irq = 112 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
+ { .name = "up_link", .dma_req = 64 + OMAP44XX_DMA_REQ_START },
+ { .name = "dn_link", .dma_req = 65 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
+ {
+ .pa_start = 0x40132000,
+ .pa_end = 0x4013207f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcpdm */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcpdm_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
+ {
+ .pa_start = 0x49032000,
+ .pa_end = 0x4903207f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> mcpdm (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcpdm_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcpdm_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* mcpdm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
+ &omap44xx_l4_abe__mcpdm,
+ &omap44xx_l4_abe__mcpdm_dma,
+};
+
+static struct omap_hwmod omap44xx_mcpdm_hwmod = {
+ .name = "mcpdm",
+ .class = &omap44xx_mcpdm_hwmod_class,
+ .mpu_irqs = omap44xx_mcpdm_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_irqs),
+ .sdma_reqs = omap44xx_mcpdm_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcpdm_sdma_reqs),
+ .main_clk = "mcpdm_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_PDM_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mcpdm_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcpdm_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mcspi' class
+ * multichannel serial port interface (mcspi) / master/slave synchronous serial
+ * bus
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcspi_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
+ .name = "mcspi",
+ .sysc = &omap44xx_mcspi_sysc,
+ .rev = OMAP4_MCSPI_REV,
+};
+
+/* mcspi1 */
+static struct omap_hwmod omap44xx_mcspi1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcspi1_irqs[] = {
+ { .irq = 65 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi1_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 34 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 35 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx1", .dma_req = 36 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx1", .dma_req = 37 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx2", .dma_req = 38 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx2", .dma_req = 39 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx3", .dma_req = 40 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx3", .dma_req = 41 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi1_addrs[] = {
+ {
+ .pa_start = 0x48098000,
+ .pa_end = 0x480981ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcspi1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcspi1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcspi1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcspi1_slaves[] = {
+ &omap44xx_l4_per__mcspi1,
+};
+
+/* mcspi1 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
+ .num_chipselect = 4,
+};
+
+static struct omap_hwmod omap44xx_mcspi1_hwmod = {
+ .name = "mcspi1",
+ .class = &omap44xx_mcspi_hwmod_class,
+ .mpu_irqs = omap44xx_mcspi1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcspi1_irqs),
+ .sdma_reqs = omap44xx_mcspi1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcspi1_sdma_reqs),
+ .main_clk = "mcspi1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI1_CLKCTRL,
+ },
+ },
+ .dev_attr = &mcspi1_dev_attr,
+ .slaves = omap44xx_mcspi1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcspi2 */
+static struct omap_hwmod omap44xx_mcspi2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcspi2_irqs[] = {
+ { .irq = 66 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi2_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 42 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 43 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx1", .dma_req = 44 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx1", .dma_req = 45 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi2_addrs[] = {
+ {
+ .pa_start = 0x4809a000,
+ .pa_end = 0x4809a1ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcspi2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcspi2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcspi2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcspi2_slaves[] = {
+ &omap44xx_l4_per__mcspi2,
+};
+
+/* mcspi2 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap44xx_mcspi2_hwmod = {
+ .name = "mcspi2",
+ .class = &omap44xx_mcspi_hwmod_class,
+ .mpu_irqs = omap44xx_mcspi2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcspi2_irqs),
+ .sdma_reqs = omap44xx_mcspi2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcspi2_sdma_reqs),
+ .main_clk = "mcspi2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI2_CLKCTRL,
+ },
+ },
+ .dev_attr = &mcspi2_dev_attr,
+ .slaves = omap44xx_mcspi2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcspi3 */
+static struct omap_hwmod omap44xx_mcspi3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcspi3_irqs[] = {
+ { .irq = 91 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi3_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 14 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 15 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx1", .dma_req = 22 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx1", .dma_req = 23 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi3_addrs[] = {
+ {
+ .pa_start = 0x480b8000,
+ .pa_end = 0x480b81ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcspi3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcspi3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcspi3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcspi3_slaves[] = {
+ &omap44xx_l4_per__mcspi3,
+};
+
+/* mcspi3 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
+ .num_chipselect = 2,
+};
+
+static struct omap_hwmod omap44xx_mcspi3_hwmod = {
+ .name = "mcspi3",
+ .class = &omap44xx_mcspi_hwmod_class,
+ .mpu_irqs = omap44xx_mcspi3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcspi3_irqs),
+ .sdma_reqs = omap44xx_mcspi3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcspi3_sdma_reqs),
+ .main_clk = "mcspi3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI3_CLKCTRL,
+ },
+ },
+ .dev_attr = &mcspi3_dev_attr,
+ .slaves = omap44xx_mcspi3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mcspi4 */
+static struct omap_hwmod omap44xx_mcspi4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mcspi4_irqs[] = {
+ { .irq = 48 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcspi4_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 69 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 70 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi4_addrs[] = {
+ {
+ .pa_start = 0x480ba000,
+ .pa_end = 0x480ba1ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mcspi4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mcspi4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mcspi4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mcspi4_slaves[] = {
+ &omap44xx_l4_per__mcspi4,
+};
+
+/* mcspi4 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
+ .num_chipselect = 1,
+};
+
+static struct omap_hwmod omap44xx_mcspi4_hwmod = {
+ .name = "mcspi4",
+ .class = &omap44xx_mcspi_hwmod_class,
+ .mpu_irqs = omap44xx_mcspi4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mcspi4_irqs),
+ .sdma_reqs = omap44xx_mcspi4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mcspi4_sdma_reqs),
+ .main_clk = "mcspi4_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MCSPI4_CLKCTRL,
+ },
+ },
+ .dev_attr = &mcspi4_dev_attr,
+ .slaves = omap44xx_mcspi4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mmc' class
+ * multimedia card high-speed/sd/sdio (mmc/sd/sdio) host controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_mmc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
+ SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_mmc_hwmod_class = {
+ .name = "mmc",
+ .sysc = &omap44xx_mmc_sysc,
+};
+
+/* mmc1 */
+
+static struct omap_hwmod_irq_info omap44xx_mmc1_irqs[] = {
+ { .irq = 83 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 60 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 61 + OMAP44XX_DMA_REQ_START },
+};
+
+/* mmc1 master ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc1_masters[] = {
+ &omap44xx_mmc1__l3_main_1,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc1_addrs[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c3ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mmc1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mmc1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc1_slaves[] = {
+ &omap44xx_l4_per__mmc1,
+};
+
+/* mmc1 dev_attr */
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+ .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod omap44xx_mmc1_hwmod = {
+ .name = "mmc1",
+ .class = &omap44xx_mmc_hwmod_class,
+ .mpu_irqs = omap44xx_mmc1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mmc1_irqs),
+ .sdma_reqs = omap44xx_mmc1_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mmc1_sdma_reqs),
+ .main_clk = "mmc1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_MMC1_CLKCTRL,
+ },
+ },
+ .dev_attr = &mmc1_dev_attr,
+ .slaves = omap44xx_mmc1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mmc1_slaves),
+ .masters = omap44xx_mmc1_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_mmc1_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mmc2 */
+static struct omap_hwmod_irq_info omap44xx_mmc2_irqs[] = {
+ { .irq = 86 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc2_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 46 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 47 + OMAP44XX_DMA_REQ_START },
+};
+
+/* mmc2 master ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc2_masters[] = {
+ &omap44xx_mmc2__l3_main_1,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc2_addrs[] = {
+ {
+ .pa_start = 0x480b4000,
+ .pa_end = 0x480b43ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mmc2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mmc2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc2_slaves[] = {
+ &omap44xx_l4_per__mmc2,
+};
+
+static struct omap_hwmod omap44xx_mmc2_hwmod = {
+ .name = "mmc2",
+ .class = &omap44xx_mmc_hwmod_class,
+ .mpu_irqs = omap44xx_mmc2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mmc2_irqs),
+ .sdma_reqs = omap44xx_mmc2_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mmc2_sdma_reqs),
+ .main_clk = "mmc2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_MMC2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mmc2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mmc2_slaves),
+ .masters = omap44xx_mmc2_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_mmc2_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mmc3 */
+static struct omap_hwmod omap44xx_mmc3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mmc3_irqs[] = {
+ { .irq = 94 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc3_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 76 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 77 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc3_addrs[] = {
+ {
+ .pa_start = 0x480ad000,
+ .pa_end = 0x480ad3ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mmc3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mmc3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc3_slaves[] = {
+ &omap44xx_l4_per__mmc3,
+};
+
+static struct omap_hwmod omap44xx_mmc3_hwmod = {
+ .name = "mmc3",
+ .class = &omap44xx_mmc_hwmod_class,
+ .mpu_irqs = omap44xx_mmc3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mmc3_irqs),
+ .sdma_reqs = omap44xx_mmc3_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mmc3_sdma_reqs),
+ .main_clk = "mmc3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD3_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mmc3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mmc3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mmc4 */
+static struct omap_hwmod omap44xx_mmc4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mmc4_irqs[] = {
+ { .irq = 96 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc4_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 56 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 57 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc4_addrs[] = {
+ {
+ .pa_start = 0x480d1000,
+ .pa_end = 0x480d13ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mmc4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mmc4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc4_slaves[] = {
+ &omap44xx_l4_per__mmc4,
+};
+
+static struct omap_hwmod omap44xx_mmc4_hwmod = {
+ .name = "mmc4",
+ .class = &omap44xx_mmc_hwmod_class,
+ .mpu_irqs = omap44xx_mmc4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mmc4_irqs),
+ .sdma_reqs = omap44xx_mmc4_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mmc4_sdma_reqs),
+ .main_clk = "mmc4_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD4_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mmc4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mmc4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* mmc5 */
+static struct omap_hwmod omap44xx_mmc5_hwmod;
+static struct omap_hwmod_irq_info omap44xx_mmc5_irqs[] = {
+ { .irq = 59 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_mmc5_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 58 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx", .dma_req = 59 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc5_addrs[] = {
+ {
+ .pa_start = 0x480d5000,
+ .pa_end = 0x480d53ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> mmc5 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc5 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc5_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_mmc5_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc5 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mmc5_slaves[] = {
+ &omap44xx_l4_per__mmc5,
+};
+
+static struct omap_hwmod omap44xx_mmc5_hwmod = {
+ .name = "mmc5",
+ .class = &omap44xx_mmc_hwmod_class,
+ .mpu_irqs = omap44xx_mmc5_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mmc5_irqs),
+ .sdma_reqs = omap44xx_mmc5_sdma_reqs,
+ .sdma_reqs_cnt = ARRAY_SIZE(omap44xx_mmc5_sdma_reqs),
+ .main_clk = "mmc5_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_MMCSD5_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_mmc5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_mmc5_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'mpu' class
* mpu sub-system
*/
@@ -1639,6 +3913,676 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
};
/*
+ * 'spinlock' class
+ * spinlock provides hardware assistance for synchronizing the processes
+ * running on multiple processors
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_spinlock_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_spinlock_hwmod_class = {
+ .name = "spinlock",
+ .sysc = &omap44xx_spinlock_sysc,
+};
+
+/* spinlock */
+static struct omap_hwmod omap44xx_spinlock_hwmod;
+static struct omap_hwmod_addr_space omap44xx_spinlock_addrs[] = {
+ {
+ .pa_start = 0x4a0f6000,
+ .pa_end = 0x4a0f6fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_cfg -> spinlock */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__spinlock = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_spinlock_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_spinlock_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_spinlock_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* spinlock slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_spinlock_slaves[] = {
+ &omap44xx_l4_cfg__spinlock,
+};
+
+static struct omap_hwmod omap44xx_spinlock_hwmod = {
+ .name = "spinlock",
+ .class = &omap44xx_spinlock_hwmod_class,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4CFG_HW_SEM_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_spinlock_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_spinlock_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'timer' class
+ * general purpose timer module with accurate 1ms tick
+ * This class contains several variants: ['timer_1ms', 'timer']
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_timer_1ms_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_EMUFREE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_timer_1ms_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap44xx_timer_1ms_sysc,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_timer_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_timer_hwmod_class = {
+ .name = "timer",
+ .sysc = &omap44xx_timer_sysc,
+};
+
+/* timer1 */
+static struct omap_hwmod omap44xx_timer1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
+ { .irq = 37 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer1_addrs[] = {
+ {
+ .pa_start = 0x4a318000,
+ .pa_end = 0x4a31807f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__timer1 = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_timer1_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_timer1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer1_slaves[] = {
+ &omap44xx_l4_wkup__timer1,
+};
+
+static struct omap_hwmod omap44xx_timer1_hwmod = {
+ .name = "timer1",
+ .class = &omap44xx_timer_1ms_hwmod_class,
+ .mpu_irqs = omap44xx_timer1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer1_irqs),
+ .main_clk = "timer1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer2 */
+static struct omap_hwmod omap44xx_timer2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer2_irqs[] = {
+ { .irq = 38 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer2_addrs[] = {
+ {
+ .pa_start = 0x48032000,
+ .pa_end = 0x4803207f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer2_slaves[] = {
+ &omap44xx_l4_per__timer2,
+};
+
+static struct omap_hwmod omap44xx_timer2_hwmod = {
+ .name = "timer2",
+ .class = &omap44xx_timer_1ms_hwmod_class,
+ .mpu_irqs = omap44xx_timer2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer2_irqs),
+ .main_clk = "timer2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer3 */
+static struct omap_hwmod omap44xx_timer3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer3_irqs[] = {
+ { .irq = 39 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer3_addrs[] = {
+ {
+ .pa_start = 0x48034000,
+ .pa_end = 0x4803407f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer3_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer3_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer3_slaves[] = {
+ &omap44xx_l4_per__timer3,
+};
+
+static struct omap_hwmod omap44xx_timer3_hwmod = {
+ .name = "timer3",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer3_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer3_irqs),
+ .main_clk = "timer3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer3_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer3_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer4 */
+static struct omap_hwmod omap44xx_timer4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer4_irqs[] = {
+ { .irq = 40 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer4_addrs[] = {
+ {
+ .pa_start = 0x48036000,
+ .pa_end = 0x4803607f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer4_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer4_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer4_slaves[] = {
+ &omap44xx_l4_per__timer4,
+};
+
+static struct omap_hwmod omap44xx_timer4_hwmod = {
+ .name = "timer4",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer4_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer4_irqs),
+ .main_clk = "timer4_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer4_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer4_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer5 */
+static struct omap_hwmod omap44xx_timer5_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer5_irqs[] = {
+ { .irq = 41 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer5_addrs[] = {
+ {
+ .pa_start = 0x40138000,
+ .pa_end = 0x4013807f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer5 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer5_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer5_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer5_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer5_dma_addrs[] = {
+ {
+ .pa_start = 0x49038000,
+ .pa_end = 0x4903807f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer5 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer5_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer5_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer5_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* timer5 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer5_slaves[] = {
+ &omap44xx_l4_abe__timer5,
+ &omap44xx_l4_abe__timer5_dma,
+};
+
+static struct omap_hwmod omap44xx_timer5_hwmod = {
+ .name = "timer5",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer5_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer5_irqs),
+ .main_clk = "timer5_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer5_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer5_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer6 */
+static struct omap_hwmod omap44xx_timer6_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer6_irqs[] = {
+ { .irq = 42 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer6_addrs[] = {
+ {
+ .pa_start = 0x4013a000,
+ .pa_end = 0x4013a07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer6 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer6_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer6_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer6_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer6_dma_addrs[] = {
+ {
+ .pa_start = 0x4903a000,
+ .pa_end = 0x4903a07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer6 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer6_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer6_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer6_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* timer6 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer6_slaves[] = {
+ &omap44xx_l4_abe__timer6,
+ &omap44xx_l4_abe__timer6_dma,
+};
+
+static struct omap_hwmod omap44xx_timer6_hwmod = {
+ .name = "timer6",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer6_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer6_irqs),
+ .main_clk = "timer6_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer6_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer6_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer7 */
+static struct omap_hwmod omap44xx_timer7_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer7_irqs[] = {
+ { .irq = 43 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer7_addrs[] = {
+ {
+ .pa_start = 0x4013c000,
+ .pa_end = 0x4013c07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer7 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer7_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer7_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer7_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer7_dma_addrs[] = {
+ {
+ .pa_start = 0x4903c000,
+ .pa_end = 0x4903c07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer7 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer7_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer7_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer7_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* timer7 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer7_slaves[] = {
+ &omap44xx_l4_abe__timer7,
+ &omap44xx_l4_abe__timer7_dma,
+};
+
+static struct omap_hwmod omap44xx_timer7_hwmod = {
+ .name = "timer7",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer7_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer7_irqs),
+ .main_clk = "timer7_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer7_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer7_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer8 */
+static struct omap_hwmod omap44xx_timer8_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer8_irqs[] = {
+ { .irq = 44 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer8_addrs[] = {
+ {
+ .pa_start = 0x4013e000,
+ .pa_end = 0x4013e07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer8 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer8_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer8_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer8_addrs),
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer8_dma_addrs[] = {
+ {
+ .pa_start = 0x4903e000,
+ .pa_end = 0x4903e07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_abe -> timer8 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer8_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer8_dma_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer8_dma_addrs),
+ .user = OCP_USER_SDMA,
+};
+
+/* timer8 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer8_slaves[] = {
+ &omap44xx_l4_abe__timer8,
+ &omap44xx_l4_abe__timer8_dma,
+};
+
+static struct omap_hwmod omap44xx_timer8_hwmod = {
+ .name = "timer8",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer8_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer8_irqs),
+ .main_clk = "timer8_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer8_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer8_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer9 */
+static struct omap_hwmod omap44xx_timer9_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer9_irqs[] = {
+ { .irq = 45 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer9_addrs[] = {
+ {
+ .pa_start = 0x4803e000,
+ .pa_end = 0x4803e07f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer9 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer9 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer9_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer9_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer9_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer9 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer9_slaves[] = {
+ &omap44xx_l4_per__timer9,
+};
+
+static struct omap_hwmod omap44xx_timer9_hwmod = {
+ .name = "timer9",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer9_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer9_irqs),
+ .main_clk = "timer9_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer9_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer9_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer10 */
+static struct omap_hwmod omap44xx_timer10_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer10_irqs[] = {
+ { .irq = 46 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer10_addrs[] = {
+ {
+ .pa_start = 0x48086000,
+ .pa_end = 0x4808607f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer10 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer10 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer10_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer10_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer10_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer10 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer10_slaves[] = {
+ &omap44xx_l4_per__timer10,
+};
+
+static struct omap_hwmod omap44xx_timer10_hwmod = {
+ .name = "timer10",
+ .class = &omap44xx_timer_1ms_hwmod_class,
+ .mpu_irqs = omap44xx_timer10_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer10_irqs),
+ .main_clk = "timer10_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer10_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer10_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* timer11 */
+static struct omap_hwmod omap44xx_timer11_hwmod;
+static struct omap_hwmod_irq_info omap44xx_timer11_irqs[] = {
+ { .irq = 47 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer11_addrs[] = {
+ {
+ .pa_start = 0x48088000,
+ .pa_end = 0x4808807f,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_per -> timer11 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer11 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer11_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer11_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_timer11_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* timer11 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_timer11_slaves[] = {
+ &omap44xx_l4_per__timer11,
+};
+
+static struct omap_hwmod omap44xx_timer11_hwmod = {
+ .name = "timer11",
+ .class = &omap44xx_timer_hwmod_class,
+ .mpu_irqs = omap44xx_timer11_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_timer11_irqs),
+ .main_clk = "timer11_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_timer11_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_timer11_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'uart' class
* universal asynchronous receiver/transmitter (uart)
*/
@@ -1870,6 +4814,88 @@ static struct omap_hwmod omap44xx_uart4_hwmod = {
};
/*
+ * 'usb_otg_hs' class
+ * high-speed on-the-go universal serial bus (usb_otg_hs) controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_otg_hs_sysc = {
+ .rev_offs = 0x0400,
+ .sysc_offs = 0x0404,
+ .syss_offs = 0x0408,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+ SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_usb_otg_hs_hwmod_class = {
+ .name = "usb_otg_hs",
+ .sysc = &omap44xx_usb_otg_hs_sysc,
+};
+
+/* usb_otg_hs */
+static struct omap_hwmod_irq_info omap44xx_usb_otg_hs_irqs[] = {
+ { .name = "mc", .irq = 92 + OMAP44XX_IRQ_GIC_START },
+ { .name = "dma", .irq = 93 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* usb_otg_hs master ports */
+static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_masters[] = {
+ &omap44xx_usb_otg_hs__l3_main_2,
+};
+
+static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
+ {
+ .pa_start = 0x4a0ab000,
+ .pa_end = 0x4a0ab003,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* l4_cfg -> usb_otg_hs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_otg_hs = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_usb_otg_hs_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_usb_otg_hs_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* usb_otg_hs slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_slaves[] = {
+ &omap44xx_l4_cfg__usb_otg_hs,
+};
+
+static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
+ { .role = "xclk", .clk = "usb_otg_hs_xclk" },
+};
+
+static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
+ .name = "usb_otg_hs",
+ .class = &omap44xx_usb_otg_hs_hwmod_class,
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .mpu_irqs = omap44xx_usb_otg_hs_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_irqs),
+ .main_clk = "usb_otg_hs_ick",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+ },
+ },
+ .opt_clks = usb_otg_hs_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(usb_otg_hs_opt_clks),
+ .slaves = omap44xx_usb_otg_hs_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_slaves),
+ .masters = omap44xx_usb_otg_hs_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_masters),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
* 'wd_timer' class
* 32-bit watchdog upward counter that generates a pulse on the reset pin on
* overflow condition
@@ -2024,13 +5050,34 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
/* mpu_bus class */
&omap44xx_mpu_private_hwmod,
+ /* aess class */
+/* &omap44xx_aess_hwmod, */
+
+ /* bandgap class */
+ &omap44xx_bandgap_hwmod,
+
+ /* counter class */
+/* &omap44xx_counter_32k_hwmod, */
+
/* dma class */
&omap44xx_dma_system_hwmod,
+ /* dmic class */
+ &omap44xx_dmic_hwmod,
+
/* dsp class */
&omap44xx_dsp_hwmod,
&omap44xx_dsp_c0_hwmod,
+ /* dss class */
+ &omap44xx_dss_hwmod,
+ &omap44xx_dss_dispc_hwmod,
+ &omap44xx_dss_dsi1_hwmod,
+ &omap44xx_dss_dsi2_hwmod,
+ &omap44xx_dss_hdmi_hwmod,
+ &omap44xx_dss_rfbi_hwmod,
+ &omap44xx_dss_venc_hwmod,
+
/* gpio class */
&omap44xx_gpio1_hwmod,
&omap44xx_gpio2_hwmod,
@@ -2039,17 +5086,56 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_gpio5_hwmod,
&omap44xx_gpio6_hwmod,
+ /* hsi class */
+/* &omap44xx_hsi_hwmod, */
+
/* i2c class */
&omap44xx_i2c1_hwmod,
&omap44xx_i2c2_hwmod,
&omap44xx_i2c3_hwmod,
&omap44xx_i2c4_hwmod,
+ /* ipu class */
+ &omap44xx_ipu_hwmod,
+ &omap44xx_ipu_c0_hwmod,
+ &omap44xx_ipu_c1_hwmod,
+
+ /* iss class */
+/* &omap44xx_iss_hwmod, */
+
/* iva class */
&omap44xx_iva_hwmod,
&omap44xx_iva_seq0_hwmod,
&omap44xx_iva_seq1_hwmod,
+ /* kbd class */
+/* &omap44xx_kbd_hwmod, */
+
+ /* mailbox class */
+ &omap44xx_mailbox_hwmod,
+
+ /* mcbsp class */
+ &omap44xx_mcbsp1_hwmod,
+ &omap44xx_mcbsp2_hwmod,
+ &omap44xx_mcbsp3_hwmod,
+ &omap44xx_mcbsp4_hwmod,
+
+ /* mcpdm class */
+/* &omap44xx_mcpdm_hwmod, */
+
+ /* mcspi class */
+ &omap44xx_mcspi1_hwmod,
+ &omap44xx_mcspi2_hwmod,
+ &omap44xx_mcspi3_hwmod,
+ &omap44xx_mcspi4_hwmod,
+
+ /* mmc class */
+ &omap44xx_mmc1_hwmod,
+ &omap44xx_mmc2_hwmod,
+ &omap44xx_mmc3_hwmod,
+ &omap44xx_mmc4_hwmod,
+ &omap44xx_mmc5_hwmod,
+
/* mpu class */
&omap44xx_mpu_hwmod,
@@ -2058,12 +5144,31 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_smartreflex_iva_hwmod,
&omap44xx_smartreflex_mpu_hwmod,
+ /* spinlock class */
+ &omap44xx_spinlock_hwmod,
+
+ /* timer class */
+ &omap44xx_timer1_hwmod,
+ &omap44xx_timer2_hwmod,
+ &omap44xx_timer3_hwmod,
+ &omap44xx_timer4_hwmod,
+ &omap44xx_timer5_hwmod,
+ &omap44xx_timer6_hwmod,
+ &omap44xx_timer7_hwmod,
+ &omap44xx_timer8_hwmod,
+ &omap44xx_timer9_hwmod,
+ &omap44xx_timer10_hwmod,
+ &omap44xx_timer11_hwmod,
+
/* uart class */
&omap44xx_uart1_hwmod,
&omap44xx_uart2_hwmod,
&omap44xx_uart3_hwmod,
&omap44xx_uart4_hwmod,
+ /* usb_otg_hs class */
+ &omap44xx_usb_otg_hs_hwmod,
+
/* wd_timer class */
&omap44xx_wd_timer2_hwmod,
&omap44xx_wd_timer3_hwmod,
@@ -2073,6 +5178,6 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
int __init omap44xx_hwmod_init(void)
{
- return omap_hwmod_init(omap44xx_hwmods);
+ return omap_hwmod_register(omap44xx_hwmods);
}
diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c
new file mode 100644
index 000000000000..82632c24076f
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_l3_noc.c
@@ -0,0 +1,253 @@
+/*
+ * OMAP4XXX L3 Interconnect error handling driver
+ *
+ * Copyright (C) 2011 Texas Corporation
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Sricharan <r.sricharan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "omap_l3_noc.h"
+
+/*
+ * Interrupt Handler for L3 error detection.
+ * 1) Identify the L3 clockdomain partition to which the error belongs to.
+ * 2) Identify the slave where the error information is logged
+ * 3) Print the logged information.
+ * 4) Add dump stack to provide kernel trace.
+ *
+ * Two Types of errors :
+ * 1) Custom errors in L3 :
+ * Target like DMM/FW/EMIF generates SRESP=ERR error
+ * 2) Standard L3 error:
+ * - Unsupported CMD.
+ * L3 tries to access target while it is idle
+ * - OCP disconnect.
+ * - Address hole error:
+ * If DSS/ISS/FDIF/USBHOSTFS access a target where they
+ * do not have connectivity, the error is logged in
+ * their default target which is DMM2.
+ *
+ * On High Secure devices, firewall errors are possible and those
+ * can be trapped as well. But the trapping is implemented as part
+ * secure software and hence need not be implemented here.
+ */
+static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
+{
+
+ struct omap4_l3 *l3 = _l3;
+ int inttype, i, j;
+ int err_src = 0;
+ u32 std_err_main_addr, std_err_main, err_reg;
+ u32 base, slave_addr, clear;
+ char *source_name;
+
+ /* Get the Type of interrupt */
+ if (irq == l3->app_irq)
+ inttype = L3_APPLICATION_ERROR;
+ else
+ inttype = L3_DEBUG_ERROR;
+
+ for (i = 0; i < L3_MODULES; i++) {
+ /*
+ * Read the regerr register of the clock domain
+ * to determine the source
+ */
+ base = (u32)l3->l3_base[i];
+ err_reg = readl(base + l3_flagmux[i] + (inttype << 3));
+
+ /* Get the corresponding error and analyse */
+ if (err_reg) {
+ /* Identify the source from control status register */
+ for (j = 0; !(err_reg & (1 << j)); j++)
+ ;
+
+ err_src = j;
+ /* Read the stderrlog_main_source from clk domain */
+ std_err_main_addr = base + (*(l3_targ[i] + err_src));
+ std_err_main = readl(std_err_main_addr);
+
+ switch ((std_err_main & CUSTOM_ERROR)) {
+ case STANDARD_ERROR:
+ source_name =
+ l3_targ_stderrlog_main_name[i][err_src];
+
+ slave_addr = std_err_main_addr +
+ L3_SLAVE_ADDRESS_OFFSET;
+ WARN(true, "L3 standard error: SOURCE:%s at address 0x%x\n",
+ source_name, readl(slave_addr));
+ /* clear the std error log*/
+ clear = std_err_main | CLEAR_STDERR_LOG;
+ writel(clear, std_err_main_addr);
+ break;
+
+ case CUSTOM_ERROR:
+ source_name =
+ l3_targ_stderrlog_main_name[i][err_src];
+
+ WARN(true, "CUSTOM SRESP error with SOURCE:%s\n",
+ source_name);
+ /* clear the std error log*/
+ clear = std_err_main | CLEAR_STDERR_LOG;
+ writel(clear, std_err_main_addr);
+ break;
+
+ default:
+ /* Nothing to be handled here as of now */
+ break;
+ }
+ /* Error found so break the for loop */
+ break;
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int __init omap4_l3_probe(struct platform_device *pdev)
+{
+ static struct omap4_l3 *l3;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
+ if (!l3)
+ ret = -ENOMEM;
+
+ platform_set_drvdata(pdev, l3);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "couldn't find resource 0\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ l3->l3_base[0] = ioremap(res->start, resource_size(res));
+ if (!(l3->l3_base[0])) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "couldn't find resource 1\n");
+ ret = -ENODEV;
+ goto err3;
+ }
+
+ l3->l3_base[1] = ioremap(res->start, resource_size(res));
+ if (!(l3->l3_base[1])) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res) {
+ dev_err(&pdev->dev, "couldn't find resource 2\n");
+ ret = -ENODEV;
+ goto err5;
+ }
+
+ l3->l3_base[2] = ioremap(res->start, resource_size(res));
+ if (!(l3->l3_base[2])) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err6;
+ }
+
+ /*
+ * Setup interrupt Handlers
+ */
+ irq = platform_get_irq(pdev, 0);
+ ret = request_irq(irq,
+ l3_interrupt_handler,
+ IRQF_DISABLED, "l3-dbg-irq", l3);
+ if (ret) {
+ pr_crit("L3: request_irq failed to register for 0x%x\n",
+ OMAP44XX_IRQ_L3_DBG);
+ goto err7;
+ }
+ l3->debug_irq = irq;
+
+ irq = platform_get_irq(pdev, 1);
+ ret = request_irq(irq,
+ l3_interrupt_handler,
+ IRQF_DISABLED, "l3-app-irq", l3);
+ if (ret) {
+ pr_crit("L3: request_irq failed to register for 0x%x\n",
+ OMAP44XX_IRQ_L3_APP);
+ goto err8;
+ }
+ l3->app_irq = irq;
+
+ goto err0;
+err8:
+err7:
+ iounmap(l3->l3_base[2]);
+err6:
+err5:
+ iounmap(l3->l3_base[1]);
+err4:
+err3:
+ iounmap(l3->l3_base[0]);
+err2:
+err1:
+ kfree(l3);
+err0:
+ return ret;
+}
+
+static int __exit omap4_l3_remove(struct platform_device *pdev)
+{
+ struct omap4_l3 *l3 = platform_get_drvdata(pdev);
+
+ free_irq(l3->app_irq, l3);
+ free_irq(l3->debug_irq, l3);
+ iounmap(l3->l3_base[0]);
+ iounmap(l3->l3_base[1]);
+ iounmap(l3->l3_base[2]);
+ kfree(l3);
+
+ return 0;
+}
+
+static struct platform_driver omap4_l3_driver = {
+ .remove = __exit_p(omap4_l3_remove),
+ .driver = {
+ .name = "omap_l3_noc",
+ },
+};
+
+static int __init omap4_l3_init(void)
+{
+ return platform_driver_probe(&omap4_l3_driver, omap4_l3_probe);
+}
+postcore_initcall_sync(omap4_l3_init);
+
+static void __exit omap4_l3_exit(void)
+{
+ platform_driver_unregister(&omap4_l3_driver);
+}
+module_exit(omap4_l3_exit);
diff --git a/arch/arm/mach-omap2/omap_l3_noc.h b/arch/arm/mach-omap2/omap_l3_noc.h
new file mode 100644
index 000000000000..359b83348aed
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_l3_noc.h
@@ -0,0 +1,132 @@
+ /*
+ * OMAP4XXX L3 Interconnect error handling driver header
+ *
+ * Copyright (C) 2011 Texas Corporation
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * sricharan <r.sricharan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H
+#define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H
+
+/*
+ * L3 register offsets
+ */
+#define L3_MODULES 3
+#define CLEAR_STDERR_LOG (1 << 31)
+#define CUSTOM_ERROR 0x2
+#define STANDARD_ERROR 0x0
+#define INBAND_ERROR 0x0
+#define EMIF_KERRLOG_OFFSET 0x10
+#define L3_SLAVE_ADDRESS_OFFSET 0x14
+#define LOGICAL_ADDR_ERRORLOG 0x4
+#define L3_APPLICATION_ERROR 0x0
+#define L3_DEBUG_ERROR 0x1
+
+u32 l3_flagmux[L3_MODULES] = {
+ 0x50C,
+ 0x100C,
+ 0X020C
+};
+
+/*
+ * L3 Target standard Error register offsets
+ */
+u32 l3_targ_stderrlog_main_clk1[] = {
+ 0x148, /* DMM1 */
+ 0x248, /* DMM2 */
+ 0x348, /* ABE */
+ 0x448, /* L4CFG */
+ 0x648 /* CLK2 PWR DISC */
+};
+
+u32 l3_targ_stderrlog_main_clk2[] = {
+ 0x548, /* CORTEX M3 */
+ 0x348, /* DSS */
+ 0x148, /* GPMC */
+ 0x448, /* ISS */
+ 0x748, /* IVAHD */
+ 0xD48, /* missing in TRM corresponds to AES1*/
+ 0x948, /* L4 PER0*/
+ 0x248, /* OCMRAM */
+ 0x148, /* missing in TRM corresponds to GPMC sERROR*/
+ 0x648, /* SGX */
+ 0x848, /* SL2 */
+ 0x1648, /* C2C */
+ 0x1148, /* missing in TRM corresponds PWR DISC CLK1*/
+ 0xF48, /* missing in TRM corrsponds to SHA1*/
+ 0xE48, /* missing in TRM corresponds to AES2*/
+ 0xC48, /* L4 PER3 */
+ 0xA48, /* L4 PER1*/
+ 0xB48 /* L4 PER2*/
+};
+
+u32 l3_targ_stderrlog_main_clk3[] = {
+ 0x0148 /* EMUSS */
+};
+
+char *l3_targ_stderrlog_main_name[L3_MODULES][18] = {
+ {
+ "DMM1",
+ "DMM2",
+ "ABE",
+ "L4CFG",
+ "CLK2 PWR DISC",
+ },
+ {
+ "CORTEX M3" ,
+ "DSS ",
+ "GPMC ",
+ "ISS ",
+ "IVAHD ",
+ "AES1",
+ "L4 PER0",
+ "OCMRAM ",
+ "GPMC sERROR",
+ "SGX ",
+ "SL2 ",
+ "C2C ",
+ "PWR DISC CLK1",
+ "SHA1",
+ "AES2",
+ "L4 PER3",
+ "L4 PER1",
+ "L4 PER2",
+ },
+ {
+ "EMUSS",
+ },
+};
+
+u32 *l3_targ[L3_MODULES] = {
+ l3_targ_stderrlog_main_clk1,
+ l3_targ_stderrlog_main_clk2,
+ l3_targ_stderrlog_main_clk3,
+};
+
+struct omap4_l3 {
+ struct device *dev;
+ struct clk *ick;
+
+ /* memory base */
+ void __iomem *l3_base[4];
+
+ int debug_irq;
+ int app_irq;
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c
new file mode 100644
index 000000000000..265bff3acb9e
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_l3_smx.c
@@ -0,0 +1,314 @@
+ /*
+ * OMAP3XXX L3 Interconnect Driver
+ *
+ * Copyright (C) 2011 Texas Corporation
+ * Felipe Balbi <balbi@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Sricharan <r.sricharan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include "omap_l3_smx.h"
+
+static inline u64 omap3_l3_readll(void __iomem *base, u16 reg)
+{
+ return __raw_readll(base + reg);
+}
+
+static inline void omap3_l3_writell(void __iomem *base, u16 reg, u64 value)
+{
+ __raw_writell(value, base + reg);
+}
+
+static inline enum omap3_l3_code omap3_l3_decode_error_code(u64 error)
+{
+ return (error & 0x0f000000) >> L3_ERROR_LOG_CODE;
+}
+
+static inline u32 omap3_l3_decode_addr(u64 error_addr)
+{
+ return error_addr & 0xffffffff;
+}
+
+static inline unsigned omap3_l3_decode_cmd(u64 error)
+{
+ return (error & 0x07) >> L3_ERROR_LOG_CMD;
+}
+
+static inline enum omap3_l3_initiator_id omap3_l3_decode_initid(u64 error)
+{
+ return (error & 0xff00) >> L3_ERROR_LOG_INITID;
+}
+
+static inline unsigned omap3_l3_decode_req_info(u64 error)
+{
+ return (error >> 32) & 0xffff;
+}
+
+static char *omap3_l3_code_string(u8 code)
+{
+ switch (code) {
+ case OMAP_L3_CODE_NOERROR:
+ return "No Error";
+ case OMAP_L3_CODE_UNSUP_CMD:
+ return "Unsupported Command";
+ case OMAP_L3_CODE_ADDR_HOLE:
+ return "Address Hole";
+ case OMAP_L3_CODE_PROTECT_VIOLATION:
+ return "Protection Violation";
+ case OMAP_L3_CODE_IN_BAND_ERR:
+ return "In-band Error";
+ case OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT:
+ return "Request Timeout Not Accepted";
+ case OMAP_L3_CODE_REQ_TOUT_NO_RESP:
+ return "Request Timeout, no response";
+ default:
+ return "UNKNOWN error";
+ }
+}
+
+static char *omap3_l3_initiator_string(u8 initid)
+{
+ switch (initid) {
+ case OMAP_L3_LCD:
+ return "LCD";
+ case OMAP_L3_SAD2D:
+ return "SAD2D";
+ case OMAP_L3_IA_MPU_SS_1:
+ case OMAP_L3_IA_MPU_SS_2:
+ case OMAP_L3_IA_MPU_SS_3:
+ case OMAP_L3_IA_MPU_SS_4:
+ case OMAP_L3_IA_MPU_SS_5:
+ return "MPU";
+ case OMAP_L3_IA_IVA_SS_1:
+ case OMAP_L3_IA_IVA_SS_2:
+ case OMAP_L3_IA_IVA_SS_3:
+ return "IVA_SS";
+ case OMAP_L3_IA_IVA_SS_DMA_1:
+ case OMAP_L3_IA_IVA_SS_DMA_2:
+ case OMAP_L3_IA_IVA_SS_DMA_3:
+ case OMAP_L3_IA_IVA_SS_DMA_4:
+ case OMAP_L3_IA_IVA_SS_DMA_5:
+ case OMAP_L3_IA_IVA_SS_DMA_6:
+ return "IVA_SS_DMA";
+ case OMAP_L3_IA_SGX:
+ return "SGX";
+ case OMAP_L3_IA_CAM_1:
+ case OMAP_L3_IA_CAM_2:
+ case OMAP_L3_IA_CAM_3:
+ return "CAM";
+ case OMAP_L3_IA_DAP:
+ return "DAP";
+ case OMAP_L3_SDMA_WR_1:
+ case OMAP_L3_SDMA_WR_2:
+ return "SDMA_WR";
+ case OMAP_L3_SDMA_RD_1:
+ case OMAP_L3_SDMA_RD_2:
+ case OMAP_L3_SDMA_RD_3:
+ case OMAP_L3_SDMA_RD_4:
+ return "SDMA_RD";
+ case OMAP_L3_USBOTG:
+ return "USB_OTG";
+ case OMAP_L3_USBHOST:
+ return "USB_HOST";
+ default:
+ return "UNKNOWN Initiator";
+ }
+}
+
+/**
+ * omap3_l3_block_irq - handles a register block's irq
+ * @l3: struct omap3_l3 *
+ * @base: register block base address
+ * @error: L3_ERROR_LOG register of our block
+ *
+ * Called in hard-irq context. Caller should take care of locking
+ *
+ * OMAP36xx TRM gives, on page 2001, Figure 9-10, the Typical Error
+ * Analysis Sequence, we are following that sequence here, please
+ * refer to that Figure for more information on the subject.
+ */
+static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
+ u64 error, int error_addr)
+{
+ u8 code = omap3_l3_decode_error_code(error);
+ u8 initid = omap3_l3_decode_initid(error);
+ u8 multi = error & L3_ERROR_LOG_MULTI;
+ u32 address = omap3_l3_decode_addr(error_addr);
+
+ WARN(true, "%s Error seen by %s %s at address %x\n",
+ omap3_l3_code_string(code),
+ omap3_l3_initiator_string(initid),
+ multi ? "Multiple Errors" : "",
+ address);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
+{
+ struct omap3_l3 *l3 = _l3;
+
+ u64 status, clear;
+ u64 error;
+ u64 error_addr;
+ u64 err_source = 0;
+ void __iomem *base;
+ int int_type;
+
+ irqreturn_t ret = IRQ_NONE;
+
+ if (irq == l3->app_irq)
+ int_type = L3_APPLICATION_ERROR;
+ else
+ int_type = L3_DEBUG_ERROR;
+
+ if (!int_type) {
+ status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0);
+ /*
+ * if we have a timeout error, there's nothing we can
+ * do besides rebooting the board. So let's BUG on any
+ * of such errors and handle the others. timeout error
+ * is severe and not expected to occur.
+ */
+ BUG_ON(status & L3_STATUS_0_TIMEOUT_MASK);
+ } else {
+ status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_1);
+ /* No timeout error for debug sources */
+ }
+
+ base = ((l3->rt) + (*(omap3_l3_bases[int_type] + err_source)));
+
+ /* identify the error source */
+ for (err_source = 0; !(status & (1 << err_source)); err_source++)
+ ;
+ error = omap3_l3_readll(base, L3_ERROR_LOG);
+
+ if (error) {
+ error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR);
+
+ ret |= omap3_l3_block_irq(l3, error, error_addr);
+ }
+
+ /* Clear the status register */
+ clear = ((L3_AGENT_STATUS_CLEAR_IA << int_type) |
+ (L3_AGENT_STATUS_CLEAR_TA));
+
+ omap3_l3_writell(base, L3_AGENT_STATUS, clear);
+
+ /* clear the error log register */
+ omap3_l3_writell(base, L3_ERROR_LOG, error);
+
+ return ret;
+}
+
+static int __init omap3_l3_probe(struct platform_device *pdev)
+{
+ struct omap3_l3 *l3;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
+ if (!l3) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ platform_set_drvdata(pdev, l3);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "couldn't find resource\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+ l3->rt = ioremap(res->start, resource_size(res));
+ if (!(l3->rt)) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ ret = request_irq(irq, omap3_l3_app_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "l3-debug-irq", l3);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't request debug irq\n");
+ goto err3;
+ }
+ l3->debug_irq = irq;
+
+ irq = platform_get_irq(pdev, 1);
+ ret = request_irq(irq, omap3_l3_app_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "l3-app-irq", l3);
+
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't request app irq\n");
+ goto err4;
+ }
+
+ l3->app_irq = irq;
+ goto err0;
+
+err4:
+err3:
+ iounmap(l3->rt);
+err2:
+err1:
+ kfree(l3);
+err0:
+ return ret;
+}
+
+static int __exit omap3_l3_remove(struct platform_device *pdev)
+{
+ struct omap3_l3 *l3 = platform_get_drvdata(pdev);
+
+ free_irq(l3->app_irq, l3);
+ free_irq(l3->debug_irq, l3);
+ iounmap(l3->rt);
+ kfree(l3);
+
+ return 0;
+}
+
+static struct platform_driver omap3_l3_driver = {
+ .remove = __exit_p(omap3_l3_remove),
+ .driver = {
+ .name = "omap_l3_smx",
+ },
+};
+
+static int __init omap3_l3_init(void)
+{
+ return platform_driver_probe(&omap3_l3_driver, omap3_l3_probe);
+}
+postcore_initcall_sync(omap3_l3_init);
+
+static void __exit omap3_l3_exit(void)
+{
+ platform_driver_unregister(&omap3_l3_driver);
+}
+module_exit(omap3_l3_exit);
diff --git a/arch/arm/mach-omap2/omap_l3_smx.h b/arch/arm/mach-omap2/omap_l3_smx.h
new file mode 100644
index 000000000000..ba2ed9a850cc
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_l3_smx.h
@@ -0,0 +1,338 @@
+ /*
+ * OMAP3XXX L3 Interconnect Driver header
+ *
+ * Copyright (C) 2011 Texas Corporation
+ * Felipe Balbi <balbi@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * sricharan <r.sricharan@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H
+#define __ARCH_ARM_MACH_OMAP2_L3_INTERCONNECT_3XXX_H
+
+/* Register definitions. All 64-bit wide */
+#define L3_COMPONENT 0x000
+#define L3_CORE 0x018
+#define L3_AGENT_CONTROL 0x020
+#define L3_AGENT_STATUS 0x028
+#define L3_ERROR_LOG 0x058
+
+#define L3_ERROR_LOG_MULTI (1 << 31)
+#define L3_ERROR_LOG_SECONDARY (1 << 30)
+
+#define L3_ERROR_LOG_ADDR 0x060
+
+/* Register definitions for Sideband Interconnect */
+#define L3_SI_CONTROL 0x020
+#define L3_SI_FLAG_STATUS_0 0x510
+
+const u64 shift = 1;
+
+#define L3_STATUS_0_MPUIA_BRST (shift << 0)
+#define L3_STATUS_0_MPUIA_RSP (shift << 1)
+#define L3_STATUS_0_MPUIA_INBAND (shift << 2)
+#define L3_STATUS_0_IVAIA_BRST (shift << 6)
+#define L3_STATUS_0_IVAIA_RSP (shift << 7)
+#define L3_STATUS_0_IVAIA_INBAND (shift << 8)
+#define L3_STATUS_0_SGXIA_BRST (shift << 9)
+#define L3_STATUS_0_SGXIA_RSP (shift << 10)
+#define L3_STATUS_0_SGXIA_MERROR (shift << 11)
+#define L3_STATUS_0_CAMIA_BRST (shift << 12)
+#define L3_STATUS_0_CAMIA_RSP (shift << 13)
+#define L3_STATUS_0_CAMIA_INBAND (shift << 14)
+#define L3_STATUS_0_DISPIA_BRST (shift << 15)
+#define L3_STATUS_0_DISPIA_RSP (shift << 16)
+#define L3_STATUS_0_DMARDIA_BRST (shift << 18)
+#define L3_STATUS_0_DMARDIA_RSP (shift << 19)
+#define L3_STATUS_0_DMAWRIA_BRST (shift << 21)
+#define L3_STATUS_0_DMAWRIA_RSP (shift << 22)
+#define L3_STATUS_0_USBOTGIA_BRST (shift << 24)
+#define L3_STATUS_0_USBOTGIA_RSP (shift << 25)
+#define L3_STATUS_0_USBOTGIA_INBAND (shift << 26)
+#define L3_STATUS_0_USBHOSTIA_BRST (shift << 27)
+#define L3_STATUS_0_USBHOSTIA_INBAND (shift << 28)
+#define L3_STATUS_0_SMSTA_REQ (shift << 48)
+#define L3_STATUS_0_GPMCTA_REQ (shift << 49)
+#define L3_STATUS_0_OCMRAMTA_REQ (shift << 50)
+#define L3_STATUS_0_OCMROMTA_REQ (shift << 51)
+#define L3_STATUS_0_IVATA_REQ (shift << 54)
+#define L3_STATUS_0_SGXTA_REQ (shift << 55)
+#define L3_STATUS_0_SGXTA_SERROR (shift << 56)
+#define L3_STATUS_0_GPMCTA_SERROR (shift << 57)
+#define L3_STATUS_0_L4CORETA_REQ (shift << 58)
+#define L3_STATUS_0_L4PERTA_REQ (shift << 59)
+#define L3_STATUS_0_L4EMUTA_REQ (shift << 60)
+#define L3_STATUS_0_MAD2DTA_REQ (shift << 61)
+
+#define L3_STATUS_0_TIMEOUT_MASK (L3_STATUS_0_MPUIA_BRST \
+ | L3_STATUS_0_MPUIA_RSP \
+ | L3_STATUS_0_IVAIA_BRST \
+ | L3_STATUS_0_IVAIA_RSP \
+ | L3_STATUS_0_SGXIA_BRST \
+ | L3_STATUS_0_SGXIA_RSP \
+ | L3_STATUS_0_CAMIA_BRST \
+ | L3_STATUS_0_CAMIA_RSP \
+ | L3_STATUS_0_DISPIA_BRST \
+ | L3_STATUS_0_DISPIA_RSP \
+ | L3_STATUS_0_DMARDIA_BRST \
+ | L3_STATUS_0_DMARDIA_RSP \
+ | L3_STATUS_0_DMAWRIA_BRST \
+ | L3_STATUS_0_DMAWRIA_RSP \
+ | L3_STATUS_0_USBOTGIA_BRST \
+ | L3_STATUS_0_USBOTGIA_RSP \
+ | L3_STATUS_0_USBHOSTIA_BRST \
+ | L3_STATUS_0_SMSTA_REQ \
+ | L3_STATUS_0_GPMCTA_REQ \
+ | L3_STATUS_0_OCMRAMTA_REQ \
+ | L3_STATUS_0_OCMROMTA_REQ \
+ | L3_STATUS_0_IVATA_REQ \
+ | L3_STATUS_0_SGXTA_REQ \
+ | L3_STATUS_0_L4CORETA_REQ \
+ | L3_STATUS_0_L4PERTA_REQ \
+ | L3_STATUS_0_L4EMUTA_REQ \
+ | L3_STATUS_0_MAD2DTA_REQ)
+
+#define L3_SI_FLAG_STATUS_1 0x530
+
+#define L3_STATUS_1_MPU_DATAIA (1 << 0)
+#define L3_STATUS_1_DAPIA0 (1 << 3)
+#define L3_STATUS_1_DAPIA1 (1 << 4)
+#define L3_STATUS_1_IVAIA (1 << 6)
+
+#define L3_PM_ERROR_LOG 0x020
+#define L3_PM_CONTROL 0x028
+#define L3_PM_ERROR_CLEAR_SINGLE 0x030
+#define L3_PM_ERROR_CLEAR_MULTI 0x038
+#define L3_PM_REQ_INFO_PERMISSION(n) (0x048 + (0x020 * n))
+#define L3_PM_READ_PERMISSION(n) (0x050 + (0x020 * n))
+#define L3_PM_WRITE_PERMISSION(n) (0x058 + (0x020 * n))
+#define L3_PM_ADDR_MATCH(n) (0x060 + (0x020 * n))
+
+/* L3 error log bit fields. Common for IA and TA */
+#define L3_ERROR_LOG_CODE 24
+#define L3_ERROR_LOG_INITID 8
+#define L3_ERROR_LOG_CMD 0
+
+/* L3 agent status bit fields. */
+#define L3_AGENT_STATUS_CLEAR_IA 0x10000000
+#define L3_AGENT_STATUS_CLEAR_TA 0x01000000
+
+#define OMAP34xx_IRQ_L3_APP 10
+#define L3_APPLICATION_ERROR 0x0
+#define L3_DEBUG_ERROR 0x1
+
+enum omap3_l3_initiator_id {
+ /* LCD has 1 ID */
+ OMAP_L3_LCD = 29,
+ /* SAD2D has 1 ID */
+ OMAP_L3_SAD2D = 28,
+ /* MPU has 5 IDs */
+ OMAP_L3_IA_MPU_SS_1 = 27,
+ OMAP_L3_IA_MPU_SS_2 = 26,
+ OMAP_L3_IA_MPU_SS_3 = 25,
+ OMAP_L3_IA_MPU_SS_4 = 24,
+ OMAP_L3_IA_MPU_SS_5 = 23,
+ /* IVA2.2 SS has 3 IDs*/
+ OMAP_L3_IA_IVA_SS_1 = 22,
+ OMAP_L3_IA_IVA_SS_2 = 21,
+ OMAP_L3_IA_IVA_SS_3 = 20,
+ /* IVA 2.2 SS DMA has 6 IDS */
+ OMAP_L3_IA_IVA_SS_DMA_1 = 19,
+ OMAP_L3_IA_IVA_SS_DMA_2 = 18,
+ OMAP_L3_IA_IVA_SS_DMA_3 = 17,
+ OMAP_L3_IA_IVA_SS_DMA_4 = 16,
+ OMAP_L3_IA_IVA_SS_DMA_5 = 15,
+ OMAP_L3_IA_IVA_SS_DMA_6 = 14,
+ /* SGX has 1 ID */
+ OMAP_L3_IA_SGX = 13,
+ /* CAM has 3 ID */
+ OMAP_L3_IA_CAM_1 = 12,
+ OMAP_L3_IA_CAM_2 = 11,
+ OMAP_L3_IA_CAM_3 = 10,
+ /* DAP has 1 ID */
+ OMAP_L3_IA_DAP = 9,
+ /* SDMA WR has 2 IDs */
+ OMAP_L3_SDMA_WR_1 = 8,
+ OMAP_L3_SDMA_WR_2 = 7,
+ /* SDMA RD has 4 IDs */
+ OMAP_L3_SDMA_RD_1 = 6,
+ OMAP_L3_SDMA_RD_2 = 5,
+ OMAP_L3_SDMA_RD_3 = 4,
+ OMAP_L3_SDMA_RD_4 = 3,
+ /* HSUSB OTG has 1 ID */
+ OMAP_L3_USBOTG = 2,
+ /* HSUSB HOST has 1 ID */
+ OMAP_L3_USBHOST = 1,
+};
+
+enum omap3_l3_code {
+ OMAP_L3_CODE_NOERROR = 0,
+ OMAP_L3_CODE_UNSUP_CMD = 1,
+ OMAP_L3_CODE_ADDR_HOLE = 2,
+ OMAP_L3_CODE_PROTECT_VIOLATION = 3,
+ OMAP_L3_CODE_IN_BAND_ERR = 4,
+ /* codes 5 and 6 are reserved */
+ OMAP_L3_CODE_REQ_TOUT_NOT_ACCEPT = 7,
+ OMAP_L3_CODE_REQ_TOUT_NO_RESP = 8,
+ /* codes 9 - 15 are also reserved */
+};
+
+struct omap3_l3 {
+ struct device *dev;
+ struct clk *ick;
+
+ /* memory base*/
+ void __iomem *rt;
+
+ int debug_irq;
+ int app_irq;
+
+ /* true when and inband functional error occurs */
+ unsigned inband:1;
+};
+
+/* offsets for l3 agents in order with the Flag status register */
+unsigned int __iomem omap3_l3_app_bases[] = {
+ /* MPU IA */
+ 0x1400,
+ 0x1400,
+ 0x1400,
+ /* RESERVED */
+ 0,
+ 0,
+ 0,
+ /* IVA 2.2 IA */
+ 0x1800,
+ 0x1800,
+ 0x1800,
+ /* SGX IA */
+ 0x1c00,
+ 0x1c00,
+ /* RESERVED */
+ 0,
+ /* CAMERA IA */
+ 0x5800,
+ 0x5800,
+ 0x5800,
+ /* DISPLAY IA */
+ 0x5400,
+ 0x5400,
+ /* RESERVED */
+ 0,
+ /*SDMA RD IA */
+ 0x4c00,
+ 0x4c00,
+ /* RESERVED */
+ 0,
+ /* SDMA WR IA */
+ 0x5000,
+ 0x5000,
+ /* RESERVED */
+ 0,
+ /* USB OTG IA */
+ 0x4400,
+ 0x4400,
+ 0x4400,
+ /* USB HOST IA */
+ 0x4000,
+ 0x4000,
+ /* RESERVED */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* SAD2D IA */
+ 0x3000,
+ 0x3000,
+ 0x3000,
+ /* RESERVED */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ /* SMA TA */
+ 0x2000,
+ /* GPMC TA */
+ 0x2400,
+ /* OCM RAM TA */
+ 0x2800,
+ /* OCM ROM TA */
+ 0x2C00,
+ /* L4 CORE TA */
+ 0x6800,
+ /* L4 PER TA */
+ 0x6c00,
+ /* IVA 2.2 TA */
+ 0x6000,
+ /* SGX TA */
+ 0x6400,
+ /* L4 EMU TA */
+ 0x7000,
+ /* GPMC TA */
+ 0x2400,
+ /* L4 CORE TA */
+ 0x6800,
+ /* L4 PER TA */
+ 0x6c00,
+ /* L4 EMU TA */
+ 0x7000,
+ /* MAD2D TA */
+ 0x3400,
+ /* RESERVED */
+ 0,
+ 0,
+};
+
+unsigned int __iomem omap3_l3_debug_bases[] = {
+ /* MPU DATA IA */
+ 0x1400,
+ /* RESERVED */
+ 0,
+ 0,
+ /* DAP IA */
+ 0x5c00,
+ 0x5c00,
+ /* RESERVED */
+ 0,
+ /* IVA 2.2 IA */
+ 0x1800,
+ /* REST RESERVED */
+};
+
+u32 *omap3_l3_bases[] = {
+ omap3_l3_app_bases,
+ omap3_l3_debug_bases,
+};
+
+/*
+ * REVISIT define __raw_readll/__raw_writell here, but move them to
+ * <asm/io.h> at some point
+ */
+#define __raw_writell(v, a) (__chk_io_ptr(a), \
+ *(volatile u64 __force *)(a) = (v))
+#define __raw_readll(a) (__chk_io_ptr(a), \
+ *(volatile u64 __force *)(a))
+
+#endif
diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h
index 46ac27dd6c84..c784c12f98a1 100644
--- a/arch/arm/mach-omap2/omap_opp_data.h
+++ b/arch/arm/mach-omap2/omap_opp_data.h
@@ -21,6 +21,8 @@
#include <plat/omap_hwmod.h>
+#include "voltage.h"
+
/*
* *BIG FAT WARNING*:
* USE the following ONLY in opp data initialization common to an SoC.
@@ -65,8 +67,30 @@ struct omap_opp_def {
.u_volt = _uv, \
}
+/*
+ * Initialization wrapper used to define SmartReflex process data
+ * XXX Is this needed? Just use C99 initializers in data files?
+ */
+#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \
+{ \
+ .volt_nominal = _v_nom, \
+ .sr_efuse_offs = _efuse_offs, \
+ .sr_errminlimit = _errminlimit, \
+ .vp_errgain = _errgain \
+}
+
/* Use this to initialize the default table */
extern int __init omap_init_opp_table(struct omap_opp_def *opp_def,
u32 opp_def_size);
+
+extern struct omap_volt_data omap34xx_vddmpu_volt_data[];
+extern struct omap_volt_data omap34xx_vddcore_volt_data[];
+extern struct omap_volt_data omap36xx_vddmpu_volt_data[];
+extern struct omap_volt_data omap36xx_vddcore_volt_data[];
+
+extern struct omap_volt_data omap44xx_vdd_mpu_volt_data[];
+extern struct omap_volt_data omap44xx_vdd_iva_volt_data[];
+extern struct omap_volt_data omap44xx_vdd_core_volt_data[];
+
#endif /* __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H */
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index ebe33df708bd..e2e605fe9138 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -29,6 +29,7 @@
#include <linux/usb.h>
#include <plat/usb.h>
+#include "control.h"
/* OMAP control module register for UTMI PHY */
#define CONTROL_DEV_CONF 0x300
@@ -162,3 +163,95 @@ int omap4430_phy_exit(struct device *dev)
return 0;
}
+
+void am35x_musb_reset(void)
+{
+ u32 regval;
+
+ /* Reset the musb interface */
+ regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+
+ regval |= AM35XX_USBOTGSS_SW_RST;
+ omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
+
+ regval &= ~AM35XX_USBOTGSS_SW_RST;
+ omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
+
+ regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+}
+
+void am35x_musb_phy_power(u8 on)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(100);
+ u32 devconf2;
+
+ if (on) {
+ /*
+ * Start the on-chip PHY and its PLL.
+ */
+ devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+ devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
+ devconf2 |= CONF2_PHY_PLLON;
+
+ omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+
+ pr_info(KERN_INFO "Waiting for PHY clock good...\n");
+ while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
+ & CONF2_PHYCLKGD)) {
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ pr_err(KERN_ERR "musb PHY clock good timed out\n");
+ break;
+ }
+ }
+ } else {
+ /*
+ * Power down the on-chip PHY.
+ */
+ devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+ devconf2 &= ~CONF2_PHY_PLLON;
+ devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
+ omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+ }
+}
+
+void am35x_musb_clear_irq(void)
+{
+ u32 regval;
+
+ regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+ regval |= AM35XX_USBOTGSS_INT_CLR;
+ omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
+ regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+}
+
+void am35x_musb_set_mode(u8 musb_mode)
+{
+ u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+ devconf2 &= ~CONF2_OTGMODE;
+ switch (musb_mode) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case MUSB_HOST: /* Force VBUS valid, ID = 0 */
+ devconf2 |= CONF2_FORCE_HOST;
+ break;
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
+ devconf2 |= CONF2_FORCE_DEVICE;
+ break;
+#endif
+#ifdef CONFIG_USB_MUSB_OTG
+ case MUSB_OTG: /* Don't override the VBUS/ID comparators */
+ devconf2 |= CONF2_NO_OVERRIDE;
+ break;
+#endif
+ default:
+ pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
+ }
+
+ omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+}
diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c
index 00e1d2b53683..0a8e74e3e811 100644
--- a/arch/arm/mach-omap2/omap_twl.c
+++ b/arch/arm/mach-omap2/omap_twl.c
@@ -18,7 +18,7 @@
#include <linux/kernel.h>
#include <linux/i2c/twl.h>
-#include <plat/voltage.h>
+#include "voltage.h"
#include "pm.h"
@@ -59,8 +59,15 @@
static bool is_offset_valid;
static u8 smps_offset;
+/*
+ * Flag to ensure Smartreflex bit in TWL
+ * being cleared in board file is not overwritten.
+ */
+static bool __initdata twl_sr_enable_autoinit;
+#define TWL4030_DCDC_GLOBAL_CFG 0x06
#define REG_SMPS_OFFSET 0xE0
+#define SMARTREFLEX_ENABLE BIT(3)
static unsigned long twl4030_vsel_to_uv(const u8 vsel)
{
@@ -269,6 +276,18 @@ int __init omap3_twl_init(void)
omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX;
}
+ /*
+ * The smartreflex bit on twl4030 specifies if the setting of voltage
+ * is done over the I2C_SR path. Since this setting is independent of
+ * the actual usage of smartreflex AVS module, we enable TWL SR bit
+ * by default irrespective of whether smartreflex AVS module is enabled
+ * on the OMAP side or not. This is because without this bit enabled,
+ * the voltage scaling through vp forceupdate/bypass mechanism of
+ * voltage scaling will not function on TWL over I2C_SR.
+ */
+ if (!twl_sr_enable_autoinit)
+ omap3_twl_set_sr_bit(true);
+
voltdm = omap_voltage_domain_lookup("mpu");
omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info);
@@ -277,3 +296,44 @@ int __init omap3_twl_init(void)
return 0;
}
+
+/**
+ * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL
+ * @enable: enable SR mode in twl or not
+ *
+ * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure
+ * voltage scaling through OMAP SR works. Else, the smartreflex bit
+ * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but
+ * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct
+ * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages,
+ * in those scenarios this bit is to be cleared (enable = false).
+ *
+ * Returns 0 on sucess, error is returned if I2C read/write fails.
+ */
+int __init omap3_twl_set_sr_bit(bool enable)
+{
+ u8 temp;
+ int ret;
+ if (twl_sr_enable_autoinit)
+ pr_warning("%s: unexpected multiple calls\n", __func__);
+
+ ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp,
+ TWL4030_DCDC_GLOBAL_CFG);
+ if (ret)
+ goto err;
+
+ if (enable)
+ temp |= SMARTREFLEX_ENABLE;
+ else
+ temp &= ~SMARTREFLEX_ENABLE;
+
+ ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp,
+ TWL4030_DCDC_GLOBAL_CFG);
+ if (!ret) {
+ twl_sr_enable_autoinit = true;
+ return 0;
+ }
+err:
+ pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret);
+ return ret;
+}
diff --git a/arch/arm/mach-omap2/opp2xxx.h b/arch/arm/mach-omap2/opp2xxx.h
index 38b730550506..8affc66a92c2 100644
--- a/arch/arm/mach-omap2/opp2xxx.h
+++ b/arch/arm/mach-omap2/opp2xxx.h
@@ -418,7 +418,7 @@ struct prcm_config {
extern const struct prcm_config omap2420_rate_table[];
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
extern const struct prcm_config omap2430_rate_table[];
#else
#define omap2430_rate_table NULL
diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
index 0486fce8a92c..d95f3f945d4a 100644
--- a/arch/arm/mach-omap2/opp3xxx_data.c
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -4,8 +4,9 @@
* Copyright (C) 2009-2010 Texas Instruments Incorporated - http://www.ti.com/
* Nishanth Menon
* Kevin Hilman
- * Copyright (C) 2010 Nokia Corporation.
+ * Copyright (C) 2010-2011 Nokia Corporation.
* Eduardo Valentin
+ * Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,19 +21,83 @@
#include <plat/cpu.h>
+#include "control.h"
#include "omap_opp_data.h"
+#include "pm.h"
+
+/* 34xx */
+
+/* VDD1 */
+
+#define OMAP3430_VDD_MPU_OPP1_UV 975000
+#define OMAP3430_VDD_MPU_OPP2_UV 1075000
+#define OMAP3430_VDD_MPU_OPP3_UV 1200000
+#define OMAP3430_VDD_MPU_OPP4_UV 1270000
+#define OMAP3430_VDD_MPU_OPP5_UV 1350000
+
+struct omap_volt_data omap34xx_vddmpu_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+/* VDD2 */
+
+#define OMAP3430_VDD_CORE_OPP1_UV 975000
+#define OMAP3430_VDD_CORE_OPP2_UV 1050000
+#define OMAP3430_VDD_CORE_OPP3_UV 1150000
+
+struct omap_volt_data omap34xx_vddcore_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+/* 36xx */
+
+/* VDD1 */
+
+#define OMAP3630_VDD_MPU_OPP50_UV 1012500
+#define OMAP3630_VDD_MPU_OPP100_UV 1200000
+#define OMAP3630_VDD_MPU_OPP120_UV 1325000
+#define OMAP3630_VDD_MPU_OPP1G_UV 1375000
+
+struct omap_volt_data omap36xx_vddmpu_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16),
+ VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23),
+ VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+/* VDD2 */
+
+#define OMAP3630_VDD_CORE_OPP50_UV 1000000
+#define OMAP3630_VDD_CORE_OPP100_UV 1200000
+
+struct omap_volt_data omap36xx_vddcore_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+/* OPP data */
static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
/* MPU OPP1 */
- OPP_INITIALIZER("mpu", true, 125000000, 975000),
+ OPP_INITIALIZER("mpu", true, 125000000, OMAP3430_VDD_MPU_OPP1_UV),
/* MPU OPP2 */
- OPP_INITIALIZER("mpu", true, 250000000, 1075000),
+ OPP_INITIALIZER("mpu", true, 250000000, OMAP3430_VDD_MPU_OPP2_UV),
/* MPU OPP3 */
- OPP_INITIALIZER("mpu", true, 500000000, 1200000),
+ OPP_INITIALIZER("mpu", true, 500000000, OMAP3430_VDD_MPU_OPP3_UV),
/* MPU OPP4 */
- OPP_INITIALIZER("mpu", true, 550000000, 1270000),
+ OPP_INITIALIZER("mpu", true, 550000000, OMAP3430_VDD_MPU_OPP4_UV),
/* MPU OPP5 */
- OPP_INITIALIZER("mpu", true, 600000000, 1350000),
+ OPP_INITIALIZER("mpu", true, 600000000, OMAP3430_VDD_MPU_OPP5_UV),
/*
* L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is
@@ -42,53 +107,53 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
* impact that frequency will do to the MPU and the whole system in
* general.
*/
- OPP_INITIALIZER("l3_main", false, 41500000, 975000),
+ OPP_INITIALIZER("l3_main", false, 41500000, OMAP3430_VDD_CORE_OPP1_UV),
/* L3 OPP2 */
- OPP_INITIALIZER("l3_main", true, 83000000, 1050000),
+ OPP_INITIALIZER("l3_main", true, 83000000, OMAP3430_VDD_CORE_OPP2_UV),
/* L3 OPP3 */
- OPP_INITIALIZER("l3_main", true, 166000000, 1150000),
+ OPP_INITIALIZER("l3_main", true, 166000000, OMAP3430_VDD_CORE_OPP3_UV),
/* DSP OPP1 */
- OPP_INITIALIZER("iva", true, 90000000, 975000),
+ OPP_INITIALIZER("iva", true, 90000000, OMAP3430_VDD_MPU_OPP1_UV),
/* DSP OPP2 */
- OPP_INITIALIZER("iva", true, 180000000, 1075000),
+ OPP_INITIALIZER("iva", true, 180000000, OMAP3430_VDD_MPU_OPP2_UV),
/* DSP OPP3 */
- OPP_INITIALIZER("iva", true, 360000000, 1200000),
+ OPP_INITIALIZER("iva", true, 360000000, OMAP3430_VDD_MPU_OPP3_UV),
/* DSP OPP4 */
- OPP_INITIALIZER("iva", true, 400000000, 1270000),
+ OPP_INITIALIZER("iva", true, 400000000, OMAP3430_VDD_MPU_OPP4_UV),
/* DSP OPP5 */
- OPP_INITIALIZER("iva", true, 430000000, 1350000),
+ OPP_INITIALIZER("iva", true, 430000000, OMAP3430_VDD_MPU_OPP5_UV),
};
static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
/* MPU OPP1 - OPP50 */
- OPP_INITIALIZER("mpu", true, 300000000, 1012500),
+ OPP_INITIALIZER("mpu", true, 300000000, OMAP3630_VDD_MPU_OPP50_UV),
/* MPU OPP2 - OPP100 */
- OPP_INITIALIZER("mpu", true, 600000000, 1200000),
+ OPP_INITIALIZER("mpu", true, 600000000, OMAP3630_VDD_MPU_OPP100_UV),
/* MPU OPP3 - OPP-Turbo */
- OPP_INITIALIZER("mpu", false, 800000000, 1325000),
+ OPP_INITIALIZER("mpu", false, 800000000, OMAP3630_VDD_MPU_OPP120_UV),
/* MPU OPP4 - OPP-SB */
- OPP_INITIALIZER("mpu", false, 1000000000, 1375000),
+ OPP_INITIALIZER("mpu", false, 1000000000, OMAP3630_VDD_MPU_OPP1G_UV),
/* L3 OPP1 - OPP50 */
- OPP_INITIALIZER("l3_main", true, 100000000, 1000000),
+ OPP_INITIALIZER("l3_main", true, 100000000, OMAP3630_VDD_CORE_OPP50_UV),
/* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */
- OPP_INITIALIZER("l3_main", true, 200000000, 1200000),
+ OPP_INITIALIZER("l3_main", true, 200000000, OMAP3630_VDD_CORE_OPP100_UV),
/* DSP OPP1 - OPP50 */
- OPP_INITIALIZER("iva", true, 260000000, 1012500),
+ OPP_INITIALIZER("iva", true, 260000000, OMAP3630_VDD_MPU_OPP50_UV),
/* DSP OPP2 - OPP100 */
- OPP_INITIALIZER("iva", true, 520000000, 1200000),
+ OPP_INITIALIZER("iva", true, 520000000, OMAP3630_VDD_MPU_OPP100_UV),
/* DSP OPP3 - OPP-Turbo */
- OPP_INITIALIZER("iva", false, 660000000, 1325000),
+ OPP_INITIALIZER("iva", false, 660000000, OMAP3630_VDD_MPU_OPP120_UV),
/* DSP OPP4 - OPP-SB */
- OPP_INITIALIZER("iva", false, 800000000, 1375000),
+ OPP_INITIALIZER("iva", false, 800000000, OMAP3630_VDD_MPU_OPP1G_UV),
};
/**
* omap3_opp_init() - initialize omap3 opp table
*/
-static int __init omap3_opp_init(void)
+int __init omap3_opp_init(void)
{
int r = -ENODEV;
diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c
index a11fa566d8ee..2293ba27101b 100644
--- a/arch/arm/mach-omap2/opp4xxx_data.c
+++ b/arch/arm/mach-omap2/opp4xxx_data.c
@@ -5,8 +5,9 @@
* Nishanth Menon
* Kevin Hilman
* Thara Gopinath
- * Copyright (C) 2010 Nokia Corporation.
+ * Copyright (C) 2010-2011 Nokia Corporation.
* Eduardo Valentin
+ * Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,28 +22,75 @@
#include <plat/cpu.h>
+#include "control.h"
#include "omap_opp_data.h"
+#include "pm.h"
+
+/*
+ * Structures containing OMAP4430 voltage supported and various
+ * voltage dependent data for each VDD.
+ */
+
+#define OMAP4430_VDD_MPU_OPP50_UV 1025000
+#define OMAP4430_VDD_MPU_OPP100_UV 1200000
+#define OMAP4430_VDD_MPU_OPPTURBO_UV 1313000
+#define OMAP4430_VDD_MPU_OPPNITRO_UV 1375000
+
+struct omap_volt_data omap44xx_vdd_mpu_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+#define OMAP4430_VDD_IVA_OPP50_UV 1013000
+#define OMAP4430_VDD_IVA_OPP100_UV 1188000
+#define OMAP4430_VDD_IVA_OPPTURBO_UV 1300000
+
+struct omap_volt_data omap44xx_vdd_iva_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP100_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
+#define OMAP4430_VDD_CORE_OPP50_UV 1025000
+#define OMAP4430_VDD_CORE_OPP100_UV 1200000
+
+struct omap_volt_data omap44xx_vdd_core_volt_data[] = {
+ VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c),
+ VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP100_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16),
+ VOLT_DATA_DEFINE(0, 0, 0, 0),
+};
+
static struct omap_opp_def __initdata omap44xx_opp_def_list[] = {
/* MPU OPP1 - OPP50 */
- OPP_INITIALIZER("mpu", true, 300000000, 1100000),
+ OPP_INITIALIZER("mpu", true, 300000000, OMAP4430_VDD_MPU_OPP50_UV),
/* MPU OPP2 - OPP100 */
- OPP_INITIALIZER("mpu", true, 600000000, 1200000),
+ OPP_INITIALIZER("mpu", true, 600000000, OMAP4430_VDD_MPU_OPP100_UV),
/* MPU OPP3 - OPP-Turbo */
- OPP_INITIALIZER("mpu", false, 800000000, 1260000),
+ OPP_INITIALIZER("mpu", true, 800000000, OMAP4430_VDD_MPU_OPPTURBO_UV),
/* MPU OPP4 - OPP-SB */
- OPP_INITIALIZER("mpu", false, 1008000000, 1350000),
+ OPP_INITIALIZER("mpu", true, 1008000000, OMAP4430_VDD_MPU_OPPNITRO_UV),
/* L3 OPP1 - OPP50 */
- OPP_INITIALIZER("l3_main_1", true, 100000000, 930000),
+ OPP_INITIALIZER("l3_main_1", true, 100000000, OMAP4430_VDD_CORE_OPP50_UV),
/* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */
- OPP_INITIALIZER("l3_main_1", true, 200000000, 1100000),
- /* TODO: add IVA, DSP, aess, fdif, gpu */
+ OPP_INITIALIZER("l3_main_1", true, 200000000, OMAP4430_VDD_CORE_OPP100_UV),
+ /* IVA OPP1 - OPP50 */
+ OPP_INITIALIZER("iva", true, 133000000, OMAP4430_VDD_IVA_OPP50_UV),
+ /* IVA OPP2 - OPP100 */
+ OPP_INITIALIZER("iva", true, 266100000, OMAP4430_VDD_IVA_OPP100_UV),
+ /* IVA OPP3 - OPP-Turbo */
+ OPP_INITIALIZER("iva", false, 332000000, OMAP4430_VDD_IVA_OPPTURBO_UV),
+ /* TODO: add DSP, aess, fdif, gpu */
};
/**
* omap4_opp_init() - initialize omap4 opp table
*/
-static int __init omap4_opp_init(void)
+int __init omap4_opp_init(void)
{
int r = -ENODEV;
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d5a102c71989..30af3351c2d6 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -18,8 +18,8 @@
#include <plat/omap-pm.h>
#include <plat/omap_device.h>
#include <plat/common.h>
-#include <plat/voltage.h>
+#include "voltage.h"
#include "powerdomain.h"
#include "clockdomain.h"
#include "pm.h"
@@ -83,7 +83,9 @@ static int _init_omap_device(char *name, struct device **new_dev)
static void omap2_init_processor_devices(void)
{
_init_omap_device("mpu", &mpu_dev);
- _init_omap_device("iva", &iva_dev);
+ if (omap3_has_iva())
+ _init_omap_device("iva", &iva_dev);
+
if (cpu_is_omap44xx()) {
_init_omap_device("l3_main_1", &l3_dev);
_init_omap_device("dsp", &dsp_dev);
@@ -124,7 +126,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
sleep_switch = LOWPOWERSTATE_SWITCH;
} else {
- omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+ clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
pwrdm_wait_transition(pwrdm);
sleep_switch = FORCEWAKEUP_SWITCH;
}
@@ -140,9 +142,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
switch (sleep_switch) {
case FORCEWAKEUP_SWITCH:
if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO)
- omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+ clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
else
- omap2_clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
+ clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
break;
case LOWPOWERSTATE_SWITCH:
pwrdm_set_lowpwrstchange(pwrdm);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 39580e6060e8..797bfd12b643 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -127,6 +127,7 @@ static inline void omap_enable_smartreflex_on_init(void) {}
#ifdef CONFIG_TWL4030_CORE
extern int omap3_twl_init(void);
extern int omap4_twl_init(void);
+extern int omap3_twl_set_sr_bit(bool enable);
#else
static inline int omap3_twl_init(void)
{
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 97feb3ab6a69..df3ded6fe194 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -363,14 +363,11 @@ static const struct platform_suspend_ops __initdata omap_pm_ops;
/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
{
- clkdm_clear_all_wkdeps(clkdm);
- clkdm_clear_all_sleepdeps(clkdm);
-
if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
- omap2_clkdm_allow_idle(clkdm);
+ clkdm_allow_idle(clkdm);
else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
atomic_read(&clkdm->usecount) == 0)
- omap2_clkdm_sleep(clkdm);
+ clkdm_sleep(clkdm);
return 0;
}
@@ -379,7 +376,10 @@ static void __init prcm_setup_regs(void)
int i, num_mem_banks;
struct powerdomain *pwrdm;
- /* Enable autoidle */
+ /*
+ * Enable autoidle
+ * XXX This should be handled by hwmod code or PRCM init code
+ */
omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
OMAP2_PRCM_SYSCONFIG_OFFSET);
@@ -405,83 +405,16 @@ static void __init prcm_setup_regs(void)
pwrdm = clkdm_get_pwrdm(dsp_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
- omap2_clkdm_sleep(dsp_clkdm);
+ clkdm_sleep(dsp_clkdm);
pwrdm = clkdm_get_pwrdm(gfx_clkdm);
pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
- omap2_clkdm_sleep(gfx_clkdm);
+ clkdm_sleep(gfx_clkdm);
- /*
- * Clear clockdomain wakeup dependencies and enable
- * hardware-supervised idle for all clkdms
- */
+ /* Enable hardware-supervised idle for all clkdms */
clkdm_for_each(clkdms_setup, NULL);
clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
- /* Enable clock autoidle for all domains */
- omap2_cm_write_mod_reg(OMAP24XX_AUTO_CAM_MASK |
- OMAP24XX_AUTO_MAILBOXES_MASK |
- OMAP24XX_AUTO_WDT4_MASK |
- OMAP2420_AUTO_WDT3_MASK |
- OMAP24XX_AUTO_MSPRO_MASK |
- OMAP2420_AUTO_MMC_MASK |
- OMAP24XX_AUTO_FAC_MASK |
- OMAP2420_AUTO_EAC_MASK |
- OMAP24XX_AUTO_HDQ_MASK |
- OMAP24XX_AUTO_UART2_MASK |
- OMAP24XX_AUTO_UART1_MASK |
- OMAP24XX_AUTO_I2C2_MASK |
- OMAP24XX_AUTO_I2C1_MASK |
- OMAP24XX_AUTO_MCSPI2_MASK |
- OMAP24XX_AUTO_MCSPI1_MASK |
- OMAP24XX_AUTO_MCBSP2_MASK |
- OMAP24XX_AUTO_MCBSP1_MASK |
- OMAP24XX_AUTO_GPT12_MASK |
- OMAP24XX_AUTO_GPT11_MASK |
- OMAP24XX_AUTO_GPT10_MASK |
- OMAP24XX_AUTO_GPT9_MASK |
- OMAP24XX_AUTO_GPT8_MASK |
- OMAP24XX_AUTO_GPT7_MASK |
- OMAP24XX_AUTO_GPT6_MASK |
- OMAP24XX_AUTO_GPT5_MASK |
- OMAP24XX_AUTO_GPT4_MASK |
- OMAP24XX_AUTO_GPT3_MASK |
- OMAP24XX_AUTO_GPT2_MASK |
- OMAP2420_AUTO_VLYNQ_MASK |
- OMAP24XX_AUTO_DSS_MASK,
- CORE_MOD, CM_AUTOIDLE1);
- omap2_cm_write_mod_reg(OMAP24XX_AUTO_UART3_MASK |
- OMAP24XX_AUTO_SSI_MASK |
- OMAP24XX_AUTO_USB_MASK,
- CORE_MOD, CM_AUTOIDLE2);
- omap2_cm_write_mod_reg(OMAP24XX_AUTO_SDRC_MASK |
- OMAP24XX_AUTO_GPMC_MASK |
- OMAP24XX_AUTO_SDMA_MASK,
- CORE_MOD, CM_AUTOIDLE3);
- omap2_cm_write_mod_reg(OMAP24XX_AUTO_PKA_MASK |
- OMAP24XX_AUTO_AES_MASK |
- OMAP24XX_AUTO_RNG_MASK |
- OMAP24XX_AUTO_SHA_MASK |
- OMAP24XX_AUTO_DES_MASK,
- CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
-
- omap2_cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI_MASK, OMAP24XX_DSP_MOD,
- CM_AUTOIDLE);
-
- /* Put DPLL and both APLLs into autoidle mode */
- omap2_cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
- (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
- (0x03 << OMAP24XX_AUTO_54M_SHIFT),
- PLL_MOD, CM_AUTOIDLE);
-
- omap2_cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL_MASK |
- OMAP24XX_AUTO_WDT1_MASK |
- OMAP24XX_AUTO_MPU_WDT_MASK |
- OMAP24XX_AUTO_GPIOS_MASK |
- OMAP24XX_AUTO_32KSYNC_MASK |
- OMAP24XX_AUTO_GPT1_MASK,
- WKUP_MOD, CM_AUTOIDLE);
-
/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
* stabilisation */
omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 2f864e4b085d..0c5e3a46a3ad 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>
+#include <trace/events/power.h>
#include <plat/sram.h>
#include "clockdomain.h"
@@ -311,11 +312,6 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void restore_control_register(u32 val)
-{
- __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));
-}
-
/* Function to restore the table entry that was modified for enabling MMU */
static void restore_table_entry(void)
{
@@ -337,7 +333,7 @@ static void restore_table_entry(void)
control_reg_value = __raw_readl(scratchpad_address
+ OMAP343X_CONTROL_REG_VALUE_OFFSET);
/* This will enable caches and prediction */
- restore_control_register(control_reg_value);
+ set_cr(control_reg_value);
}
void omap_sram_idle(void)
@@ -496,7 +492,7 @@ console_still_active:
pwrdm_post_transition();
- omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
+ clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
}
int omap3_can_sleep(void)
@@ -519,8 +515,14 @@ static void omap3_pm_idle(void)
if (omap_irq_pending() || need_resched())
goto out;
+ trace_power_start(POWER_CSTATE, 1, smp_processor_id());
+ trace_cpu_idle(1, smp_processor_id());
+
omap_sram_idle();
+ trace_power_end(smp_processor_id());
+ trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+
out:
local_fiq_enable();
local_irq_enable();
@@ -688,149 +690,15 @@ static void __init omap3_d2d_idle(void)
static void __init prcm_setup_regs(void)
{
- u32 omap3630_auto_uart4_mask = cpu_is_omap3630() ?
- OMAP3630_AUTO_UART4_MASK : 0;
u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
OMAP3630_EN_UART4_MASK : 0;
u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
OMAP3630_GRPSEL_UART4_MASK : 0;
-
- /* XXX Reset all wkdeps. This should be done when initializing
- * powerdomains */
- omap2_prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
- if (omap_rev() > OMAP3430_REV_ES1_0) {
- omap2_prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
- omap2_prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
- } else
- omap2_prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
-
- /*
- * Enable interface clock autoidle for all modules.
- * Note that in the long run this should be done by clockfw
- */
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_MODEM_MASK |
- OMAP3430ES2_AUTO_MMC3_MASK |
- OMAP3430ES2_AUTO_ICR_MASK |
- OMAP3430_AUTO_AES2_MASK |
- OMAP3430_AUTO_SHA12_MASK |
- OMAP3430_AUTO_DES2_MASK |
- OMAP3430_AUTO_MMC2_MASK |
- OMAP3430_AUTO_MMC1_MASK |
- OMAP3430_AUTO_MSPRO_MASK |
- OMAP3430_AUTO_HDQ_MASK |
- OMAP3430_AUTO_MCSPI4_MASK |
- OMAP3430_AUTO_MCSPI3_MASK |
- OMAP3430_AUTO_MCSPI2_MASK |
- OMAP3430_AUTO_MCSPI1_MASK |
- OMAP3430_AUTO_I2C3_MASK |
- OMAP3430_AUTO_I2C2_MASK |
- OMAP3430_AUTO_I2C1_MASK |
- OMAP3430_AUTO_UART2_MASK |
- OMAP3430_AUTO_UART1_MASK |
- OMAP3430_AUTO_GPT11_MASK |
- OMAP3430_AUTO_GPT10_MASK |
- OMAP3430_AUTO_MCBSP5_MASK |
- OMAP3430_AUTO_MCBSP1_MASK |
- OMAP3430ES1_AUTO_FAC_MASK | /* This is es1 only */
- OMAP3430_AUTO_MAILBOXES_MASK |
- OMAP3430_AUTO_OMAPCTRL_MASK |
- OMAP3430ES1_AUTO_FSHOSTUSB_MASK |
- OMAP3430_AUTO_HSOTGUSB_MASK |
- OMAP3430_AUTO_SAD2D_MASK |
- OMAP3430_AUTO_SSI_MASK,
- CORE_MOD, CM_AUTOIDLE1);
-
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_PKA_MASK |
- OMAP3430_AUTO_AES1_MASK |
- OMAP3430_AUTO_RNG_MASK |
- OMAP3430_AUTO_SHA11_MASK |
- OMAP3430_AUTO_DES1_MASK,
- CORE_MOD, CM_AUTOIDLE2);
-
- if (omap_rev() > OMAP3430_REV_ES1_0) {
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_MAD2D_MASK |
- OMAP3430ES2_AUTO_USBTLL_MASK,
- CORE_MOD, CM_AUTOIDLE3);
- }
-
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_WDT2_MASK |
- OMAP3430_AUTO_WDT1_MASK |
- OMAP3430_AUTO_GPIO1_MASK |
- OMAP3430_AUTO_32KSYNC_MASK |
- OMAP3430_AUTO_GPT12_MASK |
- OMAP3430_AUTO_GPT1_MASK,
- WKUP_MOD, CM_AUTOIDLE);
-
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_DSS_MASK,
- OMAP3430_DSS_MOD,
- CM_AUTOIDLE);
-
- omap2_cm_write_mod_reg(
- OMAP3430_AUTO_CAM_MASK,
- OMAP3430_CAM_MOD,
- CM_AUTOIDLE);
-
- omap2_cm_write_mod_reg(
- omap3630_auto_uart4_mask |
- OMAP3430_AUTO_GPIO6_MASK |
- OMAP3430_AUTO_GPIO5_MASK |
- OMAP3430_AUTO_GPIO4_MASK |
- OMAP3430_AUTO_GPIO3_MASK |
- OMAP3430_AUTO_GPIO2_MASK |
- OMAP3430_AUTO_WDT3_MASK |
- OMAP3430_AUTO_UART3_MASK |
- OMAP3430_AUTO_GPT9_MASK |
- OMAP3430_AUTO_GPT8_MASK |
- OMAP3430_AUTO_GPT7_MASK |
- OMAP3430_AUTO_GPT6_MASK |
- OMAP3430_AUTO_GPT5_MASK |
- OMAP3430_AUTO_GPT4_MASK |
- OMAP3430_AUTO_GPT3_MASK |
- OMAP3430_AUTO_GPT2_MASK |
- OMAP3430_AUTO_MCBSP4_MASK |
- OMAP3430_AUTO_MCBSP3_MASK |
- OMAP3430_AUTO_MCBSP2_MASK,
- OMAP3430_PER_MOD,
- CM_AUTOIDLE);
-
- if (omap_rev() > OMAP3430_REV_ES1_0) {
- omap2_cm_write_mod_reg(
- OMAP3430ES2_AUTO_USBHOST_MASK,
- OMAP3430ES2_USBHOST_MOD,
- CM_AUTOIDLE);
- }
-
+ /* XXX This should be handled by hwmod code or SCM init code */
omap_ctrl_writel(OMAP3430_AUTOIDLE_MASK, OMAP2_CONTROL_SYSCONFIG);
/*
- * Set all plls to autoidle. This is needed until autoidle is
- * enabled by clockfw
- */
- omap2_cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
- OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
- omap2_cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
- MPU_MOD,
- CM_AUTOIDLE2);
- omap2_cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
- (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
- PLL_MOD,
- CM_AUTOIDLE);
- omap2_cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
- PLL_MOD,
- CM_AUTOIDLE2);
-
- /*
* Enable control of expternal oscillator through
* sys_clkreq. In the long run clock framework should
* take care of this.
@@ -928,8 +796,7 @@ void omap3_pm_off_mode_enable(int enable)
pwrst->pwrdm == core_pwrdm &&
state == PWRDM_POWER_OFF) {
pwrst->next_state = PWRDM_POWER_RET;
- WARN_ONCE(1,
- "%s: Core OFF disabled due to errata i583\n",
+ pr_warn("%s: Core OFF disabled due to errata i583\n",
__func__);
} else {
pwrst->next_state = state;
@@ -990,10 +857,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
{
if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
- omap2_clkdm_allow_idle(clkdm);
+ clkdm_allow_idle(clkdm);
else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
atomic_read(&clkdm->usecount) == 0)
- omap2_clkdm_sleep(clkdm);
+ clkdm_sleep(clkdm);
return 0;
}
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index eaed0df16699..49c6513e90d8 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -2,7 +2,7 @@
* OMAP powerdomain control
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2009 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Written by Paul Walmsley
* Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
@@ -19,12 +19,15 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <trace/events/power.h>
+
#include "cm2xxx_3xxx.h"
#include "prcm44xx.h"
#include "cm44xx.h"
#include "prm2xxx_3xxx.h"
#include "prm44xx.h"
+#include <asm/cpu.h>
#include <plat/cpu.h>
#include "powerdomain.h"
#include "clockdomain.h"
@@ -32,6 +35,8 @@
#include "pm.h"
+#define PWRDM_TRACE_STATES_FLAG (1<<31)
+
enum {
PWRDM_STATE_NOW = 0,
PWRDM_STATE_PREV,
@@ -130,8 +135,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm)
static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
{
- int prev;
- int state;
+ int prev, state, trace_state = 0;
if (pwrdm == NULL)
return -EINVAL;
@@ -148,6 +152,17 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
pwrdm->state_counter[prev]++;
if (prev == PWRDM_POWER_RET)
_update_logic_membank_counters(pwrdm);
+ /*
+ * If the power domain did not hit the desired state,
+ * generate a trace event with both the desired and hit states
+ */
+ if (state != prev) {
+ trace_state = (PWRDM_TRACE_STATES_FLAG |
+ ((state & OMAP_POWERSTATE_MASK) << 8) |
+ ((prev & OMAP_POWERSTATE_MASK) << 0));
+ trace_power_domain_target(pwrdm->name, trace_state,
+ smp_processor_id());
+ }
break;
default:
return -EINVAL;
@@ -406,8 +421,13 @@ int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
pwrdm->name, pwrst);
- if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst)
+ if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
+ /* Trace the pwrdm desired target state */
+ trace_power_domain_target(pwrdm->name, pwrst,
+ smp_processor_id());
+ /* Program the pwrdm desired target state */
ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
+ }
return ret;
}
@@ -938,3 +958,44 @@ u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
return count;
}
+
+/**
+ * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
+ * @pwrdm: struct powerdomain *
+ *
+ * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
+ * can lose either memory or logic context or if @pwrdm is invalid, or
+ * returns 0 otherwise. This function is not concerned with how the
+ * powerdomain registers are programmed (i.e., to go off or not); it's
+ * concerned with whether it's ever possible for this powerdomain to
+ * go off while some other part of the chip is active. This function
+ * assumes that every powerdomain can go to either ON or INACTIVE.
+ */
+bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
+{
+ int i;
+
+ if (IS_ERR_OR_NULL(pwrdm)) {
+ pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
+ __func__);
+ return 1;
+ }
+
+ if (pwrdm->pwrsts & PWRSTS_OFF)
+ return 1;
+
+ if (pwrdm->pwrsts & PWRSTS_RET) {
+ if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
+ return 1;
+
+ for (i = 0; i < pwrdm->banks; i++)
+ if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
+ return 1;
+ }
+
+ for (i = 0; i < pwrdm->banks; i++)
+ if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index c66431edfeb7..027f40bd235d 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -2,7 +2,7 @@
* OMAP2/3/4 powerdomain control
*
* Copyright (C) 2007-2008, 2010 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley
*
@@ -34,17 +34,14 @@
/* Powerdomain allowable state bitfields */
#define PWRSTS_ON (1 << PWRDM_POWER_ON)
+#define PWRSTS_INACTIVE (1 << PWRDM_POWER_INACTIVE)
+#define PWRSTS_RET (1 << PWRDM_POWER_RET)
#define PWRSTS_OFF (1 << PWRDM_POWER_OFF)
-#define PWRSTS_OFF_ON ((1 << PWRDM_POWER_OFF) | \
- (1 << PWRDM_POWER_ON))
-#define PWRSTS_OFF_RET ((1 << PWRDM_POWER_OFF) | \
- (1 << PWRDM_POWER_RET))
-
-#define PWRSTS_RET_ON ((1 << PWRDM_POWER_RET) | \
- (1 << PWRDM_POWER_ON))
-
-#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
+#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON)
+#define PWRSTS_OFF_RET (PWRSTS_OFF | PWRSTS_RET)
+#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON)
+#define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON)
/* Powerdomain flags */
@@ -165,7 +162,6 @@ struct pwrdm_ops {
int (*pwrdm_wait_transition)(struct powerdomain *pwrdm);
};
-void pwrdm_fw_init(void);
void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs);
struct powerdomain *pwrdm_lookup(const char *name);
@@ -212,6 +208,7 @@ int pwrdm_pre_transition(void);
int pwrdm_post_transition(void);
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
u32 pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
+bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);
extern void omap2xxx_powerdomains_init(void);
extern void omap3xxx_powerdomains_init(void);
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
index 5b4dd971320a..4210c3399769 100644
--- a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c
@@ -2,7 +2,7 @@
* OMAP2/3 common powerdomain definitions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley, Jouni Högander
*
@@ -62,13 +62,13 @@ struct powerdomain gfx_omap2_pwrdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
CHIP_IS_OMAP3430ES1),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
@@ -76,4 +76,5 @@ struct powerdomain wkup_omap2_pwrdm = {
.name = "wkup_pwrdm",
.prcm_offs = WKUP_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+ .pwrsts = PWRSTS_ON,
};
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c
index 9b1a33500577..cc389fb2005d 100644
--- a/arch/arm/mach-omap2/powerdomains2xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c
@@ -2,7 +2,7 @@
* OMAP2XXX powerdomain definitions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley, Jouni Högander
*
@@ -30,13 +30,13 @@ static struct powerdomain dsp_pwrdm = {
.prcm_offs = OMAP24XX_DSP_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET,
+ [0] = PWRSTS_RET,
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON,
+ [0] = PWRSTS_ON,
},
};
@@ -48,10 +48,10 @@ static struct powerdomain mpu_24xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET,
+ [0] = PWRSTS_RET,
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON,
+ [0] = PWRSTS_ON,
},
};
@@ -78,7 +78,7 @@ static struct powerdomain core_24xx_pwrdm = {
* 2430-specific powerdomains
*/
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
/* XXX 2430 KILLDOMAINWKUP bit? No current users apparently */
@@ -87,17 +87,17 @@ static struct powerdomain mdm_pwrdm = {
.prcm_offs = OMAP2430_MDM_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
-#endif /* CONFIG_ARCH_OMAP2430 */
+#endif /* CONFIG_SOC_OMAP2430 */
/* As powerdomains are added or removed above, this list must also be changed */
static struct powerdomain *powerdomains_omap2xxx[] __initdata = {
@@ -111,7 +111,7 @@ static struct powerdomain *powerdomains_omap2xxx[] __initdata = {
&core_24xx_pwrdm,
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
&mdm_pwrdm,
#endif
NULL
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index e1bec562625b..9c9c113788b9 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -2,7 +2,7 @@
* OMAP3 powerdomain definitions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
+ * Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley, Jouni Högander
*
@@ -47,10 +47,10 @@ static struct powerdomain iva2_pwrdm = {
[3] = PWRSTS_OFF_RET,
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON,
- [1] = PWRDM_POWER_ON,
+ [0] = PWRSTS_ON,
+ [1] = PWRSTS_ON,
[2] = PWRSTS_OFF_ON,
- [3] = PWRDM_POWER_ON,
+ [3] = PWRSTS_ON,
},
};
@@ -128,13 +128,13 @@ static struct powerdomain dss_pwrdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.prcm_offs = OMAP3430_DSS_MOD,
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
@@ -149,13 +149,13 @@ static struct powerdomain sgx_pwrdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
/* XXX This is accurate for 3430 SGX, but what about GFX? */
.pwrsts = PWRSTS_OFF_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
@@ -164,13 +164,13 @@ static struct powerdomain cam_pwrdm = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.prcm_offs = OMAP3430_CAM_MOD,
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
@@ -182,10 +182,10 @@ static struct powerdomain per_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
@@ -200,7 +200,7 @@ static struct powerdomain neon_pwrdm = {
.prcm_offs = OMAP3430_NEON_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
};
static struct powerdomain usbhost_pwrdm = {
@@ -208,7 +208,7 @@ static struct powerdomain usbhost_pwrdm = {
.prcm_offs = OMAP3430ES2_USBHOST_MOD,
.omap_chip = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_RET,
+ .pwrsts_logic_ret = PWRSTS_RET,
/*
* REVISIT: Enabling usb host save and restore mechanism seems to
* leave the usb host domain permanently in ACTIVE mode after
@@ -218,10 +218,10 @@ static struct powerdomain usbhost_pwrdm = {
/*.flags = PWRDM_HAS_HDWR_SAR,*/ /* for USBHOST ctrlr only */
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+ [0] = PWRSTS_RET, /* MEMRETSTATE */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* MEMONSTATE */
+ [0] = PWRSTS_ON, /* MEMONSTATE */
},
};
diff --git a/arch/arm/mach-omap2/powerdomains44xx_data.c b/arch/arm/mach-omap2/powerdomains44xx_data.c
index 26d7641076d7..c4222c7036a5 100644
--- a/arch/arm/mach-omap2/powerdomains44xx_data.c
+++ b/arch/arm/mach-omap2/powerdomains44xx_data.c
@@ -2,7 +2,7 @@
* OMAP4 Power domains framework
*
* Copyright (C) 2009-2010 Texas Instruments, Inc.
- * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009-2011 Nokia Corporation
*
* Abhijit Pagare (abhijitpagare@ti.com)
* Benoit Cousson (b-cousson@ti.com)
@@ -40,18 +40,18 @@ static struct powerdomain core_44xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 5,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* core_nret_bank */
+ [0] = PWRSTS_OFF, /* core_nret_bank */
[1] = PWRSTS_OFF_RET, /* core_ocmram */
- [2] = PWRDM_POWER_RET, /* core_other_bank */
+ [2] = PWRSTS_RET, /* core_other_bank */
[3] = PWRSTS_OFF_RET, /* ducati_l2ram */
[4] = PWRSTS_OFF_RET, /* ducati_unicache */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* core_nret_bank */
+ [0] = PWRSTS_ON, /* core_nret_bank */
[1] = PWRSTS_OFF_RET, /* core_ocmram */
- [2] = PWRDM_POWER_ON, /* core_other_bank */
- [3] = PWRDM_POWER_ON, /* ducati_l2ram */
- [4] = PWRDM_POWER_ON, /* ducati_unicache */
+ [2] = PWRSTS_ON, /* core_other_bank */
+ [3] = PWRSTS_ON, /* ducati_l2ram */
+ [4] = PWRSTS_ON, /* ducati_unicache */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -65,10 +65,10 @@ static struct powerdomain gfx_44xx_pwrdm = {
.pwrsts = PWRSTS_OFF_ON,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* gfx_mem */
+ [0] = PWRSTS_OFF, /* gfx_mem */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* gfx_mem */
+ [0] = PWRSTS_ON, /* gfx_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -80,15 +80,15 @@ static struct powerdomain abe_44xx_pwrdm = {
.prcm_partition = OMAP4430_PRM_PARTITION,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_OFF,
+ .pwrsts_logic_ret = PWRSTS_OFF,
.banks = 2,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* aessmem */
- [1] = PWRDM_POWER_OFF, /* periphmem */
+ [0] = PWRSTS_RET, /* aessmem */
+ [1] = PWRSTS_OFF, /* periphmem */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* aessmem */
- [1] = PWRDM_POWER_ON, /* periphmem */
+ [0] = PWRSTS_ON, /* aessmem */
+ [1] = PWRSTS_ON, /* periphmem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -103,10 +103,10 @@ static struct powerdomain dss_44xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* dss_mem */
+ [0] = PWRSTS_OFF, /* dss_mem */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* dss_mem */
+ [0] = PWRSTS_ON, /* dss_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -121,14 +121,14 @@ static struct powerdomain tesla_44xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 3,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_RET, /* tesla_edma */
+ [0] = PWRSTS_RET, /* tesla_edma */
[1] = PWRSTS_OFF_RET, /* tesla_l1 */
[2] = PWRSTS_OFF_RET, /* tesla_l2 */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* tesla_edma */
- [1] = PWRDM_POWER_ON, /* tesla_l1 */
- [2] = PWRDM_POWER_ON, /* tesla_l2 */
+ [0] = PWRSTS_ON, /* tesla_edma */
+ [1] = PWRSTS_ON, /* tesla_l1 */
+ [2] = PWRSTS_ON, /* tesla_l2 */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -142,10 +142,10 @@ static struct powerdomain wkup_44xx_pwrdm = {
.pwrsts = PWRSTS_ON,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* wkup_bank */
+ [0] = PWRSTS_OFF, /* wkup_bank */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* wkup_bank */
+ [0] = PWRSTS_ON, /* wkup_bank */
},
};
@@ -162,7 +162,7 @@ static struct powerdomain cpu0_44xx_pwrdm = {
[0] = PWRSTS_OFF_RET, /* cpu0_l1 */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* cpu0_l1 */
+ [0] = PWRSTS_ON, /* cpu0_l1 */
},
};
@@ -179,7 +179,7 @@ static struct powerdomain cpu1_44xx_pwrdm = {
[0] = PWRSTS_OFF_RET, /* cpu1_l1 */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* cpu1_l1 */
+ [0] = PWRSTS_ON, /* cpu1_l1 */
},
};
@@ -192,10 +192,10 @@ static struct powerdomain emu_44xx_pwrdm = {
.pwrsts = PWRSTS_OFF_ON,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* emu_bank */
+ [0] = PWRSTS_OFF, /* emu_bank */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* emu_bank */
+ [0] = PWRSTS_ON, /* emu_bank */
},
};
@@ -211,12 +211,12 @@ static struct powerdomain mpu_44xx_pwrdm = {
.pwrsts_mem_ret = {
[0] = PWRSTS_OFF_RET, /* mpu_l1 */
[1] = PWRSTS_OFF_RET, /* mpu_l2 */
- [2] = PWRDM_POWER_RET, /* mpu_ram */
+ [2] = PWRSTS_RET, /* mpu_ram */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* mpu_l1 */
- [1] = PWRDM_POWER_ON, /* mpu_l2 */
- [2] = PWRDM_POWER_ON, /* mpu_ram */
+ [0] = PWRSTS_ON, /* mpu_l1 */
+ [1] = PWRSTS_ON, /* mpu_l2 */
+ [2] = PWRSTS_ON, /* mpu_ram */
},
};
@@ -227,19 +227,19 @@ static struct powerdomain ivahd_44xx_pwrdm = {
.prcm_partition = OMAP4430_PRM_PARTITION,
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
.pwrsts = PWRSTS_OFF_RET_ON,
- .pwrsts_logic_ret = PWRDM_POWER_OFF,
+ .pwrsts_logic_ret = PWRSTS_OFF,
.banks = 4,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* hwa_mem */
+ [0] = PWRSTS_OFF, /* hwa_mem */
[1] = PWRSTS_OFF_RET, /* sl2_mem */
[2] = PWRSTS_OFF_RET, /* tcm1_mem */
[3] = PWRSTS_OFF_RET, /* tcm2_mem */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* hwa_mem */
- [1] = PWRDM_POWER_ON, /* sl2_mem */
- [2] = PWRDM_POWER_ON, /* tcm1_mem */
- [3] = PWRDM_POWER_ON, /* tcm2_mem */
+ [0] = PWRSTS_ON, /* hwa_mem */
+ [1] = PWRSTS_ON, /* sl2_mem */
+ [2] = PWRSTS_ON, /* tcm1_mem */
+ [3] = PWRSTS_ON, /* tcm2_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -253,10 +253,10 @@ static struct powerdomain cam_44xx_pwrdm = {
.pwrsts = PWRSTS_OFF_ON,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* cam_mem */
+ [0] = PWRSTS_OFF, /* cam_mem */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* cam_mem */
+ [0] = PWRSTS_ON, /* cam_mem */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -271,10 +271,10 @@ static struct powerdomain l3init_44xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 1,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* l3init_bank1 */
+ [0] = PWRSTS_OFF, /* l3init_bank1 */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* l3init_bank1 */
+ [0] = PWRSTS_ON, /* l3init_bank1 */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
@@ -289,12 +289,12 @@ static struct powerdomain l4per_44xx_pwrdm = {
.pwrsts_logic_ret = PWRSTS_OFF_RET,
.banks = 2,
.pwrsts_mem_ret = {
- [0] = PWRDM_POWER_OFF, /* nonretained_bank */
- [1] = PWRDM_POWER_RET, /* retained_bank */
+ [0] = PWRSTS_OFF, /* nonretained_bank */
+ [1] = PWRSTS_RET, /* retained_bank */
},
.pwrsts_mem_on = {
- [0] = PWRDM_POWER_ON, /* nonretained_bank */
- [1] = PWRDM_POWER_ON, /* retained_bank */
+ [0] = PWRSTS_ON, /* nonretained_bank */
+ [1] = PWRSTS_ON, /* retained_bank */
},
.flags = PWRDM_HAS_LOWPOWERSTATECHANGE,
};
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 87486f559784..0363dcb0ef93 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -121,6 +121,10 @@
#define OMAP24XX_ST_MCSPI2_MASK (1 << 18)
#define OMAP24XX_ST_MCSPI1_SHIFT 17
#define OMAP24XX_ST_MCSPI1_MASK (1 << 17)
+#define OMAP24XX_ST_MCBSP2_SHIFT 16
+#define OMAP24XX_ST_MCBSP2_MASK (1 << 16)
+#define OMAP24XX_ST_MCBSP1_SHIFT 15
+#define OMAP24XX_ST_MCBSP1_MASK (1 << 15)
#define OMAP24XX_ST_GPT12_SHIFT 14
#define OMAP24XX_ST_GPT12_MASK (1 << 14)
#define OMAP24XX_ST_GPT11_SHIFT 13
@@ -191,6 +195,8 @@
#define OMAP3430_AUTOIDLE_MASK (1 << 0)
/* CM_FCLKEN1_CORE, CM_ICLKEN1_CORE, PM_WKEN1_CORE shared bits */
+#define OMAP3430_EN_MMC3_MASK (1 << 30)
+#define OMAP3430_EN_MMC3_SHIFT 30
#define OMAP3430_EN_MMC2_MASK (1 << 25)
#define OMAP3430_EN_MMC2_SHIFT 25
#define OMAP3430_EN_MMC1_MASK (1 << 24)
@@ -231,6 +237,8 @@
#define OMAP3430_EN_HSOTGUSB_SHIFT 4
/* PM_WKST1_CORE, CM_IDLEST1_CORE shared bits */
+#define OMAP3430_ST_MMC3_SHIFT 30
+#define OMAP3430_ST_MMC3_MASK (1 << 30)
#define OMAP3430_ST_MMC2_SHIFT 25
#define OMAP3430_ST_MMC2_MASK (1 << 25)
#define OMAP3430_ST_MMC1_SHIFT 24
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 679bcd28576e..6be14389e4f3 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <mach/system.h>
#include <plat/common.h>
#include <plat/prcm.h>
#include <plat/irqs.h>
@@ -57,7 +58,7 @@ u32 omap_prcm_get_reset_sources(void)
EXPORT_SYMBOL(omap_prcm_get_reset_sources);
/* Resets clock rates and reboots the system. Only called from system.h */
-void omap_prcm_arch_reset(char mode, const char *cmd)
+static void omap_prcm_arch_reset(char mode, const char *cmd)
{
s16 prcm_offs = 0;
@@ -108,6 +109,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd)
omap2_prm_read_mod_reg(prcm_offs, OMAP2_RM_RSTCTRL); /* OCP barrier */
}
+void (*arch_reset)(char, const char *) = omap_prcm_arch_reset;
+
/**
* omap2_cm_wait_idlest - wait for IDLEST bit to indicate module readiness
* @reg: physical address of module IDLEST register
diff --git a/arch/arm/mach-omap2/prcm_mpu44xx.h b/arch/arm/mach-omap2/prcm_mpu44xx.h
index 3300ff6e3cfe..d22d1b43bccd 100644
--- a/arch/arm/mach-omap2/prcm_mpu44xx.h
+++ b/arch/arm/mach-omap2/prcm_mpu44xx.h
@@ -38,8 +38,8 @@
#define OMAP4430_PRCM_MPU_CPU1_INST 0x0800
/* PRCM_MPU clockdomain register offsets (from instance start) */
-#define OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS 0x0018
-#define OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS 0x0018
+#define OMAP4430_PRCM_MPU_CPU0_CPU0_CDOFFS 0x0018
+#define OMAP4430_PRCM_MPU_CPU1_CPU1_CDOFFS 0x0018
/*
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index ec0362574b5e..051213fbc346 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -118,7 +118,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
/**
* omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
- * @shift: register bit shift corresponding to the reset line to deassert
+ * @rst_shift: register bit shift corresponding to the reset line to deassert
+ * @st_shift: register bit shift for the status of the deasserted submodule
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
@@ -129,27 +130,28 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
-int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift)
{
- u32 mask;
+ u32 rst, st;
int c;
if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
return -EINVAL;
- mask = 1 << shift;
+ rst = 1 << rst_shift;
+ st = 1 << st_shift;
/* Check the current status to avoid de-asserting the line twice */
- if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0)
+ if (omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, rst) == 0)
return -EEXIST;
/* Clear the reset status by writing 1 to the status bit */
- omap2_prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST);
+ omap2_prm_rmw_mod_reg_bits(0xffffffff, st, prm_mod, OMAP2_RM_RSTST);
/* de-assert the reset control line */
- omap2_prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL);
+ omap2_prm_rmw_mod_reg_bits(rst, 0, prm_mod, OMAP2_RM_RSTCTRL);
/* wait the status to be set */
omap_test_timeout(omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
- mask),
+ st),
MAX_MODULE_HARDRESET_WAIT, c);
return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 49654c8d18f5..a1fc62a39dbb 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -282,7 +282,8 @@ static inline int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
"not suppose to be used on omap4\n");
return 0;
}
-static inline int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+static inline int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift,
+ u8 st_shift)
{
WARN(1, "prm: omap2xxx/omap3xxx specific function and "
"not suppose to be used on omap4\n");
@@ -300,7 +301,7 @@ extern u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask);
/* These omap2_ PRM functions apply to both OMAP2 and 3 */
extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
-extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
+extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift);
#endif /* CONFIG_ARCH_OMAP4 */
#endif
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 32e91a9c8b6b..1ac361b7b8cb 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -486,7 +486,7 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
mod_timer(&uart->timer, jiffies + uart->timeout);
omap_uart_smart_idle_enable(uart, 0);
- if (cpu_is_omap34xx()) {
+ if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
u32 wk_mask = 0;
u32 padconf = 0;
@@ -655,7 +655,7 @@ static void serial_out_override(struct uart_port *up, int offset, int value)
}
#endif
-void __init omap_serial_early_init(void)
+static int __init omap_serial_early_init(void)
{
int i = 0;
@@ -672,7 +672,7 @@ void __init omap_serial_early_init(void)
uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
if (WARN_ON(!uart))
- return;
+ return -ENODEV;
uart->oh = oh;
uart->num = i++;
@@ -680,7 +680,7 @@ void __init omap_serial_early_init(void)
num_uarts++;
/*
- * NOTE: omap_hwmod_init() has not yet been called,
+ * NOTE: omap_hwmod_setup*() has not yet been called,
* so no hwmod functions will work yet.
*/
@@ -691,7 +691,10 @@ void __init omap_serial_early_init(void)
*/
uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
} while (1);
+
+ return 0;
}
+core_initcall(omap_serial_early_init);
/**
* omap_serial_init_port() - initialize single serial port
@@ -759,13 +762,13 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
p->private_data = uart;
/*
- * omap44xx: Never read empty UART fifo
+ * omap44xx, ti816x: Never read empty UART fifo
* omap3xxx: Never read empty UART fifo on UARTs
* with IP rev >=0x52
*/
uart->regshift = p->regshift;
uart->membase = p->membase;
- if (cpu_is_omap44xx())
+ if (cpu_is_omap44xx() || cpu_is_ti816x())
uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
@@ -847,7 +850,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
}
/* Enable the MDR1 errata for OMAP3 */
- if (cpu_is_omap34xx())
+ if (cpu_is_omap34xx() && !cpu_is_ti816x())
uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
}
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index 951a0be66cf7..63f10669571a 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -64,6 +64,11 @@
#define SDRC_DLLA_STATUS_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
#define SDRC_DLLA_CTRL_V OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+/*
+ * This file needs be built unconditionally as ARM to interoperate correctly
+ * with non-Thumb-2-capable firmware.
+ */
+ .arm
/*
* API functions
@@ -82,6 +87,8 @@ ENTRY(get_restore_pointer)
stmfd sp!, {lr} @ save registers on stack
adr r0, restore
ldmfd sp!, {pc} @ restore regs and return
+ENDPROC(get_restore_pointer)
+ .align
ENTRY(get_restore_pointer_sz)
.word . - get_restore_pointer
@@ -91,6 +98,8 @@ ENTRY(get_omap3630_restore_pointer)
stmfd sp!, {lr} @ save registers on stack
adr r0, restore_3630
ldmfd sp!, {pc} @ restore regs and return
+ENDPROC(get_omap3630_restore_pointer)
+ .align
ENTRY(get_omap3630_restore_pointer_sz)
.word . - get_omap3630_restore_pointer
@@ -100,6 +109,8 @@ ENTRY(get_es3_restore_pointer)
stmfd sp!, {lr} @ save registers on stack
adr r0, restore_es3
ldmfd sp!, {pc} @ restore regs and return
+ENDPROC(get_es3_restore_pointer)
+ .align
ENTRY(get_es3_restore_pointer_sz)
.word . - get_es3_restore_pointer
@@ -113,8 +124,10 @@ ENTRY(enable_omap3630_toggle_l2_on_restore)
stmfd sp!, {lr} @ save registers on stack
/* Setup so that we will disable and enable l2 */
mov r1, #0x1
- str r1, l2dis_3630
+ adrl r2, l2dis_3630 @ may be too distant for plain adr
+ str r1, [r2]
ldmfd sp!, {pc} @ restore regs and return
+ENDPROC(enable_omap3630_toggle_l2_on_restore)
.text
/* Function to call rom code to save secure ram context */
@@ -132,20 +145,22 @@ ENTRY(save_secure_ram_context)
mov r1, #0 @ set task id for ROM code in r1
mov r2, #4 @ set some flags in r2, r6
mov r6, #0xff
- mcr p15, 0, r0, c7, c10, 4 @ data write barrier
- mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
- .word 0xE1600071 @ call SMI monitor (smi #1)
+ dsb @ data write barrier
+ dmb @ data memory barrier
+ smc #1 @ call SMI monitor (smi #1)
nop
nop
nop
nop
ldmfd sp!, {r1-r12, pc}
+ .align
sram_phy_addr_mask:
.word SRAM_BASE_P
high_mask:
.word 0xffff
api_params:
.word 0x4, 0x0, 0x0, 0x1, 0x1
+ENDPROC(save_secure_ram_context)
ENTRY(save_secure_ram_context_sz)
.word . - save_secure_ram_context
@@ -175,12 +190,12 @@ ENTRY(omap34xx_cpu_suspend)
stmfd sp!, {r0-r12, lr} @ save registers on stack
/*
- * r0 contains restore pointer in sdram
+ * r0 contains CPU context save/restore pointer in sdram
* r1 contains information about saving context:
* 0 - No context lost
* 1 - Only L1 and logic lost
- * 2 - Only L2 lost
- * 3 - Both L1 and L2 lost
+ * 2 - Only L2 lost (Even L1 is retained we clean it along with L2)
+ * 3 - Both L1 and L2 lost and logic lost
*/
/* Directly jump to WFI is the context save is not required */
@@ -201,89 +216,74 @@ save_context_wfi:
beq clean_caches
l1_logic_lost:
- /* Store sp and spsr to SDRAM */
- mov r4, sp
- mrs r5, spsr
- mov r6, lr
+ mov r4, sp @ Store sp
+ mrs r5, spsr @ Store spsr
+ mov r6, lr @ Store lr
stmia r8!, {r4-r6}
- /* Save all ARM registers */
- /* Coprocessor access control register */
- mrc p15, 0, r6, c1, c0, 2
- stmia r8!, {r6}
- /* TTBR0, TTBR1 and Translation table base control */
- mrc p15, 0, r4, c2, c0, 0
- mrc p15, 0, r5, c2, c0, 1
- mrc p15, 0, r6, c2, c0, 2
- stmia r8!, {r4-r6}
- /*
- * Domain access control register, data fault status register,
- * and instruction fault status register
- */
- mrc p15, 0, r4, c3, c0, 0
- mrc p15, 0, r5, c5, c0, 0
- mrc p15, 0, r6, c5, c0, 1
- stmia r8!, {r4-r6}
- /*
- * Data aux fault status register, instruction aux fault status,
- * data fault address register and instruction fault address register
- */
- mrc p15, 0, r4, c5, c1, 0
- mrc p15, 0, r5, c5, c1, 1
- mrc p15, 0, r6, c6, c0, 0
- mrc p15, 0, r7, c6, c0, 2
- stmia r8!, {r4-r7}
- /*
- * user r/w thread and process ID, user r/o thread and process ID,
- * priv only thread and process ID, cache size selection
- */
- mrc p15, 0, r4, c13, c0, 2
- mrc p15, 0, r5, c13, c0, 3
- mrc p15, 0, r6, c13, c0, 4
- mrc p15, 2, r7, c0, c0, 0
+
+ mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register
+ mrc p15, 0, r5, c2, c0, 0 @ TTBR0
+ mrc p15, 0, r6, c2, c0, 1 @ TTBR1
+ mrc p15, 0, r7, c2, c0, 2 @ TTBCR
stmia r8!, {r4-r7}
- /* Data TLB lockdown, instruction TLB lockdown registers */
- mrc p15, 0, r5, c10, c0, 0
- mrc p15, 0, r6, c10, c0, 1
- stmia r8!, {r5-r6}
- /* Secure or non secure vector base address, FCSE PID, Context PID*/
- mrc p15, 0, r4, c12, c0, 0
- mrc p15, 0, r5, c13, c0, 0
- mrc p15, 0, r6, c13, c0, 1
- stmia r8!, {r4-r6}
- /* Primary remap, normal remap registers */
- mrc p15, 0, r4, c10, c2, 0
- mrc p15, 0, r5, c10, c2, 1
- stmia r8!,{r4-r5}
- /* Store current cpsr*/
- mrs r2, cpsr
- stmia r8!, {r2}
+ mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register
+ mrc p15, 0, r5, c10, c2, 0 @ PRRR
+ mrc p15, 0, r6, c10, c2, 1 @ NMRR
+ stmia r8!,{r4-r6}
- mrc p15, 0, r4, c1, c0, 0
- /* save control register */
+ mrc p15, 0, r4, c13, c0, 1 @ Context ID
+ mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
+ mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
+ mrs r7, cpsr @ Store current cpsr
+ stmia r8!, {r4-r7}
+
+ mrc p15, 0, r4, c1, c0, 0 @ save control register
stmia r8!, {r4}
clean_caches:
/*
- * Clean Data or unified cache to POU
- * How to invalidate only L1 cache???? - #FIX_ME#
- * mcr p15, 0, r11, c7, c11, 1
- */
- cmp r1, #0x1 @ Check whether L2 inval is required
- beq omap3_do_wfi
-
-clean_l2:
- /*
* jump out to kernel flush routine
* - reuse that code is better
* - it executes in a cached space so is faster than refetch per-block
* - should be faster and will change with kernel
* - 'might' have to copy address, load and jump to it
+ * Flush all data from the L1 data cache before disabling
+ * SCTLR.C bit.
*/
ldr r1, kernel_flush
mov lr, pc
bx r1
+ /*
+ * Clear the SCTLR.C bit to prevent further data cache
+ * allocation. Clearing SCTLR.C would make all the data accesses
+ * strongly ordered and would not hit the cache.
+ */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(1 << 2) @ Disable the C bit
+ mcr p15, 0, r0, c1, c0, 0
+ isb
+
+ /*
+ * Invalidate L1 data cache. Even though only invalidate is
+ * necessary exported flush API is used here. Doing clean
+ * on already clean cache would be almost NOP.
+ */
+ ldr r1, kernel_flush
+ blx r1
+ /*
+ * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
+ * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
+ * This sequence switches back to ARM. Note that .align may insert a
+ * nop: bx pc needs to be word-aligned in order to work.
+ */
+ THUMB( .thumb )
+ THUMB( .align )
+ THUMB( bx pc )
+ THUMB( nop )
+ .arm
+
omap3_do_wfi:
ldr r4, sdrc_power @ read the SDRC_POWER register
ldr r5, [r4] @ read the contents of SDRC_POWER
@@ -291,9 +291,8 @@ omap3_do_wfi:
str r5, [r4] @ write back to SDRC_POWER register
/* Data memory barrier and Data sync barrier */
- mov r1, #0
- mcr p15, 0, r1, c7, c10, 4
- mcr p15, 0, r1, c7, c10, 5
+ dsb
+ dmb
/*
* ===================================
@@ -319,6 +318,12 @@ omap3_do_wfi:
nop
bl wait_sdrc_ok
+ mrc p15, 0, r0, c1, c0, 0
+ tst r0, #(1 << 2) @ Check C bit enabled?
+ orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared
+ mcreq p15, 0, r0, c1, c0, 0
+ isb
+
/*
* ===================================
* == Exit point from non-OFF modes ==
@@ -408,9 +413,9 @@ skipl2dis:
mov r2, #4 @ set some flags in r2, r6
mov r6, #0xff
adr r3, l2_inv_api_params @ r3 points to dummy parameters
- mcr p15, 0, r0, c7, c10, 4 @ data write barrier
- mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
- .word 0xE1600071 @ call SMI monitor (smi #1)
+ dsb @ data write barrier
+ dmb @ data memory barrier
+ smc #1 @ call SMI monitor (smi #1)
/* Write to Aux control register to set some bits */
mov r0, #42 @ set service ID for PPA
mov r12, r0 @ copy secure Service ID in r12
@@ -419,9 +424,9 @@ skipl2dis:
mov r6, #0xff
ldr r4, scratchpad_base
ldr r3, [r4, #0xBC] @ r3 points to parameters
- mcr p15, 0, r0, c7, c10, 4 @ data write barrier
- mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
- .word 0xE1600071 @ call SMI monitor (smi #1)
+ dsb @ data write barrier
+ dmb @ data memory barrier
+ smc #1 @ call SMI monitor (smi #1)
#ifdef CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE
/* Restore L2 aux control register */
@@ -434,29 +439,30 @@ skipl2dis:
ldr r4, scratchpad_base
ldr r3, [r4, #0xBC]
adds r3, r3, #8 @ r3 points to parameters
- mcr p15, 0, r0, c7, c10, 4 @ data write barrier
- mcr p15, 0, r0, c7, c10, 5 @ data memory barrier
- .word 0xE1600071 @ call SMI monitor (smi #1)
+ dsb @ data write barrier
+ dmb @ data memory barrier
+ smc #1 @ call SMI monitor (smi #1)
#endif
b logic_l1_restore
+ .align
l2_inv_api_params:
.word 0x1, 0x00
l2_inv_gp:
/* Execute smi to invalidate L2 cache */
mov r12, #0x1 @ set up to invalidate L2
- .word 0xE1600070 @ Call SMI monitor (smieq)
+ smc #0 @ Call SMI monitor (smieq)
/* Write to Aux control register to set some bits */
ldr r4, scratchpad_base
ldr r3, [r4,#0xBC]
ldr r0, [r3,#4]
mov r12, #0x3
- .word 0xE1600070 @ Call SMI monitor (smieq)
+ smc #0 @ Call SMI monitor (smieq)
ldr r4, scratchpad_base
ldr r3, [r4,#0xBC]
ldr r0, [r3,#12]
mov r12, #0x2
- .word 0xE1600070 @ Call SMI monitor (smieq)
+ smc #0 @ Call SMI monitor (smieq)
logic_l1_restore:
ldr r1, l2dis_3630
cmp r1, #0x1 @ Test if L2 re-enable needed on 3630
@@ -475,68 +481,29 @@ skipl2reen:
ldr r4, scratchpad_base
ldr r3, [r4,#0xBC]
adds r3, r3, #16
+
ldmia r3!, {r4-r6}
- mov sp, r4
- msr spsr_cxsf, r5
- mov lr, r6
-
- ldmia r3!, {r4-r9}
- /* Coprocessor access Control Register */
- mcr p15, 0, r4, c1, c0, 2
-
- /* TTBR0 */
- MCR p15, 0, r5, c2, c0, 0
- /* TTBR1 */
- MCR p15, 0, r6, c2, c0, 1
- /* Translation table base control register */
- MCR p15, 0, r7, c2, c0, 2
- /* Domain access Control Register */
- MCR p15, 0, r8, c3, c0, 0
- /* Data fault status Register */
- MCR p15, 0, r9, c5, c0, 0
-
- ldmia r3!,{r4-r8}
- /* Instruction fault status Register */
- MCR p15, 0, r4, c5, c0, 1
- /* Data Auxiliary Fault Status Register */
- MCR p15, 0, r5, c5, c1, 0
- /* Instruction Auxiliary Fault Status Register*/
- MCR p15, 0, r6, c5, c1, 1
- /* Data Fault Address Register */
- MCR p15, 0, r7, c6, c0, 0
- /* Instruction Fault Address Register*/
- MCR p15, 0, r8, c6, c0, 2
- ldmia r3!,{r4-r7}
+ mov sp, r4 @ Restore sp
+ msr spsr_cxsf, r5 @ Restore spsr
+ mov lr, r6 @ Restore lr
+
+ ldmia r3!, {r4-r7}
+ mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register
+ mcr p15, 0, r5, c2, c0, 0 @ TTBR0
+ mcr p15, 0, r6, c2, c0, 1 @ TTBR1
+ mcr p15, 0, r7, c2, c0, 2 @ TTBCR
- /* User r/w thread and process ID */
- MCR p15, 0, r4, c13, c0, 2
- /* User ro thread and process ID */
- MCR p15, 0, r5, c13, c0, 3
- /* Privileged only thread and process ID */
- MCR p15, 0, r6, c13, c0, 4
- /* Cache size selection */
- MCR p15, 2, r7, c0, c0, 0
- ldmia r3!,{r4-r8}
- /* Data TLB lockdown registers */
- MCR p15, 0, r4, c10, c0, 0
- /* Instruction TLB lockdown registers */
- MCR p15, 0, r5, c10, c0, 1
- /* Secure or Nonsecure Vector Base Address */
- MCR p15, 0, r6, c12, c0, 0
- /* FCSE PID */
- MCR p15, 0, r7, c13, c0, 0
- /* Context PID */
- MCR p15, 0, r8, c13, c0, 1
-
- ldmia r3!,{r4-r5}
- /* Primary memory remap register */
- MCR p15, 0, r4, c10, c2, 0
- /* Normal memory remap register */
- MCR p15, 0, r5, c10, c2, 1
-
- /* Restore cpsr */
- ldmia r3!,{r4} @ load CPSR from SDRAM
- msr cpsr, r4 @ store cpsr
+ ldmia r3!,{r4-r6}
+ mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register
+ mcr p15, 0, r5, c10, c2, 0 @ PRRR
+ mcr p15, 0, r6, c10, c2, 1 @ NMRR
+
+
+ ldmia r3!,{r4-r7}
+ mcr p15, 0, r4, c13, c0, 1 @ Context ID
+ mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
+ mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
+ msr cpsr, r7 @ store cpsr
/* Enabling MMU here */
mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl
@@ -594,12 +561,17 @@ usettbr0:
ldr r2, cache_pred_disable_mask
and r4, r2
mcr p15, 0, r4, c1, c0, 0
+ dsb
+ isb
+ ldr r0, =restoremmu_on
+ bx r0
/*
* ==============================
* == Exit point from OFF mode ==
* ==============================
*/
+restoremmu_on:
ldmfd sp!, {r0-r12, pc} @ restore regs and return
@@ -609,6 +581,7 @@ usettbr0:
/* This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0 */
.text
+ .align 3
ENTRY(es3_sdrc_fix)
ldr r4, sdrc_syscfg @ get config addr
ldr r5, [r4] @ get value
@@ -636,6 +609,7 @@ ENTRY(es3_sdrc_fix)
str r5, [r4] @ kick off refreshes
bx lr
+ .align
sdrc_syscfg:
.word SDRC_SYSCONFIG_P
sdrc_mr_0:
@@ -650,6 +624,7 @@ sdrc_emr2_1:
.word SDRC_EMR2_1_P
sdrc_manual_1:
.word SDRC_MANUAL_1_P
+ENDPROC(es3_sdrc_fix)
ENTRY(es3_sdrc_fix_sz)
.word . - es3_sdrc_fix
@@ -684,6 +659,12 @@ wait_sdrc_ready:
bic r5, r5, #0x40
str r5, [r4]
+/*
+ * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a
+ * base instead.
+ * Be careful not to clobber r7 when maintaing this code.
+ */
+
is_dll_in_lock_mode:
/* Is dll in lock mode? */
ldr r4, sdrc_dlla_ctrl
@@ -691,10 +672,11 @@ is_dll_in_lock_mode:
tst r5, #0x4
bxne lr @ Return if locked
/* wait till dll locks */
+ adr r7, kick_counter
wait_dll_lock_timed:
ldr r4, wait_dll_lock_counter
add r4, r4, #1
- str r4, wait_dll_lock_counter
+ str r4, [r7, #wait_dll_lock_counter - kick_counter]
ldr r4, sdrc_dlla_status
/* Wait 20uS for lock */
mov r6, #8
@@ -720,9 +702,10 @@ kick_dll:
dsb
ldr r4, kick_counter
add r4, r4, #1
- str r4, kick_counter
+ str r4, [r7] @ kick_counter
b wait_dll_lock_timed
+ .align
cm_idlest1_core:
.word CM_IDLEST1_CORE_V
cm_idlest_ckgen:
@@ -765,6 +748,7 @@ kick_counter:
.word 0
wait_dll_lock_counter:
.word 0
+ENDPROC(omap34xx_cpu_suspend)
ENTRY(omap34xx_cpu_suspend_sz)
.word . - omap34xx_cpu_suspend
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index 60e70552b4c5..f438cf4d847b 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -11,7 +11,7 @@
* published by the Free Software Foundation.
*/
-#include <plat/smartreflex.h>
+#include "smartreflex.h"
static int sr_class3_enable(struct voltagedomain *voltdm)
{
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 1a777e34d0c2..8f674c9442bf 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -26,9 +26,9 @@
#include <linux/pm_runtime.h>
#include <plat/common.h>
-#include <plat/smartreflex.h>
#include "pm.h"
+#include "smartreflex.h"
#define SMARTREFLEX_NAME_LEN 16
#define NVALUE_NAME_LEN 40
@@ -54,6 +54,7 @@ struct omap_sr {
struct list_head node;
struct omap_sr_nvalue_table *nvalue_table;
struct voltagedomain *voltdm;
+ struct dentry *dbg_dir;
};
/* sr_list contains all the instances of smartreflex module */
@@ -260,9 +261,11 @@ static int sr_late_init(struct omap_sr *sr_info)
if (sr_class->class_type == SR_CLASS2 &&
sr_class->notify_flags && sr_info->irq) {
- name = kzalloc(SMARTREFLEX_NAME_LEN + 1, GFP_KERNEL);
- strcpy(name, "sr_");
- strcat(name, sr_info->voltdm->name);
+ name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
+ if (name == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
ret = request_irq(sr_info->irq, sr_interrupt,
0, name, (void *)sr_info);
if (ret)
@@ -821,7 +824,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
struct omap_sr_data *pdata = pdev->dev.platform_data;
struct resource *mem, *irq;
- struct dentry *vdd_dbg_dir, *dbg_dir, *nvalue_dir;
+ struct dentry *vdd_dbg_dir, *nvalue_dir;
struct omap_volt_data *volt_data;
int i, ret = 0;
@@ -896,24 +899,24 @@ static int __init omap_sr_probe(struct platform_device *pdev)
goto err_release_region;
}
- dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
- if (IS_ERR(dbg_dir)) {
+ sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
+ if (IS_ERR(sr_info->dbg_dir)) {
dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
__func__);
- ret = PTR_ERR(dbg_dir);
+ ret = PTR_ERR(sr_info->dbg_dir);
goto err_release_region;
}
- (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, dbg_dir,
- (void *)sr_info, &pm_sr_fops);
- (void) debugfs_create_x32("errweight", S_IRUGO, dbg_dir,
+ (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
+ sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops);
+ (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir,
&sr_info->err_weight);
- (void) debugfs_create_x32("errmaxlimit", S_IRUGO, dbg_dir,
+ (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir,
&sr_info->err_maxlimit);
- (void) debugfs_create_x32("errminlimit", S_IRUGO, dbg_dir,
+ (void) debugfs_create_x32("errminlimit", S_IRUGO, sr_info->dbg_dir,
&sr_info->err_minlimit);
- nvalue_dir = debugfs_create_dir("nvalue", dbg_dir);
+ nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir);
if (IS_ERR(nvalue_dir)) {
dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
"for n-values\n", __func__);
@@ -970,6 +973,8 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
if (sr_info->autocomp_active)
sr_stop_vddautocomp(sr_info);
+ if (sr_info->dbg_dir)
+ debugfs_remove_recursive(sr_info->dbg_dir);
list_del(&sr_info->node);
iounmap(sr_info->base);
diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
index 6568c885f37a..5f35b9e25556 100644
--- a/arch/arm/plat-omap/include/plat/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -21,7 +21,8 @@
#define __ASM_ARM_OMAP_SMARTREFLEX_H
#include <linux/platform_device.h>
-#include <plat/voltage.h>
+
+#include "voltage.h"
/*
* Different Smartreflex IPs version. The v1 is the 65nm version used in
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index b1e0af18a26a..10d3c5ee8018 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -23,9 +23,9 @@
#include <linux/io.h>
#include <plat/omap_device.h>
-#include <plat/smartreflex.h>
-#include <plat/voltage.h>
+#include "smartreflex.h"
+#include "voltage.h"
#include "control.h"
#include "pm.h"
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index 25011ca2145d..6f5849aaa7c0 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -34,6 +34,12 @@
#include "sdrc.h"
#include "cm2xxx_3xxx.h"
+/*
+ * This file needs be built unconditionally as ARM to interoperate correctly
+ * with non-Thumb-2-capable firmware.
+ */
+ .arm
+
.text
/* r1 parameters */
@@ -117,24 +123,36 @@ ENTRY(omap3_sram_configure_core_dpll)
@ pull the extra args off the stack
@ and store them in SRAM
+
+/*
+ * PC-relative stores are deprecated in ARMv7 and lead to undefined behaviour
+ * in Thumb-2: use a r7 as a base instead.
+ * Be careful not to clobber r7 when maintaing this file.
+ */
+ THUMB( adr r7, omap3_sram_configure_core_dpll )
+ .macro strtext Rt:req, label:req
+ ARM( str \Rt, \label )
+ THUMB( str \Rt, [r7, \label - omap3_sram_configure_core_dpll] )
+ .endm
+
ldr r4, [sp, #52]
- str r4, omap_sdrc_rfr_ctrl_0_val
+ strtext r4, omap_sdrc_rfr_ctrl_0_val
ldr r4, [sp, #56]
- str r4, omap_sdrc_actim_ctrl_a_0_val
+ strtext r4, omap_sdrc_actim_ctrl_a_0_val
ldr r4, [sp, #60]
- str r4, omap_sdrc_actim_ctrl_b_0_val
+ strtext r4, omap_sdrc_actim_ctrl_b_0_val
ldr r4, [sp, #64]
- str r4, omap_sdrc_mr_0_val
+ strtext r4, omap_sdrc_mr_0_val
ldr r4, [sp, #68]
- str r4, omap_sdrc_rfr_ctrl_1_val
+ strtext r4, omap_sdrc_rfr_ctrl_1_val
cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0,
beq skip_cs1_params @ do not use cs1 params
ldr r4, [sp, #72]
- str r4, omap_sdrc_actim_ctrl_a_1_val
+ strtext r4, omap_sdrc_actim_ctrl_a_1_val
ldr r4, [sp, #76]
- str r4, omap_sdrc_actim_ctrl_b_1_val
+ strtext r4, omap_sdrc_actim_ctrl_b_1_val
ldr r4, [sp, #80]
- str r4, omap_sdrc_mr_1_val
+ strtext r4, omap_sdrc_mr_1_val
skip_cs1_params:
mrc p15, 0, r8, c1, c0, 0 @ read ctrl register
bic r10, r8, #0x800 @ clear Z-bit, disable branch prediction
@@ -272,6 +290,7 @@ skip_cs1_prog:
ldr r12, [r11] @ posted-write barrier for SDRC
bx lr
+ .align
omap3_sdrc_power:
.word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
omap3_cm_clksel1_pll:
@@ -320,6 +339,7 @@ omap3_sdrc_dlla_ctrl:
.word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
core_m2_mask_val:
.word 0x07FFFFFF
+ENDPROC(omap3_sram_configure_core_dpll)
ENTRY(omap3_sram_configure_core_dpll_sz)
.word . - omap3_sram_configure_core_dpll
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 0fc550e7e482..3b9cf85f4bb9 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -40,10 +40,11 @@
#include <plat/dmtimer.h>
#include <asm/localtimer.h>
#include <asm/sched_clock.h>
+#include <plat/common.h>
+#include <plat/omap_hwmod.h>
#include "timer-gp.h"
-#include <plat/common.h>
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID 12
@@ -133,9 +134,13 @@ static void __init omap2_gp_clockevent_init(void)
{
u32 tick_rate;
int src;
+ char clockevent_hwmod_name[8]; /* 8 = sizeof("timerXX0") */
inited = 1;
+ sprintf(clockevent_hwmod_name, "timer%d", gptimer_id);
+ omap_hwmod_setup_one(clockevent_hwmod_name);
+
gptimer = omap_dm_timer_request_specific(gptimer_id);
BUG_ON(gptimer == NULL);
gptimer_wakeup = gptimer;
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 241fc94b4116..35559f77e2de 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -30,118 +30,11 @@
#include <mach/irqs.h>
#include <mach/am35xx.h>
#include <plat/usb.h>
-#include "control.h"
+#include <plat/omap_device.h>
+#include "mux.h"
#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
-static void am35x_musb_reset(void)
-{
- u32 regval;
-
- /* Reset the musb interface */
- regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-
- regval |= AM35XX_USBOTGSS_SW_RST;
- omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
-
- regval &= ~AM35XX_USBOTGSS_SW_RST;
- omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
-
- regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
-}
-
-static void am35x_musb_phy_power(u8 on)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(100);
- u32 devconf2;
-
- if (on) {
- /*
- * Start the on-chip PHY and its PLL.
- */
- devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
- devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
- devconf2 |= CONF2_PHY_PLLON;
-
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
-
- pr_info(KERN_INFO "Waiting for PHY clock good...\n");
- while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
- & CONF2_PHYCLKGD)) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- pr_err(KERN_ERR "musb PHY clock good timed out\n");
- break;
- }
- }
- } else {
- /*
- * Power down the on-chip PHY.
- */
- devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
- devconf2 &= ~CONF2_PHY_PLLON;
- devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
- }
-}
-
-static void am35x_musb_clear_irq(void)
-{
- u32 regval;
-
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval |= AM35XX_USBOTGSS_INT_CLR;
- omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
-}
-
-static void am35x_musb_set_mode(u8 musb_mode)
-{
- u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
-
- devconf2 &= ~CONF2_OTGMODE;
- switch (musb_mode) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- case MUSB_HOST: /* Force VBUS valid, ID = 0 */
- devconf2 |= CONF2_FORCE_HOST;
- break;
-#endif
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
- devconf2 |= CONF2_FORCE_DEVICE;
- break;
-#endif
-#ifdef CONFIG_USB_MUSB_OTG
- case MUSB_OTG: /* Don't override the VBUS/ID comparators */
- devconf2 |= CONF2_NO_OVERRIDE;
- break;
-#endif
- default:
- pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
- }
-
- omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
-}
-
-static struct resource musb_resources[] = {
- [0] = { /* start and end set dynamically */
- .flags = IORESOURCE_MEM,
- },
- [1] = { /* general IRQ */
- .start = INT_243X_HS_USB_MC,
- .flags = IORESOURCE_IRQ,
- .name = "mc",
- },
- [2] = { /* DMA IRQ */
- .start = INT_243X_HS_USB_DMA,
- .flags = IORESOURCE_IRQ,
- .name = "dma",
- },
-};
-
static struct musb_hdrc_config musb_config = {
.multipoint = 1,
.dyn_fifo = 1,
@@ -169,38 +62,65 @@ static struct musb_hdrc_platform_data musb_plat = {
static u64 musb_dmamask = DMA_BIT_MASK(32);
-static struct platform_device musb_device = {
- .name = "musb-omap2430",
- .id = -1,
- .dev = {
- .dma_mask = &musb_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &musb_plat,
+static struct omap_device_pm_latency omap_musb_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
- .num_resources = ARRAY_SIZE(musb_resources),
- .resource = musb_resources,
};
+static void usb_musb_mux_init(struct omap_musb_board_data *board_data)
+{
+ switch (board_data->interface_type) {
+ case MUSB_INTERFACE_UTMI:
+ omap_mux_init_signal("usba0_otg_dp", OMAP_PIN_INPUT);
+ omap_mux_init_signal("usba0_otg_dm", OMAP_PIN_INPUT);
+ break;
+ case MUSB_INTERFACE_ULPI:
+ omap_mux_init_signal("usba0_ulpiphy_clk",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_stp",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dir",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_nxt",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat0",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat1",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat2",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat3",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat4",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat5",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat6",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("usba0_ulpiphy_dat7",
+ OMAP_PIN_INPUT_PULLDOWN);
+ break;
+ default:
+ break;
+ }
+}
+
void __init usb_musb_init(struct omap_musb_board_data *board_data)
{
- if (cpu_is_omap243x()) {
- musb_resources[0].start = OMAP243X_HS_BASE;
- } else if (cpu_is_omap3517() || cpu_is_omap3505()) {
- musb_device.name = "musb-am35x";
- musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
- musb_resources[1].start = INT_35XX_USBOTG_IRQ;
- board_data->set_phy_power = am35x_musb_phy_power;
- board_data->clear_irq = am35x_musb_clear_irq;
- board_data->set_mode = am35x_musb_set_mode;
- board_data->reset = am35x_musb_reset;
- } else if (cpu_is_omap34xx()) {
- musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ struct platform_device *pdev;
+ struct device *dev;
+ int bus_id = -1;
+ const char *oh_name, *name;
+
+ if (cpu_is_omap3517() || cpu_is_omap3505()) {
} else if (cpu_is_omap44xx()) {
- musb_resources[0].start = OMAP44XX_HSUSB_OTG_BASE;
- musb_resources[1].start = OMAP44XX_IRQ_HS_USB_MC_N;
- musb_resources[2].start = OMAP44XX_IRQ_HS_USB_DMA_N;
+ usb_musb_mux_init(board_data);
}
- musb_resources[0].end = musb_resources[0].start + SZ_4K - 1;
/*
* REVISIT: This line can be removed once all the platforms using
@@ -212,12 +132,38 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
musb_plat.mode = board_data->mode;
musb_plat.extvbus = board_data->extvbus;
- if (platform_device_register(&musb_device) < 0)
- printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
-
if (cpu_is_omap44xx())
omap4430_phy_init(dev);
+ if (cpu_is_omap3517() || cpu_is_omap3505()) {
+ oh_name = "am35x_otg_hs";
+ name = "musb-am35x";
+ } else {
+ oh_name = "usb_otg_hs";
+ name = "musb-omap2430";
+ }
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ return;
+ }
+
+ od = omap_device_build(name, bus_id, oh, &musb_plat,
+ sizeof(musb_plat), omap_musb_latency,
+ ARRAY_SIZE(omap_musb_latency), false);
+ if (IS_ERR(od)) {
+ pr_err("Could not build omap_device for %s %s\n",
+ name, oh_name);
+ return;
+ }
+
+ pdev = &od->pdev;
+ dev = &pdev->dev;
+ get_device(dev);
+ dev->dma_mask = &musb_dmamask;
+ dev->coherent_dma_mask = musb_dmamask;
+ put_device(dev);
}
#else
diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h
new file mode 100644
index 000000000000..e7767771de49
--- /dev/null
+++ b/arch/arm/mach-omap2/vc.h
@@ -0,0 +1,83 @@
+/*
+ * OMAP3/4 Voltage Controller (VC) structure and macro definitions
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_VC_H
+#define __ARCH_ARM_MACH_OMAP2_VC_H
+
+#include <linux/kernel.h>
+
+/**
+ * struct omap_vc_common_data - per-VC register/bitfield data
+ * @cmd_on_mask: ON bitmask in PRM_VC_CMD_VAL* register
+ * @valid: VALID bitmask in PRM_VC_BYPASS_VAL register
+ * @smps_sa_reg: Offset of PRM_VC_SMPS_SA reg from PRM start
+ * @smps_volra_reg: Offset of PRM_VC_SMPS_VOL_RA reg from PRM start
+ * @bypass_val_reg: Offset of PRM_VC_BYPASS_VAL reg from PRM start
+ * @data_shift: DATA field shift in PRM_VC_BYPASS_VAL register
+ * @slaveaddr_shift: SLAVEADDR field shift in PRM_VC_BYPASS_VAL register
+ * @regaddr_shift: REGADDR field shift in PRM_VC_BYPASS_VAL register
+ * @cmd_on_shift: ON field shift in PRM_VC_CMD_VAL_* register
+ * @cmd_onlp_shift: ONLP field shift in PRM_VC_CMD_VAL_* register
+ * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register
+ * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register
+ *
+ * XXX One of cmd_on_mask and cmd_on_shift are not needed
+ * XXX VALID should probably be a shift, not a mask
+ */
+struct omap_vc_common_data {
+ u32 cmd_on_mask;
+ u32 valid;
+ u8 smps_sa_reg;
+ u8 smps_volra_reg;
+ u8 bypass_val_reg;
+ u8 data_shift;
+ u8 slaveaddr_shift;
+ u8 regaddr_shift;
+ u8 cmd_on_shift;
+ u8 cmd_onlp_shift;
+ u8 cmd_ret_shift;
+ u8 cmd_off_shift;
+};
+
+/**
+ * struct omap_vc_instance_data - VC per-instance data
+ * @vc_common: pointer to VC common data for this platform
+ * @smps_sa_mask: SA* bitmask in the PRM_VC_SMPS_SA register
+ * @smps_volra_mask: VOLRA* bitmask in the PRM_VC_VOL_RA register
+ * @smps_sa_shift: SA* field shift in the PRM_VC_SMPS_SA register
+ * @smps_volra_shift: VOLRA* field shift in the PRM_VC_VOL_RA register
+ *
+ * XXX It is not necessary to have both a *_mask and a *_shift -
+ * remove one
+ */
+struct omap_vc_instance_data {
+ const struct omap_vc_common_data *vc_common;
+ u32 smps_sa_mask;
+ u32 smps_volra_mask;
+ u8 cmdval_reg;
+ u8 smps_sa_shift;
+ u8 smps_volra_shift;
+};
+
+extern struct omap_vc_instance_data omap3_vc1_data;
+extern struct omap_vc_instance_data omap3_vc2_data;
+
+extern struct omap_vc_instance_data omap4_vc_mpu_data;
+extern struct omap_vc_instance_data omap4_vc_iva_data;
+extern struct omap_vc_instance_data omap4_vc_core_data;
+
+#endif
+
diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c
new file mode 100644
index 000000000000..f37dc4bc379a
--- /dev/null
+++ b/arch/arm/mach-omap2/vc3xxx_data.c
@@ -0,0 +1,63 @@
+/*
+ * OMAP3 Voltage Controller (VC) data
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+
+#include "prm-regbits-34xx.h"
+#include "voltage.h"
+
+#include "vc.h"
+
+/*
+ * VC data common to 34xx/36xx chips
+ * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file.
+ */
+static struct omap_vc_common_data omap3_vc_common = {
+ .smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET,
+ .smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET,
+ .bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET,
+ .data_shift = OMAP3430_DATA_SHIFT,
+ .slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT,
+ .regaddr_shift = OMAP3430_REGADDR_SHIFT,
+ .valid = OMAP3430_VALID_MASK,
+ .cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT,
+ .cmd_on_mask = OMAP3430_VC_CMD_ON_MASK,
+ .cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT,
+ .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT,
+ .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT,
+};
+
+struct omap_vc_instance_data omap3_vc1_data = {
+ .vc_common = &omap3_vc_common,
+ .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET,
+ .smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT,
+ .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK,
+ .smps_volra_shift = OMAP3430_VOLRA0_SHIFT,
+ .smps_volra_mask = OMAP3430_VOLRA0_MASK,
+};
+
+struct omap_vc_instance_data omap3_vc2_data = {
+ .vc_common = &omap3_vc_common,
+ .cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET,
+ .smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT,
+ .smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK,
+ .smps_volra_shift = OMAP3430_VOLRA1_SHIFT,
+ .smps_volra_mask = OMAP3430_VOLRA1_MASK,
+};
diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c
new file mode 100644
index 000000000000..a98da8ddec52
--- /dev/null
+++ b/arch/arm/mach-omap2/vc44xx_data.c
@@ -0,0 +1,75 @@
+/*
+ * OMAP4 Voltage Controller (VC) data
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+
+#include "prm44xx.h"
+#include "prm-regbits-44xx.h"
+#include "voltage.h"
+
+#include "vc.h"
+
+/*
+ * VC data common to 44xx chips
+ * XXX This stuff presumably belongs in the vc3xxx.c or vc.c file.
+ */
+static const struct omap_vc_common_data omap4_vc_common = {
+ .smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET,
+ .smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET,
+ .bypass_val_reg = OMAP4_PRM_VC_VAL_BYPASS_OFFSET,
+ .data_shift = OMAP4430_DATA_SHIFT,
+ .slaveaddr_shift = OMAP4430_SLAVEADDR_SHIFT,
+ .regaddr_shift = OMAP4430_REGADDR_SHIFT,
+ .valid = OMAP4430_VALID_MASK,
+ .cmd_on_shift = OMAP4430_ON_SHIFT,
+ .cmd_on_mask = OMAP4430_ON_MASK,
+ .cmd_onlp_shift = OMAP4430_ONLP_SHIFT,
+ .cmd_ret_shift = OMAP4430_RET_SHIFT,
+ .cmd_off_shift = OMAP4430_OFF_SHIFT,
+};
+
+/* VC instance data for each controllable voltage line */
+struct omap_vc_instance_data omap4_vc_mpu_data = {
+ .vc_common = &omap4_vc_common,
+ .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET,
+ .smps_sa_shift = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT,
+ .smps_sa_mask = OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK,
+ .smps_volra_shift = OMAP4430_VOLRA_VDD_MPU_L_SHIFT,
+ .smps_volra_mask = OMAP4430_VOLRA_VDD_MPU_L_MASK,
+};
+
+struct omap_vc_instance_data omap4_vc_iva_data = {
+ .vc_common = &omap4_vc_common,
+ .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET,
+ .smps_sa_shift = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT,
+ .smps_sa_mask = OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK,
+ .smps_volra_shift = OMAP4430_VOLRA_VDD_IVA_L_SHIFT,
+ .smps_volra_mask = OMAP4430_VOLRA_VDD_IVA_L_MASK,
+};
+
+struct omap_vc_instance_data omap4_vc_core_data = {
+ .vc_common = &omap4_vc_common,
+ .cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET,
+ .smps_sa_shift = OMAP4430_SA_VDD_CORE_L_0_6_SHIFT,
+ .smps_sa_mask = OMAP4430_SA_VDD_CORE_L_0_6_MASK,
+ .smps_volra_shift = OMAP4430_VOLRA_VDD_CORE_L_SHIFT,
+ .smps_volra_mask = OMAP4430_VOLRA_VDD_CORE_L_MASK,
+};
+
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 12be525b8df4..c6facf7becf8 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -7,8 +7,9 @@
* Rajendra Nayak <rnayak@ti.com>
* Lesly A M <x0080970@ti.com>
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2008, 2011 Nokia Corporation
* Kalle Jokiniemi
+ * Paul Walmsley
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Thara Gopinath <thara@ti.com>
@@ -26,7 +27,6 @@
#include <linux/slab.h>
#include <plat/common.h>
-#include <plat/voltage.h>
#include "prm-regbits-34xx.h"
#include "prm-regbits-44xx.h"
@@ -35,284 +35,30 @@
#include "prminst44xx.h"
#include "control.h"
-#define VP_IDLE_TIMEOUT 200
-#define VP_TRANXDONE_TIMEOUT 300
+#include "voltage.h"
+
+#include "vc.h"
+#include "vp.h"
+
#define VOLTAGE_DIR_SIZE 16
-/* Voltage processor register offsets */
-struct vp_reg_offs {
- u8 vpconfig;
- u8 vstepmin;
- u8 vstepmax;
- u8 vlimitto;
- u8 vstatus;
- u8 voltage;
-};
-
-/* Voltage Processor bit field values, shifts and masks */
-struct vp_reg_val {
- /* PRM module */
- u16 prm_mod;
- /* VPx_VPCONFIG */
- u32 vpconfig_erroroffset;
- u16 vpconfig_errorgain;
- u32 vpconfig_errorgain_mask;
- u8 vpconfig_errorgain_shift;
- u32 vpconfig_initvoltage_mask;
- u8 vpconfig_initvoltage_shift;
- u32 vpconfig_timeouten;
- u32 vpconfig_initvdd;
- u32 vpconfig_forceupdate;
- u32 vpconfig_vpenable;
- /* VPx_VSTEPMIN */
- u8 vstepmin_stepmin;
- u16 vstepmin_smpswaittimemin;
- u8 vstepmin_stepmin_shift;
- u8 vstepmin_smpswaittimemin_shift;
- /* VPx_VSTEPMAX */
- u8 vstepmax_stepmax;
- u16 vstepmax_smpswaittimemax;
- u8 vstepmax_stepmax_shift;
- u8 vstepmax_smpswaittimemax_shift;
- /* VPx_VLIMITTO */
- u8 vlimitto_vddmin;
- u8 vlimitto_vddmax;
- u16 vlimitto_timeout;
- u8 vlimitto_vddmin_shift;
- u8 vlimitto_vddmax_shift;
- u8 vlimitto_timeout_shift;
- /* PRM_IRQSTATUS*/
- u32 tranxdone_status;
-};
-
-/* Voltage controller registers and offsets */
-struct vc_reg_info {
- /* PRM module */
- u16 prm_mod;
- /* VC register offsets */
- u8 smps_sa_reg;
- u8 smps_volra_reg;
- u8 bypass_val_reg;
- u8 cmdval_reg;
- u8 voltsetup_reg;
- /*VC_SMPS_SA*/
- u8 smps_sa_shift;
- u32 smps_sa_mask;
- /* VC_SMPS_VOL_RA */
- u8 smps_volra_shift;
- u32 smps_volra_mask;
- /* VC_BYPASS_VAL */
- u8 data_shift;
- u8 slaveaddr_shift;
- u8 regaddr_shift;
- u32 valid;
- /* VC_CMD_VAL */
- u8 cmd_on_shift;
- u8 cmd_onlp_shift;
- u8 cmd_ret_shift;
- u8 cmd_off_shift;
- u32 cmd_on_mask;
- /* PRM_VOLTSETUP */
- u8 voltsetup_shift;
- u32 voltsetup_mask;
-};
-/**
- * omap_vdd_info - Per Voltage Domain info
- *
- * @volt_data : voltage table having the distinct voltages supported
- * by the domain and other associated per voltage data.
- * @pmic_info : pmic specific parameters which should be populted by
- * the pmic drivers.
- * @vp_offs : structure containing the offsets for various
- * vp registers
- * @vp_reg : the register values, shifts, masks for various
- * vp registers
- * @vc_reg : structure containing various various vc registers,
- * shifts, masks etc.
- * @voltdm : pointer to the voltage domain structure
- * @debug_dir : debug directory for this voltage domain.
- * @curr_volt : current voltage for this vdd.
- * @ocp_mod : The prm module for accessing the prm irqstatus reg.
- * @prm_irqst_reg : prm irqstatus register.
- * @vp_enabled : flag to keep track of whether vp is enabled or not
- * @volt_scale : API to scale the voltage of the vdd.
- */
-struct omap_vdd_info {
- struct omap_volt_data *volt_data;
- struct omap_volt_pmic_info *pmic_info;
- struct vp_reg_offs vp_offs;
- struct vp_reg_val vp_reg;
- struct vc_reg_info vc_reg;
- struct voltagedomain voltdm;
- struct dentry *debug_dir;
- u32 curr_volt;
- u16 ocp_mod;
- u8 prm_irqst_reg;
- bool vp_enabled;
- u32 (*read_reg) (u16 mod, u8 offset);
- void (*write_reg) (u32 val, u16 mod, u8 offset);
- int (*volt_scale) (struct omap_vdd_info *vdd,
- unsigned long target_volt);
-};
-
-static struct omap_vdd_info *vdd_info;
+static struct omap_vdd_info **vdd_info;
+
/*
* Number of scalable voltage domains.
*/
static int nr_scalable_vdd;
-/* OMAP3 VDD sturctures */
-static struct omap_vdd_info omap3_vdd_info[] = {
- {
- .vp_offs = {
- .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
- .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
- .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
- .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
- .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
- .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
- },
- .voltdm = {
- .name = "mpu",
- },
- },
- {
- .vp_offs = {
- .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
- .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
- .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
- .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
- .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
- .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
- },
- .voltdm = {
- .name = "core",
- },
- },
-};
-
-#define OMAP3_NR_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)
-
-/* OMAP4 VDD sturctures */
-static struct omap_vdd_info omap4_vdd_info[] = {
- {
- .vp_offs = {
- .vpconfig = OMAP4_PRM_VP_MPU_CONFIG_OFFSET,
- .vstepmin = OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET,
- .vstepmax = OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET,
- .vlimitto = OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET,
- .vstatus = OMAP4_PRM_VP_MPU_STATUS_OFFSET,
- .voltage = OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET,
- },
- .voltdm = {
- .name = "mpu",
- },
- },
- {
- .vp_offs = {
- .vpconfig = OMAP4_PRM_VP_IVA_CONFIG_OFFSET,
- .vstepmin = OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET,
- .vstepmax = OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET,
- .vlimitto = OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET,
- .vstatus = OMAP4_PRM_VP_IVA_STATUS_OFFSET,
- .voltage = OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET,
- },
- .voltdm = {
- .name = "iva",
- },
- },
- {
- .vp_offs = {
- .vpconfig = OMAP4_PRM_VP_CORE_CONFIG_OFFSET,
- .vstepmin = OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET,
- .vstepmax = OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET,
- .vlimitto = OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET,
- .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET,
- .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET,
- },
- .voltdm = {
- .name = "core",
- },
- },
-};
-
-#define OMAP4_NR_SCALABLE_VDD ARRAY_SIZE(omap4_vdd_info)
-
-/*
- * Structures containing OMAP3430/OMAP3630 voltage supported and various
- * voltage dependent data for each VDD.
- */
-#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \
-{ \
- .volt_nominal = _v_nom, \
- .sr_efuse_offs = _efuse_offs, \
- .sr_errminlimit = _errminlimit, \
- .vp_errgain = _errgain \
-}
-
-/* VDD1 */
-static struct omap_volt_data omap34xx_vddmpu_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18),
- VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18),
- VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-static struct omap_volt_data omap36xx_vddmpu_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16),
- VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23),
- VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-/* VDD2 */
-static struct omap_volt_data omap34xx_vddcore_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-static struct omap_volt_data omap36xx_vddcore_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-/*
- * Structures containing OMAP4430 voltage supported and various
- * voltage dependent data for each VDD.
- */
-static struct omap_volt_data omap44xx_vdd_mpu_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP50_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP50, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPP100_UV, OMAP44XX_CONTROL_FUSE_MPU_OPP100, 0xf9, 0x16),
- VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPTURBO, 0xfa, 0x23),
- VOLT_DATA_DEFINE(OMAP4430_VDD_MPU_OPPNITRO_UV, OMAP44XX_CONTROL_FUSE_MPU_OPPNITRO, 0xfa, 0x27),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-static struct omap_volt_data omap44xx_vdd_iva_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP50_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP50, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPP100_UV, OMAP44XX_CONTROL_FUSE_IVA_OPP100, 0xf9, 0x16),
- VOLT_DATA_DEFINE(OMAP4430_VDD_IVA_OPPTURBO_UV, OMAP44XX_CONTROL_FUSE_IVA_OPPTURBO, 0xfa, 0x23),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
-
-static struct omap_volt_data omap44xx_vdd_core_volt_data[] = {
- VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP50_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP50, 0xf4, 0x0c),
- VOLT_DATA_DEFINE(OMAP4430_VDD_CORE_OPP100_UV, OMAP44XX_CONTROL_FUSE_CORE_OPP100, 0xf9, 0x16),
- VOLT_DATA_DEFINE(0, 0, 0, 0),
-};
+/* XXX document */
+static s16 prm_mod_offs;
+static s16 prm_irqst_ocp_mod_offs;
static struct dentry *voltage_dir;
/* Init function pointers */
-static void (*vc_init) (struct omap_vdd_info *vdd);
-static int (*vdd_data_configure) (struct omap_vdd_info *vdd);
+static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
+ unsigned long target_volt);
static u32 omap3_voltage_read_reg(u16 mod, u8 offset)
{
@@ -335,6 +81,62 @@ static void omap4_voltage_write_reg(u32 val, u16 mod, u8 offset)
omap4_prminst_write_inst_reg(val, OMAP4430_PRM_PARTITION, mod, offset);
}
+static int __init _config_common_vdd_data(struct omap_vdd_info *vdd)
+{
+ char *sys_ck_name;
+ struct clk *sys_ck;
+ u32 sys_clk_speed, timeout_val, waittime;
+
+ /*
+ * XXX Clockfw should handle this, or this should be in a
+ * struct record
+ */
+ if (cpu_is_omap24xx() || cpu_is_omap34xx())
+ sys_ck_name = "sys_ck";
+ else if (cpu_is_omap44xx())
+ sys_ck_name = "sys_clkin_ck";
+ else
+ return -EINVAL;
+
+ /*
+ * Sys clk rate is require to calculate vp timeout value and
+ * smpswaittimemin and smpswaittimemax.
+ */
+ sys_ck = clk_get(NULL, sys_ck_name);
+ if (IS_ERR(sys_ck)) {
+ pr_warning("%s: Could not get the sys clk to calculate"
+ "various vdd_%s params\n", __func__, vdd->voltdm.name);
+ return -EINVAL;
+ }
+ sys_clk_speed = clk_get_rate(sys_ck);
+ clk_put(sys_ck);
+ /* Divide to avoid overflow */
+ sys_clk_speed /= 1000;
+
+ /* Generic voltage parameters */
+ vdd->curr_volt = 1200000;
+ vdd->volt_scale = vp_forceupdate_scale_voltage;
+ vdd->vp_enabled = false;
+
+ vdd->vp_rt_data.vpconfig_erroroffset =
+ (vdd->pmic_info->vp_erroroffset <<
+ vdd->vp_data->vp_common->vpconfig_erroroffset_shift);
+
+ timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000;
+ vdd->vp_rt_data.vlimitto_timeout = timeout_val;
+ vdd->vp_rt_data.vlimitto_vddmin = vdd->pmic_info->vp_vddmin;
+ vdd->vp_rt_data.vlimitto_vddmax = vdd->pmic_info->vp_vddmax;
+
+ waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) *
+ sys_clk_speed) / 1000;
+ vdd->vp_rt_data.vstepmin_smpswaittimemin = waittime;
+ vdd->vp_rt_data.vstepmax_smpswaittimemax = waittime;
+ vdd->vp_rt_data.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin;
+ vdd->vp_rt_data.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax;
+
+ return 0;
+}
+
/* Voltage debugfs support */
static int vp_volt_debug_get(void *data, u64 *val)
{
@@ -346,7 +148,7 @@ static int vp_volt_debug_get(void *data, u64 *val)
return -EINVAL;
}
- vsel = vdd->read_reg(vdd->vp_reg.prm_mod, vdd->vp_offs.voltage);
+ vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
pr_notice("curr_vsel = %x\n", vsel);
if (!vdd->pmic_info->vsel_to_uv) {
@@ -379,7 +181,6 @@ DEFINE_SIMPLE_ATTRIBUTE(nom_volt_debug_fops, nom_volt_debug_get, NULL,
static void vp_latch_vsel(struct omap_vdd_info *vdd)
{
u32 vpconfig;
- u16 mod;
unsigned long uvdc;
char vsel;
@@ -396,30 +197,27 @@ static void vp_latch_vsel(struct omap_vdd_info *vdd)
return;
}
- mod = vdd->vp_reg.prm_mod;
-
vsel = vdd->pmic_info->uv_to_vsel(uvdc);
- vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
- vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
- vdd->vp_reg.vpconfig_initvdd);
- vpconfig |= vsel << vdd->vp_reg.vpconfig_initvoltage_shift;
+ vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig);
+ vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvoltage_mask |
+ vdd->vp_data->vp_common->vpconfig_initvdd);
+ vpconfig |= vsel << vdd->vp_data->vp_common->vpconfig_initvoltage_shift;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/* Trigger initVDD value copy to voltage processor */
- vdd->write_reg((vpconfig | vdd->vp_reg.vpconfig_initvdd), mod,
- vdd->vp_offs.vpconfig);
+ vdd->write_reg((vpconfig | vdd->vp_data->vp_common->vpconfig_initvdd),
+ prm_mod_offs, vdd->vp_data->vpconfig);
/* Clear initVDD copy trigger bit */
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
}
/* Generic voltage init functions */
static void __init vp_init(struct omap_vdd_info *vdd)
{
u32 vp_val;
- u16 mod;
if (!vdd->read_reg || !vdd->write_reg) {
pr_err("%s: No read/write API for accessing vdd_%s regs\n",
@@ -427,33 +225,31 @@ static void __init vp_init(struct omap_vdd_info *vdd)
return;
}
- mod = vdd->vp_reg.prm_mod;
-
- vp_val = vdd->vp_reg.vpconfig_erroroffset |
- (vdd->vp_reg.vpconfig_errorgain <<
- vdd->vp_reg.vpconfig_errorgain_shift) |
- vdd->vp_reg.vpconfig_timeouten;
- vdd->write_reg(vp_val, mod, vdd->vp_offs.vpconfig);
-
- vp_val = ((vdd->vp_reg.vstepmin_smpswaittimemin <<
- vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
- (vdd->vp_reg.vstepmin_stepmin <<
- vdd->vp_reg.vstepmin_stepmin_shift));
- vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmin);
-
- vp_val = ((vdd->vp_reg.vstepmax_smpswaittimemax <<
- vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
- (vdd->vp_reg.vstepmax_stepmax <<
- vdd->vp_reg.vstepmax_stepmax_shift));
- vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmax);
-
- vp_val = ((vdd->vp_reg.vlimitto_vddmax <<
- vdd->vp_reg.vlimitto_vddmax_shift) |
- (vdd->vp_reg.vlimitto_vddmin <<
- vdd->vp_reg.vlimitto_vddmin_shift) |
- (vdd->vp_reg.vlimitto_timeout <<
- vdd->vp_reg.vlimitto_timeout_shift));
- vdd->write_reg(vp_val, mod, vdd->vp_offs.vlimitto);
+ vp_val = vdd->vp_rt_data.vpconfig_erroroffset |
+ (vdd->vp_rt_data.vpconfig_errorgain <<
+ vdd->vp_data->vp_common->vpconfig_errorgain_shift) |
+ vdd->vp_data->vp_common->vpconfig_timeouten;
+ vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vpconfig);
+
+ vp_val = ((vdd->vp_rt_data.vstepmin_smpswaittimemin <<
+ vdd->vp_data->vp_common->vstepmin_smpswaittimemin_shift) |
+ (vdd->vp_rt_data.vstepmin_stepmin <<
+ vdd->vp_data->vp_common->vstepmin_stepmin_shift));
+ vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vstepmin);
+
+ vp_val = ((vdd->vp_rt_data.vstepmax_smpswaittimemax <<
+ vdd->vp_data->vp_common->vstepmax_smpswaittimemax_shift) |
+ (vdd->vp_rt_data.vstepmax_stepmax <<
+ vdd->vp_data->vp_common->vstepmax_stepmax_shift));
+ vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vstepmax);
+
+ vp_val = ((vdd->vp_rt_data.vlimitto_vddmax <<
+ vdd->vp_data->vp_common->vlimitto_vddmax_shift) |
+ (vdd->vp_rt_data.vlimitto_vddmin <<
+ vdd->vp_data->vp_common->vlimitto_vddmin_shift) |
+ (vdd->vp_rt_data.vlimitto_timeout <<
+ vdd->vp_data->vp_common->vlimitto_timeout_shift));
+ vdd->write_reg(vp_val, prm_mod_offs, vdd->vp_data->vlimitto);
}
static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
@@ -480,23 +276,23 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
}
(void) debugfs_create_x16("vp_errorgain", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vpconfig_errorgain));
+ &(vdd->vp_rt_data.vpconfig_errorgain));
(void) debugfs_create_x16("vp_smpswaittimemin", S_IRUGO,
vdd->debug_dir,
- &(vdd->vp_reg.vstepmin_smpswaittimemin));
+ &(vdd->vp_rt_data.vstepmin_smpswaittimemin));
(void) debugfs_create_x8("vp_stepmin", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vstepmin_stepmin));
+ &(vdd->vp_rt_data.vstepmin_stepmin));
(void) debugfs_create_x16("vp_smpswaittimemax", S_IRUGO,
vdd->debug_dir,
- &(vdd->vp_reg.vstepmax_smpswaittimemax));
+ &(vdd->vp_rt_data.vstepmax_smpswaittimemax));
(void) debugfs_create_x8("vp_stepmax", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vstepmax_stepmax));
+ &(vdd->vp_rt_data.vstepmax_stepmax));
(void) debugfs_create_x8("vp_vddmax", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vlimitto_vddmax));
+ &(vdd->vp_rt_data.vlimitto_vddmax));
(void) debugfs_create_x8("vp_vddmin", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vlimitto_vddmin));
+ &(vdd->vp_rt_data.vlimitto_vddmin));
(void) debugfs_create_x16("vp_timeout", S_IRUGO, vdd->debug_dir,
- &(vdd->vp_reg.vlimitto_timeout));
+ &(vdd->vp_rt_data.vlimitto_timeout));
(void) debugfs_create_file("curr_vp_volt", S_IRUGO, vdd->debug_dir,
(void *) vdd, &vp_volt_debug_fops);
(void) debugfs_create_file("curr_nominal_volt", S_IRUGO,
@@ -509,8 +305,12 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
{
struct omap_volt_data *volt_data;
+ const struct omap_vc_common_data *vc_common;
+ const struct omap_vp_common_data *vp_common;
u32 vc_cmdval, vp_errgain_val;
- u16 vp_mod, vc_mod;
+
+ vc_common = vdd->vc_data->vc_common;
+ vp_common = vdd->vp_data->vp_common;
/* Check if suffiecient pmic info is available for this vdd */
if (!vdd->pmic_info) {
@@ -532,33 +332,30 @@ static int _pre_volt_scale(struct omap_vdd_info *vdd,
return -EINVAL;
}
- vp_mod = vdd->vp_reg.prm_mod;
- vc_mod = vdd->vc_reg.prm_mod;
-
/* Get volt_data corresponding to target_volt */
volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
if (IS_ERR(volt_data))
volt_data = NULL;
*target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
- *current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
+ *current_vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
/* Setting the ON voltage to the new target voltage */
- vc_cmdval = vdd->read_reg(vc_mod, vdd->vc_reg.cmdval_reg);
- vc_cmdval &= ~vdd->vc_reg.cmd_on_mask;
- vc_cmdval |= (*target_vsel << vdd->vc_reg.cmd_on_shift);
- vdd->write_reg(vc_cmdval, vc_mod, vdd->vc_reg.cmdval_reg);
+ vc_cmdval = vdd->read_reg(prm_mod_offs, vdd->vc_data->cmdval_reg);
+ vc_cmdval &= ~vc_common->cmd_on_mask;
+ vc_cmdval |= (*target_vsel << vc_common->cmd_on_shift);
+ vdd->write_reg(vc_cmdval, prm_mod_offs, vdd->vc_data->cmdval_reg);
/* Setting vp errorgain based on the voltage */
if (volt_data) {
- vp_errgain_val = vdd->read_reg(vp_mod,
- vdd->vp_offs.vpconfig);
- vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
- vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
- vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
- vdd->vp_reg.vpconfig_errorgain_shift;
- vdd->write_reg(vp_errgain_val, vp_mod,
- vdd->vp_offs.vpconfig);
+ vp_errgain_val = vdd->read_reg(prm_mod_offs,
+ vdd->vp_data->vpconfig);
+ vdd->vp_rt_data.vpconfig_errorgain = volt_data->vp_errgain;
+ vp_errgain_val &= ~vp_common->vpconfig_errorgain_mask;
+ vp_errgain_val |= vdd->vp_rt_data.vpconfig_errorgain <<
+ vp_common->vpconfig_errorgain_shift;
+ vdd->write_reg(vp_errgain_val, prm_mod_offs,
+ vdd->vp_data->vpconfig);
}
return 0;
@@ -584,7 +381,6 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
{
u32 loop_cnt = 0, retries_cnt = 0;
u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
- u16 mod;
u8 target_vsel, current_vsel;
int ret;
@@ -592,20 +388,19 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
if (ret)
return ret;
- mod = vdd->vc_reg.prm_mod;
-
- vc_valid = vdd->vc_reg.valid;
- vc_bypass_val_reg = vdd->vc_reg.bypass_val_reg;
- vc_bypass_value = (target_vsel << vdd->vc_reg.data_shift) |
+ vc_valid = vdd->vc_data->vc_common->valid;
+ vc_bypass_val_reg = vdd->vc_data->vc_common->bypass_val_reg;
+ vc_bypass_value = (target_vsel << vdd->vc_data->vc_common->data_shift) |
(vdd->pmic_info->pmic_reg <<
- vdd->vc_reg.regaddr_shift) |
+ vdd->vc_data->vc_common->regaddr_shift) |
(vdd->pmic_info->i2c_slave_addr <<
- vdd->vc_reg.slaveaddr_shift);
+ vdd->vc_data->vc_common->slaveaddr_shift);
- vdd->write_reg(vc_bypass_value, mod, vc_bypass_val_reg);
- vdd->write_reg(vc_bypass_value | vc_valid, mod, vc_bypass_val_reg);
+ vdd->write_reg(vc_bypass_value, prm_mod_offs, vc_bypass_val_reg);
+ vdd->write_reg(vc_bypass_value | vc_valid, prm_mod_offs,
+ vc_bypass_val_reg);
- vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
+ vc_bypass_value = vdd->read_reg(prm_mod_offs, vc_bypass_val_reg);
/*
* Loop till the bypass command is acknowledged from the SMPS.
* NOTE: This is legacy code. The loop count and retry count needs
@@ -624,7 +419,8 @@ static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
loop_cnt = 0;
udelay(10);
}
- vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
+ vc_bypass_value = vdd->read_reg(prm_mod_offs,
+ vc_bypass_val_reg);
}
_post_volt_scale(vdd, target_volt, target_vsel, current_vsel);
@@ -636,7 +432,6 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
unsigned long target_volt)
{
u32 vpconfig;
- u16 mod, ocp_mod;
u8 target_vsel, current_vsel, prm_irqst_reg;
int ret, timeout = 0;
@@ -644,20 +439,18 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
if (ret)
return ret;
- mod = vdd->vp_reg.prm_mod;
- ocp_mod = vdd->ocp_mod;
- prm_irqst_reg = vdd->prm_irqst_reg;
+ prm_irqst_reg = vdd->vp_data->prm_irqst_data->prm_irqst_reg;
/*
* Clear all pending TransactionDone interrupt/status. Typical latency
* is <3us
*/
while (timeout++ < VP_TRANXDONE_TIMEOUT) {
- vdd->write_reg(vdd->vp_reg.tranxdone_status,
- ocp_mod, prm_irqst_reg);
- if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
- vdd->vp_reg.tranxdone_status))
- break;
+ vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status,
+ prm_irqst_ocp_mod_offs, prm_irqst_reg);
+ if (!(vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) &
+ vdd->vp_data->prm_irqst_data->tranxdone_status))
+ break;
udelay(1);
}
if (timeout >= VP_TRANXDONE_TIMEOUT) {
@@ -667,30 +460,30 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
}
/* Configure for VP-Force Update */
- vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
- vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
- vdd->vp_reg.vpconfig_forceupdate |
- vdd->vp_reg.vpconfig_initvoltage_mask);
+ vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig);
+ vpconfig &= ~(vdd->vp_data->vp_common->vpconfig_initvdd |
+ vdd->vp_data->vp_common->vpconfig_forceupdate |
+ vdd->vp_data->vp_common->vpconfig_initvoltage_mask);
vpconfig |= ((target_vsel <<
- vdd->vp_reg.vpconfig_initvoltage_shift));
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vdd->vp_data->vp_common->vpconfig_initvoltage_shift));
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/* Trigger initVDD value copy to voltage processor */
- vpconfig |= vdd->vp_reg.vpconfig_initvdd;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig |= vdd->vp_data->vp_common->vpconfig_initvdd;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/* Force update of voltage */
- vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig |= vdd->vp_data->vp_common->vpconfig_forceupdate;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/*
* Wait for TransactionDone. Typical latency is <200us.
* Depends on SMPSWAITTIMEMIN/MAX and voltage change
*/
timeout = 0;
- omap_test_timeout((vdd->read_reg(ocp_mod, prm_irqst_reg) &
- vdd->vp_reg.tranxdone_status),
- VP_TRANXDONE_TIMEOUT, timeout);
+ omap_test_timeout((vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) &
+ vdd->vp_data->prm_irqst_data->tranxdone_status),
+ VP_TRANXDONE_TIMEOUT, timeout);
if (timeout >= VP_TRANXDONE_TIMEOUT)
pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
"TRANXDONE never got set after the voltage update\n",
@@ -704,11 +497,11 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
*/
timeout = 0;
while (timeout++ < VP_TRANXDONE_TIMEOUT) {
- vdd->write_reg(vdd->vp_reg.tranxdone_status,
- ocp_mod, prm_irqst_reg);
- if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
- vdd->vp_reg.tranxdone_status))
- break;
+ vdd->write_reg(vdd->vp_data->prm_irqst_data->tranxdone_status,
+ prm_irqst_ocp_mod_offs, prm_irqst_reg);
+ if (!(vdd->read_reg(prm_irqst_ocp_mod_offs, prm_irqst_reg) &
+ vdd->vp_data->prm_irqst_data->tranxdone_status))
+ break;
udelay(1);
}
@@ -717,222 +510,95 @@ static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
"to clear the TRANXDONE status\n",
__func__, vdd->voltdm.name);
- vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
+ vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig);
/* Clear initVDD copy trigger bit */
- vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig &= ~vdd->vp_data->vp_common->vpconfig_initvdd;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/* Clear force bit */
- vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig &= ~vdd->vp_data->vp_common->vpconfig_forceupdate;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
return 0;
}
-/* OMAP3 specific voltage init functions */
+static void __init omap3_vfsm_init(struct omap_vdd_info *vdd)
+{
+ /*
+ * Voltage Manager FSM parameters init
+ * XXX This data should be passed in from the board file
+ */
+ vdd->write_reg(OMAP3_CLKSETUP, prm_mod_offs, OMAP3_PRM_CLKSETUP_OFFSET);
+ vdd->write_reg(OMAP3_VOLTOFFSET, prm_mod_offs,
+ OMAP3_PRM_VOLTOFFSET_OFFSET);
+ vdd->write_reg(OMAP3_VOLTSETUP2, prm_mod_offs,
+ OMAP3_PRM_VOLTSETUP2_OFFSET);
+}
-/*
- * Intializes the voltage controller registers with the PMIC and board
- * specific parameters and voltage setup times for OMAP3.
- */
static void __init omap3_vc_init(struct omap_vdd_info *vdd)
{
- u32 vc_val;
- u16 mod;
- u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
static bool is_initialized;
+ u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
+ u32 vc_val;
- if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
- pr_err("%s: PMIC info requried to configure vc for"
- "vdd_%s not populated.Hence cannot initialize vc\n",
- __func__, vdd->voltdm.name);
- return;
- }
-
- if (!vdd->read_reg || !vdd->write_reg) {
- pr_err("%s: No read/write API for accessing vdd_%s regs\n",
- __func__, vdd->voltdm.name);
+ if (is_initialized)
return;
- }
-
- mod = vdd->vc_reg.prm_mod;
-
- /* Set up the SMPS_SA(i2c slave address in VC */
- vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_sa_reg);
- vc_val &= ~vdd->vc_reg.smps_sa_mask;
- vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_reg.smps_sa_shift;
- vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_sa_reg);
-
- /* Setup the VOLRA(pmic reg addr) in VC */
- vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_volra_reg);
- vc_val &= ~vdd->vc_reg.smps_volra_mask;
- vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_reg.smps_volra_shift;
- vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_volra_reg);
-
- /*Configure the setup times */
- vc_val = vdd->read_reg(mod, vdd->vc_reg.voltsetup_reg);
- vc_val &= ~vdd->vc_reg.voltsetup_mask;
- vc_val |= vdd->pmic_info->volt_setup_time <<
- vdd->vc_reg.voltsetup_shift;
- vdd->write_reg(vc_val, mod, vdd->vc_reg.voltsetup_reg);
/* Set up the on, inactive, retention and off voltage */
on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt);
onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt);
ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt);
off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt);
- vc_val = ((on_vsel << vdd->vc_reg.cmd_on_shift) |
- (onlp_vsel << vdd->vc_reg.cmd_onlp_shift) |
- (ret_vsel << vdd->vc_reg.cmd_ret_shift) |
- (off_vsel << vdd->vc_reg.cmd_off_shift));
- vdd->write_reg(vc_val, mod, vdd->vc_reg.cmdval_reg);
-
- if (is_initialized)
- return;
+ vc_val = ((on_vsel << vdd->vc_data->vc_common->cmd_on_shift) |
+ (onlp_vsel << vdd->vc_data->vc_common->cmd_onlp_shift) |
+ (ret_vsel << vdd->vc_data->vc_common->cmd_ret_shift) |
+ (off_vsel << vdd->vc_data->vc_common->cmd_off_shift));
+ vdd->write_reg(vc_val, prm_mod_offs, vdd->vc_data->cmdval_reg);
- /* Generic VC parameters init */
- vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, mod,
+ /*
+ * Generic VC parameters init
+ * XXX This data should be abstracted out
+ */
+ vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, prm_mod_offs,
OMAP3_PRM_VC_CH_CONF_OFFSET);
- vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, mod,
+ vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, prm_mod_offs,
OMAP3_PRM_VC_I2C_CFG_OFFSET);
- vdd->write_reg(OMAP3_CLKSETUP, mod, OMAP3_PRM_CLKSETUP_OFFSET);
- vdd->write_reg(OMAP3_VOLTOFFSET, mod, OMAP3_PRM_VOLTOFFSET_OFFSET);
- vdd->write_reg(OMAP3_VOLTSETUP2, mod, OMAP3_PRM_VOLTSETUP2_OFFSET);
+
+ omap3_vfsm_init(vdd);
+
is_initialized = true;
}
-/* Sets up all the VDD related info for OMAP3 */
-static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
+
+/* OMAP4 specific voltage init functions */
+static void __init omap4_vc_init(struct omap_vdd_info *vdd)
{
- struct clk *sys_ck;
- u32 sys_clk_speed, timeout_val, waittime;
+ static bool is_initialized;
+ u32 vc_val;
- if (!vdd->pmic_info) {
- pr_err("%s: PMIC info requried to configure vdd_%s not"
- "populated.Hence cannot initialize vdd_%s\n",
- __func__, vdd->voltdm.name, vdd->voltdm.name);
- return -EINVAL;
- }
+ if (is_initialized)
+ return;
- if (!strcmp(vdd->voltdm.name, "mpu")) {
- if (cpu_is_omap3630())
- vdd->volt_data = omap36xx_vddmpu_volt_data;
- else
- vdd->volt_data = omap34xx_vddmpu_volt_data;
-
- vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
- vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
- vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT;
- vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK;
- vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA0_SHIFT;
- vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA0_MASK;
- vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT;
- vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME1_MASK;
- } else if (!strcmp(vdd->voltdm.name, "core")) {
- if (cpu_is_omap3630())
- vdd->volt_data = omap36xx_vddcore_volt_data;
- else
- vdd->volt_data = omap34xx_vddcore_volt_data;
-
- vdd->vp_reg.tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK;
- vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
- vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT;
- vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK;
- vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA1_SHIFT;
- vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA1_MASK;
- vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME2_SHIFT;
- vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME2_MASK;
- } else {
- pr_warning("%s: vdd_%s does not exisit in OMAP3\n",
- __func__, vdd->voltdm.name);
- return -EINVAL;
- }
+ /* TODO: Configure setup times and CMD_VAL values*/
/*
- * Sys clk rate is require to calculate vp timeout value and
- * smpswaittimemin and smpswaittimemax.
+ * Generic VC parameters init
+ * XXX This data should be abstracted out
*/
- sys_ck = clk_get(NULL, "sys_ck");
- if (IS_ERR(sys_ck)) {
- pr_warning("%s: Could not get the sys clk to calculate"
- "various vdd_%s params\n", __func__, vdd->voltdm.name);
- return -EINVAL;
- }
- sys_clk_speed = clk_get_rate(sys_ck);
- clk_put(sys_ck);
- /* Divide to avoid overflow */
- sys_clk_speed /= 1000;
-
- /* Generic voltage parameters */
- vdd->curr_volt = 1200000;
- vdd->ocp_mod = OCP_MOD;
- vdd->prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
- vdd->read_reg = omap3_voltage_read_reg;
- vdd->write_reg = omap3_voltage_write_reg;
- vdd->volt_scale = vp_forceupdate_scale_voltage;
- vdd->vp_enabled = false;
+ vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK |
+ OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK |
+ OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK);
+ vdd->write_reg(vc_val, prm_mod_offs, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET);
- /* VC parameters */
- vdd->vc_reg.prm_mod = OMAP3430_GR_MOD;
- vdd->vc_reg.smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET;
- vdd->vc_reg.smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET;
- vdd->vc_reg.bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
- vdd->vc_reg.voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET;
- vdd->vc_reg.data_shift = OMAP3430_DATA_SHIFT;
- vdd->vc_reg.slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
- vdd->vc_reg.regaddr_shift = OMAP3430_REGADDR_SHIFT;
- vdd->vc_reg.valid = OMAP3430_VALID_MASK;
- vdd->vc_reg.cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
- vdd->vc_reg.cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
- vdd->vc_reg.cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT;
- vdd->vc_reg.cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT;
- vdd->vc_reg.cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT;
-
- vdd->vp_reg.prm_mod = OMAP3430_GR_MOD;
-
- /* VPCONFIG bit fields */
- vdd->vp_reg.vpconfig_erroroffset = (vdd->pmic_info->vp_erroroffset <<
- OMAP3430_ERROROFFSET_SHIFT);
- vdd->vp_reg.vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK;
- vdd->vp_reg.vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT;
- vdd->vp_reg.vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT;
- vdd->vp_reg.vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK;
- vdd->vp_reg.vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK;
- vdd->vp_reg.vpconfig_initvdd = OMAP3430_INITVDD_MASK;
- vdd->vp_reg.vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK;
- vdd->vp_reg.vpconfig_vpenable = OMAP3430_VPENABLE_MASK;
-
- /* VSTEPMIN VSTEPMAX bit fields */
- waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) *
- sys_clk_speed) / 1000;
- vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
- vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
- vdd->vp_reg.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin;
- vdd->vp_reg.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax;
- vdd->vp_reg.vstepmin_smpswaittimemin_shift =
- OMAP3430_SMPSWAITTIMEMIN_SHIFT;
- vdd->vp_reg.vstepmax_smpswaittimemax_shift =
- OMAP3430_SMPSWAITTIMEMAX_SHIFT;
- vdd->vp_reg.vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT;
- vdd->vp_reg.vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT;
-
- /* VLIMITTO bit fields */
- timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000;
- vdd->vp_reg.vlimitto_timeout = timeout_val;
- vdd->vp_reg.vlimitto_vddmin = vdd->pmic_info->vp_vddmin;
- vdd->vp_reg.vlimitto_vddmax = vdd->pmic_info->vp_vddmax;
- vdd->vp_reg.vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT;
- vdd->vp_reg.vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT;
- vdd->vp_reg.vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT;
+ /* XXX These are magic numbers and do not belong! */
+ vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT);
+ vdd->write_reg(vc_val, prm_mod_offs, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
- return 0;
+ is_initialized = true;
}
-/* OMAP4 specific voltage init functions */
-static void __init omap4_vc_init(struct omap_vdd_info *vdd)
+static void __init omap_vc_init(struct omap_vdd_info *vdd)
{
u32 vc_val;
- u16 mod;
- static bool is_initialized;
if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
pr_err("%s: PMIC info requried to configure vc for"
@@ -947,173 +613,61 @@ static void __init omap4_vc_init(struct omap_vdd_info *vdd)
return;
}
- mod = vdd->vc_reg.prm_mod;
-
/* Set up the SMPS_SA(i2c slave address in VC */
- vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_sa_reg);
- vc_val &= ~vdd->vc_reg.smps_sa_mask;
- vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_reg.smps_sa_shift;
- vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_sa_reg);
+ vc_val = vdd->read_reg(prm_mod_offs,
+ vdd->vc_data->vc_common->smps_sa_reg);
+ vc_val &= ~vdd->vc_data->smps_sa_mask;
+ vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_data->smps_sa_shift;
+ vdd->write_reg(vc_val, prm_mod_offs,
+ vdd->vc_data->vc_common->smps_sa_reg);
/* Setup the VOLRA(pmic reg addr) in VC */
- vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_volra_reg);
- vc_val &= ~vdd->vc_reg.smps_volra_mask;
- vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_reg.smps_volra_shift;
- vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_volra_reg);
-
- /* TODO: Configure setup times and CMD_VAL values*/
-
- if (is_initialized)
- return;
-
- /* Generic VC parameters init */
- vc_val = (OMAP4430_RAV_VDD_MPU_L_MASK | OMAP4430_CMD_VDD_MPU_L_MASK |
- OMAP4430_RAV_VDD_IVA_L_MASK | OMAP4430_CMD_VDD_IVA_L_MASK |
- OMAP4430_RAV_VDD_CORE_L_MASK | OMAP4430_CMD_VDD_CORE_L_MASK);
- vdd->write_reg(vc_val, mod, OMAP4_PRM_VC_CFG_CHANNEL_OFFSET);
-
- vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT);
- vdd->write_reg(vc_val, mod, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
+ vc_val = vdd->read_reg(prm_mod_offs,
+ vdd->vc_data->vc_common->smps_volra_reg);
+ vc_val &= ~vdd->vc_data->smps_volra_mask;
+ vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_data->smps_volra_shift;
+ vdd->write_reg(vc_val, prm_mod_offs,
+ vdd->vc_data->vc_common->smps_volra_reg);
+
+ /* Configure the setup times */
+ vc_val = vdd->read_reg(prm_mod_offs, vdd->vfsm->voltsetup_reg);
+ vc_val &= ~vdd->vfsm->voltsetup_mask;
+ vc_val |= vdd->pmic_info->volt_setup_time <<
+ vdd->vfsm->voltsetup_shift;
+ vdd->write_reg(vc_val, prm_mod_offs, vdd->vfsm->voltsetup_reg);
- is_initialized = true;
+ if (cpu_is_omap34xx())
+ omap3_vc_init(vdd);
+ else if (cpu_is_omap44xx())
+ omap4_vc_init(vdd);
}
-/* Sets up all the VDD related info for OMAP4 */
-static int __init omap4_vdd_data_configure(struct omap_vdd_info *vdd)
+static int __init omap_vdd_data_configure(struct omap_vdd_info *vdd)
{
- struct clk *sys_ck;
- u32 sys_clk_speed, timeout_val, waittime;
+ int ret = -EINVAL;
if (!vdd->pmic_info) {
pr_err("%s: PMIC info requried to configure vdd_%s not"
"populated.Hence cannot initialize vdd_%s\n",
__func__, vdd->voltdm.name, vdd->voltdm.name);
- return -EINVAL;
+ goto ovdc_out;
}
- if (!strcmp(vdd->voltdm.name, "mpu")) {
- vdd->volt_data = omap44xx_vdd_mpu_volt_data;
- vdd->vp_reg.tranxdone_status =
- OMAP4430_VP_MPU_TRANXDONE_ST_MASK;
- vdd->vc_reg.cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET;
- vdd->vc_reg.smps_sa_shift =
- OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT;
- vdd->vc_reg.smps_sa_mask =
- OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK;
- vdd->vc_reg.smps_volra_shift = OMAP4430_VOLRA_VDD_MPU_L_SHIFT;
- vdd->vc_reg.smps_volra_mask = OMAP4430_VOLRA_VDD_MPU_L_MASK;
- vdd->vc_reg.voltsetup_reg =
- OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET;
- vdd->prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET;
- } else if (!strcmp(vdd->voltdm.name, "core")) {
- vdd->volt_data = omap44xx_vdd_core_volt_data;
- vdd->vp_reg.tranxdone_status =
- OMAP4430_VP_CORE_TRANXDONE_ST_MASK;
- vdd->vc_reg.cmdval_reg =
- OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET;
- vdd->vc_reg.smps_sa_shift = OMAP4430_SA_VDD_CORE_L_0_6_SHIFT;
- vdd->vc_reg.smps_sa_mask = OMAP4430_SA_VDD_CORE_L_0_6_MASK;
- vdd->vc_reg.smps_volra_shift = OMAP4430_VOLRA_VDD_CORE_L_SHIFT;
- vdd->vc_reg.smps_volra_mask = OMAP4430_VOLRA_VDD_CORE_L_MASK;
- vdd->vc_reg.voltsetup_reg =
- OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET;
- vdd->prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET;
- } else if (!strcmp(vdd->voltdm.name, "iva")) {
- vdd->volt_data = omap44xx_vdd_iva_volt_data;
- vdd->vp_reg.tranxdone_status =
- OMAP4430_VP_IVA_TRANXDONE_ST_MASK;
- vdd->vc_reg.cmdval_reg = OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET;
- vdd->vc_reg.smps_sa_shift =
- OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT;
- vdd->vc_reg.smps_sa_mask =
- OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK;
- vdd->vc_reg.smps_volra_shift = OMAP4430_VOLRA_VDD_IVA_L_SHIFT;
- vdd->vc_reg.smps_volra_mask = OMAP4430_VOLRA_VDD_IVA_L_MASK;
- vdd->vc_reg.voltsetup_reg =
- OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET;
- vdd->prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET;
- } else {
- pr_warning("%s: vdd_%s does not exisit in OMAP4\n",
- __func__, vdd->voltdm.name);
- return -EINVAL;
- }
+ if (IS_ERR_VALUE(_config_common_vdd_data(vdd)))
+ goto ovdc_out;
- /*
- * Sys clk rate is require to calculate vp timeout value and
- * smpswaittimemin and smpswaittimemax.
- */
- sys_ck = clk_get(NULL, "sys_clkin_ck");
- if (IS_ERR(sys_ck)) {
- pr_warning("%s: Could not get the sys clk to calculate"
- "various vdd_%s params\n", __func__, vdd->voltdm.name);
- return -EINVAL;
+ if (cpu_is_omap34xx()) {
+ vdd->read_reg = omap3_voltage_read_reg;
+ vdd->write_reg = omap3_voltage_write_reg;
+ ret = 0;
+ } else if (cpu_is_omap44xx()) {
+ vdd->read_reg = omap4_voltage_read_reg;
+ vdd->write_reg = omap4_voltage_write_reg;
+ ret = 0;
}
- sys_clk_speed = clk_get_rate(sys_ck);
- clk_put(sys_ck);
- /* Divide to avoid overflow */
- sys_clk_speed /= 1000;
-
- /* Generic voltage parameters */
- vdd->curr_volt = 1200000;
- vdd->ocp_mod = OMAP4430_PRM_OCP_SOCKET_INST;
- vdd->read_reg = omap4_voltage_read_reg;
- vdd->write_reg = omap4_voltage_write_reg;
- vdd->volt_scale = vp_forceupdate_scale_voltage;
- vdd->vp_enabled = false;
- /* VC parameters */
- vdd->vc_reg.prm_mod = OMAP4430_PRM_DEVICE_INST;
- vdd->vc_reg.smps_sa_reg = OMAP4_PRM_VC_SMPS_SA_OFFSET;
- vdd->vc_reg.smps_volra_reg = OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET;
- vdd->vc_reg.bypass_val_reg = OMAP4_PRM_VC_VAL_BYPASS_OFFSET;
- vdd->vc_reg.data_shift = OMAP4430_DATA_SHIFT;
- vdd->vc_reg.slaveaddr_shift = OMAP4430_SLAVEADDR_SHIFT;
- vdd->vc_reg.regaddr_shift = OMAP4430_REGADDR_SHIFT;
- vdd->vc_reg.valid = OMAP4430_VALID_MASK;
- vdd->vc_reg.cmd_on_shift = OMAP4430_ON_SHIFT;
- vdd->vc_reg.cmd_on_mask = OMAP4430_ON_MASK;
- vdd->vc_reg.cmd_onlp_shift = OMAP4430_ONLP_SHIFT;
- vdd->vc_reg.cmd_ret_shift = OMAP4430_RET_SHIFT;
- vdd->vc_reg.cmd_off_shift = OMAP4430_OFF_SHIFT;
-
- vdd->vp_reg.prm_mod = OMAP4430_PRM_DEVICE_INST;
-
- /* VPCONFIG bit fields */
- vdd->vp_reg.vpconfig_erroroffset = (vdd->pmic_info->vp_erroroffset <<
- OMAP4430_ERROROFFSET_SHIFT);
- vdd->vp_reg.vpconfig_errorgain_mask = OMAP4430_ERRORGAIN_MASK;
- vdd->vp_reg.vpconfig_errorgain_shift = OMAP4430_ERRORGAIN_SHIFT;
- vdd->vp_reg.vpconfig_initvoltage_shift = OMAP4430_INITVOLTAGE_SHIFT;
- vdd->vp_reg.vpconfig_initvoltage_mask = OMAP4430_INITVOLTAGE_MASK;
- vdd->vp_reg.vpconfig_timeouten = OMAP4430_TIMEOUTEN_MASK;
- vdd->vp_reg.vpconfig_initvdd = OMAP4430_INITVDD_MASK;
- vdd->vp_reg.vpconfig_forceupdate = OMAP4430_FORCEUPDATE_MASK;
- vdd->vp_reg.vpconfig_vpenable = OMAP4430_VPENABLE_MASK;
-
- /* VSTEPMIN VSTEPMAX bit fields */
- waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) *
- sys_clk_speed) / 1000;
- vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
- vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
- vdd->vp_reg.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin;
- vdd->vp_reg.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax;
- vdd->vp_reg.vstepmin_smpswaittimemin_shift =
- OMAP4430_SMPSWAITTIMEMIN_SHIFT;
- vdd->vp_reg.vstepmax_smpswaittimemax_shift =
- OMAP4430_SMPSWAITTIMEMAX_SHIFT;
- vdd->vp_reg.vstepmin_stepmin_shift = OMAP4430_VSTEPMIN_SHIFT;
- vdd->vp_reg.vstepmax_stepmax_shift = OMAP4430_VSTEPMAX_SHIFT;
-
- /* VLIMITTO bit fields */
- timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000;
- vdd->vp_reg.vlimitto_timeout = timeout_val;
- vdd->vp_reg.vlimitto_vddmin = vdd->pmic_info->vp_vddmin;
- vdd->vp_reg.vlimitto_vddmax = vdd->pmic_info->vp_vddmax;
- vdd->vp_reg.vlimitto_vddmin_shift = OMAP4430_VDDMIN_SHIFT;
- vdd->vp_reg.vlimitto_vddmax_shift = OMAP4430_VDDMAX_SHIFT;
- vdd->vp_reg.vlimitto_timeout_shift = OMAP4430_TIMEOUT_SHIFT;
-
- return 0;
+ovdc_out:
+ return ret;
}
/* Public functions */
@@ -1161,8 +715,7 @@ unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
return 0;
}
- curr_vsel = vdd->read_reg(vdd->vp_reg.prm_mod,
- vdd->vp_offs.voltage);
+ curr_vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) {
pr_warning("%s: PMIC function to convert vsel to voltage"
@@ -1184,7 +737,6 @@ void omap_vp_enable(struct voltagedomain *voltdm)
{
struct omap_vdd_info *vdd;
u32 vpconfig;
- u16 mod;
if (!voltdm || IS_ERR(voltdm)) {
pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -1198,8 +750,6 @@ void omap_vp_enable(struct voltagedomain *voltdm)
return;
}
- mod = vdd->vp_reg.prm_mod;
-
/* If VP is already enabled, do nothing. Return */
if (vdd->vp_enabled)
return;
@@ -1207,9 +757,9 @@ void omap_vp_enable(struct voltagedomain *voltdm)
vp_latch_vsel(vdd);
/* Enable VP */
- vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
- vpconfig |= vdd->vp_reg.vpconfig_vpenable;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig);
+ vpconfig |= vdd->vp_data->vp_common->vpconfig_vpenable;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
vdd->vp_enabled = true;
}
@@ -1224,7 +774,6 @@ void omap_vp_disable(struct voltagedomain *voltdm)
{
struct omap_vdd_info *vdd;
u32 vpconfig;
- u16 mod;
int timeout;
if (!voltdm || IS_ERR(voltdm)) {
@@ -1239,8 +788,6 @@ void omap_vp_disable(struct voltagedomain *voltdm)
return;
}
- mod = vdd->vp_reg.prm_mod;
-
/* If VP is already disabled, do nothing. Return */
if (!vdd->vp_enabled) {
pr_warning("%s: Trying to disable VP for vdd_%s when"
@@ -1249,14 +796,14 @@ void omap_vp_disable(struct voltagedomain *voltdm)
}
/* Disable VP */
- vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
- vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
- vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
+ vpconfig = vdd->read_reg(prm_mod_offs, vdd->vp_data->vpconfig);
+ vpconfig &= ~vdd->vp_data->vp_common->vpconfig_vpenable;
+ vdd->write_reg(vpconfig, prm_mod_offs, vdd->vp_data->vpconfig);
/*
* Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
*/
- omap_test_timeout((vdd->read_reg(mod, vdd->vp_offs.vstatus)),
+ omap_test_timeout((vdd->read_reg(prm_mod_offs, vdd->vp_data->vstatus)),
VP_IDLE_TIMEOUT, timeout);
if (timeout >= VP_IDLE_TIMEOUT)
@@ -1509,8 +1056,8 @@ struct voltagedomain *omap_voltage_domain_lookup(char *name)
}
for (i = 0; i < nr_scalable_vdd; i++) {
- if (!(strcmp(name, vdd_info[i].voltdm.name)))
- return &vdd_info[i].voltdm;
+ if (!(strcmp(name, vdd_info[i]->voltdm.name)))
+ return &vdd_info[i]->voltdm;
}
return ERR_PTR(-EINVAL);
@@ -1538,35 +1085,24 @@ int __init omap_voltage_late_init(void)
pr_err("%s: Unable to create voltage debugfs main dir\n",
__func__);
for (i = 0; i < nr_scalable_vdd; i++) {
- if (vdd_data_configure(&vdd_info[i]))
+ if (omap_vdd_data_configure(vdd_info[i]))
continue;
- vc_init(&vdd_info[i]);
- vp_init(&vdd_info[i]);
- vdd_debugfs_init(&vdd_info[i]);
+ omap_vc_init(vdd_info[i]);
+ vp_init(vdd_info[i]);
+ vdd_debugfs_init(vdd_info[i]);
}
return 0;
}
-/**
- * omap_voltage_early_init()- Volatage driver early init
- */
-static int __init omap_voltage_early_init(void)
+/* XXX document */
+int __init omap_voltage_early_init(s16 prm_mod, s16 prm_irqst_ocp_mod,
+ struct omap_vdd_info *omap_vdd_array[],
+ u8 omap_vdd_count)
{
- if (cpu_is_omap34xx()) {
- vdd_info = omap3_vdd_info;
- nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
- vc_init = omap3_vc_init;
- vdd_data_configure = omap3_vdd_data_configure;
- } else if (cpu_is_omap44xx()) {
- vdd_info = omap4_vdd_info;
- nr_scalable_vdd = OMAP4_NR_SCALABLE_VDD;
- vc_init = omap4_vc_init;
- vdd_data_configure = omap4_vdd_data_configure;
- } else {
- pr_warning("%s: voltage driver support not added\n", __func__);
- }
-
+ prm_mod_offs = prm_mod;
+ prm_irqst_ocp_mod_offs = prm_irqst_ocp_mod;
+ vdd_info = omap_vdd_array;
+ nr_scalable_vdd = omap_vdd_count;
return 0;
}
-core_initcall(omap_voltage_early_init);
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/mach-omap2/voltage.h
index 5bd204e55c32..e9f5408244e0 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/mach-omap2/voltage.h
@@ -16,6 +16,10 @@
#include <linux/err.h>
+#include "vc.h"
+#include "vp.h"
+
+/* XXX document */
#define VOLTSCALE_VPFORCEUPDATE 1
#define VOLTSCALE_VCBYPASS 2
@@ -27,36 +31,22 @@
#define OMAP3_VOLTOFFSET 0xff
#define OMAP3_VOLTSETUP2 0xff
-/* Voltage value defines */
-#define OMAP3430_VDD_MPU_OPP1_UV 975000
-#define OMAP3430_VDD_MPU_OPP2_UV 1075000
-#define OMAP3430_VDD_MPU_OPP3_UV 1200000
-#define OMAP3430_VDD_MPU_OPP4_UV 1270000
-#define OMAP3430_VDD_MPU_OPP5_UV 1350000
-
-#define OMAP3430_VDD_CORE_OPP1_UV 975000
-#define OMAP3430_VDD_CORE_OPP2_UV 1050000
-#define OMAP3430_VDD_CORE_OPP3_UV 1150000
-
-#define OMAP3630_VDD_MPU_OPP50_UV 1012500
-#define OMAP3630_VDD_MPU_OPP100_UV 1200000
-#define OMAP3630_VDD_MPU_OPP120_UV 1325000
-#define OMAP3630_VDD_MPU_OPP1G_UV 1375000
-
-#define OMAP3630_VDD_CORE_OPP50_UV 1000000
-#define OMAP3630_VDD_CORE_OPP100_UV 1200000
-
-#define OMAP4430_VDD_MPU_OPP50_UV 930000
-#define OMAP4430_VDD_MPU_OPP100_UV 1100000
-#define OMAP4430_VDD_MPU_OPPTURBO_UV 1260000
-#define OMAP4430_VDD_MPU_OPPNITRO_UV 1350000
-
-#define OMAP4430_VDD_IVA_OPP50_UV 930000
-#define OMAP4430_VDD_IVA_OPP100_UV 1100000
-#define OMAP4430_VDD_IVA_OPPTURBO_UV 1260000
-
-#define OMAP4430_VDD_CORE_OPP50_UV 930000
-#define OMAP4430_VDD_CORE_OPP100_UV 1100000
+/**
+ * struct omap_vfsm_instance_data - per-voltage manager FSM register/bitfield
+ * data
+ * @voltsetup_mask: SETUP_TIME* bitmask in the PRM_VOLTSETUP* register
+ * @voltsetup_reg: register offset of PRM_VOLTSETUP from PRM base
+ * @voltsetup_shift: SETUP_TIME* field shift in the PRM_VOLTSETUP* register
+ *
+ * XXX What about VOLTOFFSET/VOLTCTRL?
+ * XXX It is not necessary to have both a _mask and a _shift for the same
+ * bitfield - remove one!
+ */
+struct omap_vfsm_instance_data {
+ u32 voltsetup_mask;
+ u8 voltsetup_reg;
+ u8 voltsetup_shift;
+};
/**
* struct voltagedomain - omap voltage domain global structure.
@@ -113,6 +103,42 @@ struct omap_volt_pmic_info {
u8 (*uv_to_vsel) (unsigned long uV);
};
+/**
+ * omap_vdd_info - Per Voltage Domain info
+ *
+ * @volt_data : voltage table having the distinct voltages supported
+ * by the domain and other associated per voltage data.
+ * @pmic_info : pmic specific parameters which should be populted by
+ * the pmic drivers.
+ * @vp_data : the register values, shifts, masks for various
+ * vp registers
+ * @vp_rt_data : VP data derived at runtime, not predefined
+ * @vc_data : structure containing various various vc registers,
+ * shifts, masks etc.
+ * @vfsm : voltage manager FSM data
+ * @voltdm : pointer to the voltage domain structure
+ * @debug_dir : debug directory for this voltage domain.
+ * @curr_volt : current voltage for this vdd.
+ * @vp_enabled : flag to keep track of whether vp is enabled or not
+ * @volt_scale : API to scale the voltage of the vdd.
+ */
+struct omap_vdd_info {
+ struct omap_volt_data *volt_data;
+ struct omap_volt_pmic_info *pmic_info;
+ struct omap_vp_instance_data *vp_data;
+ struct omap_vp_runtime_data vp_rt_data;
+ struct omap_vc_instance_data *vc_data;
+ const struct omap_vfsm_instance_data *vfsm;
+ struct voltagedomain voltdm;
+ struct dentry *debug_dir;
+ u32 curr_volt;
+ bool vp_enabled;
+ u32 (*read_reg) (u16 mod, u8 offset);
+ void (*write_reg) (u32 val, u16 mod, u8 offset);
+ int (*volt_scale) (struct omap_vdd_info *vdd,
+ unsigned long target_volt);
+};
+
unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
void omap_vp_enable(struct voltagedomain *voltdm);
void omap_vp_disable(struct voltagedomain *voltdm);
@@ -125,6 +151,9 @@ struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
unsigned long volt);
unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
+int __init omap_voltage_early_init(s16 prm_mod, s16 prm_irqst_mod,
+ struct omap_vdd_info *omap_vdd_array[],
+ u8 omap_vdd_count);
#ifdef CONFIG_PM
int omap_voltage_register_pmic(struct voltagedomain *voltdm,
struct omap_volt_pmic_info *pmic_info);
diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
new file mode 100644
index 000000000000..def230fd2fde
--- /dev/null
+++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c
@@ -0,0 +1,95 @@
+/*
+ * OMAP3 voltage domain data
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+
+#include "prm-regbits-34xx.h"
+#include "omap_opp_data.h"
+#include "voltage.h"
+#include "vc.h"
+#include "vp.h"
+
+/*
+ * VDD data
+ */
+
+static const struct omap_vfsm_instance_data omap3_vdd1_vfsm_data = {
+ .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET,
+ .voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT,
+ .voltsetup_mask = OMAP3430_SETUP_TIME1_MASK,
+};
+
+static struct omap_vdd_info omap3_vdd1_info = {
+ .vp_data = &omap3_vp1_data,
+ .vc_data = &omap3_vc1_data,
+ .vfsm = &omap3_vdd1_vfsm_data,
+ .voltdm = {
+ .name = "mpu",
+ },
+};
+
+static const struct omap_vfsm_instance_data omap3_vdd2_vfsm_data = {
+ .voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET,
+ .voltsetup_shift = OMAP3430_SETUP_TIME2_SHIFT,
+ .voltsetup_mask = OMAP3430_SETUP_TIME2_MASK,
+};
+
+static struct omap_vdd_info omap3_vdd2_info = {
+ .vp_data = &omap3_vp2_data,
+ .vc_data = &omap3_vc2_data,
+ .vfsm = &omap3_vdd2_vfsm_data,
+ .voltdm = {
+ .name = "core",
+ },
+};
+
+/* OMAP3 VDD structures */
+static struct omap_vdd_info *omap3_vdd_info[] = {
+ &omap3_vdd1_info,
+ &omap3_vdd2_info,
+};
+
+/* OMAP3 specific voltage init functions */
+static int __init omap3xxx_voltage_early_init(void)
+{
+ s16 prm_mod = OMAP3430_GR_MOD;
+ s16 prm_irqst_ocp_mod = OCP_MOD;
+
+ if (!cpu_is_omap34xx())
+ return 0;
+
+ /*
+ * XXX Will depend on the process, validation, and binning
+ * for the currently-running IC
+ */
+ if (cpu_is_omap3630()) {
+ omap3_vdd1_info.volt_data = omap36xx_vddmpu_volt_data;
+ omap3_vdd2_info.volt_data = omap36xx_vddcore_volt_data;
+ } else {
+ omap3_vdd1_info.volt_data = omap34xx_vddmpu_volt_data;
+ omap3_vdd2_info.volt_data = omap34xx_vddcore_volt_data;
+ }
+
+ return omap_voltage_early_init(prm_mod, prm_irqst_ocp_mod,
+ omap3_vdd_info,
+ ARRAY_SIZE(omap3_vdd_info));
+};
+core_initcall(omap3xxx_voltage_early_init);
diff --git a/arch/arm/mach-omap2/voltagedomains44xx_data.c b/arch/arm/mach-omap2/voltagedomains44xx_data.c
new file mode 100644
index 000000000000..cb64996de0e1
--- /dev/null
+++ b/arch/arm/mach-omap2/voltagedomains44xx_data.c
@@ -0,0 +1,102 @@
+/*
+ * OMAP3/OMAP4 Voltage Management Routines
+ *
+ * Author: Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Thara Gopinath <thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+
+#include "prm-regbits-44xx.h"
+#include "prm44xx.h"
+#include "prcm44xx.h"
+#include "prminst44xx.h"
+#include "voltage.h"
+#include "omap_opp_data.h"
+#include "vc.h"
+#include "vp.h"
+
+static const struct omap_vfsm_instance_data omap4_vdd_mpu_vfsm_data = {
+ .voltsetup_reg = OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET,
+};
+
+static struct omap_vdd_info omap4_vdd_mpu_info = {
+ .vp_data = &omap4_vp_mpu_data,
+ .vc_data = &omap4_vc_mpu_data,
+ .vfsm = &omap4_vdd_mpu_vfsm_data,
+ .voltdm = {
+ .name = "mpu",
+ },
+};
+
+static const struct omap_vfsm_instance_data omap4_vdd_iva_vfsm_data = {
+ .voltsetup_reg = OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET,
+};
+
+static struct omap_vdd_info omap4_vdd_iva_info = {
+ .vp_data = &omap4_vp_iva_data,
+ .vc_data = &omap4_vc_iva_data,
+ .vfsm = &omap4_vdd_iva_vfsm_data,
+ .voltdm = {
+ .name = "iva",
+ },
+};
+
+static const struct omap_vfsm_instance_data omap4_vdd_core_vfsm_data = {
+ .voltsetup_reg = OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET,
+};
+
+static struct omap_vdd_info omap4_vdd_core_info = {
+ .vp_data = &omap4_vp_core_data,
+ .vc_data = &omap4_vc_core_data,
+ .vfsm = &omap4_vdd_core_vfsm_data,
+ .voltdm = {
+ .name = "core",
+ },
+};
+
+/* OMAP4 VDD structures */
+static struct omap_vdd_info *omap4_vdd_info[] = {
+ &omap4_vdd_mpu_info,
+ &omap4_vdd_iva_info,
+ &omap4_vdd_core_info,
+};
+
+/* OMAP4 specific voltage init functions */
+static int __init omap44xx_voltage_early_init(void)
+{
+ s16 prm_mod = OMAP4430_PRM_DEVICE_INST;
+ s16 prm_irqst_ocp_mod = OMAP4430_PRM_OCP_SOCKET_INST;
+
+ if (!cpu_is_omap44xx())
+ return 0;
+
+ /*
+ * XXX Will depend on the process, validation, and binning
+ * for the currently-running IC
+ */
+ omap4_vdd_mpu_info.volt_data = omap44xx_vdd_mpu_volt_data;
+ omap4_vdd_iva_info.volt_data = omap44xx_vdd_iva_volt_data;
+ omap4_vdd_core_info.volt_data = omap44xx_vdd_core_volt_data;
+
+ return omap_voltage_early_init(prm_mod, prm_irqst_ocp_mod,
+ omap4_vdd_info,
+ ARRAY_SIZE(omap4_vdd_info));
+};
+core_initcall(omap44xx_voltage_early_init);
diff --git a/arch/arm/mach-omap2/vp.h b/arch/arm/mach-omap2/vp.h
new file mode 100644
index 000000000000..7ce134f7de79
--- /dev/null
+++ b/arch/arm/mach-omap2/vp.h
@@ -0,0 +1,143 @@
+/*
+ * OMAP3/4 Voltage Processor (VP) structure and macro definitions
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+#ifndef __ARCH_ARM_MACH_OMAP2_VP_H
+#define __ARCH_ARM_MACH_OMAP2_VP_H
+
+#include <linux/kernel.h>
+
+/* XXX document */
+#define VP_IDLE_TIMEOUT 200
+#define VP_TRANXDONE_TIMEOUT 300
+
+
+/**
+ * struct omap_vp_common_data - register data common to all VDDs
+ * @vpconfig_errorgain_mask: ERRORGAIN bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_initvoltage_mask: INITVOLTAGE bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_timeouten_mask: TIMEOUT bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_initvdd: INITVDD bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_forceupdate: FORCEUPDATE bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_vpenable: VPENABLE bitmask in the PRM_VP*_CONFIG reg
+ * @vpconfig_erroroffset_shift: ERROROFFSET field shift in PRM_VP*_CONFIG reg
+ * @vpconfig_errorgain_shift: ERRORGAIN field shift in PRM_VP*_CONFIG reg
+ * @vpconfig_initvoltage_shift: INITVOLTAGE field shift in PRM_VP*_CONFIG reg
+ * @vpconfig_stepmin_shift: VSTEPMIN field shift in the PRM_VP*_VSTEPMIN reg
+ * @vpconfig_smpswaittimemin_shift: SMPSWAITTIMEMIN field shift in PRM_VP*_VSTEPMIN reg
+ * @vpconfig_stepmax_shift: VSTEPMAX field shift in the PRM_VP*_VSTEPMAX reg
+ * @vpconfig_smpswaittimemax_shift: SMPSWAITTIMEMAX field shift in PRM_VP*_VSTEPMAX reg
+ * @vpconfig_vlimitto_vddmin_shift: VDDMIN field shift in PRM_VP*_VLIMITTO reg
+ * @vpconfig_vlimitto_vddmax_shift: VDDMAX field shift in PRM_VP*_VLIMITTO reg
+ * @vpconfig_vlimitto_timeout_shift: TIMEOUT field shift in PRM_VP*_VLIMITTO reg
+ *
+ * XXX It it not necessary to have both a mask and a shift for the same
+ * bitfield - remove one
+ * XXX Many of these fields are wrongly named -- e.g., vpconfig_smps* -- fix!
+ */
+struct omap_vp_common_data {
+ u32 vpconfig_errorgain_mask;
+ u32 vpconfig_initvoltage_mask;
+ u32 vpconfig_timeouten;
+ u32 vpconfig_initvdd;
+ u32 vpconfig_forceupdate;
+ u32 vpconfig_vpenable;
+ u8 vpconfig_erroroffset_shift;
+ u8 vpconfig_errorgain_shift;
+ u8 vpconfig_initvoltage_shift;
+ u8 vstepmin_stepmin_shift;
+ u8 vstepmin_smpswaittimemin_shift;
+ u8 vstepmax_stepmax_shift;
+ u8 vstepmax_smpswaittimemax_shift;
+ u8 vlimitto_vddmin_shift;
+ u8 vlimitto_vddmax_shift;
+ u8 vlimitto_timeout_shift;
+};
+
+/**
+ * struct omap_vp_prm_irqst_data - PRM_IRQSTATUS_MPU.VP_TRANXDONE_ST data
+ * @prm_irqst_reg: reg offset for PRM_IRQSTATUS_MPU from top of PRM
+ * @tranxdone_status: VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg
+ *
+ * XXX prm_irqst_reg does not belong here
+ * XXX Note that on OMAP3, VP_TRANXDONE interrupt may not work due to a
+ * hardware bug
+ * XXX This structure is probably not needed
+ */
+struct omap_vp_prm_irqst_data {
+ u8 prm_irqst_reg;
+ u32 tranxdone_status;
+};
+
+/**
+ * struct omap_vp_instance_data - VP register offsets (per-VDD)
+ * @vp_common: pointer to struct omap_vp_common_data * for this SoC
+ * @prm_irqst_data: pointer to struct omap_vp_prm_irqst_data for this VDD
+ * @vpconfig: PRM_VP*_CONFIG reg offset from PRM start
+ * @vstepmin: PRM_VP*_VSTEPMIN reg offset from PRM start
+ * @vlimitto: PRM_VP*_VLIMITTO reg offset from PRM start
+ * @vstatus: PRM_VP*_VSTATUS reg offset from PRM start
+ * @voltage: PRM_VP*_VOLTAGE reg offset from PRM start
+ *
+ * XXX vp_common is probably not needed since it is per-SoC
+ */
+struct omap_vp_instance_data {
+ const struct omap_vp_common_data *vp_common;
+ const struct omap_vp_prm_irqst_data *prm_irqst_data;
+ u8 vpconfig;
+ u8 vstepmin;
+ u8 vstepmax;
+ u8 vlimitto;
+ u8 vstatus;
+ u8 voltage;
+};
+
+/**
+ * struct omap_vp_runtime_data - VP data populated at runtime by code
+ * @vpconfig_erroroffset: value of ERROROFFSET bitfield in PRM_VP*_CONFIG
+ * @vpconfig_errorgain: value of ERRORGAIN bitfield in PRM_VP*_CONFIG
+ * @vstepmin_smpswaittimemin: value of SMPSWAITTIMEMIN bitfield in PRM_VP*_VSTEPMIN
+ * @vstepmax_smpswaittimemax: value of SMPSWAITTIMEMAX bitfield in PRM_VP*_VSTEPMAX
+ * @vlimitto_timeout: value of TIMEOUT bitfield in PRM_VP*_VLIMITTO
+ * @vstepmin_stepmin: value of VSTEPMIN bitfield in PRM_VP*_VSTEPMIN
+ * @vstepmax_stepmax: value of VSTEPMAX bitfield in PRM_VP*_VSTEPMAX
+ * @vlimitto_vddmin: value of VDDMIN bitfield in PRM_VP*_VLIMITTO
+ * @vlimitto_vddmax: value of VDDMAX bitfield in PRM_VP*_VLIMITTO
+ *
+ * XXX Is this structure really needed? Why not just program the
+ * device directly? They are in PRM space, therefore in the WKUP
+ * powerdomain, so register contents should not be lost in off-mode.
+ * XXX Some of these fields are incorrectly named, e.g., vstep*
+ */
+struct omap_vp_runtime_data {
+ u32 vpconfig_erroroffset;
+ u16 vpconfig_errorgain;
+ u16 vstepmin_smpswaittimemin;
+ u16 vstepmax_smpswaittimemax;
+ u16 vlimitto_timeout;
+ u8 vstepmin_stepmin;
+ u8 vstepmax_stepmax;
+ u8 vlimitto_vddmin;
+ u8 vlimitto_vddmax;
+};
+
+extern struct omap_vp_instance_data omap3_vp1_data;
+extern struct omap_vp_instance_data omap3_vp2_data;
+
+extern struct omap_vp_instance_data omap4_vp_mpu_data;
+extern struct omap_vp_instance_data omap4_vp_iva_data;
+extern struct omap_vp_instance_data omap4_vp_core_data;
+
+#endif
diff --git a/arch/arm/mach-omap2/vp3xxx_data.c b/arch/arm/mach-omap2/vp3xxx_data.c
new file mode 100644
index 000000000000..645217094e51
--- /dev/null
+++ b/arch/arm/mach-omap2/vp3xxx_data.c
@@ -0,0 +1,82 @@
+/*
+ * OMAP3 Voltage Processor (VP) data
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+
+#include "prm-regbits-34xx.h"
+#include "voltage.h"
+
+#include "vp.h"
+
+/*
+ * VP data common to 34xx/36xx chips
+ * XXX This stuff presumably belongs in the vp3xxx.c or vp.c file.
+ */
+static const struct omap_vp_common_data omap3_vp_common = {
+ .vpconfig_erroroffset_shift = OMAP3430_ERROROFFSET_SHIFT,
+ .vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK,
+ .vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT,
+ .vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT,
+ .vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK,
+ .vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK,
+ .vpconfig_initvdd = OMAP3430_INITVDD_MASK,
+ .vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK,
+ .vpconfig_vpenable = OMAP3430_VPENABLE_MASK,
+ .vstepmin_smpswaittimemin_shift = OMAP3430_SMPSWAITTIMEMIN_SHIFT,
+ .vstepmax_smpswaittimemax_shift = OMAP3430_SMPSWAITTIMEMAX_SHIFT,
+ .vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT,
+ .vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT,
+ .vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT,
+ .vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT,
+ .vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT,
+};
+
+static const struct omap_vp_prm_irqst_data omap3_vp1_prm_irqst_data = {
+ .prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET,
+ .tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK,
+};
+
+struct omap_vp_instance_data omap3_vp1_data = {
+ .vp_common = &omap3_vp_common,
+ .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
+ .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
+ .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
+ .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
+ .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
+ .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
+ .prm_irqst_data = &omap3_vp1_prm_irqst_data,
+};
+
+static const struct omap_vp_prm_irqst_data omap3_vp2_prm_irqst_data = {
+ .prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET,
+ .tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK,
+};
+
+struct omap_vp_instance_data omap3_vp2_data = {
+ .vp_common = &omap3_vp_common,
+ .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
+ .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
+ .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
+ .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
+ .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
+ .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
+ .prm_irqst_data = &omap3_vp2_prm_irqst_data,
+};
diff --git a/arch/arm/mach-omap2/vp44xx_data.c b/arch/arm/mach-omap2/vp44xx_data.c
new file mode 100644
index 000000000000..65d1ad63800a
--- /dev/null
+++ b/arch/arm/mach-omap2/vp44xx_data.c
@@ -0,0 +1,100 @@
+/*
+ * OMAP3 Voltage Processor (VP) data
+ *
+ * Copyright (C) 2007, 2010 Texas Instruments, Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ * Lesly A M <x0080970@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Copyright (C) 2008, 2011 Nokia Corporation
+ * Kalle Jokiniemi
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <plat/common.h>
+
+#include "prm44xx.h"
+#include "prm-regbits-44xx.h"
+#include "voltage.h"
+
+#include "vp.h"
+
+/*
+ * VP data common to 44xx chips
+ * XXX This stuff presumably belongs in the vp44xx.c or vp.c file.
+ */
+static const struct omap_vp_common_data omap4_vp_common = {
+ .vpconfig_erroroffset_shift = OMAP4430_ERROROFFSET_SHIFT,
+ .vpconfig_errorgain_mask = OMAP4430_ERRORGAIN_MASK,
+ .vpconfig_errorgain_shift = OMAP4430_ERRORGAIN_SHIFT,
+ .vpconfig_initvoltage_shift = OMAP4430_INITVOLTAGE_SHIFT,
+ .vpconfig_initvoltage_mask = OMAP4430_INITVOLTAGE_MASK,
+ .vpconfig_timeouten = OMAP4430_TIMEOUTEN_MASK,
+ .vpconfig_initvdd = OMAP4430_INITVDD_MASK,
+ .vpconfig_forceupdate = OMAP4430_FORCEUPDATE_MASK,
+ .vpconfig_vpenable = OMAP4430_VPENABLE_MASK,
+ .vstepmin_smpswaittimemin_shift = OMAP4430_SMPSWAITTIMEMIN_SHIFT,
+ .vstepmax_smpswaittimemax_shift = OMAP4430_SMPSWAITTIMEMAX_SHIFT,
+ .vstepmin_stepmin_shift = OMAP4430_VSTEPMIN_SHIFT,
+ .vstepmax_stepmax_shift = OMAP4430_VSTEPMAX_SHIFT,
+ .vlimitto_vddmin_shift = OMAP4430_VDDMIN_SHIFT,
+ .vlimitto_vddmax_shift = OMAP4430_VDDMAX_SHIFT,
+ .vlimitto_timeout_shift = OMAP4430_TIMEOUT_SHIFT,
+};
+
+static const struct omap_vp_prm_irqst_data omap4_vp_mpu_prm_irqst_data = {
+ .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET,
+ .tranxdone_status = OMAP4430_VP_MPU_TRANXDONE_ST_MASK,
+};
+
+struct omap_vp_instance_data omap4_vp_mpu_data = {
+ .vp_common = &omap4_vp_common,
+ .vpconfig = OMAP4_PRM_VP_MPU_CONFIG_OFFSET,
+ .vstepmin = OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET,
+ .vstepmax = OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET,
+ .vlimitto = OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET,
+ .vstatus = OMAP4_PRM_VP_MPU_STATUS_OFFSET,
+ .voltage = OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET,
+ .prm_irqst_data = &omap4_vp_mpu_prm_irqst_data,
+};
+
+static const struct omap_vp_prm_irqst_data omap4_vp_iva_prm_irqst_data = {
+ .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
+ .tranxdone_status = OMAP4430_VP_IVA_TRANXDONE_ST_MASK,
+};
+
+struct omap_vp_instance_data omap4_vp_iva_data = {
+ .vp_common = &omap4_vp_common,
+ .vpconfig = OMAP4_PRM_VP_IVA_CONFIG_OFFSET,
+ .vstepmin = OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET,
+ .vstepmax = OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET,
+ .vlimitto = OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET,
+ .vstatus = OMAP4_PRM_VP_IVA_STATUS_OFFSET,
+ .voltage = OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET,
+ .prm_irqst_data = &omap4_vp_iva_prm_irqst_data,
+};
+
+static const struct omap_vp_prm_irqst_data omap4_vp_core_prm_irqst_data = {
+ .prm_irqst_reg = OMAP4_PRM_IRQSTATUS_MPU_OFFSET,
+ .tranxdone_status = OMAP4430_VP_CORE_TRANXDONE_ST_MASK,
+};
+
+struct omap_vp_instance_data omap4_vp_core_data = {
+ .vp_common = &omap4_vp_common,
+ .vpconfig = OMAP4_PRM_VP_CORE_CONFIG_OFFSET,
+ .vstepmin = OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET,
+ .vstepmax = OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET,
+ .vlimitto = OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET,
+ .vstatus = OMAP4_PRM_VP_CORE_STATUS_OFFSET,
+ .voltage = OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET,
+ .prm_irqst_data = &omap4_vp_core_prm_irqst_data,
+};
+
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 8dc2c76d2260..986c3bf4e6b8 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -26,6 +26,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
+#include <mach/bridge-regs.h>
#include <mach/hardware.h>
#include <mach/orion5x.h>
#include <plat/ehci-orion.h>
@@ -599,6 +600,11 @@ void __init orion5x_wdt_init(void)
/*****************************************************************************
* Time handling
****************************************************************************/
+void __init orion5x_init_early(void)
+{
+ orion_time_set_base(TIMER_VIRT_BASE);
+}
+
int orion5x_tclk;
int __init orion5x_find_tclk(void)
@@ -616,7 +622,9 @@ int __init orion5x_find_tclk(void)
static void orion5x_timer_init(void)
{
orion5x_tclk = orion5x_find_tclk();
- orion_time_init(IRQ_ORION5X_BRIDGE, orion5x_tclk);
+
+ orion_time_init(ORION5X_BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
+ IRQ_ORION5X_BRIDGE, orion5x_tclk);
}
struct sys_timer orion5x_timer = {
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 8f004503c96d..f2b2b35e8646 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -9,6 +9,7 @@ struct mv_sata_platform_data;
* Basic Orion init functions used early by machine-setup.
*/
void orion5x_map_io(void);
+void orion5x_init_early(void);
void orion5x_init_irq(void);
void orion5x_init(void);
extern int orion5x_tclk;
diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c
index b1c451f5ee27..425807579303 100644
--- a/arch/arm/mach-orion5x/d2net-setup.c
+++ b/arch/arm/mach-orion5x/d2net-setup.c
@@ -339,6 +339,7 @@ MACHINE_START(D2NET, "LaCie d2 Network")
.boot_params = 0x00000100,
.init_machine = d2net_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
@@ -350,6 +351,7 @@ MACHINE_START(BIGDISK, "LaCie Big Disk Network")
.boot_params = 0x00000100,
.init_machine = d2net_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index df1083f5b6eb..c10a11715376 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -361,6 +361,7 @@ MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
.boot_params = 0x00000100,
.init_machine = db88f5281_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 3a7bc0e36982..90ab022eabeb 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -733,6 +733,7 @@ MACHINE_START(DNS323, "D-Link DNS-323")
.boot_params = 0x00000100,
.init_machine = dns323_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c
index ba98459f44b0..d037a90c216c 100644
--- a/arch/arm/mach-orion5x/edmini_v2-setup.c
+++ b/arch/arm/mach-orion5x/edmini_v2-setup.c
@@ -254,6 +254,7 @@ MACHINE_START(EDMINI_V2, "LaCie Ethernet Disk mini V2")
.boot_params = 0x00000100,
.init_machine = edmini_v2_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
index 5c9744cd8ef6..96484bcd34ca 100644
--- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h
+++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
@@ -22,14 +22,12 @@
#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE | 0x10c)
+#define BRIDGE_CAUSE (ORION5X_BRIDGE_VIRT_BASE | 0x110)
+
#define POWER_MNG_CTRL_REG (ORION5X_BRIDGE_VIRT_BASE | 0x11C)
-#define BRIDGE_CAUSE (ORION5X_BRIDGE_VIRT_BASE | 0x110)
#define WDT_INT_REQ 0x0008
-#define BRIDGE_MASK (ORION5X_BRIDGE_VIRT_BASE | 0x114)
-#define BRIDGE_INT_TIMER0 0x0002
-#define BRIDGE_INT_TIMER1 0x0004
#define BRIDGE_INT_TIMER1_CLR (~0x0004)
#define MAIN_IRQ_CAUSE (ORION5X_BRIDGE_VIRT_BASE | 0x200)
diff --git a/arch/arm/mach-orion5x/include/mach/gpio.h b/arch/arm/mach-orion5x/include/mach/gpio.h
index d8182e87ac16..a1d0b78decb1 100644
--- a/arch/arm/mach-orion5x/include/mach/gpio.h
+++ b/arch/arm/mach-orion5x/include/mach/gpio.h
@@ -6,32 +6,4 @@
* warranty of any kind, whether express or implied.
*/
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <mach/irqs.h>
#include <plat/gpio.h>
-#include <asm-generic/gpio.h> /* cansleep wrappers */
-
-#define GPIO_MAX 32
-#define GPIO_OUT(pin) ORION5X_DEV_BUS_REG(0x100)
-#define GPIO_IO_CONF(pin) ORION5X_DEV_BUS_REG(0x104)
-#define GPIO_BLINK_EN(pin) ORION5X_DEV_BUS_REG(0x108)
-#define GPIO_IN_POL(pin) ORION5X_DEV_BUS_REG(0x10c)
-#define GPIO_DATA_IN(pin) ORION5X_DEV_BUS_REG(0x110)
-#define GPIO_EDGE_CAUSE(pin) ORION5X_DEV_BUS_REG(0x114)
-#define GPIO_EDGE_MASK(pin) ORION5X_DEV_BUS_REG(0x118)
-#define GPIO_LEVEL_MASK(pin) ORION5X_DEV_BUS_REG(0x11c)
-
-static inline int gpio_to_irq(int pin)
-{
- return pin + IRQ_ORION5X_GPIO_START;
-}
-
-static inline int irq_to_gpio(int irq)
-{
- return irq - IRQ_ORION5X_GPIO_START;
-}
-
-
-#endif
diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h
index 2d8766570531..0a28bbc76891 100644
--- a/arch/arm/mach-orion5x/include/mach/orion5x.h
+++ b/arch/arm/mach-orion5x/include/mach/orion5x.h
@@ -73,6 +73,7 @@
#define ORION5X_DEV_BUS_PHYS_BASE (ORION5X_REGS_PHYS_BASE | 0x10000)
#define ORION5X_DEV_BUS_VIRT_BASE (ORION5X_REGS_VIRT_BASE | 0x10000)
#define ORION5X_DEV_BUS_REG(x) (ORION5X_DEV_BUS_VIRT_BASE | (x))
+#define GPIO_VIRT_BASE ORION5X_DEV_BUS_REG(0x0100)
#define SPI_PHYS_BASE (ORION5X_DEV_BUS_PHYS_BASE | 0x0600)
#define I2C_PHYS_BASE (ORION5X_DEV_BUS_PHYS_BASE | 0x1000)
#define UART0_PHYS_BASE (ORION5X_DEV_BUS_PHYS_BASE | 0x2000)
diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c
index d7512b925a85..ed85891f8699 100644
--- a/arch/arm/mach-orion5x/irq.c
+++ b/arch/arm/mach-orion5x/irq.c
@@ -28,27 +28,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
void __init orion5x_init_irq(void)
{
- int i;
-
orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK);
/*
- * Mask and clear GPIO IRQ interrupts
- */
- writel(0x0, GPIO_LEVEL_MASK(0));
- writel(0x0, GPIO_EDGE_MASK(0));
- writel(0x0, GPIO_EDGE_CAUSE(0));
-
- /*
- * Register chained level handlers for GPIO IRQs by default.
- * User can use set_type() if he wants to use edge types handlers.
+ * Initialize gpiolib for GPIOs 0-31.
*/
- for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) {
- set_irq_chip(i, &orion_gpio_irq_chip);
- set_irq_handler(i, handle_level_irq);
- irq_desc[i].status |= IRQ_LEVEL;
- set_irq_flags(i, IRQF_VALID);
- }
+ orion_gpio_init(0, 32, GPIO_VIRT_BASE, 0, IRQ_ORION5X_GPIO_START);
set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, gpio_irq_handler);
set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, gpio_irq_handler);
set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, gpio_irq_handler);
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index 4be9aa08de69..47497c76162a 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -382,6 +382,7 @@ MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
.boot_params = 0x00000100,
.init_machine = kurobox_pro_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
@@ -394,6 +395,7 @@ MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
.boot_params = 0x00000100,
.init_machine = kurobox_pro_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 20a9b66cbafa..6ae12aa6d759 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -321,6 +321,7 @@ MACHINE_START(LINKSTATION_LSCHL, "Buffalo Linkstation LiveV3 (LS-CHL)")
.boot_params = 0x00000100,
.init_machine = lschl_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index 437364b7168e..7adafd79cf98 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -268,6 +268,7 @@ MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
.boot_params = 0x00000100,
.init_machine = ls_hgl_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index ab9b0cf0a90b..869958f5c394 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -270,6 +270,7 @@ MACHINE_START(LINKSTATION_MINI, "Buffalo Linkstation Mini")
.boot_params = 0x00000100,
.init_machine = lsmini_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
index db485d3b8144..2288207726e4 100644
--- a/arch/arm/mach-orion5x/mpp.c
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -124,9 +124,6 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
- /* Initialize gpiolib. */
- orion_gpio_init();
-
for ( ; mode->mpp >= 0; mode++) {
u32 *reg;
int num_type;
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
index 2f0e16cd7e81..b43b208153cb 100644
--- a/arch/arm/mach-orion5x/mss2-setup.c
+++ b/arch/arm/mach-orion5x/mss2-setup.c
@@ -264,6 +264,7 @@ MACHINE_START(MSS2, "Maxtor Shared Storage II")
.boot_params = 0x00000100,
.init_machine = mss2_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32
diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c
index b3d90f25de9f..c55d071707f5 100644
--- a/arch/arm/mach-orion5x/mv2120-setup.c
+++ b/arch/arm/mach-orion5x/mv2120-setup.c
@@ -232,6 +232,7 @@ MACHINE_START(MV2120, "HP Media Vault mv2120")
.boot_params = 0x00000100,
.init_machine = mv2120_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32
diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c
index d6665b31665f..429ecafe9fdd 100644
--- a/arch/arm/mach-orion5x/net2big-setup.c
+++ b/arch/arm/mach-orion5x/net2big-setup.c
@@ -422,6 +422,7 @@ MACHINE_START(NET2BIG, "LaCie 2Big Network")
.boot_params = 0x00000100,
.init_machine = net2big_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index f4c26fd731f4..34310ab56e29 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -172,6 +172,7 @@ MACHINE_START(RD88F5181L_FXO, "Marvell Orion-VoIP FXO Reference Design")
.boot_params = 0x00000100,
.init_machine = rd88f5181l_fxo_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index b5942909bab0..c1f79fa014ed 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -184,6 +184,7 @@ MACHINE_START(RD88F5181L_GE, "Marvell Orion-VoIP GE Reference Design")
.boot_params = 0x00000100,
.init_machine = rd88f5181l_ge_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 165ed87029b2..67ec6959b267 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -308,6 +308,7 @@ MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
.boot_params = 0x00000100,
.init_machine = rd88f5182_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index 02ff45f3e2e3..b080c6966d10 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -126,6 +126,7 @@ MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
.boot_params = 0x00000100,
.init_machine = rd88f6183ap_ge_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c
index 4403fae5ab0e..5653ee6c71d8 100644
--- a/arch/arm/mach-orion5x/terastation_pro2-setup.c
+++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c
@@ -361,6 +361,7 @@ MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
.boot_params = 0x00000100,
.init_machine = tsp2_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index 1e196129d763..8bbd27ea6735 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -325,6 +325,7 @@ MACHINE_START(TS209, "QNAP TS-109/TS-209")
.boot_params = 0x00000100,
.init_machine = qnap_ts209_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/ts409-setup.c b/arch/arm/mach-orion5x/ts409-setup.c
index 428af2046e36..92f393f08fa4 100644
--- a/arch/arm/mach-orion5x/ts409-setup.c
+++ b/arch/arm/mach-orion5x/ts409-setup.c
@@ -314,6 +314,7 @@ MACHINE_START(TS409, "QNAP TS-409")
.boot_params = 0x00000100,
.init_machine = qnap_ts409_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
index 37b3d4875291..151e89e1e676 100644
--- a/arch/arm/mach-orion5x/ts78xx-fpga.h
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -1,3 +1,4 @@
+#define TS7800_FPGA_MAGIC 0x00b480
#define FPGAID(_magic, _rev) ((_magic << 8) + _rev)
/*
@@ -6,11 +7,15 @@
*/
enum fpga_ids {
/* Technologic Systems */
- TS7800_REV_1 = FPGAID(0x00b480, 0x01),
- TS7800_REV_2 = FPGAID(0x00b480, 0x02),
- TS7800_REV_3 = FPGAID(0x00b480, 0x03),
- TS7800_REV_4 = FPGAID(0x00b480, 0x04),
- TS7800_REV_5 = FPGAID(0x00b480, 0x05),
+ TS7800_REV_1 = FPGAID(TS7800_FPGA_MAGIC, 0x01),
+ TS7800_REV_2 = FPGAID(TS7800_FPGA_MAGIC, 0x02),
+ TS7800_REV_3 = FPGAID(TS7800_FPGA_MAGIC, 0x03),
+ TS7800_REV_4 = FPGAID(TS7800_FPGA_MAGIC, 0x04),
+ TS7800_REV_5 = FPGAID(TS7800_FPGA_MAGIC, 0x05),
+ TS7800_REV_6 = FPGAID(TS7800_FPGA_MAGIC, 0x06),
+ TS7800_REV_7 = FPGAID(TS7800_FPGA_MAGIC, 0x07),
+ TS7800_REV_8 = FPGAID(TS7800_FPGA_MAGIC, 0x08),
+ TS7800_REV_9 = FPGAID(TS7800_FPGA_MAGIC, 0x09),
/* Unaffordable & Expensive */
UAE_DUMMY = FPGAID(0xffffff, 0x01),
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index c1c1cd04bdde..8554707d20a9 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -191,6 +191,60 @@ static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
return readb(TS_NAND_CTRL) & 0x20;
}
+static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ void __iomem *io_base = chip->IO_ADDR_W;
+ unsigned long off = ((unsigned long)buf & 3);
+ int sz;
+
+ if (off) {
+ sz = min_t(int, 4 - off, len);
+ writesb(io_base, buf, sz);
+ buf += sz;
+ len -= sz;
+ }
+
+ sz = len >> 2;
+ if (sz) {
+ u32 *buf32 = (u32 *)buf;
+ writesl(io_base, buf32, sz);
+ buf += sz << 2;
+ len -= sz << 2;
+ }
+
+ if (len)
+ writesb(io_base, buf, len);
+}
+
+static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
+ uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ void __iomem *io_base = chip->IO_ADDR_R;
+ unsigned long off = ((unsigned long)buf & 3);
+ int sz;
+
+ if (off) {
+ sz = min_t(int, 4 - off, len);
+ readsb(io_base, buf, sz);
+ buf += sz;
+ len -= sz;
+ }
+
+ sz = len >> 2;
+ if (sz) {
+ u32 *buf32 = (u32 *)buf;
+ readsl(io_base, buf32, sz);
+ buf += sz << 2;
+ len -= sz << 2;
+ }
+
+ if (len)
+ readsb(io_base, buf, len);
+}
+
const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition ts78xx_ts_nand_parts[] = {
@@ -233,6 +287,8 @@ static struct platform_nand_data ts78xx_ts_nand_data = {
*/
.cmd_ctrl = ts78xx_ts_nand_cmd_ctrl,
.dev_ready = ts78xx_ts_nand_dev_ready,
+ .write_buf = ts78xx_ts_nand_write_buf,
+ .read_buf = ts78xx_ts_nand_read_buf,
},
};
@@ -334,14 +390,29 @@ static void ts78xx_fpga_supports(void)
case TS7800_REV_3:
case TS7800_REV_4:
case TS7800_REV_5:
+ case TS7800_REV_6:
+ case TS7800_REV_7:
+ case TS7800_REV_8:
+ case TS7800_REV_9:
ts78xx_fpga.supports.ts_rtc.present = 1;
ts78xx_fpga.supports.ts_nand.present = 1;
ts78xx_fpga.supports.ts_rng.present = 1;
break;
default:
- ts78xx_fpga.supports.ts_rtc.present = 0;
- ts78xx_fpga.supports.ts_nand.present = 0;
- ts78xx_fpga.supports.ts_rng.present = 0;
+ /* enable devices if magic matches */
+ switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
+ case TS7800_FPGA_MAGIC:
+ printk(KERN_WARNING "TS-7800 FPGA: unrecognized revision 0x%.2x\n",
+ ts78xx_fpga.id & 0xff);
+ ts78xx_fpga.supports.ts_rtc.present = 1;
+ ts78xx_fpga.supports.ts_nand.present = 1;
+ ts78xx_fpga.supports.ts_rng.present = 1;
+ break;
+ default:
+ ts78xx_fpga.supports.ts_rtc.present = 0;
+ ts78xx_fpga.supports.ts_nand.present = 0;
+ ts78xx_fpga.supports.ts_rng.present = 0;
+ }
}
}
@@ -553,6 +624,7 @@ MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
.boot_params = 0x00000100,
.init_machine = ts78xx_init,
.map_io = ts78xx_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
MACHINE_END
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 7994d6ec08a8..4e5216be0745 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -175,6 +175,7 @@ MACHINE_START(WNR854T, "Netgear WNR854T")
.boot_params = 0x00000100,
.init_machine = wnr854t_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index a5989b7eb53e..fab79d09cc5c 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -263,6 +263,7 @@ MACHINE_START(WRT350N_V2, "Linksys WRT350N v2")
.boot_params = 0x00000100,
.init_machine = wrt350n_v2_init,
.map_io = orion5x_map_io,
+ .init_early = orion5x_init_early,
.init_irq = orion5x_init_irq,
.timer = &orion5x_timer,
.fixup = tag_fixup_mem32,
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index 37405d9abe32..0db2411ef4bb 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -58,6 +58,9 @@
#include <linux/mfd/pcf50633/pmic.h>
#include <linux/mfd/pcf50633/backlight.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -86,6 +89,8 @@
#include <plat/udc.h>
#include <plat/gpio-cfg.h>
#include <plat/iic.h>
+#include <plat/ts.h>
+
static struct pcf50633 *gta02_pcf;
@@ -280,9 +285,6 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.valid_modes_mask = REGULATOR_MODE_NORMAL,
.always_on = 1,
.apply_uV = 1,
- .state_mem = {
- .enabled = 1,
- },
},
},
[PCF50633_REGULATOR_DOWN1] = {
@@ -301,9 +303,6 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.valid_modes_mask = REGULATOR_MODE_NORMAL,
.apply_uV = 1,
.always_on = 1,
- .state_mem = {
- .enabled = 1,
- },
},
},
[PCF50633_REGULATOR_HCLDO] = {
@@ -311,8 +310,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.min_uV = 2000000,
.max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
},
},
[PCF50633_REGULATOR_LDO1] = {
@@ -320,10 +319,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.min_uV = 3300000,
.max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
.apply_uV = 1,
- .state_mem = {
- .enabled = 0,
- },
},
},
[PCF50633_REGULATOR_LDO2] = {
@@ -347,6 +344,7 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.min_uV = 3200000,
.max_uV = 3200000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
.apply_uV = 1,
},
},
@@ -355,10 +353,8 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.min_uV = 3000000,
.max_uV = 3000000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
.apply_uV = 1,
- .state_mem = {
- .enabled = 1,
- },
},
},
[PCF50633_REGULATOR_LDO6] = {
@@ -373,9 +369,6 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
.min_uV = 1800000,
.max_uV = 1800000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
- .state_mem = {
- .enabled = 1,
- },
},
},
@@ -471,6 +464,43 @@ static struct s3c2410_hcd_info gta02_usb_info __initdata = {
},
};
+/* Touchscreen */
+static struct s3c2410_ts_mach_info gta02_ts_info = {
+ .delay = 10000,
+ .presc = 0xff, /* slow as we can go */
+ .oversampling_shift = 2,
+};
+
+/* Buttons */
+static struct gpio_keys_button gta02_buttons[] = {
+ {
+ .gpio = GTA02_GPIO_AUX_KEY,
+ .code = KEY_PHONE,
+ .desc = "Aux",
+ .type = EV_KEY,
+ .debounce_interval = 100,
+ },
+ {
+ .gpio = GTA02_GPIO_HOLD_KEY,
+ .code = KEY_PAUSE,
+ .desc = "Hold",
+ .type = EV_KEY,
+ .debounce_interval = 100,
+ },
+};
+
+static struct gpio_keys_platform_data gta02_buttons_pdata = {
+ .buttons = gta02_buttons,
+ .nbuttons = ARRAY_SIZE(gta02_buttons),
+};
+
+static struct platform_device gta02_buttons_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &gta02_buttons_pdata,
+ },
+};
static void __init gta02_map_io(void)
{
@@ -491,7 +521,11 @@ static struct platform_device *gta02_devices[] __initdata = {
&gta02_nor_flash,
&s3c24xx_pwm_device,
&s3c_device_iis,
+ &samsung_asoc_dma,
&s3c_device_i2c0,
+ &gta02_buttons_device,
+ &s3c_device_adc,
+ &s3c_device_ts,
};
/* These guys DO need to be children of PMU. */
@@ -541,6 +575,7 @@ static void __init gta02_machine_init(void)
#endif
s3c24xx_udc_set_platdata(&gta02_udc_cfg);
+ s3c24xx_ts_set_platdata(&gta02_ts_info);
s3c_ohci_set_platdata(&gta02_usb_info);
s3c_nand_set_platdata(&gta02_nand_info);
s3c_i2c0_set_platdata(NULL);
@@ -549,6 +584,8 @@ static void __init gta02_machine_init(void)
platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
pm_power_off = gta02_poweroff;
+
+ regulator_has_full_constraints();
}
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 579d2f0f4dd0..e4177e22557b 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -143,6 +143,7 @@ config MACH_SMDK6410
select S3C_DEV_USB_HSOTG
select S3C_DEV_WDT
select SAMSUNG_DEV_KEYPAD
+ select SAMSUNG_DEV_PWM
select HAVE_S3C2410_WATCHDOG if WATCHDOG
select S3C64XX_SETUP_SDHCI
select S3C64XX_SETUP_I2C1
@@ -231,7 +232,7 @@ config MACH_HMT
select S3C_DEV_NAND
select S3C_DEV_USB_HOST
select S3C64XX_SETUP_FB_24BPP
- select HAVE_PWM
+ select SAMSUNG_DEV_PWM
help
Machine support for the Airgoo HMT
@@ -249,8 +250,8 @@ config MACH_SMARTQ
select S3C64XX_SETUP_SDHCI
select S3C64XX_SETUP_FB_24BPP
select SAMSUNG_DEV_ADC
+ select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
- select HAVE_PWM
help
Shared machine support for SmartQ 5/7
diff --git a/arch/arm/mach-s3c64xx/cpufreq.c b/arch/arm/mach-s3c64xx/cpufreq.c
index 74c0e8347de5..4375b97588b8 100644
--- a/arch/arm/mach-s3c64xx/cpufreq.c
+++ b/arch/arm/mach-s3c64xx/cpufreq.c
@@ -181,7 +181,7 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
}
#endif
-static int __init s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
+static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
{
int ret;
struct cpufreq_frequency_table *freq;
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index a80a3163dd30..686a4f270b12 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -29,6 +29,7 @@
#include <linux/smsc911x.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
+#include <linux/pwm_backlight.h>
#ifdef CONFIG_SMDK6410_WM1190_EV1
#include <linux/mfd/wm8350/core.h>
@@ -49,6 +50,7 @@
#include <mach/hardware.h>
#include <mach/regs-fb.h>
#include <mach/map.h>
+#include <mach/gpio-bank-f.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -119,7 +121,6 @@ static void smdk6410_lcd_power_set(struct plat_lcd_data *pd,
{
if (power) {
gpio_direction_output(S3C64XX_GPF(13), 1);
- gpio_direction_output(S3C64XX_GPF(15), 1);
/* fire nRESET on power up */
gpio_direction_output(S3C64XX_GPN(5), 0);
@@ -127,7 +128,6 @@ static void smdk6410_lcd_power_set(struct plat_lcd_data *pd,
gpio_direction_output(S3C64XX_GPN(5), 1);
msleep(1);
} else {
- gpio_direction_output(S3C64XX_GPF(15), 0);
gpio_direction_output(S3C64XX_GPF(13), 0);
}
}
@@ -270,6 +270,45 @@ static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = {
.cols = 8,
};
+static int smdk6410_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(S3C64XX_GPF(15), "Backlight");
+ if (ret) {
+ printk(KERN_ERR "failed to request GPF for PWM-OUT1\n");
+ return ret;
+ }
+
+ /* Configure GPIO pin with S3C64XX_GPF15_PWM_TOUT1 */
+ s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
+
+ return 0;
+}
+
+static void smdk6410_backlight_exit(struct device *dev)
+{
+ s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_OUTPUT);
+ gpio_free(S3C64XX_GPF(15));
+}
+
+static struct platform_pwm_backlight_data smdk6410_backlight_data = {
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = smdk6410_backlight_init,
+ .exit = smdk6410_backlight_exit,
+};
+
+static struct platform_device smdk6410_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &s3c_device_timer[1].dev,
+ .platform_data = &smdk6410_backlight_data,
+ },
+};
+
static struct map_desc smdk6410_iodesc[] = {};
static struct platform_device *smdk6410_devices[] __initdata = {
@@ -299,6 +338,8 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_rtc,
&s3c_device_ts,
&s3c_device_wdt,
+ &s3c_device_timer[1],
+ &smdk6410_backlight_device,
};
#ifdef CONFIG_REGULATOR
@@ -694,7 +735,6 @@ static void __init smdk6410_machine_init(void)
gpio_request(S3C64XX_GPN(5), "LCD power");
gpio_request(S3C64XX_GPF(13), "LCD power");
- gpio_request(S3C64XX_GPF(15), "LCD power");
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 164d2783d381..017af4c4293c 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -10,12 +10,14 @@ if ARCH_S5P64X0
config CPU_S5P6440
bool
select S3C_PL330_DMA
+ select S5P_HRT
help
Enable S5P6440 CPU support
config CPU_S5P6450
bool
select S3C_PL330_DMA
+ select S5P_HRT
help
Enable S5P6450 CPU support
@@ -34,6 +36,7 @@ config MACH_SMDK6440
select S3C_DEV_WDT
select S3C64XX_DEV_SPI
select SAMSUNG_DEV_ADC
+ select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
select S5P64X0_SETUP_I2C1
help
@@ -47,6 +50,7 @@ config MACH_SMDK6450
select S3C_DEV_WDT
select S3C64XX_DEV_SPI
select SAMSUNG_DEV_ADC
+ select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
select S5P64X0_SETUP_I2C1
help
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index e5beb84e2393..2d559f10fd47 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/pwm_backlight.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -32,6 +33,7 @@
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/i2c.h>
+#include <mach/regs-gpio.h>
#include <plat/regs-serial.h>
#include <plat/gpio-cfg.h>
@@ -43,6 +45,7 @@
#include <plat/pll.h>
#include <plat/adc.h>
#include <plat/ts.h>
+#include <plat/s5p-time.h>
#define SMDK6440_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -88,6 +91,45 @@ static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
},
};
+static int smdk6440_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(S5P6440_GPF(15), "Backlight");
+ if (ret) {
+ printk(KERN_ERR "failed to request GPF for PWM-OUT1\n");
+ return ret;
+ }
+
+ /* Configure GPIO pin with S5P6440_GPF15_PWM_TOUT1 */
+ s3c_gpio_cfgpin(S5P6440_GPF(15), S3C_GPIO_SFN(2));
+
+ return 0;
+}
+
+static void smdk6440_backlight_exit(struct device *dev)
+{
+ s3c_gpio_cfgpin(S5P6440_GPF(15), S3C_GPIO_OUTPUT);
+ gpio_free(S5P6440_GPF(15));
+}
+
+static struct platform_pwm_backlight_data smdk6440_backlight_data = {
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = smdk6440_backlight_init,
+ .exit = smdk6440_backlight_exit,
+};
+
+static struct platform_device smdk6440_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &s3c_device_timer[1].dev,
+ .platform_data = &smdk6440_backlight_data,
+ },
+};
+
static struct platform_device *smdk6440_devices[] __initdata = {
&s3c_device_adc,
&s3c_device_rtc,
@@ -97,6 +139,8 @@ static struct platform_device *smdk6440_devices[] __initdata = {
&s3c_device_wdt,
&samsung_asoc_dma,
&s5p6440_device_iis,
+ &s3c_device_timer[1],
+ &smdk6440_backlight_device,
};
static struct s3c2410_platform_i2c s5p6440_i2c0_data __initdata = {
@@ -136,6 +180,7 @@ static void __init smdk6440_map_io(void)
s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk6440_uartcfgs, ARRAY_SIZE(smdk6440_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init smdk6440_machine_init(void)
@@ -159,5 +204,5 @@ MACHINE_START(SMDK6440, "SMDK6440")
.init_irq = s5p6440_init_irq,
.map_io = smdk6440_map_io,
.init_machine = smdk6440_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index 3a20de0a9264..d19c4690ee97 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/pwm_backlight.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -32,6 +33,7 @@
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/i2c.h>
+#include <mach/regs-gpio.h>
#include <plat/regs-serial.h>
#include <plat/gpio-cfg.h>
@@ -43,6 +45,7 @@
#include <plat/pll.h>
#include <plat/adc.h>
#include <plat/ts.h>
+#include <plat/s5p-time.h>
#define SMDK6450_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -106,6 +109,45 @@ static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = {
#endif
};
+static int smdk6450_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(S5P6450_GPF(15), "Backlight");
+ if (ret) {
+ printk(KERN_ERR "failed to request GPF for PWM-OUT1\n");
+ return ret;
+ }
+
+ /* Configure GPIO pin with S5P6450_GPF15_PWM_TOUT1 */
+ s3c_gpio_cfgpin(S5P6450_GPF(15), S3C_GPIO_SFN(2));
+
+ return 0;
+}
+
+static void smdk6450_backlight_exit(struct device *dev)
+{
+ s3c_gpio_cfgpin(S5P6450_GPF(15), S3C_GPIO_OUTPUT);
+ gpio_free(S5P6450_GPF(15));
+}
+
+static struct platform_pwm_backlight_data smdk6450_backlight_data = {
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = smdk6450_backlight_init,
+ .exit = smdk6450_backlight_exit,
+};
+
+static struct platform_device smdk6450_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &s3c_device_timer[1].dev,
+ .platform_data = &smdk6450_backlight_data,
+ },
+};
+
static struct platform_device *smdk6450_devices[] __initdata = {
&s3c_device_adc,
&s3c_device_rtc,
@@ -115,6 +157,8 @@ static struct platform_device *smdk6450_devices[] __initdata = {
&s3c_device_wdt,
&samsung_asoc_dma,
&s5p6450_device_iis0,
+ &s3c_device_timer[1],
+ &smdk6450_backlight_device,
/* s5p6450_device_spi0 will be added */
};
@@ -155,6 +199,7 @@ static void __init smdk6450_map_io(void)
s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
s3c24xx_init_clocks(19200000);
s3c24xx_init_uarts(smdk6450_uartcfgs, ARRAY_SIZE(smdk6450_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init smdk6450_machine_init(void)
@@ -178,5 +223,5 @@ MACHINE_START(SMDK6450, "SMDK6450")
.init_irq = s5p6450_init_irq,
.map_io = smdk6450_map_io,
.init_machine = smdk6450_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pc100/Kconfig b/arch/arm/mach-s5pc100/Kconfig
index b8fbf2fcba6f..608722ff4f28 100644
--- a/arch/arm/mach-s5pc100/Kconfig
+++ b/arch/arm/mach-s5pc100/Kconfig
@@ -58,6 +58,7 @@ config MACH_SMDKC100
select SAMSUNG_DEV_ADC
select SAMSUNG_DEV_IDE
select SAMSUNG_DEV_KEYPAD
+ select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
select S5PC100_SETUP_FB_24BPP
select S5PC100_SETUP_I2C1
diff --git a/arch/arm/mach-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c
index 20856eb7dd51..2842394b28b5 100644
--- a/arch/arm/mach-s5pc100/gpiolib.c
+++ b/arch/arm/mach-s5pc100/gpiolib.c
@@ -348,6 +348,7 @@ static __init int s5pc100_gpiolib_init(void)
}
samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips);
+ s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
return 0;
}
diff --git a/arch/arm/mach-s5pc100/mach-smdkc100.c b/arch/arm/mach-s5pc100/mach-smdkc100.c
index dd192a27524d..0525cb3ef406 100644
--- a/arch/arm/mach-s5pc100/mach-smdkc100.c
+++ b/arch/arm/mach-s5pc100/mach-smdkc100.c
@@ -23,12 +23,15 @@
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/input.h>
+#include <linux/pwm_backlight.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/map.h>
#include <mach/regs-fb.h>
+#include <mach/regs-gpio.h>
+
#include <video/platform_lcd.h>
#include <asm/irq.h>
@@ -107,9 +110,6 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
static void smdkc100_lcd_power_set(struct plat_lcd_data *pd,
unsigned int power)
{
- /* backlight */
- gpio_direction_output(S5PC100_GPD(0), power);
-
if (power) {
/* module reset */
gpio_direction_output(S5PC100_GPH0(6), 1);
@@ -179,6 +179,45 @@ static struct samsung_keypad_platdata smdkc100_keypad_data __initdata = {
.cols = 8,
};
+static int smdkc100_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(S5PC100_GPD(0), "Backlight");
+ if (ret) {
+ printk(KERN_ERR "failed to request GPF for PWM-OUT0\n");
+ return ret;
+ }
+
+ /* Configure GPIO pin with S5PC100_GPD_TOUT_0 */
+ s3c_gpio_cfgpin(S5PC100_GPD(0), S3C_GPIO_SFN(2));
+
+ return 0;
+}
+
+static void smdkc100_backlight_exit(struct device *dev)
+{
+ s3c_gpio_cfgpin(S5PC100_GPD(0), S3C_GPIO_OUTPUT);
+ gpio_free(S5PC100_GPD(0));
+}
+
+static struct platform_pwm_backlight_data smdkc100_backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = smdkc100_backlight_init,
+ .exit = smdkc100_backlight_exit,
+};
+
+static struct platform_device smdkc100_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &s3c_device_timer[0].dev,
+ .platform_data = &smdkc100_backlight_data,
+ },
+};
+
static struct platform_device *smdkc100_devices[] __initdata = {
&s3c_device_adc,
&s3c_device_cfcon,
@@ -200,6 +239,8 @@ static struct platform_device *smdkc100_devices[] __initdata = {
&s5p_device_fimc1,
&s5p_device_fimc2,
&s5pc100_device_spdif,
+ &s3c_device_timer[0],
+ &smdkc100_backlight_device,
};
static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
@@ -233,7 +274,6 @@ static void __init smdkc100_machine_init(void)
s5pc100_spdif_setup_gpio(S5PC100_SPDIF_GPD);
/* LCD init */
- gpio_request(S5PC100_GPD(0), "GPD");
gpio_request(S5PC100_GPH0(6), "GPH0");
smdkc100_lcd_power_set(&smdkc100_lcd_power_data, 0);
platform_add_devices(smdkc100_devices, ARRAY_SIZE(smdkc100_devices));
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 53aabef1e9ce..37b5a97594a5 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -13,6 +13,7 @@ config CPU_S5PV210
bool
select S3C_PL330_DMA
select S5P_EXT_INT
+ select S5P_HRT
select S5PV210_PM if PM
help
Enable S5PV210 CPU support
@@ -53,6 +54,11 @@ config S5PV210_SETUP_SDHCI_GPIO
help
Common setup code for SDHCI gpio.
+config S5PV210_SETUP_FIMC
+ bool
+ help
+ Common setup code for the camera interfaces.
+
menu "S5PC110 Machines"
config MACH_AQUILA
@@ -130,6 +136,7 @@ config MACH_SMDKV210
select SAMSUNG_DEV_ADC
select SAMSUNG_DEV_IDE
select SAMSUNG_DEV_KEYPAD
+ select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
select S5PV210_SETUP_FB_24BPP
select S5PV210_SETUP_I2C1
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index ff1a0db57a2f..11f17907b4e8 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -31,6 +31,7 @@ obj-y += dev-audio.o
obj-$(CONFIG_S3C64XX_DEV_SPI) += dev-spi.o
obj-$(CONFIG_S5PV210_SETUP_FB_24BPP) += setup-fb-24bpp.o
+obj-$(CONFIG_S5PV210_SETUP_FIMC) += setup-fimc.o
obj-$(CONFIG_S5PV210_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PV210_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_S5PV210_SETUP_IDE) += setup-ide.o
diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c
index a6f22920a2c2..22046e2f53c2 100644
--- a/arch/arm/mach-s5pv210/cpufreq.c
+++ b/arch/arm/mach-s5pv210/cpufreq.c
@@ -390,8 +390,7 @@ static int s5pv210_target(struct cpufreq_policy *policy,
}
#ifdef CONFIG_PM
-static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
- pm_message_t pmsg)
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
{
return 0;
}
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c
index ab673effd767..1ba20a703e05 100644
--- a/arch/arm/mach-s5pv210/gpiolib.c
+++ b/arch/arm/mach-s5pv210/gpiolib.c
@@ -281,6 +281,7 @@ static __init int s5pv210_gpiolib_init(void)
}
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
+ s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
return 0;
}
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index 4c45b74def5f..78925c516346 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -146,6 +146,10 @@
#define S5P_OM_STAT S5P_CLKREG(0xE100)
#define S5P_USB_PHY_CONTROL S5P_CLKREG(0xE80C)
#define S5P_DAC_CONTROL S5P_CLKREG(0xE810)
+#define S5P_MIPI_DPHY_CONTROL(x) S5P_CLKREG(0xE814)
+#define S5P_MIPI_DPHY_ENABLE (1 << 0)
+#define S5P_MIPI_DPHY_SRESETN (1 << 1)
+#define S5P_MIPI_DPHY_MRESETN (1 << 2)
#define S5P_INFORM0 S5P_CLKREG(0xF000)
#define S5P_INFORM1 S5P_CLKREG(0xF004)
@@ -161,7 +165,6 @@
#define S5P_MDNIE_SEL S5P_CLKREG(0x7008)
#define S5P_MIPI_PHY_CON0 S5P_CLKREG(0x7200)
#define S5P_MIPI_PHY_CON1 S5P_CLKREG(0x7204)
-#define S5P_MIPI_DPHY_CONTROL S5P_CLKREG(0xE814)
#define S5P_IDLE_CFG_TL_MASK (3 << 30)
#define S5P_IDLE_CFG_TM_MASK (3 << 28)
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index 557add4fc56c..4e1d8ff5ae59 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -39,6 +39,7 @@
#include <plat/fb.h>
#include <plat/fimc-core.h>
#include <plat/sdhci.h>
+#include <plat/s5p-time.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define AQUILA_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -296,13 +297,11 @@ static struct regulator_init_data aquila_ldo17_data = {
};
/* BUCK */
-static struct regulator_consumer_supply buck1_consumer[] = {
- { .supply = "vddarm", },
-};
+static struct regulator_consumer_supply buck1_consumer =
+ REGULATOR_SUPPLY("vddarm", NULL);
-static struct regulator_consumer_supply buck2_consumer[] = {
- { .supply = "vddint", },
-};
+static struct regulator_consumer_supply buck2_consumer =
+ REGULATOR_SUPPLY("vddint", NULL);
static struct regulator_init_data aquila_buck1_data = {
.constraints = {
@@ -313,8 +312,8 @@ static struct regulator_init_data aquila_buck1_data = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = ARRAY_SIZE(buck1_consumer),
- .consumer_supplies = buck1_consumer,
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &buck1_consumer,
};
static struct regulator_init_data aquila_buck2_data = {
@@ -326,8 +325,8 @@ static struct regulator_init_data aquila_buck2_data = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = ARRAY_SIZE(buck2_consumer),
- .consumer_supplies = buck2_consumer,
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &buck2_consumer,
};
static struct regulator_init_data aquila_buck3_data = {
@@ -391,26 +390,14 @@ static struct max8998_platform_data aquila_max8998_pdata = {
#endif
static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = {
- {
- .dev_name = "5-001a",
- .supply = "DBVDD",
- }, {
- .dev_name = "5-001a",
- .supply = "AVDD2",
- }, {
- .dev_name = "5-001a",
- .supply = "CPVDD",
- },
+ REGULATOR_SUPPLY("DBVDD", "5-001a"),
+ REGULATOR_SUPPLY("AVDD2", "5-001a"),
+ REGULATOR_SUPPLY("CPVDD", "5-001a"),
};
static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = {
- {
- .dev_name = "5-001a",
- .supply = "SPKVDD1",
- }, {
- .dev_name = "5-001a",
- .supply = "SPKVDD2",
- },
+ REGULATOR_SUPPLY("SPKVDD1", "5-001a"),
+ REGULATOR_SUPPLY("SPKVDD2", "5-001a"),
};
static struct regulator_init_data wm8994_fixed_voltage0_init_data = {
@@ -459,15 +446,11 @@ static struct platform_device wm8994_fixed_voltage1 = {
},
};
-static struct regulator_consumer_supply wm8994_avdd1_supply = {
- .dev_name = "5-001a",
- .supply = "AVDD1",
-};
+static struct regulator_consumer_supply wm8994_avdd1_supply =
+ REGULATOR_SUPPLY("AVDD1", "5-001a");
-static struct regulator_consumer_supply wm8994_dcvdd_supply = {
- .dev_name = "5-001a",
- .supply = "DCVDD",
-};
+static struct regulator_consumer_supply wm8994_dcvdd_supply =
+ REGULATOR_SUPPLY("DCVDD", "5-001a");
static struct regulator_init_data wm8994_ldo1_data = {
.constraints = {
@@ -664,6 +647,7 @@ static void __init aquila_map_io(void)
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s3c24xx_init_uarts(aquila_uartcfgs, ARRAY_SIZE(aquila_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init aquila_machine_init(void)
@@ -698,5 +682,5 @@ MACHINE_START(AQUILA, "Aquila")
.init_irq = s5pv210_init_irq,
.map_io = aquila_map_io,
.init_machine = aquila_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 056f5c769b0a..243291722c66 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -45,6 +45,7 @@
#include <plat/keypad.h>
#include <plat/sdhci.h>
#include <plat/clock.h>
+#include <plat/s5p-time.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define GONI_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -108,6 +109,8 @@ static struct s3c_fb_pd_win goni_fb_win0 = {
},
.max_bpp = 32,
.default_bpp = 16,
+ .virtual_x = 480,
+ .virtual_y = 2 * 800,
};
static struct s3c_fb_platdata goni_lcd_pdata __initdata = {
@@ -269,10 +272,30 @@ static void __init goni_tsp_init(void)
/* MAX8998 regulators */
#if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE)
+static struct regulator_consumer_supply goni_ldo3_consumers[] = {
+ REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"),
+};
+
static struct regulator_consumer_supply goni_ldo5_consumers[] = {
REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
};
+static struct regulator_consumer_supply goni_ldo8_consumers[] = {
+ REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"),
+};
+
+static struct regulator_consumer_supply goni_ldo11_consumers[] = {
+ REGULATOR_SUPPLY("vddio", "0-0030"), /* "CAM_IO_2.8V" */
+};
+
+static struct regulator_consumer_supply goni_ldo13_consumers[] = {
+ REGULATOR_SUPPLY("vdda", "0-0030"), /* "CAM_A_2.8V" */
+};
+
+static struct regulator_consumer_supply goni_ldo14_consumers[] = {
+ REGULATOR_SUPPLY("vdd_core", "0-0030"), /* "CAM_CIF_1.8V" */
+};
+
static struct regulator_init_data goni_ldo2_data = {
.constraints = {
.name = "VALIVE_1.1V",
@@ -292,8 +315,10 @@ static struct regulator_init_data goni_ldo3_data = {
.min_uV = 1100000,
.max_uV = 1100000,
.apply_uV = 1,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(goni_ldo3_consumers),
+ .consumer_supplies = goni_ldo3_consumers,
};
static struct regulator_init_data goni_ldo4_data = {
@@ -311,6 +336,7 @@ static struct regulator_init_data goni_ldo5_data = {
.min_uV = 2800000,
.max_uV = 2800000,
.apply_uV = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(goni_ldo5_consumers),
.consumer_supplies = goni_ldo5_consumers,
@@ -341,8 +367,10 @@ static struct regulator_init_data goni_ldo8_data = {
.min_uV = 3300000,
.max_uV = 3300000,
.apply_uV = 1,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(goni_ldo8_consumers),
+ .consumer_supplies = goni_ldo8_consumers,
};
static struct regulator_init_data goni_ldo9_data = {
@@ -351,7 +379,6 @@ static struct regulator_init_data goni_ldo9_data = {
.min_uV = 2800000,
.max_uV = 2800000,
.apply_uV = 1,
- .always_on = 1,
},
};
@@ -371,8 +398,10 @@ static struct regulator_init_data goni_ldo11_data = {
.min_uV = 2800000,
.max_uV = 2800000,
.apply_uV = 1,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(goni_ldo11_consumers),
+ .consumer_supplies = goni_ldo11_consumers,
};
static struct regulator_init_data goni_ldo12_data = {
@@ -381,7 +410,6 @@ static struct regulator_init_data goni_ldo12_data = {
.min_uV = 1200000,
.max_uV = 1200000,
.apply_uV = 1,
- .always_on = 1,
},
};
@@ -391,8 +419,10 @@ static struct regulator_init_data goni_ldo13_data = {
.min_uV = 2800000,
.max_uV = 2800000,
.apply_uV = 1,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(goni_ldo13_consumers),
+ .consumer_supplies = goni_ldo13_consumers,
};
static struct regulator_init_data goni_ldo14_data = {
@@ -401,8 +431,10 @@ static struct regulator_init_data goni_ldo14_data = {
.min_uV = 1800000,
.max_uV = 1800000,
.apply_uV = 1,
- .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(goni_ldo14_consumers),
+ .consumer_supplies = goni_ldo14_consumers,
};
static struct regulator_init_data goni_ldo15_data = {
@@ -411,7 +443,6 @@ static struct regulator_init_data goni_ldo15_data = {
.min_uV = 3300000,
.max_uV = 3300000,
.apply_uV = 1,
- .always_on = 1,
},
};
@@ -421,7 +452,6 @@ static struct regulator_init_data goni_ldo16_data = {
.min_uV = 1800000,
.max_uV = 1800000,
.apply_uV = 1,
- .always_on = 1,
},
};
@@ -436,13 +466,11 @@ static struct regulator_init_data goni_ldo17_data = {
};
/* BUCK */
-static struct regulator_consumer_supply buck1_consumer[] = {
- { .supply = "vddarm", },
-};
+static struct regulator_consumer_supply buck1_consumer =
+ REGULATOR_SUPPLY("vddarm", NULL);
-static struct regulator_consumer_supply buck2_consumer[] = {
- { .supply = "vddint", },
-};
+static struct regulator_consumer_supply buck2_consumer =
+ REGULATOR_SUPPLY("vddint", NULL);
static struct regulator_init_data goni_buck1_data = {
.constraints = {
@@ -453,8 +481,8 @@ static struct regulator_init_data goni_buck1_data = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = ARRAY_SIZE(buck1_consumer),
- .consumer_supplies = buck1_consumer,
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &buck1_consumer,
};
static struct regulator_init_data goni_buck2_data = {
@@ -466,8 +494,8 @@ static struct regulator_init_data goni_buck2_data = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = ARRAY_SIZE(buck2_consumer),
- .consumer_supplies = buck2_consumer,
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &buck2_consumer,
};
static struct regulator_init_data goni_buck3_data = {
@@ -531,26 +559,14 @@ static struct max8998_platform_data goni_max8998_pdata = {
#endif
static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = {
- {
- .dev_name = "5-001a",
- .supply = "DBVDD",
- }, {
- .dev_name = "5-001a",
- .supply = "AVDD2",
- }, {
- .dev_name = "5-001a",
- .supply = "CPVDD",
- },
+ REGULATOR_SUPPLY("DBVDD", "5-001a"),
+ REGULATOR_SUPPLY("AVDD2", "5-001a"),
+ REGULATOR_SUPPLY("CPVDD", "5-001a"),
};
static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = {
- {
- .dev_name = "5-001a",
- .supply = "SPKVDD1",
- }, {
- .dev_name = "5-001a",
- .supply = "SPKVDD2",
- },
+ REGULATOR_SUPPLY("SPKVDD1", "5-001a"),
+ REGULATOR_SUPPLY("SPKVDD2", "5-001a"),
};
static struct regulator_init_data wm8994_fixed_voltage0_init_data = {
@@ -599,15 +615,11 @@ static struct platform_device wm8994_fixed_voltage1 = {
},
};
-static struct regulator_consumer_supply wm8994_avdd1_supply = {
- .dev_name = "5-001a",
- .supply = "AVDD1",
-};
+static struct regulator_consumer_supply wm8994_avdd1_supply =
+ REGULATOR_SUPPLY("AVDD1", "5-001a");
-static struct regulator_consumer_supply wm8994_dcvdd_supply = {
- .dev_name = "5-001a",
- .supply = "DCVDD",
-};
+static struct regulator_consumer_supply wm8994_dcvdd_supply =
+ REGULATOR_SUPPLY("DCVDD", "5-001a");
static struct regulator_init_data wm8994_ldo1_data = {
.constraints = {
@@ -794,6 +806,7 @@ static struct platform_device *goni_devices[] __initdata = {
&goni_i2c_gpio5,
&mmc2_fixed_voltage,
&goni_device_gpiokeys,
+ &s3c_device_i2c0,
&s5p_device_fimc0,
&s5p_device_fimc1,
&s5p_device_fimc2,
@@ -823,6 +836,7 @@ static void __init goni_map_io(void)
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s3c24xx_init_uarts(goni_uartcfgs, ARRAY_SIZE(goni_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init goni_machine_init(void)
@@ -830,6 +844,9 @@ static void __init goni_machine_init(void)
/* Radio: call before I2C 1 registeration */
goni_radio_init();
+ /* I2C0 */
+ s3c_i2c0_set_platdata(NULL);
+
/* I2C1 */
s3c_i2c1_set_platdata(NULL);
i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
@@ -873,5 +890,5 @@ MACHINE_START(GONI, "GONI")
.init_irq = s5pv210_init_irq,
.map_io = goni_map_io,
.init_machine = goni_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c
index ce11a02eabf3..6c412c8ceccc 100644
--- a/arch/arm/mach-s5pv210/mach-smdkc110.c
+++ b/arch/arm/mach-s5pv210/mach-smdkc110.c
@@ -30,6 +30,7 @@
#include <plat/ata.h>
#include <plat/iic.h>
#include <plat/pm.h>
+#include <plat/s5p-time.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKC110_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -111,6 +112,7 @@ static void __init smdkc110_map_io(void)
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init smdkc110_machine_init(void)
@@ -138,5 +140,5 @@ MACHINE_START(SMDKC110, "SMDKC110")
.init_irq = s5pv210_init_irq,
.map_io = smdkc110_map_io,
.init_machine = smdkc110_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index bc9fdb52a020..bc08ac42e7cc 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -18,6 +18,7 @@
#include <linux/fb.h>
#include <linux/gpio.h>
#include <linux/delay.h>
+#include <linux/pwm_backlight.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -43,6 +44,8 @@
#include <plat/keypad.h>
#include <plat/pm.h>
#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+#include <plat/s5p-time.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -208,6 +211,45 @@ static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
.setup_gpio = s5pv210_fb_gpio_setup_24bpp,
};
+static int smdkv210_backlight_init(struct device *dev)
+{
+ int ret;
+
+ ret = gpio_request(S5PV210_GPD0(3), "Backlight");
+ if (ret) {
+ printk(KERN_ERR "failed to request GPD for PWM-OUT 3\n");
+ return ret;
+ }
+
+ /* Configure GPIO pin with S5PV210_GPD_0_3_TOUT_3 */
+ s3c_gpio_cfgpin(S5PV210_GPD0(3), S3C_GPIO_SFN(2));
+
+ return 0;
+}
+
+static void smdkv210_backlight_exit(struct device *dev)
+{
+ s3c_gpio_cfgpin(S5PV210_GPD0(3), S3C_GPIO_OUTPUT);
+ gpio_free(S5PV210_GPD0(3));
+}
+
+static struct platform_pwm_backlight_data smdkv210_backlight_data = {
+ .pwm_id = 3,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 78770,
+ .init = smdkv210_backlight_init,
+ .exit = smdkv210_backlight_exit,
+};
+
+static struct platform_device smdkv210_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &s3c_device_timer[3].dev,
+ .platform_data = &smdkv210_backlight_data,
+ },
+};
+
static struct platform_device *smdkv210_devices[] __initdata = {
&s3c_device_adc,
&s3c_device_cfcon,
@@ -229,6 +271,8 @@ static struct platform_device *smdkv210_devices[] __initdata = {
&samsung_device_keypad,
&smdkv210_dm9000,
&smdkv210_lcd_lte480wv,
+ &s3c_device_timer[3],
+ &smdkv210_backlight_device,
};
static void __init smdkv210_dm9000_init(void)
@@ -272,6 +316,7 @@ static void __init smdkv210_map_io(void)
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s3c24xx_init_uarts(smdkv210_uartcfgs, ARRAY_SIZE(smdkv210_uartcfgs));
+ s5p_set_timer_source(S5P_PWM2, S5P_PWM4);
}
static void __init smdkv210_machine_init(void)
@@ -306,5 +351,5 @@ MACHINE_START(SMDKV210, "SMDKV210")
.init_irq = s5pv210_init_irq,
.map_io = smdkv210_map_io,
.init_machine = smdkv210_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/mach-torbreck.c b/arch/arm/mach-s5pv210/mach-torbreck.c
index 043c938806b0..925fc0dc6252 100644
--- a/arch/arm/mach-s5pv210/mach-torbreck.c
+++ b/arch/arm/mach-s5pv210/mach-torbreck.c
@@ -27,6 +27,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/iic.h>
+#include <plat/s5p-time.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define TORBRECK_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -104,6 +105,7 @@ static void __init torbreck_map_io(void)
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
s3c24xx_init_clocks(24000000);
s3c24xx_init_uarts(torbreck_uartcfgs, ARRAY_SIZE(torbreck_uartcfgs));
+ s5p_set_timer_source(S5P_PWM3, S5P_PWM4);
}
static void __init torbreck_machine_init(void)
@@ -127,5 +129,5 @@ MACHINE_START(TORBRECK, "TORBRECK")
.init_irq = s5pv210_init_irq,
.map_io = torbreck_map_io,
.init_machine = torbreck_machine_init,
- .timer = &s3c24xx_timer,
+ .timer = &s5p_timer,
MACHINE_END
diff --git a/arch/arm/mach-s5pv210/setup-fimc.c b/arch/arm/mach-s5pv210/setup-fimc.c
new file mode 100644
index 000000000000..54cc5b11be0b
--- /dev/null
+++ b/arch/arm/mach-s5pv210/setup-fimc.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * S5PV210 camera interface GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <plat/camport.h>
+
+int s5pv210_fimc_setup_gpio(enum s5p_camport_id id)
+{
+ u32 gpio8, gpio5;
+ int ret;
+
+ switch (id) {
+ case S5P_CAMPORT_A:
+ gpio8 = S5PV210_GPE0(0);
+ gpio5 = S5PV210_GPE1(0);
+ break;
+
+ case S5P_CAMPORT_B:
+ gpio8 = S5PV210_GPJ0(0);
+ gpio5 = S5PV210_GPJ1(0);
+ break;
+
+ default:
+ WARN(1, "Wrong camport id: %d\n", id);
+ return -EINVAL;
+ }
+
+ ret = s3c_gpio_cfgall_range(gpio8, 8, S3C_GPIO_SFN(2),
+ S3C_GPIO_PULL_UP);
+ if (ret)
+ return ret;
+
+ return s3c_gpio_cfgall_range(gpio5, 5, S3C_GPIO_SFN(2),
+ S3C_GPIO_PULL_UP);
+}
diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig
deleted file mode 100644
index b2a9acc5185f..000000000000
--- a/arch/arm/mach-s5pv310/Kconfig
+++ /dev/null
@@ -1,151 +0,0 @@
-# arch/arm/mach-s5pv310/Kconfig
-#
-# Copyright (c) 2010 Samsung Electronics Co., Ltd.
-# http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-# Configuration options for the S5PV310
-
-if ARCH_S5PV310
-
-config CPU_S5PV310
- bool
- select S3C_PL330_DMA
- help
- Enable S5PV310 CPU support
-
-config S5PV310_DEV_PD
- bool
- help
- Compile in platform device definitions for Power Domain
-
-config S5PV310_SETUP_I2C1
- bool
- help
- Common setup code for i2c bus 1.
-
-config S5PV310_SETUP_I2C2
- bool
- help
- Common setup code for i2c bus 2.
-
-config S5PV310_SETUP_I2C3
- bool
- help
- Common setup code for i2c bus 3.
-
-config S5PV310_SETUP_I2C4
- bool
- help
- Common setup code for i2c bus 4.
-
-config S5PV310_SETUP_I2C5
- bool
- help
- Common setup code for i2c bus 5.
-
-config S5PV310_SETUP_I2C6
- bool
- help
- Common setup code for i2c bus 6.
-
-config S5PV310_SETUP_I2C7
- bool
- help
- Common setup code for i2c bus 7.
-
-config S5PV310_SETUP_SDHCI
- bool
- select S5PV310_SETUP_SDHCI_GPIO
- help
- Internal helper functions for S5PV310 based SDHCI systems.
-
-config S5PV310_SETUP_SDHCI_GPIO
- bool
- help
- Common setup code for SDHCI gpio.
-
-config S5PV310_DEV_SYSMMU
- bool
- help
- Common setup code for SYSTEM MMU in S5PV310
-
-# machine support
-
-menu "S5PC210 Machines"
-
-config MACH_SMDKC210
- bool "SMDKC210"
- select CPU_S5PV310
- select S3C_DEV_RTC
- select S3C_DEV_WDT
- select S3C_DEV_I2C1
- select S3C_DEV_HSMMC
- select S3C_DEV_HSMMC1
- select S3C_DEV_HSMMC2
- select S3C_DEV_HSMMC3
- select S5PV310_DEV_PD
- select S5PV310_SETUP_I2C1
- select S5PV310_SETUP_SDHCI
- select S5PV310_DEV_SYSMMU
- help
- Machine support for Samsung SMDKC210
- S5PC210(MCP) is one of package option of S5PV310
-
-config MACH_UNIVERSAL_C210
- bool "Mobile UNIVERSAL_C210 Board"
- select CPU_S5PV310
- select S5P_DEV_ONENAND
- select S3C_DEV_HSMMC
- select S3C_DEV_HSMMC2
- select S3C_DEV_HSMMC3
- select S5PV310_SETUP_SDHCI
- select S3C_DEV_I2C1
- select S5PV310_SETUP_I2C1
- help
- Machine support for Samsung Mobile Universal S5PC210 Reference
- Board. S5PC210(MCP) is one of package option of S5PV310
-
-endmenu
-
-menu "S5PV310 Machines"
-
-config MACH_SMDKV310
- bool "SMDKV310"
- select CPU_S5PV310
- select S3C_DEV_RTC
- select S3C_DEV_WDT
- select S3C_DEV_I2C1
- select S3C_DEV_HSMMC
- select S3C_DEV_HSMMC1
- select S3C_DEV_HSMMC2
- select S3C_DEV_HSMMC3
- select S5PV310_DEV_PD
- select S5PV310_DEV_SYSMMU
- select S5PV310_SETUP_I2C1
- select S5PV310_SETUP_SDHCI
- help
- Machine support for Samsung SMDKV310
-
-endmenu
-
-comment "Configuration for HSMMC bus width"
-
-menu "Use 8-bit bus width"
-
-config S5PV310_SDHCI_CH0_8BIT
- bool "Channel 0 with 8-bit bus"
- help
- Support HSMMC Channel 0 8-bit bus.
- If selected, Channel 1 is disabled.
-
-config S5PV310_SDHCI_CH2_8BIT
- bool "Channel 2 with 8-bit bus"
- help
- Support HSMMC Channel 2 8-bit bus.
- If selected, Channel 3 is disabled.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile
deleted file mode 100644
index 036fb383b830..000000000000
--- a/arch/arm/mach-s5pv310/Makefile
+++ /dev/null
@@ -1,43 +0,0 @@
-# arch/arm/mach-s5pv310/Makefile
-#
-# Copyright (c) 2010 Samsung Electronics Co., Ltd.
-# http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-# Core support for S5PV310 system
-
-obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o
-obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o dma.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
-
-obj-$(CONFIG_SMP) += platsmp.o headsmp.o
-obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-
-# machine support
-
-obj-$(CONFIG_MACH_SMDKC210) += mach-smdkc210.o
-obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o
-obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
-
-# device support
-
-obj-y += dev-audio.o
-obj-$(CONFIG_S5PV310_DEV_PD) += dev-pd.o
-obj-$(CONFIG_S5PV310_DEV_SYSMMU) += dev-sysmmu.o
-
-obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o
-obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o
-obj-$(CONFIG_S5PV310_SETUP_I2C3) += setup-i2c3.o
-obj-$(CONFIG_S5PV310_SETUP_I2C4) += setup-i2c4.o
-obj-$(CONFIG_S5PV310_SETUP_I2C5) += setup-i2c5.o
-obj-$(CONFIG_S5PV310_SETUP_I2C6) += setup-i2c6.o
-obj-$(CONFIG_S5PV310_SETUP_I2C7) += setup-i2c7.o
-obj-$(CONFIG_S5PV310_SETUP_SDHCI) += setup-sdhci.o
-obj-$(CONFIG_S5PV310_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
diff --git a/arch/arm/mach-s5pv310/gpiolib.c b/arch/arm/mach-s5pv310/gpiolib.c
deleted file mode 100644
index 55217b8923ec..000000000000
--- a/arch/arm/mach-s5pv310/gpiolib.c
+++ /dev/null
@@ -1,304 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/gpiolib.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * S5PV310 - GPIOlib support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <mach/map.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-static struct s3c_gpio_cfg gpio_cfg = {
- .set_config = s3c_gpio_setcfg_s3c64xx_4bit,
- .set_pull = s3c_gpio_setpull_updown,
- .get_pull = s3c_gpio_getpull_updown,
-};
-
-static struct s3c_gpio_cfg gpio_cfg_noint = {
- .set_config = s3c_gpio_setcfg_s3c64xx_4bit,
- .set_pull = s3c_gpio_setpull_updown,
- .get_pull = s3c_gpio_getpull_updown,
-};
-
-/*
- * Following are the gpio banks in v310.
- *
- * The 'config' member when left to NULL, is initialized to the default
- * structure gpio_cfg in the init function below.
- *
- * The 'base' member is also initialized in the init function below.
- * Note: The initialization of 'base' member of s3c_gpio_chip structure
- * uses the above macro and depends on the banks being listed in order here.
- */
-static struct s3c_gpio_chip s5pv310_gpio_part1_4bit[] = {
- {
- .chip = {
- .base = S5PV310_GPA0(0),
- .ngpio = S5PV310_GPIO_A0_NR,
- .label = "GPA0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPA1(0),
- .ngpio = S5PV310_GPIO_A1_NR,
- .label = "GPA1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPB(0),
- .ngpio = S5PV310_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = S5PV310_GPC0(0),
- .ngpio = S5PV310_GPIO_C0_NR,
- .label = "GPC0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPC1(0),
- .ngpio = S5PV310_GPIO_C1_NR,
- .label = "GPC1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPD0(0),
- .ngpio = S5PV310_GPIO_D0_NR,
- .label = "GPD0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPD1(0),
- .ngpio = S5PV310_GPIO_D1_NR,
- .label = "GPD1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPE0(0),
- .ngpio = S5PV310_GPIO_E0_NR,
- .label = "GPE0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPE1(0),
- .ngpio = S5PV310_GPIO_E1_NR,
- .label = "GPE1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPE2(0),
- .ngpio = S5PV310_GPIO_E2_NR,
- .label = "GPE2",
- },
- }, {
- .chip = {
- .base = S5PV310_GPE3(0),
- .ngpio = S5PV310_GPIO_E3_NR,
- .label = "GPE3",
- },
- }, {
- .chip = {
- .base = S5PV310_GPE4(0),
- .ngpio = S5PV310_GPIO_E4_NR,
- .label = "GPE4",
- },
- }, {
- .chip = {
- .base = S5PV310_GPF0(0),
- .ngpio = S5PV310_GPIO_F0_NR,
- .label = "GPF0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPF1(0),
- .ngpio = S5PV310_GPIO_F1_NR,
- .label = "GPF1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPF2(0),
- .ngpio = S5PV310_GPIO_F2_NR,
- .label = "GPF2",
- },
- }, {
- .chip = {
- .base = S5PV310_GPF3(0),
- .ngpio = S5PV310_GPIO_F3_NR,
- .label = "GPF3",
- },
- },
-};
-
-static struct s3c_gpio_chip s5pv310_gpio_part2_4bit[] = {
- {
- .chip = {
- .base = S5PV310_GPJ0(0),
- .ngpio = S5PV310_GPIO_J0_NR,
- .label = "GPJ0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPJ1(0),
- .ngpio = S5PV310_GPIO_J1_NR,
- .label = "GPJ1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPK0(0),
- .ngpio = S5PV310_GPIO_K0_NR,
- .label = "GPK0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPK1(0),
- .ngpio = S5PV310_GPIO_K1_NR,
- .label = "GPK1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPK2(0),
- .ngpio = S5PV310_GPIO_K2_NR,
- .label = "GPK2",
- },
- }, {
- .chip = {
- .base = S5PV310_GPK3(0),
- .ngpio = S5PV310_GPIO_K3_NR,
- .label = "GPK3",
- },
- }, {
- .chip = {
- .base = S5PV310_GPL0(0),
- .ngpio = S5PV310_GPIO_L0_NR,
- .label = "GPL0",
- },
- }, {
- .chip = {
- .base = S5PV310_GPL1(0),
- .ngpio = S5PV310_GPIO_L1_NR,
- .label = "GPL1",
- },
- }, {
- .chip = {
- .base = S5PV310_GPL2(0),
- .ngpio = S5PV310_GPIO_L2_NR,
- .label = "GPL2",
- },
- }, {
- .base = (S5P_VA_GPIO2 + 0xC00),
- .config = &gpio_cfg_noint,
- .irq_base = IRQ_EINT(0),
- .chip = {
- .base = S5PV310_GPX0(0),
- .ngpio = S5PV310_GPIO_X0_NR,
- .label = "GPX0",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO2 + 0xC20),
- .config = &gpio_cfg_noint,
- .irq_base = IRQ_EINT(8),
- .chip = {
- .base = S5PV310_GPX1(0),
- .ngpio = S5PV310_GPIO_X1_NR,
- .label = "GPX1",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO2 + 0xC40),
- .config = &gpio_cfg_noint,
- .irq_base = IRQ_EINT(16),
- .chip = {
- .base = S5PV310_GPX2(0),
- .ngpio = S5PV310_GPIO_X2_NR,
- .label = "GPX2",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .base = (S5P_VA_GPIO2 + 0xC60),
- .config = &gpio_cfg_noint,
- .irq_base = IRQ_EINT(24),
- .chip = {
- .base = S5PV310_GPX3(0),
- .ngpio = S5PV310_GPIO_X3_NR,
- .label = "GPX3",
- .to_irq = samsung_gpiolib_to_irq,
- },
- },
-};
-
-static struct s3c_gpio_chip s5pv310_gpio_part3_4bit[] = {
- {
- .chip = {
- .base = S5PV310_GPZ(0),
- .ngpio = S5PV310_GPIO_Z_NR,
- .label = "GPZ",
- },
- },
-};
-
-static __init int s5pv310_gpiolib_init(void)
-{
- struct s3c_gpio_chip *chip;
- int i;
- int nr_chips;
-
- /* GPIO part 1 */
-
- chip = s5pv310_gpio_part1_4bit;
- nr_chips = ARRAY_SIZE(s5pv310_gpio_part1_4bit);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (chip->config == NULL)
- chip->config = &gpio_cfg;
- if (chip->base == NULL)
- chip->base = S5P_VA_GPIO1 + (i) * 0x20;
- }
-
- samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part1_4bit, nr_chips);
-
- /* GPIO part 2 */
-
- chip = s5pv310_gpio_part2_4bit;
- nr_chips = ARRAY_SIZE(s5pv310_gpio_part2_4bit);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (chip->config == NULL)
- chip->config = &gpio_cfg;
- if (chip->base == NULL)
- chip->base = S5P_VA_GPIO2 + (i) * 0x20;
- }
-
- samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part2_4bit, nr_chips);
-
- /* GPIO part 3 */
-
- chip = s5pv310_gpio_part3_4bit;
- nr_chips = ARRAY_SIZE(s5pv310_gpio_part3_4bit);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (chip->config == NULL)
- chip->config = &gpio_cfg;
- if (chip->base == NULL)
- chip->base = S5P_VA_GPIO3 + (i) * 0x20;
- }
-
- samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part3_4bit, nr_chips);
-
- return 0;
-}
-core_initcall(s5pv310_gpiolib_init);
diff --git a/arch/arm/mach-s5pv310/include/mach/gpio.h b/arch/arm/mach-s5pv310/include/mach/gpio.h
deleted file mode 100644
index 20cb80c23466..000000000000
--- a/arch/arm/mach-s5pv310/include/mach/gpio.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/gpio.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * S5PV310 - GPIO lib support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H __FILE__
-
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep __gpio_cansleep
-#define gpio_to_irq __gpio_to_irq
-
-/* Practically, GPIO banks upto GPZ are the configurable gpio banks */
-
-/* GPIO bank sizes */
-#define S5PV310_GPIO_A0_NR (8)
-#define S5PV310_GPIO_A1_NR (6)
-#define S5PV310_GPIO_B_NR (8)
-#define S5PV310_GPIO_C0_NR (5)
-#define S5PV310_GPIO_C1_NR (5)
-#define S5PV310_GPIO_D0_NR (4)
-#define S5PV310_GPIO_D1_NR (4)
-#define S5PV310_GPIO_E0_NR (5)
-#define S5PV310_GPIO_E1_NR (8)
-#define S5PV310_GPIO_E2_NR (6)
-#define S5PV310_GPIO_E3_NR (8)
-#define S5PV310_GPIO_E4_NR (8)
-#define S5PV310_GPIO_F0_NR (8)
-#define S5PV310_GPIO_F1_NR (8)
-#define S5PV310_GPIO_F2_NR (8)
-#define S5PV310_GPIO_F3_NR (6)
-#define S5PV310_GPIO_J0_NR (8)
-#define S5PV310_GPIO_J1_NR (5)
-#define S5PV310_GPIO_K0_NR (7)
-#define S5PV310_GPIO_K1_NR (7)
-#define S5PV310_GPIO_K2_NR (7)
-#define S5PV310_GPIO_K3_NR (7)
-#define S5PV310_GPIO_L0_NR (8)
-#define S5PV310_GPIO_L1_NR (3)
-#define S5PV310_GPIO_L2_NR (8)
-#define S5PV310_GPIO_X0_NR (8)
-#define S5PV310_GPIO_X1_NR (8)
-#define S5PV310_GPIO_X2_NR (8)
-#define S5PV310_GPIO_X3_NR (8)
-#define S5PV310_GPIO_Z_NR (7)
-
-/* GPIO bank numbers */
-
-#define S5PV310_GPIO_NEXT(__gpio) \
- ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
-
-enum s5p_gpio_number {
- S5PV310_GPIO_A0_START = 0,
- S5PV310_GPIO_A1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_A0),
- S5PV310_GPIO_B_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_A1),
- S5PV310_GPIO_C0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_B),
- S5PV310_GPIO_C1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_C0),
- S5PV310_GPIO_D0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_C1),
- S5PV310_GPIO_D1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_D0),
- S5PV310_GPIO_E0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_D1),
- S5PV310_GPIO_E1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_E0),
- S5PV310_GPIO_E2_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_E1),
- S5PV310_GPIO_E3_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_E2),
- S5PV310_GPIO_E4_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_E3),
- S5PV310_GPIO_F0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_E4),
- S5PV310_GPIO_F1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_F0),
- S5PV310_GPIO_F2_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_F1),
- S5PV310_GPIO_F3_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_F2),
- S5PV310_GPIO_J0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_F3),
- S5PV310_GPIO_J1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_J0),
- S5PV310_GPIO_K0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_J1),
- S5PV310_GPIO_K1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_K0),
- S5PV310_GPIO_K2_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_K1),
- S5PV310_GPIO_K3_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_K2),
- S5PV310_GPIO_L0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_K3),
- S5PV310_GPIO_L1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_L0),
- S5PV310_GPIO_L2_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_L1),
- S5PV310_GPIO_X0_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_L2),
- S5PV310_GPIO_X1_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_X0),
- S5PV310_GPIO_X2_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_X1),
- S5PV310_GPIO_X3_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_X2),
- S5PV310_GPIO_Z_START = S5PV310_GPIO_NEXT(S5PV310_GPIO_X3),
-};
-
-/* S5PV310 GPIO number definitions */
-#define S5PV310_GPA0(_nr) (S5PV310_GPIO_A0_START + (_nr))
-#define S5PV310_GPA1(_nr) (S5PV310_GPIO_A1_START + (_nr))
-#define S5PV310_GPB(_nr) (S5PV310_GPIO_B_START + (_nr))
-#define S5PV310_GPC0(_nr) (S5PV310_GPIO_C0_START + (_nr))
-#define S5PV310_GPC1(_nr) (S5PV310_GPIO_C1_START + (_nr))
-#define S5PV310_GPD0(_nr) (S5PV310_GPIO_D0_START + (_nr))
-#define S5PV310_GPD1(_nr) (S5PV310_GPIO_D1_START + (_nr))
-#define S5PV310_GPE0(_nr) (S5PV310_GPIO_E0_START + (_nr))
-#define S5PV310_GPE1(_nr) (S5PV310_GPIO_E1_START + (_nr))
-#define S5PV310_GPE2(_nr) (S5PV310_GPIO_E2_START + (_nr))
-#define S5PV310_GPE3(_nr) (S5PV310_GPIO_E3_START + (_nr))
-#define S5PV310_GPE4(_nr) (S5PV310_GPIO_E4_START + (_nr))
-#define S5PV310_GPF0(_nr) (S5PV310_GPIO_F0_START + (_nr))
-#define S5PV310_GPF1(_nr) (S5PV310_GPIO_F1_START + (_nr))
-#define S5PV310_GPF2(_nr) (S5PV310_GPIO_F2_START + (_nr))
-#define S5PV310_GPF3(_nr) (S5PV310_GPIO_F3_START + (_nr))
-#define S5PV310_GPJ0(_nr) (S5PV310_GPIO_J0_START + (_nr))
-#define S5PV310_GPJ1(_nr) (S5PV310_GPIO_J1_START + (_nr))
-#define S5PV310_GPK0(_nr) (S5PV310_GPIO_K0_START + (_nr))
-#define S5PV310_GPK1(_nr) (S5PV310_GPIO_K1_START + (_nr))
-#define S5PV310_GPK2(_nr) (S5PV310_GPIO_K2_START + (_nr))
-#define S5PV310_GPK3(_nr) (S5PV310_GPIO_K3_START + (_nr))
-#define S5PV310_GPL0(_nr) (S5PV310_GPIO_L0_START + (_nr))
-#define S5PV310_GPL1(_nr) (S5PV310_GPIO_L1_START + (_nr))
-#define S5PV310_GPL2(_nr) (S5PV310_GPIO_L2_START + (_nr))
-#define S5PV310_GPX0(_nr) (S5PV310_GPIO_X0_START + (_nr))
-#define S5PV310_GPX1(_nr) (S5PV310_GPIO_X1_START + (_nr))
-#define S5PV310_GPX2(_nr) (S5PV310_GPIO_X2_START + (_nr))
-#define S5PV310_GPX3(_nr) (S5PV310_GPIO_X3_START + (_nr))
-#define S5PV310_GPZ(_nr) (S5PV310_GPIO_Z_START + (_nr))
-
-/* the end of the S5PV310 specific gpios */
-#define S5PV310_GPIO_END (S5PV310_GPZ(S5PV310_GPIO_Z_NR) + 1)
-#define S3C_GPIO_END S5PV310_GPIO_END
-
-/* define the number of gpios we need to the one after the GPZ() range */
-#define ARCH_NR_GPIOS (S5PV310_GPZ(S5PV310_GPIO_Z_NR) + \
- CONFIG_SAMSUNG_GPIO_EXTRA + 1)
-
-#include <asm-generic/gpio.h>
-
-#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h
deleted file mode 100644
index 901657fa7a12..000000000000
--- a/arch/arm/mach-s5pv310/include/mach/map.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/map.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * S5PV310 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MAP_H
-#define __ASM_ARCH_MAP_H __FILE__
-
-#include <plat/map-base.h>
-
-/*
- * S5PV310 UART offset is 0x10000 but the older S5P SoCs are 0x400.
- * So need to define it, and here is to avoid redefinition warning.
- */
-#define S3C_UART_OFFSET (0x10000)
-
-#include <plat/map-s5p.h>
-
-#define S5PV310_PA_SYSRAM 0x02025000
-
-#define S5PV310_PA_I2S0 0x03830000
-#define S5PV310_PA_I2S1 0xE3100000
-#define S5PV310_PA_I2S2 0xE2A00000
-
-#define S5PV310_PA_PCM0 0x03840000
-#define S5PV310_PA_PCM1 0x13980000
-#define S5PV310_PA_PCM2 0x13990000
-
-#define S5PV310_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000))
-
-#define S5PC210_PA_ONENAND 0x0C000000
-#define S5PC210_PA_ONENAND_DMA 0x0C600000
-
-#define S5PV310_PA_CHIPID 0x10000000
-
-#define S5PV310_PA_SYSCON 0x10010000
-#define S5PV310_PA_PMU 0x10020000
-#define S5PV310_PA_CMU 0x10030000
-
-#define S5PV310_PA_WATCHDOG 0x10060000
-#define S5PV310_PA_RTC 0x10070000
-
-#define S5PV310_PA_DMC0 0x10400000
-
-#define S5PV310_PA_COMBINER 0x10448000
-
-#define S5PV310_PA_COREPERI 0x10500000
-#define S5PV310_PA_GIC_CPU 0x10500100
-#define S5PV310_PA_TWD 0x10500600
-#define S5PV310_PA_GIC_DIST 0x10501000
-#define S5PV310_PA_L2CC 0x10502000
-
-#define S5PV310_PA_MDMA 0x10810000
-#define S5PV310_PA_PDMA0 0x12680000
-#define S5PV310_PA_PDMA1 0x12690000
-
-#define S5PV310_PA_SYSMMU_MDMA 0x10A40000
-#define S5PV310_PA_SYSMMU_SSS 0x10A50000
-#define S5PV310_PA_SYSMMU_FIMC0 0x11A20000
-#define S5PV310_PA_SYSMMU_FIMC1 0x11A30000
-#define S5PV310_PA_SYSMMU_FIMC2 0x11A40000
-#define S5PV310_PA_SYSMMU_FIMC3 0x11A50000
-#define S5PV310_PA_SYSMMU_JPEG 0x11A60000
-#define S5PV310_PA_SYSMMU_FIMD0 0x11E20000
-#define S5PV310_PA_SYSMMU_FIMD1 0x12220000
-#define S5PV310_PA_SYSMMU_PCIe 0x12620000
-#define S5PV310_PA_SYSMMU_G2D 0x12A20000
-#define S5PV310_PA_SYSMMU_ROTATOR 0x12A30000
-#define S5PV310_PA_SYSMMU_MDMA2 0x12A40000
-#define S5PV310_PA_SYSMMU_TV 0x12E20000
-#define S5PV310_PA_SYSMMU_MFC_L 0x13620000
-#define S5PV310_PA_SYSMMU_MFC_R 0x13630000
-
-#define S5PV310_PA_GPIO1 0x11400000
-#define S5PV310_PA_GPIO2 0x11000000
-#define S5PV310_PA_GPIO3 0x03860000
-
-#define S5PV310_PA_MIPI_CSIS0 0x11880000
-#define S5PV310_PA_MIPI_CSIS1 0x11890000
-
-#define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
-
-#define S5PV310_PA_SROMC 0x12570000
-
-#define S5PV310_PA_UART 0x13800000
-
-#define S5PV310_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
-
-#define S5PV310_PA_AC97 0x139A0000
-
-#define S5PV310_PA_TIMER 0x139D0000
-
-#define S5PV310_PA_SDRAM 0x40000000
-
-#define S5PV310_PA_SPDIF 0xE1100000
-
-/* Compatibiltiy Defines */
-
-#define S3C_PA_HSMMC0 S5PV310_PA_HSMMC(0)
-#define S3C_PA_HSMMC1 S5PV310_PA_HSMMC(1)
-#define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2)
-#define S3C_PA_HSMMC3 S5PV310_PA_HSMMC(3)
-#define S3C_PA_IIC S5PV310_PA_IIC(0)
-#define S3C_PA_IIC1 S5PV310_PA_IIC(1)
-#define S3C_PA_IIC2 S5PV310_PA_IIC(2)
-#define S3C_PA_IIC3 S5PV310_PA_IIC(3)
-#define S3C_PA_IIC4 S5PV310_PA_IIC(4)
-#define S3C_PA_IIC5 S5PV310_PA_IIC(5)
-#define S3C_PA_IIC6 S5PV310_PA_IIC(6)
-#define S3C_PA_IIC7 S5PV310_PA_IIC(7)
-#define S3C_PA_RTC S5PV310_PA_RTC
-#define S3C_PA_WDT S5PV310_PA_WATCHDOG
-
-#define S5P_PA_CHIPID S5PV310_PA_CHIPID
-#define S5P_PA_MIPI_CSIS0 S5PV310_PA_MIPI_CSIS0
-#define S5P_PA_MIPI_CSIS1 S5PV310_PA_MIPI_CSIS1
-#define S5P_PA_ONENAND S5PC210_PA_ONENAND
-#define S5P_PA_ONENAND_DMA S5PC210_PA_ONENAND_DMA
-#define S5P_PA_SDRAM S5PV310_PA_SDRAM
-#define S5P_PA_SROMC S5PV310_PA_SROMC
-#define S5P_PA_SYSCON S5PV310_PA_SYSCON
-#define S5P_PA_TIMER S5PV310_PA_TIMER
-
-/* UART */
-
-#define S3C_PA_UART S5PV310_PA_UART
-
-#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0 S5P_PA_UART(0)
-#define S5P_PA_UART1 S5P_PA_UART(1)
-#define S5P_PA_UART2 S5P_PA_UART(2)
-#define S5P_PA_UART3 S5P_PA_UART(3)
-#define S5P_PA_UART4 S5P_PA_UART(4)
-
-#define S5P_SZ_UART SZ_256
-
-#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-gpio.h b/arch/arm/mach-s5pv310/include/mach/regs-gpio.h
deleted file mode 100644
index 82e9e0c9d452..000000000000
--- a/arch/arm/mach-s5pv310/include/mach/regs-gpio.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-gpio.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * S5PV310 - GPIO (including EINT) register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_GPIO_H
-#define __ASM_ARCH_REGS_GPIO_H __FILE__
-
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-#define S5PV310_EINT40CON (S5P_VA_GPIO2 + 0xE00)
-#define S5P_EINT_CON(x) (S5PV310_EINT40CON + ((x) * 0x4))
-
-#define S5PV310_EINT40FLTCON0 (S5P_VA_GPIO2 + 0xE80)
-#define S5P_EINT_FLTCON(x) (S5PV310_EINT40FLTCON0 + ((x) * 0x4))
-
-#define S5PV310_EINT40MASK (S5P_VA_GPIO2 + 0xF00)
-#define S5P_EINT_MASK(x) (S5PV310_EINT40MASK + ((x) * 0x4))
-
-#define S5PV310_EINT40PEND (S5P_VA_GPIO2 + 0xF40)
-#define S5P_EINT_PEND(x) (S5PV310_EINT40PEND + ((x) * 0x4))
-
-#define EINT_REG_NR(x) (EINT_OFFSET(x) >> 3)
-
-#define eint_irq_to_bit(irq) (1 << (EINT_OFFSET(irq) & 0x7))
-
-#define EINT_MODE S3C_GPIO_SFN(0xf)
-
-#define EINT_GPIO_0(x) S5PV310_GPX0(x)
-#define EINT_GPIO_1(x) S5PV310_GPX1(x)
-#define EINT_GPIO_2(x) S5PV310_GPX2(x)
-#define EINT_GPIO_3(x) S5PV310_GPX3(x)
-
-#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-pmu.h b/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
deleted file mode 100644
index fb333d0f6073..000000000000
--- a/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * S5PV310 - Power management unit definition
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_PMU_H
-#define __ASM_ARCH_REGS_PMU_H __FILE__
-
-#include <mach/map.h>
-
-#define S5P_PMUREG(x) (S5P_VA_PMU + (x))
-
-#define S5P_PMU_CAM_CONF S5P_PMUREG(0x3C00)
-#define S5P_PMU_TV_CONF S5P_PMUREG(0x3C20)
-#define S5P_PMU_MFC_CONF S5P_PMUREG(0x3C40)
-#define S5P_PMU_G3D_CONF S5P_PMUREG(0x3C60)
-#define S5P_PMU_LCD0_CONF S5P_PMUREG(0x3C80)
-#define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0)
-#define S5P_PMU_GPS_CONF S5P_PMUREG(0x3CE0)
-
-#define S5P_INT_LOCAL_PWR_EN 0x7
-
-#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/sysmmu.h b/arch/arm/mach-s5pv310/include/mach/sysmmu.h
deleted file mode 100644
index 598fc5c9211b..000000000000
--- a/arch/arm/mach-s5pv310/include/mach/sysmmu.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/sysmmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * Samsung sysmmu driver for S5PV310
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARM_ARCH_SYSMMU_H
-#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
-
-#define S5PV310_SYSMMU_TOTAL_IPNUM 16
-#define S5P_SYSMMU_TOTAL_IPNUM S5PV310_SYSMMU_TOTAL_IPNUM
-
-enum s5pv310_sysmmu_ips {
- SYSMMU_MDMA,
- SYSMMU_SSS,
- SYSMMU_FIMC0,
- SYSMMU_FIMC1,
- SYSMMU_FIMC2,
- SYSMMU_FIMC3,
- SYSMMU_JPEG,
- SYSMMU_FIMD0,
- SYSMMU_FIMD1,
- SYSMMU_PCIe,
- SYSMMU_G2D,
- SYSMMU_ROTATOR,
- SYSMMU_MDMA2,
- SYSMMU_TV,
- SYSMMU_MFC_L,
- SYSMMU_MFC_R,
-};
-
-static char *sysmmu_ips_name[S5PV310_SYSMMU_TOTAL_IPNUM] = {
- "SYSMMU_MDMA" ,
- "SYSMMU_SSS" ,
- "SYSMMU_FIMC0" ,
- "SYSMMU_FIMC1" ,
- "SYSMMU_FIMC2" ,
- "SYSMMU_FIMC3" ,
- "SYSMMU_JPEG" ,
- "SYSMMU_FIMD0" ,
- "SYSMMU_FIMD1" ,
- "SYSMMU_PCIe" ,
- "SYSMMU_G2D" ,
- "SYSMMU_ROTATOR",
- "SYSMMU_MDMA2" ,
- "SYSMMU_TV" ,
- "SYSMMU_MFC_L" ,
- "SYSMMU_MFC_R" ,
-};
-
-typedef enum s5pv310_sysmmu_ips sysmmu_ips;
-
-struct sysmmu_tt_info {
- unsigned long *pgd;
- unsigned long pgd_paddr;
- unsigned long *pte;
-};
-
-struct sysmmu_controller {
- const char *name;
-
- /* channels registers */
- void __iomem *regs;
-
- /* channel irq */
- unsigned int irq;
-
- sysmmu_ips ips;
-
- /* Translation Table Info. */
- struct sysmmu_tt_info *tt_info;
-
- struct resource *mem;
- struct device *dev;
-
- /* SysMMU controller enable - true : enable */
- bool enable;
-};
-
-/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function enable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_enable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
- *
- * This function disable system mmu to transfer address
- * from virtual address to physical address
- */
-int s5p_sysmmu_disable(sysmmu_ips ips);
-
-/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical address,
- * system mmu refer address information from page table
- */
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
- *
- * This function flush all TLB entry in system mmu
- */
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
-#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/mach-universal_c210.c b/arch/arm/mach-s5pv310/mach-universal_c210.c
deleted file mode 100644
index 36bc3cf825e3..000000000000
--- a/arch/arm/mach-s5pv310/mach-universal_c210.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/mach-universal_c210.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/platform_device.h>
-#include <linux/serial_core.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/gpio_keys.h>
-#include <linux/gpio.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/mmc/host.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-#include <plat/s5pv310.h>
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/sdhci.h>
-
-#include <mach/map.h>
-
-/* Following are default values for UCON, ULCON and UFCON UART registers */
-#define UNIVERSAL_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
- S3C2410_UCON_RXILEVEL | \
- S3C2410_UCON_TXIRQMODE | \
- S3C2410_UCON_RXIRQMODE | \
- S3C2410_UCON_RXFIFO_TOI | \
- S3C2443_UCON_RXERR_IRQEN)
-
-#define UNIVERSAL_ULCON_DEFAULT S3C2410_LCON_CS8
-
-#define UNIVERSAL_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
- S5PV210_UFCON_TXTRIG256 | \
- S5PV210_UFCON_RXTRIG256)
-
-static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = {
- [0] = {
- .hwport = 0,
- .ucon = UNIVERSAL_UCON_DEFAULT,
- .ulcon = UNIVERSAL_ULCON_DEFAULT,
- .ufcon = UNIVERSAL_UFCON_DEFAULT,
- },
- [1] = {
- .hwport = 1,
- .ucon = UNIVERSAL_UCON_DEFAULT,
- .ulcon = UNIVERSAL_ULCON_DEFAULT,
- .ufcon = UNIVERSAL_UFCON_DEFAULT,
- },
- [2] = {
- .hwport = 2,
- .ucon = UNIVERSAL_UCON_DEFAULT,
- .ulcon = UNIVERSAL_ULCON_DEFAULT,
- .ufcon = UNIVERSAL_UFCON_DEFAULT,
- },
- [3] = {
- .hwport = 3,
- .ucon = UNIVERSAL_UCON_DEFAULT,
- .ulcon = UNIVERSAL_ULCON_DEFAULT,
- .ufcon = UNIVERSAL_UFCON_DEFAULT,
- },
-};
-
-static struct gpio_keys_button universal_gpio_keys_tables[] = {
- {
- .code = KEY_VOLUMEUP,
- .gpio = S5PV310_GPX2(0), /* XEINT16 */
- .desc = "gpio-keys: KEY_VOLUMEUP",
- .type = EV_KEY,
- .active_low = 1,
- .debounce_interval = 1,
- }, {
- .code = KEY_VOLUMEDOWN,
- .gpio = S5PV310_GPX2(1), /* XEINT17 */
- .desc = "gpio-keys: KEY_VOLUMEDOWN",
- .type = EV_KEY,
- .active_low = 1,
- .debounce_interval = 1,
- }, {
- .code = KEY_CONFIG,
- .gpio = S5PV310_GPX2(2), /* XEINT18 */
- .desc = "gpio-keys: KEY_CONFIG",
- .type = EV_KEY,
- .active_low = 1,
- .debounce_interval = 1,
- }, {
- .code = KEY_CAMERA,
- .gpio = S5PV310_GPX2(3), /* XEINT19 */
- .desc = "gpio-keys: KEY_CAMERA",
- .type = EV_KEY,
- .active_low = 1,
- .debounce_interval = 1,
- }, {
- .code = KEY_OK,
- .gpio = S5PV310_GPX3(5), /* XEINT29 */
- .desc = "gpio-keys: KEY_OK",
- .type = EV_KEY,
- .active_low = 1,
- .debounce_interval = 1,
- },
-};
-
-static struct gpio_keys_platform_data universal_gpio_keys_data = {
- .buttons = universal_gpio_keys_tables,
- .nbuttons = ARRAY_SIZE(universal_gpio_keys_tables),
-};
-
-static struct platform_device universal_gpio_keys = {
- .name = "gpio-keys",
- .dev = {
- .platform_data = &universal_gpio_keys_data,
- },
-};
-
-/* eMMC */
-static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
- .max_width = 8,
- .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
- MMC_CAP_DISABLE),
- .cd_type = S3C_SDHCI_CD_PERMANENT,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-};
-
-static struct regulator_consumer_supply mmc0_supplies[] = {
- REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
-};
-
-static struct regulator_init_data mmc0_fixed_voltage_init_data = {
- .constraints = {
- .name = "VMEM_VDD_2.8V",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(mmc0_supplies),
- .consumer_supplies = mmc0_supplies,
-};
-
-static struct fixed_voltage_config mmc0_fixed_voltage_config = {
- .supply_name = "MASSMEMORY_EN",
- .microvolts = 2800000,
- .gpio = S5PV310_GPE1(3),
- .enable_high = true,
- .init_data = &mmc0_fixed_voltage_init_data,
-};
-
-static struct platform_device mmc0_fixed_voltage = {
- .name = "reg-fixed-voltage",
- .id = 0,
- .dev = {
- .platform_data = &mmc0_fixed_voltage_config,
- },
-};
-
-/* SD */
-static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
- .max_width = 4,
- .host_caps = MMC_CAP_4_BIT_DATA |
- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
- MMC_CAP_DISABLE,
- .ext_cd_gpio = S5PV310_GPX3(4), /* XEINT_28 */
- .ext_cd_gpio_invert = 1,
- .cd_type = S3C_SDHCI_CD_GPIO,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
-};
-
-/* WiFi */
-static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = {
- .max_width = 4,
- .host_caps = MMC_CAP_4_BIT_DATA |
- MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
- MMC_CAP_DISABLE,
- .cd_type = S3C_SDHCI_CD_EXTERNAL,
-};
-
-static void __init universal_sdhci_init(void)
-{
- s3c_sdhci0_set_platdata(&universal_hsmmc0_data);
- s3c_sdhci2_set_platdata(&universal_hsmmc2_data);
- s3c_sdhci3_set_platdata(&universal_hsmmc3_data);
-}
-
-/* I2C0 */
-static struct i2c_board_info i2c0_devs[] __initdata = {
- /* Camera, To be updated */
-};
-
-/* I2C1 */
-static struct i2c_board_info i2c1_devs[] __initdata = {
- /* Gyro, To be updated */
-};
-
-static struct platform_device *universal_devices[] __initdata = {
- /* Samsung Platform Devices */
- &mmc0_fixed_voltage,
- &s3c_device_hsmmc0,
- &s3c_device_hsmmc2,
- &s3c_device_hsmmc3,
-
- /* Universal Devices */
- &universal_gpio_keys,
- &s5p_device_onenand,
-};
-
-static void __init universal_map_io(void)
-{
- s5p_init_io(NULL, 0, S5P_VA_CHIPID);
- s3c24xx_init_clocks(24000000);
- s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs));
-}
-
-static void __init universal_machine_init(void)
-{
- universal_sdhci_init();
-
- i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs));
- i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
-
- /* Last */
- platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices));
-}
-
-MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
- /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
- .boot_params = S5P_PA_SDRAM + 0x100,
- .init_irq = s5pv310_init_irq,
- .map_io = universal_map_io,
- .init_machine = universal_machine_init,
- .timer = &s5pv310_timer,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 4303a86e6e38..3e6f0aab460b 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -119,13 +119,6 @@ static struct platform_device keysc_device = {
};
/* FSI A */
-static struct sh_fsi_platform_info fsi_info = {
- .porta_flags = SH_FSI_OUT_SLAVE_MODE |
- SH_FSI_IN_SLAVE_MODE |
- SH_FSI_OFMT(I2S) |
- SH_FSI_IFMT(I2S),
-};
-
static struct resource fsi_resources[] = {
[0] = {
.name = "FSI",
@@ -144,9 +137,6 @@ static struct platform_device fsi_device = {
.id = -1,
.num_resources = ARRAY_SIZE(fsi_resources),
.resource = fsi_resources,
- .dev = {
- .platform_data = &fsi_info,
- },
};
static struct resource sh_mmcif_resources[] = {
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 81d6536552a9..1a8118c929be 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -673,16 +673,12 @@ static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
}
static struct sh_fsi_platform_info fsi_info = {
- .porta_flags = SH_FSI_BRS_INV |
- SH_FSI_OUT_SLAVE_MODE |
- SH_FSI_IN_SLAVE_MODE |
- SH_FSI_OFMT(PCM) |
- SH_FSI_IFMT(PCM),
+ .porta_flags = SH_FSI_BRS_INV,
.portb_flags = SH_FSI_BRS_INV |
SH_FSI_BRM_INV |
SH_FSI_LRS_INV |
- SH_FSI_OFMT(SPDIF),
+ SH_FSI_FMT_SPDIF,
.set_rate = fsi_set_rate,
};
@@ -783,6 +779,10 @@ static struct platform_device hdmi_device = {
},
};
+static struct platform_device fsi_hdmi_device = {
+ .name = "sh_fsi2_b_hdmi",
+};
+
static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
unsigned long *parent_freq)
{
@@ -936,6 +936,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
&usb1_host_device,
&fsi_device,
&fsi_ak4643_device,
+ &fsi_hdmi_device,
&sh_mmcif_device,
&lcdc1_device,
&lcdc_device,
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 1657eac5dde2..1a63c213e45d 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -399,6 +399,10 @@ static struct platform_device hdmi_device = {
},
};
+static struct platform_device fsi_hdmi_device = {
+ .name = "sh_fsi2_b_hdmi",
+};
+
static int __init hdmi_init_pm_clock(void)
{
struct clk *hdmi_ick = clk_get(&hdmi_device.dev, "ick");
@@ -609,16 +613,12 @@ fsi_set_rate_end:
}
static struct sh_fsi_platform_info fsi_info = {
- .porta_flags = SH_FSI_BRS_INV |
- SH_FSI_OUT_SLAVE_MODE |
- SH_FSI_IN_SLAVE_MODE |
- SH_FSI_OFMT(PCM) |
- SH_FSI_IFMT(PCM),
+ .porta_flags = SH_FSI_BRS_INV,
.portb_flags = SH_FSI_BRS_INV |
SH_FSI_BRM_INV |
SH_FSI_LRS_INV |
- SH_FSI_OFMT(SPDIF),
+ SH_FSI_FMT_SPDIF,
.set_rate = fsi_set_rate,
};
@@ -921,6 +921,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
&leds_device,
&fsi_device,
&fsi_ak4643_device,
+ &fsi_hdmi_device,
&sdhi0_device,
#if !defined(CONFIG_MMC_SH_MMCIF)
&sdhi1_device,
diff --git a/arch/arm/mach-tcc8k/board-tcc8000-sdk.c b/arch/arm/mach-tcc8k/board-tcc8000-sdk.c
index fb6426ddeb77..4cb3c2dd905c 100644
--- a/arch/arm/mach-tcc8k/board-tcc8000-sdk.c
+++ b/arch/arm/mach-tcc8k/board-tcc8000-sdk.c
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/delay.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
@@ -17,6 +18,8 @@
#include <asm/mach/time.h>
#include <mach/clock.h>
+#include <mach/tcc-nand.h>
+#include <mach/tcc8k-regs.h>
#include "common.h"
@@ -51,6 +54,22 @@ static struct sys_timer tcc8k_timer = {
static void __init tcc8k_map_io(void)
{
tcc8k_map_common_io();
+
+ /* set PLL0 clock to 96MHz, adapt UART0 divisor */
+ __raw_writel(0x00026003, CKC_BASE + PLL0CFG_OFFS);
+ __raw_writel(0x10000001, CKC_BASE + ACLKUART0_OFFS);
+
+ /* set PLL1 clock to 192MHz */
+ __raw_writel(0x00016003, CKC_BASE + PLL1CFG_OFFS);
+
+ /* set PLL2 clock to 48MHz */
+ __raw_writel(0x00036003, CKC_BASE + PLL2CFG_OFFS);
+
+ /* with CPU freq higher than 150 MHz, need extra DTCM wait */
+ __raw_writel(0x00000001, SCFG_BASE + DTCMWAIT_OFFS);
+
+ /* PLL locking time as specified */
+ udelay(300);
}
MACHINE_START(TCC8000_SDK, "Telechips TCC8000-SDK Demo Board")
diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c
index 3970a9cdce26..e7cdae5c77a4 100644
--- a/arch/arm/mach-tcc8k/clock.c
+++ b/arch/arm/mach-tcc8k/clock.c
@@ -45,11 +45,12 @@
#define ACLKGSB1 (CKC_BASE + ACLKGSB1_OFFS)
#define ACLKGSB2 (CKC_BASE + ACLKGSB2_OFFS)
#define ACLKGSB3 (CKC_BASE + ACLKGSB3_OFFS)
-#define ACLKUSBH (CKC_BASE + ACLKUSBH_OFFS)
#define ACLKTCT (CKC_BASE + ACLKTCT_OFFS)
#define ACLKTCX (CKC_BASE + ACLKTCX_OFFS)
#define ACLKTCZ (CKC_BASE + ACLKTCZ_OFFS)
+#define ACLK_MAX_DIV (0xfff + 1)
+
/* Crystal frequencies */
static unsigned long xi_rate, xti_rate;
@@ -106,9 +107,9 @@ static int root_clk_enable(enum root_clks src)
return 0;
}
-static int root_clk_disable(enum root_clks root_src)
+static int root_clk_disable(enum root_clks src)
{
- switch (root_src) {
+ switch (src) {
case CLK_SRC_PLL0: return pll_enable(0, 0);
case CLK_SRC_PLL1: return pll_enable(1, 0);
case CLK_SRC_PLL2: return pll_enable(2, 0);
@@ -197,7 +198,7 @@ static unsigned long get_rate_pll_div(int pll)
addr = CKC_BASE + CLKDIVC1_OFFS;
reg = __raw_readl(addr);
if (reg & CLKDIVC1_P2E)
- div = __raw_readl(addr) & 0x3f;
+ div = reg & 0x3f;
break;
}
return get_rate_pll(pll) / (div + 1);
@@ -258,14 +259,19 @@ static unsigned long aclk_best_div(struct clk *clk, unsigned long rate)
{
unsigned long div, src, freq, r1, r2;
+ if (!rate)
+ return ACLK_MAX_DIV;
+
src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
src &= CLK_SRC_MASK;
freq = root_clk_get_rate(src);
- div = freq / rate + 1;
+ div = freq / rate;
+ if (!div)
+ return 1;
+ if (div >= ACLK_MAX_DIV)
+ return ACLK_MAX_DIV;
r1 = freq / div;
r2 = freq / (div + 1);
- if (r2 >= rate)
- return div + 1;
if ((rate - r2) < (r1 - rate))
return div + 1;
@@ -287,7 +293,8 @@ static int aclk_set_rate(struct clk *clk, unsigned long rate)
u32 reg;
reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK;
- reg |= aclk_best_div(clk, rate);
+ reg |= aclk_best_div(clk, rate) - 1;
+ __raw_writel(reg, clk->aclkreg);
return 0;
}
@@ -296,15 +303,22 @@ static unsigned long get_rate_sys(struct clk *clk)
unsigned int src;
src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK;
- return root_clk_get_rate(src);
+ return root_clk_get_rate(src);
}
static unsigned long get_rate_bus(struct clk *clk)
{
- unsigned int div;
+ unsigned int reg, sdiv, bdiv, rate;
- div = (__raw_readl(CKC_BASE + CLKCTRL_OFFS) >> 4) & 0xff;
- return get_rate_sys(clk) / (div + 1);
+ reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS);
+ rate = get_rate_sys(clk);
+ sdiv = (reg >> 20) & 3;
+ if (sdiv)
+ rate /= sdiv + 1;
+ bdiv = (reg >> 4) & 0xff;
+ if (bdiv)
+ rate /= bdiv + 1;
+ return rate;
}
static unsigned long get_rate_cpu(struct clk *clk)
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index aa53ee22438f..513d6abec1f5 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -3,7 +3,7 @@
* arch/arm/mach-u300/core.c
*
*
- * Copyright (C) 2007-2010 ST-Ericsson AB
+ * Copyright (C) 2007-2010 ST-Ericsson SA
* License terms: GNU General Public License (GPL) version 2
* Core platform support, IRQ handling and device definitions.
* Author: Linus Walleij <linus.walleij@stericsson.com>
@@ -16,7 +16,9 @@
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/termios.h>
+#include <linux/dmaengine.h>
#include <linux/amba/bus.h>
+#include <linux/amba/serial.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/clk.h>
@@ -96,10 +98,20 @@ void __init u300_map_io(void)
* Declaration of devices found on the U300 board and
* their respective memory locations.
*/
+
+static struct amba_pl011_data uart0_plat_data = {
+#ifdef CONFIG_COH901318
+ .dma_filter = coh901318_filter_id,
+ .dma_rx_param = (void *) U300_DMA_UART0_RX,
+ .dma_tx_param = (void *) U300_DMA_UART0_TX,
+#endif
+};
+
static struct amba_device uart0_device = {
.dev = {
+ .coherent_dma_mask = ~0,
.init_name = "uart0", /* Slow device at 0x3000 offset */
- .platform_data = NULL,
+ .platform_data = &uart0_plat_data,
},
.res = {
.start = U300_UART0_BASE,
@@ -111,10 +123,19 @@ static struct amba_device uart0_device = {
/* The U335 have an additional UART1 on the APP CPU */
#ifdef CONFIG_MACH_U300_BS335
+static struct amba_pl011_data uart1_plat_data = {
+#ifdef CONFIG_COH901318
+ .dma_filter = coh901318_filter_id,
+ .dma_rx_param = (void *) U300_DMA_UART1_RX,
+ .dma_tx_param = (void *) U300_DMA_UART1_TX,
+#endif
+};
+
static struct amba_device uart1_device = {
.dev = {
+ .coherent_dma_mask = ~0,
.init_name = "uart1", /* Fast device at 0x7000 offset */
- .platform_data = NULL,
+ .platform_data = &uart1_plat_data,
},
.res = {
.start = U300_UART1_BASE,
@@ -960,42 +981,37 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
.priority_high = 0,
.dev_addr = U300_MSL_BASE + 6 * 0x40 + 0x220,
},
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
{
.number = U300_DMA_MMCSD_RX_TX,
.name = "MMCSD RX TX",
.priority_high = 0,
- .dev_addr = U300_MMCSD_BASE + 0x080,
.param.config = COH901318_CX_CFG_CH_DISABLE |
COH901318_CX_CFG_LCR_DISABLE |
COH901318_CX_CFG_TC_IRQ_ENABLE |
COH901318_CX_CFG_BE_IRQ_ENABLE,
.param.ctrl_lli_chained = 0 |
COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
COH901318_CX_CTRL_MASTER_MODE_M1RW |
COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
COH901318_CX_CTRL_HSP_ENABLE |
COH901318_CX_CTRL_HSS_DISABLE |
COH901318_CX_CTRL_DDMA_LEGACY,
.param.ctrl_lli = 0 |
COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
COH901318_CX_CTRL_MASTER_MODE_M1RW |
COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
COH901318_CX_CTRL_HSP_ENABLE |
COH901318_CX_CTRL_HSS_DISABLE |
COH901318_CX_CTRL_DDMA_LEGACY,
.param.ctrl_lli_last = 0 |
COH901318_CX_CTRL_TC_ENABLE |
- COH901318_CX_CTRL_BURST_COUNT_32_BYTES |
- COH901318_CX_CTRL_SRC_BUS_SIZE_32_BITS |
- COH901318_CX_CTRL_DST_BUS_SIZE_32_BITS |
COH901318_CX_CTRL_MASTER_MODE_M1RW |
COH901318_CX_CTRL_TCP_DISABLE |
COH901318_CX_CTRL_TC_IRQ_ENABLE |
@@ -1014,15 +1030,76 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
.name = "MSPRO RX",
.priority_high = 0,
},
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
{
.number = U300_DMA_UART0_TX,
.name = "UART0 TX",
.priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
},
{
.number = U300_DMA_UART0_RX,
.name = "UART0 RX",
.priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
},
{
.number = U300_DMA_APEX_TX,
@@ -1080,7 +1157,7 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
COH901318_CX_CTRL_DST_ADDR_INC_DISABLE |
COH901318_CX_CTRL_MASTER_MODE_M1RW |
COH901318_CX_CTRL_TCP_ENABLE |
- COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
COH901318_CX_CTRL_HSP_ENABLE |
COH901318_CX_CTRL_HSS_DISABLE |
COH901318_CX_CTRL_DDMA_LEGACY |
@@ -1252,15 +1329,77 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
.name = "XGAM PDI",
.priority_high = 0,
},
+ /*
+ * Don't set up device address, burst count or size of src
+ * or dst bus for this peripheral - handled by PrimeCell
+ * DMA extension.
+ */
{
.number = U300_DMA_SPI_TX,
.name = "SPI TX",
.priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
},
{
.number = U300_DMA_SPI_RX,
.name = "SPI RX",
.priority_high = 0,
+ .param.config = COH901318_CX_CFG_CH_DISABLE |
+ COH901318_CX_CFG_LCR_DISABLE |
+ COH901318_CX_CFG_TC_IRQ_ENABLE |
+ COH901318_CX_CFG_BE_IRQ_ENABLE,
+ .param.ctrl_lli_chained = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_DISABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+ .param.ctrl_lli_last = 0 |
+ COH901318_CX_CTRL_TC_ENABLE |
+ COH901318_CX_CTRL_MASTER_MODE_M1RW |
+ COH901318_CX_CTRL_TCP_DISABLE |
+ COH901318_CX_CTRL_TC_IRQ_ENABLE |
+ COH901318_CX_CTRL_HSP_ENABLE |
+ COH901318_CX_CTRL_HSS_DISABLE |
+ COH901318_CX_CTRL_DDMA_LEGACY,
+
},
{
.number = U300_DMA_GENERAL_PURPOSE_0,
@@ -1617,7 +1756,7 @@ static void __init u300_init_check_chip(void)
#endif
#ifdef CONFIG_MACH_U300_BS335
if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
- printk(KERN_ERR "Platform configured for BS365 " \
+ printk(KERN_ERR "Platform configured for BS335 " \
" with DB3350 but %s detected, expect problems!",
chipname);
}
@@ -1692,12 +1831,12 @@ void __init u300_init_devices(void)
/* Register subdevices on the I2C buses */
u300_i2c_register_board_devices();
- /* Register subdevices on the SPI bus */
- u300_spi_register_board_devices();
-
/* Register the platform devices */
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+ /* Register subdevices on the SPI bus */
+ u300_spi_register_board_devices();
+
#ifndef CONFIG_MACH_U300_SEMI_IS_SHARED
/*
* Enable SEMI self refresh. Self-refresh of the SDRAM is entered when
diff --git a/arch/arm/mach-u300/include/mach/coh901318.h b/arch/arm/mach-u300/include/mach/coh901318.h
index 6193aaa47794..7c3b2b2d25b6 100644
--- a/arch/arm/mach-u300/include/mach/coh901318.h
+++ b/arch/arm/mach-u300/include/mach/coh901318.h
@@ -102,6 +102,7 @@ struct coh901318_platform {
const int max_channels;
};
+#ifdef CONFIG_COH901318
/**
* coh901318_filter_id() - DMA channel filter function
* @chan: dma channel handle
@@ -110,6 +111,12 @@ struct coh901318_platform {
* In dma_request_channel() it specifies what channel id to be requested
*/
bool coh901318_filter_id(struct dma_chan *chan, void *chan_id);
+#else
+static inline bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
+{
+ return false;
+}
+#endif
/*
* DMA Controller - this access the static mappings of the coh901318 dma.
diff --git a/arch/arm/mach-u300/mmc.c b/arch/arm/mach-u300/mmc.c
index de1ac9ad2213..677ccef5cd32 100644
--- a/arch/arm/mach-u300/mmc.c
+++ b/arch/arm/mach-u300/mmc.c
@@ -3,159 +3,52 @@
* arch/arm/mach-u300/mmc.c
*
*
- * Copyright (C) 2009 ST-Ericsson AB
+ * Copyright (C) 2009 ST-Ericsson SA
* License terms: GNU General Public License (GPL) version 2
*
* Author: Linus Walleij <linus.walleij@stericsson.com>
- * Author: Johan Lundin <johan.lundin@stericsson.com>
+ * Author: Johan Lundin
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/mmc/host.h>
-#include <linux/input.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/regulator/consumer.h>
-#include <linux/regulator/machine.h>
#include <linux/gpio.h>
+#include <linux/dmaengine.h>
#include <linux/amba/mmci.h>
#include <linux/slab.h>
+#include <mach/coh901318.h>
+#include <mach/dma_channels.h>
#include "mmc.h"
#include "padmux.h"
-struct mmci_card_event {
- struct input_dev *mmc_input;
- int mmc_inserted;
- struct work_struct workq;
- struct mmci_platform_data mmc0_plat_data;
+static struct mmci_platform_data mmc0_plat_data = {
+ /*
+ * Do not set ocr_mask or voltage translation function,
+ * we have a regulator we can control instead.
+ */
+ /* Nominally 2.85V on our platform */
+ .f_max = 24000000,
+ .gpio_wp = -1,
+ .gpio_cd = U300_GPIO_PIN_MMC_CD,
+ .cd_invert = true,
+ .capabilities = MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+#ifdef CONFIG_COH901318
+ .dma_filter = coh901318_filter_id,
+ .dma_rx_param = (void *) U300_DMA_MMCSD_RX_TX,
+ /* Don't specify a TX channel, this RX channel is bidirectional */
+#endif
};
-static unsigned int mmc_status(struct device *dev)
-{
- struct mmci_card_event *mmci_card = container_of(
- dev->platform_data,
- struct mmci_card_event, mmc0_plat_data);
-
- return mmci_card->mmc_inserted;
-}
-
-static int mmci_callback(void *data)
-{
- struct mmci_card_event *mmci_card = data;
-
- disable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD);
- schedule_work(&mmci_card->workq);
-
- return 0;
-}
-
-
-static ssize_t gpio_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmci_card_event *mmci_card = container_of(
- dev->platform_data,
- struct mmci_card_event, mmc0_plat_data);
-
-
- return sprintf(buf, "%d\n", !mmci_card->mmc_inserted);
-}
-
-static DEVICE_ATTR(mmc_inserted, S_IRUGO, gpio_show, NULL);
-
-static void _mmci_callback(struct work_struct *ws)
-{
-
- struct mmci_card_event *mmci_card = container_of(
- ws,
- struct mmci_card_event, workq);
-
- mdelay(20);
-
- mmci_card->mmc_inserted = !gpio_get_value(U300_GPIO_PIN_MMC_CD);
-
- input_report_switch(mmci_card->mmc_input, KEY_INSERT,
- mmci_card->mmc_inserted);
- input_sync(mmci_card->mmc_input);
-
- pr_debug("MMC/SD card was %s\n",
- mmci_card->mmc_inserted ? "inserted" : "removed");
-
- enable_irq_on_gpio_pin(U300_GPIO_PIN_MMC_CD, mmci_card->mmc_inserted);
-}
-
int __devinit mmc_init(struct amba_device *adev)
{
- struct mmci_card_event *mmci_card;
struct device *mmcsd_device = &adev->dev;
struct pmx *pmx;
int ret = 0;
- mmci_card = kzalloc(sizeof(struct mmci_card_event), GFP_KERNEL);
- if (!mmci_card)
- return -ENOMEM;
-
- /*
- * Do not set ocr_mask or voltage translation function,
- * we have a regulator we can control instead.
- */
- /* Nominally 2.85V on our platform */
- mmci_card->mmc0_plat_data.f_max = 24000000;
- mmci_card->mmc0_plat_data.status = mmc_status;
- mmci_card->mmc0_plat_data.gpio_wp = -1;
- mmci_card->mmc0_plat_data.gpio_cd = -1;
- mmci_card->mmc0_plat_data.capabilities = MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
-
- mmcsd_device->platform_data = (void *) &mmci_card->mmc0_plat_data;
-
- INIT_WORK(&mmci_card->workq, _mmci_callback);
-
- ret = gpio_request(U300_GPIO_PIN_MMC_CD, "MMC card detection");
- if (ret) {
- printk(KERN_CRIT "Could not allocate MMC card detection " \
- "GPIO pin\n");
- goto out;
- }
-
- ret = gpio_direction_input(U300_GPIO_PIN_MMC_CD);
- if (ret) {
- printk(KERN_CRIT "Invalid GPIO pin requested\n");
- goto out;
- }
-
- ret = sysfs_create_file(&mmcsd_device->kobj,
- &dev_attr_mmc_inserted.attr);
- if (ret)
- goto out;
-
- mmci_card->mmc_input = input_allocate_device();
- if (!mmci_card->mmc_input) {
- printk(KERN_CRIT "Could not allocate MMC input device\n");
- return -ENOMEM;
- }
-
- mmci_card->mmc_input->name = "MMC insert notification";
- mmci_card->mmc_input->id.bustype = BUS_HOST;
- mmci_card->mmc_input->id.vendor = 0;
- mmci_card->mmc_input->id.product = 0;
- mmci_card->mmc_input->id.version = 0x0100;
- mmci_card->mmc_input->dev.parent = mmcsd_device;
- input_set_capability(mmci_card->mmc_input, EV_SW, KEY_INSERT);
-
- /*
- * Since this must always be compiled into the kernel, this input
- * is never unregistered or free:ed.
- */
- ret = input_register_device(mmci_card->mmc_input);
- if (ret) {
- input_free_device(mmci_card->mmc_input);
- goto out;
- }
-
- input_set_drvdata(mmci_card->mmc_input, mmci_card);
+ mmcsd_device->platform_data = &mmc0_plat_data;
/*
* Setup padmuxing for MMC. Since this must always be
@@ -171,12 +64,5 @@ int __devinit mmc_init(struct amba_device *adev)
pr_warning("Could not activate padmuxing\n");
}
- ret = gpio_register_callback(U300_GPIO_PIN_MMC_CD, mmci_callback,
- mmci_card);
-
- schedule_work(&mmci_card->workq);
-
- printk(KERN_INFO "Registered MMC insert/remove notification\n");
-out:
return ret;
}
diff --git a/arch/arm/mach-u300/spi.c b/arch/arm/mach-u300/spi.c
index 00869def5420..5767208f1c1d 100644
--- a/arch/arm/mach-u300/spi.c
+++ b/arch/arm/mach-u300/spi.c
@@ -11,6 +11,9 @@
#include <linux/spi/spi.h>
#include <linux/amba/pl022.h>
#include <linux/err.h>
+#include <mach/coh901318.h>
+#include <mach/dma_channels.h>
+
#include "padmux.h"
/*
@@ -30,11 +33,8 @@ static void select_dummy_chip(u32 chipselect)
}
struct pl022_config_chip dummy_chip_info = {
- /*
- * available POLLING_TRANSFER and INTERRUPT_TRANSFER,
- * DMA_TRANSFER does not work
- */
- .com_mode = INTERRUPT_TRANSFER,
+ /* available POLLING_TRANSFER, INTERRUPT_TRANSFER, DMA_TRANSFER */
+ .com_mode = DMA_TRANSFER,
.iface = SSP_INTERFACE_MOTOROLA_SPI,
/* We can only act as master but SSP_SLAVE is possible in theory */
.hierarchy = SSP_MASTER,
@@ -75,8 +75,6 @@ static struct spi_board_info u300_spi_devices[] = {
static struct pl022_ssp_controller ssp_platform_data = {
/* If you have several SPI buses this varies, we have only bus 0 */
.bus_id = 0,
- /* Set this to 1 when we think we got DMA working */
- .enable_dma = 0,
/*
* On the APP CPU GPIO 4, 5 and 6 are connected as generic
* chip selects for SPI. (Same on U330, U335 and U365.)
@@ -84,6 +82,14 @@ static struct pl022_ssp_controller ssp_platform_data = {
* and do padmuxing accordingly too.
*/
.num_chipselect = 3,
+#ifdef CONFIG_COH901318
+ .enable_dma = 1,
+ .dma_filter = coh901318_filter_id,
+ .dma_rx_param = (void *) U300_DMA_SPI_RX,
+ .dma_tx_param = (void *) U300_DMA_SPI_TX,
+#else
+ .enable_dma = 0,
+#endif
};
@@ -109,6 +115,7 @@ void __init u300_spi_init(struct amba_device *adev)
}
}
+
void __init u300_spi_register_board_devices(void)
{
/* Register any SPI devices */
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 53ebb429e971..b549a8fb4231 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -3,16 +3,18 @@
#
obj-y := clock.o cpu.o devices.o devices-common.o \
- id.o
+ id.o usb.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \
- board-mop500-keypads.o
+ board-mop500-regulators.o \
+ board-mop500-uib.o board-mop500-stuib.o \
+ board-mop500-u8500uib.o \
+ board-mop500-pins.o
obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
diff --git a/arch/arm/mach-ux500/board-mop500-keypads.c b/arch/arm/mach-ux500/board-mop500-keypads.c
deleted file mode 100644
index 70318c354d32..000000000000
--- a/arch/arm/mach-ux500/board-mop500-keypads.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Keypad layouts for various boards
- */
-
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/stmpe.h>
-#include <linux/mfd/tc3589x.h>
-#include <linux/input/matrix_keypad.h>
-
-#include <plat/pincfg.h>
-#include <plat/ske.h>
-
-#include <mach/devices.h>
-#include <mach/hardware.h>
-
-#include "devices-db8500.h"
-#include "board-mop500.h"
-
-/* STMPE/SKE keypad use this key layout */
-static const unsigned int mop500_keymap[] = {
- KEY(2, 5, KEY_END),
- KEY(4, 1, KEY_POWER),
- KEY(3, 5, KEY_VOLUMEDOWN),
- KEY(1, 3, KEY_3),
- KEY(5, 2, KEY_RIGHT),
- KEY(5, 0, KEY_9),
-
- KEY(0, 5, KEY_MENU),
- KEY(7, 6, KEY_ENTER),
- KEY(4, 5, KEY_0),
- KEY(6, 7, KEY_2),
- KEY(3, 4, KEY_UP),
- KEY(3, 3, KEY_DOWN),
-
- KEY(6, 4, KEY_SEND),
- KEY(6, 2, KEY_BACK),
- KEY(4, 2, KEY_VOLUMEUP),
- KEY(5, 5, KEY_1),
- KEY(4, 3, KEY_LEFT),
- KEY(3, 2, KEY_7),
-};
-
-static const struct matrix_keymap_data mop500_keymap_data = {
- .keymap = mop500_keymap,
- .keymap_size = ARRAY_SIZE(mop500_keymap),
-};
-
-/*
- * Nomadik SKE keypad
- */
-#define ROW_PIN_I0 164
-#define ROW_PIN_I1 163
-#define ROW_PIN_I2 162
-#define ROW_PIN_I3 161
-#define ROW_PIN_I4 156
-#define ROW_PIN_I5 155
-#define ROW_PIN_I6 154
-#define ROW_PIN_I7 153
-#define COL_PIN_O0 168
-#define COL_PIN_O1 167
-#define COL_PIN_O2 166
-#define COL_PIN_O3 165
-#define COL_PIN_O4 160
-#define COL_PIN_O5 159
-#define COL_PIN_O6 158
-#define COL_PIN_O7 157
-
-#define SKE_KPD_MAX_ROWS 8
-#define SKE_KPD_MAX_COLS 8
-
-static int ske_kp_rows[] = {
- ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
- ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
-};
-
-/*
- * ske_set_gpio_row: request and set gpio rows
- */
-static int ske_set_gpio_row(int gpio)
-{
- int ret;
-
- ret = gpio_request(gpio, "ske-kp");
- if (ret < 0) {
- pr_err("ske_set_gpio_row: gpio request failed\n");
- return ret;
- }
-
- ret = gpio_direction_output(gpio, 1);
- if (ret < 0) {
- pr_err("ske_set_gpio_row: gpio direction failed\n");
- gpio_free(gpio);
- }
-
- return ret;
-}
-
-/*
- * ske_kp_init - enable the gpio configuration
- */
-static int ske_kp_init(void)
-{
- int ret, i;
-
- for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
- ret = ske_set_gpio_row(ske_kp_rows[i]);
- if (ret < 0) {
- pr_err("ske_kp_init: failed init\n");
- return ret;
- }
- }
-
- return 0;
-}
-
-static struct ske_keypad_platform_data ske_keypad_board = {
- .init = ske_kp_init,
- .keymap_data = &mop500_keymap_data,
- .no_autorepeat = true,
- .krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
- .kcol = SKE_KPD_MAX_COLS,
- .debounce_ms = 40, /* in millisecs */
-};
-
-/*
- * STMPE1601
- */
-static struct stmpe_keypad_platform_data stmpe1601_keypad_data = {
- .debounce_ms = 64,
- .scan_count = 8,
- .no_autorepeat = true,
- .keymap_data = &mop500_keymap_data,
-};
-
-static struct stmpe_platform_data stmpe1601_data = {
- .id = 1,
- .blocks = STMPE_BLOCK_KEYPAD,
- .irq_trigger = IRQF_TRIGGER_FALLING,
- .irq_base = MOP500_STMPE1601_IRQ(0),
- .keypad = &stmpe1601_keypad_data,
- .autosleep = true,
- .autosleep_timeout = 1024,
-};
-
-static struct i2c_board_info mop500_i2c0_devices_stuib[] = {
- {
- I2C_BOARD_INFO("stmpe1601", 0x40),
- .irq = NOMADIK_GPIO_TO_IRQ(218),
- .platform_data = &stmpe1601_data,
- .flags = I2C_CLIENT_WAKE,
- },
-};
-
-/*
- * TC35893
- */
-
-static const unsigned int uib_keymap[] = {
- KEY(3, 1, KEY_END),
- KEY(4, 1, KEY_POWER),
- KEY(6, 4, KEY_VOLUMEDOWN),
- KEY(4, 2, KEY_EMAIL),
- KEY(3, 3, KEY_RIGHT),
- KEY(2, 5, KEY_BACKSPACE),
-
- KEY(6, 7, KEY_MENU),
- KEY(5, 0, KEY_ENTER),
- KEY(4, 3, KEY_0),
- KEY(3, 4, KEY_DOT),
- KEY(5, 2, KEY_UP),
- KEY(3, 5, KEY_DOWN),
-
- KEY(4, 5, KEY_SEND),
- KEY(0, 5, KEY_BACK),
- KEY(6, 2, KEY_VOLUMEUP),
- KEY(1, 3, KEY_SPACE),
- KEY(7, 6, KEY_LEFT),
- KEY(5, 5, KEY_SEARCH),
-};
-
-static struct matrix_keymap_data uib_keymap_data = {
- .keymap = uib_keymap,
- .keymap_size = ARRAY_SIZE(uib_keymap),
-};
-
-static struct tc3589x_keypad_platform_data tc35893_data = {
- .krow = TC_KPD_ROWS,
- .kcol = TC_KPD_COLUMNS,
- .debounce_period = TC_KPD_DEBOUNCE_PERIOD,
- .settle_time = TC_KPD_SETTLE_TIME,
- .irqtype = IRQF_TRIGGER_FALLING,
- .enable_wakeup = true,
- .keymap_data = &uib_keymap_data,
- .no_autorepeat = true,
-};
-
-static struct tc3589x_platform_data tc3589x_keypad_data = {
- .block = TC3589x_BLOCK_KEYPAD,
- .keypad = &tc35893_data,
- .irq_base = MOP500_EGPIO_IRQ_BASE,
-};
-
-static struct i2c_board_info mop500_i2c0_devices_uib[] = {
- {
- I2C_BOARD_INFO("tc3589x", 0x44),
- .platform_data = &tc3589x_keypad_data,
- .irq = NOMADIK_GPIO_TO_IRQ(218),
- .flags = I2C_CLIENT_WAKE,
- },
-};
-
-void mop500_keypad_init(void)
-{
- db8500_add_ske_keypad(&ske_keypad_board);
-
- i2c_register_board_info(0, mop500_i2c0_devices_stuib,
- ARRAY_SIZE(mop500_i2c0_devices_stuib));
-
- i2c_register_board_info(0, mop500_i2c0_devices_uib,
- ARRAY_SIZE(mop500_i2c0_devices_uib));
-
-}
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
new file mode 100644
index 000000000000..fd4cf1ca5efd
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <plat/pincfg.h>
+#include <mach/hardware.h>
+
+#include "pins-db8500.h"
+
+static pin_cfg_t mop500_pins_common[] = {
+ /* I2C */
+ GPIO147_I2C0_SCL,
+ GPIO148_I2C0_SDA,
+ GPIO16_I2C1_SCL,
+ GPIO17_I2C1_SDA,
+ GPIO10_I2C2_SDA,
+ GPIO11_I2C2_SCL,
+ GPIO229_I2C3_SDA,
+ GPIO230_I2C3_SCL,
+
+ /* MSP0 */
+ GPIO12_MSP0_TXD,
+ GPIO13_MSP0_TFS,
+ GPIO14_MSP0_TCK,
+ GPIO15_MSP0_RXD,
+
+ /* MSP2: HDMI */
+ GPIO193_MSP2_TXD,
+ GPIO194_MSP2_TCK,
+ GPIO195_MSP2_TFS,
+ GPIO196_MSP2_RXD | PIN_OUTPUT_LOW,
+
+ /* Touch screen INTERFACE */
+ GPIO84_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT1 */
+
+ /* STMPE1601/tc35893 keypad IRQ */
+ GPIO218_GPIO | PIN_INPUT_PULLUP,
+
+ /* MMC0 (MicroSD card) */
+ GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH,
+ GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH,
+ GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH,
+
+ GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL,
+ GPIO23_MC0_CLK | PIN_OUTPUT_LOW,
+ GPIO24_MC0_CMD | PIN_INPUT_PULLUP,
+ GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP,
+ GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP,
+ GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP,
+ GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP,
+
+ /* SDI1 (SDIO) */
+ GPIO208_MC1_CLK | PIN_OUTPUT_LOW,
+ GPIO209_MC1_FBCLK | PIN_INPUT_NOPULL,
+ GPIO210_MC1_CMD | PIN_INPUT_PULLUP,
+ GPIO211_MC1_DAT0 | PIN_INPUT_PULLUP,
+ GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP,
+ GPIO213_MC1_DAT2 | PIN_INPUT_PULLUP,
+ GPIO214_MC1_DAT3 | PIN_INPUT_PULLUP,
+
+ /* MMC2 (On-board DATA INTERFACE eMMC) */
+ GPIO128_MC2_CLK | PIN_OUTPUT_LOW,
+ GPIO129_MC2_CMD | PIN_INPUT_PULLUP,
+ GPIO130_MC2_FBCLK | PIN_INPUT_NOPULL,
+ GPIO131_MC2_DAT0 | PIN_INPUT_PULLUP,
+ GPIO132_MC2_DAT1 | PIN_INPUT_PULLUP,
+ GPIO133_MC2_DAT2 | PIN_INPUT_PULLUP,
+ GPIO134_MC2_DAT3 | PIN_INPUT_PULLUP,
+ GPIO135_MC2_DAT4 | PIN_INPUT_PULLUP,
+ GPIO136_MC2_DAT5 | PIN_INPUT_PULLUP,
+ GPIO137_MC2_DAT6 | PIN_INPUT_PULLUP,
+ GPIO138_MC2_DAT7 | PIN_INPUT_PULLUP,
+
+ /* MMC4 (On-board STORAGE INTERFACE eMMC) */
+ GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP,
+ GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP,
+ GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP,
+ GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP,
+ GPIO201_MC4_CMD | PIN_INPUT_PULLUP,
+ GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL,
+ GPIO203_MC4_CLK | PIN_OUTPUT_LOW,
+ GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP,
+ GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP,
+ GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP,
+ GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP,
+
+ /* SKE keypad */
+ GPIO153_KP_I7,
+ GPIO154_KP_I6,
+ GPIO155_KP_I5,
+ GPIO156_KP_I4,
+ GPIO157_KP_O7,
+ GPIO158_KP_O6,
+ GPIO159_KP_O5,
+ GPIO160_KP_O4,
+ GPIO161_KP_I3,
+ GPIO162_KP_I2,
+ GPIO163_KP_I1,
+ GPIO164_KP_I0,
+ GPIO165_KP_O3,
+ GPIO166_KP_O2,
+ GPIO167_KP_O1,
+ GPIO168_KP_O0,
+
+ /* UART */
+ GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
+ GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
+ GPIO2_U0_RXD | PIN_INPUT_PULLUP,
+ GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+
+ GPIO29_U2_RXD | PIN_INPUT_PULLUP,
+ GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
+ GPIO31_U2_CTSn | PIN_INPUT_PULLUP,
+ GPIO32_U2_RTSn | PIN_OUTPUT_HIGH,
+
+ /* Display & HDMI HW sync */
+ GPIO68_LCD_VSI0 | PIN_INPUT_PULLUP,
+ GPIO69_LCD_VSI1 | PIN_INPUT_PULLUP,
+};
+
+static pin_cfg_t mop500_pins_default[] = {
+ /* SSP0 */
+ GPIO143_SSP0_CLK,
+ GPIO144_SSP0_FRM,
+ GPIO145_SSP0_RXD | PIN_PULL_DOWN,
+ GPIO146_SSP0_TXD,
+
+
+ GPIO217_GPIO | PIN_INPUT_PULLUP, /* TC35892 IRQ */
+
+ /* SDI0 (MicroSD card) */
+ GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH,
+
+ /* UART */
+ GPIO4_U1_RXD | PIN_INPUT_PULLUP,
+ GPIO5_U1_TXD | PIN_OUTPUT_HIGH,
+ GPIO6_U1_CTSn | PIN_INPUT_PULLUP,
+ GPIO7_U1_RTSn | PIN_OUTPUT_HIGH,
+};
+
+static pin_cfg_t mop500_pins_hrefv60[] = {
+ /* WLAN */
+ GPIO4_GPIO | PIN_INPUT_PULLUP,/* WLAN_IRQ */
+ GPIO85_GPIO | PIN_OUTPUT_LOW,/* WLAN_ENA */
+
+ /* XENON Flashgun INTERFACE */
+ GPIO6_IP_GPIO0 | PIN_INPUT_PULLUP,/* XENON_FLASH_ID */
+ GPIO7_IP_GPIO1 | PIN_INPUT_PULLUP,/* XENON_READY */
+ GPIO170_GPIO | PIN_OUTPUT_LOW, /* XENON_CHARGE */
+
+ /* Assistant LED INTERFACE */
+ GPIO21_GPIO | PIN_OUTPUT_LOW, /* XENON_EN1 */
+ GPIO64_IP_GPIO4 | PIN_OUTPUT_LOW, /* XENON_EN2 */
+
+ /* Magnetometer */
+ GPIO31_GPIO | PIN_INPUT_PULLUP, /* magnetometer_INT */
+ GPIO32_GPIO | PIN_INPUT_PULLDOWN, /* Magnetometer DRDY */
+
+ /* Display Interface */
+ GPIO65_GPIO | PIN_OUTPUT_LOW, /* DISP1 RST */
+ GPIO66_GPIO | PIN_OUTPUT_LOW, /* DISP2 RST */
+
+ /* Touch screen INTERFACE */
+ GPIO143_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST1 */
+
+ /* Touch screen INTERFACE 2 */
+ GPIO67_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT2 */
+ GPIO146_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST2 */
+
+ /* ETM_PTM_TRACE INTERFACE */
+ GPIO70_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA23 */
+ GPIO71_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA22 */
+ GPIO72_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA21 */
+ GPIO73_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA20 */
+ GPIO74_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA19 */
+
+ /* NAHJ INTERFACE */
+ GPIO76_GPIO | PIN_OUTPUT_LOW,/* NAHJ_CTRL */
+ GPIO216_GPIO | PIN_OUTPUT_HIGH,/* NAHJ_CTRL_INV */
+
+ /* NFC INTERFACE */
+ GPIO77_GPIO | PIN_OUTPUT_LOW, /* NFC_ENA */
+ GPIO144_GPIO | PIN_INPUT_PULLDOWN, /* NFC_IRQ */
+ GPIO142_GPIO | PIN_OUTPUT_LOW, /* NFC_RESET */
+
+ /* Keyboard MATRIX INTERFACE */
+ GPIO90_MC5_CMD | PIN_OUTPUT_LOW, /* KP_O_1 */
+ GPIO87_MC5_DAT1 | PIN_OUTPUT_LOW, /* KP_O_2 */
+ GPIO86_MC5_DAT0 | PIN_OUTPUT_LOW, /* KP_O_3 */
+ GPIO96_KP_O6 | PIN_OUTPUT_LOW, /* KP_O_6 */
+ GPIO94_KP_O7 | PIN_OUTPUT_LOW, /* KP_O_7 */
+ GPIO93_MC5_DAT4 | PIN_INPUT_PULLUP, /* KP_I_0 */
+ GPIO89_MC5_DAT3 | PIN_INPUT_PULLUP, /* KP_I_2 */
+ GPIO88_MC5_DAT2 | PIN_INPUT_PULLUP, /* KP_I_3 */
+ GPIO91_GPIO | PIN_INPUT_PULLUP, /* FORCE_SENSING_INT */
+ GPIO92_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_RST */
+ GPIO97_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_WU */
+
+ /* DiPro Sensor Interface */
+ GPIO139_GPIO | PIN_INPUT_PULLUP, /* DIPRO_INT */
+
+ /* HAL SWITCH INTERFACE */
+ GPIO145_GPIO | PIN_INPUT_PULLDOWN,/* HAL_SW */
+
+ /* Audio Amplifier Interface */
+ GPIO149_GPIO | PIN_OUTPUT_LOW, /* VAUDIO_HF_EN */
+
+ /* GBF INTERFACE */
+ GPIO171_GPIO | PIN_OUTPUT_LOW, /* GBF_ENA_RESET */
+
+ /* MSP : HDTV INTERFACE */
+ GPIO192_GPIO | PIN_INPUT_PULLDOWN,
+
+ /* ACCELEROMETER_INTERFACE */
+ GPIO82_GPIO | PIN_INPUT_PULLUP, /* ACC_INT1 */
+ GPIO83_GPIO | PIN_INPUT_PULLUP, /* ACC_INT2 */
+
+ /* Proximity Sensor */
+ GPIO217_GPIO | PIN_INPUT_PULLUP,
+
+
+};
+
+void __init mop500_pins_init(void)
+{
+ nmk_config_pins(mop500_pins_common,
+ ARRAY_SIZE(mop500_pins_common));
+ if (machine_is_hrefv60())
+ nmk_config_pins(mop500_pins_hrefv60,
+ ARRAY_SIZE(mop500_pins_hrefv60));
+ else
+ nmk_config_pins(mop500_pins_default,
+ ARRAY_SIZE(mop500_pins_default));
+}
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
index 533967c2d095..875c91b2f8a4 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.c
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -11,6 +11,56 @@
#include <linux/kernel.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
+#include "board-mop500-regulators.h"
+
+static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
+ /* External displays, connector on board 2v5 power supply */
+ REGULATOR_SUPPLY("vaux12v5", "mcde.0"),
+ /* SFH7741 proximity sensor */
+ REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
+ /* BH1780GLS ambient light sensor */
+ REGULATOR_SUPPLY("vcc", "2-0029"),
+ /* lsm303dlh accelerometer */
+ REGULATOR_SUPPLY("vdd", "3-0018"),
+ /* lsm303dlh magnetometer */
+ REGULATOR_SUPPLY("vdd", "3-001e"),
+ /* Rohm BU21013 Touchscreen devices */
+ REGULATOR_SUPPLY("avdd", "3-005c"),
+ REGULATOR_SUPPLY("avdd", "3-005d"),
+ /* Synaptics RMI4 Touchscreen device */
+ REGULATOR_SUPPLY("vdd", "3-004b"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
+ /* On-board eMMC power */
+ REGULATOR_SUPPLY("vmmc", "sdi4"),
+ /* AB8500 audio codec */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ /* External MMC slot power */
+ REGULATOR_SUPPLY("vmmc", "sdi0"),
+};
+
+static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
+ /* TV-out DENC supply */
+ REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
+ /* Internal general-purpose ADC */
+ REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
+ /* SoC core supply, no device */
+ REGULATOR_SUPPLY("v-intcore", NULL),
+ /* USB Transciever */
+ REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vana_consumers[] = {
+ /* External displays, connector on board, 1v8 power supply */
+ REGULATOR_SUPPLY("vsmps2", "mcde.0"),
+};
/* AB8500 regulators */
struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
@@ -23,6 +73,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
},
/* supplies to the on-board eMMC */
[AB8500_LDO_AUX2] = {
@@ -33,6 +85,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
},
/* supply for VAUX3, supplies to SDcard slots */
[AB8500_LDO_AUX3] = {
@@ -43,6 +97,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
},
/* supply for tvout, gpadc, TVOUT LDO */
[AB8500_LDO_TVOUT] = {
@@ -50,6 +106,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.name = "V-TVOUT",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
+ .consumer_supplies = ab8500_vtvout_consumers,
},
/* supply for ab8500-vaudio, VAUDIO LDO */
[AB8500_LDO_AUDIO] = {
@@ -85,6 +143,8 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.name = "V-INTCORE",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
},
/* supply for U8500 CSI/DSI, VANA LDO */
[AB8500_LDO_ANA] = {
@@ -92,5 +152,7 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.name = "V-CSI/DSI",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
},
};
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
index 4b996676594e..bf0b02414e5b 100644
--- a/arch/arm/mach-ux500/board-mop500-sdi.c
+++ b/arch/arm/mach-ux500/board-mop500-sdi.c
@@ -12,56 +12,14 @@
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
-#include <plat/pincfg.h>
+#include <asm/mach-types.h>
+#include <plat/ste_dma40.h>
#include <mach/devices.h>
#include <mach/hardware.h>
#include "devices-db8500.h"
-#include "pins-db8500.h"
#include "board-mop500.h"
-
-static pin_cfg_t mop500_sdi_pins[] = {
- /* SDI0 (MicroSD slot) */
- GPIO18_MC0_CMDDIR,
- GPIO19_MC0_DAT0DIR,
- GPIO20_MC0_DAT2DIR,
- GPIO21_MC0_DAT31DIR,
- GPIO22_MC0_FBCLK,
- GPIO23_MC0_CLK,
- GPIO24_MC0_CMD,
- GPIO25_MC0_DAT0,
- GPIO26_MC0_DAT1,
- GPIO27_MC0_DAT2,
- GPIO28_MC0_DAT3,
-
- /* SDI4 (on-board eMMC) */
- GPIO197_MC4_DAT3,
- GPIO198_MC4_DAT2,
- GPIO199_MC4_DAT1,
- GPIO200_MC4_DAT0,
- GPIO201_MC4_CMD,
- GPIO202_MC4_FBCLK,
- GPIO203_MC4_CLK,
- GPIO204_MC4_DAT7,
- GPIO205_MC4_DAT6,
- GPIO206_MC4_DAT5,
- GPIO207_MC4_DAT4,
-};
-
-static pin_cfg_t mop500_sdi2_pins[] = {
- /* SDI2 (POP eMMC) */
- GPIO128_MC2_CLK,
- GPIO129_MC2_CMD,
- GPIO130_MC2_FBCLK,
- GPIO131_MC2_DAT0,
- GPIO132_MC2_DAT1,
- GPIO133_MC2_DAT2,
- GPIO134_MC2_DAT3,
- GPIO135_MC2_DAT4,
- GPIO136_MC2_DAT5,
- GPIO137_MC2_DAT6,
- GPIO138_MC2_DAT7,
-};
+#include "ste-dma40-db8500.h"
/*
* SDI 0 (MicroSD slot)
@@ -86,48 +44,134 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
MCI_DATA2DIREN | MCI_DATA31DIREN;
}
+#ifdef CONFIG_STE_DMA40
+struct stedma40_chan_cfg mop500_sdi0_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV29_SD_MM0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV29_SD_MM0_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+#endif
+
static struct mmci_platform_data mop500_sdi0_data = {
.vdd_handler = mop500_sdi0_vdd_handler,
.ocr_mask = MMC_VDD_29_30,
.f_max = 100000000,
.capabilities = MMC_CAP_4_BIT_DATA,
- .gpio_cd = GPIO_SDMMC_CD,
.gpio_wp = -1,
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &mop500_sdi0_dma_cfg_rx,
+ .dma_tx_param = &mop500_sdi0_dma_cfg_tx,
+#endif
};
-void mop500_sdi_tc35892_init(void)
+/* GPIO pins used by the sdi0 level shifter */
+static int sdi0_en = -1;
+static int sdi0_vsel = -1;
+
+static void sdi0_configure(void)
{
int ret;
- ret = gpio_request(GPIO_SDMMC_EN, "SDMMC_EN");
+ ret = gpio_request(sdi0_en, "level shifter enable");
if (!ret)
- ret = gpio_request(GPIO_SDMMC_1V8_3V_SEL,
- "GPIO_SDMMC_1V8_3V_SEL");
- if (ret)
+ ret = gpio_request(sdi0_vsel,
+ "level shifter 1v8-3v select");
+
+ if (ret) {
+ pr_warning("unable to config sdi0 gpios for level shifter.\n");
return;
+ }
- gpio_direction_output(GPIO_SDMMC_1V8_3V_SEL, 1);
- gpio_direction_output(GPIO_SDMMC_EN, 0);
+ /* Select the default 2.9V and enable level shifter */
+ gpio_direction_output(sdi0_vsel, 0);
+ gpio_direction_output(sdi0_en, 1);
+ /* Add the device */
db8500_add_sdi0(&mop500_sdi0_data);
}
+void mop500_sdi_tc35892_init(void)
+{
+ mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD;
+ sdi0_en = GPIO_SDMMC_EN;
+ sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL;
+ sdi0_configure();
+}
+
/*
* SDI 2 (POP eMMC, not on DB8500ed)
*/
+#ifdef CONFIG_STE_DMA40
+struct stedma40_chan_cfg mop500_sdi2_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV28_SD_MM2_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg mop500_sdi2_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV28_SD_MM2_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+#endif
+
static struct mmci_platform_data mop500_sdi2_data = {
.ocr_mask = MMC_VDD_165_195,
.f_max = 100000000,
.capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_cd = -1,
.gpio_wp = -1,
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &mop500_sdi2_dma_cfg_rx,
+ .dma_tx_param = &mop500_sdi2_dma_cfg_tx,
+#endif
};
/*
* SDI 4 (on-board eMMC)
*/
+#ifdef CONFIG_STE_DMA40
+struct stedma40_chan_cfg mop500_sdi4_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV42_SD_MM4_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg mop500_sdi4_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV42_SD_MM4_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+#endif
+
static struct mmci_platform_data mop500_sdi4_data = {
.ocr_mask = MMC_VDD_29_30,
.f_max = 100000000,
@@ -135,26 +179,32 @@ static struct mmci_platform_data mop500_sdi4_data = {
MMC_CAP_MMC_HIGHSPEED,
.gpio_cd = -1,
.gpio_wp = -1,
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &mop500_sdi4_dma_cfg_rx,
+ .dma_tx_param = &mop500_sdi4_dma_cfg_tx,
+#endif
};
void __init mop500_sdi_init(void)
{
- nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins));
+ /* PoP:ed eMMC on top of DB8500 v1.0 has problems with high speed */
+ if (!cpu_is_u8500v10())
+ mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED;
+ db8500_add_sdi2(&mop500_sdi2_data);
+
+ /* On-board eMMC */
+ db8500_add_sdi4(&mop500_sdi4_data);
+ if (machine_is_hrefv60()) {
+ mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
+ sdi0_en = HREFV60_SDMMC_EN_GPIO;
+ sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO;
+ sdi0_configure();
+ }
/*
- * sdi0 will finally be added when the TC35892 initializes and calls
+ * On boards with the TC35892 GPIO expander, sdi0 will finally
+ * be added when the TC35892 initializes and calls
* mop500_sdi_tc35892_init() above.
*/
-
- /* PoP:ed eMMC */
- if (!cpu_is_u8500ed()) {
- nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins));
- /* POP eMMC on v1.0 has problems with high speed */
- if (!cpu_is_u8500v10())
- mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED;
- db8500_add_sdi2(&mop500_sdi2_data);
- }
-
- /* On-board eMMC */
- db8500_add_sdi4(&mop500_sdi4_data);
}
diff --git a/arch/arm/mach-ux500/board-mop500-stuib.c b/arch/arm/mach-ux500/board-mop500-stuib.c
new file mode 100644
index 000000000000..8c979770d872
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-stuib.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/input/bu21013.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/input/matrix_keypad.h>
+#include <asm/mach-types.h>
+
+#include "board-mop500.h"
+
+/* STMPE/SKE keypad use this key layout */
+static const unsigned int mop500_keymap[] = {
+ KEY(2, 5, KEY_END),
+ KEY(4, 1, KEY_POWER),
+ KEY(3, 5, KEY_VOLUMEDOWN),
+ KEY(1, 3, KEY_3),
+ KEY(5, 2, KEY_RIGHT),
+ KEY(5, 0, KEY_9),
+
+ KEY(0, 5, KEY_MENU),
+ KEY(7, 6, KEY_ENTER),
+ KEY(4, 5, KEY_0),
+ KEY(6, 7, KEY_2),
+ KEY(3, 4, KEY_UP),
+ KEY(3, 3, KEY_DOWN),
+
+ KEY(6, 4, KEY_SEND),
+ KEY(6, 2, KEY_BACK),
+ KEY(4, 2, KEY_VOLUMEUP),
+ KEY(5, 5, KEY_1),
+ KEY(4, 3, KEY_LEFT),
+ KEY(3, 2, KEY_7),
+};
+
+static const struct matrix_keymap_data mop500_keymap_data = {
+ .keymap = mop500_keymap,
+ .keymap_size = ARRAY_SIZE(mop500_keymap),
+};
+/*
+ * STMPE1601
+ */
+static struct stmpe_keypad_platform_data stmpe1601_keypad_data = {
+ .debounce_ms = 64,
+ .scan_count = 8,
+ .no_autorepeat = true,
+ .keymap_data = &mop500_keymap_data,
+};
+
+static struct stmpe_platform_data stmpe1601_data = {
+ .id = 1,
+ .blocks = STMPE_BLOCK_KEYPAD,
+ .irq_trigger = IRQF_TRIGGER_FALLING,
+ .irq_base = MOP500_STMPE1601_IRQ(0),
+ .keypad = &stmpe1601_keypad_data,
+ .autosleep = true,
+ .autosleep_timeout = 1024,
+};
+
+static struct i2c_board_info __initdata mop500_i2c0_devices_stuib[] = {
+ {
+ I2C_BOARD_INFO("stmpe1601", 0x40),
+ .irq = NOMADIK_GPIO_TO_IRQ(218),
+ .platform_data = &stmpe1601_data,
+ .flags = I2C_CLIENT_WAKE,
+ },
+};
+
+/*
+ * BU21013 ROHM touchscreen interface on the STUIBs
+ */
+
+/* tracks number of bu21013 devices being enabled */
+static int bu21013_devices;
+
+#define TOUCH_GPIO_PIN 84
+
+#define TOUCH_XMAX 384
+#define TOUCH_YMAX 704
+
+#define PRCMU_CLOCK_OCR 0x1CC
+#define TSC_EXT_CLOCK_9_6MHZ 0x840000
+
+/**
+ * bu21013_gpio_board_init : configures the touch panel.
+ * @reset_pin: reset pin number
+ * This function can be used to configures
+ * the voltage and reset the touch panel controller.
+ */
+static int bu21013_gpio_board_init(int reset_pin)
+{
+ int retval = 0;
+
+ bu21013_devices++;
+ if (bu21013_devices == 1) {
+ retval = gpio_request(reset_pin, "touchp_reset");
+ if (retval) {
+ printk(KERN_ERR "Unable to request gpio reset_pin");
+ return retval;
+ }
+ retval = gpio_direction_output(reset_pin, 1);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: gpio direction failed\n",
+ __func__);
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+/**
+ * bu21013_gpio_board_exit : deconfigures the touch panel controller
+ * @reset_pin: reset pin number
+ * This function can be used to deconfigures the chip selection
+ * for touch panel controller.
+ */
+static int bu21013_gpio_board_exit(int reset_pin)
+{
+ int retval = 0;
+
+ if (bu21013_devices == 1) {
+ retval = gpio_direction_output(reset_pin, 0);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: gpio direction failed\n",
+ __func__);
+ return retval;
+ }
+ gpio_set_value(reset_pin, 0);
+ }
+ bu21013_devices--;
+
+ return retval;
+}
+
+/**
+ * bu21013_read_pin_val : get the interrupt pin value
+ * This function can be used to get the interrupt pin value for touch panel
+ * controller.
+ */
+static int bu21013_read_pin_val(void)
+{
+ return gpio_get_value(TOUCH_GPIO_PIN);
+}
+
+static struct bu21013_platform_device tsc_plat_device = {
+ .cs_en = bu21013_gpio_board_init,
+ .cs_dis = bu21013_gpio_board_exit,
+ .irq_read_val = bu21013_read_pin_val,
+ .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN),
+ .touch_x_max = TOUCH_XMAX,
+ .touch_y_max = TOUCH_YMAX,
+ .ext_clk = false,
+ .x_flip = false,
+ .y_flip = true,
+};
+
+static struct bu21013_platform_device tsc_plat2_device = {
+ .cs_en = bu21013_gpio_board_init,
+ .cs_dis = bu21013_gpio_board_exit,
+ .irq_read_val = bu21013_read_pin_val,
+ .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN),
+ .touch_x_max = TOUCH_XMAX,
+ .touch_y_max = TOUCH_YMAX,
+ .ext_clk = false,
+ .x_flip = false,
+ .y_flip = true,
+};
+
+static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = {
+ {
+ I2C_BOARD_INFO("bu21013_tp", 0x5C),
+ .platform_data = &tsc_plat_device,
+ },
+ {
+ I2C_BOARD_INFO("bu21013_tp", 0x5D),
+ .platform_data = &tsc_plat2_device,
+ },
+
+};
+
+void __init mop500_stuib_init(void)
+{
+ if (machine_is_hrefv60()) {
+ tsc_plat_device.cs_pin = HREFV60_TOUCH_RST_GPIO;
+ tsc_plat2_device.cs_pin = HREFV60_TOUCH_RST_GPIO;
+ } else {
+ tsc_plat_device.cs_pin = GPIO_BU21013_CS;
+ tsc_plat2_device.cs_pin = GPIO_BU21013_CS;
+
+ }
+
+ mop500_uib_i2c_add(0, mop500_i2c0_devices_stuib,
+ ARRAY_SIZE(mop500_i2c0_devices_stuib));
+
+ mop500_uib_i2c_add(3, u8500_i2c3_devices_stuib,
+ ARRAY_SIZE(u8500_i2c3_devices_stuib));
+}
diff --git a/arch/arm/mach-ux500/board-mop500-u8500uib.c b/arch/arm/mach-ux500/board-mop500-u8500uib.c
new file mode 100644
index 000000000000..d8a8734a0eba
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-u8500uib.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Board data for the U8500 UIB, also known as the New UIB
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/tc3589x.h>
+#include <linux/input/matrix_keypad.h>
+#include <../drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h>
+
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+
+#include "board-mop500.h"
+
+/*
+ * Synaptics RMI4 touchscreen interface on the U8500 UIB
+ */
+
+/*
+ * Descriptor structure.
+ * Describes the number of i2c devices on the bus that speak RMI.
+ */
+static struct synaptics_rmi4_platform_data rmi4_i2c_dev_platformdata = {
+ .irq_number = NOMADIK_GPIO_TO_IRQ(84),
+ .irq_type = (IRQF_TRIGGER_FALLING | IRQF_SHARED),
+ .x_flip = false,
+ .y_flip = true,
+ .regulator_en = false,
+};
+
+static struct i2c_board_info __initdata mop500_i2c3_devices_u8500[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", 0x4B),
+ .platform_data = &rmi4_i2c_dev_platformdata,
+ },
+};
+
+/*
+ * TC35893
+ */
+static const unsigned int u8500_keymap[] = {
+ KEY(3, 1, KEY_END),
+ KEY(4, 1, KEY_POWER),
+ KEY(6, 4, KEY_VOLUMEDOWN),
+ KEY(4, 2, KEY_EMAIL),
+ KEY(3, 3, KEY_RIGHT),
+ KEY(2, 5, KEY_BACKSPACE),
+
+ KEY(6, 7, KEY_MENU),
+ KEY(5, 0, KEY_ENTER),
+ KEY(4, 3, KEY_0),
+ KEY(3, 4, KEY_DOT),
+ KEY(5, 2, KEY_UP),
+ KEY(3, 5, KEY_DOWN),
+
+ KEY(4, 5, KEY_SEND),
+ KEY(0, 5, KEY_BACK),
+ KEY(6, 2, KEY_VOLUMEUP),
+ KEY(1, 3, KEY_SPACE),
+ KEY(7, 6, KEY_LEFT),
+ KEY(5, 5, KEY_SEARCH),
+};
+
+static struct matrix_keymap_data u8500_keymap_data = {
+ .keymap = u8500_keymap,
+ .keymap_size = ARRAY_SIZE(u8500_keymap),
+};
+
+static struct tc3589x_keypad_platform_data tc35893_data = {
+ .krow = TC_KPD_ROWS,
+ .kcol = TC_KPD_COLUMNS,
+ .debounce_period = TC_KPD_DEBOUNCE_PERIOD,
+ .settle_time = TC_KPD_SETTLE_TIME,
+ .irqtype = IRQF_TRIGGER_FALLING,
+ .enable_wakeup = true,
+ .keymap_data = &u8500_keymap_data,
+ .no_autorepeat = true,
+};
+
+static struct tc3589x_platform_data tc3589x_keypad_data = {
+ .block = TC3589x_BLOCK_KEYPAD,
+ .keypad = &tc35893_data,
+ .irq_base = MOP500_EGPIO_IRQ_BASE,
+};
+
+static struct i2c_board_info __initdata mop500_i2c0_devices_u8500[] = {
+ {
+ I2C_BOARD_INFO("tc3589x", 0x44),
+ .platform_data = &tc3589x_keypad_data,
+ .irq = NOMADIK_GPIO_TO_IRQ(218),
+ .flags = I2C_CLIENT_WAKE,
+ },
+};
+
+
+void __init mop500_u8500uib_init(void)
+{
+ mop500_uib_i2c_add(3, mop500_i2c3_devices_u8500,
+ ARRAY_SIZE(mop500_i2c3_devices_u8500));
+
+ mop500_uib_i2c_add(0, mop500_i2c0_devices_u8500,
+ ARRAY_SIZE(mop500_i2c0_devices_u8500));
+
+}
diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c
new file mode 100644
index 000000000000..69cce41f602a
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-uib.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#define pr_fmt(fmt) "mop500-uib: " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <mach/hardware.h>
+#include "board-mop500.h"
+
+enum mop500_uib {
+ STUIB,
+ U8500UIB,
+};
+
+struct uib {
+ const char *name;
+ const char *option;
+ void (*init)(void);
+};
+
+static struct __initdata uib mop500_uibs[] = {
+ [STUIB] = {
+ .name = "ST-UIB",
+ .option = "stuib",
+ .init = mop500_stuib_init,
+ },
+ [U8500UIB] = {
+ .name = "U8500-UIB",
+ .option = "u8500uib",
+ .init = mop500_u8500uib_init,
+ },
+};
+
+static struct uib *mop500_uib;
+
+static int __init mop500_uib_setup(char *str)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mop500_uibs); i++) {
+ struct uib *uib = &mop500_uibs[i];
+
+ if (!strcmp(str, uib->option)) {
+ mop500_uib = uib;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(mop500_uibs))
+ pr_err("invalid uib= option (%s)\n", str);
+
+ return 1;
+}
+__setup("uib=", mop500_uib_setup);
+
+/*
+ * The UIBs are detected after the I2C host controllers are registered, so
+ * i2c_register_board_info() can't be used.
+ */
+void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
+ unsigned n)
+{
+ struct i2c_adapter *adap;
+ struct i2c_client *client;
+ int i;
+
+ adap = i2c_get_adapter(busnum);
+ if (!adap) {
+ pr_err("failed to get adapter i2c%d\n", busnum);
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ client = i2c_new_device(adap, &info[i]);
+ if (!client)
+ pr_err("failed to register %s to i2c%d\n",
+ info[i].type, busnum);
+ }
+
+ i2c_put_adapter(adap);
+}
+
+static void __init __mop500_uib_init(struct uib *uib, const char *why)
+{
+ pr_info("%s (%s)\n", uib->name, why);
+ uib->init();
+}
+
+/*
+ * Detect the UIB attached based on the presence or absence of i2c devices.
+ */
+static int __init mop500_uib_init(void)
+{
+ struct uib *uib = mop500_uib;
+ struct i2c_adapter *i2c0;
+ int ret;
+
+ if (!cpu_is_u8500())
+ return -ENODEV;
+
+ if (uib) {
+ __mop500_uib_init(uib, "from uib= boot argument");
+ return 0;
+ }
+
+ i2c0 = i2c_get_adapter(0);
+ if (!i2c0) {
+ __mop500_uib_init(&mop500_uibs[STUIB],
+ "fallback, could not get i2c0");
+ return -ENODEV;
+ }
+
+ /* U8500-UIB has the TC35893 at 0x44 on I2C0, the ST-UIB doesn't. */
+ ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL);
+ i2c_put_adapter(i2c0);
+
+ if (ret == 0)
+ uib = &mop500_uibs[U8500UIB];
+ else
+ uib = &mop500_uibs[STUIB];
+
+ __mop500_uib_init(uib, "detected");
+
+ return 0;
+}
+
+module_init(mop500_uib_init);
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index a393f57ed2a8..8790d984cac8 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -17,68 +17,30 @@
#include <linux/gpio.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl022.h>
+#include <linux/amba/serial.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/tc3589x.h>
+#include <linux/leds-lp5521.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <plat/pincfg.h>
#include <plat/i2c.h>
+#include <plat/ste_dma40.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/irqs.h>
+#include "ste-dma40-db8500.h"
#include "devices-db8500.h"
-#include "pins-db8500.h"
#include "board-mop500.h"
#include "board-mop500-regulators.h"
-static pin_cfg_t mop500_pins[] = {
- /* SSP0 */
- GPIO143_SSP0_CLK,
- GPIO144_SSP0_FRM,
- GPIO145_SSP0_RXD,
- GPIO146_SSP0_TXD,
-
- /* I2C */
- GPIO147_I2C0_SCL,
- GPIO148_I2C0_SDA,
- GPIO16_I2C1_SCL,
- GPIO17_I2C1_SDA,
- GPIO10_I2C2_SDA,
- GPIO11_I2C2_SCL,
- GPIO229_I2C3_SDA,
- GPIO230_I2C3_SCL,
-
- /* SKE keypad */
- GPIO153_KP_I7,
- GPIO154_KP_I6,
- GPIO155_KP_I5,
- GPIO156_KP_I4,
- GPIO157_KP_O7,
- GPIO158_KP_O6,
- GPIO159_KP_O5,
- GPIO160_KP_O4,
- GPIO161_KP_I3,
- GPIO162_KP_I2,
- GPIO163_KP_I1,
- GPIO164_KP_I0,
- GPIO165_KP_O3,
- GPIO166_KP_O2,
- GPIO167_KP_O1,
- GPIO168_KP_O0,
-
- /* GPIO_EXP_INT */
- GPIO217_GPIO,
-
- /* STMPE1601 IRQ */
- GPIO218_GPIO | PIN_INPUT_PULLUP,
-};
-
static struct ab8500_platform_data ab8500_platdata = {
.irq_base = MOP500_AB8500_IRQ_BASE,
.regulator = ab8500_regulators,
@@ -103,16 +65,6 @@ struct platform_device ab8500_device = {
.resource = ab8500_resources,
};
-static struct pl022_ssp_controller ssp0_platform_data = {
- .bus_id = 0,
- /* pl022 not yet supports dma */
- .enable_dma = 0,
- /* on this platform, gpio 31,142,144,214 &
- * 224 are connected as chip selects
- */
- .num_chipselect = 5,
-};
-
/*
* TC35892
*/
@@ -133,14 +85,81 @@ static struct tc3589x_platform_data mop500_tc35892_data = {
.irq_base = MOP500_EGPIO_IRQ_BASE,
};
+static struct lp5521_led_config lp5521_pri_led[] = {
+ [0] = {
+ .chan_nr = 0,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+ [1] = {
+ .chan_nr = 1,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+ [2] = {
+ .chan_nr = 2,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+};
+
+static struct lp5521_platform_data __initdata lp5521_pri_data = {
+ .label = "lp5521_pri",
+ .led_config = &lp5521_pri_led[0],
+ .num_channels = 3,
+ .clock_mode = LP5521_CLOCK_EXT,
+};
+
+static struct lp5521_led_config lp5521_sec_led[] = {
+ [0] = {
+ .chan_nr = 0,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+ [1] = {
+ .chan_nr = 1,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+ [2] = {
+ .chan_nr = 2,
+ .led_current = 0x2f,
+ .max_current = 0x5f,
+ },
+};
+
+static struct lp5521_platform_data __initdata lp5521_sec_data = {
+ .label = "lp5521_sec",
+ .led_config = &lp5521_sec_led[0],
+ .num_channels = 3,
+ .clock_mode = LP5521_CLOCK_EXT,
+};
+
static struct i2c_board_info mop500_i2c0_devices[] = {
{
I2C_BOARD_INFO("tc3589x", 0x42),
- .irq = NOMADIK_GPIO_TO_IRQ(217),
+ .irq = NOMADIK_GPIO_TO_IRQ(217),
.platform_data = &mop500_tc35892_data,
},
};
+static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
+ {
+ /* lp5521 LED driver, 1st device */
+ I2C_BOARD_INFO("lp5521", 0x33),
+ .platform_data = &lp5521_pri_data,
+ },
+ {
+ /* lp5521 LED driver, 2st device */
+ I2C_BOARD_INFO("lp5521", 0x34),
+ .platform_data = &lp5521_sec_data,
+ },
+ {
+ /* Light sensor Rohm BH1780GLI */
+ I2C_BOARD_INFO("bh1780", 0x29),
+ },
+};
+
#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
static struct nmk_i2c_controller u8500_i2c##id##_data = { \
/* \
@@ -178,8 +197,93 @@ static void __init mop500_i2c_init(void)
db8500_add_i2c3(&u8500_i2c3_data);
}
+static struct gpio_keys_button mop500_gpio_keys[] = {
+ {
+ .desc = "SFH7741 Proximity Sensor",
+ .type = EV_SW,
+ .code = SW_FRONT_PROXIMITY,
+ .active_low = 0,
+ .can_disable = 1,
+ }
+};
+
+static struct regulator *prox_regulator;
+static int mop500_prox_activate(struct device *dev);
+static void mop500_prox_deactivate(struct device *dev);
+
+static struct gpio_keys_platform_data mop500_gpio_keys_data = {
+ .buttons = mop500_gpio_keys,
+ .nbuttons = ARRAY_SIZE(mop500_gpio_keys),
+ .enable = mop500_prox_activate,
+ .disable = mop500_prox_deactivate,
+};
+
+static struct platform_device mop500_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = 0,
+ .dev = {
+ .platform_data = &mop500_gpio_keys_data,
+ },
+};
+
+static int mop500_prox_activate(struct device *dev)
+{
+ prox_regulator = regulator_get(&mop500_gpio_keys_device.dev,
+ "vcc");
+ if (IS_ERR(prox_regulator)) {
+ dev_err(&mop500_gpio_keys_device.dev,
+ "no regulator\n");
+ return PTR_ERR(prox_regulator);
+ }
+ regulator_enable(prox_regulator);
+ return 0;
+}
+
+static void mop500_prox_deactivate(struct device *dev)
+{
+ regulator_disable(prox_regulator);
+ regulator_put(prox_regulator);
+}
+
/* add any platform devices here - TODO */
static struct platform_device *platform_devs[] __initdata = {
+ &mop500_gpio_keys_device,
+};
+
+#ifdef CONFIG_STE_DMA40
+static struct stedma40_chan_cfg ssp0_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV8_SSP0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg ssp0_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV8_SSP0_TX,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+#endif
+
+static struct pl022_ssp_controller ssp0_platform_data = {
+ .bus_id = 0,
+#ifdef CONFIG_STE_DMA40
+ .enable_dma = 1,
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &ssp0_dma_cfg_rx,
+ .dma_tx_param = &ssp0_dma_cfg_tx,
+#else
+ .enable_dma = 0,
+#endif
+ /* on this platform, gpio 31,142,144,214 &
+ * 224 are connected as chip selects
+ */
+ .num_chipselect = 5,
};
static void __init mop500_spi_init(void)
@@ -187,18 +291,108 @@ static void __init mop500_spi_init(void)
db8500_add_ssp0(&ssp0_platform_data);
}
+#ifdef CONFIG_STE_DMA40
+static struct stedma40_chan_cfg uart0_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV13_UART0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg uart0_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV13_UART0_TX,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg uart1_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV12_UART1_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg uart1_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV12_UART1_TX,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg uart2_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV11_UART2_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+
+static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV11_UART2_TX,
+ .src_info.data_width = STEDMA40_BYTE_WIDTH,
+ .dst_info.data_width = STEDMA40_BYTE_WIDTH,
+};
+#endif
+
+static struct amba_pl011_data uart0_plat = {
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &uart0_dma_cfg_rx,
+ .dma_tx_param = &uart0_dma_cfg_tx,
+#endif
+};
+
+static struct amba_pl011_data uart1_plat = {
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &uart1_dma_cfg_rx,
+ .dma_tx_param = &uart1_dma_cfg_tx,
+#endif
+};
+
+static struct amba_pl011_data uart2_plat = {
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &uart2_dma_cfg_rx,
+ .dma_tx_param = &uart2_dma_cfg_tx,
+#endif
+};
+
static void __init mop500_uart_init(void)
{
- db8500_add_uart0();
- db8500_add_uart1();
- db8500_add_uart2();
+ db8500_add_uart0(&uart0_plat);
+ db8500_add_uart1(&uart1_plat);
+ db8500_add_uart2(&uart2_plat);
}
-static void __init u8500_init_machine(void)
+static void __init mop500_init_machine(void)
{
+ /*
+ * The HREFv60 board removed a GPIO expander and routed
+ * all these GPIO pins to the internal GPIO controller
+ * instead.
+ */
+ if (machine_is_hrefv60())
+ mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
+ else
+ mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
+
u8500_init_devices();
- nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins));
+ mop500_pins_init();
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
@@ -207,12 +401,12 @@ static void __init u8500_init_machine(void)
mop500_spi_init();
mop500_uart_init();
- mop500_keypad_init();
-
platform_device_register(&ab8500_device);
i2c_register_board_info(0, mop500_i2c0_devices,
ARRAY_SIZE(mop500_i2c0_devices));
+ i2c_register_board_info(2, mop500_i2c2_devices,
+ ARRAY_SIZE(mop500_i2c2_devices));
}
MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
@@ -222,5 +416,13 @@ MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
.init_irq = ux500_init_irq,
/* we re-use nomadik timer here */
.timer = &ux500_timer,
- .init_machine = u8500_init_machine,
+ .init_machine = mop500_init_machine,
+MACHINE_END
+
+MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+")
+ .boot_params = 0x100,
+ .map_io = u8500_map_io,
+ .init_irq = ux500_init_irq,
+ .timer = &ux500_timer,
+ .init_machine = mop500_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
index 3104ae2a02c2..56722f4be71b 100644
--- a/arch/arm/mach-ux500/board-mop500.h
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -7,15 +7,36 @@
#ifndef __BOARD_MOP500_H
#define __BOARD_MOP500_H
-#define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x))
+/* HREFv60-specific GPIO assignments, this board has no GPIO expander */
+#define HREFV60_TOUCH_RST_GPIO 143
+#define HREFV60_PROX_SENSE_GPIO 217
+#define HREFV60_HAL_SW_GPIO 145
+#define HREFV60_SDMMC_EN_GPIO 169
+#define HREFV60_SDMMC_1V8_3V_GPIO 5
+#define HREFV60_SDMMC_CD_GPIO 95
+#define HREFV60_ACCEL_INT1_GPIO 82
+#define HREFV60_ACCEL_INT2_GPIO 83
+#define HREFV60_MAGNET_DRDY_GPIO 32
+#define HREFV60_DISP1_RST_GPIO 65
+#define HREFV60_DISP2_RST_GPIO 66
/* GPIOs on the TC35892 expander */
+#define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x))
#define GPIO_SDMMC_CD MOP500_EGPIO(3)
+#define GPIO_PROX_SENSOR MOP500_EGPIO(7)
+#define GPIO_BU21013_CS MOP500_EGPIO(13)
#define GPIO_SDMMC_EN MOP500_EGPIO(17)
#define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18)
+struct i2c_board_info;
+
extern void mop500_sdi_init(void);
extern void mop500_sdi_tc35892_init(void);
-extern void mop500_keypad_init(void);
+void __init mop500_u8500uib_init(void);
+void __init mop500_stuib_init(void);
+void __init mop500_pins_init(void);
+
+void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
+ unsigned n);
#endif
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c
index 54712acc0394..739fb4c5b160 100644
--- a/arch/arm/mach-ux500/board-u5500-sdi.c
+++ b/arch/arm/mach-ux500/board-u5500-sdi.c
@@ -31,6 +31,26 @@ static pin_cfg_t u5500_sdi_pins[] = {
GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW,
};
+#ifdef CONFIG_STE_DMA40
+struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+
+static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = {
+ .mode = STEDMA40_MODE_LOGICAL,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB5500_DMA_DEV24_SDMMC0_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+};
+#endif
+
static struct mmci_platform_data u5500_sdi0_data = {
.ocr_mask = MMC_VDD_165_195,
.f_max = 50000000,
@@ -39,6 +59,11 @@ static struct mmci_platform_data u5500_sdi0_data = {
MMC_CAP_MMC_HIGHSPEED,
.gpio_cd = -1,
.gpio_wp = -1,
+#ifdef CONFIG_STE_DMA40
+ .dma_filter = stedma40_filter,
+ .dma_rx_param = &u5500_sdi0_dma_cfg_rx,
+ .dma_tx_param = &u5500_sdi0_dma_cfg_tx,
+#endif
};
void __init u5500_sdi_init(void)
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
index 39d370c1f3b4..44fd3b5c33ec 100644
--- a/arch/arm/mach-ux500/board-u5500.c
+++ b/arch/arm/mach-ux500/board-u5500.c
@@ -22,9 +22,9 @@
static void __init u5500_uart_init(void)
{
- db5500_add_uart0();
- db5500_add_uart1();
- db5500_add_uart2();
+ db5500_add_uart0(NULL);
+ db5500_add_uart1(NULL);
+ db5500_add_uart2(NULL);
}
static void __init u5500_init_machine(void)
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index b2b0a3b9be8f..32ce90840ee1 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -313,7 +313,7 @@ static DEFINE_PRCMU_CLK_RATE(uartclk, 0x0, 5, UARTCLK, 38400000);
static DEFINE_PRCMU_CLK(msp02clk, 0x0, 6, MSP02CLK);
static DEFINE_PRCMU_CLK(msp1clk, 0x0, 7, MSP1CLK); /* v1 */
static DEFINE_PRCMU_CLK_RATE(i2cclk, 0x0, 8, I2CCLK, 48000000);
-static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 50000000);
+static DEFINE_PRCMU_CLK_RATE(sdmmcclk, 0x0, 9, SDMMCCLK, 100000000);
static DEFINE_PRCMU_CLK(slimclk, 0x0, 10, SLIMCLK);
static DEFINE_PRCMU_CLK(per1clk, 0x0, 11, PER1CLK);
static DEFINE_PRCMU_CLK(per2clk, 0x0, 12, PER2CLK);
@@ -520,7 +520,7 @@ static struct clk_lookup u8500_ed_clks[] = {
CLK(ssp0_ed, "ssp0", NULL),
/* Peripheral Cluster #5 */
- CLK(usb_ed, "musb_hdrc.0", "usb"),
+ CLK(usb_ed, "musb-ux500.0", "usb"),
/* Peripheral Cluster #6 */
CLK(dmc_ed, "dmc", NULL),
@@ -561,7 +561,7 @@ static struct clk_lookup u8500_v1_clks[] = {
CLK(ssp0_v1, "ssp0", NULL),
/* Peripheral Cluster #5 */
- CLK(usb_v1, "musb_hdrc.0", "usb"),
+ CLK(usb_v1, "musb-ux500.0", "usb"),
/* Peripheral Cluster #6 */
CLK(mtu1_v1, "mtu1", NULL),
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
index af04e0891a78..c9dc2eff3cb2 100644
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ b/arch/arm/mach-ux500/cpu-db5500.c
@@ -11,6 +11,7 @@
#include <linux/irq.h>
#include <asm/mach/map.h>
+#include <asm/pmu.h>
#include <plat/gpio.h>
@@ -18,8 +19,10 @@
#include <mach/devices.h>
#include <mach/setup.h>
#include <mach/irqs.h>
+#include <mach/usb.h>
#include "devices-db5500.h"
+#include "ste-dma40-db5500.h"
static struct map_desc u5500_uart_io_desc[] __initdata = {
__IO_DEV_DESC(U5500_UART0_BASE, SZ_4K),
@@ -43,6 +46,26 @@ static struct map_desc u5500_io_desc[] __initdata = {
__IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
};
+static struct resource db5500_pmu_resources[] = {
+ [0] = {
+ .start = IRQ_DB5500_PMU0,
+ .end = IRQ_DB5500_PMU0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [1] = {
+ .start = IRQ_DB5500_PMU1,
+ .end = IRQ_DB5500_PMU1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device db5500_pmu_device = {
+ .name = "arm-pmu",
+ .id = ARM_PMU_DEVICE_CPU,
+ .num_resources = ARRAY_SIZE(db5500_pmu_resources),
+ .resource = db5500_pmu_resources,
+};
+
static struct resource mbox0_resources[] = {
{
.name = "mbox_peer",
@@ -127,7 +150,8 @@ static struct platform_device mbox2_device = {
.num_resources = ARRAY_SIZE(mbox2_resources),
};
-static struct platform_device *u5500_platform_devs[] __initdata = {
+static struct platform_device *db5500_platform_devs[] __initdata = {
+ &db5500_pmu_device,
&mbox0_device,
&mbox1_device,
&mbox2_device,
@@ -166,12 +190,35 @@ void __init u5500_map_io(void)
iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
}
+static int usb_db5500_rx_dma_cfg[] = {
+ DB5500_DMA_DEV4_USB_OTG_IEP_1_9,
+ DB5500_DMA_DEV5_USB_OTG_IEP_2_10,
+ DB5500_DMA_DEV6_USB_OTG_IEP_3_11,
+ DB5500_DMA_DEV20_USB_OTG_IEP_4_12,
+ DB5500_DMA_DEV21_USB_OTG_IEP_5_13,
+ DB5500_DMA_DEV22_USB_OTG_IEP_6_14,
+ DB5500_DMA_DEV23_USB_OTG_IEP_7_15,
+ DB5500_DMA_DEV38_USB_OTG_IEP_8
+};
+
+static int usb_db5500_tx_dma_cfg[] = {
+ DB5500_DMA_DEV4_USB_OTG_OEP_1_9,
+ DB5500_DMA_DEV5_USB_OTG_OEP_2_10,
+ DB5500_DMA_DEV6_USB_OTG_OEP_3_11,
+ DB5500_DMA_DEV20_USB_OTG_OEP_4_12,
+ DB5500_DMA_DEV21_USB_OTG_OEP_5_13,
+ DB5500_DMA_DEV22_USB_OTG_OEP_6_14,
+ DB5500_DMA_DEV23_USB_OTG_OEP_7_15,
+ DB5500_DMA_DEV38_USB_OTG_OEP_8
+};
+
void __init u5500_init_devices(void)
{
db5500_add_gpios();
db5500_dma_init();
db5500_add_rtc();
+ db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
- platform_add_devices(u5500_platform_devs,
- ARRAY_SIZE(u5500_platform_devs));
+ platform_add_devices(db5500_platform_devs,
+ ARRAY_SIZE(db5500_platform_devs));
}
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 1748fbc58530..516126cb357d 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -12,21 +12,21 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <asm/mach/map.h>
+#include <asm/pmu.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
+#include <mach/usb.h>
#include "devices-db8500.h"
-
-static struct platform_device *platform_devs[] __initdata = {
- &u8500_dma40_device,
-};
+#include "ste-dma40-db8500.h"
/* minimum static i/o mapping required to boot U8500 platforms */
static struct map_desc u8500_uart_io_desc[] __initdata = {
@@ -89,6 +89,51 @@ void __init u8500_map_io(void)
iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
}
+static struct resource db8500_pmu_resources[] = {
+ [0] = {
+ .start = IRQ_DB8500_PMU,
+ .end = IRQ_DB8500_PMU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/*
+ * The PMU IRQ lines of two cores are wired together into a single interrupt.
+ * Bounce the interrupt to the other core if it's not ours.
+ */
+static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler)
+{
+ irqreturn_t ret = handler(irq, dev);
+ int other = !smp_processor_id();
+
+ if (ret == IRQ_NONE && cpu_online(other))
+ irq_set_affinity(irq, cpumask_of(other));
+
+ /*
+ * We should be able to get away with the amount of IRQ_NONEs we give,
+ * while still having the spurious IRQ detection code kick in if the
+ * interrupt really starts hitting spuriously.
+ */
+ return ret;
+}
+
+static struct arm_pmu_platdata db8500_pmu_platdata = {
+ .handle_irq = db8500_pmu_handler,
+};
+
+static struct platform_device db8500_pmu_device = {
+ .name = "arm-pmu",
+ .id = ARM_PMU_DEVICE_CPU,
+ .num_resources = ARRAY_SIZE(db8500_pmu_resources),
+ .resource = db8500_pmu_resources,
+ .dev.platform_data = &db8500_pmu_platdata,
+};
+
+static struct platform_device *platform_devs[] __initdata = {
+ &u8500_dma40_device,
+ &db8500_pmu_device,
+};
+
static resource_size_t __initdata db8500_gpio_base[] = {
U8500_GPIOBANK0_BASE,
U8500_GPIOBANK1_BASE,
@@ -111,6 +156,28 @@ static void __init db8500_add_gpios(void)
IRQ_DB8500_GPIO0, &pdata);
}
+static int usb_db8500_rx_dma_cfg[] = {
+ DB8500_DMA_DEV38_USB_OTG_IEP_1_9,
+ DB8500_DMA_DEV37_USB_OTG_IEP_2_10,
+ DB8500_DMA_DEV36_USB_OTG_IEP_3_11,
+ DB8500_DMA_DEV19_USB_OTG_IEP_4_12,
+ DB8500_DMA_DEV18_USB_OTG_IEP_5_13,
+ DB8500_DMA_DEV17_USB_OTG_IEP_6_14,
+ DB8500_DMA_DEV16_USB_OTG_IEP_7_15,
+ DB8500_DMA_DEV39_USB_OTG_IEP_8
+};
+
+static int usb_db8500_tx_dma_cfg[] = {
+ DB8500_DMA_DEV38_USB_OTG_OEP_1_9,
+ DB8500_DMA_DEV37_USB_OTG_OEP_2_10,
+ DB8500_DMA_DEV36_USB_OTG_OEP_3_11,
+ DB8500_DMA_DEV19_USB_OTG_OEP_4_12,
+ DB8500_DMA_DEV18_USB_OTG_OEP_5_13,
+ DB8500_DMA_DEV17_USB_OTG_OEP_6_14,
+ DB8500_DMA_DEV16_USB_OTG_OEP_7_15,
+ DB8500_DMA_DEV39_USB_OTG_OEP_8
+};
+
/*
* This function is called from the board init
*/
@@ -121,6 +188,7 @@ void __init u8500_init_devices(void)
db8500_add_rtc();
db8500_add_gpios();
+ db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c
index fe69f5fac1bb..13a4ce046ae5 100644
--- a/arch/arm/mach-ux500/devices-common.c
+++ b/arch/arm/mach-ux500/devices-common.c
@@ -139,6 +139,7 @@ void dbx500_add_gpios(resource_size_t *base, int num, int irq,
for (i = 0; i < num; i++, first += 32, irq++) {
pdata->first_gpio = first;
pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
+ pdata->num_gpio = 32;
dbx500_add_gpio(i, base[i], irq, pdata);
}
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index cbadc117d2db..c719b5a1d913 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -42,10 +42,13 @@ dbx500_add_sdi(const char *name, resource_size_t base, int irq,
return dbx500_add_amba_device(name, base, irq, pdata, 0);
}
+struct amba_pl011_data;
+
static inline struct amba_device *
-dbx500_add_uart(const char *name, resource_size_t base, int irq)
+dbx500_add_uart(const char *name, resource_size_t base, int irq,
+ struct amba_pl011_data *pdata)
{
- return dbx500_add_amba_device(name, base, irq, NULL, 0);
+ return dbx500_add_amba_device(name, base, irq, pdata, 0);
}
struct nmk_i2c_controller;
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h
index c8d7901c1f2d..94627f7783b0 100644
--- a/arch/arm/mach-ux500/devices-db5500.h
+++ b/arch/arm/mach-ux500/devices-db5500.h
@@ -34,6 +34,9 @@
#define db5500_add_rtc() \
dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
+#define db5500_add_usb(rx_cfg, tx_cfg) \
+ ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
+
#define db5500_add_sdi0(pdata) \
dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata)
#define db5500_add_sdi1(pdata) \
@@ -54,13 +57,13 @@
#define db5500_add_spi3(pdata) \
dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata)
-#define db5500_add_uart0() \
- dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0)
-#define db5500_add_uart1() \
- dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1)
-#define db5500_add_uart2() \
- dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2)
-#define db5500_add_uart3() \
- dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3)
+#define db5500_add_uart0(plat) \
+ dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
+#define db5500_add_uart1(plat) \
+ dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat)
+#define db5500_add_uart2(plat) \
+ dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat)
+#define db5500_add_uart3(plat) \
+ dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat)
#endif
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 23c695d54977..73b17404b194 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/amba/bus.h>
+#include <linux/amba/pl022.h>
#include <plat/ste_dma40.h>
@@ -67,12 +68,72 @@ struct stedma40_chan_cfg dma40_memcpy_conf_log = {
/*
* Mapping between destination event lines and physical device address.
- * The event line is tied to a device and therefor the address is constant.
+ * The event line is tied to a device and therefore the address is constant.
+ * When the address comes from a primecell it will be configured in runtime
+ * and we set the address to -1 as a placeholder.
*/
-static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV];
+static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = {
+ /* MUSB - these will be runtime-reconfigured */
+ [DB8500_DMA_DEV39_USB_OTG_OEP_8] = -1,
+ [DB8500_DMA_DEV16_USB_OTG_OEP_7_15] = -1,
+ [DB8500_DMA_DEV17_USB_OTG_OEP_6_14] = -1,
+ [DB8500_DMA_DEV18_USB_OTG_OEP_5_13] = -1,
+ [DB8500_DMA_DEV19_USB_OTG_OEP_4_12] = -1,
+ [DB8500_DMA_DEV36_USB_OTG_OEP_3_11] = -1,
+ [DB8500_DMA_DEV37_USB_OTG_OEP_2_10] = -1,
+ [DB8500_DMA_DEV38_USB_OTG_OEP_1_9] = -1,
+ /* PrimeCells - run-time configured */
+ [DB8500_DMA_DEV0_SPI0_TX] = -1,
+ [DB8500_DMA_DEV1_SD_MMC0_TX] = -1,
+ [DB8500_DMA_DEV2_SD_MMC1_TX] = -1,
+ [DB8500_DMA_DEV3_SD_MMC2_TX] = -1,
+ [DB8500_DMA_DEV8_SSP0_TX] = -1,
+ [DB8500_DMA_DEV9_SSP1_TX] = -1,
+ [DB8500_DMA_DEV11_UART2_TX] = -1,
+ [DB8500_DMA_DEV12_UART1_TX] = -1,
+ [DB8500_DMA_DEV13_UART0_TX] = -1,
+ [DB8500_DMA_DEV28_SD_MM2_TX] = -1,
+ [DB8500_DMA_DEV29_SD_MM0_TX] = -1,
+ [DB8500_DMA_DEV32_SD_MM1_TX] = -1,
+ [DB8500_DMA_DEV33_SPI2_TX] = -1,
+ [DB8500_DMA_DEV35_SPI1_TX] = -1,
+ [DB8500_DMA_DEV40_SPI3_TX] = -1,
+ [DB8500_DMA_DEV41_SD_MM3_TX] = -1,
+ [DB8500_DMA_DEV42_SD_MM4_TX] = -1,
+ [DB8500_DMA_DEV43_SD_MM5_TX] = -1,
+};
/* Mapping between source event lines and physical device address */
-static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV];
+static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = {
+ /* MUSB - these will be runtime-reconfigured */
+ [DB8500_DMA_DEV39_USB_OTG_IEP_8] = -1,
+ [DB8500_DMA_DEV16_USB_OTG_IEP_7_15] = -1,
+ [DB8500_DMA_DEV17_USB_OTG_IEP_6_14] = -1,
+ [DB8500_DMA_DEV18_USB_OTG_IEP_5_13] = -1,
+ [DB8500_DMA_DEV19_USB_OTG_IEP_4_12] = -1,
+ [DB8500_DMA_DEV36_USB_OTG_IEP_3_11] = -1,
+ [DB8500_DMA_DEV37_USB_OTG_IEP_2_10] = -1,
+ [DB8500_DMA_DEV38_USB_OTG_IEP_1_9] = -1,
+ /* PrimeCells */
+ [DB8500_DMA_DEV0_SPI0_RX] = -1,
+ [DB8500_DMA_DEV1_SD_MMC0_RX] = -1,
+ [DB8500_DMA_DEV2_SD_MMC1_RX] = -1,
+ [DB8500_DMA_DEV3_SD_MMC2_RX] = -1,
+ [DB8500_DMA_DEV8_SSP0_RX] = -1,
+ [DB8500_DMA_DEV9_SSP1_RX] = -1,
+ [DB8500_DMA_DEV11_UART2_RX] = -1,
+ [DB8500_DMA_DEV12_UART1_RX] = -1,
+ [DB8500_DMA_DEV13_UART0_RX] = -1,
+ [DB8500_DMA_DEV28_SD_MM2_RX] = -1,
+ [DB8500_DMA_DEV29_SD_MM0_RX] = -1,
+ [DB8500_DMA_DEV32_SD_MM1_RX] = -1,
+ [DB8500_DMA_DEV33_SPI2_RX] = -1,
+ [DB8500_DMA_DEV35_SPI1_RX] = -1,
+ [DB8500_DMA_DEV40_SPI3_RX] = -1,
+ [DB8500_DMA_DEV41_SD_MM3_RX] = -1,
+ [DB8500_DMA_DEV42_SD_MM4_RX] = -1,
+ [DB8500_DMA_DEV43_SD_MM5_RX] = -1,
+};
/* Reserved event lines for memcpy only */
static int dma40_memcpy_event[] = {
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
index 3a770c756979..9cc6f8f5d3e6 100644
--- a/arch/arm/mach-ux500/devices-db8500.h
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -61,6 +61,9 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
#define db8500_add_rtc() \
dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
+#define db8500_add_usb(rx_cfg, tx_cfg) \
+ ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
+
#define db8500_add_sdi0(pdata) \
dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata)
#define db8500_add_sdi1(pdata) \
@@ -88,11 +91,11 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
#define db8500_add_spi3(pdata) \
dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata)
-#define db8500_add_uart0() \
- dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0)
-#define db8500_add_uart1() \
- dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1)
-#define db8500_add_uart2() \
- dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2)
+#define db8500_add_uart0(pdata) \
+ dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
+#define db8500_add_uart1(pdata) \
+ dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata)
+#define db8500_add_uart2(pdata) \
+ dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata)
#endif
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c
index 32a061f8a95b..1cfab68ae417 100644
--- a/arch/arm/mach-ux500/dma-db5500.c
+++ b/arch/arm/mach-ux500/dma-db5500.c
@@ -73,11 +73,27 @@ static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
*/
static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = {
[DB5500_DMA_DEV24_SDMMC0_RX] = -1,
+ [DB5500_DMA_DEV38_USB_OTG_IEP_8] = -1,
+ [DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = -1,
+ [DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = -1,
+ [DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = -1,
+ [DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = -1,
+ [DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = -1,
+ [DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = -1,
+ [DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = -1,
};
/* Mapping between destination event lines and physical device address */
static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = {
[DB5500_DMA_DEV24_SDMMC0_TX] = -1,
+ [DB5500_DMA_DEV38_USB_OTG_OEP_8] = -1,
+ [DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = -1,
+ [DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = -1,
+ [DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = -1,
+ [DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = -1,
+ [DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = -1,
+ [DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = -1,
+ [DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = -1,
};
static int dma40_memcpy_event[] = {
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
index 9a6614c6808e..ab0fe1432fae 100644
--- a/arch/arm/mach-ux500/include/mach/uncompress.h
+++ b/arch/arm/mach-ux500/include/mach/uncompress.h
@@ -50,7 +50,11 @@ static void flush(void)
static inline void arch_decomp_setup(void)
{
- if (machine_is_u8500())
+ /* Check in run time if we run on an U8500 or U5500 */
+ if (machine_is_u8500() ||
+ machine_is_svp8500v1() ||
+ machine_is_svp8500v2() ||
+ machine_is_hrefv60())
ux500_uart_base = U8500_UART2_BASE;
else if (machine_is_u5500())
ux500_uart_base = U5500_UART0_BASE;
diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h
new file mode 100644
index 000000000000..d3739d418813
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/usb.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __ASM_ARCH_USB_H
+#define __ASM_ARCH_USB_H
+
+#include <linux/dmaengine.h>
+
+#define UX500_MUSB_DMA_NUM_RX_CHANNELS 8
+#define UX500_MUSB_DMA_NUM_TX_CHANNELS 8
+
+struct ux500_musb_board_data {
+ void **dma_rx_param_array;
+ void **dma_tx_param_array;
+ u32 num_rx_channels;
+ u32 num_tx_channels;
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+};
+
+void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
+ int *dma_tx_cfg);
+#endif
diff --git a/arch/arm/mach-ux500/mbox-db5500.c b/arch/arm/mach-ux500/mbox-db5500.c
index cbf15718fc3c..a4ffb9f4f461 100644
--- a/arch/arm/mach-ux500/mbox-db5500.c
+++ b/arch/arm/mach-ux500/mbox-db5500.c
@@ -498,7 +498,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
#endif
dev_info(&(mbox->pdev->dev),
- "Mailbox driver with index %d initated!\n", mbox_id);
+ "Mailbox driver with index %d initiated!\n", mbox_id);
exit:
return mbox;
diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c
new file mode 100644
index 000000000000..82e535953fd9
--- /dev/null
+++ b/arch/arm/mach-ux500/usb.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/platform_device.h>
+#include <linux/usb/musb.h>
+#include <plat/ste_dma40.h>
+#include <mach/hardware.h>
+#include <mach/usb.h>
+
+#define MUSB_DMA40_RX_CH { \
+ .mode = STEDMA40_MODE_LOGICAL, \
+ .dir = STEDMA40_PERIPH_TO_MEM, \
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY, \
+ .src_info.data_width = STEDMA40_WORD_WIDTH, \
+ .dst_info.data_width = STEDMA40_WORD_WIDTH, \
+ .src_info.psize = STEDMA40_PSIZE_LOG_16, \
+ .dst_info.psize = STEDMA40_PSIZE_LOG_16, \
+ }
+
+#define MUSB_DMA40_TX_CH { \
+ .mode = STEDMA40_MODE_LOGICAL, \
+ .dir = STEDMA40_MEM_TO_PERIPH, \
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY, \
+ .src_info.data_width = STEDMA40_WORD_WIDTH, \
+ .dst_info.data_width = STEDMA40_WORD_WIDTH, \
+ .src_info.psize = STEDMA40_PSIZE_LOG_16, \
+ .dst_info.psize = STEDMA40_PSIZE_LOG_16, \
+ }
+
+static struct stedma40_chan_cfg musb_dma_rx_ch[UX500_MUSB_DMA_NUM_RX_CHANNELS]
+ = {
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH,
+ MUSB_DMA40_RX_CH
+};
+
+static struct stedma40_chan_cfg musb_dma_tx_ch[UX500_MUSB_DMA_NUM_TX_CHANNELS]
+ = {
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+ MUSB_DMA40_TX_CH,
+};
+
+static void *ux500_dma_rx_param_array[UX500_MUSB_DMA_NUM_RX_CHANNELS] = {
+ &musb_dma_rx_ch[0],
+ &musb_dma_rx_ch[1],
+ &musb_dma_rx_ch[2],
+ &musb_dma_rx_ch[3],
+ &musb_dma_rx_ch[4],
+ &musb_dma_rx_ch[5],
+ &musb_dma_rx_ch[6],
+ &musb_dma_rx_ch[7]
+};
+
+static void *ux500_dma_tx_param_array[UX500_MUSB_DMA_NUM_TX_CHANNELS] = {
+ &musb_dma_tx_ch[0],
+ &musb_dma_tx_ch[1],
+ &musb_dma_tx_ch[2],
+ &musb_dma_tx_ch[3],
+ &musb_dma_tx_ch[4],
+ &musb_dma_tx_ch[5],
+ &musb_dma_tx_ch[6],
+ &musb_dma_tx_ch[7]
+};
+
+static struct ux500_musb_board_data musb_board_data = {
+ .dma_rx_param_array = ux500_dma_rx_param_array,
+ .dma_tx_param_array = ux500_dma_tx_param_array,
+ .num_rx_channels = UX500_MUSB_DMA_NUM_RX_CHANNELS,
+ .num_tx_channels = UX500_MUSB_DMA_NUM_TX_CHANNELS,
+ .dma_filter = stedma40_filter,
+};
+
+static u64 ux500_musb_dmamask = DMA_BIT_MASK(32);
+
+static struct musb_hdrc_config musb_hdrc_config = {
+ .multipoint = true,
+ .dyn_fifo = true,
+ .num_eps = 16,
+ .ram_bits = 16,
+};
+
+static struct musb_hdrc_platform_data musb_platform_data = {
+#if defined(CONFIG_USB_MUSB_OTG)
+ .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+ .mode = MUSB_PERIPHERAL,
+#else /* defined(CONFIG_USB_MUSB_HOST) */
+ .mode = MUSB_HOST,
+#endif
+ .config = &musb_hdrc_config,
+ .board_data = &musb_board_data,
+};
+
+static struct resource usb_resources[] = {
+ [0] = {
+ .name = "usb-mem",
+ .flags = IORESOURCE_MEM,
+ },
+
+ [1] = {
+ .name = "mc", /* hard-coded in musb */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ux500_musb_device = {
+ .name = "musb-ux500",
+ .id = 0,
+ .dev = {
+ .platform_data = &musb_platform_data,
+ .dma_mask = &ux500_musb_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(usb_resources),
+ .resource = usb_resources,
+};
+
+static inline void ux500_usb_dma_update_rx_ch_config(int *src_dev_type)
+{
+ u32 idx;
+
+ for (idx = 0; idx < UX500_MUSB_DMA_NUM_RX_CHANNELS; idx++)
+ musb_dma_rx_ch[idx].src_dev_type = src_dev_type[idx];
+}
+
+static inline void ux500_usb_dma_update_tx_ch_config(int *dst_dev_type)
+{
+ u32 idx;
+
+ for (idx = 0; idx < UX500_MUSB_DMA_NUM_TX_CHANNELS; idx++)
+ musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx];
+}
+
+void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
+ int *dma_tx_cfg)
+{
+ ux500_musb_device.resource[0].start = base;
+ ux500_musb_device.resource[0].end = base + SZ_64K - 1;
+ ux500_musb_device.resource[1].start = irq;
+ ux500_musb_device.resource[1].end = irq;
+
+ ux500_usb_dma_update_rx_ch_config(dma_rx_cfg);
+ ux500_usb_dma_update_tx_ch_config(dma_tx_cfg);
+
+ platform_device_register(&ux500_musb_device);
+}
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 89266382b536..0074b8dba793 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -819,8 +819,8 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
config CACHE_L2X0
bool "Enable the L2x0 outer cache controller"
depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
- REALVIEW_EB_A9MP || ARCH_MX35 || ARCH_MX31 || MACH_REALVIEW_PBX || \
- ARCH_NOMADIK || ARCH_OMAP4 || ARCH_S5PV310 || ARCH_TEGRA || \
+ REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \
+ ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE
default y
select OUTER_CACHE
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index 389f21795015..b0cb4258e382 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -33,6 +33,7 @@ config ARCH_MX3
config ARCH_MXC91231
bool "MXC91231-based"
select CPU_V6
+ select MXC_AVIC
help
This enables support for systems based on the Freescale MXC91231 family
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 5fd20e96876c..a1387875a491 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
obj-$(CONFIG_MXC_PWM) += pwm.o
-obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
obj-$(CONFIG_MXC_ULPI) += ulpi.o
obj-$(CONFIG_MXC_USE_EPIT) += epit.o
obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
diff --git a/arch/arm/plat-mxc/devices.c b/arch/arm/plat-mxc/devices.c
index e9bcefe79a43..eee1b6096a08 100644
--- a/arch/arm/plat-mxc/devices.c
+++ b/arch/arm/plat-mxc/devices.c
@@ -81,6 +81,8 @@ struct platform_device *__init imx_add_platform_device_dmamask(
ret = platform_device_add(pdev);
if (ret) {
err:
+ if (dmamask)
+ kfree(pdev->dev.dma_mask);
platform_device_put(pdev);
return ERR_PTR(ret);
}
diff --git a/arch/arm/plat-mxc/devices/platform-fec.c b/arch/arm/plat-mxc/devices/platform-fec.c
index b50c3517d083..6561c9df5f0d 100644
--- a/arch/arm/plat-mxc/devices/platform-fec.c
+++ b/arch/arm/plat-mxc/devices/platform-fec.c
@@ -31,6 +31,11 @@ const struct imx_fec_data imx35_fec_data __initconst =
imx_fec_data_entry_single(MX35);
#endif
+#ifdef CONFIG_SOC_IMX50
+const struct imx_fec_data imx50_fec_data __initconst =
+ imx_fec_data_entry_single(MX50);
+#endif
+
#ifdef CONFIG_SOC_IMX51
const struct imx_fec_data imx51_fec_data __initconst =
imx_fec_data_entry_single(MX51);
@@ -57,7 +62,7 @@ struct platform_device *__init imx_add_fec(
},
};
- return imx_add_platform_device("fec", 0 /* -1? */,
+ return imx_add_platform_device_dmamask("fec", 0,
res, ARRAY_SIZE(res),
- pdata, sizeof(*pdata));
+ pdata, sizeof(*pdata), DMA_BIT_MASK(32));
}
diff --git a/arch/arm/plat-mxc/devices/platform-imx-dma.c b/arch/arm/plat-mxc/devices/platform-imx-dma.c
index 33530d2d5ed1..3538b85ede91 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-dma.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-dma.c
@@ -94,7 +94,7 @@ static struct sdma_script_start_addrs addr_imx25_to1 = {
};
#endif
-#ifdef CONFIG_ARCH_MX31
+#ifdef CONFIG_SOC_IMX31
static struct sdma_script_start_addrs addr_imx31_to1 = {
.per_2_per_addr = 1677,
};
@@ -106,7 +106,7 @@ static struct sdma_script_start_addrs addr_imx31_to2 = {
};
#endif
-#ifdef CONFIG_ARCH_MX35
+#ifdef CONFIG_SOC_IMX35
static struct sdma_script_start_addrs addr_imx35_to1 = {
.ap_2_ap_addr = 642,
.uart_2_mcu_addr = 817,
@@ -194,7 +194,7 @@ static int __init imxXX_add_imx_dma(void)
} else
#endif
-#if defined(CONFIG_ARCH_MX51)
+#if defined(CONFIG_SOC_IMX51)
if (cpu_is_mx51()) {
imx51_imx_sdma_data.pdata.script_addrs = &addr_imx51_to1;
ret = imx_add_imx_sdma(&imx51_imx_sdma_data);
diff --git a/arch/arm/plat-mxc/devices/platform-imx-fb.c b/arch/arm/plat-mxc/devices/platform-imx-fb.c
index 6100a7d824dd..79a1cb18a5b0 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-fb.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-fb.c
@@ -16,6 +16,11 @@
.irq = soc ## _INT_LCDC, \
}
+#ifdef CONFIG_SOC_IMX1
+const struct imx_imx_fb_data imx1_imx_fb_data __initconst =
+ imx_imx_fb_data_entry_single(MX1, SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX1 */
+
#ifdef CONFIG_SOC_IMX21
const struct imx_imx_fb_data imx21_imx_fb_data __initconst =
imx_imx_fb_data_entry_single(MX21, SZ_4K);
diff --git a/arch/arm/plat-mxc/devices/platform-imx-i2c.c b/arch/arm/plat-mxc/devices/platform-imx-i2c.c
index 7ba94e1bbda3..2ab74f0da9a6 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-i2c.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-i2c.c
@@ -69,6 +69,16 @@ const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX35 */
+#ifdef CONFIG_SOC_IMX50
+const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst = {
+#define imx50_imx_i2c_data_entry(_id, _hwid) \
+ imx_imx_i2c_data_entry(MX50, _id, _hwid, SZ_4K)
+ imx50_imx_i2c_data_entry(0, 1),
+ imx50_imx_i2c_data_entry(1, 2),
+ imx50_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_SOC_IMX51 */
+
#ifdef CONFIG_SOC_IMX51
const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = {
#define imx51_imx_i2c_data_entry(_id, _hwid) \
diff --git a/arch/arm/plat-mxc/devices/platform-imx2-wdt.c b/arch/arm/plat-mxc/devices/platform-imx2-wdt.c
index e0aec61177f4..5e07ef2bf1c4 100644
--- a/arch/arm/plat-mxc/devices/platform-imx2-wdt.c
+++ b/arch/arm/plat-mxc/devices/platform-imx2-wdt.c
@@ -53,6 +53,15 @@ const struct imx_imx2_wdt_data imx51_imx2_wdt_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX51 */
+#ifdef CONFIG_SOC_IMX53
+const struct imx_imx2_wdt_data imx53_imx2_wdt_data[] __initconst = {
+#define imx53_imx2_wdt_data_entry(_id, _hwid) \
+ imx_imx2_wdt_data_entry(MX53, _id, _hwid, SZ_16K)
+ imx53_imx2_wdt_data_entry(0, 1),
+ imx53_imx2_wdt_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
struct platform_device *__init imx_add_imx2_wdt(
const struct imx_imx2_wdt_data *data)
{
diff --git a/arch/arm/plat-mxc/devices/platform-spi_imx.c b/arch/arm/plat-mxc/devices/platform-spi_imx.c
index 013c85f20b58..f4a60ab6763b 100644
--- a/arch/arm/plat-mxc/devices/platform-spi_imx.c
+++ b/arch/arm/plat-mxc/devices/platform-spi_imx.c
@@ -21,6 +21,15 @@
#define imx_spi_imx_data_entry(soc, type, devid, id, hwid, size) \
[id] = imx_spi_imx_data_entry_single(soc, type, devid, id, hwid, size)
+#ifdef CONFIG_SOC_IMX1
+const struct imx_spi_imx_data imx1_cspi_data[] __initconst = {
+#define imx1_cspi_data_entry(_id, _hwid) \
+ imx_spi_imx_data_entry(MX1, CSPI, "imx1-cspi", _id, _hwid, SZ_4K)
+ imx1_cspi_data_entry(0, 1),
+ imx1_cspi_data_entry(1, 2),
+};
+#endif
+
#ifdef CONFIG_SOC_IMX21
const struct imx_spi_imx_data imx21_cspi_data[] __initconst = {
#define imx21_cspi_data_entry(_id, _hwid) \
diff --git a/arch/arm/plat-mxc/ehci.c b/arch/arm/plat-mxc/ehci.c
deleted file mode 100644
index 8772ce346a58..000000000000
--- a/arch/arm/plat-mxc/ehci.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
- * Copyright (C) 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 the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/mxc_ehci.h>
-
-#define USBCTRL_OTGBASE_OFFSET 0x600
-
-#define MX31_OTG_SIC_SHIFT 29
-#define MX31_OTG_SIC_MASK (0x3 << MX31_OTG_SIC_SHIFT)
-#define MX31_OTG_PM_BIT (1 << 24)
-
-#define MX31_H2_SIC_SHIFT 21
-#define MX31_H2_SIC_MASK (0x3 << MX31_H2_SIC_SHIFT)
-#define MX31_H2_PM_BIT (1 << 16)
-#define MX31_H2_DT_BIT (1 << 5)
-
-#define MX31_H1_SIC_SHIFT 13
-#define MX31_H1_SIC_MASK (0x3 << MX31_H1_SIC_SHIFT)
-#define MX31_H1_PM_BIT (1 << 8)
-#define MX31_H1_DT_BIT (1 << 4)
-
-#define MX35_OTG_SIC_SHIFT 29
-#define MX35_OTG_SIC_MASK (0x3 << MX35_OTG_SIC_SHIFT)
-#define MX35_OTG_PM_BIT (1 << 24)
-
-#define MX35_H1_SIC_SHIFT 21
-#define MX35_H1_SIC_MASK (0x3 << MX35_H1_SIC_SHIFT)
-#define MX35_H1_PM_BIT (1 << 8)
-#define MX35_H1_IPPUE_UP_BIT (1 << 7)
-#define MX35_H1_IPPUE_DOWN_BIT (1 << 6)
-#define MX35_H1_TLL_BIT (1 << 5)
-#define MX35_H1_USBTE_BIT (1 << 4)
-
-#define MXC_OTG_OFFSET 0
-#define MXC_H1_OFFSET 0x200
-#define MXC_H2_OFFSET 0x400
-
-/* USB_CTRL */
-#define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) /* OTG wakeup intr enable */
-#define MXC_OTG_UCTRL_OPM_BIT (1 << 24) /* OTG power mask */
-#define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) /* Host1 ULPI interrupt enable */
-#define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) /* HOST1 wakeup intr enable */
-#define MXC_H1_UCTRL_H1PM_BIT (1 << 8) /* HOST1 power mask */
-
-/* USB_PHY_CTRL_FUNC */
-#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
-#define MXC_H1_OC_DIS_BIT (1 << 5) /* UH1 Disable Overcurrent Event */
-
-/* USBH2CTRL */
-#define MXC_H2_UCTRL_H2UIE_BIT (1 << 8)
-#define MXC_H2_UCTRL_H2WIE_BIT (1 << 7)
-#define MXC_H2_UCTRL_H2PM_BIT (1 << 4)
-
-#define MXC_USBCMD_OFFSET 0x140
-
-/* USBCMD */
-#define MXC_UCMD_ITC_NO_THRESHOLD_MASK (~(0xff << 16)) /* Interrupt Threshold Control */
-
-int mxc_initialize_usb_hw(int port, unsigned int flags)
-{
- unsigned int v;
-#if defined(CONFIG_SOC_IMX25)
- if (cpu_is_mx25()) {
- v = readl(MX25_IO_ADDRESS(MX25_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
-
- switch (port) {
- case 0: /* OTG port */
- v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX35_OTG_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX35_OTG_PM_BIT;
-
- break;
- case 1: /* H1 port */
- v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT |
- MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX35_H1_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX35_H1_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX35_H1_TLL_BIT;
-
- if (flags & MXC_EHCI_INTERNAL_PHY)
- v |= MX35_H1_USBTE_BIT;
-
- if (flags & MXC_EHCI_IPPUE_DOWN)
- v |= MX35_H1_IPPUE_DOWN_BIT;
-
- if (flags & MXC_EHCI_IPPUE_UP)
- v |= MX35_H1_IPPUE_UP_BIT;
-
- break;
- default:
- return -EINVAL;
- }
-
- writel(v, MX25_IO_ADDRESS(MX25_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
- return 0;
- }
-#endif /* if defined(CONFIG_SOC_IMX25) */
-#if defined(CONFIG_ARCH_MX3)
- if (cpu_is_mx31()) {
- v = readl(MX31_IO_ADDRESS(MX31_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
-
- switch (port) {
- case 0: /* OTG port */
- v &= ~(MX31_OTG_SIC_MASK | MX31_OTG_PM_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_OTG_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_OTG_PM_BIT;
-
- break;
- case 1: /* H1 port */
- v &= ~(MX31_H1_SIC_MASK | MX31_H1_PM_BIT | MX31_H1_DT_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_H1_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_H1_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX31_H1_DT_BIT;
-
- break;
- case 2: /* H2 port */
- v &= ~(MX31_H2_SIC_MASK | MX31_H2_PM_BIT | MX31_H2_DT_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_H2_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_H2_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX31_H2_DT_BIT;
-
- break;
- default:
- return -EINVAL;
- }
-
- writel(v, MX31_IO_ADDRESS(MX31_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
- return 0;
- }
-
- if (cpu_is_mx35()) {
- v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
-
- switch (port) {
- case 0: /* OTG port */
- v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX35_OTG_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX35_OTG_PM_BIT;
-
- break;
- case 1: /* H1 port */
- v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT |
- MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX35_H1_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX35_H1_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX35_H1_TLL_BIT;
-
- if (flags & MXC_EHCI_INTERNAL_PHY)
- v |= MX35_H1_USBTE_BIT;
-
- if (flags & MXC_EHCI_IPPUE_DOWN)
- v |= MX35_H1_IPPUE_DOWN_BIT;
-
- if (flags & MXC_EHCI_IPPUE_UP)
- v |= MX35_H1_IPPUE_UP_BIT;
-
- break;
- default:
- return -EINVAL;
- }
-
- writel(v, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
- return 0;
- }
-#endif /* CONFIG_ARCH_MX3 */
-#ifdef CONFIG_MACH_MX27
- if (cpu_is_mx27()) {
- /* On i.MX27 we can use the i.MX31 USBCTRL bits, they
- * are identical
- */
- v = readl(MX27_IO_ADDRESS(MX27_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
- switch (port) {
- case 0: /* OTG port */
- v &= ~(MX31_OTG_SIC_MASK | MX31_OTG_PM_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_OTG_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_OTG_PM_BIT;
- break;
- case 1: /* H1 port */
- v &= ~(MX31_H1_SIC_MASK | MX31_H1_PM_BIT | MX31_H1_DT_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_H1_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_H1_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX31_H1_DT_BIT;
-
- break;
- case 2: /* H2 port */
- v &= ~(MX31_H2_SIC_MASK | MX31_H2_PM_BIT | MX31_H2_DT_BIT);
- v |= (flags & MXC_EHCI_INTERFACE_MASK)
- << MX31_H2_SIC_SHIFT;
- if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
- v |= MX31_H2_PM_BIT;
-
- if (!(flags & MXC_EHCI_TTL_ENABLED))
- v |= MX31_H2_DT_BIT;
-
- break;
- default:
- return -EINVAL;
- }
- writel(v, MX27_IO_ADDRESS(MX27_USB_BASE_ADDR +
- USBCTRL_OTGBASE_OFFSET));
- return 0;
- }
-#endif /* CONFIG_MACH_MX27 */
-#ifdef CONFIG_SOC_IMX51
- if (cpu_is_mx51()) {
- void __iomem *usb_base;
- void __iomem *usbotg_base;
- void __iomem *usbother_base;
- int ret = 0;
-
- usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
- if (!usb_base) {
- printk(KERN_ERR "%s(): ioremap failed\n", __func__);
- return -ENOMEM;
- }
-
- switch (port) {
- case 0: /* OTG port */
- usbotg_base = usb_base + MXC_OTG_OFFSET;
- break;
- case 1: /* Host 1 port */
- usbotg_base = usb_base + MXC_H1_OFFSET;
- break;
- case 2: /* Host 2 port */
- usbotg_base = usb_base + MXC_H2_OFFSET;
- break;
- default:
- printk(KERN_ERR"%s no such port %d\n", __func__, port);
- ret = -ENOENT;
- goto error;
- }
- usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
- switch (port) {
- case 0: /*OTG port */
- if (flags & MXC_EHCI_INTERNAL_PHY) {
- v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
-
- if (flags & MXC_EHCI_POWER_PINS_ENABLED) {
- /* OC/USBPWR is not used */
- v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
- } else {
- /* OC/USBPWR is used */
- v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
- }
- __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
-
- v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
- if (flags & MXC_EHCI_WAKEUP_ENABLED)
- v |= MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup enable */
- else
- v &= ~MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup disable */
- if (flags & MXC_EHCI_POWER_PINS_ENABLED)
- v |= MXC_OTG_UCTRL_OPM_BIT;
- else
- v &= ~MXC_OTG_UCTRL_OPM_BIT;
- __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
- }
- break;
- case 1: /* Host 1 */
- /*Host ULPI */
- v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
- if (flags & MXC_EHCI_WAKEUP_ENABLED) {
- /* HOST1 wakeup/ULPI intr enable */
- v |= (MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);
- } else {
- /* HOST1 wakeup/ULPI intr disable */
- v &= ~(MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT);
- }
-
- if (flags & MXC_EHCI_POWER_PINS_ENABLED)
- v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
- else
- v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
- __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
-
- v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
- if (flags & MXC_EHCI_POWER_PINS_ENABLED)
- v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
- else
- v |= MXC_H1_OC_DIS_BIT; /* OC is not used */
- __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
-
- v = __raw_readl(usbotg_base + MXC_USBCMD_OFFSET);
- if (flags & MXC_EHCI_ITC_NO_THRESHOLD)
- /* Interrupt Threshold Control:Immediate (no threshold) */
- v &= MXC_UCMD_ITC_NO_THRESHOLD_MASK;
- __raw_writel(v, usbotg_base + MXC_USBCMD_OFFSET);
- break;
- case 2: /* Host 2 ULPI */
- v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET);
- if (flags & MXC_EHCI_WAKEUP_ENABLED) {
- /* HOST1 wakeup/ULPI intr enable */
- v |= (MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT);
- } else {
- /* HOST1 wakeup/ULPI intr disable */
- v &= ~(MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT);
- }
-
- if (flags & MXC_EHCI_POWER_PINS_ENABLED)
- v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
- else
- v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
- __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
- break;
- }
-
-error:
- iounmap(usb_base);
- return ret;
- }
-#endif
- printk(KERN_WARNING
- "%s() unable to setup USBCONTROL for this CPU\n", __func__);
- return -EINVAL;
-}
-EXPORT_SYMBOL(mxc_initialize_usb_hw);
-
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c
index d17b3c996b84..57d59855f9ec 100644
--- a/arch/arm/plat-mxc/gpio.c
+++ b/arch/arm/plat-mxc/gpio.c
@@ -233,6 +233,7 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
}
static struct irq_chip gpio_irq_chip = {
+ .name = "GPIO",
.irq_ack = gpio_ack_irq,
.irq_mask = gpio_mask_irq,
.irq_unmask = gpio_unmask_irq,
@@ -349,113 +350,3 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
return 0;
}
-
-#define DEFINE_IMX_GPIO_PORT_IRQ_HIGH(soc, _id, _hwid, _irq, _irq_high) \
- { \
- .chip.label = "gpio-" #_id, \
- .irq = _irq, \
- .irq_high = _irq_high, \
- .base = soc ## _IO_ADDRESS( \
- soc ## _GPIO ## _hwid ## _BASE_ADDR), \
- .virtual_irq_start = MXC_GPIO_IRQ_START + (_id) * 32, \
- }
-
-#define DEFINE_IMX_GPIO_PORT_IRQ(soc, _id, _hwid, _irq) \
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(soc, _id, _hwid, _irq, 0)
-#define DEFINE_IMX_GPIO_PORT(soc, _id, _hwid) \
- DEFINE_IMX_GPIO_PORT_IRQ(soc, _id, _hwid, 0)
-
-#define DEFINE_REGISTER_FUNCTION(prefix) \
-int __init prefix ## _register_gpios(void) \
-{ \
- return mxc_gpio_init(prefix ## _gpio_ports, \
- ARRAY_SIZE(prefix ## _gpio_ports)); \
-}
-
-#if defined(CONFIG_SOC_IMX1)
-static struct mxc_gpio_port imx1_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX1, 0, 1, MX1_GPIO_INT_PORTA),
- DEFINE_IMX_GPIO_PORT_IRQ(MX1, 1, 2, MX1_GPIO_INT_PORTB),
- DEFINE_IMX_GPIO_PORT_IRQ(MX1, 2, 3, MX1_GPIO_INT_PORTC),
- DEFINE_IMX_GPIO_PORT_IRQ(MX1, 3, 4, MX1_GPIO_INT_PORTD),
-};
-
-DEFINE_REGISTER_FUNCTION(imx1)
-
-#endif /* if defined(CONFIG_SOC_IMX1) */
-
-#if defined(CONFIG_SOC_IMX21)
-static struct mxc_gpio_port imx21_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX21, 0, 1, MX21_INT_GPIO),
- DEFINE_IMX_GPIO_PORT(MX21, 1, 2),
- DEFINE_IMX_GPIO_PORT(MX21, 2, 3),
- DEFINE_IMX_GPIO_PORT(MX21, 3, 4),
- DEFINE_IMX_GPIO_PORT(MX21, 4, 5),
- DEFINE_IMX_GPIO_PORT(MX21, 5, 6),
-};
-
-DEFINE_REGISTER_FUNCTION(imx21)
-
-#endif /* if defined(CONFIG_SOC_IMX21) */
-
-#if defined(CONFIG_SOC_IMX25)
-static struct mxc_gpio_port imx25_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX25, 0, 1, MX25_INT_GPIO1),
- DEFINE_IMX_GPIO_PORT_IRQ(MX25, 1, 2, MX25_INT_GPIO2),
- DEFINE_IMX_GPIO_PORT_IRQ(MX25, 2, 3, MX25_INT_GPIO3),
- DEFINE_IMX_GPIO_PORT_IRQ(MX25, 3, 4, MX25_INT_GPIO4),
-};
-
-DEFINE_REGISTER_FUNCTION(imx25)
-
-#endif /* if defined(CONFIG_SOC_IMX25) */
-
-#if defined(CONFIG_SOC_IMX27)
-static struct mxc_gpio_port imx27_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX27, 0, 1, MX27_INT_GPIO),
- DEFINE_IMX_GPIO_PORT(MX27, 1, 2),
- DEFINE_IMX_GPIO_PORT(MX27, 2, 3),
- DEFINE_IMX_GPIO_PORT(MX27, 3, 4),
- DEFINE_IMX_GPIO_PORT(MX27, 4, 5),
- DEFINE_IMX_GPIO_PORT(MX27, 5, 6),
-};
-
-DEFINE_REGISTER_FUNCTION(imx27)
-
-#endif /* if defined(CONFIG_SOC_IMX27) */
-
-#if defined(CONFIG_SOC_IMX31)
-static struct mxc_gpio_port imx31_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 0, 1, MX31_INT_GPIO1),
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 1, 2, MX31_INT_GPIO2),
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 2, 3, MX31_INT_GPIO3),
-};
-
-DEFINE_REGISTER_FUNCTION(imx31)
-
-#endif /* if defined(CONFIG_SOC_IMX31) */
-
-#if defined(CONFIG_SOC_IMX35)
-static struct mxc_gpio_port imx35_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 0, 1, MX35_INT_GPIO1),
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 1, 2, MX35_INT_GPIO2),
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 2, 3, MX35_INT_GPIO3),
-};
-
-DEFINE_REGISTER_FUNCTION(imx35)
-
-#endif /* if defined(CONFIG_SOC_IMX35) */
-
-#if defined(CONFIG_SOC_IMX50)
-static struct mxc_gpio_port imx50_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 0, 1, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH),
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 1, 2, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH),
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 2, 3, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 3, 4, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 4, 5, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
- DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 5, 6, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH),
-};
-
-DEFINE_REGISTER_FUNCTION(imx50)
-
-#endif /* if defined(CONFIG_SOC_IMX50) */
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index aea2cd3b6d15..a22ebe11a602 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -24,6 +24,16 @@ extern void mx50_map_io(void);
extern void mx51_map_io(void);
extern void mx53_map_io(void);
extern void mxc91231_map_io(void);
+extern void imx1_init_early(void);
+extern void imx21_init_early(void);
+extern void imx25_init_early(void);
+extern void imx27_init_early(void);
+extern void imx31_init_early(void);
+extern void imx35_init_early(void);
+extern void imx50_init_early(void);
+extern void imx51_init_early(void);
+extern void imx53_init_early(void);
+extern void mxc91231_init_early(void);
extern void mxc_init_irq(void __iomem *);
extern void tzic_init_irq(void __iomem *);
extern void mx1_init_irq(void);
diff --git a/arch/arm/plat-mxc/include/mach/gpio.h b/arch/arm/plat-mxc/include/mach/gpio.h
index 0044e2f1bea8..a2747f12813e 100644
--- a/arch/arm/plat-mxc/include/mach/gpio.h
+++ b/arch/arm/plat-mxc/include/mach/gpio.h
@@ -46,6 +46,21 @@ struct mxc_gpio_port {
spinlock_t lock;
};
+#define DEFINE_IMX_GPIO_PORT_IRQ_HIGH(soc, _id, _hwid, _irq, _irq_high) \
+ { \
+ .chip.label = "gpio-" #_id, \
+ .irq = _irq, \
+ .irq_high = _irq_high, \
+ .base = soc ## _IO_ADDRESS( \
+ soc ## _GPIO ## _hwid ## _BASE_ADDR), \
+ .virtual_irq_start = MXC_GPIO_IRQ_START + (_id) * 32, \
+ }
+
+#define DEFINE_IMX_GPIO_PORT_IRQ(soc, _id, _hwid, _irq) \
+ DEFINE_IMX_GPIO_PORT_IRQ_HIGH(soc, _id, _hwid, _irq, 0)
+#define DEFINE_IMX_GPIO_PORT(soc, _id, _hwid) \
+ DEFINE_IMX_GPIO_PORT_IRQ(soc, _id, _hwid, 0)
+
int mxc_gpio_init(struct mxc_gpio_port*, int);
#endif
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx3.h b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
index cbaed295a2bf..c92f0b1f216f 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx3.h
@@ -112,12 +112,12 @@ enum iomux_gp_func {
* - setups the iomux according to the configuration
* - if the pin is configured as a GPIO, we claim it through kernel gpiolib
*/
-int mxc_iomux_alloc_pin(const unsigned int pin, const char *label);
+int mxc_iomux_alloc_pin(unsigned int pin, const char *label);
/*
* setups mutliple pins
* convenient way to call the above function with tables
*/
-int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
+int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
const char *label);
/*
@@ -126,12 +126,12 @@ int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
* - frees the GPIO if the pin was configured as GPIO
* - DOES NOT reconfigure the IOMUX in its reset state
*/
-void mxc_iomux_release_pin(const unsigned int pin);
+void mxc_iomux_release_pin(unsigned int pin);
/*
* releases multiple pins
* convenvient way to call the above function with tables
*/
-void mxc_iomux_release_multiple_pins(unsigned int *pin_list, int count);
+void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count);
/*
* This function enables/disables the general purpose function for a particular
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx35.h b/arch/arm/plat-mxc/include/mach/iomux-mx35.h
index 2a24bae1b878..3117c18bbbd9 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx35.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx35.h
@@ -989,13 +989,13 @@
#define MX35_PAD_ATA_DATA2__IPU_DIAGB_9 IOMUX_PAD(0x6e8, 0x284, 6, 0x0, 0, NO_PAD_CTRL)
#define MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28 IOMUX_PAD(0x6e8, 0x284, 7, 0x0, 0, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__ATA_DATA_3 IOMUX_PAD(0x6e8, 0x288, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__ESDHC3_CLK IOMUX_PAD(0x6e8, 0x288, 1, 0x814, 1, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5 IOMUX_PAD(0x6e8, 0x288, 2, 0x9b8, 1, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__CSPI2_SCLK IOMUX_PAD(0x6e8, 0x288, 4, 0x7e0, 2, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__GPIO2_16 IOMUX_PAD(0x6e8, 0x288, 5, 0x884, 1, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__IPU_DIAGB_10 IOMUX_PAD(0x6e8, 0x288, 6, 0x0, 0, NO_PAD_CTRL)
-#define MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29 IOMUX_PAD(0x6e8, 0x288, 7, 0x0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ATA_DATA_3 IOMUX_PAD(0x6ec, 0x288, 0, 0x0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ESDHC3_CLK IOMUX_PAD(0x6ec, 0x288, 1, 0x814, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5 IOMUX_PAD(0x6ec, 0x288, 2, 0x9b8, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__CSPI2_SCLK IOMUX_PAD(0x6ec, 0x288, 4, 0x7e0, 2, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__GPIO2_16 IOMUX_PAD(0x6ec, 0x288, 5, 0x884, 1, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__IPU_DIAGB_10 IOMUX_PAD(0x6ec, 0x288, 6, 0x0, 0, NO_PAD_CTRL)
+#define MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29 IOMUX_PAD(0x6ec, 0x288, 7, 0x0, 0, NO_PAD_CTRL)
#define MX35_PAD_ATA_DATA4__ATA_DATA_4 IOMUX_PAD(0x6f0, 0x28c, 0, 0x0, 0, NO_PAD_CTRL)
#define MX35_PAD_ATA_DATA4__ESDHC3_CMD IOMUX_PAD(0x6f0, 0x28c, 1, 0x818, 1, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx50.h b/arch/arm/plat-mxc/include/mach/iomux-mx50.h
index 058a922ca147..98e7fd0b9083 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx50.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx50.h
@@ -86,7 +86,7 @@
#define MX50_PAD_I2C1_SCL__I2C1_SCL IOMUX_PAD(0x2EC, 0x40, IOMUX_CONFIG_SION, 0x0, 0, \
MX50_I2C_PAD_CTRL)
#define MX50_PAD_I2C1_SCL__GPIO_6_18 IOMUX_PAD(0x2EC, 0x40, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C1_SCL__UART2_TXD IOMUX_PAD(0x2EC, 0x40, 2, 0x7cc, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_I2C1_SCL__UART2_TXD IOMUX_PAD(0x2EC, 0x40, 2, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_I2C1_SDA__I2C1_SDA IOMUX_PAD(0x2F0, 0x44, IOMUX_CONFIG_SION, 0x0, 0, \
MX50_I2C_PAD_CTRL)
@@ -96,7 +96,7 @@
#define MX50_PAD_I2C2_SCL__I2C2_SCL IOMUX_PAD(0x2F4, 0x48, IOMUX_CONFIG_SION, 0x0, 0, \
MX50_I2C_PAD_CTRL)
#define MX50_PAD_I2C2_SCL__GPIO_6_20 IOMUX_PAD(0x2F4, 0x48, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_I2C2_SCL__UART2_CTS IOMUX_PAD(0x2F4, 0x48, 2, 0x7c8, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_I2C2_SCL__UART2_CTS IOMUX_PAD(0x2F4, 0x48, 2, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_I2C2_SCL__DCDC_OK IOMUX_PAD(0x2F4, 0x48, 7, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_I2C2_SDA__I2C2_SDA IOMUX_PAD(0x2F8, 0x4C, IOMUX_CONFIG_SION, 0x0, 0, \
@@ -172,7 +172,7 @@
#define MX50_PAD_SSI_RXFS__AUD3_RXFS IOMUX_PAD(0x328, 0x7C, 0, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_SSI_RXFS__GPIO_6_4 IOMUX_PAD(0x328, 0x7C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_SSI_RXFS__UART5_TXD IOMUX_PAD(0x328, 0x7C, 2, 0x7e4, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_SSI_RXFS__UART5_TXD IOMUX_PAD(0x328, 0x7C, 2, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_SSI_RXFS__WEIM_D6 IOMUX_PAD(0x328, 0x7C, 3, 0x804, 0, NO_PAD_CTRL)
#define MX50_PAD_SSI_RXFS__CSPI_SS2 IOMUX_PAD(0x328, 0x7C, 4, 0x6f0, 0, MX50_CSPI_SS_PAD)
#define MX50_PAD_SSI_RXFS__FEC_COL IOMUX_PAD(0x328, 0x7C, 5, 0x770, 0, PAD_CTL_DSE_HIGH)
@@ -186,25 +186,25 @@
#define MX50_PAD_SSI_RXC__FEC_RX_CLK IOMUX_PAD(0x32C, 0x80, 5, 0x780, 0, NO_PAD_CTRL)
#define MX50_PAD_SSI_RXC__FEC_MDIO IOMUX_PAD(0x32C, 0x80, 6, 0x774, 1, MX50_FEC_PAD_CTRL)
-#define MX50_PAD_UART1_TXD__UART1_TXD IOMUX_PAD(0x330, 0x84, 0, 0x7c4, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART1_TXD__UART1_TXD IOMUX_PAD(0x330, 0x84, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART1_TXD__GPIO_6_6 IOMUX_PAD(0x330, 0x84, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_UART1_RXD__UART1_RXD IOMUX_PAD(0x334, 0x88, 0, 0x7c4, 1, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART1_RXD__GPIO_6_7 IOMUX_PAD(0x334, 0x88, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__UART1_CTS IOMUX_PAD(0x338, 0x8C, 0, 0x7c0, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART1_CTS__UART1_CTS IOMUX_PAD(0x338, 0x8C, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART1_CTS__GPIO_6_8 IOMUX_PAD(0x338, 0x8C, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART1_CTS__UART5_TXD IOMUX_PAD(0x338, 0x8C, 2, 0x7e4, 2, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART1_CTS__UART5_TXD IOMUX_PAD(0x338, 0x8C, 2, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART1_CTS__SD4_D4 IOMUX_PAD(0x338, 0x8C, 4, 0x760, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART1_CTS__SD4_CMD IOMUX_PAD(0x338, 0x8C, 5, 0x74c, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART1_RTS__UART1_RTS IOMUX_PAD(0x33C, 0x90, 0, 0x7c0, 1, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART1_RTS__GPIO_6_9 IOMUX_PAD(0x33C, 0x90, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_UART1_RTS__UART5_RXD IOMUX_PAD(0x33C, 0x90, 2, 0x7e4, 3, MX50_UART_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__SD4_D5 IOMUX_PAD(0x33C, 0x90, 4, 0x0, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART1_RTS__SD4_CLK IOMUX_PAD(0x33C, 0x90, 5, 0x0, 1, MX50_SD_PAD_CTRL)
+#define MX50_PAD_UART1_RTS__SD4_D5 IOMUX_PAD(0x33C, 0x90, 4, 0x764, 0, MX50_SD_PAD_CTRL)
+#define MX50_PAD_UART1_RTS__SD4_CLK IOMUX_PAD(0x33C, 0x90, 5, 0x748, 0, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(0x340, 0x94, 0, 0x7cc, 2, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(0x340, 0x94, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART2_TXD__GPIO_6_10 IOMUX_PAD(0x340, 0x94, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_UART2_TXD__SD4_D6 IOMUX_PAD(0x340, 0x94, 4, 0x768, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART2_TXD__SD4_D4 IOMUX_PAD(0x340, 0x94, 5, 0x760, 1, MX50_SD_PAD_CTRL)
@@ -214,7 +214,7 @@
#define MX50_PAD_UART2_RXD__SD4_D7 IOMUX_PAD(0x344, 0x98, 4, 0x76c, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART2_RXD__SD4_D5 IOMUX_PAD(0x344, 0x98, 5, 0x764, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART2_CTS__UART2_CTS IOMUX_PAD(0x348, 0x9C, 0, 0x7c8, 2, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART2_CTS__UART2_CTS IOMUX_PAD(0x348, 0x9C, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART2_CTS__GPIO_6_12 IOMUX_PAD(0x348, 0x9C, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_UART2_CTS__SD4_CMD IOMUX_PAD(0x348, 0x9C, 4, 0x74c, 1, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART2_CTS__SD4_D6 IOMUX_PAD(0x348, 0x9C, 5, 0x768, 1, MX50_SD_PAD_CTRL)
@@ -224,7 +224,7 @@
#define MX50_PAD_UART2_RTS__SD4_CLK IOMUX_PAD(0x34C, 0xA0, 4, 0x748, 1, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART2_RTS__SD4_D7 IOMUX_PAD(0x34C, 0xA0, 5, 0x76c, 1, MX50_SD_PAD_CTRL)
-#define MX50_PAD_UART3_TXD__UART3_TXD IOMUX_PAD(0x350, 0xA4, 0, 0x7d4, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART3_TXD__UART3_TXD IOMUX_PAD(0x350, 0xA4, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART3_TXD__GPIO_6_14 IOMUX_PAD(0x350, 0xA4, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_UART3_TXD__SD1_D4 IOMUX_PAD(0x350, 0xA4, 3, 0x0, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART3_TXD__SD4_D0 IOMUX_PAD(0x350, 0xA4, 4, 0x750, 0, MX50_SD_PAD_CTRL)
@@ -238,9 +238,9 @@
#define MX50_PAD_UART3_RXD__SD2_CD IOMUX_PAD(0x354, 0xA8, 5, 0x740, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART3_RXD__WEIM_D13 IOMUX_PAD(0x354, 0xA8, 6, 0x820, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__UART4_TXD IOMUX_PAD(0x358, 0xAC, 0, 0x7dc, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART4_TXD__UART4_TXD IOMUX_PAD(0x358, 0xAC, 0, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART4_TXD__GPIO_6_16 IOMUX_PAD(0x358, 0xAC, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_UART4_TXD__UART3_CTS IOMUX_PAD(0x358, 0xAC, 2, 0x7d0, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_UART4_TXD__UART3_CTS IOMUX_PAD(0x358, 0xAC, 2, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_UART4_TXD__SD1_D6 IOMUX_PAD(0x358, 0xAC, 3, 0x0, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART4_TXD__SD4_D2 IOMUX_PAD(0x358, 0xAC, 4, 0x758, 0, MX50_SD_PAD_CTRL)
#define MX50_PAD_UART4_TXD__SD2_LCTL IOMUX_PAD(0x358, 0xAC, 5, 0x0, 0, MX50_SD_PAD_CTRL)
@@ -278,7 +278,7 @@
#define MX50_PAD_ECSPI1_MOSI__GPIO_4_13 IOMUX_PAD(0x374, 0xC8, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI1_MOSI__CSPI_SS1 IOMUX_PAD(0x374, 0xC8, 2, 0x6ec, 1, MX50_CSPI_SS_PAD)
#define MX50_PAD_ECSPI1_MOSI__ECSPI2_SS1 IOMUX_PAD(0x374, 0xC8, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_MOSI__UART3_CTS IOMUX_PAD(0x374, 0xC8, 4, 0x7d0, 3, MX50_UART_PAD_CTRL)
+#define MX50_PAD_ECSPI1_MOSI__UART3_CTS IOMUX_PAD(0x374, 0xC8, 4, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_ECSPI1_MOSI__EPDC_SDCE7 IOMUX_PAD(0x374, 0xC8, 5, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI1_MOSI__WEIM_D9 IOMUX_PAD(0x374, 0xC8, 7, 0x810, 0, NO_PAD_CTRL)
@@ -294,7 +294,7 @@
#define MX50_PAD_ECSPI1_SS0__GPIO_4_15 IOMUX_PAD(0x37C, 0xD0, 1, 0x0, 0, PAD_CTL_PUS_100K_UP)
#define MX50_PAD_ECSPI1_SS0__CSPI_SS3 IOMUX_PAD(0x37C, 0xD0, 2, 0x6f4, 1, MX50_CSPI_SS_PAD)
#define MX50_PAD_ECSPI1_SS0__ECSPI2_SS3 IOMUX_PAD(0x37C, 0xD0, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI1_SS0__UART4_CTS IOMUX_PAD(0x37C, 0xD0, 4, 0x7d8, 1, MX50_UART_PAD_CTRL)
+#define MX50_PAD_ECSPI1_SS0__UART4_CTS IOMUX_PAD(0x37C, 0xD0, 4, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_ECSPI1_SS0__EPDC_SDCE9 IOMUX_PAD(0x37C, 0xD0, 5, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI1_SS0__WEIM_D11 IOMUX_PAD(0x37C, 0xD0, 7, 0x818, 0, NO_PAD_CTRL)
@@ -311,17 +311,17 @@
#define MX50_PAD_ECSPI2_MOSI__GPIO_4_17 IOMUX_PAD(0x384, 0xD8, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MOSI__ELCDIF_RD IOMUX_PAD(0x384, 0xD8, 2, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MOSI__ECSPI1_SS1 IOMUX_PAD(0x384, 0xD8, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_MOSI__UART5_CTS IOMUX_PAD(0x384, 0xD8, 4, 0x7e0, 1, MX50_UART_PAD_CTRL)
+#define MX50_PAD_ECSPI2_MOSI__UART5_CTS IOMUX_PAD(0x384, 0xD8, 4, 0x0, 0, MX50_UART_PAD_CTRL)
#define MX50_PAD_ECSPI2_MOSI__ELCDIF_EN IOMUX_PAD(0x384, 0xD8, 5, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MOSI__NANDF_CEN5 IOMUX_PAD(0x384, 0xD8, 6, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MOSI__WEIM_D9 IOMUX_PAD(0x384, 0xD8, 7, 0x810, 1, NO_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__ECSPI2_MISO IOMUX_PAD(0x388, 0xDC, 0, 0x73c, 0, NO_PAD_CTRL)
+#define MX50_PAD_ECSPI2_MISO__ECSPI2_MISO IOMUX_PAD(0x388, 0xDC, 0, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MISO__GPIO_4_18 IOMUX_PAD(0x388, 0xDC, 1, 0x0, 0, PAD_CTL_PUS_100K_UP)
#define MX50_PAD_ECSPI2_MISO__ELCDIF_RS IOMUX_PAD(0x388, 0xDC, 2, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MISO__ECSPI1_SS2 IOMUX_PAD(0x388, 0xDC, 3, 0x0, 0, MX50_CSPI_SS_PAD)
-#define MX50_PAD_ECSPI2_MISO__UART5_TXD IOMUX_PAD(0x388, 0xDC, 4, 0x7e4, 4, MX50_UART_PAD_CTRL)
-#define MX50_PAD_ECSPI2_MISO__ELCDIF_VSYNC IOMUX_PAD(0x388, 0xDC, 5, 0x0, 0, NO_PAD_CTRL)
+#define MX50_PAD_ECSPI2_MISO__UART5_TXD IOMUX_PAD(0x388, 0xDC, 4, 0x0, 0, MX50_UART_PAD_CTRL)
+#define MX50_PAD_ECSPI2_MISO__ELCDIF_VSYNC IOMUX_PAD(0x388, 0xDC, 5, 0x73c, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MISO__NANDF_CEN6 IOMUX_PAD(0x388, 0xDC, 6, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_ECSPI2_MISO__WEIM_D10 IOMUX_PAD(0x388, 0xDC, 7, 0x814, 1, NO_PAD_CTRL)
@@ -503,7 +503,7 @@
#define MX50_PAD_DISP_RD__ELCDIF_EN IOMUX_PAD(0x430, 0x150, 2, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
#define MX50_PAD_DISP_RD__WEIM_A25 IOMUX_PAD(0x430, 0x150, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_DISP_RS__ELCDIF_RS IOMUX_PAD(0x434, 0x154, 0, 0x73c, 1, MX50_ELCDIF_PAD_CTRL)
+#define MX50_PAD_DISP_RS__ELCDIF_RS IOMUX_PAD(0x434, 0x154, 0, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
#define MX50_PAD_DISP_RS__GPIO_2_17 IOMUX_PAD(0x434, 0x154, 1, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_DISP_RS__ELCDIF_VSYNC IOMUX_PAD(0x434, 0x154, 2, 0x73c, 1, MX50_ELCDIF_PAD_CTRL)
#define MX50_PAD_DISP_RS__WEIM_A26 IOMUX_PAD(0x434, 0x154, 3, 0x0, 0, NO_PAD_CTRL)
@@ -691,8 +691,8 @@
#define MX50_PAD_EPDC_D9__EPDC_D9 IOMUX_PAD(0x570, 0x1D4, 0, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_EPDC_D9__GPIO_3_9 IOMUX_PAD(0x570, 0x1D4, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D9__WEIM_D9 IOMUX_PAD(0x570, 0x1D4, 2, 0x0, 0, NO_PAD_CTRL)
-#define MX50_PAD_EPDC_D9__ELCDIF_D25 IOMUX_PAD(0x570, 0x1D4, 3, 0x810, 2, MX50_ELCDIF_PAD_CTRL)
+#define MX50_PAD_EPDC_D9__WEIM_D9 IOMUX_PAD(0x570, 0x1D4, 2, 0x810, 2, NO_PAD_CTRL)
+#define MX50_PAD_EPDC_D9__ELCDIF_D25 IOMUX_PAD(0x570, 0x1D4, 3, 0x0, 0, MX50_ELCDIF_PAD_CTRL)
#define MX50_PAD_EPDC_D10__EPDC_D10 IOMUX_PAD(0x574, 0x1D8, 0, 0x0, 0, NO_PAD_CTRL)
#define MX50_PAD_EPDC_D10__GPIO_3_10 IOMUX_PAD(0x574, 0x1D8, 1, 0x0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
index b6767f90ef14..df6acc066fb1 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
@@ -473,7 +473,7 @@
#define _MX51_PAD_UART2_RXD__UART2_RXD IOMUX_PAD(0x628, 0x238, 0, 0x09ec, 2, 0)
#define _MX51_PAD_UART2_TXD__FIRI_RXD IOMUX_PAD(0x62c, 0x23c, 1, 0x0000, 0, 0)
#define _MX51_PAD_UART2_TXD__GPIO1_21 IOMUX_PAD(0x62c, 0x23c, 3, 0x0000, 0, 0)
-#define _MX51_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(0x62c, 0x23c, 0, 0x09ec, 3, 0)
+#define _MX51_PAD_UART2_TXD__UART2_TXD IOMUX_PAD(0x62c, 0x23c, 0, 0x0000, 0, 0)
#define _MX51_PAD_UART3_RXD__CSI1_D0 IOMUX_PAD(0x630, 0x240, 2, 0x0000, 0, 0)
#define _MX51_PAD_UART3_RXD__GPIO1_22 IOMUX_PAD(0x630, 0x240, 3, 0x0000, 0, 0)
#define _MX51_PAD_UART3_RXD__UART1_DTR IOMUX_PAD(0x630, 0x240, 0, 0x0000, 0, 0)
@@ -528,7 +528,7 @@
#define _MX51_PAD_USBH1_DATA1__UART2_RXD IOMUX_PAD(0x68c, 0x28c, 1, 0x09ec, 4, 0)
#define _MX51_PAD_USBH1_DATA1__USBH1_DATA1 IOMUX_PAD(0x68c, 0x28c, 0, 0x0000, 0, 0)
#define _MX51_PAD_USBH1_DATA2__GPIO1_13 IOMUX_PAD(0x690, 0x290, 2, 0x0000, 0, 0)
-#define _MX51_PAD_USBH1_DATA2__UART2_TXD IOMUX_PAD(0x690, 0x290, 1, 0x09ec, 5, 0)
+#define _MX51_PAD_USBH1_DATA2__UART2_TXD IOMUX_PAD(0x690, 0x290, 1, 0x0000, 0, 0)
#define _MX51_PAD_USBH1_DATA2__USBH1_DATA2 IOMUX_PAD(0x690, 0x290, 0, 0x0000, 0, 0)
#define _MX51_PAD_USBH1_DATA3__GPIO1_14 IOMUX_PAD(0x694, 0x294, 2, 0x0000, 0, 0)
#define _MX51_PAD_USBH1_DATA3__UART2_RTS IOMUX_PAD(0x694, 0x294, 1, 0x09e8, 5, 0)
@@ -985,11 +985,11 @@
#define MX51_PAD_NANDF_WE_B__GPIO3_3 (_MX51_PAD_NANDF_WE_B__GPIO3_3 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_WE_B__NANDF_WE_B (_MX51_PAD_NANDF_WE_B__NANDF_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_WE_B__PATA_DIOW (_MX51_PAD_NANDF_WE_B__PATA_DIOW | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_WE_B__SD3_DATA0 (_MX51_PAD_NANDF_WE_B__SD3_DATA0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_WE_B__SD3_DATA0 (_MX51_PAD_NANDF_WE_B__SD3_DATA0 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_RE_B__GPIO3_4 (_MX51_PAD_NANDF_RE_B__GPIO3_4 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_RE_B__NANDF_RE_B (_MX51_PAD_NANDF_RE_B__NANDF_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_RE_B__PATA_DIOR (_MX51_PAD_NANDF_RE_B__PATA_DIOR | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_RE_B__SD3_DATA1 (_MX51_PAD_NANDF_RE_B__SD3_DATA1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_RE_B__SD3_DATA1 (_MX51_PAD_NANDF_RE_B__SD3_DATA1 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_ALE__GPIO3_5 (_MX51_PAD_NANDF_ALE__GPIO3_5 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_ALE__NANDF_ALE (_MX51_PAD_NANDF_ALE__NANDF_ALE | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_ALE__PATA_BUFFER_EN (_MX51_PAD_NANDF_ALE__PATA_BUFFER_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
@@ -999,18 +999,18 @@
#define MX51_PAD_NANDF_WP_B__GPIO3_7 (_MX51_PAD_NANDF_WP_B__GPIO3_7 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_WP_B__NANDF_WP_B (_MX51_PAD_NANDF_WP_B__NANDF_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_WP_B__PATA_DMACK (_MX51_PAD_NANDF_WP_B__PATA_DMACK | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_WP_B__SD3_DATA2 (_MX51_PAD_NANDF_WP_B__SD3_DATA2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_WP_B__SD3_DATA2 (_MX51_PAD_NANDF_WP_B__SD3_DATA2 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_RB0__ECSPI2_SS1 (_MX51_PAD_NANDF_RB0__ECSPI2_SS1 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_RB0__GPIO3_8 (_MX51_PAD_NANDF_RB0__GPIO3_8 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_RB0__NANDF_RB0 (_MX51_PAD_NANDF_RB0__NANDF_RB0 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_RB0__PATA_DMARQ (_MX51_PAD_NANDF_RB0__PATA_DMARQ | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_RB0__SD3_DATA3 (_MX51_PAD_NANDF_RB0__SD3_DATA3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_RB0__SD3_DATA3 (_MX51_PAD_NANDF_RB0__SD3_DATA3 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_RB1__CSPI_MOSI (_MX51_PAD_NANDF_RB1__CSPI_MOSI | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_RB1__ECSPI2_RDY (_MX51_PAD_NANDF_RB1__ECSPI2_RDY | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_RB1__GPIO3_9 (_MX51_PAD_NANDF_RB1__GPIO3_9 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_RB1__NANDF_RB1 (_MX51_PAD_NANDF_RB1__NANDF_RB1 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_RB1__PATA_IORDY (_MX51_PAD_NANDF_RB1__PATA_IORDY | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_RB1__SD4_CMD (_MX51_PAD_NANDF_RB1__SD4_CMD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_RB1__SD4_CMD (_MX51_PAD_NANDF_RB1__SD4_CMD | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_RB2__DISP2_WAIT (_MX51_PAD_NANDF_RB2__DISP2_WAIT | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_RB2__ECSPI2_SCLK (_MX51_PAD_NANDF_RB2__ECSPI2_SCLK | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_RB2__FEC_COL (_MX51_PAD_NANDF_RB2__FEC_COL | MUX_PAD_CTRL(MX51_PAD_CTRL_2))
@@ -1036,41 +1036,41 @@
#define MX51_PAD_NANDF_CS2__GPIO3_18 (_MX51_PAD_NANDF_CS2__GPIO3_18 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS2__NANDF_CS2 (_MX51_PAD_NANDF_CS2__NANDF_CS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS2__PATA_CS_0 (_MX51_PAD_NANDF_CS2__PATA_CS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS2__SD4_CLK (_MX51_PAD_NANDF_CS2__SD4_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS2__SD4_CLK (_MX51_PAD_NANDF_CS2__SD4_CLK | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS))
#define MX51_PAD_NANDF_CS2__USBH3_H1_DP (_MX51_PAD_NANDF_CS2__USBH3_H1_DP | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS3__FEC_MDC (_MX51_PAD_NANDF_CS3__FEC_MDC | MUX_PAD_CTRL(MX51_PAD_CTRL_5))
#define MX51_PAD_NANDF_CS3__GPIO3_19 (_MX51_PAD_NANDF_CS3__GPIO3_19 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS3__NANDF_CS3 (_MX51_PAD_NANDF_CS3__NANDF_CS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS3__PATA_CS_1 (_MX51_PAD_NANDF_CS3__PATA_CS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS3__SD4_DAT0 (_MX51_PAD_NANDF_CS3__SD4_DAT0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS3__SD4_DAT0 (_MX51_PAD_NANDF_CS3__SD4_DAT0 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_CS3__USBH3_H1_DM (_MX51_PAD_NANDF_CS3__USBH3_H1_DM | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS4__FEC_TDATA1 (_MX51_PAD_NANDF_CS4__FEC_TDATA1 | MUX_PAD_CTRL(MX51_PAD_CTRL_5))
#define MX51_PAD_NANDF_CS4__GPIO3_20 (_MX51_PAD_NANDF_CS4__GPIO3_20 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS4__NANDF_CS4 (_MX51_PAD_NANDF_CS4__NANDF_CS4 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS4__PATA_DA_0 (_MX51_PAD_NANDF_CS4__PATA_DA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS4__SD4_DAT1 (_MX51_PAD_NANDF_CS4__SD4_DAT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS4__SD4_DAT1 (_MX51_PAD_NANDF_CS4__SD4_DAT1 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_CS4__USBH3_STP (_MX51_PAD_NANDF_CS4__USBH3_STP | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS5__FEC_TDATA2 (_MX51_PAD_NANDF_CS5__FEC_TDATA2 | MUX_PAD_CTRL(MX51_PAD_CTRL_5))
#define MX51_PAD_NANDF_CS5__GPIO3_21 (_MX51_PAD_NANDF_CS5__GPIO3_21 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS5__NANDF_CS5 (_MX51_PAD_NANDF_CS5__NANDF_CS5 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS5__PATA_DA_1 (_MX51_PAD_NANDF_CS5__PATA_DA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS5__SD4_DAT2 (_MX51_PAD_NANDF_CS5__SD4_DAT2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS5__SD4_DAT2 (_MX51_PAD_NANDF_CS5__SD4_DAT2 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_CS5__USBH3_DIR (_MX51_PAD_NANDF_CS5__USBH3_DIR | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS6__CSPI_SS3 (_MX51_PAD_NANDF_CS6__CSPI_SS3 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_CS6__FEC_TDATA3 (_MX51_PAD_NANDF_CS6__FEC_TDATA3 | MUX_PAD_CTRL(MX51_PAD_CTRL_5))
#define MX51_PAD_NANDF_CS6__GPIO3_22 (_MX51_PAD_NANDF_CS6__GPIO3_22 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS6__NANDF_CS6 (_MX51_PAD_NANDF_CS6__NANDF_CS6 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_NANDF_CS6__PATA_DA_2 (_MX51_PAD_NANDF_CS6__PATA_DA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS6__SD4_DAT3 (_MX51_PAD_NANDF_CS6__SD4_DAT3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS6__SD4_DAT3 (_MX51_PAD_NANDF_CS6__SD4_DAT3 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_CS7__FEC_TX_EN (_MX51_PAD_NANDF_CS7__FEC_TX_EN | MUX_PAD_CTRL(MX51_PAD_CTRL_5))
#define MX51_PAD_NANDF_CS7__GPIO3_23 (_MX51_PAD_NANDF_CS7__GPIO3_23 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_CS7__NANDF_CS7 (_MX51_PAD_NANDF_CS7__NANDF_CS7 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_CS7__SD3_CLK (_MX51_PAD_NANDF_CS7__SD3_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_CS7__SD3_CLK (_MX51_PAD_NANDF_CS7__SD3_CLK | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS))
#define MX51_PAD_NANDF_RDY_INT__ECSPI2_SS0 (_MX51_PAD_NANDF_RDY_INT__ECSPI2_SS0 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK (_MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK | MUX_PAD_CTRL(MX51_PAD_CTRL_4))
#define MX51_PAD_NANDF_RDY_INT__GPIO3_24 (_MX51_PAD_NANDF_RDY_INT__GPIO3_24 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT (_MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_NANDF_RDY_INT__SD3_CMD (_MX51_PAD_NANDF_RDY_INT__SD3_CMD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_NANDF_RDY_INT__SD3_CMD (_MX51_PAD_NANDF_RDY_INT__SD3_CMD | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_NANDF_D15__ECSPI2_MOSI (_MX51_PAD_NANDF_D15__ECSPI2_MOSI | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_NANDF_D15__GPIO3_25 (_MX51_PAD_NANDF_D15__GPIO3_25 | MUX_PAD_CTRL(MX51_GPIO_PAD_CTRL))
#define MX51_PAD_NANDF_D15__NANDF_D15 (_MX51_PAD_NANDF_D15__NANDF_D15 | MUX_PAD_CTRL(NO_PAD_CTRL))
@@ -1479,26 +1479,26 @@
#define MX51_PAD_SD1_CLK__SD1_CLK (_MX51_PAD_SD1_CLK__SD1_CLK | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS))
#define MX51_PAD_SD1_DATA0__AUD5_TXD (_MX51_PAD_SD1_DATA0__AUD5_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD1_DATA0__CSPI_MISO (_MX51_PAD_SD1_DATA0__CSPI_MISO | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
-#define MX51_PAD_SD1_DATA0__SD1_DATA0 (_MX51_PAD_SD1_DATA0__SD1_DATA0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD1_DATA0__SD1_DATA0 (_MX51_PAD_SD1_DATA0__SD1_DATA0 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_EIM_DA0__EIM_DA0 (_MX51_PAD_EIM_DA0__EIM_DA0 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA1__EIM_DA1 (_MX51_PAD_EIM_DA1__EIM_DA1 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA2__EIM_DA2 (_MX51_PAD_EIM_DA2__EIM_DA2 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA3__EIM_DA3 (_MX51_PAD_EIM_DA3__EIM_DA3 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD1_DATA1__AUD5_RXD (_MX51_PAD_SD1_DATA1__AUD5_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD1_DATA1__SD1_DATA1 (_MX51_PAD_SD1_DATA1__SD1_DATA1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD1_DATA1__SD1_DATA1 (_MX51_PAD_SD1_DATA1__SD1_DATA1 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_EIM_DA4__EIM_DA4 (_MX51_PAD_EIM_DA4__EIM_DA4 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA5__EIM_DA5 (_MX51_PAD_EIM_DA5__EIM_DA5 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA6__EIM_DA6 (_MX51_PAD_EIM_DA6__EIM_DA6 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA7__EIM_DA7 (_MX51_PAD_EIM_DA7__EIM_DA7 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD1_DATA2__AUD5_TXC (_MX51_PAD_SD1_DATA2__AUD5_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD1_DATA2__SD1_DATA2 (_MX51_PAD_SD1_DATA2__SD1_DATA2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD1_DATA2__SD1_DATA2 (_MX51_PAD_SD1_DATA2__SD1_DATA2 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_EIM_DA10__EIM_DA10 (_MX51_PAD_EIM_DA10__EIM_DA10 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA11__EIM_DA11 (_MX51_PAD_EIM_DA11__EIM_DA11 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA8__EIM_DA8 (_MX51_PAD_EIM_DA8__EIM_DA8 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_EIM_DA9__EIM_DA9 (_MX51_PAD_EIM_DA9__EIM_DA9 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD1_DATA3__AUD5_TXFS (_MX51_PAD_SD1_DATA3__AUD5_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD1_DATA3__CSPI_SS1 (_MX51_PAD_SD1_DATA3__CSPI_SS1 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
-#define MX51_PAD_SD1_DATA3__SD1_DATA3 (_MX51_PAD_SD1_DATA3__SD1_DATA3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD1_DATA3__SD1_DATA3 (_MX51_PAD_SD1_DATA3__SD1_DATA3 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_GPIO1_0__CSPI_SS2 (_MX51_PAD_GPIO1_0__CSPI_SS2 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_GPIO1_0__GPIO1_0 (_MX51_PAD_GPIO1_0__GPIO1_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_GPIO1_0__SD1_CD (_MX51_PAD_GPIO1_0__SD1_CD | MUX_PAD_CTRL(MX51_ESDHC_PAD_CTRL))
@@ -1517,16 +1517,16 @@
#define MX51_PAD_SD2_CLK__SD2_CLK (_MX51_PAD_SD2_CLK__SD2_CLK | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS))
#define MX51_PAD_SD2_DATA0__CSPI_MISO (_MX51_PAD_SD2_DATA0__CSPI_MISO | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_SD2_DATA0__SD1_DAT4 (_MX51_PAD_SD2_DATA0__SD1_DAT4 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD2_DATA0__SD2_DATA0 (_MX51_PAD_SD2_DATA0__SD2_DATA0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD2_DATA0__SD2_DATA0 (_MX51_PAD_SD2_DATA0__SD2_DATA0 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_SD2_DATA1__SD1_DAT5 (_MX51_PAD_SD2_DATA1__SD1_DAT5 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD2_DATA1__SD2_DATA1 (_MX51_PAD_SD2_DATA1__SD2_DATA1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD2_DATA1__SD2_DATA1 (_MX51_PAD_SD2_DATA1__SD2_DATA1 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_SD2_DATA1__USBH3_H2_DP (_MX51_PAD_SD2_DATA1__USBH3_H2_DP | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD2_DATA2__SD1_DAT6 (_MX51_PAD_SD2_DATA2__SD1_DAT6 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD2_DATA2__SD2_DATA2 (_MX51_PAD_SD2_DATA2__SD2_DATA2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD2_DATA2__SD2_DATA2 (_MX51_PAD_SD2_DATA2__SD2_DATA2 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_SD2_DATA2__USBH3_H2_DM (_MX51_PAD_SD2_DATA2__USBH3_H2_DM | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_SD2_DATA3__CSPI_SS2 (_MX51_PAD_SD2_DATA3__CSPI_SS2 | MUX_PAD_CTRL(MX51_ECSPI_PAD_CTRL))
#define MX51_PAD_SD2_DATA3__SD1_DAT7 (_MX51_PAD_SD2_DATA3__SD1_DAT7 | MUX_PAD_CTRL(NO_PAD_CTRL))
-#define MX51_PAD_SD2_DATA3__SD2_DATA3 (_MX51_PAD_SD2_DATA3__SD2_DATA3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX51_PAD_SD2_DATA3__SD2_DATA3 (_MX51_PAD_SD2_DATA3__SD2_DATA3 | MUX_PAD_CTRL(MX51_SDHCI_PAD_CTRL))
#define MX51_PAD_GPIO1_2__CCM_OUT_2 (_MX51_PAD_GPIO1_2__CCM_OUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_GPIO1_2__GPIO1_2 (_MX51_PAD_GPIO1_2__GPIO1_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
#define MX51_PAD_GPIO1_2__I2C2_SCL (_MX51_PAD_GPIO1_2__I2C2_SCL | MUX_PAD_CTRL(MX51_I2C_PAD_CTRL))
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx53.h b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
index 68e11d7ab79d..e95d9cb8aeb7 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx53.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,305 +21,2358 @@
#include <mach/iomux-v3.h>
-/*
- * various IOMUX alternate output functions (1-7)
- */
-typedef enum iomux_config {
- IOMUX_CONFIG_ALT0,
- IOMUX_CONFIG_ALT1,
- IOMUX_CONFIG_ALT2,
- IOMUX_CONFIG_ALT3,
- IOMUX_CONFIG_ALT4,
- IOMUX_CONFIG_ALT5,
- IOMUX_CONFIG_ALT6,
- IOMUX_CONFIG_ALT7,
- IOMUX_CONFIG_GPIO, /* added to help user use GPIO mode */
-} iomux_pin_cfg_t;
-
/* These 2 defines are for pins that may not have a mux register, but could
* have a pad setting register, and vice-versa. */
-#define NON_MUX_I 0x00
#define NON_PAD_I 0x00
#define MX53_UART_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_DSE_HIGH | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
-/* UART1 */
-#define MX53_PAD_CSI0_D10__UART1_TXD IOMUX_PAD(0x414, 0xE8, 2, 0x0, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_CSI0_D11__UART1_RXD IOMUX_PAD(0x418, 0xEC, 2, 0x878, 1, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DIOW__UART1_TXD IOMUX_PAD(0x5F0, 0x270, 3, 0x0, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DMACK__UART1_RXD IOMUX_PAD(0x5F4, 0x274, 3, 0x880, 3, MX53_UART_PAD_CTRL)
-
-/* UART2 */
-#define MX53_PAD_ATA_BUFFER_EN__UART2_RXD IOMUX_PAD(0x5FC, 0x27C, 3, 0x880, 3, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DMARQ__UART2_TXD IOMUX_PAD(0x5F8, 0x278, 3, 0x0, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DIOR__UART2_RTS IOMUX_PAD(0x604, 0x284, 3, 0x87C, 3, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_INTRQ__UART2_CTS IOMUX_PAD(0x600, 0x280, 3, 0x0, 0, MX53_UART_PAD_CTRL)
+#define MX53_SDHC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
+ PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_HIGH | \
+ PAD_CTL_SRE_FAST)
-/* UART3 */
-#define MX53_PAD_ATA_CS_0__UART3_TXD IOMUX_PAD(0x61C, 0x29C, 4, 0x0, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_CS_1__UART3_RXD IOMUX_PAD(0x620, 0x2A0, 4, 0x888, 3, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DA_1__UART3_CTS IOMUX_PAD(0x614, 0x294, 4, 0x0, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_ATA_DA_2__UART3_RTS IOMUX_PAD(0x618, 0x298, 4, 0x884, 5, MX53_UART_PAD_CTRL)
+#define _MX53_PAD_GPIO_19__KPP_COL_5 IOMUX_PAD(0x348, 0x20, 0, 0x840, 0, 0)
+#define _MX53_PAD_GPIO_19__GPIO4_5 IOMUX_PAD(0x348, 0x20, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__CCM_CLKO IOMUX_PAD(0x348, 0x20, 2, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__SPDIF_OUT1 IOMUX_PAD(0x348, 0x20, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 IOMUX_PAD(0x348, 0x20, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__ECSPI1_RDY IOMUX_PAD(0x348, 0x20, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__FEC_TDATA_3 IOMUX_PAD(0x348, 0x20, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_19__SRC_INT_BOOT IOMUX_PAD(0x348, 0x20,7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL0__KPP_COL_0 IOMUX_PAD(0x34C, 0x24, o, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL0__GPIO4_6 IOMUX_PAD(0x34C, 0x24, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC IOMUX_PAD(0x34C, 0x24, 2, 0x758, 0, 0)
+#define _MX53_PAD_KEY_COL0__UART4_TXD_MUX IOMUX_PAD(0x34C, 0x24, 4, 0x890, 0, 0)
+#define _MX53_PAD_KEY_COL0__ECSPI1_SCLK IOMUX_PAD(0x34C, 0x24, 5, 0x79C, 0, 0)
+#define _MX53_PAD_KEY_COL0__FEC_RDATA_3 IOMUX_PAD(0x34C, 0x24, 6, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL0__SRC_ANY_PU_RST IOMUX_PAD(0x34C, 0x24, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW0__KPP_ROW_0 IOMUX_PAD(0x350, 0x28, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW0__GPIO4_7 IOMUX_PAD(0x350, 0x28, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD IOMUX_PAD(0x350, 0x28, 2, 0x74C, 0, 0)
+#define _MX53_PAD_KEY_ROW0__UART4_RXD_MUX IOMUX_PAD(0x350, 0x28, 4, 0x890, 1, 0)
+#define _MX53_PAD_KEY_ROW0__ECSPI1_MOSI IOMUX_PAD(0x350, 0x28, 5, 0x7A4, 0, 0)
+#define _MX53_PAD_KEY_ROW0__FEC_TX_ER IOMUX_PAD(0x350, 0x28, 6, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL1__KPP_COL_1 IOMUX_PAD(0x354, 0x2C, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL1__GPIO4_8 IOMUX_PAD(0x354, 0x2C, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS IOMUX_PAD(0x354, 0x2C, 2, 0x75C, 0, 0)
+#define _MX53_PAD_KEY_COL1__UART5_TXD_MUX IOMUX_PAD(0x354, 0x2C, 4, 0x898, 0, 0)
+#define _MX53_PAD_KEY_COL1__ECSPI1_MISO IOMUX_PAD(0x354, 0x2C, 5, 0x7A0, 0, 0)
+#define _MX53_PAD_KEY_COL1__FEC_RX_CLK IOMUX_PAD(0x354, 0x2C, 6, 0x808, 0, 0)
+#define _MX53_PAD_KEY_COL1__USBPHY1_TXREADY IOMUX_PAD(0x354, 0x2C, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW1__KPP_ROW_1 IOMUX_PAD(0x358, 0x30, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW1__GPIO4_9 IOMUX_PAD(0x358, 0x30, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD IOMUX_PAD(0x358, 0x30, 2, 0x748, 0, 0)
+#define _MX53_PAD_KEY_ROW1__UART5_RXD_MUX IOMUX_PAD(0x358, 0x30, 4, 0x898, 1, 0)
+#define _MX53_PAD_KEY_ROW1__ECSPI1_SS0 IOMUX_PAD(0x358, 0x30, 5, 0x7A8, 0, 0)
+#define _MX53_PAD_KEY_ROW1__FEC_COL IOMUX_PAD(0x358, 0x30, 6, 0x800, 0, 0)
+#define _MX53_PAD_KEY_ROW1__USBPHY1_RXVALID IOMUX_PAD(0x358, 0x30, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL2__KPP_COL_2 IOMUX_PAD(0x35C, 0x34, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL2__GPIO4_10 IOMUX_PAD(0x35C, 0x34, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL2__CAN1_TXCAN IOMUX_PAD(0x35C, 0x34, 2, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL2__FEC_MDIO IOMUX_PAD(0x35C, 0x34, 4, 0x804, 0, 0)
+#define _MX53_PAD_KEY_COL2__ECSPI1_SS1 IOMUX_PAD(0x35C, 0x34, 5, 0x7AC, 0, 0)
+#define _MX53_PAD_KEY_COL2__FEC_RDATA_2 IOMUX_PAD(0x35C, 0x34, 6, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE IOMUX_PAD(0x35C, 0x34, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__KPP_ROW_2 IOMUX_PAD(0x360, 0x38, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__GPIO4_11 IOMUX_PAD(0x360, 0x38, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__CAN1_RXCAN IOMUX_PAD(0x360, 0x38, 2, 0x760, 0, 0)
+#define _MX53_PAD_KEY_ROW2__FEC_MDC IOMUX_PAD(0x360, 0x38, 4, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__ECSPI1_SS2 IOMUX_PAD(0x360, 0x38, 5, 0x7B0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__FEC_TDATA_2 IOMUX_PAD(0x360, 0x38, 6, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW2__USBPHY1_RXERROR IOMUX_PAD(0x360, 0x38, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL3__KPP_COL_3 IOMUX_PAD(0x364, 0x3C, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL3__GPIO4_12 IOMUX_PAD(0x364, 0x3C, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL3__USBOH3_H2_DP IOMUX_PAD(0x364, 0x3C, 2, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL3__SPDIF_IN1 IOMUX_PAD(0x364, 0x3C, 3, 0x870, 0, 0)
+#define _MX53_PAD_KEY_COL3__I2C2_SCL IOMUX_PAD(0x364, 0x3C, 4 | IOMUX_CONFIG_SION, 0x81C, 0, 0)
+#define _MX53_PAD_KEY_COL3__ECSPI1_SS3 IOMUX_PAD(0x364, 0x3C, 5, 0x7B4, 0, 0)
+#define _MX53_PAD_KEY_COL3__FEC_CRS IOMUX_PAD(0x364, 0x3C, 6, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK IOMUX_PAD(0x364, 0x3C, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW3__KPP_ROW_3 IOMUX_PAD(0x368, 0x40, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW3__GPIO4_13 IOMUX_PAD(0x368, 0x40, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW3__USBOH3_H2_DM IOMUX_PAD(0x368, 0x40, 2, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK IOMUX_PAD(0x368, 0x40, 3, 0x768, 0, 0)
+#define _MX53_PAD_KEY_ROW3__I2C2_SDA IOMUX_PAD(0x368, 0x40, 4 | IOMUX_CONFIG_SION, 0x820, 0, 0)
+#define _MX53_PAD_KEY_ROW3__OSC32K_32K_OUT IOMUX_PAD(0x368, 0x40, 5, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW3__CCM_PLL4_BYP IOMUX_PAD(0x368, 0x40, 6, 0x77C, 0, 0)
+#define _MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 IOMUX_PAD(0x368, 0x40, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL4__KPP_COL_4 IOMUX_PAD(0x36C, 0x44, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL4__GPIO4_14 IOMUX_PAD(0x36C, 0x44, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL4__CAN2_TXCAN IOMUX_PAD(0x36C, 0x44, 2, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL4__IPU_SISG_4 IOMUX_PAD(0x36C, 0x44, 3, 0x0, 0, 0)
+#define _MX53_PAD_KEY_COL4__UART5_RTS IOMUX_PAD(0x36C, 0x44, 4, 0x894, 0, 0)
+#define _MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC IOMUX_PAD(0x36C, 0x44, 5, 0x89C, 0, 0)
+#define _MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 IOMUX_PAD(0x36C, 0x44, 7, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW4__KPP_ROW_4 IOMUX_PAD(0x370, 0x48, 0, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW4__GPIO4_15 IOMUX_PAD(0x370, 0x48, 1, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW4__CAN2_RXCAN IOMUX_PAD(0x370, 0x48, 2, 0x764, 0, 0)
+#define _MX53_PAD_KEY_ROW4__IPU_SISG_5 IOMUX_PAD(0x370, 0x48, 3, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW4__UART5_CTS IOMUX_PAD(0x370, 0x48, 4, 0x894, 1, 0)
+#define _MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR IOMUX_PAD(0x370, 0x48, 5, 0x0, 0, 0)
+#define _MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID IOMUX_PAD(0x370, 0x48, 7, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK IOMUX_PAD(0x378, 0x4C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__GPIO4_16 IOMUX_PAD(0x378, 0x4C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR IOMUX_PAD(0x378, 0x4C, 2, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 IOMUX_PAD(0x378, 0x4C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 IOMUX_PAD(0x378, 0x4C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID IOMUX_PAD(0x378, 0x4C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 IOMUX_PAD(0x37C, 0x50, 0, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__GPIO4_17 IOMUX_PAD(0x37C, 0x50, 1, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC IOMUX_PAD(0x37C, 0x50, 2, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 IOMUX_PAD(0x37C, 0x50, 5, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 IOMUX_PAD(0x37C, 0x50, 6, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN15__USBPHY1_BVALID IOMUX_PAD(0x37C, 0x50, 7, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 IOMUX_PAD(0x380, 0x54, 0, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__GPIO4_18 IOMUX_PAD(0x380, 0x54, 1, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD IOMUX_PAD(0x380, 0x54, 2, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 IOMUX_PAD(0x380, 0x54, 5, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 IOMUX_PAD(0x380, 0x54, 6, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION IOMUX_PAD(0x380, 0x54, 7, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 IOMUX_PAD(0x384, 0x58, 0, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__GPIO4_19 IOMUX_PAD(0x384, 0x58, 1, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS IOMUX_PAD(0x384, 0x58, 2, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 IOMUX_PAD(0x384, 0x58, 5, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 IOMUX_PAD(0x384, 0x58, 6, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN3__USBPHY1_IDDIG IOMUX_PAD(0x384, 0x58, 7, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 IOMUX_PAD(0x388, 0x5C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__GPIO4_20 IOMUX_PAD(0x388, 0x5C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD IOMUX_PAD(0x388, 0x5C, 2, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__ESDHC1_WP IOMUX_PAD(0x388, 0x5C, 3, 0x7FC, 0, 0)
+#define _MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD IOMUX_PAD(0x388, 0x5C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 IOMUX_PAD(0x388, 0x5C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT IOMUX_PAD(0x388, 0x5C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 IOMUX_PAD(0x38C, 0x60, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__GPIO4_21 IOMUX_PAD(0x38C, 0x60, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__CSPI_SCLK IOMUX_PAD(0x38C, 0x60, 2, 0x780, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 IOMUX_PAD(0x38C, 0x60, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN IOMUX_PAD(0x38C, 0x60, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 IOMUX_PAD(0x38C, 0x60, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY IOMUX_PAD(0x38C, 0x60, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 IOMUX_PAD(0x390, 0x64, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__GPIO4_22 IOMUX_PAD(0x390, 0x64, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__CSPI_MOSI IOMUX_PAD(0x390, 0x64, 2, 0x788, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 IOMUX_PAD(0x390, 0x64, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL IOMUX_PAD(0x390, 0x64, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 IOMUX_PAD(0x390, 0x64, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID IOMUX_PAD(0x390, 0x64, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 IOMUX_PAD(0x394, 0x68, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__GPIO4_23 IOMUX_PAD(0x394, 0x68, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__CSPI_MISO IOMUX_PAD(0x394, 0x68, 2, 0x784, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 IOMUX_PAD(0x394, 0x68, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE IOMUX_PAD(0x394, 0x68, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 IOMUX_PAD(0x394, 0x68, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE IOMUX_PAD(0x394, 0x68, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 IOMUX_PAD(0x398, 0x6C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__GPIO4_24 IOMUX_PAD(0x398, 0x6C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__CSPI_SS0 IOMUX_PAD(0x398, 0x6C, 2, 0x78C, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 IOMUX_PAD(0x398, 0x6C, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR IOMUX_PAD(0x398, 0x6C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 IOMUX_PAD(0x398, 0x6C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR IOMUX_PAD(0x398, 0x6C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 IOMUX_PAD(0x39C, 0x70, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__GPIO4_25 IOMUX_PAD(0x39C, 0x70, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__CSPI_SS1 IOMUX_PAD(0x39C, 0x70, 2, 0x790, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 IOMUX_PAD(0x39C, 0x70, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB IOMUX_PAD(0x39C, 0x70, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 IOMUX_PAD(0x39C, 0x70, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK IOMUX_PAD(0x39C, 0x70, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 IOMUX_PAD(0x3A0, 0x74, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__GPIO4_26 IOMUX_PAD(0x3A0, 0x74, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__CSPI_SS2 IOMUX_PAD(0x3A0, 0x74, 2, 0x794, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 IOMUX_PAD(0x3A0, 0x74, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS IOMUX_PAD(0x3A0, 0x74, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 IOMUX_PAD(0x3A0, 0x74, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 IOMUX_PAD(0x3A0, 0x74, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 IOMUX_PAD(0x3A4, 0x78, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__GPIO4_27 IOMUX_PAD(0x3A4, 0x78, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__CSPI_SS3 IOMUX_PAD(0x3A4, 0x78, 2, 0x798, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 IOMUX_PAD(0x3A4, 0x78, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE IOMUX_PAD(0x3A4, 0x78, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 IOMUX_PAD(0x3A4, 0x78, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 IOMUX_PAD(0x3A4, 0x78, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 IOMUX_PAD(0x3A8, 0x7C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__GPIO4_28 IOMUX_PAD(0x3A8, 0x7C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__CSPI_RDY IOMUX_PAD(0x3A8, 0x7C, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 IOMUX_PAD(0x3A8, 0x7C, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 IOMUX_PAD(0x3A8, 0x7C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 IOMUX_PAD(0x3A8, 0x7C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID IOMUX_PAD(0x3A8, 0x7C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 IOMUX_PAD(0x3AC, 0x80, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__GPIO4_29 IOMUX_PAD(0x3AC, 0x80, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__PWM1_PWMO IOMUX_PAD(0x3AC, 0x80, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B IOMUX_PAD(0x3AC, 0x80, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 IOMUX_PAD(0x3AC, 0x80, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 IOMUX_PAD(0x3AC, 0x80, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT8__USBPHY2_AVALID IOMUX_PAD(0x3AC, 0x80, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 IOMUX_PAD(0x3B0, 0x84, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__GPIO4_30 IOMUX_PAD(0x3B0, 0x84, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__PWM2_PWMO IOMUX_PAD(0x3B0, 0x84, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B IOMUX_PAD(0x3B0, 0x84, 3, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 IOMUX_PAD(0x3B0, 0x84, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 IOMUX_PAD(0x3B0, 0x84, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 IOMUX_PAD(0x3B0, 0x84, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 IOMUX_PAD(0x3B4, 0x88, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__GPIO4_31 IOMUX_PAD(0x3B4, 0x88, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP IOMUX_PAD(0x3B4, 0x88, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 IOMUX_PAD(0x3B4, 0x88, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 IOMUX_PAD(0x3B4, 0x88, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 IOMUX_PAD(0x3B4, 0x88, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 IOMUX_PAD(0x3B8, 0x8C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__GPIO5_5 IOMUX_PAD(0x3B8, 0x8C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT IOMUX_PAD(0x3B8, 0x8C, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 IOMUX_PAD(0x3B8, 0x8C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 IOMUX_PAD(0x3B8, 0x8C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 IOMUX_PAD(0x3B8, 0x8C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 IOMUX_PAD(0x3BC, 0x90, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__GPIO5_6 IOMUX_PAD(0x3BC, 0x90, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK IOMUX_PAD(0x3BC, 0x90, 2, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 IOMUX_PAD(0x3BC, 0x90, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 IOMUX_PAD(0x3BC, 0x90, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 IOMUX_PAD(0x3BC, 0x90, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 IOMUX_PAD(0x3C0, 0x94, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__GPIO5_7 IOMUX_PAD(0x3C0, 0x94, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS IOMUX_PAD(0x3C0, 0x94, 3, 0x754, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 IOMUX_PAD(0x3C0, 0x94, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 IOMUX_PAD(0x3C0, 0x94, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 IOMUX_PAD(0x3C0, 0x94, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 IOMUX_PAD(0x3C4, 0x98, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__GPIO5_8 IOMUX_PAD(0x3C4, 0x98, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC IOMUX_PAD(0x3C4, 0x98, 3, 0x750, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 IOMUX_PAD(0x3C4, 0x98, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 IOMUX_PAD(0x3C4, 0x98, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 IOMUX_PAD(0x3C4, 0x98, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 IOMUX_PAD(0x3C8, 0x9C, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__GPIO5_9 IOMUX_PAD(0x3C8, 0x9C, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__ECSPI1_SS1 IOMUX_PAD(0x3C8, 0x9C, 2, 0x7AC, 1, 0)
+#define _MX53_PAD_DISP0_DAT15__ECSPI2_SS1 IOMUX_PAD(0x3C8, 0x9C, 3, 0x7C8, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 IOMUX_PAD(0x3C8, 0x9C, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 IOMUX_PAD(0x3C8, 0x9C, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 IOMUX_PAD(0x3C8, 0x9C, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 IOMUX_PAD(0x3CC, 0xA0, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__GPIO5_10 IOMUX_PAD(0x3CC, 0xA0, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__ECSPI2_MOSI IOMUX_PAD(0x3CC, 0xA0, 2, 0x7C0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC IOMUX_PAD(0x3CC, 0xA0, 3, 0x758, 1, 0)
+#define _MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 IOMUX_PAD(0x3CC, 0xA0, 4, 0x868, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 IOMUX_PAD(0x3CC, 0xA0, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 IOMUX_PAD(0x3CC, 0xA0, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 IOMUX_PAD(0x3CC, 0xA0, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 IOMUX_PAD(0x3D0, 0xA4, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__GPIO5_11 IOMUX_PAD(0x3D0, 0xA4, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__ECSPI2_MISO IOMUX_PAD(0x3D0, 0xA4, 2, 0x7BC, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD IOMUX_PAD(0x3D0, 0xA4, 3, 0x74C, 1, 0)
+#define _MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 IOMUX_PAD(0x3D0, 0xA4, 4, 0x86C, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 IOMUX_PAD(0x3D0, 0xA4, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 IOMUX_PAD(0x3D0, 0xA4, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 IOMUX_PAD(0x3D4, 0xA8, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__GPIO5_12 IOMUX_PAD(0x3D4, 0xA8, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__ECSPI2_SS0 IOMUX_PAD(0x3D4, 0xA8, 2, 0x7C4, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS IOMUX_PAD(0x3D4, 0xA8, 3, 0x75C, 1, 0)
+#define _MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS IOMUX_PAD(0x3D4, 0xA8, 4, 0x73C, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 IOMUX_PAD(0x3D4, 0xA8, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 IOMUX_PAD(0x3D4, 0xA8, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 IOMUX_PAD(0x3D4, 0xA8, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 IOMUX_PAD(0x3D8, 0xAC, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__GPIO5_13 IOMUX_PAD(0x3D8, 0xAC, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__ECSPI2_SCLK IOMUX_PAD(0x3D8, 0xAC, 2, 0x7B8, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD IOMUX_PAD(0x3D8, 0xAC, 3, 0x748, 1, 0)
+#define _MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC IOMUX_PAD(0x3D8, 0xAC, 4, 0x738, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 IOMUX_PAD(0x3D8, 0xAC, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 IOMUX_PAD(0x3D8, 0xAC, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 IOMUX_PAD(0x3D8, 0xAC, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 IOMUX_PAD(0x3DC, 0xB0, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__GPIO5_14 IOMUX_PAD(0x3DC, 0xB0, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__ECSPI1_SCLK IOMUX_PAD(0x3DC, 0xB0, 2, 0x79C, 1, 0)
+#define _MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC IOMUX_PAD(0x3DC, 0xB0, 3, 0x740, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 IOMUX_PAD(0x3DC, 0xB0, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 IOMUX_PAD(0x3DC, 0xB0, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT20__SATA_PHY_TDI IOMUX_PAD(0x3DC, 0xB0, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 IOMUX_PAD(0x3E0, 0xB4, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__GPIO5_15 IOMUX_PAD(0x3E0, 0xB4, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__ECSPI1_MOSI IOMUX_PAD(0x3E0, 0xB4, 2, 0x7A4, 1, 0)
+#define _MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD IOMUX_PAD(0x3E0, 0xB4, 3, 0x734, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 IOMUX_PAD(0x3E0, 0xB4, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 IOMUX_PAD(0x3E0, 0xB4, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT21__SATA_PHY_TDO IOMUX_PAD(0x3E0, 0xB4, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 IOMUX_PAD(0x3E4, 0xB8, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__GPIO5_16 IOMUX_PAD(0x3E4, 0xB8, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__ECSPI1_MISO IOMUX_PAD(0x3E4, 0xB8, 2, 0x7A0, 1, 0)
+#define _MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS IOMUX_PAD(0x3E4, 0xB8, 3, 0x744, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 IOMUX_PAD(0x3E4, 0xB8, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 IOMUX_PAD(0x3E4, 0xB8, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT22__SATA_PHY_TCK IOMUX_PAD(0x3E4, 0xB8, 7, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 IOMUX_PAD(0x3E8, 0xBC, 0, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__GPIO5_17 IOMUX_PAD(0x3E8, 0xBC, 1, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__ECSPI1_SS0 IOMUX_PAD(0x3E8, 0xBC, 2, 0x7A8, 1, 0)
+#define _MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD IOMUX_PAD(0x3E8, 0xBC, 3, 0x730, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 IOMUX_PAD(0x3E8, 0xBC, 5, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 IOMUX_PAD(0x3E8, 0xBC, 6, 0x0, 0, 0)
+#define _MX53_PAD_DISP0_DAT23__SATA_PHY_TMS IOMUX_PAD(0x3E8, 0xBC, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK IOMUX_PAD(0x3EC, 0xC0, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_PIXCLK__GPIO5_18 IOMUX_PAD(0x3EC, 0xC0, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 IOMUX_PAD(0x3EC, 0xC0, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 IOMUX_PAD(0x3EC, 0xC0, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC IOMUX_PAD(0x3F0, 0xC4, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__GPIO5_19 IOMUX_PAD(0x3F0, 0xC4, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK IOMUX_PAD(0x3F0, 0xC4, 2, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 IOMUX_PAD(0x3F0, 0xC4, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 IOMUX_PAD(0x3F0, 0xC4, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_MCLK__TPIU_TRCTL IOMUX_PAD(0x3F0, 0xC4, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN IOMUX_PAD(0x3F4, 0xC8, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DATA_EN__GPIO5_20 IOMUX_PAD(0x3F4, 0xC8, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 IOMUX_PAD(0x3F4, 0xC8, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 IOMUX_PAD(0x3F4, 0xC8, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK IOMUX_PAD(0x3F4, 0xC8, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC IOMUX_PAD(0x3F8, 0xCC, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_VSYNC__GPIO5_21 IOMUX_PAD(0x3F8, 0xCC, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 IOMUX_PAD(0x3F8, 0xCC, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 IOMUX_PAD(0x3F8, 0xCC, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 IOMUX_PAD(0x3F8, 0xCC, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 IOMUX_PAD(0x3FC, 0xD0, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__GPIO5_22 IOMUX_PAD(0x3FC, 0xD0, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__KPP_COL_5 IOMUX_PAD(0x3FC, 0xD0, 2, 0x840, 1, 0)
+#define _MX53_PAD_CSI0_DAT4__ECSPI1_SCLK IOMUX_PAD(0x3FC, 0xD0, 3, 0x79C, 2, 0)
+#define _MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP IOMUX_PAD(0x3FC, 0xD0, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC IOMUX_PAD(0x3FC, 0xD0, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 IOMUX_PAD(0x3FC, 0xD0, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 IOMUX_PAD(0x3FC, 0xD0, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 IOMUX_PAD(0x400, 0xD4, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__GPIO5_23 IOMUX_PAD(0x400, 0xD4, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__KPP_ROW_5 IOMUX_PAD(0x400, 0xD4, 2, 0x84C, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__ECSPI1_MOSI IOMUX_PAD(0x400, 0xD4, 3, 0x7A4, 2, 0)
+#define _MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT IOMUX_PAD(0x400, 0xD4, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD IOMUX_PAD(0x400, 0xD4, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 IOMUX_PAD(0x400, 0xD4, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 IOMUX_PAD(0x400, 0xD4, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 IOMUX_PAD(0x404, 0xD8, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__GPIO5_24 IOMUX_PAD(0x404, 0xD8, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__KPP_COL_6 IOMUX_PAD(0x404, 0xD8, 2, 0x844, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__ECSPI1_MISO IOMUX_PAD(0x404, 0xD8, 3, 0x7A0, 2, 0)
+#define _MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK IOMUX_PAD(0x404, 0xD8, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS IOMUX_PAD(0x404, 0xD8, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 IOMUX_PAD(0x404, 0xD8, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 IOMUX_PAD(0x404, 0xD8, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 IOMUX_PAD(0x408, 0xDC, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__GPIO5_25 IOMUX_PAD(0x408, 0xDC, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__KPP_ROW_6 IOMUX_PAD(0x408, 0xDC, 2, 0x850, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__ECSPI1_SS0 IOMUX_PAD(0x408, 0xDC, 3, 0x7A8, 2, 0)
+#define _MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR IOMUX_PAD(0x408, 0xDC, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD IOMUX_PAD(0x408, 0xDC, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 IOMUX_PAD(0x408, 0xDC, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 IOMUX_PAD(0x408, 0xDC, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 IOMUX_PAD(0x40C, 0xE0, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__GPIO5_26 IOMUX_PAD(0x40C, 0xE0, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__KPP_COL_7 IOMUX_PAD(0x40C, 0xE0, 2, 0x848, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__ECSPI2_SCLK IOMUX_PAD(0x40C, 0xE0, 3, 0x7B8, 1, 0)
+#define _MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC IOMUX_PAD(0x40C, 0xE0, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__I2C1_SDA IOMUX_PAD(0x40C, 0xE0, 5 | IOMUX_CONFIG_SION, 0x818, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 IOMUX_PAD(0x40C, 0xE0, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 IOMUX_PAD(0x40C, 0xE0, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 IOMUX_PAD(0x410, 0xE4, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__GPIO5_27 IOMUX_PAD(0x410, 0xE4, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__KPP_ROW_7 IOMUX_PAD(0x410, 0xE4, 2, 0x854, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__ECSPI2_MOSI IOMUX_PAD(0x410, 0xE4, 3, 0x7C0, 1, 0)
+#define _MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR IOMUX_PAD(0x410, 0xE4, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__I2C1_SCL IOMUX_PAD(0x410, 0xE4, 5 | IOMUX_CONFIG_SION, 0x814, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 IOMUX_PAD(0x410, 0xE4, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 IOMUX_PAD(0x410, 0xE4, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 IOMUX_PAD(0x414, 0xE8, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__GPIO5_28 IOMUX_PAD(0x414, 0xE8, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__UART1_TXD_MUX IOMUX_PAD(0x414, 0xE8, 2, 0x878, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__ECSPI2_MISO IOMUX_PAD(0x414, 0xE8, 3, 0x7BC, 1, 0)
+#define _MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC IOMUX_PAD(0x414, 0xE8, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 IOMUX_PAD(0x414, 0xE8, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 IOMUX_PAD(0x414, 0xE8, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 IOMUX_PAD(0x414, 0xE8, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 IOMUX_PAD(0x418, 0xEC, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__GPIO5_29 IOMUX_PAD(0x418, 0xEC, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__UART1_RXD_MUX IOMUX_PAD(0x418, 0xEC, 2, 0x878, 1, 0)
+#define _MX53_PAD_CSI0_DAT11__ECSPI2_SS0 IOMUX_PAD(0x418, 0xEC, 3, 0x7C4, 1, 0)
+#define _MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS IOMUX_PAD(0x418, 0xEC, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 IOMUX_PAD(0x418, 0xEC, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 IOMUX_PAD(0x418, 0xEC, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 IOMUX_PAD(0x418, 0xEC, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 IOMUX_PAD(0x41C, 0xF0, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__GPIO5_30 IOMUX_PAD(0x41C, 0xF0, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__UART4_TXD_MUX IOMUX_PAD(0x41C, 0xF0, 2, 0x890, 2, 0)
+#define _MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 IOMUX_PAD(0x41C, 0xF0, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 IOMUX_PAD(0x41C, 0xF0, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 IOMUX_PAD(0x41C, 0xF0, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 IOMUX_PAD(0x41C, 0xF0, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 IOMUX_PAD(0x420, 0xF4, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__GPIO5_31 IOMUX_PAD(0x420, 0xF4, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__UART4_RXD_MUX IOMUX_PAD(0x420, 0xF4, 2, 0x890, 3, 0)
+#define _MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 IOMUX_PAD(0x420, 0xF4, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 IOMUX_PAD(0x420, 0xF4, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 IOMUX_PAD(0x420, 0xF4, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 IOMUX_PAD(0x420, 0xF4, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 IOMUX_PAD(0x424, 0xF8, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__GPIO6_0 IOMUX_PAD(0x424, 0xF8, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__UART5_TXD_MUX IOMUX_PAD(0x424, 0xF8, 2, 0x898, 2, 0)
+#define _MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 IOMUX_PAD(0x424, 0xF8, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 IOMUX_PAD(0x424, 0xF8, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 IOMUX_PAD(0x424, 0xF8, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 IOMUX_PAD(0x424, 0xF8, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 IOMUX_PAD(0x428, 0xFC, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__GPIO6_1 IOMUX_PAD(0x428, 0xFC, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__UART5_RXD_MUX IOMUX_PAD(0x428, 0xFC, 2, 0x898, 3, 0)
+#define _MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 IOMUX_PAD(0x428, 0xFC, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 IOMUX_PAD(0x428, 0xFC, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 IOMUX_PAD(0x428, 0xFC, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 IOMUX_PAD(0x428, 0xFC, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 IOMUX_PAD(0x42C, 0x100, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__GPIO6_2 IOMUX_PAD(0x42C, 0x100, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__UART4_RTS IOMUX_PAD(0x42C, 0x100, 2, 0x88C, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 IOMUX_PAD(0x42C, 0x100, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 IOMUX_PAD(0x42C, 0x100, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 IOMUX_PAD(0x42C, 0x100, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 IOMUX_PAD(0x42C, 0x100, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 IOMUX_PAD(0x430, 0x104, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__GPIO6_3 IOMUX_PAD(0x430, 0x104, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__UART4_CTS IOMUX_PAD(0x430, 0x104, 2, 0x88C, 1, 0)
+#define _MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 IOMUX_PAD(0x430, 0x104, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 IOMUX_PAD(0x430, 0x104, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 IOMUX_PAD(0x430, 0x104, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 IOMUX_PAD(0x430, 0x104, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 IOMUX_PAD(0x434, 0x108, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__GPIO6_4 IOMUX_PAD(0x434, 0x108, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__UART5_RTS IOMUX_PAD(0x434, 0x108, 2, 0x894, 2, 0)
+#define _MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 IOMUX_PAD(0x434, 0x108, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 IOMUX_PAD(0x434, 0x108, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 IOMUX_PAD(0x434, 0x108, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 IOMUX_PAD(0x434, 0x108, 7, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 IOMUX_PAD(0x438, 0x10C, 0, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__GPIO6_5 IOMUX_PAD(0x438, 0x10C, 1, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__UART5_CTS IOMUX_PAD(0x438, 0x10C, 2, 0x894, 3, 0)
+#define _MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 IOMUX_PAD(0x438, 0x10C, 4, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 IOMUX_PAD(0x438, 0x10C, 5, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 IOMUX_PAD(0x438, 0x10C, 6, 0x0, 0, 0)
+#define _MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK IOMUX_PAD(0x438, 0x10C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__EMI_WEIM_A_25 IOMUX_PAD(0x458, 0x110, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__GPIO5_2 IOMUX_PAD(0x458, 0x110, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__ECSPI2_RDY IOMUX_PAD(0x458, 0x110, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__IPU_DI1_PIN12 IOMUX_PAD(0x458, 0x110, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__CSPI_SS1 IOMUX_PAD(0x458, 0x110, 4, 0x790, 1, 0)
+#define _MX53_PAD_EIM_A25__IPU_DI0_D1_CS IOMUX_PAD(0x458, 0x110, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A25__USBPHY1_BISTOK IOMUX_PAD(0x458, 0x110, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 IOMUX_PAD(0x45C, 0x114, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB2__GPIO2_30 IOMUX_PAD(0x45C, 0x114, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK IOMUX_PAD(0x45C, 0x114, 2, 0x76C, 0, 0)
+#define _MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS IOMUX_PAD(0x45C, 0x114, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB2__ECSPI1_SS0 IOMUX_PAD(0x45C, 0x114, 4, 0x7A8, 3, 0)
+#define _MX53_PAD_EIM_EB2__I2C2_SCL IOMUX_PAD(0x45C, 0x114, 5 | IOMUX_CONFIG_SION, 0x81C, 1, 0)
+#define _MX53_PAD_EIM_D16__EMI_WEIM_D_16 IOMUX_PAD(0x460, 0x118, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D16__GPIO3_16 IOMUX_PAD(0x460, 0x118, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D16__IPU_DI0_PIN5 IOMUX_PAD(0x460, 0x118, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK IOMUX_PAD(0x460, 0x118, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D16__ECSPI1_SCLK IOMUX_PAD(0x460, 0x118, 4, 0x79C, 3, 0)
+#define _MX53_PAD_EIM_D16__I2C2_SDA IOMUX_PAD(0x460, 0x118, 5, 0x820, 1, 0)
+#define _MX53_PAD_EIM_D17__EMI_WEIM_D_17 IOMUX_PAD(0x464, 0x11C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D17__GPIO3_17 IOMUX_PAD(0x464, 0x11C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D17__IPU_DI0_PIN6 IOMUX_PAD(0x464, 0x11C, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN IOMUX_PAD(0x464, 0x11C, 3, 0x830, 0, 0)
+#define _MX53_PAD_EIM_D17__ECSPI1_MISO IOMUX_PAD(0x464, 0x11C, 4, 0x7A0, 3, 0)
+#define _MX53_PAD_EIM_D17__I2C3_SCL IOMUX_PAD(0x464, 0x11C, 5, 0x824, 0, 0)
+#define _MX53_PAD_EIM_D18__EMI_WEIM_D_18 IOMUX_PAD(0x468, 0x120, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D18__GPIO3_18 IOMUX_PAD(0x468, 0x120, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D18__IPU_DI0_PIN7 IOMUX_PAD(0x468, 0x120, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO IOMUX_PAD(0x468, 0x120, 3, 0x830, 1, 0)
+#define _MX53_PAD_EIM_D18__ECSPI1_MOSI IOMUX_PAD(0x468, 0x120, 4, 0x7A4, 3, 0)
+#define _MX53_PAD_EIM_D18__I2C3_SDA IOMUX_PAD(0x468, 0x120, 5, 0x828, 0, 0)
+#define _MX53_PAD_EIM_D18__IPU_DI1_D0_CS IOMUX_PAD(0x468, 0x120, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__EMI_WEIM_D_19 IOMUX_PAD(0x46C, 0x124, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__GPIO3_19 IOMUX_PAD(0x46C, 0x124, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__IPU_DI0_PIN8 IOMUX_PAD(0x46C, 0x124, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS IOMUX_PAD(0x46C, 0x124, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__ECSPI1_SS1 IOMUX_PAD(0x46C, 0x124, 4, 0x7AC, 2, 0)
+#define _MX53_PAD_EIM_D19__EPIT1_EPITO IOMUX_PAD(0x46C, 0x124, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D19__UART1_CTS IOMUX_PAD(0x46C, 0x124, 6, 0x874, 0, 0)
+#define _MX53_PAD_EIM_D19__USBOH3_USBH2_OC IOMUX_PAD(0x46C, 0x124, 7, 0x8A4, 0, 0)
+#define _MX53_PAD_EIM_D20__EMI_WEIM_D_20 IOMUX_PAD(0x470, 0x128, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D20__GPIO3_20 IOMUX_PAD(0x470, 0x128, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D20__IPU_DI0_PIN16 IOMUX_PAD(0x470, 0x128, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D20__IPU_SER_DISP0_CS IOMUX_PAD(0x470, 0x128, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D20__CSPI_SS0 IOMUX_PAD(0x470, 0x128, 4, 0x78C, 1, 0)
+#define _MX53_PAD_EIM_D20__EPIT2_EPITO IOMUX_PAD(0x470, 0x128, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D20__UART1_RTS IOMUX_PAD(0x470, 0x128, 6, 0x874, 1, 0)
+#define _MX53_PAD_EIM_D20__USBOH3_USBH2_PWR IOMUX_PAD(0x470, 0x128, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D21__EMI_WEIM_D_21 IOMUX_PAD(0x474, 0x12C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D21__GPIO3_21 IOMUX_PAD(0x474, 0x12C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D21__IPU_DI0_PIN17 IOMUX_PAD(0x474, 0x12C, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK IOMUX_PAD(0x474, 0x12C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D21__CSPI_SCLK IOMUX_PAD(0x474, 0x12C, 4, 0x780, 1, 0)
+#define _MX53_PAD_EIM_D21__I2C1_SCL IOMUX_PAD(0x474, 0x12C, 5, 0x814, 1, 0)
+#define _MX53_PAD_EIM_D21__USBOH3_USBOTG_OC IOMUX_PAD(0x474, 0x12C, 6, 0x89C, 1, 0)
+#define _MX53_PAD_EIM_D22__EMI_WEIM_D_22 IOMUX_PAD(0x478, 0x130, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D22__GPIO3_22 IOMUX_PAD(0x478, 0x130, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D22__IPU_DI0_PIN1 IOMUX_PAD(0x478, 0x130, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN IOMUX_PAD(0x478, 0x130, 3, 0x82C, 0, 0)
+#define _MX53_PAD_EIM_D22__CSPI_MISO IOMUX_PAD(0x478, 0x130, 4, 0x784, 1, 0)
+#define _MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR IOMUX_PAD(0x478, 0x130, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__EMI_WEIM_D_23 IOMUX_PAD(0x47C, 0x134, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__GPIO3_23 IOMUX_PAD(0x47C, 0x134, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__UART3_CTS IOMUX_PAD(0x47C, 0x134, 2, 0x884, 0, 0)
+#define _MX53_PAD_EIM_D23__UART1_DCD IOMUX_PAD(0x47C, 0x134, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__IPU_DI0_D0_CS IOMUX_PAD(0x47C, 0x134, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__IPU_DI1_PIN2 IOMUX_PAD(0x47C, 0x134, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN IOMUX_PAD(0x47C, 0x134, 6, 0x834, 0, 0)
+#define _MX53_PAD_EIM_D23__IPU_DI1_PIN14 IOMUX_PAD(0x47C, 0x134, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 IOMUX_PAD(0x480, 0x138, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB3__GPIO2_31 IOMUX_PAD(0x480, 0x138, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB3__UART3_RTS IOMUX_PAD(0x480, 0x138, 2, 0x884, 1, 0)
+#define _MX53_PAD_EIM_EB3__UART1_RI IOMUX_PAD(0x480, 0x138, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB3__IPU_DI1_PIN3 IOMUX_PAD(0x480, 0x138, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC IOMUX_PAD(0x480, 0x138, 6, 0x838, 0, 0)
+#define _MX53_PAD_EIM_EB3__IPU_DI1_PIN16 IOMUX_PAD(0x480, 0x138, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D24__EMI_WEIM_D_24 IOMUX_PAD(0x484, 0x13C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D24__GPIO3_24 IOMUX_PAD(0x484, 0x13C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D24__UART3_TXD_MUX IOMUX_PAD(0x484, 0x13C, 2, 0x888, 0, 0)
+#define _MX53_PAD_EIM_D24__ECSPI1_SS2 IOMUX_PAD(0x484, 0x13C, 3, 0x7B0, 1, 0)
+#define _MX53_PAD_EIM_D24__CSPI_SS2 IOMUX_PAD(0x484, 0x13C, 4, 0x794, 1, 0)
+#define _MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS IOMUX_PAD(0x484, 0x13C, 5, 0x754, 1, 0)
+#define _MX53_PAD_EIM_D24__ECSPI2_SS2 IOMUX_PAD(0x484, 0x13C, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D24__UART1_DTR IOMUX_PAD(0x484, 0x13C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D25__EMI_WEIM_D_25 IOMUX_PAD(0x488, 0x140, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D25__GPIO3_25 IOMUX_PAD(0x488, 0x140, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D25__UART3_RXD_MUX IOMUX_PAD(0x488, 0x140, 2, 0x888, 1, 0)
+#define _MX53_PAD_EIM_D25__ECSPI1_SS3 IOMUX_PAD(0x488, 0x140, 3, 0x7B4, 1, 0)
+#define _MX53_PAD_EIM_D25__CSPI_SS3 IOMUX_PAD(0x488, 0x140, 4, 0x798, 1, 0)
+#define _MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC IOMUX_PAD(0x488, 0x140, 5, 0x750, 1, 0)
+#define _MX53_PAD_EIM_D25__ECSPI2_SS3 IOMUX_PAD(0x488, 0x140, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D25__UART1_DSR IOMUX_PAD(0x488, 0x140, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__EMI_WEIM_D_26 IOMUX_PAD(0x48C, 0x144, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__GPIO3_26 IOMUX_PAD(0x48C, 0x144, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__UART2_TXD_MUX IOMUX_PAD(0x48C, 0x144, 2, 0x880, 0, 0)
+#define _MX53_PAD_EIM_D26__FIRI_RXD IOMUX_PAD(0x48C, 0x144, 3, 0x80C, 0, 0)
+#define _MX53_PAD_EIM_D26__IPU_CSI0_D_1 IOMUX_PAD(0x48C, 0x144, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__IPU_DI1_PIN11 IOMUX_PAD(0x48C, 0x144, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__IPU_SISG_2 IOMUX_PAD(0x48C, 0x144, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 IOMUX_PAD(0x48C, 0x144, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__EMI_WEIM_D_27 IOMUX_PAD(0x490, 0x148, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__GPIO3_27 IOMUX_PAD(0x490, 0x148, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__UART2_RXD_MUX IOMUX_PAD(0x490, 0x148, 2, 0x880, 1, 0)
+#define _MX53_PAD_EIM_D27__FIRI_TXD IOMUX_PAD(0x490, 0x148, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__IPU_CSI0_D_0 IOMUX_PAD(0x490, 0x148, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__IPU_DI1_PIN13 IOMUX_PAD(0x490, 0x148, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__IPU_SISG_3 IOMUX_PAD(0x490, 0x148, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 IOMUX_PAD(0x490, 0x148, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D28__EMI_WEIM_D_28 IOMUX_PAD(0x494, 0x14C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D28__GPIO3_28 IOMUX_PAD(0x494, 0x14C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D28__UART2_CTS IOMUX_PAD(0x494, 0x14C, 2, 0x87C, 0, 0)
+#define _MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO IOMUX_PAD(0x494, 0x14C, 3, 0x82C, 1, 0)
+#define _MX53_PAD_EIM_D28__CSPI_MOSI IOMUX_PAD(0x494, 0x14C, 4, 0x788, 1, 0)
+#define _MX53_PAD_EIM_D28__I2C1_SDA IOMUX_PAD(0x494, 0x14C, 5, 0x818, 1, 0)
+#define _MX53_PAD_EIM_D28__IPU_EXT_TRIG IOMUX_PAD(0x494, 0x14C, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D28__IPU_DI0_PIN13 IOMUX_PAD(0x494, 0x14C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D29__EMI_WEIM_D_29 IOMUX_PAD(0x498, 0x150, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D29__GPIO3_29 IOMUX_PAD(0x498, 0x150, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D29__UART2_RTS IOMUX_PAD(0x498, 0x150, 2, 0x87C, 1, 0)
+#define _MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS IOMUX_PAD(0x498, 0x150, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D29__CSPI_SS0 IOMUX_PAD(0x498, 0x150, 4, 0x78C, 2, 0)
+#define _MX53_PAD_EIM_D29__IPU_DI1_PIN15 IOMUX_PAD(0x498, 0x150, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D29__IPU_CSI1_VSYNC IOMUX_PAD(0x498, 0x150, 6, 0x83C, 0, 0)
+#define _MX53_PAD_EIM_D29__IPU_DI0_PIN14 IOMUX_PAD(0x498, 0x150, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__EMI_WEIM_D_30 IOMUX_PAD(0x49C, 0x154, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__GPIO3_30 IOMUX_PAD(0x49C, 0x154, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__UART3_CTS IOMUX_PAD(0x49C, 0x154, 2, 0x884, 2, 0)
+#define _MX53_PAD_EIM_D30__IPU_CSI0_D_3 IOMUX_PAD(0x49C, 0x154, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__IPU_DI0_PIN11 IOMUX_PAD(0x49C, 0x154, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 IOMUX_PAD(0x49C, 0x154, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D30__USBOH3_USBH1_OC IOMUX_PAD(0x49C, 0x154, 6, 0x8A0, 0, 0)
+#define _MX53_PAD_EIM_D30__USBOH3_USBH2_OC IOMUX_PAD(0x49C, 0x154, 7, 0x8A4, 1, 0)
+#define _MX53_PAD_EIM_D31__EMI_WEIM_D_31 IOMUX_PAD(0x4A0, 0x158, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__GPIO3_31 IOMUX_PAD(0x4A0, 0x158, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__UART3_RTS IOMUX_PAD(0x4A0, 0x158, 2, 0x884, 3, 0)
+#define _MX53_PAD_EIM_D31__IPU_CSI0_D_2 IOMUX_PAD(0x4A0, 0x158, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__IPU_DI0_PIN12 IOMUX_PAD(0x4A0, 0x158, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 IOMUX_PAD(0x4A0, 0x158, 5, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__USBOH3_USBH1_PWR IOMUX_PAD(0x4A0, 0x158, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_D31__USBOH3_USBH2_PWR IOMUX_PAD(0x4A0, 0x158, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__EMI_WEIM_A_24 IOMUX_PAD(0x4A8, 0x15C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__GPIO5_4 IOMUX_PAD(0x4A8, 0x15C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 IOMUX_PAD(0x4A8, 0x15C, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__IPU_CSI1_D_19 IOMUX_PAD(0x4A8, 0x15C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__IPU_SISG_2 IOMUX_PAD(0x4A8, 0x15C, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A24__USBPHY2_BVALID IOMUX_PAD(0x4A8, 0x15C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__EMI_WEIM_A_23 IOMUX_PAD(0x4AC, 0x160, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__GPIO6_6 IOMUX_PAD(0x4AC, 0x160, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 IOMUX_PAD(0x4AC, 0x160, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__IPU_CSI1_D_18 IOMUX_PAD(0x4AC, 0x160, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__IPU_SISG_3 IOMUX_PAD(0x4AC, 0x160, 6, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A23__USBPHY2_ENDSESSION IOMUX_PAD(0x4AC, 0x160, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A22__EMI_WEIM_A_22 IOMUX_PAD(0x4B0, 0x164, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A22__GPIO2_16 IOMUX_PAD(0x4B0, 0x164, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 IOMUX_PAD(0x4B0, 0x164, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A22__IPU_CSI1_D_17 IOMUX_PAD(0x4B0, 0x164, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A22__SRC_BT_CFG1_7 IOMUX_PAD(0x4B0, 0x164, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A21__EMI_WEIM_A_21 IOMUX_PAD(0x4B4, 0x168, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A21__GPIO2_17 IOMUX_PAD(0x4B4, 0x168, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 IOMUX_PAD(0x4B4, 0x168, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A21__IPU_CSI1_D_16 IOMUX_PAD(0x4B4, 0x168, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A21__SRC_BT_CFG1_6 IOMUX_PAD(0x4B4, 0x168, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A20__EMI_WEIM_A_20 IOMUX_PAD(0x4B8, 0x16C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A20__GPIO2_18 IOMUX_PAD(0x4B8, 0x16C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 IOMUX_PAD(0x4B8, 0x16C, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A20__IPU_CSI1_D_15 IOMUX_PAD(0x4B8, 0x16C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A20__SRC_BT_CFG1_5 IOMUX_PAD(0x4B8, 0x16C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A19__EMI_WEIM_A_19 IOMUX_PAD(0x4BC, 0x170, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A19__GPIO2_19 IOMUX_PAD(0x4BC, 0x170, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 IOMUX_PAD(0x4BC, 0x170, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A19__IPU_CSI1_D_14 IOMUX_PAD(0x4BC, 0x170, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A19__SRC_BT_CFG1_4 IOMUX_PAD(0x4BC, 0x170, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A18__EMI_WEIM_A_18 IOMUX_PAD(0x4C0, 0x174, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A18__GPIO2_20 IOMUX_PAD(0x4C0, 0x174, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 IOMUX_PAD(0x4C0, 0x174, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A18__IPU_CSI1_D_13 IOMUX_PAD(0x4C0, 0x174, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A18__SRC_BT_CFG1_3 IOMUX_PAD(0x4C0, 0x174, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A17__EMI_WEIM_A_17 IOMUX_PAD(0x4C4, 0x178, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A17__GPIO2_21 IOMUX_PAD(0x4C4, 0x178, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 IOMUX_PAD(0x4C4, 0x178, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A17__IPU_CSI1_D_12 IOMUX_PAD(0x4C4, 0x178, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A17__SRC_BT_CFG1_2 IOMUX_PAD(0x4C4, 0x178, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A16__EMI_WEIM_A_16 IOMUX_PAD(0x4C8, 0x17C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A16__GPIO2_22 IOMUX_PAD(0x4C8, 0x17C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK IOMUX_PAD(0x4C8, 0x17C, 2, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK IOMUX_PAD(0x4C8, 0x17C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_A16__SRC_BT_CFG1_1 IOMUX_PAD(0x4C8, 0x17C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 IOMUX_PAD(0x4CC, 0x180, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS0__GPIO2_23 IOMUX_PAD(0x4CC, 0x180, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS0__ECSPI2_SCLK IOMUX_PAD(0x4CC, 0x180, 2, 0x7B8, 2, 0)
+#define _MX53_PAD_EIM_CS0__IPU_DI1_PIN5 IOMUX_PAD(0x4CC, 0x180, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 IOMUX_PAD(0x4D0, 0x184, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS1__GPIO2_24 IOMUX_PAD(0x4D0, 0x184, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_CS1__ECSPI2_MOSI IOMUX_PAD(0x4D0, 0x184, 2, 0x7C0, 2, 0)
+#define _MX53_PAD_EIM_CS1__IPU_DI1_PIN6 IOMUX_PAD(0x4D0, 0x184, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_OE__EMI_WEIM_OE IOMUX_PAD(0x4D4, 0x188, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_OE__GPIO2_25 IOMUX_PAD(0x4D4, 0x188, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_OE__ECSPI2_MISO IOMUX_PAD(0x4D4, 0x188, 2, 0x7BC, 2, 0)
+#define _MX53_PAD_EIM_OE__IPU_DI1_PIN7 IOMUX_PAD(0x4D4, 0x188, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_OE__USBPHY2_IDDIG IOMUX_PAD(0x4D4, 0x188, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_RW__EMI_WEIM_RW IOMUX_PAD(0x4D8, 0x18C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_RW__GPIO2_26 IOMUX_PAD(0x4D8, 0x18C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_RW__ECSPI2_SS0 IOMUX_PAD(0x4D8, 0x18C, 2, 0x7C4, 2, 0)
+#define _MX53_PAD_EIM_RW__IPU_DI1_PIN8 IOMUX_PAD(0x4D8, 0x18C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT IOMUX_PAD(0x4D8, 0x18C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_LBA__EMI_WEIM_LBA IOMUX_PAD(0x4DC, 0x190, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_LBA__GPIO2_27 IOMUX_PAD(0x4DC, 0x190, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_LBA__ECSPI2_SS1 IOMUX_PAD(0x4DC, 0x190, 2, 0x7C8, 1, 0)
+#define _MX53_PAD_EIM_LBA__IPU_DI1_PIN17 IOMUX_PAD(0x4DC, 0x190, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 IOMUX_PAD(0x4DC, 0x190, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 IOMUX_PAD(0x4E4, 0x194, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB0__GPIO2_28 IOMUX_PAD(0x4E4, 0x194, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 IOMUX_PAD(0x4E4, 0x194, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB0__IPU_CSI1_D_11 IOMUX_PAD(0x4E4, 0x194, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB0__GPC_PMIC_RDY IOMUX_PAD(0x4E4, 0x194, 5, 0x810, 0, 0)
+#define _MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 IOMUX_PAD(0x4E4, 0x194, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 IOMUX_PAD(0x4E8, 0x198, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB1__GPIO2_29 IOMUX_PAD(0x4E8, 0x198, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 IOMUX_PAD(0x4E8, 0x198, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB1__IPU_CSI1_D_10 IOMUX_PAD(0x4E8, 0x198, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 IOMUX_PAD(0x4E8, 0x198, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 IOMUX_PAD(0x4EC, 0x19C, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA0__GPIO3_0 IOMUX_PAD(0x4EC, 0x19C, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 IOMUX_PAD(0x4EC, 0x19C, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA0__IPU_CSI1_D_9 IOMUX_PAD(0x4EC, 0x19C, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 IOMUX_PAD(0x4EC, 0x19C, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 IOMUX_PAD(0x4F0, 0x1A0, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA1__GPIO3_1 IOMUX_PAD(0x4F0, 0x1A0, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 IOMUX_PAD(0x4F0, 0x1A0, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA1__IPU_CSI1_D_8 IOMUX_PAD(0x4F0, 0x1A0, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 IOMUX_PAD(0x4F0, 0x1A0, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 IOMUX_PAD(0x4F4, 0x1A4, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA2__GPIO3_2 IOMUX_PAD(0x4F4, 0x1A4, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 IOMUX_PAD(0x4F4, 0x1A4, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA2__IPU_CSI1_D_7 IOMUX_PAD(0x4F4, 0x1A4, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 IOMUX_PAD(0x4F4, 0x1A4, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 IOMUX_PAD(0x4F8, 0x1A8, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA3__GPIO3_3 IOMUX_PAD(0x4F8, 0x1A8, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 IOMUX_PAD(0x4F8, 0x1A8, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA3__IPU_CSI1_D_6 IOMUX_PAD(0x4F8, 0x1A8, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 IOMUX_PAD(0x4F8, 0x1A8, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 IOMUX_PAD(0x4FC, 0x1AC, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA4__GPIO3_4 IOMUX_PAD(0x4FC, 0x1AC, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 IOMUX_PAD(0x4FC, 0x1AC, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA4__IPU_CSI1_D_5 IOMUX_PAD(0x4FC, 0x1AC, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 IOMUX_PAD(0x4FC, 0x1AC, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 IOMUX_PAD(0x500, 0x1B0, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA5__GPIO3_5 IOMUX_PAD(0x500, 0x1B0, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 IOMUX_PAD(0x500, 0x1B0, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA5__IPU_CSI1_D_4 IOMUX_PAD(0x500, 0x1B0, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 IOMUX_PAD(0x500, 0x1B0, 17, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 IOMUX_PAD(0x504, 0x1B4, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA6__GPIO3_6 IOMUX_PAD(0x504, 0x1B4, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 IOMUX_PAD(0x504, 0x1B4, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA6__IPU_CSI1_D_3 IOMUX_PAD(0x504, 0x1B4, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 IOMUX_PAD(0x504, 0x1B4, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 IOMUX_PAD(0x508, 0x1B8, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA7__GPIO3_7 IOMUX_PAD(0x508, 0x1B8, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 IOMUX_PAD(0x508, 0x1B8, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA7__IPU_CSI1_D_2 IOMUX_PAD(0x508, 0x1B8, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 IOMUX_PAD(0x508, 0x1B8, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 IOMUX_PAD(0x50C, 0x1BC, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA8__GPIO3_8 IOMUX_PAD(0x50C, 0x1BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 IOMUX_PAD(0x50C, 0x1BC, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA8__IPU_CSI1_D_1 IOMUX_PAD(0x50C, 0x1BC, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 IOMUX_PAD(0x50C, 0x1BC, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 IOMUX_PAD(0x510, 0x1C0, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA9__GPIO3_9 IOMUX_PAD(0x510, 0x1C0, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 IOMUX_PAD(0x510, 0x1C0, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA9__IPU_CSI1_D_0 IOMUX_PAD(0x510, 0x1C0, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 IOMUX_PAD(0x510, 0x1C0, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 IOMUX_PAD(0x514, 0x1C4, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA10__GPIO3_10 IOMUX_PAD(0x514, 0x1C4, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA10__IPU_DI1_PIN15 IOMUX_PAD(0x514, 0x1C4, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN IOMUX_PAD(0x514, 0x1C4, 4, 0x834, 1, 0)
+#define _MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 IOMUX_PAD(0x514, 0x1C4, 7, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 IOMUX_PAD(0x518, 0x1C8, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA11__GPIO3_11 IOMUX_PAD(0x518, 0x1C8, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA11__IPU_DI1_PIN2 IOMUX_PAD(0x518, 0x1C8, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC IOMUX_PAD(0x518, 0x1C8, 4, 0x838, 1, 0)
+#define _MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 IOMUX_PAD(0x51C, 0x1CC, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA12__GPIO3_12 IOMUX_PAD(0x51C, 0x1CC, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA12__IPU_DI1_PIN3 IOMUX_PAD(0x51C, 0x1CC, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC IOMUX_PAD(0x51C, 0x1CC, 4, 0x83C, 1, 0)
+#define _MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 IOMUX_PAD(0x520, 0x1D0, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA13__GPIO3_13 IOMUX_PAD(0x520, 0x1D0, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA13__IPU_DI1_D0_CS IOMUX_PAD(0x520, 0x1D0, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK IOMUX_PAD(0x520, 0x1D0, 4, 0x76C, 1, 0)
+#define _MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 IOMUX_PAD(0x524, 0x1D4, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA14__GPIO3_14 IOMUX_PAD(0x524, 0x1D4, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA14__IPU_DI1_D1_CS IOMUX_PAD(0x524, 0x1D4, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK IOMUX_PAD(0x524, 0x1D4, 4, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 IOMUX_PAD(0x528, 0x1D8, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA15__GPIO3_15 IOMUX_PAD(0x528, 0x1D8, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA15__IPU_DI1_PIN1 IOMUX_PAD(0x528, 0x1D8, 3, 0x0, 0, 0)
+#define _MX53_PAD_EIM_DA15__IPU_DI1_PIN4 IOMUX_PAD(0x528, 0x1D8, 4, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B IOMUX_PAD(0x52C, 0x1DC, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_WE_B__GPIO6_12 IOMUX_PAD(0x52C, 0x1DC, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B IOMUX_PAD(0x530, 0x1E0, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_RE_B__GPIO6_13 IOMUX_PAD(0x530, 0x1E0, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT IOMUX_PAD(0x534, 0x1E4, 0, 0x0, 0, 0)
+#define _MX53_PAD_EIM_WAIT__GPIO5_0 IOMUX_PAD(0x534, 0x1E4, 1, 0x0, 0, 0)
+#define _MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B IOMUX_PAD(0x534, 0x1E4, 2, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX3_P__GPIO6_22 IOMUX_PAD(NON_PAD_I, 0x1EC, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 IOMUX_PAD(NON_PAD_I, 0x1EC, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX2_P__GPIO6_24 IOMUX_PAD(NON_PAD_I, 0x1F0, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 IOMUX_PAD(NON_PAD_I, 0x1F0, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_CLK_P__GPIO6_26 IOMUX_PAD(NON_PAD_I, 0x1F4, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK IOMUX_PAD(NON_PAD_I, 0x1F4, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX1_P__GPIO6_28 IOMUX_PAD(NON_PAD_I, 0x1F8, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 IOMUX_PAD(NON_PAD_I, 0x1F8, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX0_P__GPIO6_30 IOMUX_PAD(NON_PAD_I, 0x1FC, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 IOMUX_PAD(NON_PAD_I, 0x1FC, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX3_P__GPIO7_22 IOMUX_PAD(NON_PAD_I, 0x200, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 IOMUX_PAD(NON_PAD_I, 0x200, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_CLK_P__GPIO7_24 IOMUX_PAD(NON_PAD_I, 0x204, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK IOMUX_PAD(NON_PAD_I, 0x204, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX2_P__GPIO7_26 IOMUX_PAD(NON_PAD_I, 0x208, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 IOMUX_PAD(NON_PAD_I, 0x208, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX1_P__GPIO7_28 IOMUX_PAD(NON_PAD_I, 0x20C, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 IOMUX_PAD(NON_PAD_I, 0x20C, 1, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX0_P__GPIO7_30 IOMUX_PAD(NON_PAD_I, 0x210, 0, 0x0, 0, 0)
+#define _MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 IOMUX_PAD(NON_PAD_I, 0x210, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_10__GPIO4_0 IOMUX_PAD(0x540, 0x214, 0, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_10__OSC32k_32K_OUT IOMUX_PAD(0x540, 0x214, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_11__GPIO4_1 IOMUX_PAD(0x544, 0x218, 0, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_12__GPIO4_2 IOMUX_PAD(0x548, 0x21C, 0, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_13__GPIO4_3 IOMUX_PAD(0x54C, 0x220, 0, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_14__GPIO4_4 IOMUX_PAD(0x550, 0x224, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CLE__EMI_NANDF_CLE IOMUX_PAD(0x5A0, 0x228, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CLE__GPIO6_7 IOMUX_PAD(0x5A0, 0x228, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 IOMUX_PAD(0x5A0, 0x228, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_ALE__EMI_NANDF_ALE IOMUX_PAD(0x5A4, 0x22C, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_ALE__GPIO6_8 IOMUX_PAD(0x5A4, 0x22C, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 IOMUX_PAD(0x5A4, 0x22C, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B IOMUX_PAD(0x5A8, 0x230, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_WP_B__GPIO6_9 IOMUX_PAD(0x5A8, 0x230, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 IOMUX_PAD(0x5A8, 0x230, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 IOMUX_PAD(0x5AC, 0x234, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_RB0__GPIO6_10 IOMUX_PAD(0x5AC, 0x234, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 IOMUX_PAD(0x5AC, 0x234, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 IOMUX_PAD(0x5B0, 0x238, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS0__GPIO6_11 IOMUX_PAD(0x5B0, 0x238, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 IOMUX_PAD(0x5B0, 0x238, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 IOMUX_PAD(0x5B4, 0x23C, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS1__GPIO6_14 IOMUX_PAD(0x5B4, 0x23C, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS1__MLB_MLBCLK IOMUX_PAD(0x5B4, 0x23C, 6, 0x858, 0, 0)
+#define _MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 IOMUX_PAD(0x5B4, 0x23C, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 IOMUX_PAD(0x5B8, 0x240, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__GPIO6_15 IOMUX_PAD(0x5B8, 0x240, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__IPU_SISG_0 IOMUX_PAD(0x5B8, 0x240, 2, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__ESAI1_TX0 IOMUX_PAD(0x5B8, 0x240, 3, 0x7E4, 0, 0)
+#define _MX53_PAD_NANDF_CS2__EMI_WEIM_CRE IOMUX_PAD(0x5B8, 0x240, 4, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK IOMUX_PAD(0x5B8, 0x240, 5, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS2__MLB_MLBSIG IOMUX_PAD(0x5B8, 0x240, 6, 0x860, 0, 0)
+#define _MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 IOMUX_PAD(0x5B8, 0x240, 7, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 IOMUX_PAD(0x5BC, 0x244, 0, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS3__GPIO6_16 IOMUX_PAD(0x5BC, 0x244, 1, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS3__IPU_SISG_1 IOMUX_PAD(0x5BC, 0x244, 2, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS3__ESAI1_TX1 IOMUX_PAD(0x5BC, 0x244, 3, 0x7E8, 0, 0)
+#define _MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 IOMUX_PAD(0x5BC, 0x244, 4, 0x0, 0, 0)
+#define _MX53_PAD_NANDF_CS3__MLB_MLBDAT IOMUX_PAD(0x5BC, 0x244, 6, 0x85C, 0, 0)
+#define _MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 IOMUX_PAD(0x5BC, 0x244, 7, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDIO__FEC_MDIO IOMUX_PAD(0x5C4, 0x248, 0, 0x804, 1, 0)
+#define _MX53_PAD_FEC_MDIO__GPIO1_22 IOMUX_PAD(0x5C4, 0x248, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDIO__ESAI1_SCKR IOMUX_PAD(0x5C4, 0x248, 2, 0x7DC, 0, 0)
+#define _MX53_PAD_FEC_MDIO__FEC_COL IOMUX_PAD(0x5C4, 0x248, 3, 0x800, 1, 0)
+#define _MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 IOMUX_PAD(0x5C4, 0x248, 4, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 IOMUX_PAD(0x5C4, 0x248, 5, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 IOMUX_PAD(0x5C4, 0x248, 6, 0x0, 0, 0)
+#define _MX53_PAD_FEC_REF_CLK__FEC_TX_CLK IOMUX_PAD(0x5C8, 0x24C, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_REF_CLK__GPIO1_23 IOMUX_PAD(0x5C8, 0x24C, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_REF_CLK__ESAI1_FSR IOMUX_PAD(0x5C8, 0x24C, 2, 0x7CC, 0, 0)
+#define _MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 IOMUX_PAD(0x5C8, 0x24C, 5, 0x0, 0, 0)
+#define _MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 IOMUX_PAD(0x5C8, 0x24C, 6, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RX_ER__FEC_RX_ER IOMUX_PAD(0x5CC, 0x250, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RX_ER__GPIO1_24 IOMUX_PAD(0x5CC, 0x250, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RX_ER__ESAI1_HCKR IOMUX_PAD(0x5CC, 0x250, 2, 0x7D4, 0, 0)
+#define _MX53_PAD_FEC_RX_ER__FEC_RX_CLK IOMUX_PAD(0x5CC, 0x250, 3, 0x808, 1, 0)
+#define _MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 IOMUX_PAD(0x5CC, 0x250, 4, 0x0, 0, 0)
+#define _MX53_PAD_FEC_CRS_DV__FEC_RX_DV IOMUX_PAD(0x5D0, 0x254, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_CRS_DV__GPIO1_25 IOMUX_PAD(0x5D0, 0x254, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_CRS_DV__ESAI1_SCKT IOMUX_PAD(0x5D0, 0x254, 2, 0x7E0, 0, 0)
+#define _MX53_PAD_FEC_RXD1__FEC_RDATA_1 IOMUX_PAD(0x5D4, 0x258, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RXD1__GPIO1_26 IOMUX_PAD(0x5D4, 0x258, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RXD1__ESAI1_FST IOMUX_PAD(0x5D4, 0x258, 2, 0x7D0, 0, 0)
+#define _MX53_PAD_FEC_RXD1__MLB_MLBSIG IOMUX_PAD(0x5D4, 0x258, 3, 0x860, 1, 0)
+#define _MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 IOMUX_PAD(0x5D4, 0x258, 4, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RXD0__FEC_RDATA_0 IOMUX_PAD(0x5D8, 0x25C, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RXD0__GPIO1_27 IOMUX_PAD(0x5D8, 0x25C, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_RXD0__ESAI1_HCKT IOMUX_PAD(0x5D8, 0x25C, 2, 0x7D8, 0, 0)
+#define _MX53_PAD_FEC_RXD0__OSC32k_32K_OUT IOMUX_PAD(0x5D8, 0x25C, 3, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TX_EN__FEC_TX_EN IOMUX_PAD(0x5DC, 0x260, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TX_EN__GPIO1_28 IOMUX_PAD(0x5DC, 0x260, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 IOMUX_PAD(0x5DC, 0x260, 2, 0x7F0, 0, 0)
+#define _MX53_PAD_FEC_TXD1__FEC_TDATA_1 IOMUX_PAD(0x5E0, 0x264, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TXD1__GPIO1_29 IOMUX_PAD(0x5E0, 0x264, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 IOMUX_PAD(0x5E0, 0x264, 2, 0x7EC, 0, 0)
+#define _MX53_PAD_FEC_TXD1__MLB_MLBCLK IOMUX_PAD(0x5E0, 0x264, 3, 0x858, 1, 0)
+#define _MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK IOMUX_PAD(0x5E0, 0x264, 4, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TXD0__FEC_TDATA_0 IOMUX_PAD(0x5E4, 0x268, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TXD0__GPIO1_30 IOMUX_PAD(0x5E4, 0x268, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 IOMUX_PAD(0x5E4, 0x268, 2, 0x7F4, 0, 0)
+#define _MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 IOMUX_PAD(0x5E4, 0x268, 7, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(0x5E8, 0x26C, 0, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDC__GPIO1_31 IOMUX_PAD(0x5E8, 0x26C, 1, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 IOMUX_PAD(0x5E8, 0x26C, 2, 0x7F8, 0, 0)
+#define _MX53_PAD_FEC_MDC__MLB_MLBDAT IOMUX_PAD(0x5E8, 0x26C, 3, 0x85C, 1, 0)
+#define _MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG IOMUX_PAD(0x5E8, 0x26C, 4, 0x0, 0, 0)
+#define _MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 IOMUX_PAD(0x5E8, 0x26C, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOW__PATA_DIOW IOMUX_PAD(0x5F0, 0x270, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOW__GPIO6_17 IOMUX_PAD(0x5F0, 0x270, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOW__UART1_TXD_MUX IOMUX_PAD(0x5F0, 0x270, 3, 0x878, 2, 0)
+#define _MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 IOMUX_PAD(0x5F0, 0x270, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMACK__PATA_DMACK IOMUX_PAD(0x5F4, 0x274, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMACK__GPIO6_18 IOMUX_PAD(0x5F4, 0x274, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMACK__UART1_RXD_MUX IOMUX_PAD(0x5F4, 0x274, 3, 0x878, 3, 0)
+#define _MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 IOMUX_PAD(0x5F4, 0x274, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMARQ__PATA_DMARQ IOMUX_PAD(0x5F8, 0x278, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMARQ__GPIO7_0 IOMUX_PAD(0x5F8, 0x278, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMARQ__UART2_TXD_MUX IOMUX_PAD(0x5F8, 0x278, 3, 0x880, 2, 0)
+#define _MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 IOMUX_PAD(0x5F8, 0x278, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 IOMUX_PAD(0x5F8, 0x278, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN IOMUX_PAD(0x5FC, 0x27C, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_BUFFER_EN__GPIO7_1 IOMUX_PAD(0x5FC, 0x27C, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX IOMUX_PAD(0x5FC, 0x27C, 3, 0x880, 3, 0)
+#define _MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 IOMUX_PAD(0x5FC, 0x27C, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 IOMUX_PAD(0x5FC, 0x27C, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_INTRQ__PATA_INTRQ IOMUX_PAD(0x600, 0x280, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_INTRQ__GPIO7_2 IOMUX_PAD(0x600, 0x280, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_INTRQ__UART2_CTS IOMUX_PAD(0x600, 0x280, 3, 0x87C, 2, 0)
+#define _MX53_PAD_PATA_INTRQ__CAN1_TXCAN IOMUX_PAD(0x600, 0x280, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 IOMUX_PAD(0x600, 0x280, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 IOMUX_PAD(0x600, 0x280, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOR__PATA_DIOR IOMUX_PAD(0x604, 0x284, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOR__GPIO7_3 IOMUX_PAD(0x604, 0x284, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DIOR__UART2_RTS IOMUX_PAD(0x604, 0x284, 3, 0x87C, 3, 0)
+#define _MX53_PAD_PATA_DIOR__CAN1_RXCAN IOMUX_PAD(0x604, 0x284, 4, 0x760, 1, 0)
+#define _MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 IOMUX_PAD(0x604, 0x284, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B IOMUX_PAD(0x608, 0x288, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_RESET_B__GPIO7_4 IOMUX_PAD(0x608, 0x288, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_RESET_B__ESDHC3_CMD IOMUX_PAD(0x608, 0x288, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_RESET_B__UART1_CTS IOMUX_PAD(0x608, 0x288, 3, 0x874, 2, 0)
+#define _MX53_PAD_PATA_RESET_B__CAN2_TXCAN IOMUX_PAD(0x608, 0x288, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 IOMUX_PAD(0x608, 0x288, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_IORDY__PATA_IORDY IOMUX_PAD(0x60C, 0x28C, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_IORDY__GPIO7_5 IOMUX_PAD(0x60C, 0x28C, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_IORDY__ESDHC3_CLK IOMUX_PAD(0x60C, 0x28C, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_IORDY__UART1_RTS IOMUX_PAD(0x60C, 0x28C, 3, 0x874, 3, 0)
+#define _MX53_PAD_PATA_IORDY__CAN2_RXCAN IOMUX_PAD(0x60C, 0x28C, 4, 0x764, 1, 0)
+#define _MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 IOMUX_PAD(0x60C, 0x28C, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_0__PATA_DA_0 IOMUX_PAD(0x610, 0x290, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_0__GPIO7_6 IOMUX_PAD(0x610, 0x290, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_0__ESDHC3_RST IOMUX_PAD(0x610, 0x290, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_0__OWIRE_LINE IOMUX_PAD(0x610, 0x290, 4, 0x864, 0, 0)
+#define _MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 IOMUX_PAD(0x610, 0x290, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_1__PATA_DA_1 IOMUX_PAD(0x614, 0x294, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_1__GPIO7_7 IOMUX_PAD(0x614, 0x294, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_1__ESDHC4_CMD IOMUX_PAD(0x614, 0x294, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_1__UART3_CTS IOMUX_PAD(0x614, 0x294, 4, 0x884, 4, 0)
+#define _MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 IOMUX_PAD(0x614, 0x294, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_2__PATA_DA_2 IOMUX_PAD(0x618, 0x298, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_2__GPIO7_8 IOMUX_PAD(0x618, 0x298, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_2__ESDHC4_CLK IOMUX_PAD(0x618, 0x298, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DA_2__UART3_RTS IOMUX_PAD(0x618, 0x298, 4, 0x884, 5, 0)
+#define _MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 IOMUX_PAD(0x618, 0x298, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_0__PATA_CS_0 IOMUX_PAD(0x61C, 0x29C, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_0__GPIO7_9 IOMUX_PAD(0x61C, 0x29C, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_0__UART3_TXD_MUX IOMUX_PAD(0x61C, 0x29C, 4, 0x888, 2, 0)
+#define _MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 IOMUX_PAD(0x61C, 0x29C, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_1__PATA_CS_1 IOMUX_PAD(0x620, 0x2A0, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_1__GPIO7_10 IOMUX_PAD(0x620, 0x2A0, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_CS_1__UART3_RXD_MUX IOMUX_PAD(0x620, 0x2A0, 4, 0x888, 3, 0)
+#define _MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 IOMUX_PAD(0x620, 0x2A0, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__PATA_DATA_0 IOMUX_PAD(0x628, 0x2A4, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__GPIO2_0 IOMUX_PAD(0x628, 0x2A4, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 IOMUX_PAD(0x628, 0x2A4, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__ESDHC3_DAT4 IOMUX_PAD(0x628, 0x2A4, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 IOMUX_PAD(0x628, 0x2A4, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 IOMUX_PAD(0x628, 0x2A4, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 IOMUX_PAD(0x628, 0x2A4, 7, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__PATA_DATA_1 IOMUX_PAD(0x62C, 0x2A8, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__GPIO2_1 IOMUX_PAD(0x62C, 0x2A8, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 IOMUX_PAD(0x62C, 0x2A8, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__ESDHC3_DAT5 IOMUX_PAD(0x62C, 0x2A8, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 IOMUX_PAD(0x62C, 0x2A8, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 IOMUX_PAD(0x62C, 0x2A8, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__PATA_DATA_2 IOMUX_PAD(0x630, 0x2AC, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__GPIO2_2 IOMUX_PAD(0x630, 0x2AC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 IOMUX_PAD(0x630, 0x2AC, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__ESDHC3_DAT6 IOMUX_PAD(0x630, 0x2AC, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 IOMUX_PAD(0x630, 0x2AC, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 IOMUX_PAD(0x630, 0x2AC, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__PATA_DATA_3 IOMUX_PAD(0x634, 0x2B0, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__GPIO2_3 IOMUX_PAD(0x634, 0x2B0, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 IOMUX_PAD(0x634, 0x2B0, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__ESDHC3_DAT7 IOMUX_PAD(0x634, 0x2B0, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 IOMUX_PAD(0x634, 0x2B0, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 IOMUX_PAD(0x634, 0x2B0, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__PATA_DATA_4 IOMUX_PAD(0x638, 0x2B4, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__GPIO2_4 IOMUX_PAD(0x638, 0x2B4, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 IOMUX_PAD(0x638, 0x2B4, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__ESDHC4_DAT4 IOMUX_PAD(0x638, 0x2B4, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 IOMUX_PAD(0x638, 0x2B4, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 IOMUX_PAD(0x638, 0x2B4, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__PATA_DATA_5 IOMUX_PAD(0x63C, 0x2B8, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__GPIO2_5 IOMUX_PAD(0x63C, 0x2B8, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 IOMUX_PAD(0x63C, 0x2B8, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__ESDHC4_DAT5 IOMUX_PAD(0x63C, 0x2B8, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 IOMUX_PAD(0x63C, 0x2B8, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 IOMUX_PAD(0x63C, 0x2B8, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__PATA_DATA_6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__GPIO2_6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__ESDHC4_DAT6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 IOMUX_PAD(0x640, 0x2BC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__PATA_DATA_7 IOMUX_PAD(0x644, 0x2C0, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__GPIO2_7 IOMUX_PAD(0x644, 0x2C0, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 IOMUX_PAD(0x644, 0x2C0, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__ESDHC4_DAT7 IOMUX_PAD(0x644, 0x2C0, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 IOMUX_PAD(0x644, 0x2C0, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 IOMUX_PAD(0x644, 0x2C0, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__PATA_DATA_8 IOMUX_PAD(0x648, 0x2C4, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__GPIO2_8 IOMUX_PAD(0x648, 0x2C4, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__ESDHC1_DAT4 IOMUX_PAD(0x648, 0x2C4, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 IOMUX_PAD(0x648, 0x2C4, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__ESDHC3_DAT0 IOMUX_PAD(0x648, 0x2C4, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 IOMUX_PAD(0x648, 0x2C4, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 IOMUX_PAD(0x648, 0x2C4, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__PATA_DATA_9 IOMUX_PAD(0x64C, 0x2C8, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__GPIO2_9 IOMUX_PAD(0x64C, 0x2C8, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__ESDHC1_DAT5 IOMUX_PAD(0x64C, 0x2C8, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 IOMUX_PAD(0x64C, 0x2C8, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__ESDHC3_DAT1 IOMUX_PAD(0x64C, 0x2C8, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 IOMUX_PAD(0x64C, 0x2C8, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 IOMUX_PAD(0x64C, 0x2C8, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__PATA_DATA_10 IOMUX_PAD(0x650, 0x2CC, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__GPIO2_10 IOMUX_PAD(0x650, 0x2CC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__ESDHC1_DAT6 IOMUX_PAD(0x650, 0x2CC, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 IOMUX_PAD(0x650, 0x2CC, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__ESDHC3_DAT2 IOMUX_PAD(0x650, 0x2CC, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 IOMUX_PAD(0x650, 0x2CC, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 IOMUX_PAD(0x650, 0x2CC, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__PATA_DATA_11 IOMUX_PAD(0x654, 0x2D0, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__GPIO2_11 IOMUX_PAD(0x654, 0x2D0, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__ESDHC1_DAT7 IOMUX_PAD(0x654, 0x2D0, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 IOMUX_PAD(0x654, 0x2D0, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__ESDHC3_DAT3 IOMUX_PAD(0x654, 0x2D0, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 IOMUX_PAD(0x654, 0x2D0, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 IOMUX_PAD(0x654, 0x2D0, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__PATA_DATA_12 IOMUX_PAD(0x658, 0x2D4, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__GPIO2_12 IOMUX_PAD(0x658, 0x2D4, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__ESDHC2_DAT4 IOMUX_PAD(0x658, 0x2D4, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 IOMUX_PAD(0x658, 0x2D4, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__ESDHC4_DAT0 IOMUX_PAD(0x658, 0x2D4, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 IOMUX_PAD(0x658, 0x2D4, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 IOMUX_PAD(0x658, 0x2D4, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__PATA_DATA_13 IOMUX_PAD(0x65C, 0x2D8, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__GPIO2_13 IOMUX_PAD(0x65C, 0x2D8, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__ESDHC2_DAT5 IOMUX_PAD(0x65C, 0x2D8, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 IOMUX_PAD(0x65C, 0x2D8, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__ESDHC4_DAT1 IOMUX_PAD(0x65C, 0x2D8, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 IOMUX_PAD(0x65C, 0x2D8, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 IOMUX_PAD(0x65C, 0x2D8, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__PATA_DATA_14 IOMUX_PAD(0x660, 0x2DC, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__GPIO2_14 IOMUX_PAD(0x660, 0x2DC, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__ESDHC2_DAT6 IOMUX_PAD(0x660, 0x2DC, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 IOMUX_PAD(0x660, 0x2DC, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__ESDHC4_DAT2 IOMUX_PAD(0x660, 0x2DC, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 IOMUX_PAD(0x660, 0x2DC, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 IOMUX_PAD(0x660, 0x2DC, 6, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__PATA_DATA_15 IOMUX_PAD(0x664, 0x2E0, 0, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__GPIO2_15 IOMUX_PAD(0x664, 0x2E0, 1, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__ESDHC2_DAT7 IOMUX_PAD(0x664, 0x2E0, 2, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 IOMUX_PAD(0x664, 0x2E0, 3, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__ESDHC4_DAT3 IOMUX_PAD(0x664, 0x2E0, 4, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 IOMUX_PAD(0x664, 0x2E0, 5, 0x0, 0, 0)
+#define _MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 IOMUX_PAD(0x664, 0x2E0, 6, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA0__ESDHC1_DAT0 IOMUX_PAD(0x66C, 0x2E4, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA0__GPIO1_16 IOMUX_PAD(0x66C, 0x2E4, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA0__GPT_CAPIN1 IOMUX_PAD(0x66C, 0x2E4, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA0__CSPI_MISO IOMUX_PAD(0x66C, 0x2E4, 5, 0x784, 2, 0)
+#define _MX53_PAD_SD1_DATA0__CCM_PLL3_BYP IOMUX_PAD(0x66C, 0x2E4, 7, 0x778, 0, 0)
+#define _MX53_PAD_SD1_DATA1__ESDHC1_DAT1 IOMUX_PAD(0x670, 0x2E8, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA1__GPIO1_17 IOMUX_PAD(0x670, 0x2E8, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA1__GPT_CAPIN2 IOMUX_PAD(0x670, 0x2E8, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA1__CSPI_SS0 IOMUX_PAD(0x670, 0x2E8, 5, 0x78C, 3, 0)
+#define _MX53_PAD_SD1_DATA1__CCM_PLL4_BYP IOMUX_PAD(0x670, 0x2E8, 7, 0x77C, 1, 0)
+#define _MX53_PAD_SD1_CMD__ESDHC1_CMD IOMUX_PAD(0x674, 0x2EC, IOMUX_CONFIG_SION, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CMD__GPIO1_18 IOMUX_PAD(0x674, 0x2EC, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CMD__GPT_CMPOUT1 IOMUX_PAD(0x674, 0x2EC, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CMD__CSPI_MOSI IOMUX_PAD(0x674, 0x2EC, 5, 0x788, 2, 0)
+#define _MX53_PAD_SD1_CMD__CCM_PLL1_BYP IOMUX_PAD(0x674, 0x2EC, 7, 0x770, 0, 0)
+#define _MX53_PAD_SD1_DATA2__ESDHC1_DAT2 IOMUX_PAD(0x678, 0x2F0, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__GPIO1_19 IOMUX_PAD(0x678, 0x2F0, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__GPT_CMPOUT2 IOMUX_PAD(0x678, 0x2F0, 2, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__PWM2_PWMO IOMUX_PAD(0x678, 0x2F0, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__WDOG1_WDOG_B IOMUX_PAD(0x678, 0x2F0, 4, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__CSPI_SS1 IOMUX_PAD(0x678, 0x2F0, 5, 0x790, 2, 0)
+#define _MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB IOMUX_PAD(0x678, 0x2F0, 6, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA2__CCM_PLL2_BYP IOMUX_PAD(0x678, 0x2F0, 7, 0x774, 0, 0)
+#define _MX53_PAD_SD1_CLK__ESDHC1_CLK IOMUX_PAD(0x67C, 0x2F4, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CLK__GPIO1_20 IOMUX_PAD(0x67C, 0x2F4, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CLK__OSC32k_32K_OUT IOMUX_PAD(0x67C, 0x2F4, 2, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CLK__GPT_CLKIN IOMUX_PAD(0x67C, 0x2F4, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_CLK__CSPI_SCLK IOMUX_PAD(0x67C, 0x2F4, 5, 0x780, 2, 0)
+#define _MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 IOMUX_PAD(0x67C, 0x2F4, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__ESDHC1_DAT3 IOMUX_PAD(0x680, 0x2F8, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__GPIO1_21 IOMUX_PAD(0x680, 0x2F8, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__GPT_CMPOUT3 IOMUX_PAD(0x680, 0x2F8, 2, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__PWM1_PWMO IOMUX_PAD(0x680, 0x2F8, 3, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__WDOG2_WDOG_B IOMUX_PAD(0x680, 0x2F8, 4, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__CSPI_SS2 IOMUX_PAD(0x680, 0x2F8, 5, 0x794, 2, 0)
+#define _MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB IOMUX_PAD(0x680, 0x2F8, 6, 0x0, 0, 0)
+#define _MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 IOMUX_PAD(0x680, 0x2F8, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CLK__ESDHC2_CLK IOMUX_PAD(0x688, 0x2FC, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CLK__GPIO1_10 IOMUX_PAD(0x688, 0x2FC, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CLK__KPP_COL_5 IOMUX_PAD(0x688, 0x2FC, 2, 0x840, 2, 0)
+#define _MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS IOMUX_PAD(0x688, 0x2FC, 3, 0x73C, 1, 0)
+#define _MX53_PAD_SD2_CLK__CSPI_SCLK IOMUX_PAD(0x688, 0x2FC, 5, 0x780, 3, 0)
+#define _MX53_PAD_SD2_CLK__SCC_RANDOM_V IOMUX_PAD(0x688, 0x2FC, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CMD__ESDHC2_CMD IOMUX_PAD(0x68C, 0x300, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CMD__GPIO1_11 IOMUX_PAD(0x68C, 0x300, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_CMD__KPP_ROW_5 IOMUX_PAD(0x68C, 0x300, 2, 0x84C, 1, 0)
+#define _MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC IOMUX_PAD(0x68C, 0x300, 3, 0x738, 1, 0)
+#define _MX53_PAD_SD2_CMD__CSPI_MOSI IOMUX_PAD(0x68C, 0x300, 5, 0x788, 3, 0)
+#define _MX53_PAD_SD2_CMD__SCC_RANDOM IOMUX_PAD(0x68C, 0x300, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA3__ESDHC2_DAT3 IOMUX_PAD(0x690, 0x304, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA3__GPIO1_12 IOMUX_PAD(0x690, 0x304, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA3__KPP_COL_6 IOMUX_PAD(0x690, 0x304, 2, 0x844, 1, 0)
+#define _MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC IOMUX_PAD(0x690, 0x304, 3, 0x740, 1, 0)
+#define _MX53_PAD_SD2_DATA3__CSPI_SS2 IOMUX_PAD(0x690, 0x304, 5, 0x794, 3, 0)
+#define _MX53_PAD_SD2_DATA3__SJC_DONE IOMUX_PAD(0x690, 0x304, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA2__ESDHC2_DAT2 IOMUX_PAD(0x694, 0x308, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA2__GPIO1_13 IOMUX_PAD(0x694, 0x308, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA2__KPP_ROW_6 IOMUX_PAD(0x694, 0x308, 2, 0x850, 1, 0)
+#define _MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD IOMUX_PAD(0x694, 0x308, 3, 0x734, 1, 0)
+#define _MX53_PAD_SD2_DATA2__CSPI_SS1 IOMUX_PAD(0x694, 0x308, 5, 0x790, 3, 0)
+#define _MX53_PAD_SD2_DATA2__SJC_FAIL IOMUX_PAD(0x694, 0x308, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA1__ESDHC2_DAT1 IOMUX_PAD(0x698, 0x30C, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA1__GPIO1_14 IOMUX_PAD(0x698, 0x30C, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA1__KPP_COL_7 IOMUX_PAD(0x698, 0x30C, 2, 0x848, 1, 0)
+#define _MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS IOMUX_PAD(0x698, 0x30C, 3, 0x744, 0, 0)
+#define _MX53_PAD_SD2_DATA1__CSPI_SS0 IOMUX_PAD(0x698, 0x30C, 5, 0x78C, 4, 0)
+#define _MX53_PAD_SD2_DATA1__RTIC_SEC_VIO IOMUX_PAD(0x698, 0x30C, 7, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA0__ESDHC2_DAT0 IOMUX_PAD(0x69C, 0x310, 0, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA0__GPIO1_15 IOMUX_PAD(0x69C, 0x310, 1, 0x0, 0, 0)
+#define _MX53_PAD_SD2_DATA0__KPP_ROW_7 IOMUX_PAD(0x69C, 0x310, 2, 0x854, 1, 0)
+#define _MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD IOMUX_PAD(0x69C, 0x310, 3, 0x730, 1, 0)
+#define _MX53_PAD_SD2_DATA0__CSPI_MISO IOMUX_PAD(0x69C, 0x310, 5, 0x784, 3, 0)
+#define _MX53_PAD_SD2_DATA0__RTIC_DONE_INT IOMUX_PAD(0x69C, 0x310, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__CCM_CLKO IOMUX_PAD(0x6A4, 0x314, 0, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__GPIO1_0 IOMUX_PAD(0x6A4, 0x314, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__KPP_COL_5 IOMUX_PAD(0x6A4, 0x314, 2, 0x840, 3, 0)
+#define _MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK IOMUX_PAD(0x6A4, 0x314, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__EPIT1_EPITO IOMUX_PAD(0x6A4, 0x314, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__SRTC_ALARM_DEB IOMUX_PAD(0x6A4, 0x314, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__USBOH3_USBH1_PWR IOMUX_PAD(0x6A4, 0x314, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_0__CSU_TD IOMUX_PAD(0x6A4, 0x314, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__ESAI1_SCKR IOMUX_PAD(0x6A8, 0x318, 0, 0x7DC, 1, 0)
+#define _MX53_PAD_GPIO_1__GPIO1_1 IOMUX_PAD(0x6A8, 0x318, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__KPP_ROW_5 IOMUX_PAD(0x6A8, 0x318, 2, 0x84C, 2, 0)
+#define _MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK IOMUX_PAD(0x6A8, 0x318, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__PWM2_PWMO IOMUX_PAD(0x6A8, 0x318, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__WDOG2_WDOG_B IOMUX_PAD(0x6A8, 0x318, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__ESDHC1_CD IOMUX_PAD(0x6A8, 0x318, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_1__SRC_TESTER_ACK IOMUX_PAD(0x6A8, 0x318, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_9__ESAI1_FSR IOMUX_PAD(0x6AC, 0x31C, 0, 0x7CC, 1, 0)
+#define _MX53_PAD_GPIO_9__GPIO1_9 IOMUX_PAD(0x6AC, 0x31C, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_9__KPP_COL_6 IOMUX_PAD(0x6AC, 0x31C, 2, 0x844, 2, 0)
+#define _MX53_PAD_GPIO_9__CCM_REF_EN_B IOMUX_PAD(0x6AC, 0x31C, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_9__PWM1_PWMO IOMUX_PAD(0x6AC, 0x31C, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_9__WDOG1_WDOG_B IOMUX_PAD(0x6AC, 0x31C, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_9__ESDHC1_WP IOMUX_PAD(0x6AC, 0x31C, 6, 0x7FC, 1, 0)
+#define _MX53_PAD_GPIO_9__SCC_FAIL_STATE IOMUX_PAD(0x6AC, 0x31C, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_3__ESAI1_HCKR IOMUX_PAD(0x6B0, 0x320, 0, 0x7D4, 1, 0)
+#define _MX53_PAD_GPIO_3__GPIO1_3 IOMUX_PAD(0x6B0, 0x320, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_3__I2C3_SCL IOMUX_PAD(0x6B0, 0x320, 2 | IOMUX_CONFIG_SION, 0x824, 1, 0)
+#define _MX53_PAD_GPIO_3__DPLLIP1_TOG_EN IOMUX_PAD(0x6B0, 0x320, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_3__CCM_CLKO2 IOMUX_PAD(0x6B0, 0x320, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 IOMUX_PAD(0x6B0, 0x320, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_3__USBOH3_USBH1_OC IOMUX_PAD(0x6B0, 0x320, 6, 0x8A0, 1, 0)
+#define _MX53_PAD_GPIO_3__MLB_MLBCLK IOMUX_PAD(0x6B0, 0x320, 7, 0x858, 2, 0)
+#define _MX53_PAD_GPIO_6__ESAI1_SCKT IOMUX_PAD(0x6B4, 0x324, 0, 0x7E0, 1, 0)
+#define _MX53_PAD_GPIO_6__GPIO1_6 IOMUX_PAD(0x6B4, 0x324, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_6__I2C3_SDA IOMUX_PAD(0x6B4, 0x324, 2 | IOMUX_CONFIG_SION, 0x828, 1, 0)
+#define _MX53_PAD_GPIO_6__CCM_CCM_OUT_0 IOMUX_PAD(0x6B4, 0x324, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_6__CSU_CSU_INT_DEB IOMUX_PAD(0x6B4, 0x324, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 IOMUX_PAD(0x6B4, 0x324, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_6__ESDHC2_LCTL IOMUX_PAD(0x6B4, 0x324, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_6__MLB_MLBSIG IOMUX_PAD(0x6B4, 0x324, 7, 0x860, 2, 0)
+#define _MX53_PAD_GPIO_2__ESAI1_FST IOMUX_PAD(0x6B8, 0x328, 0, 0x7D0, 1, 0)
+#define _MX53_PAD_GPIO_2__GPIO1_2 IOMUX_PAD(0x6B8, 0x328, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_2__KPP_ROW_6 IOMUX_PAD(0x6B8, 0x328, 2, 0x850, 2, 0)
+#define _MX53_PAD_GPIO_2__CCM_CCM_OUT_1 IOMUX_PAD(0x6B8, 0x328, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 IOMUX_PAD(0x6B8, 0x328, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 IOMUX_PAD(0x6B8, 0x328, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_2__ESDHC2_WP IOMUX_PAD(0x6B8, 0x328, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_2__MLB_MLBDAT IOMUX_PAD(0x6B8, 0x328, 7, 0x85C, 2, 0)
+#define _MX53_PAD_GPIO_4__ESAI1_HCKT IOMUX_PAD(0x6BC, 0x32C, 0, 0x7D8, 1, 0)
+#define _MX53_PAD_GPIO_4__GPIO1_4 IOMUX_PAD(0x6BC, 0x32C, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_4__KPP_COL_7 IOMUX_PAD(0x6BC, 0x32C, 2, 0x848, 2, 0)
+#define _MX53_PAD_GPIO_4__CCM_CCM_OUT_2 IOMUX_PAD(0x6BC, 0x32C, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 IOMUX_PAD(0x6BC, 0x32C, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 IOMUX_PAD(0x6BC, 0x32C, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_4__ESDHC2_CD IOMUX_PAD(0x6BC, 0x32C, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_4__SCC_SEC_STATE IOMUX_PAD(0x6BC, 0x32C, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_5__ESAI1_TX2_RX3 IOMUX_PAD(0x6C0, 0x330, 0, 0x7EC, 1, 0)
+#define _MX53_PAD_GPIO_5__GPIO1_5 IOMUX_PAD(0x6C0, 0x330, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_5__KPP_ROW_7 IOMUX_PAD(0x6C0, 0x330, 2, 0x854, 2, 0)
+#define _MX53_PAD_GPIO_5__CCM_CLKO IOMUX_PAD(0x6C0, 0x330, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 IOMUX_PAD(0x6C0, 0x330, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 IOMUX_PAD(0x6C0, 0x330, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_5__I2C3_SCL IOMUX_PAD(0x6C0, 0x330, 6, 0x824, 2, 0)
+#define _MX53_PAD_GPIO_5__CCM_PLL1_BYP IOMUX_PAD(0x6C0, 0x330, 7, 0x770, 1, 0)
+#define _MX53_PAD_GPIO_7__ESAI1_TX4_RX1 IOMUX_PAD(0x6C4, 0x334, 0, 0x7F4, 1, 0)
+#define _MX53_PAD_GPIO_7__GPIO1_7 IOMUX_PAD(0x6C4, 0x334, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_7__EPIT1_EPITO IOMUX_PAD(0x6C4, 0x334, 2, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_7__CAN1_TXCAN IOMUX_PAD(0x6C4, 0x334, 3, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_7__UART2_TXD_MUX IOMUX_PAD(0x6C4, 0x334, 4, 0x880, 4, 0)
+#define _MX53_PAD_GPIO_7__FIRI_RXD IOMUX_PAD(0x6C4, 0x334, 5, 0x80C, 1, 0)
+#define _MX53_PAD_GPIO_7__SPDIF_PLOCK IOMUX_PAD(0x6C4, 0x334, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_7__CCM_PLL2_BYP IOMUX_PAD(0x6C4, 0x334, 7, 0x774, 1, 0)
+#define _MX53_PAD_GPIO_8__ESAI1_TX5_RX0 IOMUX_PAD(0x6C8, 0x338, 0, 0x7F8, 1, 0)
+#define _MX53_PAD_GPIO_8__GPIO1_8 IOMUX_PAD(0x6C8, 0x338, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_8__EPIT2_EPITO IOMUX_PAD(0x6C8, 0x338, 2, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_8__CAN1_RXCAN IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 3, 0)
+#define _MX53_PAD_GPIO_8__UART2_RXD_MUX IOMUX_PAD(0x6C8, 0x338, 4, 0x880, 5, 0)
+#define _MX53_PAD_GPIO_8__FIRI_TXD IOMUX_PAD(0x6C8, 0x338, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_8__SPDIF_SRCLK IOMUX_PAD(0x6C8, 0x338, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_8__CCM_PLL3_BYP IOMUX_PAD(0x6C8, 0x338, 7, 0x778, 1, 0)
+#define _MX53_PAD_GPIO_16__ESAI1_TX3_RX2 IOMUX_PAD(0x6CC, 0x33C, 0, 0x7F0, 1, 0)
+#define _MX53_PAD_GPIO_16__GPIO7_11 IOMUX_PAD(0x6CC, 0x33C, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT IOMUX_PAD(0x6CC, 0x33C, 2, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 IOMUX_PAD(0x6CC, 0x33C, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_16__SPDIF_IN1 IOMUX_PAD(0x6CC, 0x33C, 5, 0x870, 1, 0)
+#define _MX53_PAD_GPIO_16__I2C3_SDA IOMUX_PAD(0x6CC, 0x33C, 6 | IOMUX_CONFIG_SION, 0x828, 2, 0)
+#define _MX53_PAD_GPIO_16__SJC_DE_B IOMUX_PAD(0x6CC, 0x33C, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_17__ESAI1_TX0 IOMUX_PAD(0x6D0, 0x340, 0, 0x7E4, 1, 0)
+#define _MX53_PAD_GPIO_17__GPIO7_12 IOMUX_PAD(0x6D0, 0x340, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 IOMUX_PAD(0x6D0, 0x340, 2, 0x868, 1, 0)
+#define _MX53_PAD_GPIO_17__GPC_PMIC_RDY IOMUX_PAD(0x6D0, 0x340, 3, 0x810, 1, 0)
+#define _MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG IOMUX_PAD(0x6D0, 0x340, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_17__SPDIF_OUT1 IOMUX_PAD(0x6D0, 0x340, 5, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_17__IPU_SNOOP2 IOMUX_PAD(0x6D0, 0x340, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_17__SJC_JTAG_ACT IOMUX_PAD(0x6D0, 0x340, 7, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_18__ESAI1_TX1 IOMUX_PAD(0x6D4, 0x344, 0, 0x7E8, 1, 0)
+#define _MX53_PAD_GPIO_18__GPIO7_13 IOMUX_PAD(0x6D4, 0x344, 1, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 IOMUX_PAD(0x6D4, 0x344, 2, 0x86C, 1, 0)
+#define _MX53_PAD_GPIO_18__OWIRE_LINE IOMUX_PAD(0x6D4, 0x344, 3, 0x864, 1, 0)
+#define _MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG IOMUX_PAD(0x6D4, 0x344, 4, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK IOMUX_PAD(0x6D4, 0x344, 5, 0x768, 1, 0)
+#define _MX53_PAD_GPIO_18__ESDHC1_LCTL IOMUX_PAD(0x6D4, 0x344, 6, 0x0, 0, 0)
+#define _MX53_PAD_GPIO_18__SRC_SYSTEM_RST IOMUX_PAD(0x6D4, 0x344, 7, 0x0, 0, 0)
-#define MX53_PAD_GPIO_19__GPIO_4_5 IOMUX_PAD(0x348, 0x20,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL0__GPIO_4_6 IOMUX_PAD(0x34C, 0x24,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW0__GPIO_4_7 IOMUX_PAD(0x350, 0x28,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL1__GPIO_4_8 IOMUX_PAD(0x354, 0x2C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW1__GPIO_4_9 IOMUX_PAD(0x358, 0x30,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL2__GPIO_4_10 IOMUX_PAD(0x35C, 0x34,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW2__GPIO_4_11 IOMUX_PAD(0x360, 0x38,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL3__GPIO_4_12 IOMUX_PAD(0x364, 0x3C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW3__GPIO_4_13 IOMUX_PAD(0x368, 0x40,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL4__GPIO_4_14 IOMUX_PAD(0x36C, 0x44,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW4__GPIO_4_15 IOMUX_PAD(0x370, 0x48,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_KEYPAD__NVCC_KEYPAD IOMUX_PAD(0x374, NON_MUX_I,IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DI0_DISP_CLK__GPIO_4_16 IOMUX_PAD(0x378, 0x4C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DI0_PIN15__GPIO_4_17 IOMUX_PAD(0x37C, 0x50,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DI0_PIN2__GPIO_4_18 IOMUX_PAD(0x380, 0x54,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DI0_PIN3__GPIO_4_19 IOMUX_PAD(0x384, 0x58,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DI0_PIN4__GPIO_4_20 IOMUX_PAD(0x388, 0x5C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT0__GPIO_4_21 IOMUX_PAD(0x38C, 0x60,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT1__GPIO_4_22 IOMUX_PAD(0x390, 0x64,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT2__GPIO_4_23 IOMUX_PAD(0x394, 0x68,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT3__GPIO_4_24 IOMUX_PAD(0x398, 0x6C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT4__GPIO_4_25 IOMUX_PAD(0x39C, 0x70,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT5__GPIO_4_26 IOMUX_PAD(0x3A0, 0x74,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT6__GPIO_4_27 IOMUX_PAD(0x3A4, 0x78,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT7__GPIO_4_28 IOMUX_PAD(0x3A8, 0x7C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT8__GPIO_4_29 IOMUX_PAD(0x3AC, 0x80,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT9__GPIO_4_30 IOMUX_PAD(0x3B0, 0x84,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT10__GPIO_4_31 IOMUX_PAD(0x3B4, 0x88,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT11__GPIO_5_5 IOMUX_PAD(0x3B8, 0x8C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT12__GPIO_5_6 IOMUX_PAD(0x3BC, 0x90,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT13__GPIO_5_7 IOMUX_PAD(0x3C0, 0x94,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT14__GPIO_5_8 IOMUX_PAD(0x3C4, 0x98,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT15__GPIO_5_9 IOMUX_PAD(0x3C8, 0x9C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT16__GPIO_5_10 IOMUX_PAD(0x3CC, 0xA0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT17__GPIO_5_11 IOMUX_PAD(0x3D0, 0xA4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT18__GPIO_5_12 IOMUX_PAD(0x3D4, 0xA8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT19__GPIO_5_13 IOMUX_PAD(0x3D8, 0xAC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT20__GPIO_5_14 IOMUX_PAD(0x3DC, 0xB0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT21__GPIO_5_15 IOMUX_PAD(0x3E0, 0xB4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT22__GPIO_5_16 IOMUX_PAD(0x3E4, 0xB8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DISP0_DAT23__GPIO_5_17 IOMUX_PAD(0x3E8, 0xBC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_PIXCLK__GPIO_5_18 IOMUX_PAD(0x3EC, 0xC0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_MCLK__GPIO_5_19 IOMUX_PAD(0x3F0, 0xC4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_DATA_EN__GPIO_5_20 IOMUX_PAD(0x3F4, 0xC8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_VSYNC__GPIO_5_21 IOMUX_PAD(0x3F8, 0xCC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D4__GPIO_5_22 IOMUX_PAD(0x3FC, 0xD0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D5__GPIO_5_23 IOMUX_PAD(0x400, 0xD4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D6__GPIO_5_24 IOMUX_PAD(0x404, 0xD8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D7__GPIO_5_25 IOMUX_PAD(0x408, 0xDC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D8__GPIO_5_26 IOMUX_PAD(0x40C, 0xE0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D9__GPIO_5_27 IOMUX_PAD(0x410, 0xE4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D10__GPIO_5_28 IOMUX_PAD(0x414, 0xE8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D11__GPIO_5_29 IOMUX_PAD(0x418, 0xEC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D12__GPIO_5_30 IOMUX_PAD(0x41C, 0xF0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D13__GPIO_5_31 IOMUX_PAD(0x420, 0xF4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D14__GPIO_6_0 IOMUX_PAD(0x424, 0xF8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D15__GPIO_6_1 IOMUX_PAD(0x428, 0xFC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D16__GPIO_6_2 IOMUX_PAD(0x42C, 0x100,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D17__GPIO_6_3 IOMUX_PAD(0x430, 0x104,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D18__GPIO_6_4 IOMUX_PAD(0x434, 0x108,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_CSI0_D19__GPIO_6_5 IOMUX_PAD(0x438, 0x10C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_CSI0__NVCC_CSI0 IOMUX_PAD(0x43C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_TMS__JTAG_TMS IOMUX_PAD(0x440, NON_MUX_I,IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_MOD__JTAG_MOD IOMUX_PAD(0x444, NON_MUX_I,IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_TRSTB__JTAG_TRSTB IOMUX_PAD(0x448, NON_MUX_I,IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_TDI__JTAG_TDI IOMUX_PAD(0x44C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_TCK__JTAG_TCK IOMUX_PAD(0x450, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_JTAG_TDO__JTAG_TDO IOMUX_PAD(0x454, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A25__GPIO_5_2 IOMUX_PAD(0x458, 0x110,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_EB2__GPIO_2_30 IOMUX_PAD(0x45C, 0x114,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D16__GPIO_3_16 IOMUX_PAD(0x460, 0x118,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D17__GPIO_3_17 IOMUX_PAD(0x464, 0x11C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D18__GPIO_3_18 IOMUX_PAD(0x468, 0x120,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D16__CSPI1_SCLK IOMUX_PAD(0x460, 0x118,IOMUX_CONFIG_ALT4, 0x79c, 3, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D17__CSPI1_MISO IOMUX_PAD(0x464, 0x11C,IOMUX_CONFIG_ALT4, 0x7a0, 3, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D18__CSPI1_MOSI IOMUX_PAD(0x468, 0x120,IOMUX_CONFIG_ALT4, 0x7a4, 3, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D19__GPIO_3_19 IOMUX_PAD(0x46C, 0x124,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D20__GPIO_3_20 IOMUX_PAD(0x470, 0x128,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D21__GPIO_3_21 IOMUX_PAD(0x474, 0x12C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D22__GPIO_3_22 IOMUX_PAD(0x478, 0x130,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D23__GPIO_3_23 IOMUX_PAD(0x47C, 0x134,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_EB3__GPIO_2_31 IOMUX_PAD(0x480, 0x138,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D24__GPIO_3_24 IOMUX_PAD(0x484, 0x13C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D25__GPIO_3_25 IOMUX_PAD(0x488, 0x140,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D26__GPIO_3_26 IOMUX_PAD(0x48C, 0x144,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D27__GPIO_3_27 IOMUX_PAD(0x490, 0x148,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D28__GPIO_3_28 IOMUX_PAD(0x494, 0x14C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D29__GPIO_3_29 IOMUX_PAD(0x498, 0x150,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D30__GPIO_3_30 IOMUX_PAD(0x49C, 0x154,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D31__GPIO_3_31 IOMUX_PAD(0x4A0, 0x158,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_EIM1__NVCC_EIM1 IOMUX_PAD(0x4A4, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A24__GPIO_5_4 IOMUX_PAD(0x4A8, 0x15C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A23__GPIO_6_6 IOMUX_PAD(0x4AC, 0x160,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A22__GPIO_2_16 IOMUX_PAD(0x4B0, 0x164,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A21__GPIO_2_17 IOMUX_PAD(0x4B4, 0x168,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A20__GPIO_2_18 IOMUX_PAD(0x4B8, 0x16C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A19__GPIO_2_19 IOMUX_PAD(0x4BC, 0x170,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A18__GPIO_2_20 IOMUX_PAD(0x4C0, 0x174,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A17__GPIO_2_21 IOMUX_PAD(0x4C4, 0x178,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_A16__GPIO_2_22 IOMUX_PAD(0x4C8, 0x17C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_CS0__GPIO_2_23 IOMUX_PAD(0x4CC, 0x180,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_CS1__GPIO_2_24 IOMUX_PAD(0x4D0, 0x184,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_OE__GPIO_2_25 IOMUX_PAD(0x4D4, 0x188,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_RW__GPIO_2_26 IOMUX_PAD(0x4D8, 0x18C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_LBA__GPIO_2_27 IOMUX_PAD(0x4DC, 0x190,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_EIM4__NVCC_EIM4 IOMUX_PAD(0x4E0, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_EB0__GPIO_2_28 IOMUX_PAD(0x4E4, 0x194,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_EB1__GPIO_2_29 IOMUX_PAD(0x4E8, 0x198,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA0__GPIO_3_0 IOMUX_PAD(0x4EC, 0x19C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA1__GPIO_3_1 IOMUX_PAD(0x4F0, 0x1A0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA2__GPIO_3_2 IOMUX_PAD(0x4F4, 0x1A4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA3__GPIO_3_3 IOMUX_PAD(0x4F8, 0x1A8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA4__GPIO_3_4 IOMUX_PAD(0x4FC, 0x1AC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA5__GPIO_3_5 IOMUX_PAD(0x500, 0x1B0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA6__GPIO_3_6 IOMUX_PAD(0x504, 0x1B4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA7__GPIO_3_7 IOMUX_PAD(0x508, 0x1B8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA8__GPIO_3_8 IOMUX_PAD(0x50C, 0x1BC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA9__GPIO_3_9 IOMUX_PAD(0x510, 0x1C0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA10__GPIO_3_10 IOMUX_PAD(0x514, 0x1C4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA11__GPIO_3_11 IOMUX_PAD(0x518, 0x1C8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA12__GPIO_3_12 IOMUX_PAD(0x51C, 0x1CC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA13__GPIO_3_13 IOMUX_PAD(0x520, 0x1D0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA14__GPIO_3_14 IOMUX_PAD(0x524, 0x1D4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_DA15__GPIO_3_15 IOMUX_PAD(0x528, 0x1D8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_WE_B__GPIO_6_12 IOMUX_PAD(0x52C, 0x1DC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_RE_B__GPIO_6_13 IOMUX_PAD(0x530, 0x1E0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_WAIT__GPIO_5_0 IOMUX_PAD(0x534, 0x1E4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_EIM_BCLK__EIM_BCLK IOMUX_PAD(0x538, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_EIM7__NVCC_EIM7 IOMUX_PAD(0x53C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS1_TX3_P__GPIO_6_22 IOMUX_PAD(NON_PAD_I, 0x1EC, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS1_TX2_P__GPIO_6_24 IOMUX_PAD(NON_PAD_I, 0x1F0, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS1_CLK_P__GPIO_6_26 IOMUX_PAD(NON_PAD_I, 0x1F4, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS1_TX1_P__GPIO_6_28 IOMUX_PAD(NON_PAD_I, 0x1F8, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS1_TX0_P__GPIO_6_30 IOMUX_PAD(NON_PAD_I, 0x1FC, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS0_TX3_P__GPIO_7_22 IOMUX_PAD(NON_PAD_I, 0x200, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS0_CLK_P__GPIO_7_24 IOMUX_PAD(NON_PAD_I, 0x204, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS0_TX2_P__GPIO_7_26 IOMUX_PAD(NON_PAD_I, 0x208, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS0_TX1_P__GPIO_7_28 IOMUX_PAD(NON_PAD_I, 0x20C, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_LVDS0_TX0_P__GPIO_7_30 IOMUX_PAD(NON_PAD_I, 0x210, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_10__GPIO_4_0 IOMUX_PAD(0x540, 0x214, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_11__GPIO_4_1 IOMUX_PAD(0x544, 0x218, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_12__GPIO_4_2 IOMUX_PAD(0x548, 0x21C, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_13__GPIO_4_3 IOMUX_PAD(0x54C, 0x220, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_14__GPIO_4_4 IOMUX_PAD(0x550, 0x224, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_DQM3__DRAM_DQM3 IOMUX_PAD(0x554, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDQS3__DRAM_SDQS3 IOMUX_PAD(0x558, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDCKE1__DRAM_SDCKE1 IOMUX_PAD(0x55C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_DQM2__DRAM_DQM2 IOMUX_PAD(0x560, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDODT1__DRAM_SDODT1 IOMUX_PAD(0x564, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDQS2__DRAM_SDQS2 IOMUX_PAD(0x568, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_RESET__DRAM_RESET IOMUX_PAD(0x56C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDCLK1__DRAM_SDCLK1 IOMUX_PAD(0x570, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_CAS__DRAM_CAS IOMUX_PAD(0x574, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDCLK0__DRAM_SDCLK0 IOMUX_PAD(0x578, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDQS0__DRAM_SDQS0 IOMUX_PAD(0x57C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDODT0__DRAM_SDODT0 IOMUX_PAD(0x580, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_DQM0__DRAM_DQM0 IOMUX_PAD(0x584, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_RAS__DRAM_RAS IOMUX_PAD(0x588, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDCKE0__DRAM_SDCKE0 IOMUX_PAD(0x58C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_SDQS1__DRAM_SDQS1 IOMUX_PAD(0x590, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_DRAM_DQM1__DRAM_DQM1 IOMUX_PAD(0x594, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_PMIC_ON_REQ__PMIC_ON_REQ IOMUX_PAD(0x598, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_PMIC_STBY_REQ__PMIC_STBY_REQ IOMUX_PAD(0x59C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_CLE__GPIO_6_7 IOMUX_PAD(0x5A0, 0x228,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_ALE__GPIO_6_8 IOMUX_PAD(0x5A4, 0x22C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_WP_B__GPIO_6_9 IOMUX_PAD(0x5A8, 0x230,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_RB0__GPIO_6_10 IOMUX_PAD(0x5AC, 0x234,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_CS0__GPIO_6_11 IOMUX_PAD(0x5B0, 0x238,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_CS1__GPIO_6_14 IOMUX_PAD(0x5B4, 0x23C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_CS2__GPIO_6_15 IOMUX_PAD(0x5B8, 0x240,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NANDF_CS3__GPIO_6_16 IOMUX_PAD(0x5BC, 0x244,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_NANDF__NVCC_NANDF IOMUX_PAD(0x5C0, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_MDIO__GPIO_1_22 IOMUX_PAD(0x5C4, 0x248,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_REF_CLK__GPIO_1_23 IOMUX_PAD(0x5C8, 0x24C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_RX_ER__GPIO_1_24 IOMUX_PAD(0x5CC, 0x250,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_CRS_DV__GPIO_1_25 IOMUX_PAD(0x5D0, 0x254,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_RXD1__GPIO_1_26 IOMUX_PAD(0x5D4, 0x258,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_RXD0__GPIO_1_27 IOMUX_PAD(0x5D8, 0x25C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_TX_EN__GPIO_1_28 IOMUX_PAD(0x5DC, 0x260,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_TXD1__GPIO_1_29 IOMUX_PAD(0x5E0, 0x264,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_TXD0__GPIO_1_30 IOMUX_PAD(0x5E4, 0x268,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_FEC_MDC__GPIO_1_31 IOMUX_PAD(0x5E8, 0x26C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_FEC__NVCC_FEC IOMUX_PAD(0x5EC, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DIOW__GPIO_6_17 IOMUX_PAD(0x5F0, 0x270,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DMACK__GPIO_6_18 IOMUX_PAD(0x5F4, 0x274,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DMARQ__GPIO_7_0 IOMUX_PAD(0x5F8, 0x278,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_BUFFER_EN__GPIO_7_1 IOMUX_PAD(0x5FC, 0x27C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_INTRQ__GPIO_7_2 IOMUX_PAD(0x600, 0x280,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DIOR__GPIO_7_3 IOMUX_PAD(0x604, 0x284,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_RESET_B__GPIO_7_4 IOMUX_PAD(0x608, 0x288,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_IORDY__GPIO_7_5 IOMUX_PAD(0x60C, 0x28C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DA_0__GPIO_7_6 IOMUX_PAD(0x610, 0x290,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DA_1__GPIO_7_7 IOMUX_PAD(0x614, 0x294,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DA_2__GPIO_7_8 IOMUX_PAD(0x618, 0x298,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_CS_0__GPIO_7_9 IOMUX_PAD(0x61C, 0x29C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_CS_1__GPIO_7_10 IOMUX_PAD(0x620, 0x2A0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_ATA2__NVCC_ATA2 IOMUX_PAD(0x624, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA0__GPIO_2_0 IOMUX_PAD(0x628, 0x2A4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA1__GPIO_2_1 IOMUX_PAD(0x62C, 0x2A8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA2__GPIO_2_2 IOMUX_PAD(0x630, 0x2AC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA3__GPIO_2_3 IOMUX_PAD(0x634, 0x2B0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA4__GPIO_2_4 IOMUX_PAD(0x638, 0x2B4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA5__GPIO_2_5 IOMUX_PAD(0x63C, 0x2B8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA6__GPIO_2_6 IOMUX_PAD(0x640, 0x2BC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA7__GPIO_2_7 IOMUX_PAD(0x644, 0x2C0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA8__GPIO_2_8 IOMUX_PAD(0x648, 0x2C4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA9__GPIO_2_9 IOMUX_PAD(0x64C, 0x2C8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA10__GPIO_2_10 IOMUX_PAD(0x650, 0x2CC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA11__GPIO_2_11 IOMUX_PAD(0x654, 0x2D0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA12__GPIO_2_12 IOMUX_PAD(0x658, 0x2D4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA13__GPIO_2_13 IOMUX_PAD(0x65C, 0x2D8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA14__GPIO_2_14 IOMUX_PAD(0x660, 0x2DC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_ATA_DATA15__GPIO_2_15 IOMUX_PAD(0x664, 0x2E0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_ATA0__NVCC_ATA0 IOMUX_PAD(0x668, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_DATA0__GPIO_1_16 IOMUX_PAD(0x66C, 0x2E4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_DATA1__GPIO_1_17 IOMUX_PAD(0x670, 0x2E8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_CMD__GPIO_1_18 IOMUX_PAD(0x674, 0x2EC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_DATA2__GPIO_1_19 IOMUX_PAD(0x678, 0x2F0,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_CLK__GPIO_1_20 IOMUX_PAD(0x67C, 0x2F4,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD1_DATA3__GPIO_1_21 IOMUX_PAD(0x680, 0x2F8,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_SD1__NVCC_SD1 IOMUX_PAD(0x684, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_CLK__GPIO_1_10 IOMUX_PAD(0x688, 0x2FC,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_CMD__GPIO_1_11 IOMUX_PAD(0x68C, 0x300,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_DATA3__GPIO_1_12 IOMUX_PAD(0x690, 0x304,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_DATA2__GPIO_1_13 IOMUX_PAD(0x694, 0x308,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_DATA1__GPIO_1_14 IOMUX_PAD(0x698, 0x30C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_SD2_DATA0__GPIO_1_15 IOMUX_PAD(0x69C, 0x310,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_SD2__NVCC_SD2 IOMUX_PAD(0x6A0, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_0__GPIO_1_0 IOMUX_PAD(0x6A4, 0x314,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_1__GPIO_1_1 IOMUX_PAD(0x6A8, 0x318,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_9__GPIO_1_9 IOMUX_PAD(0x6AC, 0x31C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_3__GPIO_1_3 IOMUX_PAD(0x6B0, 0x320,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_6__GPIO_1_6 IOMUX_PAD(0x6B4, 0x324,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_2__GPIO_1_2 IOMUX_PAD(0x6B8, 0x328,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_4__GPIO_1_4 IOMUX_PAD(0x6BC, 0x32C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_5__GPIO_1_5 IOMUX_PAD(0x6C0, 0x330,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_7__GPIO_1_7 IOMUX_PAD(0x6C4, 0x334,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_8__GPIO_1_8 IOMUX_PAD(0x6C8, 0x338,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_16__GPIO_7_11 IOMUX_PAD(0x6CC, 0x33C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_17__GPIO_7_12 IOMUX_PAD(0x6D0, 0x340,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_18__GPIO_7_13 IOMUX_PAD(0x6D4, 0x344,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_NVCC_GPIO__NVCC_GPIO IOMUX_PAD(0x6D8, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_POR_B__POR_B IOMUX_PAD(0x6DC, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_BOOT_MODE1__BOOT_MODE1 IOMUX_PAD(0x6E0, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_RESET_IN_B__RESET_IN_B IOMUX_PAD(0x6E4, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_BOOT_MODE0__BOOT_MODE0 IOMUX_PAD(0x6E8, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_TEST_MODE__TEST_MODE IOMUX_PAD(0x6EC, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_ADDDS__GRP_ADDDS IOMUX_PAD(0x6F0, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDRMODE_CTL__GRP_DDRMODE_CTL IOMUX_PAD(0x6F4, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDRPKE__GRP_DDRPKE IOMUX_PAD(0x6FC, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDRPK__GRP_DDRPK IOMUX_PAD(0x708, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_TERM_CTL3__GRP_TERM_CTL3 IOMUX_PAD(0x70C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDRHYS__GRP_DDRHYS IOMUX_PAD(0x710, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDRMODE__GRP_DDRMODE IOMUX_PAD(0x714, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_B0DS__GRP_B0DS IOMUX_PAD(0x718, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_B1DS__GRP_B1DS IOMUX_PAD(0x71C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_CTLDS__GRP_CTLDS IOMUX_PAD(0x720, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_DDR_TYPE__GRP_DDR_TYPE IOMUX_PAD(0x724, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_B2DS__GRP_B2DS IOMUX_PAD(0x728, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
-#define MX53_PAD_GRP_B3DS__GRP_B3DS IOMUX_PAD(0x72C, NON_MUX_I, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
+#define MX53_PAD_GPIO_19__KPP_COL_5 (_MX53_PAD_GPIO_19__KPP_COL_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__GPIO4_5 (_MX53_PAD_GPIO_19__GPIO4_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__CCM_CLKO (_MX53_PAD_GPIO_19__CCM_CLKO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__SPDIF_OUT1 (_MX53_PAD_GPIO_19__SPDIF_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 (_MX53_PAD_GPIO_19__RTC_CE_RTC_EXT_TRIG2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__ECSPI1_RDY (_MX53_PAD_GPIO_19__ECSPI1_RDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__FEC_TDATA_3 (_MX53_PAD_GPIO_19__FEC_TDATA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_19__SRC_INT_BOOT (_MX53_PAD_GPIO_19__SRC_INT_BOOT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__KPP_COL_0 (_MX53_PAD_KEY_COL0__KPP_COL_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__GPIO4_6 (_MX53_PAD_KEY_COL0__GPIO4_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC (_MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__UART4_TXD_MUX (_MX53_PAD_KEY_COL0__UART4_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__ECSPI1_SCLK (_MX53_PAD_KEY_COL0__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__FEC_RDATA_3 (_MX53_PAD_KEY_COL0__FEC_RDATA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL0__SRC_ANY_PU_RST (_MX53_PAD_KEY_COL0__SRC_ANY_PU_RST | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__KPP_ROW_0 (_MX53_PAD_KEY_ROW0__KPP_ROW_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__GPIO4_7 (_MX53_PAD_KEY_ROW0__GPIO4_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD (_MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__UART4_RXD_MUX (_MX53_PAD_KEY_ROW0__UART4_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__ECSPI1_MOSI (_MX53_PAD_KEY_ROW0__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW0__FEC_TX_ER (_MX53_PAD_KEY_ROW0__FEC_TX_ER | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__KPP_COL_1 (_MX53_PAD_KEY_COL1__KPP_COL_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__GPIO4_8 (_MX53_PAD_KEY_COL1__GPIO4_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS (_MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__UART5_TXD_MUX (_MX53_PAD_KEY_COL1__UART5_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__ECSPI1_MISO (_MX53_PAD_KEY_COL1__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__FEC_RX_CLK (_MX53_PAD_KEY_COL1__FEC_RX_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL1__USBPHY1_TXREADY (_MX53_PAD_KEY_COL1__USBPHY1_TXREADY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__KPP_ROW_1 (_MX53_PAD_KEY_ROW1__KPP_ROW_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__GPIO4_9 (_MX53_PAD_KEY_ROW1__GPIO4_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD (_MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__UART5_RXD_MUX (_MX53_PAD_KEY_ROW1__UART5_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__ECSPI1_SS0 (_MX53_PAD_KEY_ROW1__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__FEC_COL (_MX53_PAD_KEY_ROW1__FEC_COL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW1__USBPHY1_RXVALID (_MX53_PAD_KEY_ROW1__USBPHY1_RXVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__KPP_COL_2 (_MX53_PAD_KEY_COL2__KPP_COL_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__GPIO4_10 (_MX53_PAD_KEY_COL2__GPIO4_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__CAN1_TXCAN (_MX53_PAD_KEY_COL2__CAN1_TXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__FEC_MDIO (_MX53_PAD_KEY_COL2__FEC_MDIO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__ECSPI1_SS1 (_MX53_PAD_KEY_COL2__ECSPI1_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__FEC_RDATA_2 (_MX53_PAD_KEY_COL2__FEC_RDATA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE (_MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__KPP_ROW_2 (_MX53_PAD_KEY_ROW2__KPP_ROW_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__GPIO4_11 (_MX53_PAD_KEY_ROW2__GPIO4_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__CAN1_RXCAN (_MX53_PAD_KEY_ROW2__CAN1_RXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__FEC_MDC (_MX53_PAD_KEY_ROW2__FEC_MDC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__ECSPI1_SS2 (_MX53_PAD_KEY_ROW2__ECSPI1_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__FEC_TDATA_2 (_MX53_PAD_KEY_ROW2__FEC_TDATA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW2__USBPHY1_RXERROR (_MX53_PAD_KEY_ROW2__USBPHY1_RXERROR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__KPP_COL_3 (_MX53_PAD_KEY_COL3__KPP_COL_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__GPIO4_12 (_MX53_PAD_KEY_COL3__GPIO4_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__USBOH3_H2_DP (_MX53_PAD_KEY_COL3__USBOH3_H2_DP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__SPDIF_IN1 (_MX53_PAD_KEY_COL3__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__I2C2_SCL (_MX53_PAD_KEY_COL3__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__ECSPI1_SS3 (_MX53_PAD_KEY_COL3__ECSPI1_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__FEC_CRS (_MX53_PAD_KEY_COL3__FEC_CRS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK (_MX53_PAD_KEY_COL3__USBPHY1_SIECLOCK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__KPP_ROW_3 (_MX53_PAD_KEY_ROW3__KPP_ROW_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__GPIO4_13 (_MX53_PAD_KEY_ROW3__GPIO4_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__USBOH3_H2_DM (_MX53_PAD_KEY_ROW3__USBOH3_H2_DM | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK (_MX53_PAD_KEY_ROW3__CCM_ASRC_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__I2C2_SDA (_MX53_PAD_KEY_ROW3__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__OSC32K_32K_OUT (_MX53_PAD_KEY_ROW3__OSC32K_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__CCM_PLL4_BYP (_MX53_PAD_KEY_ROW3__CCM_PLL4_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 (_MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__KPP_COL_4 (_MX53_PAD_KEY_COL4__KPP_COL_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__GPIO4_14 (_MX53_PAD_KEY_COL4__GPIO4_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__CAN2_TXCAN (_MX53_PAD_KEY_COL4__CAN2_TXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__IPU_SISG_4 (_MX53_PAD_KEY_COL4__IPU_SISG_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__UART5_RTS (_MX53_PAD_KEY_COL4__UART5_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC (_MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 (_MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__KPP_ROW_4 (_MX53_PAD_KEY_ROW4__KPP_ROW_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__GPIO4_15 (_MX53_PAD_KEY_ROW4__GPIO4_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__CAN2_RXCAN (_MX53_PAD_KEY_ROW4__CAN2_RXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__IPU_SISG_5 (_MX53_PAD_KEY_ROW4__IPU_SISG_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__UART5_CTS (_MX53_PAD_KEY_ROW4__UART5_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR (_MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID (_MX53_PAD_KEY_ROW4__USBPHY1_VBUSVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK (_MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__GPIO4_16 (_MX53_PAD_DI0_DISP_CLK__GPIO4_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR (_MX53_PAD_DI0_DISP_CLK__USBOH3_USBH2_DIR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 (_MX53_PAD_DI0_DISP_CLK__SDMA_DEBUG_CORE_STATE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 (_MX53_PAD_DI0_DISP_CLK__EMI_EMI_DEBUG_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID (_MX53_PAD_DI0_DISP_CLK__USBPHY1_AVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 (_MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__GPIO4_17 (_MX53_PAD_DI0_PIN15__GPIO4_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC (_MX53_PAD_DI0_PIN15__AUDMUX_AUD6_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 (_MX53_PAD_DI0_PIN15__SDMA_DEBUG_CORE_STATE_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 (_MX53_PAD_DI0_PIN15__EMI_EMI_DEBUG_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN15__USBPHY1_BVALID (_MX53_PAD_DI0_PIN15__USBPHY1_BVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 (_MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__GPIO4_18 (_MX53_PAD_DI0_PIN2__GPIO4_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD (_MX53_PAD_DI0_PIN2__AUDMUX_AUD6_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 (_MX53_PAD_DI0_PIN2__SDMA_DEBUG_CORE_STATE_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 (_MX53_PAD_DI0_PIN2__EMI_EMI_DEBUG_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION (_MX53_PAD_DI0_PIN2__USBPHY1_ENDSESSION | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 (_MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__GPIO4_19 (_MX53_PAD_DI0_PIN3__GPIO4_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS (_MX53_PAD_DI0_PIN3__AUDMUX_AUD6_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 (_MX53_PAD_DI0_PIN3__SDMA_DEBUG_CORE_STATE_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 (_MX53_PAD_DI0_PIN3__EMI_EMI_DEBUG_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN3__USBPHY1_IDDIG (_MX53_PAD_DI0_PIN3__USBPHY1_IDDIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 (_MX53_PAD_DI0_PIN4__IPU_DI0_PIN4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__GPIO4_20 (_MX53_PAD_DI0_PIN4__GPIO4_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD (_MX53_PAD_DI0_PIN4__AUDMUX_AUD6_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__ESDHC1_WP (_MX53_PAD_DI0_PIN4__ESDHC1_WP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD (_MX53_PAD_DI0_PIN4__SDMA_DEBUG_YIELD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 (_MX53_PAD_DI0_PIN4__EMI_EMI_DEBUG_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT (_MX53_PAD_DI0_PIN4__USBPHY1_HOSTDISCONNECT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 (_MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__GPIO4_21 (_MX53_PAD_DISP0_DAT0__GPIO4_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__CSPI_SCLK (_MX53_PAD_DISP0_DAT0__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 (_MX53_PAD_DISP0_DAT0__USBOH3_USBH2_DATA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN (_MX53_PAD_DISP0_DAT0__SDMA_DEBUG_CORE_RUN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 (_MX53_PAD_DISP0_DAT0__EMI_EMI_DEBUG_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY (_MX53_PAD_DISP0_DAT0__USBPHY2_TXREADY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 (_MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__GPIO4_22 (_MX53_PAD_DISP0_DAT1__GPIO4_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__CSPI_MOSI (_MX53_PAD_DISP0_DAT1__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 (_MX53_PAD_DISP0_DAT1__USBOH3_USBH2_DATA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL (_MX53_PAD_DISP0_DAT1__SDMA_DEBUG_EVENT_CHANNEL_SEL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 (_MX53_PAD_DISP0_DAT1__EMI_EMI_DEBUG_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID (_MX53_PAD_DISP0_DAT1__USBPHY2_RXVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 (_MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__GPIO4_23 (_MX53_PAD_DISP0_DAT2__GPIO4_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__CSPI_MISO (_MX53_PAD_DISP0_DAT2__CSPI_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 (_MX53_PAD_DISP0_DAT2__USBOH3_USBH2_DATA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE (_MX53_PAD_DISP0_DAT2__SDMA_DEBUG_MODE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 (_MX53_PAD_DISP0_DAT2__EMI_EMI_DEBUG_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE (_MX53_PAD_DISP0_DAT2__USBPHY2_RXACTIVE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 (_MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__GPIO4_24 (_MX53_PAD_DISP0_DAT3__GPIO4_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__CSPI_SS0 (_MX53_PAD_DISP0_DAT3__CSPI_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 (_MX53_PAD_DISP0_DAT3__USBOH3_USBH2_DATA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR (_MX53_PAD_DISP0_DAT3__SDMA_DEBUG_BUS_ERROR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 (_MX53_PAD_DISP0_DAT3__EMI_EMI_DEBUG_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR (_MX53_PAD_DISP0_DAT3__USBPHY2_RXERROR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 (_MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__GPIO4_25 (_MX53_PAD_DISP0_DAT4__GPIO4_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__CSPI_SS1 (_MX53_PAD_DISP0_DAT4__CSPI_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 (_MX53_PAD_DISP0_DAT4__USBOH3_USBH2_DATA_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB (_MX53_PAD_DISP0_DAT4__SDMA_DEBUG_BUS_RWB | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 (_MX53_PAD_DISP0_DAT4__EMI_EMI_DEBUG_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK (_MX53_PAD_DISP0_DAT4__USBPHY2_SIECLOCK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 (_MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__GPIO4_26 (_MX53_PAD_DISP0_DAT5__GPIO4_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__CSPI_SS2 (_MX53_PAD_DISP0_DAT5__CSPI_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 (_MX53_PAD_DISP0_DAT5__USBOH3_USBH2_DATA_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS (_MX53_PAD_DISP0_DAT5__SDMA_DEBUG_MATCHED_DMBUS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 (_MX53_PAD_DISP0_DAT5__EMI_EMI_DEBUG_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 (_MX53_PAD_DISP0_DAT5__USBPHY2_LINESTATE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 (_MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__GPIO4_27 (_MX53_PAD_DISP0_DAT6__GPIO4_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__CSPI_SS3 (_MX53_PAD_DISP0_DAT6__CSPI_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 (_MX53_PAD_DISP0_DAT6__USBOH3_USBH2_DATA_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE (_MX53_PAD_DISP0_DAT6__SDMA_DEBUG_RTBUFFER_WRITE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 (_MX53_PAD_DISP0_DAT6__EMI_EMI_DEBUG_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 (_MX53_PAD_DISP0_DAT6__USBPHY2_LINESTATE_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 (_MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__GPIO4_28 (_MX53_PAD_DISP0_DAT7__GPIO4_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__CSPI_RDY (_MX53_PAD_DISP0_DAT7__CSPI_RDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 (_MX53_PAD_DISP0_DAT7__USBOH3_USBH2_DATA_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 (_MX53_PAD_DISP0_DAT7__SDMA_DEBUG_EVENT_CHANNEL_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 (_MX53_PAD_DISP0_DAT7__EMI_EMI_DEBUG_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID (_MX53_PAD_DISP0_DAT7__USBPHY2_VBUSVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 (_MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__GPIO4_29 (_MX53_PAD_DISP0_DAT8__GPIO4_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__PWM1_PWMO (_MX53_PAD_DISP0_DAT8__PWM1_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B (_MX53_PAD_DISP0_DAT8__WDOG1_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 (_MX53_PAD_DISP0_DAT8__SDMA_DEBUG_EVENT_CHANNEL_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 (_MX53_PAD_DISP0_DAT8__EMI_EMI_DEBUG_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT8__USBPHY2_AVALID (_MX53_PAD_DISP0_DAT8__USBPHY2_AVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 (_MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__GPIO4_30 (_MX53_PAD_DISP0_DAT9__GPIO4_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__PWM2_PWMO (_MX53_PAD_DISP0_DAT9__PWM2_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B (_MX53_PAD_DISP0_DAT9__WDOG2_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 (_MX53_PAD_DISP0_DAT9__SDMA_DEBUG_EVENT_CHANNEL_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 (_MX53_PAD_DISP0_DAT9__EMI_EMI_DEBUG_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 (_MX53_PAD_DISP0_DAT9__USBPHY2_VSTATUS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 (_MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__GPIO4_31 (_MX53_PAD_DISP0_DAT10__GPIO4_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP (_MX53_PAD_DISP0_DAT10__USBOH3_USBH2_STP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 (_MX53_PAD_DISP0_DAT10__SDMA_DEBUG_EVENT_CHANNEL_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 (_MX53_PAD_DISP0_DAT10__EMI_EMI_DEBUG_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 (_MX53_PAD_DISP0_DAT10__USBPHY2_VSTATUS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 (_MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__GPIO5_5 (_MX53_PAD_DISP0_DAT11__GPIO5_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT (_MX53_PAD_DISP0_DAT11__USBOH3_USBH2_NXT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 (_MX53_PAD_DISP0_DAT11__SDMA_DEBUG_EVENT_CHANNEL_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 (_MX53_PAD_DISP0_DAT11__EMI_EMI_DEBUG_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 (_MX53_PAD_DISP0_DAT11__USBPHY2_VSTATUS_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 (_MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__GPIO5_6 (_MX53_PAD_DISP0_DAT12__GPIO5_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK (_MX53_PAD_DISP0_DAT12__USBOH3_USBH2_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 (_MX53_PAD_DISP0_DAT12__SDMA_DEBUG_EVENT_CHANNEL_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 (_MX53_PAD_DISP0_DAT12__EMI_EMI_DEBUG_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 (_MX53_PAD_DISP0_DAT12__USBPHY2_VSTATUS_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 (_MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__GPIO5_7 (_MX53_PAD_DISP0_DAT13__GPIO5_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS (_MX53_PAD_DISP0_DAT13__AUDMUX_AUD5_RXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 (_MX53_PAD_DISP0_DAT13__SDMA_DEBUG_EVT_CHN_LINES_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 (_MX53_PAD_DISP0_DAT13__EMI_EMI_DEBUG_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 (_MX53_PAD_DISP0_DAT13__USBPHY2_VSTATUS_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 (_MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__GPIO5_8 (_MX53_PAD_DISP0_DAT14__GPIO5_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC (_MX53_PAD_DISP0_DAT14__AUDMUX_AUD5_RXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 (_MX53_PAD_DISP0_DAT14__SDMA_DEBUG_EVT_CHN_LINES_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 (_MX53_PAD_DISP0_DAT14__EMI_EMI_DEBUG_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 (_MX53_PAD_DISP0_DAT14__USBPHY2_VSTATUS_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 (_MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__GPIO5_9 (_MX53_PAD_DISP0_DAT15__GPIO5_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__ECSPI1_SS1 (_MX53_PAD_DISP0_DAT15__ECSPI1_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__ECSPI2_SS1 (_MX53_PAD_DISP0_DAT15__ECSPI2_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 (_MX53_PAD_DISP0_DAT15__SDMA_DEBUG_EVT_CHN_LINES_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 (_MX53_PAD_DISP0_DAT15__EMI_EMI_DEBUG_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 (_MX53_PAD_DISP0_DAT15__USBPHY2_VSTATUS_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 (_MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__GPIO5_10 (_MX53_PAD_DISP0_DAT16__GPIO5_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__ECSPI2_MOSI (_MX53_PAD_DISP0_DAT16__ECSPI2_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC (_MX53_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 (_MX53_PAD_DISP0_DAT16__SDMA_EXT_EVENT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 (_MX53_PAD_DISP0_DAT16__SDMA_DEBUG_EVT_CHN_LINES_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 (_MX53_PAD_DISP0_DAT16__EMI_EMI_DEBUG_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 (_MX53_PAD_DISP0_DAT16__USBPHY2_VSTATUS_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 (_MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__GPIO5_11 (_MX53_PAD_DISP0_DAT17__GPIO5_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__ECSPI2_MISO (_MX53_PAD_DISP0_DAT17__ECSPI2_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD (_MX53_PAD_DISP0_DAT17__AUDMUX_AUD5_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 (_MX53_PAD_DISP0_DAT17__SDMA_EXT_EVENT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 (_MX53_PAD_DISP0_DAT17__SDMA_DEBUG_EVT_CHN_LINES_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 (_MX53_PAD_DISP0_DAT17__EMI_EMI_DEBUG_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 (_MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__GPIO5_12 (_MX53_PAD_DISP0_DAT18__GPIO5_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__ECSPI2_SS0 (_MX53_PAD_DISP0_DAT18__ECSPI2_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS (_MX53_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS (_MX53_PAD_DISP0_DAT18__AUDMUX_AUD4_RXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 (_MX53_PAD_DISP0_DAT18__SDMA_DEBUG_EVT_CHN_LINES_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 (_MX53_PAD_DISP0_DAT18__EMI_EMI_DEBUG_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 (_MX53_PAD_DISP0_DAT18__EMI_WEIM_CS_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 (_MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__GPIO5_13 (_MX53_PAD_DISP0_DAT19__GPIO5_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__ECSPI2_SCLK (_MX53_PAD_DISP0_DAT19__ECSPI2_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD (_MX53_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC (_MX53_PAD_DISP0_DAT19__AUDMUX_AUD4_RXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 (_MX53_PAD_DISP0_DAT19__SDMA_DEBUG_EVT_CHN_LINES_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 (_MX53_PAD_DISP0_DAT19__EMI_EMI_DEBUG_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 (_MX53_PAD_DISP0_DAT19__EMI_WEIM_CS_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 (_MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__GPIO5_14 (_MX53_PAD_DISP0_DAT20__GPIO5_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__ECSPI1_SCLK (_MX53_PAD_DISP0_DAT20__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC (_MX53_PAD_DISP0_DAT20__AUDMUX_AUD4_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 (_MX53_PAD_DISP0_DAT20__SDMA_DEBUG_EVT_CHN_LINES_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 (_MX53_PAD_DISP0_DAT20__EMI_EMI_DEBUG_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT20__SATA_PHY_TDI (_MX53_PAD_DISP0_DAT20__SATA_PHY_TDI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 (_MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__GPIO5_15 (_MX53_PAD_DISP0_DAT21__GPIO5_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__ECSPI1_MOSI (_MX53_PAD_DISP0_DAT21__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD (_MX53_PAD_DISP0_DAT21__AUDMUX_AUD4_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 (_MX53_PAD_DISP0_DAT21__SDMA_DEBUG_BUS_DEVICE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 (_MX53_PAD_DISP0_DAT21__EMI_EMI_DEBUG_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT21__SATA_PHY_TDO (_MX53_PAD_DISP0_DAT21__SATA_PHY_TDO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 (_MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__GPIO5_16 (_MX53_PAD_DISP0_DAT22__GPIO5_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__ECSPI1_MISO (_MX53_PAD_DISP0_DAT22__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS (_MX53_PAD_DISP0_DAT22__AUDMUX_AUD4_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 (_MX53_PAD_DISP0_DAT22__SDMA_DEBUG_BUS_DEVICE_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 (_MX53_PAD_DISP0_DAT22__EMI_EMI_DEBUG_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT22__SATA_PHY_TCK (_MX53_PAD_DISP0_DAT22__SATA_PHY_TCK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 (_MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__GPIO5_17 (_MX53_PAD_DISP0_DAT23__GPIO5_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__ECSPI1_SS0 (_MX53_PAD_DISP0_DAT23__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD (_MX53_PAD_DISP0_DAT23__AUDMUX_AUD4_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 (_MX53_PAD_DISP0_DAT23__SDMA_DEBUG_BUS_DEVICE_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 (_MX53_PAD_DISP0_DAT23__EMI_EMI_DEBUG_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_DISP0_DAT23__SATA_PHY_TMS (_MX53_PAD_DISP0_DAT23__SATA_PHY_TMS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK (_MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_PIXCLK__GPIO5_18 (_MX53_PAD_CSI0_PIXCLK__GPIO5_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 (_MX53_PAD_CSI0_PIXCLK__SDMA_DEBUG_PC_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 (_MX53_PAD_CSI0_PIXCLK__EMI_EMI_DEBUG_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC (_MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__GPIO5_19 (_MX53_PAD_CSI0_MCLK__GPIO5_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK (_MX53_PAD_CSI0_MCLK__CCM_CSI0_MCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 (_MX53_PAD_CSI0_MCLK__SDMA_DEBUG_PC_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 (_MX53_PAD_CSI0_MCLK__EMI_EMI_DEBUG_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_MCLK__TPIU_TRCTL (_MX53_PAD_CSI0_MCLK__TPIU_TRCTL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN (_MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DATA_EN__GPIO5_20 (_MX53_PAD_CSI0_DATA_EN__GPIO5_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 (_MX53_PAD_CSI0_DATA_EN__SDMA_DEBUG_PC_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 (_MX53_PAD_CSI0_DATA_EN__EMI_EMI_DEBUG_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK (_MX53_PAD_CSI0_DATA_EN__TPIU_TRCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC (_MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_VSYNC__GPIO5_21 (_MX53_PAD_CSI0_VSYNC__GPIO5_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 (_MX53_PAD_CSI0_VSYNC__SDMA_DEBUG_PC_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 (_MX53_PAD_CSI0_VSYNC__EMI_EMI_DEBUG_32 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 (_MX53_PAD_CSI0_VSYNC__TPIU_TRACE_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 (_MX53_PAD_CSI0_DAT4__IPU_CSI0_D_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__GPIO5_22 (_MX53_PAD_CSI0_DAT4__GPIO5_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__KPP_COL_5 (_MX53_PAD_CSI0_DAT4__KPP_COL_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__ECSPI1_SCLK (_MX53_PAD_CSI0_DAT4__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP (_MX53_PAD_CSI0_DAT4__USBOH3_USBH3_STP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC (_MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 (_MX53_PAD_CSI0_DAT4__EMI_EMI_DEBUG_33 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 (_MX53_PAD_CSI0_DAT4__TPIU_TRACE_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 (_MX53_PAD_CSI0_DAT5__IPU_CSI0_D_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__GPIO5_23 (_MX53_PAD_CSI0_DAT5__GPIO5_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__KPP_ROW_5 (_MX53_PAD_CSI0_DAT5__KPP_ROW_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__ECSPI1_MOSI (_MX53_PAD_CSI0_DAT5__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT (_MX53_PAD_CSI0_DAT5__USBOH3_USBH3_NXT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD (_MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 (_MX53_PAD_CSI0_DAT5__EMI_EMI_DEBUG_34 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 (_MX53_PAD_CSI0_DAT5__TPIU_TRACE_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 (_MX53_PAD_CSI0_DAT6__IPU_CSI0_D_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__GPIO5_24 (_MX53_PAD_CSI0_DAT6__GPIO5_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__KPP_COL_6 (_MX53_PAD_CSI0_DAT6__KPP_COL_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__ECSPI1_MISO (_MX53_PAD_CSI0_DAT6__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK (_MX53_PAD_CSI0_DAT6__USBOH3_USBH3_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS (_MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 (_MX53_PAD_CSI0_DAT6__EMI_EMI_DEBUG_35 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 (_MX53_PAD_CSI0_DAT6__TPIU_TRACE_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 (_MX53_PAD_CSI0_DAT7__IPU_CSI0_D_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__GPIO5_25 (_MX53_PAD_CSI0_DAT7__GPIO5_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__KPP_ROW_6 (_MX53_PAD_CSI0_DAT7__KPP_ROW_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__ECSPI1_SS0 (_MX53_PAD_CSI0_DAT7__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR (_MX53_PAD_CSI0_DAT7__USBOH3_USBH3_DIR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD (_MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 (_MX53_PAD_CSI0_DAT7__EMI_EMI_DEBUG_36 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 (_MX53_PAD_CSI0_DAT7__TPIU_TRACE_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 (_MX53_PAD_CSI0_DAT8__IPU_CSI0_D_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__GPIO5_26 (_MX53_PAD_CSI0_DAT8__GPIO5_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__KPP_COL_7 (_MX53_PAD_CSI0_DAT8__KPP_COL_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__ECSPI2_SCLK (_MX53_PAD_CSI0_DAT8__ECSPI2_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC (_MX53_PAD_CSI0_DAT8__USBOH3_USBH3_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__I2C1_SDA (_MX53_PAD_CSI0_DAT8__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 (_MX53_PAD_CSI0_DAT8__EMI_EMI_DEBUG_37 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 (_MX53_PAD_CSI0_DAT8__TPIU_TRACE_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 (_MX53_PAD_CSI0_DAT9__IPU_CSI0_D_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__GPIO5_27 (_MX53_PAD_CSI0_DAT9__GPIO5_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__KPP_ROW_7 (_MX53_PAD_CSI0_DAT9__KPP_ROW_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__ECSPI2_MOSI (_MX53_PAD_CSI0_DAT9__ECSPI2_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR (_MX53_PAD_CSI0_DAT9__USBOH3_USBH3_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__I2C1_SCL (_MX53_PAD_CSI0_DAT9__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 (_MX53_PAD_CSI0_DAT9__EMI_EMI_DEBUG_38 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 (_MX53_PAD_CSI0_DAT9__TPIU_TRACE_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 (_MX53_PAD_CSI0_DAT10__IPU_CSI0_D_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__GPIO5_28 (_MX53_PAD_CSI0_DAT10__GPIO5_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__UART1_TXD_MUX (_MX53_PAD_CSI0_DAT10__UART1_TXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__ECSPI2_MISO (_MX53_PAD_CSI0_DAT10__ECSPI2_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC (_MX53_PAD_CSI0_DAT10__AUDMUX_AUD3_RXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 (_MX53_PAD_CSI0_DAT10__SDMA_DEBUG_PC_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 (_MX53_PAD_CSI0_DAT10__EMI_EMI_DEBUG_39 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 (_MX53_PAD_CSI0_DAT10__TPIU_TRACE_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 (_MX53_PAD_CSI0_DAT11__IPU_CSI0_D_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__GPIO5_29 (_MX53_PAD_CSI0_DAT11__GPIO5_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__UART1_RXD_MUX (_MX53_PAD_CSI0_DAT11__UART1_RXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__ECSPI2_SS0 (_MX53_PAD_CSI0_DAT11__ECSPI2_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS (_MX53_PAD_CSI0_DAT11__AUDMUX_AUD3_RXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 (_MX53_PAD_CSI0_DAT11__SDMA_DEBUG_PC_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 (_MX53_PAD_CSI0_DAT11__EMI_EMI_DEBUG_40 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 (_MX53_PAD_CSI0_DAT11__TPIU_TRACE_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 (_MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__GPIO5_30 (_MX53_PAD_CSI0_DAT12__GPIO5_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__UART4_TXD_MUX (_MX53_PAD_CSI0_DAT12__UART4_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 (_MX53_PAD_CSI0_DAT12__USBOH3_USBH3_DATA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 (_MX53_PAD_CSI0_DAT12__SDMA_DEBUG_PC_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 (_MX53_PAD_CSI0_DAT12__EMI_EMI_DEBUG_41 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 (_MX53_PAD_CSI0_DAT12__TPIU_TRACE_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 (_MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__GPIO5_31 (_MX53_PAD_CSI0_DAT13__GPIO5_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__UART4_RXD_MUX (_MX53_PAD_CSI0_DAT13__UART4_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 (_MX53_PAD_CSI0_DAT13__USBOH3_USBH3_DATA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 (_MX53_PAD_CSI0_DAT13__SDMA_DEBUG_PC_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 (_MX53_PAD_CSI0_DAT13__EMI_EMI_DEBUG_42 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 (_MX53_PAD_CSI0_DAT13__TPIU_TRACE_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 (_MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__GPIO6_0 (_MX53_PAD_CSI0_DAT14__GPIO6_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__UART5_TXD_MUX (_MX53_PAD_CSI0_DAT14__UART5_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 (_MX53_PAD_CSI0_DAT14__USBOH3_USBH3_DATA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 (_MX53_PAD_CSI0_DAT14__SDMA_DEBUG_PC_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 (_MX53_PAD_CSI0_DAT14__EMI_EMI_DEBUG_43 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 (_MX53_PAD_CSI0_DAT14__TPIU_TRACE_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 (_MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__GPIO6_1 (_MX53_PAD_CSI0_DAT15__GPIO6_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__UART5_RXD_MUX (_MX53_PAD_CSI0_DAT15__UART5_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 (_MX53_PAD_CSI0_DAT15__USBOH3_USBH3_DATA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 (_MX53_PAD_CSI0_DAT15__SDMA_DEBUG_PC_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 (_MX53_PAD_CSI0_DAT15__EMI_EMI_DEBUG_44 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 (_MX53_PAD_CSI0_DAT15__TPIU_TRACE_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 (_MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__GPIO6_2 (_MX53_PAD_CSI0_DAT16__GPIO6_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__UART4_RTS (_MX53_PAD_CSI0_DAT16__UART4_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 (_MX53_PAD_CSI0_DAT16__USBOH3_USBH3_DATA_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 (_MX53_PAD_CSI0_DAT16__SDMA_DEBUG_PC_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 (_MX53_PAD_CSI0_DAT16__EMI_EMI_DEBUG_45 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 (_MX53_PAD_CSI0_DAT16__TPIU_TRACE_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 (_MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__GPIO6_3 (_MX53_PAD_CSI0_DAT17__GPIO6_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__UART4_CTS (_MX53_PAD_CSI0_DAT17__UART4_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 (_MX53_PAD_CSI0_DAT17__USBOH3_USBH3_DATA_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 (_MX53_PAD_CSI0_DAT17__SDMA_DEBUG_PC_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 (_MX53_PAD_CSI0_DAT17__EMI_EMI_DEBUG_46 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 (_MX53_PAD_CSI0_DAT17__TPIU_TRACE_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 (_MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__GPIO6_4 (_MX53_PAD_CSI0_DAT18__GPIO6_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__UART5_RTS (_MX53_PAD_CSI0_DAT18__UART5_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 (_MX53_PAD_CSI0_DAT18__USBOH3_USBH3_DATA_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 (_MX53_PAD_CSI0_DAT18__SDMA_DEBUG_PC_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 (_MX53_PAD_CSI0_DAT18__EMI_EMI_DEBUG_47 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 (_MX53_PAD_CSI0_DAT18__TPIU_TRACE_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 (_MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__GPIO6_5 (_MX53_PAD_CSI0_DAT19__GPIO6_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__UART5_CTS (_MX53_PAD_CSI0_DAT19__UART5_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 (_MX53_PAD_CSI0_DAT19__USBOH3_USBH3_DATA_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 (_MX53_PAD_CSI0_DAT19__SDMA_DEBUG_PC_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 (_MX53_PAD_CSI0_DAT19__EMI_EMI_DEBUG_48 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK (_MX53_PAD_CSI0_DAT19__USBPHY2_BISTOK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__EMI_WEIM_A_25 (_MX53_PAD_EIM_A25__EMI_WEIM_A_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__GPIO5_2 (_MX53_PAD_EIM_A25__GPIO5_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__ECSPI2_RDY (_MX53_PAD_EIM_A25__ECSPI2_RDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__IPU_DI1_PIN12 (_MX53_PAD_EIM_A25__IPU_DI1_PIN12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__CSPI_SS1 (_MX53_PAD_EIM_A25__CSPI_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__IPU_DI0_D1_CS (_MX53_PAD_EIM_A25__IPU_DI0_D1_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A25__USBPHY1_BISTOK (_MX53_PAD_EIM_A25__USBPHY1_BISTOK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 (_MX53_PAD_EIM_EB2__EMI_WEIM_EB_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__GPIO2_30 (_MX53_PAD_EIM_EB2__GPIO2_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK (_MX53_PAD_EIM_EB2__CCM_DI1_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS (_MX53_PAD_EIM_EB2__IPU_SER_DISP1_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__ECSPI1_SS0 (_MX53_PAD_EIM_EB2__ECSPI1_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB2__I2C2_SCL (_MX53_PAD_EIM_EB2__I2C2_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__EMI_WEIM_D_16 (_MX53_PAD_EIM_D16__EMI_WEIM_D_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__GPIO3_16 (_MX53_PAD_EIM_D16__GPIO3_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__IPU_DI0_PIN5 (_MX53_PAD_EIM_D16__IPU_DI0_PIN5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK (_MX53_PAD_EIM_D16__IPU_DISPB1_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__ECSPI1_SCLK (_MX53_PAD_EIM_D16__ECSPI1_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D16__I2C2_SDA (_MX53_PAD_EIM_D16__I2C2_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__EMI_WEIM_D_17 (_MX53_PAD_EIM_D17__EMI_WEIM_D_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__GPIO3_17 (_MX53_PAD_EIM_D17__GPIO3_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__IPU_DI0_PIN6 (_MX53_PAD_EIM_D17__IPU_DI0_PIN6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN (_MX53_PAD_EIM_D17__IPU_DISPB1_SER_DIN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__ECSPI1_MISO (_MX53_PAD_EIM_D17__ECSPI1_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D17__I2C3_SCL (_MX53_PAD_EIM_D17__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__EMI_WEIM_D_18 (_MX53_PAD_EIM_D18__EMI_WEIM_D_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__GPIO3_18 (_MX53_PAD_EIM_D18__GPIO3_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__IPU_DI0_PIN7 (_MX53_PAD_EIM_D18__IPU_DI0_PIN7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO (_MX53_PAD_EIM_D18__IPU_DISPB1_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__ECSPI1_MOSI (_MX53_PAD_EIM_D18__ECSPI1_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__I2C3_SDA (_MX53_PAD_EIM_D18__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D18__IPU_DI1_D0_CS (_MX53_PAD_EIM_D18__IPU_DI1_D0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__EMI_WEIM_D_19 (_MX53_PAD_EIM_D19__EMI_WEIM_D_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__GPIO3_19 (_MX53_PAD_EIM_D19__GPIO3_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__IPU_DI0_PIN8 (_MX53_PAD_EIM_D19__IPU_DI0_PIN8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS (_MX53_PAD_EIM_D19__IPU_DISPB1_SER_RS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__ECSPI1_SS1 (_MX53_PAD_EIM_D19__ECSPI1_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__EPIT1_EPITO (_MX53_PAD_EIM_D19__EPIT1_EPITO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__UART1_CTS (_MX53_PAD_EIM_D19__UART1_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D19__USBOH3_USBH2_OC (_MX53_PAD_EIM_D19__USBOH3_USBH2_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__EMI_WEIM_D_20 (_MX53_PAD_EIM_D20__EMI_WEIM_D_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__GPIO3_20 (_MX53_PAD_EIM_D20__GPIO3_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__IPU_DI0_PIN16 (_MX53_PAD_EIM_D20__IPU_DI0_PIN16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__IPU_SER_DISP0_CS (_MX53_PAD_EIM_D20__IPU_SER_DISP0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__CSPI_SS0 (_MX53_PAD_EIM_D20__CSPI_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__EPIT2_EPITO (_MX53_PAD_EIM_D20__EPIT2_EPITO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__UART1_RTS (_MX53_PAD_EIM_D20__UART1_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D20__USBOH3_USBH2_PWR (_MX53_PAD_EIM_D20__USBOH3_USBH2_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__EMI_WEIM_D_21 (_MX53_PAD_EIM_D21__EMI_WEIM_D_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__GPIO3_21 (_MX53_PAD_EIM_D21__GPIO3_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__IPU_DI0_PIN17 (_MX53_PAD_EIM_D21__IPU_DI0_PIN17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK (_MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__CSPI_SCLK (_MX53_PAD_EIM_D21__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__I2C1_SCL (_MX53_PAD_EIM_D21__I2C1_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D21__USBOH3_USBOTG_OC (_MX53_PAD_EIM_D21__USBOH3_USBOTG_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__EMI_WEIM_D_22 (_MX53_PAD_EIM_D22__EMI_WEIM_D_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__GPIO3_22 (_MX53_PAD_EIM_D22__GPIO3_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__IPU_DI0_PIN1 (_MX53_PAD_EIM_D22__IPU_DI0_PIN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN (_MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__CSPI_MISO (_MX53_PAD_EIM_D22__CSPI_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR (_MX53_PAD_EIM_D22__USBOH3_USBOTG_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__EMI_WEIM_D_23 (_MX53_PAD_EIM_D23__EMI_WEIM_D_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__GPIO3_23 (_MX53_PAD_EIM_D23__GPIO3_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__UART3_CTS (_MX53_PAD_EIM_D23__UART3_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__UART1_DCD (_MX53_PAD_EIM_D23__UART1_DCD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__IPU_DI0_D0_CS (_MX53_PAD_EIM_D23__IPU_DI0_D0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__IPU_DI1_PIN2 (_MX53_PAD_EIM_D23__IPU_DI1_PIN2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN (_MX53_PAD_EIM_D23__IPU_CSI1_DATA_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D23__IPU_DI1_PIN14 (_MX53_PAD_EIM_D23__IPU_DI1_PIN14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 (_MX53_PAD_EIM_EB3__EMI_WEIM_EB_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__GPIO2_31 (_MX53_PAD_EIM_EB3__GPIO2_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__UART3_RTS (_MX53_PAD_EIM_EB3__UART3_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__UART1_RI (_MX53_PAD_EIM_EB3__UART1_RI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__IPU_DI1_PIN3 (_MX53_PAD_EIM_EB3__IPU_DI1_PIN3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC (_MX53_PAD_EIM_EB3__IPU_CSI1_HSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB3__IPU_DI1_PIN16 (_MX53_PAD_EIM_EB3__IPU_DI1_PIN16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__EMI_WEIM_D_24 (_MX53_PAD_EIM_D24__EMI_WEIM_D_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__GPIO3_24 (_MX53_PAD_EIM_D24__GPIO3_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__UART3_TXD_MUX (_MX53_PAD_EIM_D24__UART3_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__ECSPI1_SS2 (_MX53_PAD_EIM_D24__ECSPI1_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__CSPI_SS2 (_MX53_PAD_EIM_D24__CSPI_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS (_MX53_PAD_EIM_D24__AUDMUX_AUD5_RXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__ECSPI2_SS2 (_MX53_PAD_EIM_D24__ECSPI2_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D24__UART1_DTR (_MX53_PAD_EIM_D24__UART1_DTR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__EMI_WEIM_D_25 (_MX53_PAD_EIM_D25__EMI_WEIM_D_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__GPIO3_25 (_MX53_PAD_EIM_D25__GPIO3_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__UART3_RXD_MUX (_MX53_PAD_EIM_D25__UART3_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__ECSPI1_SS3 (_MX53_PAD_EIM_D25__ECSPI1_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__CSPI_SS3 (_MX53_PAD_EIM_D25__CSPI_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC (_MX53_PAD_EIM_D25__AUDMUX_AUD5_RXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__ECSPI2_SS3 (_MX53_PAD_EIM_D25__ECSPI2_SS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D25__UART1_DSR (_MX53_PAD_EIM_D25__UART1_DSR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__EMI_WEIM_D_26 (_MX53_PAD_EIM_D26__EMI_WEIM_D_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__GPIO3_26 (_MX53_PAD_EIM_D26__GPIO3_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__UART2_TXD_MUX (_MX53_PAD_EIM_D26__UART2_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__FIRI_RXD (_MX53_PAD_EIM_D26__FIRI_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__IPU_CSI0_D_1 (_MX53_PAD_EIM_D26__IPU_CSI0_D_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__IPU_DI1_PIN11 (_MX53_PAD_EIM_D26__IPU_DI1_PIN11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__IPU_SISG_2 (_MX53_PAD_EIM_D26__IPU_SISG_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 (_MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__EMI_WEIM_D_27 (_MX53_PAD_EIM_D27__EMI_WEIM_D_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__GPIO3_27 (_MX53_PAD_EIM_D27__GPIO3_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__UART2_RXD_MUX (_MX53_PAD_EIM_D27__UART2_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__FIRI_TXD (_MX53_PAD_EIM_D27__FIRI_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__IPU_CSI0_D_0 (_MX53_PAD_EIM_D27__IPU_CSI0_D_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__IPU_DI1_PIN13 (_MX53_PAD_EIM_D27__IPU_DI1_PIN13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__IPU_SISG_3 (_MX53_PAD_EIM_D27__IPU_SISG_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 (_MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__EMI_WEIM_D_28 (_MX53_PAD_EIM_D28__EMI_WEIM_D_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__GPIO3_28 (_MX53_PAD_EIM_D28__GPIO3_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__UART2_CTS (_MX53_PAD_EIM_D28__UART2_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO (_MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__CSPI_MOSI (_MX53_PAD_EIM_D28__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__I2C1_SDA (_MX53_PAD_EIM_D28__I2C1_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__IPU_EXT_TRIG (_MX53_PAD_EIM_D28__IPU_EXT_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D28__IPU_DI0_PIN13 (_MX53_PAD_EIM_D28__IPU_DI0_PIN13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__EMI_WEIM_D_29 (_MX53_PAD_EIM_D29__EMI_WEIM_D_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__GPIO3_29 (_MX53_PAD_EIM_D29__GPIO3_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__UART2_RTS (_MX53_PAD_EIM_D29__UART2_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS (_MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__CSPI_SS0 (_MX53_PAD_EIM_D29__CSPI_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__IPU_DI1_PIN15 (_MX53_PAD_EIM_D29__IPU_DI1_PIN15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__IPU_CSI1_VSYNC (_MX53_PAD_EIM_D29__IPU_CSI1_VSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D29__IPU_DI0_PIN14 (_MX53_PAD_EIM_D29__IPU_DI0_PIN14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__EMI_WEIM_D_30 (_MX53_PAD_EIM_D30__EMI_WEIM_D_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__GPIO3_30 (_MX53_PAD_EIM_D30__GPIO3_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__UART3_CTS (_MX53_PAD_EIM_D30__UART3_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__IPU_CSI0_D_3 (_MX53_PAD_EIM_D30__IPU_CSI0_D_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__IPU_DI0_PIN11 (_MX53_PAD_EIM_D30__IPU_DI0_PIN11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 (_MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__USBOH3_USBH1_OC (_MX53_PAD_EIM_D30__USBOH3_USBH1_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D30__USBOH3_USBH2_OC (_MX53_PAD_EIM_D30__USBOH3_USBH2_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__EMI_WEIM_D_31 (_MX53_PAD_EIM_D31__EMI_WEIM_D_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__GPIO3_31 (_MX53_PAD_EIM_D31__GPIO3_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__UART3_RTS (_MX53_PAD_EIM_D31__UART3_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__IPU_CSI0_D_2 (_MX53_PAD_EIM_D31__IPU_CSI0_D_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__IPU_DI0_PIN12 (_MX53_PAD_EIM_D31__IPU_DI0_PIN12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 (_MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__USBOH3_USBH1_PWR (_MX53_PAD_EIM_D31__USBOH3_USBH1_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_D31__USBOH3_USBH2_PWR (_MX53_PAD_EIM_D31__USBOH3_USBH2_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__EMI_WEIM_A_24 (_MX53_PAD_EIM_A24__EMI_WEIM_A_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__GPIO5_4 (_MX53_PAD_EIM_A24__GPIO5_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 (_MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__IPU_CSI1_D_19 (_MX53_PAD_EIM_A24__IPU_CSI1_D_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__IPU_SISG_2 (_MX53_PAD_EIM_A24__IPU_SISG_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A24__USBPHY2_BVALID (_MX53_PAD_EIM_A24__USBPHY2_BVALID | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__EMI_WEIM_A_23 (_MX53_PAD_EIM_A23__EMI_WEIM_A_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__GPIO6_6 (_MX53_PAD_EIM_A23__GPIO6_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 (_MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__IPU_CSI1_D_18 (_MX53_PAD_EIM_A23__IPU_CSI1_D_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__IPU_SISG_3 (_MX53_PAD_EIM_A23__IPU_SISG_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A23__USBPHY2_ENDSESSION (_MX53_PAD_EIM_A23__USBPHY2_ENDSESSION | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A22__EMI_WEIM_A_22 (_MX53_PAD_EIM_A22__EMI_WEIM_A_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A22__GPIO2_16 (_MX53_PAD_EIM_A22__GPIO2_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 (_MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A22__IPU_CSI1_D_17 (_MX53_PAD_EIM_A22__IPU_CSI1_D_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A22__SRC_BT_CFG1_7 (_MX53_PAD_EIM_A22__SRC_BT_CFG1_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A21__EMI_WEIM_A_21 (_MX53_PAD_EIM_A21__EMI_WEIM_A_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A21__GPIO2_17 (_MX53_PAD_EIM_A21__GPIO2_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 (_MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A21__IPU_CSI1_D_16 (_MX53_PAD_EIM_A21__IPU_CSI1_D_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A21__SRC_BT_CFG1_6 (_MX53_PAD_EIM_A21__SRC_BT_CFG1_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A20__EMI_WEIM_A_20 (_MX53_PAD_EIM_A20__EMI_WEIM_A_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A20__GPIO2_18 (_MX53_PAD_EIM_A20__GPIO2_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 (_MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A20__IPU_CSI1_D_15 (_MX53_PAD_EIM_A20__IPU_CSI1_D_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A20__SRC_BT_CFG1_5 (_MX53_PAD_EIM_A20__SRC_BT_CFG1_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A19__EMI_WEIM_A_19 (_MX53_PAD_EIM_A19__EMI_WEIM_A_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A19__GPIO2_19 (_MX53_PAD_EIM_A19__GPIO2_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 (_MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A19__IPU_CSI1_D_14 (_MX53_PAD_EIM_A19__IPU_CSI1_D_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A19__SRC_BT_CFG1_4 (_MX53_PAD_EIM_A19__SRC_BT_CFG1_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A18__EMI_WEIM_A_18 (_MX53_PAD_EIM_A18__EMI_WEIM_A_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A18__GPIO2_20 (_MX53_PAD_EIM_A18__GPIO2_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 (_MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A18__IPU_CSI1_D_13 (_MX53_PAD_EIM_A18__IPU_CSI1_D_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A18__SRC_BT_CFG1_3 (_MX53_PAD_EIM_A18__SRC_BT_CFG1_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A17__EMI_WEIM_A_17 (_MX53_PAD_EIM_A17__EMI_WEIM_A_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A17__GPIO2_21 (_MX53_PAD_EIM_A17__GPIO2_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 (_MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A17__IPU_CSI1_D_12 (_MX53_PAD_EIM_A17__IPU_CSI1_D_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A17__SRC_BT_CFG1_2 (_MX53_PAD_EIM_A17__SRC_BT_CFG1_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A16__EMI_WEIM_A_16 (_MX53_PAD_EIM_A16__EMI_WEIM_A_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A16__GPIO2_22 (_MX53_PAD_EIM_A16__GPIO2_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK (_MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK (_MX53_PAD_EIM_A16__IPU_CSI1_PIXCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_A16__SRC_BT_CFG1_1 (_MX53_PAD_EIM_A16__SRC_BT_CFG1_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 (_MX53_PAD_EIM_CS0__EMI_WEIM_CS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS0__GPIO2_23 (_MX53_PAD_EIM_CS0__GPIO2_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS0__ECSPI2_SCLK (_MX53_PAD_EIM_CS0__ECSPI2_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS0__IPU_DI1_PIN5 (_MX53_PAD_EIM_CS0__IPU_DI1_PIN5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 (_MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS1__GPIO2_24 (_MX53_PAD_EIM_CS1__GPIO2_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS1__ECSPI2_MOSI (_MX53_PAD_EIM_CS1__ECSPI2_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_CS1__IPU_DI1_PIN6 (_MX53_PAD_EIM_CS1__IPU_DI1_PIN6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_OE__EMI_WEIM_OE (_MX53_PAD_EIM_OE__EMI_WEIM_OE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_OE__GPIO2_25 (_MX53_PAD_EIM_OE__GPIO2_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_OE__ECSPI2_MISO (_MX53_PAD_EIM_OE__ECSPI2_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_OE__IPU_DI1_PIN7 (_MX53_PAD_EIM_OE__IPU_DI1_PIN7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_OE__USBPHY2_IDDIG (_MX53_PAD_EIM_OE__USBPHY2_IDDIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_RW__EMI_WEIM_RW (_MX53_PAD_EIM_RW__EMI_WEIM_RW | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_RW__GPIO2_26 (_MX53_PAD_EIM_RW__GPIO2_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_RW__ECSPI2_SS0 (_MX53_PAD_EIM_RW__ECSPI2_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_RW__IPU_DI1_PIN8 (_MX53_PAD_EIM_RW__IPU_DI1_PIN8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT (_MX53_PAD_EIM_RW__USBPHY2_HOSTDISCONNECT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_LBA__EMI_WEIM_LBA (_MX53_PAD_EIM_LBA__EMI_WEIM_LBA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_LBA__GPIO2_27 (_MX53_PAD_EIM_LBA__GPIO2_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_LBA__ECSPI2_SS1 (_MX53_PAD_EIM_LBA__ECSPI2_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_LBA__IPU_DI1_PIN17 (_MX53_PAD_EIM_LBA__IPU_DI1_PIN17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 (_MX53_PAD_EIM_LBA__SRC_BT_CFG1_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 (_MX53_PAD_EIM_EB0__EMI_WEIM_EB_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__GPIO2_28 (_MX53_PAD_EIM_EB0__GPIO2_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 (_MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__IPU_CSI1_D_11 (_MX53_PAD_EIM_EB0__IPU_CSI1_D_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__GPC_PMIC_RDY (_MX53_PAD_EIM_EB0__GPC_PMIC_RDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 (_MX53_PAD_EIM_EB0__SRC_BT_CFG2_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 (_MX53_PAD_EIM_EB1__EMI_WEIM_EB_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB1__GPIO2_29 (_MX53_PAD_EIM_EB1__GPIO2_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 (_MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB1__IPU_CSI1_D_10 (_MX53_PAD_EIM_EB1__IPU_CSI1_D_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 (_MX53_PAD_EIM_EB1__SRC_BT_CFG2_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 (_MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA0__GPIO3_0 (_MX53_PAD_EIM_DA0__GPIO3_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 (_MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA0__IPU_CSI1_D_9 (_MX53_PAD_EIM_DA0__IPU_CSI1_D_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 (_MX53_PAD_EIM_DA0__SRC_BT_CFG2_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 (_MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA1__GPIO3_1 (_MX53_PAD_EIM_DA1__GPIO3_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 (_MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA1__IPU_CSI1_D_8 (_MX53_PAD_EIM_DA1__IPU_CSI1_D_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 (_MX53_PAD_EIM_DA1__SRC_BT_CFG2_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 (_MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA2__GPIO3_2 (_MX53_PAD_EIM_DA2__GPIO3_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 (_MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA2__IPU_CSI1_D_7 (_MX53_PAD_EIM_DA2__IPU_CSI1_D_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 (_MX53_PAD_EIM_DA2__SRC_BT_CFG2_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 (_MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA3__GPIO3_3 (_MX53_PAD_EIM_DA3__GPIO3_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 (_MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA3__IPU_CSI1_D_6 (_MX53_PAD_EIM_DA3__IPU_CSI1_D_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 (_MX53_PAD_EIM_DA3__SRC_BT_CFG2_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 (_MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA4__GPIO3_4 (_MX53_PAD_EIM_DA4__GPIO3_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 (_MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA4__IPU_CSI1_D_5 (_MX53_PAD_EIM_DA4__IPU_CSI1_D_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 (_MX53_PAD_EIM_DA4__SRC_BT_CFG3_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 (_MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA5__GPIO3_5 (_MX53_PAD_EIM_DA5__GPIO3_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 (_MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA5__IPU_CSI1_D_4 (_MX53_PAD_EIM_DA5__IPU_CSI1_D_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 (_MX53_PAD_EIM_DA5__SRC_BT_CFG3_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 (_MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA6__GPIO3_6 (_MX53_PAD_EIM_DA6__GPIO3_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 (_MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA6__IPU_CSI1_D_3 (_MX53_PAD_EIM_DA6__IPU_CSI1_D_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 (_MX53_PAD_EIM_DA6__SRC_BT_CFG3_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 (_MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA7__GPIO3_7 (_MX53_PAD_EIM_DA7__GPIO3_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 (_MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA7__IPU_CSI1_D_2 (_MX53_PAD_EIM_DA7__IPU_CSI1_D_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 (_MX53_PAD_EIM_DA7__SRC_BT_CFG3_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 (_MX53_PAD_EIM_DA8__EMI_NAND_WEIM_DA_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA8__GPIO3_8 (_MX53_PAD_EIM_DA8__GPIO3_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 (_MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA8__IPU_CSI1_D_1 (_MX53_PAD_EIM_DA8__IPU_CSI1_D_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 (_MX53_PAD_EIM_DA8__SRC_BT_CFG3_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 (_MX53_PAD_EIM_DA9__EMI_NAND_WEIM_DA_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA9__GPIO3_9 (_MX53_PAD_EIM_DA9__GPIO3_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 (_MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA9__IPU_CSI1_D_0 (_MX53_PAD_EIM_DA9__IPU_CSI1_D_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 (_MX53_PAD_EIM_DA9__SRC_BT_CFG3_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 (_MX53_PAD_EIM_DA10__EMI_NAND_WEIM_DA_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA10__GPIO3_10 (_MX53_PAD_EIM_DA10__GPIO3_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA10__IPU_DI1_PIN15 (_MX53_PAD_EIM_DA10__IPU_DI1_PIN15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN (_MX53_PAD_EIM_DA10__IPU_CSI1_DATA_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 (_MX53_PAD_EIM_DA10__SRC_BT_CFG3_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 (_MX53_PAD_EIM_DA11__EMI_NAND_WEIM_DA_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA11__GPIO3_11 (_MX53_PAD_EIM_DA11__GPIO3_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA11__IPU_DI1_PIN2 (_MX53_PAD_EIM_DA11__IPU_DI1_PIN2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC (_MX53_PAD_EIM_DA11__IPU_CSI1_HSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 (_MX53_PAD_EIM_DA12__EMI_NAND_WEIM_DA_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA12__GPIO3_12 (_MX53_PAD_EIM_DA12__GPIO3_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA12__IPU_DI1_PIN3 (_MX53_PAD_EIM_DA12__IPU_DI1_PIN3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC (_MX53_PAD_EIM_DA12__IPU_CSI1_VSYNC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 (_MX53_PAD_EIM_DA13__EMI_NAND_WEIM_DA_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA13__GPIO3_13 (_MX53_PAD_EIM_DA13__GPIO3_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA13__IPU_DI1_D0_CS (_MX53_PAD_EIM_DA13__IPU_DI1_D0_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK (_MX53_PAD_EIM_DA13__CCM_DI1_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 (_MX53_PAD_EIM_DA14__EMI_NAND_WEIM_DA_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA14__GPIO3_14 (_MX53_PAD_EIM_DA14__GPIO3_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA14__IPU_DI1_D1_CS (_MX53_PAD_EIM_DA14__IPU_DI1_D1_CS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK (_MX53_PAD_EIM_DA14__CCM_DI0_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 (_MX53_PAD_EIM_DA15__EMI_NAND_WEIM_DA_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA15__GPIO3_15 (_MX53_PAD_EIM_DA15__GPIO3_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA15__IPU_DI1_PIN1 (_MX53_PAD_EIM_DA15__IPU_DI1_PIN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_DA15__IPU_DI1_PIN4 (_MX53_PAD_EIM_DA15__IPU_DI1_PIN4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B (_MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_WE_B__GPIO6_12 (_MX53_PAD_NANDF_WE_B__GPIO6_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B (_MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_RE_B__GPIO6_13 (_MX53_PAD_NANDF_RE_B__GPIO6_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT (_MX53_PAD_EIM_WAIT__EMI_WEIM_WAIT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_WAIT__GPIO5_0 (_MX53_PAD_EIM_WAIT__GPIO5_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B (_MX53_PAD_EIM_WAIT__EMI_WEIM_DTACK_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX3_P__GPIO6_22 (_MX53_PAD_LVDS1_TX3_P__GPIO6_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 (_MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX2_P__GPIO6_24 (_MX53_PAD_LVDS1_TX2_P__GPIO6_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 (_MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_CLK_P__GPIO6_26 (_MX53_PAD_LVDS1_CLK_P__GPIO6_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK (_MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX1_P__GPIO6_28 (_MX53_PAD_LVDS1_TX1_P__GPIO6_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 (_MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX0_P__GPIO6_30 (_MX53_PAD_LVDS1_TX0_P__GPIO6_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 (_MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX3_P__GPIO7_22 (_MX53_PAD_LVDS0_TX3_P__GPIO7_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 (_MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_CLK_P__GPIO7_24 (_MX53_PAD_LVDS0_CLK_P__GPIO7_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK (_MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX2_P__GPIO7_26 (_MX53_PAD_LVDS0_TX2_P__GPIO7_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 (_MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX1_P__GPIO7_28 (_MX53_PAD_LVDS0_TX1_P__GPIO7_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 (_MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX0_P__GPIO7_30 (_MX53_PAD_LVDS0_TX0_P__GPIO7_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 (_MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_10__GPIO4_0 (_MX53_PAD_GPIO_10__GPIO4_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_10__OSC32k_32K_OUT (_MX53_PAD_GPIO_10__OSC32k_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_11__GPIO4_1 (_MX53_PAD_GPIO_11__GPIO4_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_12__GPIO4_2 (_MX53_PAD_GPIO_12__GPIO4_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_13__GPIO4_3 (_MX53_PAD_GPIO_13__GPIO4_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_14__GPIO4_4 (_MX53_PAD_GPIO_14__GPIO4_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CLE__EMI_NANDF_CLE (_MX53_PAD_NANDF_CLE__EMI_NANDF_CLE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CLE__GPIO6_7 (_MX53_PAD_NANDF_CLE__GPIO6_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 (_MX53_PAD_NANDF_CLE__USBPHY1_VSTATUS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_ALE__EMI_NANDF_ALE (_MX53_PAD_NANDF_ALE__EMI_NANDF_ALE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_ALE__GPIO6_8 (_MX53_PAD_NANDF_ALE__GPIO6_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 (_MX53_PAD_NANDF_ALE__USBPHY1_VSTATUS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B (_MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_WP_B__GPIO6_9 (_MX53_PAD_NANDF_WP_B__GPIO6_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 (_MX53_PAD_NANDF_WP_B__USBPHY1_VSTATUS_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 (_MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_RB0__GPIO6_10 (_MX53_PAD_NANDF_RB0__GPIO6_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 (_MX53_PAD_NANDF_RB0__USBPHY1_VSTATUS_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 (_MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS0__GPIO6_11 (_MX53_PAD_NANDF_CS0__GPIO6_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 (_MX53_PAD_NANDF_CS0__USBPHY1_VSTATUS_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 (_MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS1__GPIO6_14 (_MX53_PAD_NANDF_CS1__GPIO6_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS1__MLB_MLBCLK (_MX53_PAD_NANDF_CS1__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 (_MX53_PAD_NANDF_CS1__USBPHY1_VSTATUS_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 (_MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__GPIO6_15 (_MX53_PAD_NANDF_CS2__GPIO6_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__IPU_SISG_0 (_MX53_PAD_NANDF_CS2__IPU_SISG_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__ESAI1_TX0 (_MX53_PAD_NANDF_CS2__ESAI1_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__EMI_WEIM_CRE (_MX53_PAD_NANDF_CS2__EMI_WEIM_CRE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK (_MX53_PAD_NANDF_CS2__CCM_CSI0_MCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__MLB_MLBSIG (_MX53_PAD_NANDF_CS2__MLB_MLBSIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 (_MX53_PAD_NANDF_CS2__USBPHY1_VSTATUS_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 (_MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__GPIO6_16 (_MX53_PAD_NANDF_CS3__GPIO6_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__IPU_SISG_1 (_MX53_PAD_NANDF_CS3__IPU_SISG_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__ESAI1_TX1 (_MX53_PAD_NANDF_CS3__ESAI1_TX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 (_MX53_PAD_NANDF_CS3__EMI_WEIM_A_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__MLB_MLBDAT (_MX53_PAD_NANDF_CS3__MLB_MLBDAT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 (_MX53_PAD_NANDF_CS3__USBPHY1_VSTATUS_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__FEC_MDIO (_MX53_PAD_FEC_MDIO__FEC_MDIO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__GPIO1_22 (_MX53_PAD_FEC_MDIO__GPIO1_22 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__ESAI1_SCKR (_MX53_PAD_FEC_MDIO__ESAI1_SCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__FEC_COL (_MX53_PAD_FEC_MDIO__FEC_COL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 (_MX53_PAD_FEC_MDIO__RTC_CE_RTC_PS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 (_MX53_PAD_FEC_MDIO__SDMA_DEBUG_BUS_DEVICE_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 (_MX53_PAD_FEC_MDIO__EMI_EMI_DEBUG_49 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_REF_CLK__FEC_TX_CLK (_MX53_PAD_FEC_REF_CLK__FEC_TX_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_REF_CLK__GPIO1_23 (_MX53_PAD_FEC_REF_CLK__GPIO1_23 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_REF_CLK__ESAI1_FSR (_MX53_PAD_FEC_REF_CLK__ESAI1_FSR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 (_MX53_PAD_FEC_REF_CLK__SDMA_DEBUG_BUS_DEVICE_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 (_MX53_PAD_FEC_REF_CLK__EMI_EMI_DEBUG_50 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RX_ER__FEC_RX_ER (_MX53_PAD_FEC_RX_ER__FEC_RX_ER | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RX_ER__GPIO1_24 (_MX53_PAD_FEC_RX_ER__GPIO1_24 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RX_ER__ESAI1_HCKR (_MX53_PAD_FEC_RX_ER__ESAI1_HCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RX_ER__FEC_RX_CLK (_MX53_PAD_FEC_RX_ER__FEC_RX_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 (_MX53_PAD_FEC_RX_ER__RTC_CE_RTC_PS3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_CRS_DV__FEC_RX_DV (_MX53_PAD_FEC_CRS_DV__FEC_RX_DV | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_CRS_DV__GPIO1_25 (_MX53_PAD_FEC_CRS_DV__GPIO1_25 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_CRS_DV__ESAI1_SCKT (_MX53_PAD_FEC_CRS_DV__ESAI1_SCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD1__FEC_RDATA_1 (_MX53_PAD_FEC_RXD1__FEC_RDATA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD1__GPIO1_26 (_MX53_PAD_FEC_RXD1__GPIO1_26 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD1__ESAI1_FST (_MX53_PAD_FEC_RXD1__ESAI1_FST | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD1__MLB_MLBSIG (_MX53_PAD_FEC_RXD1__MLB_MLBSIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 (_MX53_PAD_FEC_RXD1__RTC_CE_RTC_PS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD0__FEC_RDATA_0 (_MX53_PAD_FEC_RXD0__FEC_RDATA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD0__GPIO1_27 (_MX53_PAD_FEC_RXD0__GPIO1_27 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD0__ESAI1_HCKT (_MX53_PAD_FEC_RXD0__ESAI1_HCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_RXD0__OSC32k_32K_OUT (_MX53_PAD_FEC_RXD0__OSC32k_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TX_EN__FEC_TX_EN (_MX53_PAD_FEC_TX_EN__FEC_TX_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TX_EN__GPIO1_28 (_MX53_PAD_FEC_TX_EN__GPIO1_28 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 (_MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD1__FEC_TDATA_1 (_MX53_PAD_FEC_TXD1__FEC_TDATA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD1__GPIO1_29 (_MX53_PAD_FEC_TXD1__GPIO1_29 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 (_MX53_PAD_FEC_TXD1__ESAI1_TX2_RX3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD1__MLB_MLBCLK (_MX53_PAD_FEC_TXD1__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK (_MX53_PAD_FEC_TXD1__RTC_CE_RTC_PRSC_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD0__FEC_TDATA_0 (_MX53_PAD_FEC_TXD0__FEC_TDATA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD0__GPIO1_30 (_MX53_PAD_FEC_TXD0__GPIO1_30 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 (_MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 (_MX53_PAD_FEC_TXD0__USBPHY2_DATAOUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__FEC_MDC (_MX53_PAD_FEC_MDC__FEC_MDC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__GPIO1_31 (_MX53_PAD_FEC_MDC__GPIO1_31 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 (_MX53_PAD_FEC_MDC__ESAI1_TX5_RX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__MLB_MLBDAT (_MX53_PAD_FEC_MDC__MLB_MLBDAT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG (_MX53_PAD_FEC_MDC__RTC_CE_RTC_ALARM1_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 (_MX53_PAD_FEC_MDC__USBPHY2_DATAOUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOW__PATA_DIOW (_MX53_PAD_PATA_DIOW__PATA_DIOW | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOW__GPIO6_17 (_MX53_PAD_PATA_DIOW__GPIO6_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOW__UART1_TXD_MUX (_MX53_PAD_PATA_DIOW__UART1_TXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 (_MX53_PAD_PATA_DIOW__USBPHY2_DATAOUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMACK__PATA_DMACK (_MX53_PAD_PATA_DMACK__PATA_DMACK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMACK__GPIO6_18 (_MX53_PAD_PATA_DMACK__GPIO6_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMACK__UART1_RXD_MUX (_MX53_PAD_PATA_DMACK__UART1_RXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 (_MX53_PAD_PATA_DMACK__USBPHY2_DATAOUT_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMARQ__PATA_DMARQ (_MX53_PAD_PATA_DMARQ__PATA_DMARQ | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMARQ__GPIO7_0 (_MX53_PAD_PATA_DMARQ__GPIO7_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMARQ__UART2_TXD_MUX (_MX53_PAD_PATA_DMARQ__UART2_TXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 (_MX53_PAD_PATA_DMARQ__CCM_CCM_OUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 (_MX53_PAD_PATA_DMARQ__USBPHY2_DATAOUT_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN (_MX53_PAD_PATA_BUFFER_EN__PATA_BUFFER_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_BUFFER_EN__GPIO7_1 (_MX53_PAD_PATA_BUFFER_EN__GPIO7_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX (_MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 (_MX53_PAD_PATA_BUFFER_EN__CCM_CCM_OUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 (_MX53_PAD_PATA_BUFFER_EN__USBPHY2_DATAOUT_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__PATA_INTRQ (_MX53_PAD_PATA_INTRQ__PATA_INTRQ | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__GPIO7_2 (_MX53_PAD_PATA_INTRQ__GPIO7_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__UART2_CTS (_MX53_PAD_PATA_INTRQ__UART2_CTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__CAN1_TXCAN (_MX53_PAD_PATA_INTRQ__CAN1_TXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 (_MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 (_MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOR__PATA_DIOR (_MX53_PAD_PATA_DIOR__PATA_DIOR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOR__GPIO7_3 (_MX53_PAD_PATA_DIOR__GPIO7_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOR__UART2_RTS (_MX53_PAD_PATA_DIOR__UART2_RTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DIOR__CAN1_RXCAN (_MX53_PAD_PATA_DIOR__CAN1_RXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 (_MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B (_MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__GPIO7_4 (_MX53_PAD_PATA_RESET_B__GPIO7_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__ESDHC3_CMD (_MX53_PAD_PATA_RESET_B__ESDHC3_CMD | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__UART1_CTS (_MX53_PAD_PATA_RESET_B__UART1_CTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__CAN2_TXCAN (_MX53_PAD_PATA_RESET_B__CAN2_TXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 (_MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__PATA_IORDY (_MX53_PAD_PATA_IORDY__PATA_IORDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__GPIO7_5 (_MX53_PAD_PATA_IORDY__GPIO7_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__ESDHC3_CLK (_MX53_PAD_PATA_IORDY__ESDHC3_CLK | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__UART1_RTS (_MX53_PAD_PATA_IORDY__UART1_RTS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__CAN2_RXCAN (_MX53_PAD_PATA_IORDY__CAN2_RXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 (_MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_0__PATA_DA_0 (_MX53_PAD_PATA_DA_0__PATA_DA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_0__GPIO7_6 (_MX53_PAD_PATA_DA_0__GPIO7_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_0__ESDHC3_RST (_MX53_PAD_PATA_DA_0__ESDHC3_RST | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_0__OWIRE_LINE (_MX53_PAD_PATA_DA_0__OWIRE_LINE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 (_MX53_PAD_PATA_DA_0__USBPHY1_DATAOUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_1__PATA_DA_1 (_MX53_PAD_PATA_DA_1__PATA_DA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_1__GPIO7_7 (_MX53_PAD_PATA_DA_1__GPIO7_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_1__ESDHC4_CMD (_MX53_PAD_PATA_DA_1__ESDHC4_CMD | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DA_1__UART3_CTS (_MX53_PAD_PATA_DA_1__UART3_CTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 (_MX53_PAD_PATA_DA_1__USBPHY1_DATAOUT_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_2__PATA_DA_2 (_MX53_PAD_PATA_DA_2__PATA_DA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_2__GPIO7_8 (_MX53_PAD_PATA_DA_2__GPIO7_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DA_2__ESDHC4_CLK (_MX53_PAD_PATA_DA_2__ESDHC4_CLK | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DA_2__UART3_RTS (_MX53_PAD_PATA_DA_2__UART3_RTS | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 (_MX53_PAD_PATA_DA_2__USBPHY1_DATAOUT_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_0__PATA_CS_0 (_MX53_PAD_PATA_CS_0__PATA_CS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_0__GPIO7_9 (_MX53_PAD_PATA_CS_0__GPIO7_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_0__UART3_TXD_MUX (_MX53_PAD_PATA_CS_0__UART3_TXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 (_MX53_PAD_PATA_CS_0__USBPHY1_DATAOUT_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_1__PATA_CS_1 (_MX53_PAD_PATA_CS_1__PATA_CS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_1__GPIO7_10 (_MX53_PAD_PATA_CS_1__GPIO7_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_CS_1__UART3_RXD_MUX (_MX53_PAD_PATA_CS_1__UART3_RXD_MUX | MUX_PAD_CTRL(MX53_UART_PAD_CTRL))
+#define MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 (_MX53_PAD_PATA_CS_1__USBPHY1_DATAOUT_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__PATA_DATA_0 (_MX53_PAD_PATA_DATA0__PATA_DATA_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__GPIO2_0 (_MX53_PAD_PATA_DATA0__GPIO2_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 (_MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__ESDHC3_DAT4 (_MX53_PAD_PATA_DATA0__ESDHC3_DAT4 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 (_MX53_PAD_PATA_DATA0__GPU3d_GPU_DEBUG_OUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 (_MX53_PAD_PATA_DATA0__IPU_DIAG_BUS_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 (_MX53_PAD_PATA_DATA0__USBPHY1_DATAOUT_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__PATA_DATA_1 (_MX53_PAD_PATA_DATA1__PATA_DATA_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__GPIO2_1 (_MX53_PAD_PATA_DATA1__GPIO2_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 (_MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__ESDHC3_DAT5 (_MX53_PAD_PATA_DATA1__ESDHC3_DAT5 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 (_MX53_PAD_PATA_DATA1__GPU3d_GPU_DEBUG_OUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 (_MX53_PAD_PATA_DATA1__IPU_DIAG_BUS_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__PATA_DATA_2 (_MX53_PAD_PATA_DATA2__PATA_DATA_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__GPIO2_2 (_MX53_PAD_PATA_DATA2__GPIO2_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 (_MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__ESDHC3_DAT6 (_MX53_PAD_PATA_DATA2__ESDHC3_DAT6 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 (_MX53_PAD_PATA_DATA2__GPU3d_GPU_DEBUG_OUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 (_MX53_PAD_PATA_DATA2__IPU_DIAG_BUS_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__PATA_DATA_3 (_MX53_PAD_PATA_DATA3__PATA_DATA_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__GPIO2_3 (_MX53_PAD_PATA_DATA3__GPIO2_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 (_MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__ESDHC3_DAT7 (_MX53_PAD_PATA_DATA3__ESDHC3_DAT7 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 (_MX53_PAD_PATA_DATA3__GPU3d_GPU_DEBUG_OUT_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 (_MX53_PAD_PATA_DATA3__IPU_DIAG_BUS_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__PATA_DATA_4 (_MX53_PAD_PATA_DATA4__PATA_DATA_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__GPIO2_4 (_MX53_PAD_PATA_DATA4__GPIO2_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 (_MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__ESDHC4_DAT4 (_MX53_PAD_PATA_DATA4__ESDHC4_DAT4 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 (_MX53_PAD_PATA_DATA4__GPU3d_GPU_DEBUG_OUT_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 (_MX53_PAD_PATA_DATA4__IPU_DIAG_BUS_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__PATA_DATA_5 (_MX53_PAD_PATA_DATA5__PATA_DATA_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__GPIO2_5 (_MX53_PAD_PATA_DATA5__GPIO2_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 (_MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__ESDHC4_DAT5 (_MX53_PAD_PATA_DATA5__ESDHC4_DAT5 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 (_MX53_PAD_PATA_DATA5__GPU3d_GPU_DEBUG_OUT_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 (_MX53_PAD_PATA_DATA5__IPU_DIAG_BUS_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__PATA_DATA_6 (_MX53_PAD_PATA_DATA6__PATA_DATA_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__GPIO2_6 (_MX53_PAD_PATA_DATA6__GPIO2_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 (_MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__ESDHC4_DAT6 (_MX53_PAD_PATA_DATA6__ESDHC4_DAT6 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 (_MX53_PAD_PATA_DATA6__GPU3d_GPU_DEBUG_OUT_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 (_MX53_PAD_PATA_DATA6__IPU_DIAG_BUS_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__PATA_DATA_7 (_MX53_PAD_PATA_DATA7__PATA_DATA_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__GPIO2_7 (_MX53_PAD_PATA_DATA7__GPIO2_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 (_MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__ESDHC4_DAT7 (_MX53_PAD_PATA_DATA7__ESDHC4_DAT7 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 (_MX53_PAD_PATA_DATA7__GPU3d_GPU_DEBUG_OUT_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 (_MX53_PAD_PATA_DATA7__IPU_DIAG_BUS_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__PATA_DATA_8 (_MX53_PAD_PATA_DATA8__PATA_DATA_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__GPIO2_8 (_MX53_PAD_PATA_DATA8__GPIO2_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__ESDHC1_DAT4 (_MX53_PAD_PATA_DATA8__ESDHC1_DAT4 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 (_MX53_PAD_PATA_DATA8__EMI_NANDF_D_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__ESDHC3_DAT0 (_MX53_PAD_PATA_DATA8__ESDHC3_DAT0 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 (_MX53_PAD_PATA_DATA8__GPU3d_GPU_DEBUG_OUT_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 (_MX53_PAD_PATA_DATA8__IPU_DIAG_BUS_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__PATA_DATA_9 (_MX53_PAD_PATA_DATA9__PATA_DATA_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__GPIO2_9 (_MX53_PAD_PATA_DATA9__GPIO2_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__ESDHC1_DAT5 (_MX53_PAD_PATA_DATA9__ESDHC1_DAT5 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 (_MX53_PAD_PATA_DATA9__EMI_NANDF_D_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__ESDHC3_DAT1 (_MX53_PAD_PATA_DATA9__ESDHC3_DAT1 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 (_MX53_PAD_PATA_DATA9__GPU3d_GPU_DEBUG_OUT_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 (_MX53_PAD_PATA_DATA9__IPU_DIAG_BUS_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__PATA_DATA_10 (_MX53_PAD_PATA_DATA10__PATA_DATA_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__GPIO2_10 (_MX53_PAD_PATA_DATA10__GPIO2_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__ESDHC1_DAT6 (_MX53_PAD_PATA_DATA10__ESDHC1_DAT6 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 (_MX53_PAD_PATA_DATA10__EMI_NANDF_D_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__ESDHC3_DAT2 (_MX53_PAD_PATA_DATA10__ESDHC3_DAT2 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 (_MX53_PAD_PATA_DATA10__GPU3d_GPU_DEBUG_OUT_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 (_MX53_PAD_PATA_DATA10__IPU_DIAG_BUS_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__PATA_DATA_11 (_MX53_PAD_PATA_DATA11__PATA_DATA_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__GPIO2_11 (_MX53_PAD_PATA_DATA11__GPIO2_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__ESDHC1_DAT7 (_MX53_PAD_PATA_DATA11__ESDHC1_DAT7 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 (_MX53_PAD_PATA_DATA11__EMI_NANDF_D_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__ESDHC3_DAT3 (_MX53_PAD_PATA_DATA11__ESDHC3_DAT3 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 (_MX53_PAD_PATA_DATA11__GPU3d_GPU_DEBUG_OUT_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 (_MX53_PAD_PATA_DATA11__IPU_DIAG_BUS_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__PATA_DATA_12 (_MX53_PAD_PATA_DATA12__PATA_DATA_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__GPIO2_12 (_MX53_PAD_PATA_DATA12__GPIO2_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__ESDHC2_DAT4 (_MX53_PAD_PATA_DATA12__ESDHC2_DAT4 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 (_MX53_PAD_PATA_DATA12__EMI_NANDF_D_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__ESDHC4_DAT0 (_MX53_PAD_PATA_DATA12__ESDHC4_DAT0 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 (_MX53_PAD_PATA_DATA12__GPU3d_GPU_DEBUG_OUT_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 (_MX53_PAD_PATA_DATA12__IPU_DIAG_BUS_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__PATA_DATA_13 (_MX53_PAD_PATA_DATA13__PATA_DATA_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__GPIO2_13 (_MX53_PAD_PATA_DATA13__GPIO2_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__ESDHC2_DAT5 (_MX53_PAD_PATA_DATA13__ESDHC2_DAT5 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 (_MX53_PAD_PATA_DATA13__EMI_NANDF_D_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__ESDHC4_DAT1 (_MX53_PAD_PATA_DATA13__ESDHC4_DAT1 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 (_MX53_PAD_PATA_DATA13__GPU3d_GPU_DEBUG_OUT_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 (_MX53_PAD_PATA_DATA13__IPU_DIAG_BUS_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__PATA_DATA_14 (_MX53_PAD_PATA_DATA14__PATA_DATA_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__GPIO2_14 (_MX53_PAD_PATA_DATA14__GPIO2_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__ESDHC2_DAT6 (_MX53_PAD_PATA_DATA14__ESDHC2_DAT6 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 (_MX53_PAD_PATA_DATA14__EMI_NANDF_D_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__ESDHC4_DAT2 (_MX53_PAD_PATA_DATA14__ESDHC4_DAT2 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 (_MX53_PAD_PATA_DATA14__GPU3d_GPU_DEBUG_OUT_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 (_MX53_PAD_PATA_DATA14__IPU_DIAG_BUS_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__PATA_DATA_15 (_MX53_PAD_PATA_DATA15__PATA_DATA_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__GPIO2_15 (_MX53_PAD_PATA_DATA15__GPIO2_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__ESDHC2_DAT7 (_MX53_PAD_PATA_DATA15__ESDHC2_DAT7 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 (_MX53_PAD_PATA_DATA15__EMI_NANDF_D_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__ESDHC4_DAT3 (_MX53_PAD_PATA_DATA15__ESDHC4_DAT3 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 (_MX53_PAD_PATA_DATA15__GPU3d_GPU_DEBUG_OUT_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 (_MX53_PAD_PATA_DATA15__IPU_DIAG_BUS_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA0__ESDHC1_DAT0 (_MX53_PAD_SD1_DATA0__ESDHC1_DAT0 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_DATA0__GPIO1_16 (_MX53_PAD_SD1_DATA0__GPIO1_16 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA0__GPT_CAPIN1 (_MX53_PAD_SD1_DATA0__GPT_CAPIN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA0__CSPI_MISO (_MX53_PAD_SD1_DATA0__CSPI_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA0__CCM_PLL3_BYP (_MX53_PAD_SD1_DATA0__CCM_PLL3_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA1__ESDHC1_DAT1 (_MX53_PAD_SD1_DATA1__ESDHC1_DAT1 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_DATA1__GPIO1_17 (_MX53_PAD_SD1_DATA1__GPIO1_17 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA1__GPT_CAPIN2 (_MX53_PAD_SD1_DATA1__GPT_CAPIN2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA1__CSPI_SS0 (_MX53_PAD_SD1_DATA1__CSPI_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA1__CCM_PLL4_BYP (_MX53_PAD_SD1_DATA1__CCM_PLL4_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CMD__ESDHC1_CMD (_MX53_PAD_SD1_CMD__ESDHC1_CMD | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_CMD__GPIO1_18 (_MX53_PAD_SD1_CMD__GPIO1_18 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CMD__GPT_CMPOUT1 (_MX53_PAD_SD1_CMD__GPT_CMPOUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CMD__CSPI_MOSI (_MX53_PAD_SD1_CMD__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CMD__CCM_PLL1_BYP (_MX53_PAD_SD1_CMD__CCM_PLL1_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__ESDHC1_DAT2 (_MX53_PAD_SD1_DATA2__ESDHC1_DAT2 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__GPIO1_19 (_MX53_PAD_SD1_DATA2__GPIO1_19 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__GPT_CMPOUT2 (_MX53_PAD_SD1_DATA2__GPT_CMPOUT2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__PWM2_PWMO (_MX53_PAD_SD1_DATA2__PWM2_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__WDOG1_WDOG_B (_MX53_PAD_SD1_DATA2__WDOG1_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__CSPI_SS1 (_MX53_PAD_SD1_DATA2__CSPI_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB (_MX53_PAD_SD1_DATA2__WDOG1_WDOG_RST_B_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA2__CCM_PLL2_BYP (_MX53_PAD_SD1_DATA2__CCM_PLL2_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__ESDHC1_CLK (_MX53_PAD_SD1_CLK__ESDHC1_CLK | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__GPIO1_20 (_MX53_PAD_SD1_CLK__GPIO1_20 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__OSC32k_32K_OUT (_MX53_PAD_SD1_CLK__OSC32k_32K_OUT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__GPT_CLKIN (_MX53_PAD_SD1_CLK__GPT_CLKIN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__CSPI_SCLK (_MX53_PAD_SD1_CLK__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 (_MX53_PAD_SD1_CLK__SATA_PHY_DTB_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__ESDHC1_DAT3 (_MX53_PAD_SD1_DATA3__ESDHC1_DAT3 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__GPIO1_21 (_MX53_PAD_SD1_DATA3__GPIO1_21 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__GPT_CMPOUT3 (_MX53_PAD_SD1_DATA3__GPT_CMPOUT3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__PWM1_PWMO (_MX53_PAD_SD1_DATA3__PWM1_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__WDOG2_WDOG_B (_MX53_PAD_SD1_DATA3__WDOG2_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__CSPI_SS2 (_MX53_PAD_SD1_DATA3__CSPI_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB (_MX53_PAD_SD1_DATA3__WDOG2_WDOG_RST_B_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 (_MX53_PAD_SD1_DATA3__SATA_PHY_DTB_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__ESDHC2_CLK (_MX53_PAD_SD2_CLK__ESDHC2_CLK | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__GPIO1_10 (_MX53_PAD_SD2_CLK__GPIO1_10 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__KPP_COL_5 (_MX53_PAD_SD2_CLK__KPP_COL_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS (_MX53_PAD_SD2_CLK__AUDMUX_AUD4_RXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__CSPI_SCLK (_MX53_PAD_SD2_CLK__CSPI_SCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CLK__SCC_RANDOM_V (_MX53_PAD_SD2_CLK__SCC_RANDOM_V | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__ESDHC2_CMD (_MX53_PAD_SD2_CMD__ESDHC2_CMD | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__GPIO1_11 (_MX53_PAD_SD2_CMD__GPIO1_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__KPP_ROW_5 (_MX53_PAD_SD2_CMD__KPP_ROW_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC (_MX53_PAD_SD2_CMD__AUDMUX_AUD4_RXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__CSPI_MOSI (_MX53_PAD_SD2_CMD__CSPI_MOSI | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_CMD__SCC_RANDOM (_MX53_PAD_SD2_CMD__SCC_RANDOM | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__ESDHC2_DAT3 (_MX53_PAD_SD2_DATA3__ESDHC2_DAT3 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__GPIO1_12 (_MX53_PAD_SD2_DATA3__GPIO1_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__KPP_COL_6 (_MX53_PAD_SD2_DATA3__KPP_COL_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC (_MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__CSPI_SS2 (_MX53_PAD_SD2_DATA3__CSPI_SS2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA3__SJC_DONE (_MX53_PAD_SD2_DATA3__SJC_DONE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__ESDHC2_DAT2 (_MX53_PAD_SD2_DATA2__ESDHC2_DAT2 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__GPIO1_13 (_MX53_PAD_SD2_DATA2__GPIO1_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__KPP_ROW_6 (_MX53_PAD_SD2_DATA2__KPP_ROW_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD (_MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__CSPI_SS1 (_MX53_PAD_SD2_DATA2__CSPI_SS1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA2__SJC_FAIL (_MX53_PAD_SD2_DATA2__SJC_FAIL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__ESDHC2_DAT1 (_MX53_PAD_SD2_DATA1__ESDHC2_DAT1 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__GPIO1_14 (_MX53_PAD_SD2_DATA1__GPIO1_14 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__KPP_COL_7 (_MX53_PAD_SD2_DATA1__KPP_COL_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS (_MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__CSPI_SS0 (_MX53_PAD_SD2_DATA1__CSPI_SS0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA1__RTIC_SEC_VIO (_MX53_PAD_SD2_DATA1__RTIC_SEC_VIO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__ESDHC2_DAT0 (_MX53_PAD_SD2_DATA0__ESDHC2_DAT0 | MUX_PAD_CTRL(MX53_SDHC_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__GPIO1_15 (_MX53_PAD_SD2_DATA0__GPIO1_15 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__KPP_ROW_7 (_MX53_PAD_SD2_DATA0__KPP_ROW_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD (_MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__CSPI_MISO (_MX53_PAD_SD2_DATA0__CSPI_MISO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_SD2_DATA0__RTIC_DONE_INT (_MX53_PAD_SD2_DATA0__RTIC_DONE_INT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__CCM_CLKO (_MX53_PAD_GPIO_0__CCM_CLKO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__GPIO1_0 (_MX53_PAD_GPIO_0__GPIO1_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__KPP_COL_5 (_MX53_PAD_GPIO_0__KPP_COL_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK (_MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__EPIT1_EPITO (_MX53_PAD_GPIO_0__EPIT1_EPITO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__SRTC_ALARM_DEB (_MX53_PAD_GPIO_0__SRTC_ALARM_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__USBOH3_USBH1_PWR (_MX53_PAD_GPIO_0__USBOH3_USBH1_PWR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_0__CSU_TD (_MX53_PAD_GPIO_0__CSU_TD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__ESAI1_SCKR (_MX53_PAD_GPIO_1__ESAI1_SCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__GPIO1_1 (_MX53_PAD_GPIO_1__GPIO1_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__KPP_ROW_5 (_MX53_PAD_GPIO_1__KPP_ROW_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK (_MX53_PAD_GPIO_1__CCM_SSI_EXT2_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__PWM2_PWMO (_MX53_PAD_GPIO_1__PWM2_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__WDOG2_WDOG_B (_MX53_PAD_GPIO_1__WDOG2_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__ESDHC1_CD (_MX53_PAD_GPIO_1__ESDHC1_CD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_1__SRC_TESTER_ACK (_MX53_PAD_GPIO_1__SRC_TESTER_ACK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__ESAI1_FSR (_MX53_PAD_GPIO_9__ESAI1_FSR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__GPIO1_9 (_MX53_PAD_GPIO_9__GPIO1_9 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__KPP_COL_6 (_MX53_PAD_GPIO_9__KPP_COL_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__CCM_REF_EN_B (_MX53_PAD_GPIO_9__CCM_REF_EN_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__PWM1_PWMO (_MX53_PAD_GPIO_9__PWM1_PWMO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__WDOG1_WDOG_B (_MX53_PAD_GPIO_9__WDOG1_WDOG_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__ESDHC1_WP (_MX53_PAD_GPIO_9__ESDHC1_WP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_9__SCC_FAIL_STATE (_MX53_PAD_GPIO_9__SCC_FAIL_STATE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__ESAI1_HCKR (_MX53_PAD_GPIO_3__ESAI1_HCKR | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__GPIO1_3 (_MX53_PAD_GPIO_3__GPIO1_3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__I2C3_SCL (_MX53_PAD_GPIO_3__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__DPLLIP1_TOG_EN (_MX53_PAD_GPIO_3__DPLLIP1_TOG_EN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__CCM_CLKO2 (_MX53_PAD_GPIO_3__CCM_CLKO2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 (_MX53_PAD_GPIO_3__OBSERVE_MUX_OBSRV_INT_OUT0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__USBOH3_USBH1_OC (_MX53_PAD_GPIO_3__USBOH3_USBH1_OC | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_3__MLB_MLBCLK (_MX53_PAD_GPIO_3__MLB_MLBCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__ESAI1_SCKT (_MX53_PAD_GPIO_6__ESAI1_SCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__GPIO1_6 (_MX53_PAD_GPIO_6__GPIO1_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__I2C3_SDA (_MX53_PAD_GPIO_6__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__CCM_CCM_OUT_0 (_MX53_PAD_GPIO_6__CCM_CCM_OUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__CSU_CSU_INT_DEB (_MX53_PAD_GPIO_6__CSU_CSU_INT_DEB | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 (_MX53_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__ESDHC2_LCTL (_MX53_PAD_GPIO_6__ESDHC2_LCTL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_6__MLB_MLBSIG (_MX53_PAD_GPIO_6__MLB_MLBSIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__ESAI1_FST (_MX53_PAD_GPIO_2__ESAI1_FST | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__GPIO1_2 (_MX53_PAD_GPIO_2__GPIO1_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__KPP_ROW_6 (_MX53_PAD_GPIO_2__KPP_ROW_6 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__CCM_CCM_OUT_1 (_MX53_PAD_GPIO_2__CCM_CCM_OUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 (_MX53_PAD_GPIO_2__CSU_CSU_ALARM_AUT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 (_MX53_PAD_GPIO_2__OBSERVE_MUX_OBSRV_INT_OUT2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__ESDHC2_WP (_MX53_PAD_GPIO_2__ESDHC2_WP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_2__MLB_MLBDAT (_MX53_PAD_GPIO_2__MLB_MLBDAT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__ESAI1_HCKT (_MX53_PAD_GPIO_4__ESAI1_HCKT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__GPIO1_4 (_MX53_PAD_GPIO_4__GPIO1_4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__KPP_COL_7 (_MX53_PAD_GPIO_4__KPP_COL_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__CCM_CCM_OUT_2 (_MX53_PAD_GPIO_4__CCM_CCM_OUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 (_MX53_PAD_GPIO_4__CSU_CSU_ALARM_AUT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 (_MX53_PAD_GPIO_4__OBSERVE_MUX_OBSRV_INT_OUT3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__ESDHC2_CD (_MX53_PAD_GPIO_4__ESDHC2_CD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_4__SCC_SEC_STATE (_MX53_PAD_GPIO_4__SCC_SEC_STATE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__ESAI1_TX2_RX3 (_MX53_PAD_GPIO_5__ESAI1_TX2_RX3 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__GPIO1_5 (_MX53_PAD_GPIO_5__GPIO1_5 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__KPP_ROW_7 (_MX53_PAD_GPIO_5__KPP_ROW_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__CCM_CLKO (_MX53_PAD_GPIO_5__CCM_CLKO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 (_MX53_PAD_GPIO_5__CSU_CSU_ALARM_AUT_2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 (_MX53_PAD_GPIO_5__OBSERVE_MUX_OBSRV_INT_OUT4 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__I2C3_SCL (_MX53_PAD_GPIO_5__I2C3_SCL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_5__CCM_PLL1_BYP (_MX53_PAD_GPIO_5__CCM_PLL1_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__ESAI1_TX4_RX1 (_MX53_PAD_GPIO_7__ESAI1_TX4_RX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__GPIO1_7 (_MX53_PAD_GPIO_7__GPIO1_7 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__EPIT1_EPITO (_MX53_PAD_GPIO_7__EPIT1_EPITO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__CAN1_TXCAN (_MX53_PAD_GPIO_7__CAN1_TXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__UART2_TXD_MUX (_MX53_PAD_GPIO_7__UART2_TXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__FIRI_RXD (_MX53_PAD_GPIO_7__FIRI_RXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__SPDIF_PLOCK (_MX53_PAD_GPIO_7__SPDIF_PLOCK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_7__CCM_PLL2_BYP (_MX53_PAD_GPIO_7__CCM_PLL2_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__ESAI1_TX5_RX0 (_MX53_PAD_GPIO_8__ESAI1_TX5_RX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__GPIO1_8 (_MX53_PAD_GPIO_8__GPIO1_8 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__EPIT2_EPITO (_MX53_PAD_GPIO_8__EPIT2_EPITO | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__CAN1_RXCAN (_MX53_PAD_GPIO_8__CAN1_RXCAN | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__UART2_RXD_MUX (_MX53_PAD_GPIO_8__UART2_RXD_MUX | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__FIRI_TXD (_MX53_PAD_GPIO_8__FIRI_TXD | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__SPDIF_SRCLK (_MX53_PAD_GPIO_8__SPDIF_SRCLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_8__CCM_PLL3_BYP (_MX53_PAD_GPIO_8__CCM_PLL3_BYP | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__ESAI1_TX3_RX2 (_MX53_PAD_GPIO_16__ESAI1_TX3_RX2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__GPIO7_11 (_MX53_PAD_GPIO_16__GPIO7_11 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT (_MX53_PAD_GPIO_16__TZIC_PWRFAIL_INT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 (_MX53_PAD_GPIO_16__RTC_CE_RTC_EXT_TRIG1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__SPDIF_IN1 (_MX53_PAD_GPIO_16__SPDIF_IN1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__I2C3_SDA (_MX53_PAD_GPIO_16__I2C3_SDA | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_16__SJC_DE_B (_MX53_PAD_GPIO_16__SJC_DE_B | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__ESAI1_TX0 (_MX53_PAD_GPIO_17__ESAI1_TX0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__GPIO7_12 (_MX53_PAD_GPIO_17__GPIO7_12 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 (_MX53_PAD_GPIO_17__SDMA_EXT_EVENT_0 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__GPC_PMIC_RDY (_MX53_PAD_GPIO_17__GPC_PMIC_RDY | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG (_MX53_PAD_GPIO_17__RTC_CE_RTC_FSV_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__SPDIF_OUT1 (_MX53_PAD_GPIO_17__SPDIF_OUT1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__IPU_SNOOP2 (_MX53_PAD_GPIO_17__IPU_SNOOP2 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_17__SJC_JTAG_ACT (_MX53_PAD_GPIO_17__SJC_JTAG_ACT | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__ESAI1_TX1 (_MX53_PAD_GPIO_18__ESAI1_TX1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__GPIO7_13 (_MX53_PAD_GPIO_18__GPIO7_13 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 (_MX53_PAD_GPIO_18__SDMA_EXT_EVENT_1 | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__OWIRE_LINE (_MX53_PAD_GPIO_18__OWIRE_LINE | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG (_MX53_PAD_GPIO_18__RTC_CE_RTC_ALARM2_TRIG | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK (_MX53_PAD_GPIO_18__CCM_ASRC_EXT_CLK | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__ESDHC1_LCTL (_MX53_PAD_GPIO_18__ESDHC1_LCTL | MUX_PAD_CTRL(NO_PAD_CTRL))
+#define MX53_PAD_GPIO_18__SRC_SYSTEM_RST (_MX53_PAD_GPIO_18__SRC_SYSTEM_RST | MUX_PAD_CTRL(NO_PAD_CTRL))
#endif /* __MACH_IOMUX_MX53_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h b/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
index 15d59510f597..bf28df0d58b7 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
@@ -46,12 +46,12 @@
* - setups the iomux according to the configuration
* - if the pin is configured as a GPIO, we claim it through kernel gpiolib
*/
-int mxc_iomux_alloc_pin(const unsigned int pin_mode, const char *label);
+int mxc_iomux_alloc_pin(unsigned int pin_mode, const char *label);
/*
* setups mutliple pins
* convenient way to call the above function with tables
*/
-int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
+int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
const char *label);
/*
@@ -60,12 +60,12 @@ int mxc_iomux_setup_multiple_pins(unsigned int *pin_list, unsigned count,
* - frees the GPIO if the pin was configured as GPIO
* - DOES NOT reconfigure the IOMUX in its reset state
*/
-void mxc_iomux_release_pin(const unsigned int pin_mode);
+void mxc_iomux_release_pin(unsigned int pin_mode);
/*
* releases multiple pins
* convenvient way to call the above function with tables
*/
-void mxc_iomux_release_multiple_pins(unsigned int *pin_list, int count);
+void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count);
#define MUX_SIDE_AP (0)
#define MUX_SIDE_SP (1)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v1.h b/arch/arm/plat-mxc/include/mach/iomux-v1.h
index 884f5753f279..c07d30210c57 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-v1.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-v1.h
@@ -100,4 +100,6 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
const char *label);
extern void mxc_gpio_release_multiple_pins(const int *pin_list, int count);
+extern int __init imx_iomuxv1_init(void __iomem *base, int numports);
+
#endif /* __MACH_IOMUX_V1_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h
index ba65c9231a78..a3d930d3e65d 100644
--- a/arch/arm/plat-mxc/include/mach/irqs.h
+++ b/arch/arm/plat-mxc/include/mach/irqs.h
@@ -23,17 +23,17 @@
#define MXC_GPIO_IRQ_START MXC_INTERNAL_IRQS
/* these are ordered by size to support multi-SoC kernels */
-#if defined CONFIG_ARCH_MX53
+#if defined CONFIG_SOC_IMX53
#define MXC_GPIO_IRQS (32 * 7)
#elif defined CONFIG_ARCH_MX2
#define MXC_GPIO_IRQS (32 * 6)
-#elif defined CONFIG_ARCH_MX50
+#elif defined CONFIG_SOC_IMX50
#define MXC_GPIO_IRQS (32 * 6)
#elif defined CONFIG_ARCH_MX1
#define MXC_GPIO_IRQS (32 * 4)
#elif defined CONFIG_ARCH_MX25
#define MXC_GPIO_IRQS (32 * 4)
-#elif defined CONFIG_ARCH_MX51
+#elif defined CONFIG_SOC_IMX51
#define MXC_GPIO_IRQS (32 * 4)
#elif defined CONFIG_ARCH_MXC91231
#define MXC_GPIO_IRQS (32 * 4)
diff --git a/arch/arm/plat-mxc/include/mach/mx1.h b/arch/arm/plat-mxc/include/mach/mx1.h
index 75d96214b831..97b19e7800bc 100644
--- a/arch/arm/plat-mxc/include/mach/mx1.h
+++ b/arch/arm/plat-mxc/include/mach/mx1.h
@@ -54,13 +54,13 @@
#define MX1_AIPI2_BASE_ADDR (0x10000 + MX1_IO_BASE_ADDR)
#define MX1_SIM_BASE_ADDR (0x11000 + MX1_IO_BASE_ADDR)
#define MX1_USBD_BASE_ADDR (0x12000 + MX1_IO_BASE_ADDR)
-#define MX1_SPI1_BASE_ADDR (0x13000 + MX1_IO_BASE_ADDR)
+#define MX1_CSPI1_BASE_ADDR (0x13000 + MX1_IO_BASE_ADDR)
#define MX1_MMC_BASE_ADDR (0x14000 + MX1_IO_BASE_ADDR)
#define MX1_ASP_BASE_ADDR (0x15000 + MX1_IO_BASE_ADDR)
#define MX1_BTA_BASE_ADDR (0x16000 + MX1_IO_BASE_ADDR)
#define MX1_I2C_BASE_ADDR (0x17000 + MX1_IO_BASE_ADDR)
#define MX1_SSI_BASE_ADDR (0x18000 + MX1_IO_BASE_ADDR)
-#define MX1_SPI2_BASE_ADDR (0x19000 + MX1_IO_BASE_ADDR)
+#define MX1_CSPI2_BASE_ADDR (0x19000 + MX1_IO_BASE_ADDR)
#define MX1_MSHC_BASE_ADDR (0x1A000 + MX1_IO_BASE_ADDR)
#define MX1_CCM_BASE_ADDR (0x1B000 + MX1_IO_BASE_ADDR)
#define MX1_SCM_BASE_ADDR (0x1B804 + MX1_IO_BASE_ADDR)
@@ -89,7 +89,7 @@
#define MX1_GPIO_INT_PORTA 11
#define MX1_GPIO_INT_PORTB 12
#define MX1_GPIO_INT_PORTC 13
-#define MX1_LCDC_INT 14
+#define MX1_INT_LCDC 14
#define MX1_SIM_INT 15
#define MX1_SIM_DATA_INT 16
#define MX1_RTC_INT 17
@@ -112,7 +112,8 @@
#define MX1_PWM_INT 34
#define MX1_SDHC_INT 35
#define MX1_INT_I2C 39
-#define MX1_CSPI_INT 41
+#define MX1_INT_CSPI2 40
+#define MX1_INT_CSPI1 41
#define MX1_SSI_TX_INT 42
#define MX1_SSI_TX_ERR_INT 43
#define MX1_SSI_RX_INT 44
diff --git a/arch/arm/plat-mxc/include/mach/mx53.h b/arch/arm/plat-mxc/include/mach/mx53.h
index d7a8e52181ea..ace17864575e 100644
--- a/arch/arm/plat-mxc/include/mach/mx53.h
+++ b/arch/arm/plat-mxc/include/mach/mx53.h
@@ -79,7 +79,7 @@
#define MX53_GPIO3_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x0008C000)
#define MX53_GPIO4_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x00090000)
#define MX53_KPP_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x00094000)
-#define MX53_WDOG_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x00098000)
+#define MX53_WDOG1_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x00098000)
#define MX53_WDOG2_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x0009C000)
#define MX53_GPT1_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000A0000)
#define MX53_SRTC_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000A4000)
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 04c7a26b1f26..7e072637eefa 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -103,7 +103,7 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx27() (0)
#endif
-#ifdef CONFIG_ARCH_MX31
+#ifdef CONFIG_SOC_IMX31
# ifdef mxc_cpu_type
# undef mxc_cpu_type
# define mxc_cpu_type __mxc_cpu_type
@@ -115,7 +115,7 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx31() (0)
#endif
-#ifdef CONFIG_ARCH_MX35
+#ifdef CONFIG_SOC_IMX35
# ifdef mxc_cpu_type
# undef mxc_cpu_type
# define mxc_cpu_type __mxc_cpu_type
@@ -127,7 +127,7 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx35() (0)
#endif
-#ifdef CONFIG_ARCH_MX50
+#ifdef CONFIG_SOC_IMX50
# ifdef mxc_cpu_type
# undef mxc_cpu_type
# define mxc_cpu_type __mxc_cpu_type
@@ -139,7 +139,7 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx50() (0)
#endif
-#ifdef CONFIG_ARCH_MX51
+#ifdef CONFIG_SOC_IMX51
# ifdef mxc_cpu_type
# undef mxc_cpu_type
# define mxc_cpu_type __mxc_cpu_type
@@ -151,7 +151,7 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx51() (0)
#endif
-#ifdef CONFIG_ARCH_MX53
+#ifdef CONFIG_SOC_IMX53
# ifdef mxc_cpu_type
# undef mxc_cpu_type
# define mxc_cpu_type __mxc_cpu_type
diff --git a/arch/arm/plat-mxc/include/mach/mxc_ehci.h b/arch/arm/plat-mxc/include/mach/mxc_ehci.h
index a523a4079299..2c159dc2398b 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_ehci.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_ehci.h
@@ -44,11 +44,14 @@ struct mxc_usbh_platform_data {
int (*exit)(struct platform_device *pdev);
unsigned int portsc;
- unsigned int flags;
struct otg_transceiver *otg;
};
-int mxc_initialize_usb_hw(int port, unsigned int flags);
+int mx51_initialize_usb_hw(int port, unsigned int flags);
+int mx25_initialize_usb_hw(int port, unsigned int flags);
+int mx31_initialize_usb_hw(int port, unsigned int flags);
+int mx35_initialize_usb_hw(int port, unsigned int flags);
+int mx27_initialize_usb_hw(int port, unsigned int flags);
#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
diff --git a/arch/arm/plat-mxc/include/mach/ulpi.h b/arch/arm/plat-mxc/include/mach/ulpi.h
index 96b6ab4c40c3..f9161c96d7bd 100644
--- a/arch/arm/plat-mxc/include/mach/ulpi.h
+++ b/arch/arm/plat-mxc/include/mach/ulpi.h
@@ -1,6 +1,15 @@
#ifndef __MACH_ULPI_H
#define __MACH_ULPI_H
+#ifdef CONFIG_USB_ULPI
+struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags);
+#else
+static inline struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+{
+ return NULL;
+}
+#endif
+
extern struct otg_io_access_ops mxc_ulpi_access_ops;
#endif /* __MACH_ULPI_H */
diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h
index ff469c4f1d76..4864b0afd440 100644
--- a/arch/arm/plat-mxc/include/mach/uncompress.h
+++ b/arch/arm/plat-mxc/include/mach/uncompress.h
@@ -62,6 +62,7 @@ static inline void flush(void)
#define MX2X_UART1_BASE_ADDR 0x1000a000
#define MX3X_UART1_BASE_ADDR 0x43F90000
#define MX3X_UART2_BASE_ADDR 0x43F94000
+#define MX3X_UART5_BASE_ADDR 0x43FB4000
#define MX51_UART1_BASE_ADDR 0x73fbc000
#define MX50_UART1_BASE_ADDR 0x53fbc000
#define MX53_UART1_BASE_ADDR 0x53fbc000
@@ -83,6 +84,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
case MACH_TYPE_MX21ADS:
case MACH_TYPE_PCA100:
case MACH_TYPE_MXT_TD60:
+ case MACH_TYPE_IMX27IPCAM:
uart_base = MX2X_UART1_BASE_ADDR;
break;
case MACH_TYPE_MX31LITE:
@@ -101,6 +103,9 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
case MACH_TYPE_MAGX_ZN5:
uart_base = MX3X_UART2_BASE_ADDR;
break;
+ case MACH_TYPE_BUG:
+ uart_base = MX3X_UART5_BASE_ADDR;
+ break;
case MACH_TYPE_MX51_BABBAGE:
case MACH_TYPE_EUKREA_CPUIMX51SD:
case MACH_TYPE_MX51_3DS:
@@ -110,6 +115,8 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
uart_base = MX50_UART1_BASE_ADDR;
break;
case MACH_TYPE_MX53_EVK:
+ case MACH_TYPE_MX53_LOCO:
+ case MACH_TYPE_MX53_SMD:
uart_base = MX53_UART1_BASE_ADDR;
break;
default:
diff --git a/arch/arm/plat-mxc/iomux-v1.c b/arch/arm/plat-mxc/iomux-v1.c
index 960a02cbcbaf..3238c10d4e02 100644
--- a/arch/arm/plat-mxc/iomux-v1.c
+++ b/arch/arm/plat-mxc/iomux-v1.c
@@ -211,28 +211,10 @@ void mxc_gpio_release_multiple_pins(const int *pin_list, int count)
}
EXPORT_SYMBOL(mxc_gpio_release_multiple_pins);
-static int imx_iomuxv1_init(void)
+int __init imx_iomuxv1_init(void __iomem *base, int numports)
{
-#ifdef CONFIG_ARCH_MX1
- if (cpu_is_mx1()) {
- imx_iomuxv1_baseaddr = MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR);
- imx_iomuxv1_numports = MX1_NUM_GPIO_PORT;
- } else
-#endif
-#ifdef CONFIG_MACH_MX21
- if (cpu_is_mx21()) {
- imx_iomuxv1_baseaddr = MX21_IO_ADDRESS(MX21_GPIO_BASE_ADDR);
- imx_iomuxv1_numports = MX21_NUM_GPIO_PORT;
- } else
-#endif
-#ifdef CONFIG_MACH_MX27
- if (cpu_is_mx27()) {
- imx_iomuxv1_baseaddr = MX27_IO_ADDRESS(MX27_GPIO_BASE_ADDR);
- imx_iomuxv1_numports = MX27_NUM_GPIO_PORT;
- } else
-#endif
- return -ENODEV;
+ imx_iomuxv1_baseaddr = base;
+ imx_iomuxv1_numports = numports;
return 0;
}
-pure_initcall(imx_iomuxv1_init);
diff --git a/arch/arm/plat-mxc/ulpi.c b/arch/arm/plat-mxc/ulpi.c
index 582c6dfaba4a..477e45bea1be 100644
--- a/arch/arm/plat-mxc/ulpi.c
+++ b/arch/arm/plat-mxc/ulpi.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
#include <mach/ulpi.h>
@@ -111,3 +112,7 @@ struct otg_io_access_ops mxc_ulpi_access_ops = {
};
EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops);
+struct otg_transceiver *imx_otg_ulpi_create(unsigned int flags)
+{
+ return otg_ulpi_create(&mxc_ulpi_access_ops, flags);
+}
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c
index 1e88ecb846d1..70620426ee55 100644
--- a/arch/arm/plat-nomadik/gpio.c
+++ b/arch/arm/plat-nomadik/gpio.c
@@ -30,23 +30,39 @@
/*
* The GPIO module in the Nomadik family of Systems-on-Chip is an
* AMBA device, managing 32 pins and alternate functions. The logic block
- * is currently only used in the Nomadik.
+ * is currently used in the Nomadik and ux500.
*
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
-#define NMK_GPIO_PER_CHIP 32
+#define NMK_GPIO_PER_CHIP 32
+
struct nmk_gpio_chip {
struct gpio_chip chip;
void __iomem *addr;
struct clk *clk;
+ unsigned int bank;
unsigned int parent_irq;
+ int secondary_parent_irq;
+ u32 (*get_secondary_status)(unsigned int bank);
+ void (*set_ioforce)(bool enable);
spinlock_t lock;
/* Keep track of configured edges */
u32 edge_rising;
u32 edge_falling;
+ u32 real_wake;
+ u32 rwimsc;
+ u32 fwimsc;
+ u32 slpm;
};
+static struct nmk_gpio_chip *
+nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)];
+
+static DEFINE_SPINLOCK(nmk_gpio_slpm_lock);
+
+#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips)
+
static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
unsigned offset, int gpio_mode)
{
@@ -118,8 +134,35 @@ static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
__nmk_gpio_set_output(nmk_chip, offset, val);
}
+static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, int gpio_mode,
+ bool glitch)
+{
+ u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
+ u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
+
+ if (glitch && nmk_chip->set_ioforce) {
+ u32 bit = BIT(offset);
+
+ /* Prevent spurious wakeups */
+ writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC);
+ writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC);
+
+ nmk_chip->set_ioforce(true);
+ }
+
+ __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode);
+
+ if (glitch && nmk_chip->set_ioforce) {
+ nmk_chip->set_ioforce(false);
+
+ writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC);
+ writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC);
+ }
+}
+
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
- pin_cfg_t cfg, bool sleep)
+ pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
{
static const char *afnames[] = {
[NMK_GPIO_ALT_GPIO] = "GPIO",
@@ -144,6 +187,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
int slpm = PIN_SLPM(cfg);
int output = PIN_DIR(cfg);
int val = PIN_VAL(cfg);
+ bool glitch = af == NMK_GPIO_ALT_C;
dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
@@ -155,6 +199,8 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
int slpm_output = PIN_SLPM_DIR(cfg);
int slpm_val = PIN_SLPM_VAL(cfg);
+ af = NMK_GPIO_ALT_GPIO;
+
/*
* The SLPM_* values are normal values + 1 to allow zero to
* mean "same as normal".
@@ -180,8 +226,116 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
__nmk_gpio_set_pull(nmk_chip, offset, pull);
}
- __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
- __nmk_gpio_set_mode(nmk_chip, offset, af);
+ /*
+ * If we've backed up the SLPM registers (glitch workaround), modify
+ * the backups since they will be restored.
+ */
+ if (slpmregs) {
+ if (slpm == NMK_GPIO_SLPM_NOCHANGE)
+ slpmregs[nmk_chip->bank] |= BIT(offset);
+ else
+ slpmregs[nmk_chip->bank] &= ~BIT(offset);
+ } else
+ __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
+
+ __nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
+}
+
+/*
+ * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
+ * - Save SLPM registers
+ * - Set SLPM=0 for the IOs you want to switch and others to 1
+ * - Configure the GPIO registers for the IOs that are being switched
+ * - Set IOFORCE=1
+ * - Modify the AFLSA/B registers for the IOs that are being switched
+ * - Set IOFORCE=0
+ * - Restore SLPM registers
+ * - Any spurious wake up event during switch sequence to be ignored and
+ * cleared
+ */
+static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
+{
+ int i;
+
+ for (i = 0; i < NUM_BANKS; i++) {
+ struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+ unsigned int temp = slpm[i];
+
+ if (!chip)
+ break;
+
+ slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
+ writel(temp, chip->addr + NMK_GPIO_SLPC);
+ }
+}
+
+static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
+{
+ int i;
+
+ for (i = 0; i < NUM_BANKS; i++) {
+ struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+ if (!chip)
+ break;
+
+ writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
+ }
+}
+
+static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
+{
+ static unsigned int slpm[NUM_BANKS];
+ unsigned long flags;
+ bool glitch = false;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
+ glitch = true;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+
+ if (glitch) {
+ memset(slpm, 0xff, sizeof(slpm));
+
+ for (i = 0; i < num; i++) {
+ int pin = PIN_NUM(cfgs[i]);
+ int offset = pin % NMK_GPIO_PER_CHIP;
+
+ if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
+ slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
+ }
+
+ nmk_gpio_glitch_slpm_init(slpm);
+ }
+
+ for (i = 0; i < num; i++) {
+ struct nmk_gpio_chip *nmk_chip;
+ int pin = PIN_NUM(cfgs[i]);
+
+ nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(pin));
+ if (!nmk_chip) {
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_lock(&nmk_chip->lock);
+ __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
+ cfgs[i], sleep, glitch ? slpm : NULL);
+ spin_unlock(&nmk_chip->lock);
+ }
+
+ if (glitch)
+ nmk_gpio_glitch_slpm_restore(slpm);
+
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+
+ return ret;
}
/**
@@ -200,19 +354,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
*/
int nmk_config_pin(pin_cfg_t cfg, bool sleep)
{
- struct nmk_gpio_chip *nmk_chip;
- int gpio = PIN_NUM(cfg);
- unsigned long flags;
-
- nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
- if (!nmk_chip)
- return -EINVAL;
-
- spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep);
- spin_unlock_irqrestore(&nmk_chip->lock, flags);
-
- return 0;
+ return __nmk_config_pins(&cfg, 1, sleep);
}
EXPORT_SYMBOL(nmk_config_pin);
@@ -226,31 +368,13 @@ EXPORT_SYMBOL(nmk_config_pin);
*/
int nmk_config_pins(pin_cfg_t *cfgs, int num)
{
- int ret = 0;
- int i;
-
- for (i = 0; i < num; i++) {
- ret = nmk_config_pin(cfgs[i], false);
- if (ret)
- break;
- }
-
- return ret;
+ return __nmk_config_pins(cfgs, num, false);
}
EXPORT_SYMBOL(nmk_config_pins);
int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
{
- int ret = 0;
- int i;
-
- for (i = 0; i < num; i++) {
- ret = nmk_config_pin(cfgs[i], true);
- if (ret)
- break;
- }
-
- return ret;
+ return __nmk_config_pins(cfgs, num, true);
}
EXPORT_SYMBOL(nmk_config_pins_sleep);
@@ -277,9 +401,13 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
if (!nmk_chip)
return -EINVAL;
- spin_lock_irqsave(&nmk_chip->lock, flags);
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+ spin_lock(&nmk_chip->lock);
+
__nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
- spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+ spin_unlock(&nmk_chip->lock);
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
return 0;
}
@@ -314,6 +442,15 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
}
/* Mode functions */
+/**
+ * nmk_gpio_set_mode() - set the mux mode of a gpio pin
+ * @gpio: pin number
+ * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
+ * NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
+ *
+ * Sets the mode of the specified pin to one of the alternate functions or
+ * plain GPIO.
+ */
int nmk_gpio_set_mode(int gpio, int gpio_mode)
{
struct nmk_gpio_chip *nmk_chip;
@@ -401,8 +538,20 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
}
}
-static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which,
- bool enable)
+static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
+ int gpio, bool on)
+{
+#ifdef CONFIG_ARCH_U8500
+ if (cpu_is_u8500v2()) {
+ __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
+ on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+ : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+ }
+#endif
+ __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+}
+
+static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
{
int gpio;
struct nmk_gpio_chip *nmk_chip;
@@ -415,44 +564,58 @@ static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which,
if (!nmk_chip)
return -EINVAL;
- spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_irq_modify(nmk_chip, gpio, which, enable);
- spin_unlock_irqrestore(&nmk_chip->lock, flags);
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+ spin_lock(&nmk_chip->lock);
+
+ __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
+
+ if (!(nmk_chip->real_wake & bitmask))
+ __nmk_gpio_set_wake(nmk_chip, gpio, enable);
+
+ spin_unlock(&nmk_chip->lock);
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
return 0;
}
static void nmk_gpio_irq_mask(struct irq_data *d)
{
- nmk_gpio_irq_modify(d, NORMAL, false);
+ nmk_gpio_irq_maskunmask(d, false);
}
static void nmk_gpio_irq_unmask(struct irq_data *d)
{
- nmk_gpio_irq_modify(d, NORMAL, true);
+ nmk_gpio_irq_maskunmask(d, true);
}
static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
+ struct irq_desc *desc = irq_to_desc(d->irq);
+ bool enabled = !(desc->status & IRQ_DISABLED);
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
+ u32 bitmask;
int gpio;
gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return -EINVAL;
+ bitmask = nmk_gpio_get_bitmask(gpio);
- spin_lock_irqsave(&nmk_chip->lock, flags);
-#ifdef CONFIG_ARCH_U8500
- if (cpu_is_u8500v2()) {
- __nmk_gpio_set_slpm(nmk_chip, gpio,
- on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
- : NMK_GPIO_SLPM_WAKEUP_DISABLE);
- }
-#endif
- __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
- spin_unlock_irqrestore(&nmk_chip->lock, flags);
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+ spin_lock(&nmk_chip->lock);
+
+ if (!enabled)
+ __nmk_gpio_set_wake(nmk_chip, gpio, on);
+
+ if (on)
+ nmk_chip->real_wake |= bitmask;
+ else
+ nmk_chip->real_wake &= ~bitmask;
+
+ spin_unlock(&nmk_chip->lock);
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
return 0;
}
@@ -483,7 +646,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (enabled)
__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
- if (wake)
+ if (enabled || wake)
__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
nmk_chip->edge_rising &= ~bitmask;
@@ -497,7 +660,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (enabled)
__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
- if (wake)
+ if (enabled || wake)
__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
@@ -514,12 +677,11 @@ static struct irq_chip nmk_gpio_irq_chip = {
.irq_set_wake = nmk_gpio_irq_set_wake,
};
-static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
+ u32 status)
{
struct nmk_gpio_chip *nmk_chip;
struct irq_chip *host_chip = get_irq_chip(irq);
- unsigned int gpio_irq;
- u32 pending;
unsigned int first_irq;
if (host_chip->irq_mask_ack)
@@ -532,29 +694,56 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
nmk_chip = get_irq_data(irq);
first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
- while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) {
- gpio_irq = first_irq + __ffs(pending);
- generic_handle_irq(gpio_irq);
+ while (status) {
+ int bit = __ffs(status);
+
+ generic_handle_irq(first_irq + bit);
+ status &= ~BIT(bit);
}
host_chip->irq_unmask(&desc->irq_data);
}
+static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct nmk_gpio_chip *nmk_chip = get_irq_data(irq);
+ u32 status = readl(nmk_chip->addr + NMK_GPIO_IS);
+
+ __nmk_gpio_irq_handler(irq, desc, status);
+}
+
+static void nmk_gpio_secondary_irq_handler(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct nmk_gpio_chip *nmk_chip = get_irq_data(irq);
+ u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
+
+ __nmk_gpio_irq_handler(irq, desc, status);
+}
+
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
{
unsigned int first_irq;
int i;
first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
- for (i = first_irq; i < first_irq + NMK_GPIO_PER_CHIP; i++) {
+ for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
set_irq_chip(i, &nmk_gpio_irq_chip);
set_irq_handler(i, handle_edge_irq);
set_irq_flags(i, IRQF_VALID);
set_irq_chip_data(i, nmk_chip);
set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
}
+
set_irq_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
set_irq_data(nmk_chip->parent_irq, nmk_chip);
+
+ if (nmk_chip->secondary_parent_irq >= 0) {
+ set_irq_chained_handler(nmk_chip->secondary_parent_irq,
+ nmk_gpio_secondary_irq_handler);
+ set_irq_data(nmk_chip->secondary_parent_irq, nmk_chip);
+ }
+
return 0;
}
@@ -605,6 +794,97 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
}
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ int mode;
+ unsigned i;
+ unsigned gpio = chip->base;
+ int is_out;
+ struct nmk_gpio_chip *nmk_chip =
+ container_of(chip, struct nmk_gpio_chip, chip);
+ const char *modes[] = {
+ [NMK_GPIO_ALT_GPIO] = "gpio",
+ [NMK_GPIO_ALT_A] = "altA",
+ [NMK_GPIO_ALT_B] = "altB",
+ [NMK_GPIO_ALT_C] = "altC",
+ };
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ const char *label = gpiochip_is_requested(chip, i);
+ bool pull;
+ u32 bit = 1 << i;
+
+ if (!label)
+ continue;
+
+ is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
+ pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
+ mode = nmk_gpio_get_mode(gpio);
+ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
+ gpio, label,
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, i) ? "hi" : "lo")
+ : "? ",
+ (mode < 0) ? "unknown" : modes[mode],
+ pull ? "pull" : "none");
+
+ if (!is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ *
+ * More significantly, trigger type flags aren't
+ * currently maintained by genirq.
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+
+ switch (desc->status & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ trigger = "(default)";
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "edge-falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "edge-rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "edge-both";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "level-high";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "level-low";
+ break;
+ default:
+ trigger = "?trigger?";
+ break;
+ }
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ (desc->status & IRQ_WAKEUP)
+ ? " wakeup" : "");
+ }
+ }
+
+ seq_printf(s, "\n");
+ }
+}
+
+#else
+#define nmk_gpio_dbg_show NULL
+#endif
+
/* This structure is replicated for each GPIO block allocated at probe time */
static struct gpio_chip nmk_gpio_template = {
.direction_input = nmk_gpio_make_input,
@@ -612,10 +892,64 @@ static struct gpio_chip nmk_gpio_template = {
.direction_output = nmk_gpio_make_output,
.set = nmk_gpio_set_output,
.to_irq = nmk_gpio_to_irq,
- .ngpio = NMK_GPIO_PER_CHIP,
+ .dbg_show = nmk_gpio_dbg_show,
.can_sleep = 0,
};
+/*
+ * Called from the suspend/resume path to only keep the real wakeup interrupts
+ * (those that have had set_irq_wake() called on them) as wakeup interrupts,
+ * and not the rest of the interrupts which we needed to have as wakeups for
+ * cpuidle.
+ *
+ * PM ops are not used since this needs to be done at the end, after all the
+ * other drivers are done with their suspend callbacks.
+ */
+void nmk_gpio_wakeups_suspend(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_BANKS; i++) {
+ struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+ if (!chip)
+ break;
+
+ chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
+ chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
+
+ writel(chip->rwimsc & chip->real_wake,
+ chip->addr + NMK_GPIO_RWIMSC);
+ writel(chip->fwimsc & chip->real_wake,
+ chip->addr + NMK_GPIO_FWIMSC);
+
+ if (cpu_is_u8500v2()) {
+ chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
+
+ /* 0 -> wakeup enable */
+ writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
+ }
+ }
+}
+
+void nmk_gpio_wakeups_resume(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_BANKS; i++) {
+ struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+ if (!chip)
+ break;
+
+ writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
+ writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
+
+ if (cpu_is_u8500v2())
+ writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
+ }
+}
+
static int __devinit nmk_gpio_probe(struct platform_device *dev)
{
struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
@@ -623,6 +957,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
struct gpio_chip *chip;
struct resource *res;
struct clk *clk;
+ int secondary_irq;
int irq;
int ret;
@@ -641,6 +976,12 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
goto out;
}
+ secondary_irq = platform_get_irq(dev, 1);
+ if (secondary_irq >= 0 && !pdata->get_secondary_status) {
+ ret = -EINVAL;
+ goto out;
+ }
+
if (request_mem_region(res->start, resource_size(res),
dev_name(&dev->dev)) == NULL) {
ret = -EBUSY;
@@ -664,14 +1005,19 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
* The virt address in nmk_chip->addr is in the nomadik register space,
* so we can simply convert the resource address, without remapping
*/
+ nmk_chip->bank = dev->id;
nmk_chip->clk = clk;
nmk_chip->addr = io_p2v(res->start);
nmk_chip->chip = nmk_gpio_template;
nmk_chip->parent_irq = irq;
+ nmk_chip->secondary_parent_irq = secondary_irq;
+ nmk_chip->get_secondary_status = pdata->get_secondary_status;
+ nmk_chip->set_ioforce = pdata->set_ioforce;
spin_lock_init(&nmk_chip->lock);
chip = &nmk_chip->chip;
chip->base = pdata->first_gpio;
+ chip->ngpio = pdata->num_gpio;
chip->label = pdata->name ?: dev_name(&dev->dev);
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
@@ -680,6 +1026,9 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
if (ret)
goto out_free;
+ BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
+
+ nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
platform_set_drvdata(dev, nmk_chip);
nmk_gpio_init_irq(nmk_chip);
@@ -705,10 +1054,8 @@ static struct platform_driver nmk_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gpio",
- },
+ },
.probe = nmk_gpio_probe,
- .suspend = NULL, /* to be done */
- .resume = NULL,
};
static int __init nmk_gpio_init(void)
diff --git a/arch/arm/plat-nomadik/include/plat/gpio.h b/arch/arm/plat-nomadik/include/plat/gpio.h
index 67b113d639d8..1b9f6f0843d1 100644
--- a/arch/arm/plat-nomadik/include/plat/gpio.h
+++ b/arch/arm/plat-nomadik/include/plat/gpio.h
@@ -75,6 +75,9 @@ extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
extern int nmk_gpio_get_mode(int gpio);
+extern void nmk_gpio_wakeups_suspend(void);
+extern void nmk_gpio_wakeups_resume(void);
+
/*
* Platform data to register a block: only the initial gpio/irq number.
*/
@@ -82,6 +85,9 @@ struct nmk_gpio_platform_data {
char *name;
int first_gpio;
int first_irq;
+ int num_gpio;
+ u32 (*get_secondary_status)(unsigned int bank);
+ void (*set_ioforce)(bool enable);
};
#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index b6333ae3f92a..cd5f993612fd 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -54,7 +54,7 @@ config OMAP_SMARTREFLEX
user must write 1 to
/debug/voltage/vdd_<X>/smartreflex/autocomp,
where X is mpu or core for OMAP3.
- Optionallly autocompensation can be enabled in the kernel
+ Optionally autocompensation can be enabled in the kernel
by default during system init via the enable_on_init flag
which an be passed as platform data to the smartreflex driver.
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index fc62fb5fc20b..c9122dd6ee8d 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -37,14 +37,16 @@ static struct clk_functions *arch_clock;
int clk_enable(struct clk *clk)
{
unsigned long flags;
- int ret = 0;
+ int ret;
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
+ if (!arch_clock || !arch_clock->clk_enable)
+ return -EINVAL;
+
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_enable)
- ret = arch_clock->clk_enable(clk);
+ ret = arch_clock->clk_enable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
@@ -58,6 +60,9 @@ void clk_disable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return;
+ if (!arch_clock || !arch_clock->clk_disable)
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (clk->usecount == 0) {
pr_err("Trying disable clock %s with 0 usecount\n",
@@ -66,8 +71,7 @@ void clk_disable(struct clk *clk)
goto out;
}
- if (arch_clock->clk_disable)
- arch_clock->clk_disable(clk);
+ arch_clock->clk_disable(clk);
out:
spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -77,7 +81,7 @@ EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long flags;
- unsigned long ret = 0;
+ unsigned long ret;
if (clk == NULL || IS_ERR(clk))
return 0;
@@ -97,14 +101,16 @@ EXPORT_SYMBOL(clk_get_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
- long ret = 0;
+ long ret;
if (clk == NULL || IS_ERR(clk))
- return ret;
+ return 0;
+
+ if (!arch_clock || !arch_clock->clk_round_rate)
+ return 0;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_round_rate)
- ret = arch_clock->clk_round_rate(clk, rate);
+ ret = arch_clock->clk_round_rate(clk, rate);
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
@@ -119,14 +125,13 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
if (clk == NULL || IS_ERR(clk))
return ret;
+ if (!arch_clock || !arch_clock->clk_set_rate)
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_set_rate)
- ret = arch_clock->clk_set_rate(clk, rate);
- if (ret == 0) {
- if (clk->recalc)
- clk->rate = clk->recalc(clk);
+ ret = arch_clock->clk_set_rate(clk, rate);
+ if (ret == 0)
propagate_rate(clk);
- }
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
@@ -141,15 +146,14 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
return ret;
+ if (!arch_clock || !arch_clock->clk_set_parent)
+ return ret;
+
spin_lock_irqsave(&clockfw_lock, flags);
if (clk->usecount == 0) {
- if (arch_clock->clk_set_parent)
- ret = arch_clock->clk_set_parent(clk, parent);
- if (ret == 0) {
- if (clk->recalc)
- clk->rate = clk->recalc(clk);
+ ret = arch_clock->clk_set_parent(clk, parent);
+ if (ret == 0)
propagate_rate(clk);
- }
} else
ret = -EBUSY;
spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -335,6 +339,38 @@ struct clk *omap_clk_get_by_name(const char *name)
return ret;
}
+int omap_clk_enable_autoidle_all(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->allow_idle)
+ c->ops->allow_idle(c);
+
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return 0;
+}
+
+int omap_clk_disable_autoidle_all(void)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ list_for_each_entry(c, &clocks, node)
+ if (c->ops->deny_idle)
+ c->ops->deny_idle(c);
+
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return 0;
+}
+
/*
* Low level helpers
*/
@@ -367,9 +403,11 @@ void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
{
unsigned long flags;
+ if (!arch_clock || !arch_clock->clk_init_cpufreq_table)
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_init_cpufreq_table)
- arch_clock->clk_init_cpufreq_table(table);
+ arch_clock->clk_init_cpufreq_table(table);
spin_unlock_irqrestore(&clockfw_lock, flags);
}
@@ -377,9 +415,11 @@ void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
{
unsigned long flags;
+ if (!arch_clock || !arch_clock->clk_exit_cpufreq_table)
+ return;
+
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_exit_cpufreq_table)
- arch_clock->clk_exit_cpufreq_table(table);
+ arch_clock->clk_exit_cpufreq_table(table);
spin_unlock_irqrestore(&clockfw_lock, flags);
}
#endif
@@ -397,6 +437,9 @@ static int __init clk_disable_unused(void)
struct clk *ck;
unsigned long flags;
+ if (!arch_clock || !arch_clock->clk_disable_unused)
+ return 0;
+
pr_info("clock: disabling unused clocks to save power\n");
list_for_each_entry(ck, &clocks, node) {
if (ck->ops == &clkops_null)
@@ -406,14 +449,14 @@ static int __init clk_disable_unused(void)
continue;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_disable_unused)
- arch_clock->clk_disable_unused(ck);
+ arch_clock->clk_disable_unused(ck);
spin_unlock_irqrestore(&clockfw_lock, flags);
}
return 0;
}
late_initcall(clk_disable_unused);
+late_initcall(omap_clk_enable_autoidle_all);
#endif
int __init clk_init(struct clk_functions * custom_clocks)
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index f04731820301..d9f10a31e604 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -24,10 +24,11 @@
#define NO_LENGTH_CHECK 0xffffffff
-struct omap_board_config_kernel *omap_board_config;
+struct omap_board_config_kernel *omap_board_config __initdata;
int omap_board_config_size;
-static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
+static const void *__init get_config(u16 tag, size_t len,
+ int skip, size_t *len_out)
{
struct omap_board_config_kernel *kinfo = NULL;
int i;
@@ -49,17 +50,15 @@ static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
return kinfo->data;
}
-const void *__omap_get_config(u16 tag, size_t len, int nr)
+const void *__init __omap_get_config(u16 tag, size_t len, int nr)
{
return get_config(tag, len, nr, NULL);
}
-EXPORT_SYMBOL(__omap_get_config);
-const void *omap_get_var_config(u16 tag, size_t *len)
+const void *__init omap_get_var_config(u16 tag, size_t *len)
{
return get_config(tag, NO_LENGTH_CHECK, 0, len);
}
-EXPORT_SYMBOL(omap_get_var_config);
void __init omap_reserve(void)
{
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 862dda95d61d..f7fed6080190 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -54,7 +54,7 @@ static cycle_t notrace omap16xx_32k_read(struct clocksource *cs)
#define omap16xx_32k_read NULL
#endif
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
static cycle_t notrace omap2420_32k_read(struct clocksource *cs)
{
return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
@@ -63,7 +63,7 @@ static cycle_t notrace omap2420_32k_read(struct clocksource *cs)
#define omap2420_32k_read NULL
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
static cycle_t notrace omap2430_32k_read(struct clocksource *cs)
{
return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 11c54ec8d47f..da4f68dbba1d 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -101,7 +101,7 @@ static int omap_target(struct cpufreq_policy *policy,
return ret;
}
-static int __init omap_cpu_init(struct cpufreq_policy *policy)
+static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 10245b837c10..7d9f815cedec 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -35,8 +35,8 @@
static struct platform_device **omap_mcbsp_devices;
-void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
- int size)
+void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
+ struct omap_mcbsp_platform_data *config, int size)
{
int i;
@@ -54,6 +54,8 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
new_mcbsp = platform_device_alloc("omap-mcbsp", i + 1);
if (!new_mcbsp)
continue;
+ platform_device_add_resources(new_mcbsp, &res[i * res_count],
+ res_count);
new_mcbsp->dev.platform_data = &config[i];
ret = platform_device_add(new_mcbsp);
if (ret) {
@@ -65,8 +67,8 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
}
#else
-void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
- int size)
+void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
+ struct omap_mcbsp_platform_data *config, int size)
{ }
#endif
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 85363084cc1a..2ec3b5d9f214 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -134,7 +134,7 @@ static inline void omap_enable_channel_irq(int lch);
#ifdef CONFIG_ARCH_OMAP15XX
/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
-int omap_dma_in_1510_mode(void)
+static int omap_dma_in_1510_mode(void)
{
return enable_1510_mode;
}
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 1d706cf63ca0..ee9f6ebba29b 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -342,6 +342,10 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
l |= 0x02 << 3; /* Set to smart-idle mode */
l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */
+ /* Enable autoidle on OMAP2 / OMAP3 */
+ if (cpu_is_omap24xx() || cpu_is_omap34xx())
+ l |= 0x1 << 0;
+
/*
* Enable wake-up on OMAP2 CPUs.
*/
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index a4f8003de664..3341ca4703e9 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -112,6 +112,7 @@ static inline int omap1_i2c_add_bus(int bus_id)
}
+#ifdef CONFIG_ARCH_OMAP2PLUS
/*
* XXX This function is a temporary compatibility wrapper - only
* needed until the I2C driver can be converted to call
@@ -130,7 +131,6 @@ static struct omap_device_pm_latency omap_i2c_latency[] = {
},
};
-#ifdef CONFIG_ARCH_OMAP2PLUS
static inline int omap2_i2c_add_bus(int bus_id)
{
int l;
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index 3cf4fa25ab3d..97126dfd2888 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -151,14 +151,14 @@ struct omap_board_config_kernel {
const void *data;
};
-extern const void *__omap_get_config(u16 tag, size_t len, int nr);
+extern const void *__init __omap_get_config(u16 tag, size_t len, int nr);
#define omap_get_config(tag, type) \
((const type *) __omap_get_config((tag), sizeof(type), 0))
#define omap_get_nr_config(tag, type, nr) \
((const type *) __omap_get_config((tag), sizeof(type), (nr)))
-extern const void *omap_get_var_config(u16 tag, size_t *len);
+extern const void *__init omap_get_var_config(u16 tag, size_t *len);
extern struct omap_board_config_kernel *omap_board_config;
extern int omap_board_config_size;
diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h
index 256ab3f1ec8f..f1899a3e4174 100644
--- a/arch/arm/plat-omap/include/plat/clkdev_omap.h
+++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h
@@ -38,6 +38,7 @@ struct omap_clk {
#define CK_3517 (1 << 9)
#define CK_36XX (1 << 10) /* 36xx/37xx-specific clocks */
#define CK_443X (1 << 11)
+#define CK_TI816X (1 << 12)
#define CK_34XX (CK_3430ES1 | CK_3430ES2PLUS)
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 8eb0adab19ea..006e599c6613 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -25,6 +25,8 @@ struct clockdomain;
* @disable: fn ptr that enables the current clock in hardware
* @find_idlest: function returning the IDLEST register for the clock's IP blk
* @find_companion: function returning the "companion" clk reg for the clock
+ * @allow_idle: fn ptr that enables autoidle for the current clock in hardware
+ * @deny_idle: fn ptr that disables autoidle for the current clock in hardware
*
* A "companion" clk is an accompanying clock to the one being queried
* that must be enabled for the IP module connected to the clock to
@@ -42,6 +44,8 @@ struct clkops {
u8 *, u8 *);
void (*find_companion)(struct clk *, void __iomem **,
u8 *);
+ void (*allow_idle)(struct clk *);
+ void (*deny_idle)(struct clk *);
};
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -53,6 +57,7 @@ struct clkops {
#define RATE_IN_3430ES2PLUS (1 << 3) /* 3430 ES >= 2 rates only */
#define RATE_IN_36XX (1 << 4)
#define RATE_IN_4430 (1 << 5)
+#define RATE_IN_TI816X (1 << 6)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_34XX (RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS)
@@ -104,7 +109,6 @@ struct clksel {
* @clk_ref: struct clk pointer to the clock's reference clock input
* @control_reg: register containing the DPLL mode bitfield
* @enable_mask: mask of the DPLL mode bitfield in @control_reg
- * @rate_tolerance: maximum variance allowed from target rate (in Hz)
* @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
* @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
* @max_multiplier: maximum valid non-bypass multiplier value (actual)
@@ -130,12 +134,9 @@ struct clksel {
* XXX Some DPLLs have multiple bypass inputs, so it's not technically
* correct to only have one @clk_bypass pointer.
*
- * XXX @rate_tolerance should probably be deprecated - currently there
- * don't seem to be any usecases for DPLL rounding that is not exact.
- *
* XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m,
* @last_rounded_n) should be separated from the runtime-fixed fields
- * and placed into a differenct structure, so that the runtime-fixed data
+ * and placed into a different structure, so that the runtime-fixed data
* can be placed into read-only space.
*/
struct dpll_data {
@@ -146,7 +147,6 @@ struct dpll_data {
struct clk *clk_ref;
void __iomem *control_reg;
u32 enable_mask;
- unsigned int rate_tolerance;
unsigned long last_rounded_rate;
u16 last_rounded_m;
u16 max_multiplier;
@@ -171,12 +171,24 @@ struct dpll_data {
#endif
-/* struct clk.flags possibilities */
+/*
+ * struct clk.flags possibilities
+ *
+ * XXX document the rest of the clock flags here
+ *
+ * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL
+ * bits share the same register. This flag allows the
+ * omap4_dpllmx*() code to determine which GATE_CTRL bit field
+ * should be used. This is a temporary solution - a better approach
+ * would be to associate clock type-specific data with the clock,
+ * similar to the struct dpll_data approach.
+ */
#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */
#define CLOCK_IDLE_CONTROL (1 << 1)
#define CLOCK_NO_IDLE_PARENT (1 << 2)
#define ENABLE_ON_INIT (1 << 3) /* Enable upon framework init */
#define INVERT_ENABLE (1 << 4) /* 0 enables, 1 disables */
+#define CLOCK_CLKOUTX2 (1 << 5)
/**
* struct clk - OMAP struct clk
@@ -292,6 +304,8 @@ extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
#endif
extern struct clk *omap_clk_get_by_name(const char *name);
+extern int omap_clk_enable_autoidle_all(void);
+extern int omap_clk_disable_autoidle_all(void);
extern const struct clkops clkops_null;
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index 29b2afb4288f..5288130be96e 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -56,16 +56,13 @@ struct omap_globals {
unsigned long prm; /* Power and Reset Management */
unsigned long cm; /* Clock Management */
unsigned long cm2;
- unsigned long uart1_phys;
- unsigned long uart2_phys;
- unsigned long uart3_phys;
- unsigned long uart4_phys;
};
void omap2_set_globals_242x(void);
void omap2_set_globals_243x(void);
void omap2_set_globals_3xxx(void);
void omap2_set_globals_443x(void);
+void omap2_set_globals_ti816x(void);
/* These get called from omap2_set_globals_xxxx(), do not call these */
void omap2_set_globals_tap(struct omap_globals *);
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 3fd8b4055727..8198bb6cdb5e 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -5,7 +5,7 @@
*
* Copyright (C) 2004, 2008 Nokia Corporation
*
- * Copyright (C) 2009 Texas Instruments.
+ * Copyright (C) 2009-11 Texas Instruments.
*
* Written by Tony Lindgren <tony.lindgren@nokia.com>
*
@@ -105,6 +105,12 @@ static inline int is_omap ##subclass (void) \
return (GET_OMAP_SUBCLASS == (id)) ? 1 : 0; \
}
+#define IS_TI_SUBCLASS(subclass, id) \
+static inline int is_ti ##subclass (void) \
+{ \
+ return (GET_OMAP_SUBCLASS == (id)) ? 1 : 0; \
+}
+
IS_OMAP_CLASS(7xx, 0x07)
IS_OMAP_CLASS(15xx, 0x15)
IS_OMAP_CLASS(16xx, 0x16)
@@ -118,6 +124,8 @@ IS_OMAP_SUBCLASS(343x, 0x343)
IS_OMAP_SUBCLASS(363x, 0x363)
IS_OMAP_SUBCLASS(443x, 0x443)
+IS_TI_SUBCLASS(816x, 0x816)
+
#define cpu_is_omap7xx() 0
#define cpu_is_omap15xx() 0
#define cpu_is_omap16xx() 0
@@ -126,6 +134,7 @@ IS_OMAP_SUBCLASS(443x, 0x443)
#define cpu_is_omap243x() 0
#define cpu_is_omap34xx() 0
#define cpu_is_omap343x() 0
+#define cpu_is_ti816x() 0
#define cpu_is_omap44xx() 0
#define cpu_is_omap443x() 0
@@ -170,11 +179,11 @@ IS_OMAP_SUBCLASS(443x, 0x443)
# undef cpu_is_omap24xx
# define cpu_is_omap24xx() is_omap24xx()
# endif
-# if defined (CONFIG_ARCH_OMAP2420)
+# if defined (CONFIG_SOC_OMAP2420)
# undef cpu_is_omap242x
# define cpu_is_omap242x() is_omap242x()
# endif
-# if defined (CONFIG_ARCH_OMAP2430)
+# if defined (CONFIG_SOC_OMAP2430)
# undef cpu_is_omap243x
# define cpu_is_omap243x() is_omap243x()
# endif
@@ -189,11 +198,11 @@ IS_OMAP_SUBCLASS(443x, 0x443)
# undef cpu_is_omap24xx
# define cpu_is_omap24xx() 1
# endif
-# if defined(CONFIG_ARCH_OMAP2420)
+# if defined(CONFIG_SOC_OMAP2420)
# undef cpu_is_omap242x
# define cpu_is_omap242x() 1
# endif
-# if defined(CONFIG_ARCH_OMAP2430)
+# if defined(CONFIG_SOC_OMAP2430)
# undef cpu_is_omap243x
# define cpu_is_omap243x() 1
# endif
@@ -201,7 +210,7 @@ IS_OMAP_SUBCLASS(443x, 0x443)
# undef cpu_is_omap34xx
# define cpu_is_omap34xx() 1
# endif
-# if defined(CONFIG_ARCH_OMAP3430)
+# if defined(CONFIG_SOC_OMAP3430)
# undef cpu_is_omap343x
# define cpu_is_omap343x() 1
# endif
@@ -330,6 +339,7 @@ IS_OMAP_TYPE(3517, 0x3517)
# undef cpu_is_omap3530
# undef cpu_is_omap3505
# undef cpu_is_omap3517
+# undef cpu_is_ti816x
# define cpu_is_omap3430() is_omap3430()
# define cpu_is_omap3503() (cpu_is_omap3430() && \
(!omap3_has_iva()) && \
@@ -345,6 +355,7 @@ IS_OMAP_TYPE(3517, 0x3517)
# define cpu_is_omap3517() is_omap3517()
# undef cpu_is_omap3630
# define cpu_is_omap3630() is_omap363x()
+# define cpu_is_ti816x() is_ti816x()
#endif
# if defined(CONFIG_ARCH_OMAP4)
@@ -389,9 +400,15 @@ IS_OMAP_TYPE(3517, 0x3517)
#define OMAP3505_REV(v) (OMAP35XX_CLASS | (0x3505 << 16) | (v << 8))
#define OMAP3517_REV(v) (OMAP35XX_CLASS | (0x3517 << 16) | (v << 8))
+#define TI816X_CLASS 0x81600034
+#define TI8168_REV_ES1_0 TI816X_CLASS
+#define TI8168_REV_ES1_1 (TI816X_CLASS | (OMAP_REVBITS_01 << 8))
+
#define OMAP443X_CLASS 0x44300044
-#define OMAP4430_REV_ES1_0 OMAP443X_CLASS
-#define OMAP4430_REV_ES2_0 0x44301044
+#define OMAP4430_REV_ES1_0 (OMAP443X_CLASS | (0x10 << 8))
+#define OMAP4430_REV_ES2_0 (OMAP443X_CLASS | (0x20 << 8))
+#define OMAP4430_REV_ES2_1 (OMAP443X_CLASS | (0x21 << 8))
+#define OMAP4430_REV_ES2_2 (OMAP443X_CLASS | (0x22 << 8))
/*
* omap_chip bits
@@ -419,11 +436,16 @@ IS_OMAP_TYPE(3517, 0x3517)
#define CHIP_IS_OMAP3630ES1_1 (1 << 9)
#define CHIP_IS_OMAP3630ES1_2 (1 << 10)
#define CHIP_IS_OMAP4430ES2 (1 << 11)
+#define CHIP_IS_OMAP4430ES2_1 (1 << 12)
+#define CHIP_IS_OMAP4430ES2_2 (1 << 13)
+#define CHIP_IS_TI816X (1 << 14)
#define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
-#define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1 | \
- CHIP_IS_OMAP4430ES2)
+#define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1 | \
+ CHIP_IS_OMAP4430ES2 | \
+ CHIP_IS_OMAP4430ES2_1 | \
+ CHIP_IS_OMAP4430ES2_2)
/*
* "GE" here represents "greater than or equal to" in terms of ES
@@ -455,6 +477,7 @@ extern u32 omap3_features;
#define OMAP3_HAS_ISP BIT(4)
#define OMAP3_HAS_192MHZ_CLK BIT(5)
#define OMAP3_HAS_IO_WAKEUP BIT(6)
+#define OMAP3_HAS_SDRC BIT(7)
#define OMAP3_HAS_FEATURE(feat,flag) \
static inline unsigned int omap3_has_ ##feat(void) \
@@ -469,5 +492,6 @@ OMAP3_HAS_FEATURE(neon, NEON)
OMAP3_HAS_FEATURE(isp, ISP)
OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK)
OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP)
+OMAP3_HAS_FEATURE(sdrc, SDRC)
#endif
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
index 537f4e449f50..0f140ecedb01 100644
--- a/arch/arm/plat-omap/include/plat/display.h
+++ b/arch/arm/plat-omap/include/plat/display.h
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/device.h>
+#include <linux/platform_device.h>
#include <asm/atomic.h>
#define DISPC_IRQ_FRAMEDONE (1 << 0)
@@ -226,6 +227,16 @@ struct omap_dss_board_info {
struct omap_dss_device *default_device;
};
+#if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS)
+/* Init with the board info */
+extern int omap_display_init(struct omap_dss_board_info *board_data);
+#else
+static inline int omap_display_init(struct omap_dss_board_info *board_data)
+{
+ return 0;
+}
+#endif
+
struct omap_video_timings {
/* Unit: pixels */
u16 x_res;
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index dfa3aff9761b..d6c70d2f4030 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -3,6 +3,12 @@
*
* OMAP Dual-Mode Timers
*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ *
+ * Platform device conversion and hwmod support.
+ *
* Copyright (C) 2005 Nokia Corporation
* Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
* PWM and clock framwork support by Timo Teras.
@@ -44,6 +50,11 @@
#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01
#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
+/*
+ * IP revision identifier so that Highlander IP
+ * in OMAP4 can be distinguished.
+ */
+#define OMAP_TIMER_IP_VERSION_1 0x1
struct omap_dm_timer;
extern struct omap_dm_timer *gptimer_wakeup;
extern struct sys_timer omap_timer;
diff --git a/arch/arm/plat-omap/include/plat/fpga.h b/arch/arm/plat-omap/include/plat/fpga.h
index ae39bcb3f5ba..bd3c6324ae1f 100644
--- a/arch/arm/plat-omap/include/plat/fpga.h
+++ b/arch/arm/plat-omap/include/plat/fpga.h
@@ -30,18 +30,18 @@ extern void omap1510_fpga_init_irq(void);
* ---------------------------------------------------------------------------
*/
/* maps in the FPGA registers and the ETHR registers */
-#define H2P2_DBG_FPGA_BASE IOMEM(0xE8000000) /* VA */
+#define H2P2_DBG_FPGA_BASE 0xE8000000 /* VA */
#define H2P2_DBG_FPGA_SIZE SZ_4K /* SIZE */
#define H2P2_DBG_FPGA_START 0x04000000 /* PA */
#define H2P2_DBG_FPGA_ETHR_START (H2P2_DBG_FPGA_START + 0x300)
-#define H2P2_DBG_FPGA_FPGA_REV (H2P2_DBG_FPGA_BASE + 0x10) /* FPGA Revision */
-#define H2P2_DBG_FPGA_BOARD_REV (H2P2_DBG_FPGA_BASE + 0x12) /* Board Revision */
-#define H2P2_DBG_FPGA_GPIO (H2P2_DBG_FPGA_BASE + 0x14) /* GPIO outputs */
-#define H2P2_DBG_FPGA_LEDS (H2P2_DBG_FPGA_BASE + 0x16) /* LEDs outputs */
-#define H2P2_DBG_FPGA_MISC_INPUTS (H2P2_DBG_FPGA_BASE + 0x18) /* Misc inputs */
-#define H2P2_DBG_FPGA_LAN_STATUS (H2P2_DBG_FPGA_BASE + 0x1A) /* LAN Status line */
-#define H2P2_DBG_FPGA_LAN_RESET (H2P2_DBG_FPGA_BASE + 0x1C) /* LAN Reset line */
+#define H2P2_DBG_FPGA_FPGA_REV IOMEM(H2P2_DBG_FPGA_BASE + 0x10) /* FPGA Revision */
+#define H2P2_DBG_FPGA_BOARD_REV IOMEM(H2P2_DBG_FPGA_BASE + 0x12) /* Board Revision */
+#define H2P2_DBG_FPGA_GPIO IOMEM(H2P2_DBG_FPGA_BASE + 0x14) /* GPIO outputs */
+#define H2P2_DBG_FPGA_LEDS IOMEM(H2P2_DBG_FPGA_BASE + 0x16) /* LEDs outputs */
+#define H2P2_DBG_FPGA_MISC_INPUTS IOMEM(H2P2_DBG_FPGA_BASE + 0x18) /* Misc inputs */
+#define H2P2_DBG_FPGA_LAN_STATUS IOMEM(H2P2_DBG_FPGA_BASE + 0x1A) /* LAN Status line */
+#define H2P2_DBG_FPGA_LAN_RESET IOMEM(H2P2_DBG_FPGA_BASE + 0x1C) /* LAN Reset line */
/* NOTE: most boards don't have a static mapping for the FPGA ... */
struct h2p2_dbg_fpga {
@@ -81,55 +81,55 @@ struct h2p2_dbg_fpga {
* OMAP-1510 FPGA
* ---------------------------------------------------------------------------
*/
-#define OMAP1510_FPGA_BASE IOMEM(0xE8000000) /* VA */
+#define OMAP1510_FPGA_BASE 0xE8000000 /* VA */
#define OMAP1510_FPGA_SIZE SZ_4K
#define OMAP1510_FPGA_START 0x08000000 /* PA */
/* Revision */
-#define OMAP1510_FPGA_REV_LOW (OMAP1510_FPGA_BASE + 0x0)
-#define OMAP1510_FPGA_REV_HIGH (OMAP1510_FPGA_BASE + 0x1)
+#define OMAP1510_FPGA_REV_LOW IOMEM(OMAP1510_FPGA_BASE + 0x0)
+#define OMAP1510_FPGA_REV_HIGH IOMEM(OMAP1510_FPGA_BASE + 0x1)
-#define OMAP1510_FPGA_LCD_PANEL_CONTROL (OMAP1510_FPGA_BASE + 0x2)
-#define OMAP1510_FPGA_LED_DIGIT (OMAP1510_FPGA_BASE + 0x3)
-#define INNOVATOR_FPGA_HID_SPI (OMAP1510_FPGA_BASE + 0x4)
-#define OMAP1510_FPGA_POWER (OMAP1510_FPGA_BASE + 0x5)
+#define OMAP1510_FPGA_LCD_PANEL_CONTROL IOMEM(OMAP1510_FPGA_BASE + 0x2)
+#define OMAP1510_FPGA_LED_DIGIT IOMEM(OMAP1510_FPGA_BASE + 0x3)
+#define INNOVATOR_FPGA_HID_SPI IOMEM(OMAP1510_FPGA_BASE + 0x4)
+#define OMAP1510_FPGA_POWER IOMEM(OMAP1510_FPGA_BASE + 0x5)
/* Interrupt status */
-#define OMAP1510_FPGA_ISR_LO (OMAP1510_FPGA_BASE + 0x6)
-#define OMAP1510_FPGA_ISR_HI (OMAP1510_FPGA_BASE + 0x7)
+#define OMAP1510_FPGA_ISR_LO IOMEM(OMAP1510_FPGA_BASE + 0x6)
+#define OMAP1510_FPGA_ISR_HI IOMEM(OMAP1510_FPGA_BASE + 0x7)
/* Interrupt mask */
-#define OMAP1510_FPGA_IMR_LO (OMAP1510_FPGA_BASE + 0x8)
-#define OMAP1510_FPGA_IMR_HI (OMAP1510_FPGA_BASE + 0x9)
+#define OMAP1510_FPGA_IMR_LO IOMEM(OMAP1510_FPGA_BASE + 0x8)
+#define OMAP1510_FPGA_IMR_HI IOMEM(OMAP1510_FPGA_BASE + 0x9)
/* Reset registers */
-#define OMAP1510_FPGA_HOST_RESET (OMAP1510_FPGA_BASE + 0xa)
-#define OMAP1510_FPGA_RST (OMAP1510_FPGA_BASE + 0xb)
-
-#define OMAP1510_FPGA_AUDIO (OMAP1510_FPGA_BASE + 0xc)
-#define OMAP1510_FPGA_DIP (OMAP1510_FPGA_BASE + 0xe)
-#define OMAP1510_FPGA_FPGA_IO (OMAP1510_FPGA_BASE + 0xf)
-#define OMAP1510_FPGA_UART1 (OMAP1510_FPGA_BASE + 0x14)
-#define OMAP1510_FPGA_UART2 (OMAP1510_FPGA_BASE + 0x15)
-#define OMAP1510_FPGA_OMAP1510_STATUS (OMAP1510_FPGA_BASE + 0x16)
-#define OMAP1510_FPGA_BOARD_REV (OMAP1510_FPGA_BASE + 0x18)
-#define OMAP1510P1_PPT_DATA (OMAP1510_FPGA_BASE + 0x100)
-#define OMAP1510P1_PPT_STATUS (OMAP1510_FPGA_BASE + 0x101)
-#define OMAP1510P1_PPT_CONTROL (OMAP1510_FPGA_BASE + 0x102)
-
-#define OMAP1510_FPGA_TOUCHSCREEN (OMAP1510_FPGA_BASE + 0x204)
-
-#define INNOVATOR_FPGA_INFO (OMAP1510_FPGA_BASE + 0x205)
-#define INNOVATOR_FPGA_LCD_BRIGHT_LO (OMAP1510_FPGA_BASE + 0x206)
-#define INNOVATOR_FPGA_LCD_BRIGHT_HI (OMAP1510_FPGA_BASE + 0x207)
-#define INNOVATOR_FPGA_LED_GRN_LO (OMAP1510_FPGA_BASE + 0x208)
-#define INNOVATOR_FPGA_LED_GRN_HI (OMAP1510_FPGA_BASE + 0x209)
-#define INNOVATOR_FPGA_LED_RED_LO (OMAP1510_FPGA_BASE + 0x20a)
-#define INNOVATOR_FPGA_LED_RED_HI (OMAP1510_FPGA_BASE + 0x20b)
-#define INNOVATOR_FPGA_CAM_USB_CONTROL (OMAP1510_FPGA_BASE + 0x20c)
-#define INNOVATOR_FPGA_EXP_CONTROL (OMAP1510_FPGA_BASE + 0x20d)
-#define INNOVATOR_FPGA_ISR2 (OMAP1510_FPGA_BASE + 0x20e)
-#define INNOVATOR_FPGA_IMR2 (OMAP1510_FPGA_BASE + 0x210)
+#define OMAP1510_FPGA_HOST_RESET IOMEM(OMAP1510_FPGA_BASE + 0xa)
+#define OMAP1510_FPGA_RST IOMEM(OMAP1510_FPGA_BASE + 0xb)
+
+#define OMAP1510_FPGA_AUDIO IOMEM(OMAP1510_FPGA_BASE + 0xc)
+#define OMAP1510_FPGA_DIP IOMEM(OMAP1510_FPGA_BASE + 0xe)
+#define OMAP1510_FPGA_FPGA_IO IOMEM(OMAP1510_FPGA_BASE + 0xf)
+#define OMAP1510_FPGA_UART1 IOMEM(OMAP1510_FPGA_BASE + 0x14)
+#define OMAP1510_FPGA_UART2 IOMEM(OMAP1510_FPGA_BASE + 0x15)
+#define OMAP1510_FPGA_OMAP1510_STATUS IOMEM(OMAP1510_FPGA_BASE + 0x16)
+#define OMAP1510_FPGA_BOARD_REV IOMEM(OMAP1510_FPGA_BASE + 0x18)
+#define OMAP1510P1_PPT_DATA IOMEM(OMAP1510_FPGA_BASE + 0x100)
+#define OMAP1510P1_PPT_STATUS IOMEM(OMAP1510_FPGA_BASE + 0x101)
+#define OMAP1510P1_PPT_CONTROL IOMEM(OMAP1510_FPGA_BASE + 0x102)
+
+#define OMAP1510_FPGA_TOUCHSCREEN IOMEM(OMAP1510_FPGA_BASE + 0x204)
+
+#define INNOVATOR_FPGA_INFO IOMEM(OMAP1510_FPGA_BASE + 0x205)
+#define INNOVATOR_FPGA_LCD_BRIGHT_LO IOMEM(OMAP1510_FPGA_BASE + 0x206)
+#define INNOVATOR_FPGA_LCD_BRIGHT_HI IOMEM(OMAP1510_FPGA_BASE + 0x207)
+#define INNOVATOR_FPGA_LED_GRN_LO IOMEM(OMAP1510_FPGA_BASE + 0x208)
+#define INNOVATOR_FPGA_LED_GRN_HI IOMEM(OMAP1510_FPGA_BASE + 0x209)
+#define INNOVATOR_FPGA_LED_RED_LO IOMEM(OMAP1510_FPGA_BASE + 0x20a)
+#define INNOVATOR_FPGA_LED_RED_HI IOMEM(OMAP1510_FPGA_BASE + 0x20b)
+#define INNOVATOR_FPGA_CAM_USB_CONTROL IOMEM(OMAP1510_FPGA_BASE + 0x20c)
+#define INNOVATOR_FPGA_EXP_CONTROL IOMEM(OMAP1510_FPGA_BASE + 0x20d)
+#define INNOVATOR_FPGA_ISR2 IOMEM(OMAP1510_FPGA_BASE + 0x20e)
+#define INNOVATOR_FPGA_IMR2 IOMEM(OMAP1510_FPGA_BASE + 0x210)
#define OMAP1510_FPGA_ETHR_START (OMAP1510_FPGA_START + 0x300)
diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h
index 85ded598853e..12b316165037 100644
--- a/arch/arm/plat-omap/include/plat/gpmc.h
+++ b/arch/arm/plat-omap/include/plat/gpmc.h
@@ -41,6 +41,8 @@
#define GPMC_NAND_ADDRESS 0x0000000b
#define GPMC_NAND_DATA 0x0000000c
+#define GPMC_ENABLE_IRQ 0x0000000d
+
/* ECC commands */
#define GPMC_ECC_READ 0 /* Reset Hardware ECC for read */
#define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
@@ -78,6 +80,19 @@
#define WR_RD_PIN_MONITORING 0x00600000
#define GPMC_PREFETCH_STATUS_FIFO_CNT(val) ((val >> 24) & 0x7F)
#define GPMC_PREFETCH_STATUS_COUNT(val) (val & 0x00003fff)
+#define GPMC_IRQ_FIFOEVENTENABLE 0x01
+#define GPMC_IRQ_COUNT_EVENT 0x02
+
+#define PREFETCH_FIFOTHRESHOLD_MAX 0x40
+#define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8)
+
+enum omap_ecc {
+ /* 1-bit ecc: stored at end of spare area */
+ OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
+ OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
+ /* 1-bit ecc: stored at begining of spare area as romcode */
+ OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
+};
/*
* Note that all values in this struct are in nanoseconds except sync_clk
@@ -130,12 +145,11 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
extern void gpmc_cs_free(int cs);
extern int gpmc_cs_set_reserved(int cs, int reserved);
extern int gpmc_cs_reserved(int cs);
-extern int gpmc_prefetch_enable(int cs, int dma_mode,
+extern int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
unsigned int u32_count, int is_write);
extern int gpmc_prefetch_reset(int cs);
extern void omap3_gpmc_save_context(void);
extern void omap3_gpmc_restore_context(void);
-extern void gpmc_init(void);
extern int gpmc_read_status(int cmd);
extern int gpmc_cs_configure(int cs, int cmd, int wval);
extern int gpmc_nand_read(int cs, int cmd);
diff --git a/arch/arm/plat-omap/include/plat/hardware.h b/arch/arm/plat-omap/include/plat/hardware.h
index d5b26adfb890..e87efe1499b8 100644
--- a/arch/arm/plat-omap/include/plat/hardware.h
+++ b/arch/arm/plat-omap/include/plat/hardware.h
@@ -286,5 +286,6 @@
#include <plat/omap24xx.h>
#include <plat/omap34xx.h>
#include <plat/omap44xx.h>
+#include <plat/ti816x.h>
#endif /* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
index ef4106c13183..d72ec85c97e6 100644
--- a/arch/arm/plat-omap/include/plat/io.h
+++ b/arch/arm/plat-omap/include/plat/io.h
@@ -259,7 +259,7 @@ struct omap_sdrc_params;
extern void omap1_map_common_io(void);
extern void omap1_init_common_hw(void);
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
extern void omap242x_map_common_io(void);
#else
static inline void omap242x_map_common_io(void)
@@ -267,7 +267,7 @@ static inline void omap242x_map_common_io(void)
}
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
extern void omap243x_map_common_io(void);
#else
static inline void omap243x_map_common_io(void)
@@ -283,6 +283,14 @@ static inline void omap34xx_map_common_io(void)
}
#endif
+#ifdef CONFIG_SOC_OMAPTI816X
+extern void omapti816x_map_common_io(void);
+#else
+static inline void omapti816x_map_common_io(void)
+{
+}
+#endif
+
#ifdef CONFIG_ARCH_OMAP4
extern void omap44xx_map_common_io(void);
#else
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h
index 69230d685538..174f1b9c8c03 100644
--- a/arch/arm/plat-omap/include/plat/iommu.h
+++ b/arch/arm/plat-omap/include/plat/iommu.h
@@ -31,6 +31,7 @@ struct iommu {
struct clk *clk;
void __iomem *regbase;
struct device *dev;
+ void *isr_priv;
unsigned int refcount;
struct mutex iommu_lock; /* global for this whole object */
@@ -47,7 +48,7 @@ struct iommu {
struct list_head mmap;
struct mutex mmap_lock; /* protect mmap */
- int (*isr)(struct iommu *obj);
+ int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv);
void *ctx; /* iommu context: registres saved area */
u32 da_start;
@@ -109,6 +110,13 @@ struct iommu_platform_data {
u32 da_end;
};
+/* IOMMU errors */
+#define OMAP_IOMMU_ERR_TLB_MISS (1 << 0)
+#define OMAP_IOMMU_ERR_TRANS_FAULT (1 << 1)
+#define OMAP_IOMMU_ERR_EMU_MISS (1 << 2)
+#define OMAP_IOMMU_ERR_TBLWALK_FAULT (1 << 3)
+#define OMAP_IOMMU_ERR_MULTIHIT_FAULT (1 << 4)
+
#if defined(CONFIG_ARCH_OMAP1)
#error "iommu for this processor not implemented yet"
#else
@@ -154,11 +162,17 @@ extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
extern void flush_iotlb_all(struct iommu *obj);
extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
+extern void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd,
+ u32 **ppte);
extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end);
extern struct iommu *iommu_get(const char *name);
extern void iommu_put(struct iommu *obj);
+extern int iommu_set_isr(const char *name,
+ int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
+ void *priv),
+ void *isr_priv);
extern void iommu_save_ctx(struct iommu *obj);
extern void iommu_restore_ctx(struct iommu *obj);
diff --git a/arch/arm/plat-omap/include/plat/iovmm.h b/arch/arm/plat-omap/include/plat/iovmm.h
index bdc7ce5d7a4a..32a2f6c4d39e 100644
--- a/arch/arm/plat-omap/include/plat/iovmm.h
+++ b/arch/arm/plat-omap/include/plat/iovmm.h
@@ -71,8 +71,6 @@ struct iovm_struct {
#define IOVMF_LINEAR_MASK (3 << (2 + IOVMF_SW_SHIFT))
#define IOVMF_DA_FIXED (1 << (4 + IOVMF_SW_SHIFT))
-#define IOVMF_DA_ANON (2 << (4 + IOVMF_SW_SHIFT))
-#define IOVMF_DA_MASK (3 << (4 + IOVMF_SW_SHIFT))
extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index 2910de921c52..d77928370463 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -315,9 +315,12 @@
#define INT_34XX_SSM_ABORT_IRQ 6
#define INT_34XX_SYS_NIRQ 7
#define INT_34XX_D2D_FW_IRQ 8
+#define INT_34XX_L3_DBG_IRQ 9
+#define INT_34XX_L3_APP_IRQ 10
#define INT_34XX_PRCM_MPU_IRQ 11
#define INT_34XX_MCBSP1_IRQ 16
#define INT_34XX_MCBSP2_IRQ 17
+#define INT_34XX_GPMC_IRQ 20
#define INT_34XX_MCBSP3_IRQ 22
#define INT_34XX_MCBSP4_IRQ 23
#define INT_34XX_CAM_IRQ 24
@@ -411,7 +414,13 @@
#define TWL_IRQ_END TWL6030_IRQ_END
#endif
-#define NR_IRQS TWL_IRQ_END
+/* GPMC related */
+#define OMAP_GPMC_IRQ_BASE (TWL_IRQ_END)
+#define OMAP_GPMC_NR_IRQS 7
+#define OMAP_GPMC_IRQ_END (OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS)
+
+
+#define NR_IRQS OMAP_GPMC_IRQ_END
#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
diff --git a/arch/arm/plat-omap/include/plat/l3_2xxx.h b/arch/arm/plat-omap/include/plat/l3_2xxx.h
new file mode 100644
index 000000000000..b8b5641379b0
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/l3_2xxx.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/plat-omap/include/plat/l3_2xxx.h - L3 firewall definitions
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Sumit Semwal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L3_2XXX_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L3_2XXX_H
+
+/* L3 CONNIDs */
+/* Display Sub system (DSS) */
+#define OMAP2_L3_CORE_FW_CONNID_DSS 8
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/l3_3xxx.h b/arch/arm/plat-omap/include/plat/l3_3xxx.h
new file mode 100644
index 000000000000..cde1938c5f82
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/l3_3xxx.h
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/plat-omap/include/plat/l3_3xxx.h - L3 firewall definitions
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Sumit Semwal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L3_3XXX_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L3_3XXX_H
+
+/* L3 Initiator IDs */
+/* Display Sub system (DSS) */
+#define OMAP3_L3_CORE_FW_INIT_ID_DSS 29
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/l4_2xxx.h b/arch/arm/plat-omap/include/plat/l4_2xxx.h
new file mode 100644
index 000000000000..3f39cf8a35c6
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/l4_2xxx.h
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/plat-omap/include/plat/l4_2xxx.h - L4 firewall definitions
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Sumit Semwal
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L4_2XXX_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_L4_2XXX_H
+
+/* L4 CORE */
+/* Display Sub system (DSS) */
+#define OMAP2420_L4_CORE_FW_DSS_CORE_REGION 28
+#define OMAP2420_L4_CORE_FW_DSS_DISPC_REGION 29
+#define OMAP2420_L4_CORE_FW_DSS_RFBI_REGION 30
+#define OMAP2420_L4_CORE_FW_DSS_VENC_REGION 31
+#define OMAP2420_L4_CORE_FW_DSS_TA_REGION 32
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/l4_3xxx.h b/arch/arm/plat-omap/include/plat/l4_3xxx.h
index 5e1949375422..881a858b1ffc 100644
--- a/arch/arm/plat-omap/include/plat/l4_3xxx.h
+++ b/arch/arm/plat-omap/include/plat/l4_3xxx.h
@@ -21,4 +21,14 @@
#define OMAP3_L4_CORE_FW_I2C3_REGION 73
#define OMAP3_L4_CORE_FW_I2C3_TA_REGION 74
+/* Display Sub system (DSS) */
+#define OMAP3_L4_CORE_FW_DSS_PROT_GROUP 2
+
+#define OMAP3_L4_CORE_FW_DSS_DSI_REGION 104
+#define OMAP3ES1_L4_CORE_FW_DSS_CORE_REGION 3
+#define OMAP3_L4_CORE_FW_DSS_CORE_REGION 4
+#define OMAP3_L4_CORE_FW_DSS_DISPC_REGION 4
+#define OMAP3_L4_CORE_FW_DSS_RFBI_REGION 5
+#define OMAP3_L4_CORE_FW_DSS_VENC_REGION 6
+#define OMAP3_L4_CORE_FW_DSS_TA_REGION 7
#endif
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index b87d83ccd545..f8f690ab2997 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -37,6 +37,10 @@ static struct platform_device omap_mcbsp##port_nr = { \
.id = OMAP_MCBSP##port_nr, \
}
+#define MCBSP_CONFIG_TYPE2 0x2
+#define MCBSP_CONFIG_TYPE3 0x3
+#define MCBSP_CONFIG_TYPE4 0x4
+
#define OMAP7XX_MCBSP1_BASE 0xfffb1000
#define OMAP7XX_MCBSP2_BASE 0xfffb1800
@@ -48,32 +52,14 @@ static struct platform_device omap_mcbsp##port_nr = { \
#define OMAP1610_MCBSP2_BASE 0xfffb1000
#define OMAP1610_MCBSP3_BASE 0xe1017000
-#define OMAP24XX_MCBSP1_BASE 0x48074000
-#define OMAP24XX_MCBSP2_BASE 0x48076000
-#define OMAP2430_MCBSP3_BASE 0x4808c000
-#define OMAP2430_MCBSP4_BASE 0x4808e000
-#define OMAP2430_MCBSP5_BASE 0x48096000
-
-#define OMAP34XX_MCBSP1_BASE 0x48074000
-#define OMAP34XX_MCBSP2_BASE 0x49022000
-#define OMAP34XX_MCBSP2_ST_BASE 0x49028000
-#define OMAP34XX_MCBSP3_BASE 0x49024000
-#define OMAP34XX_MCBSP3_ST_BASE 0x4902A000
-#define OMAP34XX_MCBSP3_BASE 0x49024000
-#define OMAP34XX_MCBSP4_BASE 0x49026000
-#define OMAP34XX_MCBSP5_BASE 0x48096000
-
-#define OMAP44XX_MCBSP1_BASE 0x49022000
-#define OMAP44XX_MCBSP2_BASE 0x49024000
-#define OMAP44XX_MCBSP3_BASE 0x49026000
-#define OMAP44XX_MCBSP4_BASE 0x48096000
-
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+#ifdef CONFIG_ARCH_OMAP1
#define OMAP_MCBSP_REG_DRR2 0x00
#define OMAP_MCBSP_REG_DRR1 0x02
#define OMAP_MCBSP_REG_DXR2 0x04
#define OMAP_MCBSP_REG_DXR1 0x06
+#define OMAP_MCBSP_REG_DRR 0x02
+#define OMAP_MCBSP_REG_DXR 0x06
#define OMAP_MCBSP_REG_SPCR2 0x08
#define OMAP_MCBSP_REG_SPCR1 0x0a
#define OMAP_MCBSP_REG_RCR2 0x0c
@@ -106,13 +92,6 @@ static struct platform_device omap_mcbsp##port_nr = { \
#define OMAP_MCBSP_REG_XCCR 0x00
#define OMAP_MCBSP_REG_RCCR 0x00
-#define AUDIO_MCBSP_DATAWRITE (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
-#define AUDIO_MCBSP_DATAREAD (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
-
-#define AUDIO_MCBSP OMAP_MCBSP1
-#define AUDIO_DMA_TX OMAP_DMA_MCBSP1_TX
-#define AUDIO_DMA_RX OMAP_DMA_MCBSP1_RX
-
#else
#define OMAP_MCBSP_REG_DRR2 0x00
@@ -168,13 +147,6 @@ static struct platform_device omap_mcbsp##port_nr = { \
#define OMAP_ST_REG_SFIRCR 0x28
#define OMAP_ST_REG_SSELCR 0x2C
-#define AUDIO_MCBSP_DATAWRITE (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
-#define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
-
-#define AUDIO_MCBSP OMAP_MCBSP2
-#define AUDIO_DMA_TX OMAP24XX_DMA_MCBSP2_TX
-#define AUDIO_DMA_RX OMAP24XX_DMA_MCBSP2_RX
-
#endif
/************************** McBSP SPCR1 bit definitions ***********************/
@@ -428,8 +400,9 @@ struct omap_mcbsp_platform_data {
#ifdef CONFIG_ARCH_OMAP3
/* Sidetone block for McBSP 2 and 3 */
unsigned long phys_base_st;
- u16 buffer_size;
#endif
+ u16 buffer_size;
+ unsigned int mcbsp_config_type;
};
struct omap_mcbsp_st_data {
@@ -445,6 +418,7 @@ struct omap_mcbsp_st_data {
struct omap_mcbsp {
struct device *dev;
unsigned long phys_base;
+ unsigned long phys_dma_base;
void __iomem *io_base;
u8 id;
u8 free;
@@ -471,7 +445,6 @@ struct omap_mcbsp {
/* Protect the field .free, while checking if the mcbsp is in use */
spinlock_t lock;
struct omap_mcbsp_platform_data *pdata;
- struct clk *iclk;
struct clk *fclk;
#ifdef CONFIG_ARCH_OMAP3
struct omap_mcbsp_st_data *st_data;
@@ -480,7 +453,17 @@ struct omap_mcbsp {
u16 max_rx_thres;
#endif
void *reg_cache;
+ unsigned int mcbsp_config_type;
};
+
+/**
+ * omap_mcbsp_dev_attr - OMAP McBSP device attributes for omap_hwmod
+ * @sidetone: name of the sidetone device
+ */
+struct omap_mcbsp_dev_attr {
+ const char *sidetone;
+};
+
extern struct omap_mcbsp **mcbsp_ptr;
extern int omap_mcbsp_count, omap_mcbsp_cache_size;
@@ -488,8 +471,8 @@ extern int omap_mcbsp_count, omap_mcbsp_cache_size;
#define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
int omap_mcbsp_init(void);
-void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
- int size);
+void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
+ struct omap_mcbsp_platform_data *config, int size);
void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
#ifdef CONFIG_ARCH_OMAP3
void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
@@ -539,6 +522,9 @@ int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
void omap2_mcbsp1_mux_clkr_src(u8 mux);
void omap2_mcbsp1_mux_fsr_src(u8 mux);
+int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream);
+int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream);
+
#ifdef CONFIG_ARCH_OMAP3
/* Sidetone specific API */
int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
diff --git a/arch/arm/plat-omap/include/plat/mcspi.h b/arch/arm/plat-omap/include/plat/mcspi.h
index 1254e4945b6f..3d51b18131cc 100644
--- a/arch/arm/plat-omap/include/plat/mcspi.h
+++ b/arch/arm/plat-omap/include/plat/mcspi.h
@@ -1,8 +1,19 @@
#ifndef _OMAP2_MCSPI_H
#define _OMAP2_MCSPI_H
+#define OMAP2_MCSPI_REV 0
+#define OMAP3_MCSPI_REV 1
+#define OMAP4_MCSPI_REV 2
+
+#define OMAP4_MCSPI_REG_OFFSET 0x100
+
struct omap2_mcspi_platform_config {
unsigned short num_cs;
+ unsigned int regs_offset;
+};
+
+struct omap2_mcspi_dev_attr {
+ unsigned short num_chipselect;
};
struct omap2_mcspi_device_config {
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index f57f36abb07e..f38fef9f1310 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -24,25 +24,19 @@
#define OMAP1_MMC2_BASE 0xfffb7c00 /* omap16xx only */
#define OMAP24XX_NR_MMC 2
-#define OMAP34XX_NR_MMC 3
-#define OMAP44XX_NR_MMC 5
#define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE
-#define OMAP3_HSMMC_SIZE 0x200
-#define OMAP4_HSMMC_SIZE 0x1000
#define OMAP2_MMC1_BASE 0x4809c000
-#define OMAP2_MMC2_BASE 0x480b4000
-#define OMAP3_MMC3_BASE 0x480ad000
-#define OMAP4_MMC4_BASE 0x480d1000
-#define OMAP4_MMC5_BASE 0x480d5000
+
#define OMAP4_MMC_REG_OFFSET 0x100
-#define HSMMC5 (1 << 4)
-#define HSMMC4 (1 << 3)
-#define HSMMC3 (1 << 2)
-#define HSMMC2 (1 << 1)
-#define HSMMC1 (1 << 0)
#define OMAP_MMC_MAX_SLOTS 2
+#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(1)
+
+struct omap_mmc_dev_attr {
+ u8 flags;
+};
+
struct omap_mmc_platform_data {
/* back-link to device */
struct device *dev;
@@ -71,6 +65,9 @@ struct omap_mmc_platform_data {
u64 dma_mask;
+ /* Integrating attributes from the omap_hwmod layer */
+ u8 controller_flags;
+
/* Register offset deviation */
u16 reg_offset;
@@ -159,8 +156,7 @@ extern void omap_mmc_notify_cover_event(struct device *dev, int slot,
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
int nr_controllers);
-void omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
- int nr_controllers);
+void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data);
int omap_mmc_add(const char *name, int id, unsigned long base,
unsigned long size, unsigned int irq,
struct omap_mmc_platform_data *data);
@@ -169,8 +165,7 @@ static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
int nr_controllers)
{
}
-static inline void omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
- int nr_controllers)
+static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
{
}
static inline int omap_mmc_add(const char *name, int id, unsigned long base,
diff --git a/arch/arm/plat-omap/include/plat/multi.h b/arch/arm/plat-omap/include/plat/multi.h
index ffd909fa5287..999ffba2690c 100644
--- a/arch/arm/plat-omap/include/plat/multi.h
+++ b/arch/arm/plat-omap/include/plat/multi.h
@@ -66,7 +66,7 @@
# error "OMAP1 and OMAP2PLUS can't be selected at the same time"
# endif
#endif
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
# ifdef OMAP_NAME
# undef MULTI_OMAP2
# define MULTI_OMAP2
@@ -74,7 +74,7 @@
# define OMAP_NAME omap2420
# endif
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
# ifdef OMAP_NAME
# undef MULTI_OMAP2
# define MULTI_OMAP2
diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h
index 6562cd082bb1..d86d1ecf0068 100644
--- a/arch/arm/plat-omap/include/plat/nand.h
+++ b/arch/arm/plat-omap/include/plat/nand.h
@@ -8,8 +8,16 @@
* published by the Free Software Foundation.
*/
+#include <plat/gpmc.h>
#include <linux/mtd/partitions.h>
+enum nand_io {
+ NAND_OMAP_PREFETCH_POLLED = 0, /* prefetch polled mode, default */
+ NAND_OMAP_POLLED, /* polled mode, without prefetch */
+ NAND_OMAP_PREFETCH_DMA, /* prefetch enabled sDMA mode */
+ NAND_OMAP_PREFETCH_IRQ /* prefetch enabled irq mode */
+};
+
struct omap_nand_platform_data {
unsigned int options;
int cs;
@@ -20,8 +28,11 @@ struct omap_nand_platform_data {
int (*nand_setup)(void);
int (*dev_ready)(struct omap_nand_platform_data *);
int dma_channel;
+ int gpmc_irq;
+ enum nand_io xfer_type;
unsigned long phys_base;
int devsize;
+ enum omap_ecc ecc_opt;
};
/* minimum size for IO mapping */
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 1eee85a8abb3..1adea9c62984 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -1,7 +1,7 @@
/*
* omap_hwmod macros, structures
*
- * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009-2011 Nokia Corporation
* Paul Walmsley
*
* Created in collaboration with (alphabetical order): Benoît Cousson,
@@ -30,11 +30,11 @@
#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/list.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <plat/cpu.h>
-#include <plat/voltage.h>
struct omap_device;
@@ -90,6 +90,9 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2;
struct omap_hwmod_mux_info {
int nr_pads;
struct omap_device_pad *pads;
+ int nr_pads_dynamic;
+ struct omap_device_pad **pads_dynamic;
+ bool enabled;
};
/**
@@ -124,6 +127,7 @@ struct omap_hwmod_dma_info {
* struct omap_hwmod_rst_info - IPs reset lines use by hwmod
* @name: name of the reset line (module local name)
* @rst_shift: Offset of the reset bit
+ * @st_shift: Offset of the reset status bit (OMAP2/3 only)
*
* @name should be something short, e.g., "cpu0" or "rst". It is defined
* locally to the hwmod.
@@ -131,6 +135,7 @@ struct omap_hwmod_dma_info {
struct omap_hwmod_rst_info {
const char *name;
u8 rst_shift;
+ u8 st_shift;
};
/**
@@ -178,7 +183,8 @@ struct omap_hwmod_omap2_firewall {
#define ADDR_TYPE_RT (1 << 1)
/**
- * struct omap_hwmod_addr_space - MPU address space handled by the hwmod
+ * struct omap_hwmod_addr_space - address space handled by the hwmod
+ * @name: name of the address space
* @pa_start: starting physical address
* @pa_end: ending physical address
* @flags: (see omap_hwmod_addr_space.flags macros above)
@@ -187,6 +193,7 @@ struct omap_hwmod_omap2_firewall {
* structure. GPMC is one example.
*/
struct omap_hwmod_addr_space {
+ const char *name;
u32 pa_start;
u32 pa_end;
u8 flags;
@@ -370,9 +377,11 @@ struct omap_hwmod_omap4_prcm {
* of standby, rather than relying on module smart-standby
* HWMOD_INIT_NO_RESET: don't reset this module at boot - important for
* SDRAM controller, etc. XXX probably belongs outside the main hwmod file
+ * XXX Should be HWMOD_SETUP_NO_RESET
* HWMOD_INIT_NO_IDLE: don't idle this module at boot - important for SDRAM
* controller, etc. XXX probably belongs outside the main hwmod file
- * HWMOD_NO_AUTOIDLE: disable module autoidle (OCP_SYSCONFIG.AUTOIDLE)
+ * XXX Should be HWMOD_SETUP_NO_IDLE
+ * HWMOD_NO_OCP_AUTOIDLE: disable module autoidle (OCP_SYSCONFIG.AUTOIDLE)
* when module is enabled, rather than the default, which is to
* enable autoidle
* HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
@@ -535,11 +544,12 @@ struct omap_hwmod {
const struct omap_chip_id omap_chip;
};
-int omap_hwmod_init(struct omap_hwmod **ohs);
+int omap_hwmod_register(struct omap_hwmod **ohs);
struct omap_hwmod *omap_hwmod_lookup(const char *name);
int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
void *data);
-int omap_hwmod_late_init(void);
+
+int __init omap_hwmod_setup_one(const char *name);
int omap_hwmod_enable(struct omap_hwmod *oh);
int _omap_hwmod_enable(struct omap_hwmod *oh);
@@ -555,6 +565,7 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh);
int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode);
+int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle);
int omap_hwmod_reset(struct omap_hwmod *oh);
void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
@@ -589,6 +600,8 @@ int omap_hwmod_for_each_by_class(const char *classname,
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state);
u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh);
+int omap_hwmod_no_setup_reset(struct omap_hwmod *oh);
+
/*
* Chip variant-specific hwmod init routines - XXX should be converted
* to use initcalls once the initial boot ordering is straightened out
diff --git a/arch/arm/plat-omap/include/plat/onenand.h b/arch/arm/plat-omap/include/plat/onenand.h
index affe87e9ece7..cbe897ca7f9e 100644
--- a/arch/arm/plat-omap/include/plat/onenand.h
+++ b/arch/arm/plat-omap/include/plat/onenand.h
@@ -15,12 +15,20 @@
#define ONENAND_SYNC_READ (1 << 0)
#define ONENAND_SYNC_READWRITE (1 << 1)
+struct onenand_freq_info {
+ u16 maf_id;
+ u16 dev_id;
+ u16 ver_id;
+};
+
struct omap_onenand_platform_data {
int cs;
int gpio_irq;
struct mtd_partition *parts;
int nr_parts;
- int (*onenand_setup)(void __iomem *, int freq);
+ int (*onenand_setup)(void __iomem *, int *freq_ptr);
+ int (*get_freq)(const struct onenand_freq_info *freq_info,
+ bool *clk_dep);
int dma_channel;
u8 flags;
u8 regulator_can_sleep;
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h
index 2fdf8c80d390..267f43bb2a4e 100644
--- a/arch/arm/plat-omap/include/plat/prcm.h
+++ b/arch/arm/plat-omap/include/plat/prcm.h
@@ -28,7 +28,6 @@
#define __ASM_ARM_ARCH_OMAP_PRCM_H
u32 omap_prcm_get_reset_sources(void);
-void omap_prcm_arch_reset(char mode, const char *cmd);
int omap2_cm_wait_idlest(void __iomem *reg, u32 mask, u8 idlest,
const char *name);
diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
index efd87c8dda69..925b12b500dc 100644
--- a/arch/arm/plat-omap/include/plat/sdrc.h
+++ b/arch/arm/plat-omap/include/plat/sdrc.h
@@ -124,8 +124,14 @@ struct omap_sdrc_params {
u32 mr;
};
-void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+void omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1);
+#else
+static inline void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
+ struct omap_sdrc_params *sdrc_cs1) {};
+#endif
+
int omap2_sdrc_get_params(unsigned long r,
struct omap_sdrc_params **sdrc_cs0,
struct omap_sdrc_params **sdrc_cs1);
diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h
index 8ff605c83aca..2723f9166ea2 100644
--- a/arch/arm/plat-omap/include/plat/serial.h
+++ b/arch/arm/plat-omap/include/plat/serial.h
@@ -51,6 +51,11 @@
#define OMAP4_UART3_BASE 0x48020000
#define OMAP4_UART4_BASE 0x4806e000
+/* TI816X serial ports */
+#define TI816X_UART1_BASE 0x48020000
+#define TI816X_UART2_BASE 0x48022000
+#define TI816X_UART3_BASE 0x48024000
+
/* External port on Zoom2/3 */
#define ZOOM_UART_BASE 0x10000000
#define ZOOM_UART_VIRT 0xfa400000
@@ -81,6 +86,9 @@
#define OMAP4UART2 OMAP2UART2
#define OMAP4UART3 43
#define OMAP4UART4 44
+#define TI816XUART1 81
+#define TI816XUART2 82
+#define TI816XUART3 83
#define ZOOM_UART 95 /* Only on zoom2/3 */
/* This is only used by 8250.c for omap1510 */
@@ -96,7 +104,6 @@
struct omap_board_data;
-extern void __init omap_serial_early_init(void);
extern void omap_serial_init(void);
extern void omap_serial_init_port(struct omap_board_data *bdata);
extern int omap_uart_can_sleep(void);
diff --git a/arch/arm/plat-omap/include/plat/system.h b/arch/arm/plat-omap/include/plat/system.h
index d0a119f735b4..c5fa9e929009 100644
--- a/arch/arm/plat-omap/include/plat/system.h
+++ b/arch/arm/plat-omap/include/plat/system.h
@@ -4,48 +4,14 @@
*/
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#include <linux/clk.h>
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-
-#include <plat/prcm.h>
-
-#ifndef CONFIG_MACH_VOICEBLUE
-#define voiceblue_reset() do {} while (0)
-#else
-extern void voiceblue_reset(void);
-#endif
+#include <asm/proc-fns.h>
static inline void arch_idle(void)
{
cpu_do_idle();
}
-static inline void omap1_arch_reset(char mode, const char *cmd)
-{
- /*
- * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
- * "Global Software Reset Affects Traffic Controller Frequency".
- */
- if (cpu_is_omap5912()) {
- omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4),
- DPLL_CTL);
- omap_writew(0x8, ARM_RSTCT1);
- }
-
- if (machine_is_voiceblue())
- voiceblue_reset();
- else
- omap_writew(1, ARM_RSTCT1);
-}
-
-static inline void arch_reset(char mode, const char *cmd)
-{
- if (!cpu_class_is_omap2())
- omap1_arch_reset(mode, cmd);
- else
- omap_prcm_arch_reset(mode, cmd);
-}
+extern void (*arch_reset)(char, const char *);
#endif
diff --git a/arch/arm/plat-omap/include/plat/ti816x.h b/arch/arm/plat-omap/include/plat/ti816x.h
new file mode 100644
index 000000000000..50510f5dda1e
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/ti816x.h
@@ -0,0 +1,27 @@
+/*
+ * This file contains the address data for various TI816X modules.
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_TI816X_H
+#define __ASM_ARCH_TI816X_H
+
+#define L4_SLOW_TI816X_BASE 0x48000000
+
+#define TI816X_SCM_BASE 0x48140000
+#define TI816X_CTRL_BASE TI816X_SCM_BASE
+#define TI816X_PRCM_BASE 0x48180000
+
+#define TI816X_ARM_INTC_BASE 0x48200000
+
+#endif /* __ASM_ARCH_TI816X_H */
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index ad98b85cae21..30b891c4a93f 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -93,6 +93,10 @@ static inline void flush(void)
#define DEBUG_LL_ZOOM(mach) \
_DEBUG_LL_ENTRY(mach, ZOOM_UART_BASE, ZOOM_PORT_SHIFT, ZOOM_UART)
+#define DEBUG_LL_TI816X(p, mach) \
+ _DEBUG_LL_ENTRY(mach, TI816X_UART##p##_BASE, OMAP_PORT_SHIFT, \
+ TI816XUART##p)
+
static inline void __arch_decomp_setup(unsigned long arch_id)
{
int port = 0;
@@ -166,6 +170,9 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
DEBUG_LL_ZOOM(omap_zoom2);
DEBUG_LL_ZOOM(omap_zoom3);
+ /* TI8168 base boards using UART3 */
+ DEBUG_LL_TI816X(3, ti8168evm);
+
} while (0);
}
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index fe449f1a1c14..02b96c8f6a17 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -110,6 +110,11 @@ extern int omap4430_phy_exit(struct device *dev);
extern int omap4430_phy_suspend(struct device *dev, int suspend);
#endif
+extern void am35x_musb_reset(void);
+extern void am35x_musb_phy_power(u8 on);
+extern void am35x_musb_clear_irq(void);
+extern void am35x_musb_set_mode(u8 musb_mode);
+
/*
* FIXME correct answer depends on hmc_mode,
* as does (on omap1) any nonzero value for config->otg port number
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
index f1295fafcd31..f1ecfa9fc61d 100644
--- a/arch/arm/plat-omap/io.c
+++ b/arch/arm/plat-omap/io.c
@@ -85,7 +85,10 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
}
#endif
#ifdef CONFIG_ARCH_OMAP3
- if (cpu_is_omap34xx()) {
+ if (cpu_is_ti816x()) {
+ if (BETWEEN(p, L4_34XX_PHYS, L4_34XX_SIZE))
+ return XLATE(p, L4_34XX_PHYS, L4_34XX_VIRT);
+ } else if (cpu_is_omap34xx()) {
if (BETWEEN(p, L3_34XX_PHYS, L3_34XX_SIZE))
return XLATE(p, L3_34XX_PHYS, L3_34XX_VIRT);
if (BETWEEN(p, L4_34XX_PHYS, L4_34XX_SIZE))
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index b1107c08da56..8a51fd58f656 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -104,6 +104,9 @@ static int iommu_enable(struct iommu *obj)
if (!obj)
return -EINVAL;
+ if (!arch_iommu)
+ return -ENODEV;
+
clk_enable(obj->clk);
err = arch_iommu->enable(obj);
@@ -780,25 +783,19 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
*/
static irqreturn_t iommu_fault_handler(int irq, void *data)
{
- u32 stat, da;
+ u32 da, errs;
u32 *iopgd, *iopte;
- int err = -EIO;
struct iommu *obj = data;
if (!obj->refcount)
return IRQ_NONE;
- /* Dynamic loading TLB or PTE */
- if (obj->isr)
- err = obj->isr(obj);
-
- if (!err)
- return IRQ_HANDLED;
-
clk_enable(obj->clk);
- stat = iommu_report_fault(obj, &da);
+ errs = iommu_report_fault(obj, &da);
clk_disable(obj->clk);
- if (!stat)
+
+ /* Fault callback or TLB/PTE Dynamic loading */
+ if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
return IRQ_HANDLED;
iommu_disable(obj);
@@ -806,15 +803,16 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
iopgd = iopgd_offset(obj, da);
if (!iopgd_is_table(*iopgd)) {
- dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__,
- da, iopgd, *iopgd);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
+ "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
return IRQ_NONE;
}
iopte = iopte_offset(iopgd, da);
- dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
- __func__, da, iopgd, *iopgd, iopte, *iopte);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
+ "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
+ iopte, *iopte);
return IRQ_NONE;
}
@@ -917,6 +915,33 @@ void iommu_put(struct iommu *obj)
}
EXPORT_SYMBOL_GPL(iommu_put);
+int iommu_set_isr(const char *name,
+ int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
+ void *priv),
+ void *isr_priv)
+{
+ struct device *dev;
+ struct iommu *obj;
+
+ dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
+ device_match_by_alias);
+ if (!dev)
+ return -ENODEV;
+
+ obj = to_iommu(dev);
+ mutex_lock(&obj->iommu_lock);
+ if (obj->refcount != 0) {
+ mutex_unlock(&obj->iommu_lock);
+ return -EBUSY;
+ }
+ obj->isr = isr;
+ obj->isr_priv = isr_priv;
+ mutex_unlock(&obj->iommu_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_set_isr);
+
/*
* OMAP Device MMU(IOMMU) detection
*/
@@ -957,11 +982,6 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
err = -ENODEV;
goto err_mem;
}
- obj->regbase = ioremap(res->start, resource_size(res));
- if (!obj->regbase) {
- err = -ENOMEM;
- goto err_mem;
- }
res = request_mem_region(res->start, resource_size(res),
dev_name(&pdev->dev));
@@ -970,6 +990,12 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
goto err_mem;
}
+ obj->regbase = ioremap(res->start, resource_size(res));
+ if (!obj->regbase) {
+ err = -ENOMEM;
+ goto err_ioremap;
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
err = -ENODEV;
@@ -998,8 +1024,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
err_pgd:
free_irq(irq, obj);
err_irq:
- release_mem_region(res->start, resource_size(res));
iounmap(obj->regbase);
+err_ioremap:
+ release_mem_region(res->start, resource_size(res));
err_mem:
clk_put(obj->clk);
err_clk:
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index 6dc1296c8c77..51ef43e8def6 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -271,20 +271,21 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
size_t bytes, u32 flags)
{
struct iovm_struct *new, *tmp;
- u32 start, prev_end, alignement;
+ u32 start, prev_end, alignment;
if (!obj || !bytes)
return ERR_PTR(-EINVAL);
start = da;
- alignement = PAGE_SIZE;
+ alignment = PAGE_SIZE;
- if (flags & IOVMF_DA_ANON) {
- start = obj->da_start;
+ if (~flags & IOVMF_DA_FIXED) {
+ /* Don't map address 0 */
+ start = obj->da_start ? obj->da_start : alignment;
if (flags & IOVMF_LINEAR)
- alignement = iopgsz_max(bytes);
- start = roundup(start, alignement);
+ alignment = iopgsz_max(bytes);
+ start = roundup(start, alignment);
} else if (start < obj->da_start || start > obj->da_end ||
obj->da_end - start < bytes) {
return ERR_PTR(-EINVAL);
@@ -303,8 +304,8 @@ static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
if (tmp->da_start > start && (tmp->da_start - start) >= bytes)
goto found;
- if (tmp->da_end >= start && flags & IOVMF_DA_ANON)
- start = roundup(tmp->da_end + 1, alignement);
+ if (tmp->da_end >= start && ~flags & IOVMF_DA_FIXED)
+ start = roundup(tmp->da_end + 1, alignment);
prev_end = tmp->da_end;
}
@@ -650,7 +651,6 @@ u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
flags &= IOVMF_HW_MASK;
flags |= IOVMF_DISCONT;
flags |= IOVMF_MMIO;
- flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
if (IS_ERR_VALUE(da))
@@ -690,7 +690,7 @@ EXPORT_SYMBOL_GPL(iommu_vunmap);
* @flags: iovma and page property
*
* Allocate @bytes linearly and creates 1-n-1 mapping and returns
- * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ * @da again, which might be adjusted if 'IOVMF_DA_FIXED' is not set.
*/
u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
{
@@ -709,7 +709,6 @@ u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
flags &= IOVMF_HW_MASK;
flags |= IOVMF_DISCONT;
flags |= IOVMF_ALLOC;
- flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
sgt = sgtable_alloc(bytes, flags, da, 0);
if (IS_ERR(sgt)) {
@@ -780,7 +779,7 @@ static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
* @flags: iovma and page property
*
* Creates 1-1-1 mapping and returns @da again, which can be
- * adjusted if 'IOVMF_DA_ANON' is set.
+ * adjusted if 'IOVMF_DA_FIXED' is not set.
*/
u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
u32 flags)
@@ -799,7 +798,6 @@ u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
flags &= IOVMF_HW_MASK;
flags |= IOVMF_LINEAR;
flags |= IOVMF_MMIO;
- flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
da = __iommu_kmap(obj, da, pa, va, bytes, flags);
if (IS_ERR_VALUE(da))
@@ -838,7 +836,7 @@ EXPORT_SYMBOL_GPL(iommu_kunmap);
* @flags: iovma and page property
*
* Allocate @bytes linearly and creates 1-1-1 mapping and returns
- * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
+ * @da again, which might be adjusted if 'IOVMF_DA_FIXED' is not set.
*/
u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
{
@@ -858,7 +856,6 @@ u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
flags &= IOVMF_HW_MASK;
flags |= IOVMF_LINEAR;
flags |= IOVMF_ALLOC;
- flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
da = __iommu_kmap(obj, da, pa, va, bytes, flags);
if (IS_ERR_VALUE(da))
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index b5a6e178a7f9..d598d9fd65ac 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -27,6 +27,8 @@
#include <plat/dma.h>
#include <plat/mcbsp.h>
+#include <plat/omap_device.h>
+#include <linux/pm_runtime.h>
/* XXX These "sideways" includes are a sign that something is wrong */
#include "../mach-omap2/cm2xxx_3xxx.h"
@@ -227,10 +229,83 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
}
EXPORT_SYMBOL(omap_mcbsp_config);
+/**
+ * omap_mcbsp_dma_params - returns the dma channel number
+ * @id - mcbsp id
+ * @stream - indicates the direction of data flow (rx or tx)
+ *
+ * Returns the dma channel number for the rx channel or tx channel
+ * based on the value of @stream for the requested mcbsp given by @id
+ */
+int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream)
+{
+ struct omap_mcbsp *mcbsp;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return -ENODEV;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ if (stream)
+ return mcbsp->dma_rx_sync;
+ else
+ return mcbsp->dma_tx_sync;
+}
+EXPORT_SYMBOL(omap_mcbsp_dma_ch_params);
+
+/**
+ * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register
+ * @id - mcbsp id
+ * @stream - indicates the direction of data flow (rx or tx)
+ *
+ * Returns the address of mcbsp data transmit register or data receive register
+ * to be used by DMA for transferring/receiving data based on the value of
+ * @stream for the requested mcbsp given by @id
+ */
+int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream)
+{
+ struct omap_mcbsp *mcbsp;
+ int data_reg;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return -ENODEV;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ data_reg = mcbsp->phys_dma_base;
+
+ if (mcbsp->mcbsp_config_type < MCBSP_CONFIG_TYPE2) {
+ if (stream)
+ data_reg += OMAP_MCBSP_REG_DRR1;
+ else
+ data_reg += OMAP_MCBSP_REG_DXR1;
+ } else {
+ if (stream)
+ data_reg += OMAP_MCBSP_REG_DRR;
+ else
+ data_reg += OMAP_MCBSP_REG_DXR;
+ }
+
+ return data_reg;
+}
+EXPORT_SYMBOL(omap_mcbsp_dma_reg_params);
+
#ifdef CONFIG_ARCH_OMAP3
+static struct omap_device *find_omap_device_by_dev(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ return container_of(pdev, struct omap_device, pdev);
+}
+
static void omap_st_on(struct omap_mcbsp *mcbsp)
{
unsigned int w;
+ struct omap_device *od;
+
+ od = find_omap_device_by_dev(mcbsp->dev);
/*
* Sidetone uses McBSP ICLK - which must not idle when sidetones
@@ -244,9 +319,6 @@ static void omap_st_on(struct omap_mcbsp *mcbsp)
w = MCBSP_READ(mcbsp, SSELCR);
MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN);
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
-
/* Enable Sidetone from Sidetone Core */
w = MCBSP_ST_READ(mcbsp, SSELCR);
MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN);
@@ -255,13 +327,13 @@ static void omap_st_on(struct omap_mcbsp *mcbsp)
static void omap_st_off(struct omap_mcbsp *mcbsp)
{
unsigned int w;
+ struct omap_device *od;
+
+ od = find_omap_device_by_dev(mcbsp->dev);
w = MCBSP_ST_READ(mcbsp, SSELCR);
MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN));
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE);
-
w = MCBSP_READ(mcbsp, SSELCR);
MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN));
@@ -273,9 +345,9 @@ static void omap_st_off(struct omap_mcbsp *mcbsp)
static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir)
{
u16 val, i;
+ struct omap_device *od;
- val = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, val & ~(ST_AUTOIDLE));
+ od = find_omap_device_by_dev(mcbsp->dev);
val = MCBSP_ST_READ(mcbsp, SSELCR);
@@ -303,9 +375,9 @@ static void omap_st_chgain(struct omap_mcbsp *mcbsp)
{
u16 w;
struct omap_mcbsp_st_data *st_data = mcbsp->st_data;
+ struct omap_device *od;
- w = MCBSP_ST_READ(mcbsp, SYSCONFIG);
- MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE));
+ od = find_omap_device_by_dev(mcbsp->dev);
w = MCBSP_ST_READ(mcbsp, SSELCR);
@@ -648,48 +720,33 @@ EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode);
static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
{
+ struct omap_device *od;
+
+ od = find_omap_device_by_dev(mcbsp->dev);
/*
* Enable wakup behavior, smart idle and all wakeups
* REVISIT: some wakeups may be unnecessary
*/
if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
- u16 syscon;
-
- syscon = MCBSP_READ(mcbsp, SYSCON);
- syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
-
- if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
- syscon |= (ENAWAKEUP | SIDLEMODE(0x02) |
- CLOCKACTIVITY(0x02));
- MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
- } else {
- syscon |= SIDLEMODE(0x01);
- }
-
- MCBSP_WRITE(mcbsp, SYSCON, syscon);
+ MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN);
}
}
static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
{
+ struct omap_device *od;
+
+ od = find_omap_device_by_dev(mcbsp->dev);
+
/*
* Disable wakup behavior, smart idle and all wakeups
*/
if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
- u16 syscon;
-
- syscon = MCBSP_READ(mcbsp, SYSCON);
- syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03));
/*
* HW bug workaround - If no_idle mode is taken, we need to
* go to smart_idle before going to always_idle, or the
* device will not hit retention anymore.
*/
- syscon |= SIDLEMODE(0x02);
- MCBSP_WRITE(mcbsp, SYSCON, syscon);
-
- syscon &= ~(SIDLEMODE(0x03));
- MCBSP_WRITE(mcbsp, SYSCON, syscon);
MCBSP_WRITE(mcbsp, WAKEUPEN, 0);
}
@@ -764,8 +821,7 @@ int omap_mcbsp_request(unsigned int id)
if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
mcbsp->pdata->ops->request(id);
- clk_enable(mcbsp->iclk);
- clk_enable(mcbsp->fclk);
+ pm_runtime_get_sync(mcbsp->dev);
/* Do procedure specific to omap34xx arch, if applicable */
omap34xx_mcbsp_request(mcbsp);
@@ -813,8 +869,7 @@ err_clk_disable:
/* Do procedure specific to omap34xx arch, if applicable */
omap34xx_mcbsp_free(mcbsp);
- clk_disable(mcbsp->fclk);
- clk_disable(mcbsp->iclk);
+ pm_runtime_put_sync(mcbsp->dev);
spin_lock(&mcbsp->lock);
mcbsp->free = true;
@@ -844,8 +899,7 @@ void omap_mcbsp_free(unsigned int id)
/* Do procedure specific to omap34xx arch, if applicable */
omap34xx_mcbsp_free(mcbsp);
- clk_disable(mcbsp->fclk);
- clk_disable(mcbsp->iclk);
+ pm_runtime_put_sync(mcbsp->dev);
if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
/* Free IRQs */
@@ -1649,7 +1703,8 @@ static const struct attribute_group sidetone_attr_group = {
static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
{
- struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
+ struct platform_device *pdev;
+ struct resource *res;
struct omap_mcbsp_st_data *st_data;
int err;
@@ -1659,7 +1714,10 @@ static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
goto err1;
}
- st_data->io_base_st = ioremap(pdata->phys_base_st, SZ_4K);
+ pdev = container_of(mcbsp->dev, struct platform_device, dev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sidetone");
+ st_data->io_base_st = ioremap(res->start, resource_size(res));
if (!st_data->io_base_st) {
err = -ENOMEM;
goto err2;
@@ -1748,6 +1806,7 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data;
struct omap_mcbsp *mcbsp;
int id = pdev->id - 1;
+ struct resource *res;
int ret = 0;
if (!pdata) {
@@ -1777,47 +1836,78 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
mcbsp->dma_tx_lch = -1;
mcbsp->dma_rx_lch = -1;
- mcbsp->phys_base = pdata->phys_base;
- mcbsp->io_base = ioremap(pdata->phys_base, SZ_4K);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+ if (!res) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "%s:mcbsp%d has invalid memory"
+ "resource\n", __func__, pdev->id);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ }
+ mcbsp->phys_base = res->start;
+ omap_mcbsp_cache_size = resource_size(res);
+ mcbsp->io_base = ioremap(res->start, resource_size(res));
if (!mcbsp->io_base) {
ret = -ENOMEM;
goto err_ioremap;
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+ if (!res)
+ mcbsp->phys_dma_base = mcbsp->phys_base;
+ else
+ mcbsp->phys_dma_base = res->start;
+
/* Default I/O is IRQ based */
mcbsp->io_type = OMAP_MCBSP_IRQ_IO;
- mcbsp->tx_irq = pdata->tx_irq;
- mcbsp->rx_irq = pdata->rx_irq;
- mcbsp->dma_rx_sync = pdata->dma_rx_sync;
- mcbsp->dma_tx_sync = pdata->dma_tx_sync;
- mcbsp->iclk = clk_get(&pdev->dev, "ick");
- if (IS_ERR(mcbsp->iclk)) {
- ret = PTR_ERR(mcbsp->iclk);
- dev_err(&pdev->dev, "unable to get ick: %d\n", ret);
- goto err_iclk;
+ mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx");
+ mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx");
+
+ /* From OMAP4 there will be a single irq line */
+ if (mcbsp->tx_irq == -ENXIO)
+ mcbsp->tx_irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(&pdev->dev, "%s:mcbsp%d has invalid rx DMA channel\n",
+ __func__, pdev->id);
+ ret = -ENODEV;
+ goto err_res;
+ }
+ mcbsp->dma_rx_sync = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(&pdev->dev, "%s:mcbsp%d has invalid tx DMA channel\n",
+ __func__, pdev->id);
+ ret = -ENODEV;
+ goto err_res;
}
+ mcbsp->dma_tx_sync = res->start;
mcbsp->fclk = clk_get(&pdev->dev, "fck");
if (IS_ERR(mcbsp->fclk)) {
ret = PTR_ERR(mcbsp->fclk);
dev_err(&pdev->dev, "unable to get fck: %d\n", ret);
- goto err_fclk;
+ goto err_res;
}
mcbsp->pdata = pdata;
mcbsp->dev = &pdev->dev;
mcbsp_ptr[id] = mcbsp;
+ mcbsp->mcbsp_config_type = pdata->mcbsp_config_type;
platform_set_drvdata(pdev, mcbsp);
+ pm_runtime_enable(mcbsp->dev);
/* Initialize mcbsp properties for OMAP34XX if needed / applicable */
omap34xx_device_init(mcbsp);
return 0;
-err_fclk:
- clk_put(mcbsp->iclk);
-err_iclk:
+err_res:
iounmap(mcbsp->io_base);
err_ioremap:
kfree(mcbsp);
@@ -1839,7 +1929,6 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
omap34xx_device_exit(mcbsp);
clk_put(mcbsp->fclk);
- clk_put(mcbsp->iclk);
iounmap(mcbsp->io_base);
kfree(mcbsp);
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 57adb270767b..9bbda9acb73b 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -83,9 +83,11 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/clkdev.h>
#include <plat/omap_device.h>
#include <plat/omap_hwmod.h>
+#include <plat/clock.h>
/* These parameters are passed to _omap_device_{de,}activate() */
#define USE_WAKEUP_LAT 0
@@ -239,12 +241,12 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
}
/**
- * _add_optional_clock_alias - Add clock alias for hwmod optional clocks
+ * _add_optional_clock_clkdev - Add clkdev entry for hwmod optional clocks
* @od: struct omap_device *od
*
* For every optional clock present per hwmod per omap_device, this function
- * adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role>
- * if an entry is already present in it with the form <dev-id=NULL, con-id=role>
+ * adds an entry in the clkdev table of the form <dev-id=dev_name, con-id=role>
+ * if it does not exist already.
*
* The function is called from inside omap_device_build_ss(), after
* omap_device_register.
@@ -254,25 +256,39 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev)
*
* No return value.
*/
-static void _add_optional_clock_alias(struct omap_device *od,
+static void _add_optional_clock_clkdev(struct omap_device *od,
struct omap_hwmod *oh)
{
int i;
for (i = 0; i < oh->opt_clks_cnt; i++) {
struct omap_hwmod_opt_clk *oc;
- int r;
+ struct clk *r;
+ struct clk_lookup *l;
oc = &oh->opt_clks[i];
if (!oc->_clk)
continue;
- r = clk_add_alias(oc->role, dev_name(&od->pdev.dev),
- (char *)oc->clk, &od->pdev.dev);
- if (r)
- pr_err("omap_device: %s: clk_add_alias for %s failed\n",
+ r = clk_get_sys(dev_name(&od->pdev.dev), oc->role);
+ if (!IS_ERR(r))
+ continue; /* clkdev entry exists */
+
+ r = omap_clk_get_by_name((char *)oc->clk);
+ if (IS_ERR(r)) {
+ pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n",
+ dev_name(&od->pdev.dev), oc->clk);
+ continue;
+ }
+
+ l = clkdev_alloc(r, oc->role, dev_name(&od->pdev.dev));
+ if (!l) {
+ pr_err("omap_device: %s: clkdev_alloc for %s failed\n",
dev_name(&od->pdev.dev), oc->role);
+ return;
+ }
+ clkdev_add(l);
}
}
@@ -480,7 +496,7 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,
for (i = 0; i < oh_cnt; i++) {
hwmods[i]->od = od;
- _add_optional_clock_alias(od, hwmods[i]);
+ _add_optional_clock_clkdev(od, hwmods[i]);
}
if (ret)
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 68fcc7dc56e7..a3f50b34a90d 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -316,7 +316,7 @@ u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass)
}
#endif
-#ifdef CONFIG_ARCH_OMAP2420
+#ifdef CONFIG_SOC_OMAP2420
static int __init omap242x_sram_init(void)
{
_omap2_sram_ddr_init = omap_sram_push(omap242x_sram_ddr_init,
@@ -337,7 +337,7 @@ static inline int omap242x_sram_init(void)
}
#endif
-#ifdef CONFIG_ARCH_OMAP2430
+#ifdef CONFIG_SOC_OMAP2430
static int __init omap243x_sram_init(void)
{
_omap2_sram_ddr_init = omap_sram_push(omap243x_sram_ddr_init,
@@ -409,20 +409,6 @@ static inline int omap34xx_sram_init(void)
}
#endif
-#ifdef CONFIG_ARCH_OMAP4
-static int __init omap44xx_sram_init(void)
-{
- printk(KERN_ERR "FIXME: %s not implemented\n", __func__);
-
- return -ENODEV;
-}
-#else
-static inline int omap44xx_sram_init(void)
-{
- return 0;
-}
-#endif
-
int __init omap_sram_init(void)
{
omap_detect_sram();
@@ -436,8 +422,6 @@ int __init omap_sram_init(void)
omap243x_sram_init();
else if (cpu_is_omap34xx())
omap34xx_sram_init();
- else if (cpu_is_omap44xx())
- omap44xx_sram_init();
return 0;
}
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index 5f3522314815..078894bc3b9a 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -17,55 +17,123 @@
#include <linux/io.h>
#include <linux/gpio.h>
-static DEFINE_SPINLOCK(gpio_lock);
-static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)];
-static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)];
+/*
+ * GPIO unit register offsets.
+ */
+#define GPIO_OUT_OFF 0x0000
+#define GPIO_IO_CONF_OFF 0x0004
+#define GPIO_BLINK_EN_OFF 0x0008
+#define GPIO_IN_POL_OFF 0x000c
+#define GPIO_DATA_IN_OFF 0x0010
+#define GPIO_EDGE_CAUSE_OFF 0x0014
+#define GPIO_EDGE_MASK_OFF 0x0018
+#define GPIO_LEVEL_MASK_OFF 0x001c
+
+struct orion_gpio_chip {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ void __iomem *base;
+ unsigned long valid_input;
+ unsigned long valid_output;
+ int mask_offset;
+ int secondary_irq_base;
+};
+
+static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_OUT_OFF;
+}
+
+static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_IO_CONF_OFF;
+}
+
+static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_BLINK_EN_OFF;
+}
+
+static void __iomem *GPIO_IN_POL(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_IN_POL_OFF;
+}
+
+static void __iomem *GPIO_DATA_IN(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_DATA_IN_OFF;
+}
+
+static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + GPIO_EDGE_CAUSE_OFF;
+}
+
+static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF;
+}
+
+static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip)
+{
+ return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
+}
+
-static inline void __set_direction(unsigned pin, int input)
+static struct orion_gpio_chip orion_gpio_chips[2];
+static int orion_gpio_chip_count;
+
+static inline void
+__set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input)
{
u32 u;
- u = readl(GPIO_IO_CONF(pin));
+ u = readl(GPIO_IO_CONF(ochip));
if (input)
- u |= 1 << (pin & 31);
+ u |= 1 << pin;
else
- u &= ~(1 << (pin & 31));
- writel(u, GPIO_IO_CONF(pin));
+ u &= ~(1 << pin);
+ writel(u, GPIO_IO_CONF(ochip));
}
-static void __set_level(unsigned pin, int high)
+static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high)
{
u32 u;
- u = readl(GPIO_OUT(pin));
+ u = readl(GPIO_OUT(ochip));
if (high)
- u |= 1 << (pin & 31);
+ u |= 1 << pin;
else
- u &= ~(1 << (pin & 31));
- writel(u, GPIO_OUT(pin));
+ u &= ~(1 << pin);
+ writel(u, GPIO_OUT(ochip));
}
-static inline void __set_blinking(unsigned pin, int blink)
+static inline void
+__set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink)
{
u32 u;
- u = readl(GPIO_BLINK_EN(pin));
+ u = readl(GPIO_BLINK_EN(ochip));
if (blink)
- u |= 1 << (pin & 31);
+ u |= 1 << pin;
else
- u &= ~(1 << (pin & 31));
- writel(u, GPIO_BLINK_EN(pin));
+ u &= ~(1 << pin);
+ writel(u, GPIO_BLINK_EN(ochip));
}
-static inline int orion_gpio_is_valid(unsigned pin, int mode)
+static inline int
+orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode)
{
- if (pin < GPIO_MAX) {
- if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input))
- goto err_out;
- if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output))
- goto err_out;
- return true;
- }
+ if (pin >= ochip->chip.ngpio)
+ goto err_out;
+
+ if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input))
+ goto err_out;
+
+ if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output))
+ goto err_out;
+
+ return 1;
err_out:
pr_debug("%s: invalid GPIO %d\n", __func__, pin);
@@ -75,134 +143,155 @@ err_out:
/*
* GENERIC_GPIO primitives.
*/
+static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
+{
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
+
+ if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) ||
+ orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
+ return 0;
+
+ return -EINVAL;
+}
+
static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags;
- if (!orion_gpio_is_valid(pin, GPIO_INPUT_OK))
+ if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK))
return -EINVAL;
- spin_lock_irqsave(&gpio_lock, flags);
-
- /* Configure GPIO direction. */
- __set_direction(pin, 1);
-
- spin_unlock_irqrestore(&gpio_lock, flags);
+ spin_lock_irqsave(&ochip->lock, flags);
+ __set_direction(ochip, pin, 1);
+ spin_unlock_irqrestore(&ochip->lock, flags);
return 0;
}
-static int orion_gpio_get_value(struct gpio_chip *chip, unsigned pin)
+static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
{
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
int val;
- if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)))
- val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin));
- else
- val = readl(GPIO_OUT(pin));
+ if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) {
+ val = readl(GPIO_DATA_IN(ochip)) ^ readl(GPIO_IN_POL(ochip));
+ } else {
+ val = readl(GPIO_OUT(ochip));
+ }
- return (val >> (pin & 31)) & 1;
+ return (val >> pin) & 1;
}
-static int orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
- int value)
+static int
+orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
{
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags;
- if (!orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
+ if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
return -EINVAL;
- spin_lock_irqsave(&gpio_lock, flags);
-
- /* Disable blinking. */
- __set_blinking(pin, 0);
-
- /* Configure GPIO output value. */
- __set_level(pin, value);
-
- /* Configure GPIO direction. */
- __set_direction(pin, 0);
-
- spin_unlock_irqrestore(&gpio_lock, flags);
+ spin_lock_irqsave(&ochip->lock, flags);
+ __set_blinking(ochip, pin, 0);
+ __set_level(ochip, pin, value);
+ __set_direction(ochip, pin, 0);
+ spin_unlock_irqrestore(&ochip->lock, flags);
return 0;
}
-static void orion_gpio_set_value(struct gpio_chip *chip, unsigned pin,
- int value)
+static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
{
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
unsigned long flags;
- spin_lock_irqsave(&gpio_lock, flags);
-
- /* Configure GPIO output value. */
- __set_level(pin, value);
-
- spin_unlock_irqrestore(&gpio_lock, flags);
+ spin_lock_irqsave(&ochip->lock, flags);
+ __set_level(ochip, pin, value);
+ spin_unlock_irqrestore(&ochip->lock, flags);
}
-static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
+static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
{
- if (orion_gpio_is_valid(pin, GPIO_INPUT_OK) ||
- orion_gpio_is_valid(pin, GPIO_OUTPUT_OK))
- return 0;
- return -EINVAL;
-}
+ struct orion_gpio_chip *ochip =
+ container_of(chip, struct orion_gpio_chip, chip);
-static struct gpio_chip orion_gpiochip = {
- .label = "orion_gpio",
- .direction_input = orion_gpio_direction_input,
- .get = orion_gpio_get_value,
- .direction_output = orion_gpio_direction_output,
- .set = orion_gpio_set_value,
- .request = orion_gpio_request,
- .base = 0,
- .ngpio = GPIO_MAX,
- .can_sleep = 0,
-};
-
-void __init orion_gpio_init(void)
-{
- gpiochip_add(&orion_gpiochip);
+ return ochip->secondary_irq_base + pin;
}
+
/*
* Orion-specific GPIO API extensions.
*/
+static struct orion_gpio_chip *orion_gpio_chip_find(int pin)
+{
+ int i;
+
+ for (i = 0; i < orion_gpio_chip_count; i++) {
+ struct orion_gpio_chip *ochip = orion_gpio_chips + i;
+ struct gpio_chip *chip = &ochip->chip;
+
+ if (pin >= chip->base && pin < chip->base + chip->ngpio)
+ return ochip;
+ }
+
+ return NULL;
+}
+
void __init orion_gpio_set_unused(unsigned pin)
{
+ struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
+
+ if (ochip == NULL)
+ return;
+
+ pin -= ochip->chip.base;
+
/* Configure as output, drive low. */
- __set_level(pin, 0);
- __set_direction(pin, 0);
+ __set_level(ochip, pin, 0);
+ __set_direction(ochip, pin, 0);
}
void __init orion_gpio_set_valid(unsigned pin, int mode)
{
+ struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
+
+ if (ochip == NULL)
+ return;
+
+ pin -= ochip->chip.base;
+
if (mode == 1)
mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK;
+
if (mode & GPIO_INPUT_OK)
- __set_bit(pin, gpio_valid_input);
+ __set_bit(pin, &ochip->valid_input);
else
- __clear_bit(pin, gpio_valid_input);
+ __clear_bit(pin, &ochip->valid_input);
+
if (mode & GPIO_OUTPUT_OK)
- __set_bit(pin, gpio_valid_output);
+ __set_bit(pin, &ochip->valid_output);
else
- __clear_bit(pin, gpio_valid_output);
+ __clear_bit(pin, &ochip->valid_output);
}
void orion_gpio_set_blink(unsigned pin, int blink)
{
+ struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
unsigned long flags;
- spin_lock_irqsave(&gpio_lock, flags);
+ if (ochip == NULL)
+ return;
- /* Set output value to zero. */
- __set_level(pin, 0);
-
- /* Set blinking. */
- __set_blinking(pin, blink);
-
- spin_unlock_irqrestore(&gpio_lock, flags);
+ spin_lock_irqsave(&ochip->lock, flags);
+ __set_level(ochip, pin, 0);
+ __set_blinking(ochip, pin, blink);
+ spin_unlock_irqrestore(&ochip->lock, flags);
}
EXPORT_SYMBOL(orion_gpio_set_blink);
@@ -234,59 +323,78 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
****************************************************************************/
static void gpio_irq_ack(struct irq_data *d)
{
- int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
+ struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
+ int type;
+
+ type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- int pin = irq_to_gpio(d->irq);
- writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin));
+ int pin = d->irq - ochip->secondary_irq_base;
+
+ writel(~(1 << pin), GPIO_EDGE_CAUSE(ochip));
}
}
static void gpio_irq_mask(struct irq_data *d)
{
- int pin = irq_to_gpio(d->irq);
- int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
- u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
- GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
- u32 u = readl(reg);
- u &= ~(1 << (pin & 31));
- writel(u, reg);
+ struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
+ int type;
+ void __iomem *reg;
+ int pin;
+
+ type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = GPIO_EDGE_MASK(ochip);
+ else
+ reg = GPIO_LEVEL_MASK(ochip);
+
+ pin = d->irq - ochip->secondary_irq_base;
+
+ writel(readl(reg) & ~(1 << pin), reg);
}
static void gpio_irq_unmask(struct irq_data *d)
{
- int pin = irq_to_gpio(d->irq);
- int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
- u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
- GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
- u32 u = readl(reg);
- u |= 1 << (pin & 31);
- writel(u, reg);
+ struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
+ int type;
+ void __iomem *reg;
+ int pin;
+
+ type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ reg = GPIO_EDGE_MASK(ochip);
+ else
+ reg = GPIO_LEVEL_MASK(ochip);
+
+ pin = d->irq - ochip->secondary_irq_base;
+
+ writel(readl(reg) | (1 << pin), reg);
}
static int gpio_irq_set_type(struct irq_data *d, u32 type)
{
- int pin = irq_to_gpio(d->irq);
- struct irq_desc *desc;
+ struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
+ int pin;
u32 u;
- u = readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31));
+ pin = d->irq - ochip->secondary_irq_base;
+
+ u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
if (!u) {
printk(KERN_ERR "orion gpio_irq_set_type failed "
"(irq %d, pin %d).\n", d->irq, pin);
return -EINVAL;
}
- desc = irq_desc + d->irq;
-
/*
* Set edge/level type.
*/
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- desc->handle_irq = handle_edge_irq;
+ set_irq_handler(d->irq, handle_edge_irq);
} else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- desc->handle_irq = handle_level_irq;
+ set_irq_handler(d->irq, handle_level_irq);
} else {
- printk(KERN_ERR "failed to set irq=%d (type=%d)\n", d->irq, type);
+ printk(KERN_ERR "failed to set irq=%d (type=%d)\n",
+ d->irq, type);
return -EINVAL;
}
@@ -294,31 +402,29 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type)
* Configure interrupt polarity.
*/
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) {
- u = readl(GPIO_IN_POL(pin));
- u &= ~(1 << (pin & 31));
- writel(u, GPIO_IN_POL(pin));
+ u = readl(GPIO_IN_POL(ochip));
+ u &= ~(1 << pin);
+ writel(u, GPIO_IN_POL(ochip));
} else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) {
- u = readl(GPIO_IN_POL(pin));
- u |= 1 << (pin & 31);
- writel(u, GPIO_IN_POL(pin));
+ u = readl(GPIO_IN_POL(ochip));
+ u |= 1 << pin;
+ writel(u, GPIO_IN_POL(ochip));
} else if (type == IRQ_TYPE_EDGE_BOTH) {
u32 v;
- v = readl(GPIO_IN_POL(pin)) ^ readl(GPIO_DATA_IN(pin));
+ v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip));
/*
* set initial polarity based on current input level
*/
- u = readl(GPIO_IN_POL(pin));
- if (v & (1 << (pin & 31)))
- u |= 1 << (pin & 31); /* falling */
+ u = readl(GPIO_IN_POL(ochip));
+ if (v & (1 << pin))
+ u |= 1 << pin; /* falling */
else
- u &= ~(1 << (pin & 31)); /* rising */
- writel(u, GPIO_IN_POL(pin));
+ u &= ~(1 << pin); /* rising */
+ writel(u, GPIO_IN_POL(ochip));
}
- desc->status = (desc->status & ~IRQ_TYPE_SENSE_MASK) | type;
-
return 0;
}
@@ -330,29 +436,87 @@ struct irq_chip orion_gpio_irq_chip = {
.irq_set_type = gpio_irq_set_type,
};
+void __init orion_gpio_init(int gpio_base, int ngpio,
+ u32 base, int mask_offset, int secondary_irq_base)
+{
+ struct orion_gpio_chip *ochip;
+ int i;
+
+ if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips))
+ return;
+
+ ochip = orion_gpio_chips + orion_gpio_chip_count;
+ ochip->chip.label = "orion_gpio";
+ ochip->chip.request = orion_gpio_request;
+ ochip->chip.direction_input = orion_gpio_direction_input;
+ ochip->chip.get = orion_gpio_get;
+ ochip->chip.direction_output = orion_gpio_direction_output;
+ ochip->chip.set = orion_gpio_set;
+ ochip->chip.to_irq = orion_gpio_to_irq;
+ ochip->chip.base = gpio_base;
+ ochip->chip.ngpio = ngpio;
+ ochip->chip.can_sleep = 0;
+ spin_lock_init(&ochip->lock);
+ ochip->base = (void __iomem *)base;
+ ochip->valid_input = 0;
+ ochip->valid_output = 0;
+ ochip->mask_offset = mask_offset;
+ ochip->secondary_irq_base = secondary_irq_base;
+
+ gpiochip_add(&ochip->chip);
+
+ orion_gpio_chip_count++;
+
+ /*
+ * Mask and clear GPIO interrupts.
+ */
+ writel(0, GPIO_EDGE_CAUSE(ochip));
+ writel(0, GPIO_EDGE_MASK(ochip));
+ writel(0, GPIO_LEVEL_MASK(ochip));
+
+ for (i = 0; i < ngpio; i++) {
+ unsigned int irq = secondary_irq_base + i;
+
+ set_irq_chip(irq, &orion_gpio_irq_chip);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_chip_data(irq, ochip);
+ irq_desc[irq].status |= IRQ_LEVEL;
+ set_irq_flags(irq, IRQF_VALID);
+ }
+}
+
void orion_gpio_irq_handler(int pinoff)
{
+ struct orion_gpio_chip *ochip;
u32 cause;
- int pin;
+ int i;
- cause = readl(GPIO_DATA_IN(pinoff)) & readl(GPIO_LEVEL_MASK(pinoff));
- cause |= readl(GPIO_EDGE_CAUSE(pinoff)) & readl(GPIO_EDGE_MASK(pinoff));
+ ochip = orion_gpio_chip_find(pinoff);
+ if (ochip == NULL)
+ return;
- for (pin = pinoff; pin < pinoff + 8; pin++) {
- int irq = gpio_to_irq(pin);
- struct irq_desc *desc = irq_desc + irq;
+ cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
+ cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
- if (!(cause & (1 << (pin & 31))))
+ for (i = 0; i < ochip->chip.ngpio; i++) {
+ int irq;
+ struct irq_desc *desc;
+
+ irq = ochip->secondary_irq_base + i;
+
+ if (!(cause & (1 << i)))
continue;
+ desc = irq_desc + irq;
if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
/* Swap polarity (race with GPIO line) */
u32 polarity;
- polarity = readl(GPIO_IN_POL(pin));
- polarity ^= 1 << (pin & 31);
- writel(polarity, GPIO_IN_POL(pin));
+ polarity = readl(GPIO_IN_POL(ochip));
+ polarity ^= 1 << i;
+ writel(polarity, GPIO_IN_POL(ochip));
}
+
desc_handle_irq(irq, desc);
}
}
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index 07c430fdc9ef..5578b9803fc6 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -12,6 +12,7 @@
#define __PLAT_GPIO_H
#include <linux/init.h>
+#include <asm-generic/gpio.h>
/*
* GENERIC_GPIO primitives.
@@ -19,6 +20,7 @@
#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
/*
* Orion-specific GPIO API extensions.
@@ -31,7 +33,8 @@ void orion_gpio_set_blink(unsigned pin, int blink);
void orion_gpio_set_valid(unsigned pin, int mode);
/* Initialize gpiolib. */
-void __init orion_gpio_init(void);
+void __init orion_gpio_init(int gpio_base, int ngpio,
+ u32 base, int mask_offset, int secondary_irq_base);
/*
* GPIO interrupt handling.
diff --git a/arch/arm/plat-orion/include/plat/time.h b/arch/arm/plat-orion/include/plat/time.h
index c06ca35f3613..4d5f1f6e18df 100644
--- a/arch/arm/plat-orion/include/plat/time.h
+++ b/arch/arm/plat-orion/include/plat/time.h
@@ -11,7 +11,10 @@
#ifndef __PLAT_TIME_H
#define __PLAT_TIME_H
-void orion_time_init(unsigned int irq, unsigned int tclk);
+void orion_time_set_base(u32 timer_base);
+
+void orion_time_init(u32 bridge_base, u32 bridge_timer1_clr_mask,
+ unsigned int irq, unsigned int tclk);
#endif
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index c3da2478b2aa..742b0323c57b 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -18,28 +18,42 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/sched_clock.h>
-#include <asm/mach/time.h>
-#include <mach/bridge-regs.h>
-#include <mach/hardware.h>
/*
- * Number of timer ticks per jiffy.
+ * MBus bridge block registers.
*/
-static u32 ticks_per_jiffy;
+#define BRIDGE_CAUSE_OFF 0x0110
+#define BRIDGE_MASK_OFF 0x0114
+#define BRIDGE_INT_TIMER0 0x0002
+#define BRIDGE_INT_TIMER1 0x0004
/*
* Timer block registers.
*/
-#define TIMER_CTRL (TIMER_VIRT_BASE + 0x0000)
-#define TIMER0_EN 0x0001
-#define TIMER0_RELOAD_EN 0x0002
-#define TIMER1_EN 0x0004
-#define TIMER1_RELOAD_EN 0x0008
-#define TIMER0_RELOAD (TIMER_VIRT_BASE + 0x0010)
-#define TIMER0_VAL (TIMER_VIRT_BASE + 0x0014)
-#define TIMER1_RELOAD (TIMER_VIRT_BASE + 0x0018)
-#define TIMER1_VAL (TIMER_VIRT_BASE + 0x001c)
+#define TIMER_CTRL_OFF 0x0000
+#define TIMER0_EN 0x0001
+#define TIMER0_RELOAD_EN 0x0002
+#define TIMER1_EN 0x0004
+#define TIMER1_RELOAD_EN 0x0008
+#define TIMER0_RELOAD_OFF 0x0010
+#define TIMER0_VAL_OFF 0x0014
+#define TIMER1_RELOAD_OFF 0x0018
+#define TIMER1_VAL_OFF 0x001c
+
+
+/*
+ * SoC-specific data.
+ */
+static void __iomem *bridge_base;
+static u32 bridge_timer1_clr_mask;
+static void __iomem *timer_base;
+
+
+/*
+ * Number of timer ticks per jiffy.
+ */
+static u32 ticks_per_jiffy;
/*
@@ -50,14 +64,14 @@ static DEFINE_CLOCK_DATA(cd);
unsigned long long notrace sched_clock(void)
{
- u32 cyc = 0xffffffff - readl(TIMER0_VAL);
+ u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF);
return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}
static void notrace orion_update_sched_clock(void)
{
- u32 cyc = 0xffffffff - readl(TIMER0_VAL);
+ u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF);
update_sched_clock(&cd, cyc, (u32)~0);
}
@@ -71,7 +85,7 @@ static void __init setup_sched_clock(unsigned long tclk)
*/
static cycle_t orion_clksrc_read(struct clocksource *cs)
{
- return 0xffffffff - readl(TIMER0_VAL);
+ return 0xffffffff - readl(timer_base + TIMER0_VAL_OFF);
}
static struct clocksource orion_clksrc = {
@@ -101,23 +115,23 @@ orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
/*
* Clear and enable clockevent timer interrupt.
*/
- writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
+ writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
- u = readl(BRIDGE_MASK);
+ u = readl(bridge_base + BRIDGE_MASK_OFF);
u |= BRIDGE_INT_TIMER1;
- writel(u, BRIDGE_MASK);
+ writel(u, bridge_base + BRIDGE_MASK_OFF);
/*
* Setup new clockevent timer value.
*/
- writel(delta, TIMER1_VAL);
+ writel(delta, timer_base + TIMER1_VAL_OFF);
/*
* Enable the timer.
*/
- u = readl(TIMER_CTRL);
+ u = readl(timer_base + TIMER_CTRL_OFF);
u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN;
- writel(u, TIMER_CTRL);
+ writel(u, timer_base + TIMER_CTRL_OFF);
local_irq_restore(flags);
@@ -135,37 +149,38 @@ orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
/*
* Setup timer to fire at 1/HZ intervals.
*/
- writel(ticks_per_jiffy - 1, TIMER1_RELOAD);
- writel(ticks_per_jiffy - 1, TIMER1_VAL);
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF);
+ writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF);
/*
* Enable timer interrupt.
*/
- u = readl(BRIDGE_MASK);
- writel(u | BRIDGE_INT_TIMER1, BRIDGE_MASK);
+ u = readl(bridge_base + BRIDGE_MASK_OFF);
+ writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF);
/*
* Enable timer.
*/
- u = readl(TIMER_CTRL);
- writel(u | TIMER1_EN | TIMER1_RELOAD_EN, TIMER_CTRL);
+ u = readl(timer_base + TIMER_CTRL_OFF);
+ writel(u | TIMER1_EN | TIMER1_RELOAD_EN,
+ timer_base + TIMER_CTRL_OFF);
} else {
/*
* Disable timer.
*/
- u = readl(TIMER_CTRL);
- writel(u & ~TIMER1_EN, TIMER_CTRL);
+ u = readl(timer_base + TIMER_CTRL_OFF);
+ writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF);
/*
* Disable timer interrupt.
*/
- u = readl(BRIDGE_MASK);
- writel(u & ~BRIDGE_INT_TIMER1, BRIDGE_MASK);
+ u = readl(bridge_base + BRIDGE_MASK_OFF);
+ writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF);
/*
* ACK pending timer interrupt.
*/
- writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
+ writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
}
local_irq_restore(flags);
@@ -185,7 +200,7 @@ static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
/*
* ACK timer interrupt and call event handler.
*/
- writel(BRIDGE_INT_TIMER1_CLR, BRIDGE_CAUSE);
+ writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF);
orion_clkevt.event_handler(&orion_clkevt);
return IRQ_HANDLED;
@@ -197,31 +212,45 @@ static struct irqaction orion_timer_irq = {
.handler = orion_timer_interrupt
};
-void __init orion_time_init(unsigned int irq, unsigned int tclk)
+void __init
+orion_time_set_base(u32 _timer_base)
+{
+ timer_base = (void __iomem *)_timer_base;
+}
+
+void __init
+orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,
+ unsigned int irq, unsigned int tclk)
{
u32 u;
+ /*
+ * Set SoC-specific data.
+ */
+ bridge_base = (void __iomem *)_bridge_base;
+ bridge_timer1_clr_mask = _bridge_timer1_clr_mask;
+
ticks_per_jiffy = (tclk + HZ/2) / HZ;
/*
- * Set scale and timer for sched_clock
+ * Set scale and timer for sched_clock.
*/
setup_sched_clock(tclk);
/*
* Setup free-running clocksource timer (interrupts
- * disabled.)
+ * disabled).
*/
- writel(0xffffffff, TIMER0_VAL);
- writel(0xffffffff, TIMER0_RELOAD);
- u = readl(BRIDGE_MASK);
- writel(u & ~BRIDGE_INT_TIMER0, BRIDGE_MASK);
- u = readl(TIMER_CTRL);
- writel(u | TIMER0_EN | TIMER0_RELOAD_EN, TIMER_CTRL);
+ writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
+ writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
+ u = readl(bridge_base + BRIDGE_MASK_OFF);
+ writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF);
+ u = readl(timer_base + TIMER_CTRL_OFF);
+ writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF);
clocksource_register_hz(&orion_clksrc, tclk);
/*
- * Setup clockevent timer (interrupt-driven.)
+ * Setup clockevent timer (interrupt-driven).
*/
setup_irq(irq, &orion_timer_irq);
orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift);
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index eb105e61c746..d9c4096ebf45 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -56,13 +56,6 @@ config S3C24XX_DCLK
help
Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
-config S3C24XX_PWM
- bool "PWM device support"
- select HAVE_PWM
- help
- Support for exporting the PWM timer blocks via the pwm device
- system.
-
# gpio configurations
config S3C24XX_GPIO_EXTRA
diff --git a/arch/arm/plat-s3c24xx/cpu-freq.c b/arch/arm/plat-s3c24xx/cpu-freq.c
index 25a8fc7f512e..eea75ff81d15 100644
--- a/arch/arm/plat-s3c24xx/cpu-freq.c
+++ b/arch/arm/plat-s3c24xx/cpu-freq.c
@@ -433,7 +433,7 @@ static int s3c_cpufreq_verify(struct cpufreq_policy *policy)
static struct cpufreq_frequency_table suspend_pll;
static unsigned int suspend_freq;
-static int s3c_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
+static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
{
suspend_pll.frequency = clk_get_rate(_clk_mpll);
suspend_pll.index = __raw_readl(S3C2410_MPLLCON);
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 557f8c507f6d..849229716586 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -7,10 +7,10 @@
config PLAT_S5P
bool
- depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310)
+ depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4)
default y
- select ARM_VIC if !ARCH_S5PV310
- select ARM_GIC if ARCH_S5PV310
+ select ARM_VIC if !ARCH_EXYNOS4
+ select ARM_GIC if ARCH_EXYNOS4
select NO_IOPORT
select ARCH_REQUIRE_GPIOLIB
select S3C_GPIO_TRACK
@@ -37,11 +37,16 @@ config S5P_GPIO_INT
help
Common code for the GPIO interrupts (other than external interrupts.)
+config S5P_HRT
+ bool
+ help
+ Use the High Resolution timer support
+
comment "System MMU"
config S5P_SYSTEM_MMU
bool "S5P SYSTEM MMU"
- depends on ARCH_S5PV310
+ depends on ARCH_EXYNOS4
help
Say Y here if you want to enable System MMU
@@ -60,6 +65,11 @@ config S5P_DEV_FIMC2
help
Compile in platform device definitions for FIMC controller 2
+config S5P_DEV_FIMC3
+ bool
+ help
+ Compile in platform device definitions for FIMC controller 3
+
config S5P_DEV_ONENAND
bool
help
@@ -74,3 +84,8 @@ config S5P_DEV_CSIS1
bool
help
Compile in platform device definitions for MIPI-CSIS channel 1
+
+config S5P_SETUP_MIPIPHY
+ bool
+ help
+ Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 4bd5cf908977..42afff7f60be 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -22,12 +22,15 @@ obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += irq-pm.o
+obj-$(CONFIG_S5P_HRT) += s5p-time.o
# devices
obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
+obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
+obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
index 047d31c1bbd8..c3bfe9b13acf 100644
--- a/arch/arm/plat-s5p/cpu.c
+++ b/arch/arm/plat-s5p/cpu.c
@@ -1,7 +1,7 @@
/* linux/arch/arm/plat-s5p/cpu.c
*
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* S5P CPU Support
*
@@ -12,17 +12,20 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <mach/map.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+
+#include <mach/map.h>
#include <mach/regs-clock.h>
+
#include <plat/cpu.h>
#include <plat/s5p6440.h>
#include <plat/s5p6442.h>
#include <plat/s5p6450.h>
#include <plat/s5pc100.h>
#include <plat/s5pv210.h>
-#include <plat/s5pv310.h>
+#include <plat/exynos4.h>
/* table of supported CPUs */
@@ -31,7 +34,7 @@ static const char name_s5p6442[] = "S5P6442";
static const char name_s5p6450[] = "S5P6450";
static const char name_s5pc100[] = "S5PC100";
static const char name_s5pv210[] = "S5PV210/S5PC110";
-static const char name_s5pv310[] = "S5PV310";
+static const char name_exynos4210[] = "EXYNOS4210";
static struct cpu_table cpu_ids[] __initdata = {
{
@@ -75,13 +78,13 @@ static struct cpu_table cpu_ids[] __initdata = {
.init = s5pv210_init,
.name = name_s5pv210,
}, {
- .idcode = 0x43200000,
+ .idcode = 0x43210000,
.idmask = 0xfffff000,
- .map_io = s5pv310_map_io,
- .init_clocks = s5pv310_init_clocks,
- .init_uarts = s5pv310_init_uarts,
- .init = s5pv310_init,
- .name = name_s5pv310,
+ .map_io = exynos4_map_io,
+ .init_clocks = exynos4_init_clocks,
+ .init_uarts = exynos4_init_uarts,
+ .init = exynos4_init,
+ .name = name_exynos4210,
},
};
diff --git a/arch/arm/plat-s5p/dev-csis0.c b/arch/arm/plat-s5p/dev-csis0.c
index dfab1c85f54f..e3aabef5e347 100644
--- a/arch/arm/plat-s5p/dev-csis0.c
+++ b/arch/arm/plat-s5p/dev-csis0.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Samsung Electronics
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
*
* S5P series device definition for MIPI-CSIS channel 0
*
diff --git a/arch/arm/plat-s5p/dev-csis1.c b/arch/arm/plat-s5p/dev-csis1.c
index e3053f27fbbf..08b91b580207 100644
--- a/arch/arm/plat-s5p/dev-csis1.c
+++ b/arch/arm/plat-s5p/dev-csis1.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Samsung Electronics
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
*
* S5P series device definition for MIPI-CSIS channel 1
*
diff --git a/arch/arm/plat-s5p/dev-fimc3.c b/arch/arm/plat-s5p/dev-fimc3.c
new file mode 100644
index 000000000000..ef31beca386c
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-fimc3.c
@@ -0,0 +1,43 @@
+/* linux/arch/arm/plat-s5p/dev-fimc3.c
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * Base S5P FIMC3 resource and device definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <mach/map.h>
+
+static struct resource s5p_fimc3_resource[] = {
+ [0] = {
+ .start = S5P_PA_FIMC3,
+ .end = S5P_PA_FIMC3 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FIMC3,
+ .end = IRQ_FIMC3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 s5p_fimc3_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device s5p_device_fimc3 = {
+ .name = "s5p-fimc",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(s5p_fimc3_resource),
+ .resource = s5p_fimc3_resource,
+ .dev = {
+ .dma_mask = &s5p_fimc3_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
diff --git a/arch/arm/plat-s5p/include/plat/camport.h b/arch/arm/plat-s5p/include/plat/camport.h
new file mode 100644
index 000000000000..71688c8ba288
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/camport.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P series camera interface helper functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PLAT_S5P_CAMPORT_H_
+#define PLAT_S5P_CAMPORT_H_ __FILE__
+
+enum s5p_camport_id {
+ S5P_CAMPORT_A,
+ S5P_CAMPORT_B,
+};
+
+/*
+ * The helper functions to configure GPIO for the camera parallel bus.
+ * The camera port can be multiplexed with any FIMC entity, even multiple
+ * FIMC entities are allowed to be attached to a single port simultaneously.
+ * These functions are to be used in the board setup code.
+ */
+int s5pv210_fimc_setup_gpio(enum s5p_camport_id id);
+int exynos4_fimc_setup_gpio(enum s5p_camport_id id);
+
+#endif
diff --git a/arch/arm/plat-s5p/include/plat/csis.h b/arch/arm/plat-s5p/include/plat/csis.h
deleted file mode 100644
index 51e308c7981d..000000000000
--- a/arch/arm/plat-s5p/include/plat/csis.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics
- *
- * S5P series MIPI CSI slave device support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef PLAT_S5P_CSIS_H_
-#define PLAT_S5P_CSIS_H_ __FILE__
-
-/**
- * struct s5p_platform_mipi_csis - platform data for MIPI-CSIS
- * @clk_rate: bus clock frequency
- * @lanes: number of data lanes used
- * @alignment: data alignment in bits
- * @hs_settle: HS-RX settle time
- */
-struct s5p_platform_mipi_csis {
- unsigned long clk_rate;
- u8 lanes;
- u8 alignment;
- u8 hs_settle;
-};
-
-#endif /* PLAT_S5P_CSIS_H_ */
diff --git a/arch/arm/plat-s5p/include/plat/exynos4.h b/arch/arm/plat-s5p/include/plat/exynos4.h
new file mode 100644
index 000000000000..907caab53dcf
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/exynos4.h
@@ -0,0 +1,34 @@
+/* linux/arch/arm/plat-s5p/include/plat/exynos4.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Header file for exynos4 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* Common init code for EXYNOS4 related SoCs */
+
+extern void exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+extern void exynos4_register_clocks(void);
+extern void exynos4_setup_clocks(void);
+
+#ifdef CONFIG_CPU_EXYNOS4210
+
+extern int exynos4_init(void);
+extern void exynos4_init_irq(void);
+extern void exynos4_map_io(void);
+extern void exynos4_init_clocks(int xtal);
+extern struct sys_timer exynos4_timer;
+
+#define exynos4_init_uarts exynos4_common_init_uarts
+
+#else
+#define exynos4_init_clocks NULL
+#define exynos4_init_uarts NULL
+#define exynos4_map_io NULL
+#define exynos4_init NULL
+#endif
diff --git a/arch/arm/plat-s5p/include/plat/mipi_csis.h b/arch/arm/plat-s5p/include/plat/mipi_csis.h
new file mode 100644
index 000000000000..9bd254c5ed22
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/mipi_csis.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P series MIPI CSI slave device support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef PLAT_S5P_MIPI_CSIS_H_
+#define PLAT_S5P_MIPI_CSIS_H_ __FILE__
+
+struct platform_device;
+
+/**
+ * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver
+ * @clk_rate: bus clock frequency
+ * @lanes: number of data lanes used
+ * @alignment: data alignment in bits
+ * @hs_settle: HS-RX settle time
+ * @fixed_phy_vdd: false to enable external D-PHY regulator management in the
+ * driver or true in case this regulator has no enable function
+ * @phy_enable: pointer to a callback controlling D-PHY enable/reset
+ */
+struct s5p_platform_mipi_csis {
+ unsigned long clk_rate;
+ u8 lanes;
+ u8 alignment;
+ u8 hs_settle;
+ bool fixed_phy_vdd;
+ int (*phy_enable)(struct platform_device *pdev, bool on);
+};
+
+/**
+ * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control
+ * @pdev: MIPI-CSIS platform device
+ * @on: true to enable D-PHY and deassert its reset
+ * false to disable D-PHY
+ */
+int s5p_csis_phy_enable(struct platform_device *pdev, bool on);
+
+#endif /* PLAT_S5P_MIPI_CSIS_H_ */
diff --git a/arch/arm/plat-s5p/include/plat/s5p-time.h b/arch/arm/plat-s5p/include/plat/s5p-time.h
new file mode 100644
index 000000000000..575e88109db8
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/s5p-time.h
@@ -0,0 +1,40 @@
+/* linux/arch/arm/plat-s5p/include/plat/s5p-time.h
+ *
+ * Copyright 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file for s5p time support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_S5P_TIME_H
+#define __ASM_PLAT_S5P_TIME_H __FILE__
+
+/* S5P HR-Timer Clock mode */
+enum s5p_timer_mode {
+ S5P_PWM0,
+ S5P_PWM1,
+ S5P_PWM2,
+ S5P_PWM3,
+ S5P_PWM4,
+};
+
+struct s5p_timer_source {
+ unsigned int event_id;
+ unsigned int source_id;
+};
+
+/* Be able to sleep for atleast 4 seconds (usually more) */
+#define S5PTIMER_MIN_RANGE 4
+
+#define TCNT_MAX 0xffffffff
+#define NON_PERIODIC 0
+#define PERIODIC 1
+
+extern void __init s5p_set_timer_source(enum s5p_timer_mode event,
+ enum s5p_timer_mode source);
+extern struct sys_timer s5p_timer;
+#endif /* __ASM_PLAT_S5P_TIME_H */
diff --git a/arch/arm/plat-s5p/include/plat/s5pv310.h b/arch/arm/plat-s5p/include/plat/s5pv310.h
deleted file mode 100644
index 769c991ceb37..000000000000
--- a/arch/arm/plat-s5p/include/plat/s5pv310.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* linux/arch/arm/plat-s5p/include/plat/s5pv310.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com/
- *
- * Header file for s5pv310 cpu support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* Common init code for S5PV310 related SoCs */
-
-extern void s5pv310_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-extern void s5pv310_register_clocks(void);
-extern void s5pv310_setup_clocks(void);
-
-#ifdef CONFIG_CPU_S5PV310
-
-extern int s5pv310_init(void);
-extern void s5pv310_init_irq(void);
-extern void s5pv310_map_io(void);
-extern void s5pv310_init_clocks(int xtal);
-extern struct sys_timer s5pv310_timer;
-
-#define s5pv310_init_uarts s5pv310_common_init_uarts
-
-#else
-#define s5pv310_init_clocks NULL
-#define s5pv310_init_uarts NULL
-#define s5pv310_map_io NULL
-#define s5pv310_init NULL
-#endif
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
new file mode 100644
index 000000000000..bf5283c2a19d
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,95 @@
+/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung System MMU driver for S5P platform
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM__PLAT_SYSMMU_H
+#define __ASM__PLAT_SYSMMU_H __FILE__
+
+enum S5P_SYSMMU_INTERRUPT_TYPE {
+ SYSMMU_PAGEFAULT,
+ SYSMMU_AR_MULTIHIT,
+ SYSMMU_AW_MULTIHIT,
+ SYSMMU_BUSERROR,
+ SYSMMU_AR_SECURITY,
+ SYSMMU_AR_ACCESS,
+ SYSMMU_AW_SECURITY,
+ SYSMMU_AW_PROTECTION, /* 7 */
+ SYSMMU_FAULTS_NUM
+};
+
+#ifdef CONFIG_S5P_SYSTEM_MMU
+
+#include <mach/sysmmu.h>
+
+/**
+ * s5p_sysmmu_enable() - enable system mmu of ip
+ * @ips: The ip connected system mmu.
+ * #pgd: Base physical address of the 1st level page table
+ *
+ * This function enable system mmu to transfer address
+ * from virtual address to physical address
+ */
+void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
+
+/**
+ * s5p_sysmmu_disable() - disable sysmmu mmu of ip
+ * @ips: The ip connected system mmu.
+ *
+ * This function disable system mmu to transfer address
+ * from virtual address to physical address
+ */
+void s5p_sysmmu_disable(sysmmu_ips ips);
+
+/**
+ * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
+ * @ips: The ip connected system mmu.
+ * @pgd: The page table base address.
+ *
+ * This function set page table base address
+ * When system mmu transfer address from virtaul address to physical address,
+ * system mmu refer address information from page table
+ */
+void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
+
+/**
+ * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
+ * @ips: The ip connected system mmu.
+ *
+ * This function flush all TLB entry in system mmu
+ */
+void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
+
+/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
+ * @itype: type of fault.
+ * @pgtable_base: the physical address of page table base. This is 0 if @ips is
+ * SYSMMU_BUSERROR.
+ * @fault_addr: the device (virtual) address that the System MMU tried to
+ * translated. This is 0 if @ips is SYSMMU_BUSERROR.
+ * Called when interrupt occurred by the System MMUs
+ * The device drivers of peripheral devices that has a System MMU can implement
+ * a fault handler to resolve address translation fault by System MMU.
+ * The meanings of return value and parameters are described below.
+
+ * return value: non-zero if the fault is correctly resolved.
+ * zero if the fault is not handled.
+ */
+void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
+ int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr));
+#else
+#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
+#define s5p_sysmmu_disable(ips) do { } while (0)
+#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
+#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
+#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
+#endif
+#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 3b6bf89d1739..cd87d3256e03 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -17,82 +17,79 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/slab.h>
#include <mach/map.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
-#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x))
+#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
-#define GPIOINT_CON_OFFSET 0x700
-#define GPIOINT_MASK_OFFSET 0x900
-#define GPIOINT_PEND_OFFSET 0xA00
+#define CON_OFFSET 0x700
+#define MASK_OFFSET 0x900
+#define PEND_OFFSET 0xA00
+#define REG_OFFSET(x) ((x) << 2)
-static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
-
-static int s5p_gpioint_get_group(struct irq_data *data)
-{
- struct gpio_chip *chip = irq_data_get_irq_data(data);
- struct s3c_gpio_chip *s3c_chip = container_of(chip,
- struct s3c_gpio_chip, chip);
- int group;
-
- for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++)
- if (s3c_chip == irq_chips[group])
- break;
+struct s5p_gpioint_bank {
+ struct list_head list;
+ int start;
+ int nr_groups;
+ int irq;
+ struct s3c_gpio_chip **chips;
+ void (*handler)(unsigned int, struct irq_desc *);
+};
- return group;
-}
+LIST_HEAD(banks);
static int s5p_gpioint_get_offset(struct irq_data *data)
{
- struct gpio_chip *chip = irq_data_get_irq_data(data);
- struct s3c_gpio_chip *s3c_chip = container_of(chip,
- struct s3c_gpio_chip, chip);
-
- return data->irq - s3c_chip->irq_base;
+ struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
+ return data->irq - chip->irq_base;
}
static void s5p_gpioint_ack(struct irq_data *data)
{
+ struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
int group, offset, pend_offset;
unsigned int value;
- group = s5p_gpioint_get_group(data);
+ group = chip->group;
offset = s5p_gpioint_get_offset(data);
- pend_offset = group << 2;
+ pend_offset = REG_OFFSET(group);
- value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
- value |= 1 << offset;
- __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
+ value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
+ value |= BIT(offset);
+ __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
}
static void s5p_gpioint_mask(struct irq_data *data)
{
+ struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
int group, offset, mask_offset;
unsigned int value;
- group = s5p_gpioint_get_group(data);
+ group = chip->group;
offset = s5p_gpioint_get_offset(data);
- mask_offset = group << 2;
+ mask_offset = REG_OFFSET(group);
- value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
- value |= 1 << offset;
- __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+ value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
+ value |= BIT(offset);
+ __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
}
static void s5p_gpioint_unmask(struct irq_data *data)
{
+ struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
int group, offset, mask_offset;
unsigned int value;
- group = s5p_gpioint_get_group(data);
+ group = chip->group;
offset = s5p_gpioint_get_offset(data);
- mask_offset = group << 2;
+ mask_offset = REG_OFFSET(group);
- value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
- value &= ~(1 << offset);
- __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+ value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
+ value &= ~BIT(offset);
+ __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
}
static void s5p_gpioint_mask_ack(struct irq_data *data)
@@ -103,12 +100,13 @@ static void s5p_gpioint_mask_ack(struct irq_data *data)
static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
{
+ struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
int group, offset, con_offset;
unsigned int value;
- group = s5p_gpioint_get_group(data);
+ group = chip->group;
offset = s5p_gpioint_get_offset(data);
- con_offset = group << 2;
+ con_offset = REG_OFFSET(group);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -132,15 +130,15 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
return -EINVAL;
}
- value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset);
+ value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset);
value &= ~(0x7 << (offset * 0x4));
value |= (type << (offset * 0x4));
- __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset);
+ __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset);
return 0;
}
-struct irq_chip s5p_gpioint = {
+static struct irq_chip s5p_gpioint = {
.name = "s5p_gpioint",
.irq_ack = s5p_gpioint_ack,
.irq_mask = s5p_gpioint_mask,
@@ -151,30 +149,29 @@ struct irq_chip s5p_gpioint = {
static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
{
- int group, offset, pend_offset, mask_offset;
- int real_irq;
+ struct s5p_gpioint_bank *bank = get_irq_data(irq);
+ int group, pend_offset, mask_offset;
unsigned int pend, mask;
- for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) {
- pend_offset = group << 2;
- pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) +
- pend_offset);
+ for (group = 0; group < bank->nr_groups; group++) {
+ struct s3c_gpio_chip *chip = bank->chips[group];
+ if (!chip)
+ continue;
+
+ pend_offset = REG_OFFSET(group);
+ pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
if (!pend)
continue;
- mask_offset = group << 2;
- mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) +
- mask_offset);
+ mask_offset = REG_OFFSET(group);
+ mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
pend &= ~mask;
- for (offset = 0; offset < 8; offset++) {
- if (pend & (1 << offset)) {
- struct s3c_gpio_chip *chip = irq_chips[group];
- if (chip) {
- real_irq = chip->irq_base + offset;
- generic_handle_irq(real_irq);
- }
- }
+ while (pend) {
+ int offset = fls(pend) - 1;
+ int real_irq = chip->irq_base + offset;
+ generic_handle_irq(real_irq);
+ pend &= ~BIT(offset);
}
}
}
@@ -182,27 +179,48 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
{
static int used_gpioint_groups = 0;
- static bool handler_registered = 0;
int irq, group = chip->group;
int i;
+ struct s5p_gpioint_bank *bank = NULL;
if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
return -ENOMEM;
+ list_for_each_entry(bank, &banks, list) {
+ if (group >= bank->start &&
+ group < bank->start + bank->nr_groups)
+ break;
+ }
+ if (!bank)
+ return -EINVAL;
+
+ if (!bank->handler) {
+ bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) *
+ bank->nr_groups, GFP_KERNEL);
+ if (!bank->chips)
+ return -ENOMEM;
+
+ set_irq_chained_handler(bank->irq, s5p_gpioint_handler);
+ set_irq_data(bank->irq, bank);
+ bank->handler = s5p_gpioint_handler;
+ printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
+ bank->irq);
+ }
+
+ /*
+ * chained GPIO irq has been sucessfully registered, allocate new gpio
+ * int group and assign irq nubmers
+ */
+
chip->irq_base = S5P_GPIOINT_BASE +
used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
used_gpioint_groups++;
- if (!handler_registered) {
- set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
- handler_registered = 1;
- }
-
- irq_chips[group] = chip;
+ bank->chips[group - bank->start] = chip;
for (i = 0; i < chip->chip.ngpio; i++) {
irq = chip->irq_base + i;
set_irq_chip(irq, &s5p_gpioint);
- set_irq_data(irq, &chip->chip);
+ set_irq_data(irq, chip);
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
@@ -235,3 +253,19 @@ int __init s5p_register_gpio_interrupt(int pin)
}
return ret;
}
+
+int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
+{
+ struct s5p_gpioint_bank *bank;
+
+ bank = kzalloc(sizeof(*bank), GFP_KERNEL);
+ if (!bank)
+ return -ENOMEM;
+
+ bank->start = start;
+ bank->nr_groups = nr_groups;
+ bank->irq = chain_irq;
+
+ list_add_tail(&bank->list, &banks);
+ return 0;
+}
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
new file mode 100644
index 000000000000..8090403eec0f
--- /dev/null
+++ b/arch/arm/plat-s5p/s5p-time.c
@@ -0,0 +1,448 @@
+/* linux/arch/arm/plat-s5p/s5p-time.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * S5P - Common hr-timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/platform_device.h>
+
+#include <asm/smp_twd.h>
+#include <asm/mach/time.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/sched_clock.h>
+
+#include <mach/map.h>
+#include <plat/devs.h>
+#include <plat/regs-timer.h>
+#include <plat/s5p-time.h>
+
+static struct clk *tin_event;
+static struct clk *tin_source;
+static struct clk *tdiv_event;
+static struct clk *tdiv_source;
+static struct clk *timerclk;
+static struct s5p_timer_source timer_source;
+static unsigned long clock_count_per_tick;
+static void s5p_timer_resume(void);
+
+static void s5p_time_stop(enum s5p_timer_mode mode)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (mode) {
+ case S5P_PWM0:
+ tcon &= ~S3C2410_TCON_T0START;
+ break;
+
+ case S5P_PWM1:
+ tcon &= ~S3C2410_TCON_T1START;
+ break;
+
+ case S5P_PWM2:
+ tcon &= ~S3C2410_TCON_T2START;
+ break;
+
+ case S5P_PWM3:
+ tcon &= ~S3C2410_TCON_T3START;
+ break;
+
+ case S5P_PWM4:
+ tcon &= ~S3C2410_TCON_T4START;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", mode);
+ break;
+ }
+ __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ tcnt--;
+
+ switch (mode) {
+ case S5P_PWM0:
+ tcon &= ~(0x0f << 0);
+ tcon |= S3C2410_TCON_T0MANUALUPD;
+ break;
+
+ case S5P_PWM1:
+ tcon &= ~(0x0f << 8);
+ tcon |= S3C2410_TCON_T1MANUALUPD;
+ break;
+
+ case S5P_PWM2:
+ tcon &= ~(0x0f << 12);
+ tcon |= S3C2410_TCON_T2MANUALUPD;
+ break;
+
+ case S5P_PWM3:
+ tcon &= ~(0x0f << 16);
+ tcon |= S3C2410_TCON_T3MANUALUPD;
+ break;
+
+ case S5P_PWM4:
+ tcon &= ~(0x07 << 20);
+ tcon |= S3C2410_TCON_T4MANUALUPD;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", mode);
+ break;
+ }
+
+ __raw_writel(tcnt, S3C2410_TCNTB(mode));
+ __raw_writel(tcnt, S3C2410_TCMPB(mode));
+ __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s5p_time_start(enum s5p_timer_mode mode, bool periodic)
+{
+ unsigned long tcon;
+
+ tcon = __raw_readl(S3C2410_TCON);
+
+ switch (mode) {
+ case S5P_PWM0:
+ tcon |= S3C2410_TCON_T0START;
+ tcon &= ~S3C2410_TCON_T0MANUALUPD;
+
+ if (periodic)
+ tcon |= S3C2410_TCON_T0RELOAD;
+ else
+ tcon &= ~S3C2410_TCON_T0RELOAD;
+ break;
+
+ case S5P_PWM1:
+ tcon |= S3C2410_TCON_T1START;
+ tcon &= ~S3C2410_TCON_T1MANUALUPD;
+
+ if (periodic)
+ tcon |= S3C2410_TCON_T1RELOAD;
+ else
+ tcon &= ~S3C2410_TCON_T1RELOAD;
+ break;
+
+ case S5P_PWM2:
+ tcon |= S3C2410_TCON_T2START;
+ tcon &= ~S3C2410_TCON_T2MANUALUPD;
+
+ if (periodic)
+ tcon |= S3C2410_TCON_T2RELOAD;
+ else
+ tcon &= ~S3C2410_TCON_T2RELOAD;
+ break;
+
+ case S5P_PWM3:
+ tcon |= S3C2410_TCON_T3START;
+ tcon &= ~S3C2410_TCON_T3MANUALUPD;
+
+ if (periodic)
+ tcon |= S3C2410_TCON_T3RELOAD;
+ else
+ tcon &= ~S3C2410_TCON_T3RELOAD;
+ break;
+
+ case S5P_PWM4:
+ tcon |= S3C2410_TCON_T4START;
+ tcon &= ~S3C2410_TCON_T4MANUALUPD;
+
+ if (periodic)
+ tcon |= S3C2410_TCON_T4RELOAD;
+ else
+ tcon &= ~S3C2410_TCON_T4RELOAD;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", mode);
+ break;
+ }
+ __raw_writel(tcon, S3C2410_TCON);
+}
+
+static int s5p_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ s5p_time_setup(timer_source.event_id, cycles);
+ s5p_time_start(timer_source.event_id, NON_PERIODIC);
+
+ return 0;
+}
+
+static void s5p_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ s5p_time_stop(timer_source.event_id);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ s5p_time_setup(timer_source.event_id, clock_count_per_tick);
+ s5p_time_start(timer_source.event_id, PERIODIC);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ s5p_timer_resume();
+ break;
+ }
+}
+
+static void s5p_timer_resume(void)
+{
+ /* event timer restart */
+ s5p_time_setup(timer_source.event_id, clock_count_per_tick);
+ s5p_time_start(timer_source.event_id, PERIODIC);
+
+ /* source timer restart */
+ s5p_time_setup(timer_source.source_id, TCNT_MAX);
+ s5p_time_start(timer_source.source_id, PERIODIC);
+}
+
+void __init s5p_set_timer_source(enum s5p_timer_mode event,
+ enum s5p_timer_mode source)
+{
+ s3c_device_timer[event].dev.bus = &platform_bus_type;
+ s3c_device_timer[source].dev.bus = &platform_bus_type;
+
+ timer_source.event_id = event;
+ timer_source.source_id = source;
+}
+
+static struct clock_event_device time_event_device = {
+ .name = "s5p_event_timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .set_next_event = s5p_set_next_event,
+ .set_mode = s5p_set_mode,
+};
+
+static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction s5p_clock_event_irq = {
+ .name = "s5p_time_irq",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = s5p_clock_event_isr,
+ .dev_id = &time_event_device,
+};
+
+static void __init s5p_clockevent_init(void)
+{
+ unsigned long pclk;
+ unsigned long clock_rate;
+ unsigned int irq_number;
+ struct clk *tscaler;
+
+ pclk = clk_get_rate(timerclk);
+
+ tscaler = clk_get_parent(tdiv_event);
+
+ clk_set_rate(tscaler, pclk / 2);
+ clk_set_rate(tdiv_event, pclk / 2);
+ clk_set_parent(tin_event, tdiv_event);
+
+ clock_rate = clk_get_rate(tin_event);
+ clock_count_per_tick = clock_rate / HZ;
+
+ clockevents_calc_mult_shift(&time_event_device,
+ clock_rate, S5PTIMER_MIN_RANGE);
+ time_event_device.max_delta_ns =
+ clockevent_delta2ns(-1, &time_event_device);
+ time_event_device.min_delta_ns =
+ clockevent_delta2ns(1, &time_event_device);
+
+ time_event_device.cpumask = cpumask_of(0);
+ clockevents_register_device(&time_event_device);
+
+ irq_number = timer_source.event_id + IRQ_TIMER0;
+ setup_irq(irq_number, &s5p_clock_event_irq);
+}
+
+static cycle_t s5p_timer_read(struct clocksource *cs)
+{
+ unsigned long offset = 0;
+
+ switch (timer_source.source_id) {
+ case S5P_PWM0:
+ case S5P_PWM1:
+ case S5P_PWM2:
+ case S5P_PWM3:
+ offset = (timer_source.source_id * 0x0c) + 0x14;
+ break;
+
+ case S5P_PWM4:
+ offset = 0x40;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
+ return 0;
+ }
+
+ return (cycle_t) ~__raw_readl(S3C_TIMERREG(offset));
+}
+
+/*
+ * Override the global weak sched_clock symbol with this
+ * local implementation which uses the clocksource to get some
+ * better resolution when scheduling the kernel. We accept that
+ * this wraps around for now, since it is just a relative time
+ * stamp. (Inspired by U300 implementation.)
+ */
+static DEFINE_CLOCK_DATA(cd);
+
+unsigned long long notrace sched_clock(void)
+{
+ u32 cyc;
+ unsigned long offset = 0;
+
+ switch (timer_source.source_id) {
+ case S5P_PWM0:
+ case S5P_PWM1:
+ case S5P_PWM2:
+ case S5P_PWM3:
+ offset = (timer_source.source_id * 0x0c) + 0x14;
+ break;
+
+ case S5P_PWM4:
+ offset = 0x40;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
+ return 0;
+ }
+
+ cyc = ~__raw_readl(S3C_TIMERREG(offset));
+ return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+}
+
+static void notrace s5p_update_sched_clock(void)
+{
+ u32 cyc;
+ unsigned long offset = 0;
+
+ switch (timer_source.source_id) {
+ case S5P_PWM0:
+ case S5P_PWM1:
+ case S5P_PWM2:
+ case S5P_PWM3:
+ offset = (timer_source.source_id * 0x0c) + 0x14;
+ break;
+
+ case S5P_PWM4:
+ offset = 0x40;
+ break;
+
+ default:
+ printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
+ }
+
+ cyc = ~__raw_readl(S3C_TIMERREG(offset));
+ update_sched_clock(&cd, cyc, (u32)~0);
+}
+
+struct clocksource time_clocksource = {
+ .name = "s5p_clocksource_timer",
+ .rating = 250,
+ .read = s5p_timer_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init s5p_clocksource_init(void)
+{
+ unsigned long pclk;
+ unsigned long clock_rate;
+
+ pclk = clk_get_rate(timerclk);
+
+ clk_set_rate(tdiv_source, pclk / 2);
+ clk_set_parent(tin_source, tdiv_source);
+
+ clock_rate = clk_get_rate(tin_source);
+
+ init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
+
+ s5p_time_setup(timer_source.source_id, TCNT_MAX);
+ s5p_time_start(timer_source.source_id, PERIODIC);
+
+ if (clocksource_register_hz(&time_clocksource, clock_rate))
+ panic("%s: can't register clocksource\n", time_clocksource.name);
+}
+
+static void __init s5p_timer_resources(void)
+{
+
+ unsigned long event_id = timer_source.event_id;
+ unsigned long source_id = timer_source.source_id;
+
+ timerclk = clk_get(NULL, "timers");
+ if (IS_ERR(timerclk))
+ panic("failed to get timers clock for timer");
+
+ clk_enable(timerclk);
+
+ tin_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tin");
+ if (IS_ERR(tin_event))
+ panic("failed to get pwm-tin clock for event timer");
+
+ tdiv_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tdiv");
+ if (IS_ERR(tdiv_event))
+ panic("failed to get pwm-tdiv clock for event timer");
+
+ clk_enable(tin_event);
+
+ tin_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tin");
+ if (IS_ERR(tin_source))
+ panic("failed to get pwm-tin clock for source timer");
+
+ tdiv_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tdiv");
+ if (IS_ERR(tdiv_source))
+ panic("failed to get pwm-tdiv clock for source timer");
+
+ clk_enable(tin_source);
+}
+
+static void __init s5p_timer_init(void)
+{
+ s5p_timer_resources();
+ s5p_clockevent_init();
+ s5p_clocksource_init();
+}
+
+struct sys_timer s5p_timer = {
+ .init = s5p_timer_init,
+};
diff --git a/arch/arm/plat-s5p/setup-mipiphy.c b/arch/arm/plat-s5p/setup-mipiphy.c
new file mode 100644
index 000000000000..683c466c0e6a
--- /dev/null
+++ b/arch/arm/plat-s5p/setup-mipiphy.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P - Helper functions for MIPI-CSIS and MIPI-DSIM D-PHY control
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <mach/regs-clock.h>
+
+static int __s5p_mipi_phy_control(struct platform_device *pdev,
+ bool on, u32 reset)
+{
+ static DEFINE_SPINLOCK(lock);
+ void __iomem *addr;
+ unsigned long flags;
+ int pid;
+ u32 cfg;
+
+ if (!pdev)
+ return -EINVAL;
+
+ pid = (pdev->id == -1) ? 0 : pdev->id;
+
+ if (pid != 0 && pid != 1)
+ return -EINVAL;
+
+ addr = S5P_MIPI_DPHY_CONTROL(pid);
+
+ spin_lock_irqsave(&lock, flags);
+
+ cfg = __raw_readl(addr);
+ cfg = on ? (cfg | reset) : (cfg & ~reset);
+ __raw_writel(cfg, addr);
+
+ if (on) {
+ cfg |= S5P_MIPI_DPHY_ENABLE;
+ } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN |
+ S5P_MIPI_DPHY_MRESETN) & ~reset)) {
+ cfg &= ~S5P_MIPI_DPHY_ENABLE;
+ }
+
+ __raw_writel(cfg, addr);
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+int s5p_csis_phy_enable(struct platform_device *pdev, bool on)
+{
+ return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN);
+}
+
+int s5p_dsim_phy_enable(struct platform_device *pdev, bool on)
+{
+ return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN);
+}
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
index ffe8a48bc3c1..54f5eddc921d 100644
--- a/arch/arm/plat-s5p/sysmmu.c
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -12,280 +12,266 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <asm/pgtable.h>
+
#include <mach/map.h>
#include <mach/regs-sysmmu.h>
-#include <mach/sysmmu.h>
+#include <plat/sysmmu.h>
+
+#define CTRL_ENABLE 0x5
+#define CTRL_BLOCK 0x7
+#define CTRL_DISABLE 0x0
+
+static struct device *dev;
+
+static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
+ S5P_PAGE_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_DEFAULT_SLAVE_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AR_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR,
+ S5P_AW_FAULT_ADDR
+};
+
+static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
+ "PAGE FAULT",
+ "AR MULTI-HIT FAULT",
+ "AW MULTI-HIT FAULT",
+ "BUS ERROR",
+ "AR SECURITY PROTECTION FAULT",
+ "AR ACCESS PROTECTION FAULT",
+ "AW SECURITY PROTECTION FAULT",
+ "AW ACCESS PROTECTION FAULT"
+};
-struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
+static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
+ enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr);
-void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
+/*
+ * If adjacent 2 bits are true, the system MMU is enabled.
+ * The system MMU is disabled, otherwise.
+ */
+static unsigned long sysmmu_states;
+
+static inline void set_sysmmu_active(sysmmu_ips ips)
{
- unsigned int reg_mmu_ctrl;
- unsigned int reg_mmu_status;
- unsigned int reg_pt_base_addr;
- unsigned int reg_int_status;
- unsigned int reg_page_ft_addr;
-
- reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
- reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
- reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
- reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
- reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
-
- printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
- printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
- printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
- printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
-
- switch (reg_int_status & 0xFF) {
- case 0x1:
- printk(KERN_INFO "%s: Page fault\n", __func__);
- printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
- break;
- case 0x2:
- printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
- break;
- case 0x4:
- printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
- break;
- case 0x8:
- printk(KERN_INFO "%s: Bus error\n", __func__);
- break;
- case 0x10:
- printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
- break;
- case 0x20:
- printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
- break;
- case 0x40:
- printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
- break;
- case 0x80:
- printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
- break;
- }
+ sysmmu_states |= 3 << (ips * 2);
}
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
+static inline void set_sysmmu_inactive(sysmmu_ips ips)
{
- unsigned int i;
- unsigned int reg_int_status;
- struct sysmmu_controller *sysmmuconp;
-
- for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
- sysmmuconp = &s5p_sysmmu_cntlrs[i];
-
- if (sysmmuconp->enable == true) {
- reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
-
- if (reg_int_status & 0xFF)
- s5p_sysmmu_register(sysmmuconp);
- }
- }
- return IRQ_HANDLED;
+ sysmmu_states &= ~(3 << (ips * 2));
}
-int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
+static inline int is_sysmmu_active(sysmmu_ips ips)
{
- struct sysmmu_controller *sysmmuconp = NULL;
-
- sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- return 1;
- }
-
- /* Set sysmmu page table base address */
- __raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
+ return sysmmu_states & (3 << (ips * 2));
+}
- if (s5p_sysmmu_tlb_invalidate(ips) != 0)
- printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
+static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
- return 0;
+static inline void sysmmu_block(sysmmu_ips ips)
+{
+ __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
+ dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
}
-static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
+static inline void sysmmu_unblock(sysmmu_ips ips)
{
- unsigned int pg;
- struct sysmmu_controller *sysmmuconp;
+ __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
+ dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
+}
- sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
+{
+ __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
+ dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
+}
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- return 1;
+static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
+{
+ if (unlikely(pgd == 0)) {
+ pgd = (unsigned long)ZERO_PAGE(0);
+ __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
+ } else {
+ __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
}
- __asm__("mrc p15, 0, %0, c2, c0, 0" \
- : "=r" (pg) : : "cc"); \
- pg &= ~0x3fff;
+ __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
- printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
-
- /* Set sysmmu page table base address */
- __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
+ dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
+ sysmmu_ips_name[ips], pgd);
+ __sysmmu_tlb_invalidate(ips);
+}
- return 0;
+void sysmmu_set_fault_handler(sysmmu_ips ips,
+ int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr))
+{
+ BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
+ fault_handlers[ips] = handler;
}
-int s5p_sysmmu_enable(sysmmu_ips ips)
+static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
{
- unsigned int reg;
+ /* SYSMMU is in blocked when interrupt occurred. */
+ unsigned long base = 0;
+ sysmmu_ips ips = (sysmmu_ips)dev_id;
+ enum S5P_SYSMMU_INTERRUPT_TYPE itype;
- struct sysmmu_controller *sysmmuconp;
+ itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
+ __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
- sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+ BUG_ON(!((itype >= 0) && (itype < 8)));
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- return 1;
- }
+ dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
+ sysmmu_ips_name[ips]);
- s5p_sysmmu_set_tablebase(ips);
+ if (fault_handlers[ips]) {
+ unsigned long addr;
- /* replacement policy : LRU */
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
- reg |= 0x1;
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
+ base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
+ addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
- /* Enable interrupt, Enable MMU */
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
- reg |= (0x1 << 2) | (0x1 << 0);
+ if (fault_handlers[ips](itype, base, addr)) {
+ __raw_writel(1 << itype,
+ sysmmusfrs[ips] + S5P_INT_CLEAR);
+ dev_notice(dev, "%s from %s is resolved."
+ " Retrying translation.\n",
+ sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
+ } else {
+ base = 0;
+ }
+ }
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+ sysmmu_unblock(ips);
- sysmmuconp->enable = true;
+ if (!base)
+ dev_notice(dev, "%s from %s is not handled.\n",
+ sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
- return 0;
+ return IRQ_HANDLED;
}
-int s5p_sysmmu_disable(sysmmu_ips ips)
+void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
{
- unsigned int reg;
-
- struct sysmmu_controller *sysmmuconp = NULL;
-
- if (ips > S5P_SYSMMU_TOTAL_IPNUM)
- printk(KERN_ERR "failed to get ips parameter\n");
-
- sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- return 1;
+ if (is_sysmmu_active(ips)) {
+ sysmmu_block(ips);
+ __sysmmu_set_ptbase(ips, pgd);
+ sysmmu_unblock(ips);
+ } else {
+ dev_dbg(dev, "%s is disabled. "
+ "Skipping initializing page table base.\n",
+ sysmmu_ips_name[ips]);
}
+}
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
-
- /* replacement policy : LRU */
- reg |= 0x1;
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
-
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
+{
+ if (!is_sysmmu_active(ips)) {
+ sysmmu_clk_enable(ips);
- /* Disable MMU */
- reg &= ~0x1;
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+ __sysmmu_set_ptbase(ips, pgd);
- sysmmuconp->enable = false;
+ __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- return 0;
+ set_sysmmu_active(ips);
+ dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
+ } else {
+ dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
+ }
}
-int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
+void s5p_sysmmu_disable(sysmmu_ips ips)
{
- unsigned int reg;
- struct sysmmu_controller *sysmmuconp = NULL;
-
- sysmmuconp = &s5p_sysmmu_cntlrs[ips];
-
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- return 1;
+ if (is_sysmmu_active(ips)) {
+ __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
+ set_sysmmu_inactive(ips);
+ sysmmu_clk_disable(ips);
+ dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
+ } else {
+ dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
}
+}
- /* set Block MMU for flush TLB */
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
- reg |= 0x1 << 1;
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
- /* flush all TLB entry */
- __raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH);
-
- /* set Un-block MMU after flush TLB */
- reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
- reg &= ~(0x1 << 1);
- __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
-
- return 0;
+void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
+{
+ if (is_sysmmu_active(ips)) {
+ sysmmu_block(ips);
+ __sysmmu_tlb_invalidate(ips);
+ sysmmu_unblock(ips);
+ } else {
+ dev_dbg(dev, "%s is disabled. "
+ "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
+ }
}
static int s5p_sysmmu_probe(struct platform_device *pdev)
{
- int i;
- int ret;
- struct resource *res;
- struct sysmmu_controller *sysmmuconp;
- sysmmu_ips ips;
+ int i, ret;
+ struct resource *res, *mem;
+
+ dev = &pdev->dev;
for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
- sysmmuconp = &s5p_sysmmu_cntlrs[i];
- if (sysmmuconp == NULL) {
- printk(KERN_ERR "failed to get ip's sysmmu info\n");
- ret = -ENOENT;
- goto err_res;
- }
+ int irq;
- sysmmuconp->name = sysmmu_ips_name[i];
+ sysmmu_clk_init(dev, i);
+ sysmmu_clk_disable(i);
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (!res) {
- printk(KERN_ERR "failed to get sysmmu resource\n");
+ dev_err(dev, "Failed to get the resource of %s.\n",
+ sysmmu_ips_name[i]);
ret = -ENODEV;
goto err_res;
}
- sysmmuconp->mem = request_mem_region(res->start,
+ mem = request_mem_region(res->start,
((res->end) - (res->start)) + 1, pdev->name);
- if (!sysmmuconp->mem) {
- pr_err("failed to request sysmmu memory region\n");
+ if (!mem) {
+ dev_err(dev, "Failed to request the memory region of %s.\n",
+ sysmmu_ips_name[i]);
ret = -EBUSY;
goto err_res;
}
- sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1);
- if (!sysmmuconp->regs) {
- pr_err("failed to sysmmu ioremap\n");
+ sysmmusfrs[i] = ioremap(res->start, res->end - res->start + 1);
+ if (!sysmmusfrs[i]) {
+ dev_err(dev, "Failed to ioremap() for %s.\n",
+ sysmmu_ips_name[i]);
ret = -ENXIO;
goto err_reg;
}
- sysmmuconp->irq = platform_get_irq(pdev, i);
- if (sysmmuconp->irq <= 0) {
- pr_err("failed to get sysmmu irq resource\n");
+ irq = platform_get_irq(pdev, i);
+ if (irq <= 0) {
+ dev_err(dev, "Failed to get the IRQ resource of %s.\n",
+ sysmmu_ips_name[i]);
ret = -ENOENT;
goto err_map;
}
- ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp);
- if (ret) {
- pr_err("failed to request irq\n");
+ if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
+ pdev->name, (void *)i)) {
+ dev_err(dev, "Failed to request IRQ for %s.\n",
+ sysmmu_ips_name[i]);
ret = -ENOENT;
goto err_map;
}
-
- ips = (sysmmu_ips)i;
-
- sysmmuconp->ips = ips;
}
return 0;
-err_reg:
- release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
err_map:
- iounmap(sysmmuconp->regs);
+ iounmap(sysmmusfrs[i]);
+err_reg:
+ release_mem_region(mem->start, resource_size(mem));
err_res:
return ret;
}
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 32be05cf82a3..be72100b81b4 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -273,6 +273,19 @@ config SAMSUNG_DEV_KEYPAD
help
Compile in platform device definitions for keypad
+config SAMSUNG_DEV_PWM
+ bool
+ default y if ARCH_S3C2410
+ help
+ Compile in platform device definition for PWM Timer
+
+config S3C24XX_PWM
+ bool "PWM device support"
+ select HAVE_PWM
+ help
+ Support for exporting the PWM timer blocks via the pwm device
+ system
+
# DMA
config S3C_DMA
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 29932f88a8d6..e9de58a2e294 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_SAMSUNG_DEV_ADC) += dev-adc.o
obj-$(CONFIG_SAMSUNG_DEV_IDE) += dev-ide.o
obj-$(CONFIG_SAMSUNG_DEV_TS) += dev-ts.o
obj-$(CONFIG_SAMSUNG_DEV_KEYPAD) += dev-keypad.o
+obj-$(CONFIG_SAMSUNG_DEV_PWM) += dev-pwm.o
# DMA support
diff --git a/arch/arm/plat-samsung/dev-pwm.c b/arch/arm/plat-samsung/dev-pwm.c
new file mode 100644
index 000000000000..dab47b0e1900
--- /dev/null
+++ b/arch/arm/plat-samsung/dev-pwm.c
@@ -0,0 +1,53 @@
+/* linux/arch/arm/plat-samsung/dev-pwm.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Copyright (c) 2007 Ben Dooks
+ * Copyright (c) 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
+ *
+ * S3C series device definition for the PWM timer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+
+#include <plat/devs.h>
+
+#define TIMER_RESOURCE_SIZE (1)
+
+#define TIMER_RESOURCE(_tmr, _irq) \
+ (struct resource [TIMER_RESOURCE_SIZE]) { \
+ [0] = { \
+ .start = _irq, \
+ .end = _irq, \
+ .flags = IORESOURCE_IRQ \
+ } \
+ }
+
+#define DEFINE_S3C_TIMER(_tmr_no, _irq) \
+ .name = "s3c24xx-pwm", \
+ .id = _tmr_no, \
+ .num_resources = TIMER_RESOURCE_SIZE, \
+ .resource = TIMER_RESOURCE(_tmr_no, _irq), \
+
+/*
+ * since we already have an static mapping for the timer,
+ * we do not bother setting any IO resource for the base.
+ */
+
+struct platform_device s3c_device_timer[] = {
+ [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },
+ [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },
+ [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },
+ [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
+ [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
+};
+EXPORT_SYMBOL(s3c_device_timer);
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 9addb3dfb4bc..cedfff51c82b 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -82,6 +82,7 @@ extern struct sysdev_class s3c64xx_sysclass;
extern struct sysdev_class s5p64x0_sysclass;
extern struct sysdev_class s5p6442_sysclass;
extern struct sysdev_class s5pv210_sysclass;
+extern struct sysdev_class exynos4_sysclass;
extern void (*s5pc1xx_idle)(void);
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index b4d208b42957..f0da6b70fba4 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -1,5 +1,8 @@
/* arch/arm/plat-samsung/include/plat/devs.h
*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
@@ -96,15 +99,16 @@ extern struct platform_device s5pv210_device_iis1;
extern struct platform_device s5pv210_device_iis2;
extern struct platform_device s5pv210_device_spdif;
-extern struct platform_device s5pv310_device_ac97;
-extern struct platform_device s5pv310_device_pcm0;
-extern struct platform_device s5pv310_device_pcm1;
-extern struct platform_device s5pv310_device_pcm2;
-extern struct platform_device s5pv310_device_i2s0;
-extern struct platform_device s5pv310_device_i2s1;
-extern struct platform_device s5pv310_device_i2s2;
-extern struct platform_device s5pv310_device_spdif;
-extern struct platform_device s5pv310_device_pd[];
+extern struct platform_device exynos4_device_ac97;
+extern struct platform_device exynos4_device_pcm0;
+extern struct platform_device exynos4_device_pcm1;
+extern struct platform_device exynos4_device_pcm2;
+extern struct platform_device exynos4_device_i2s0;
+extern struct platform_device exynos4_device_i2s1;
+extern struct platform_device exynos4_device_i2s2;
+extern struct platform_device exynos4_device_spdif;
+extern struct platform_device exynos4_device_pd[];
+extern struct platform_device exynos4_device_ahci;
extern struct platform_device s5p6442_device_pcm0;
extern struct platform_device s5p6442_device_pcm1;
@@ -133,11 +137,12 @@ extern struct platform_device samsung_device_keypad;
extern struct platform_device s5p_device_fimc0;
extern struct platform_device s5p_device_fimc1;
extern struct platform_device s5p_device_fimc2;
+extern struct platform_device s5p_device_fimc3;
extern struct platform_device s5p_device_mipi_csis0;
extern struct platform_device s5p_device_mipi_csis1;
-extern struct platform_device s5pv310_device_sysmmu;
+extern struct platform_device exynos4_device_sysmmu;
/* s3c2440 specific devices */
diff --git a/arch/arm/plat-samsung/include/plat/fimc-core.h b/arch/arm/plat-samsung/include/plat/fimc-core.h
index 81a3bfeeccad..945a99d59563 100644
--- a/arch/arm/plat-samsung/include/plat/fimc-core.h
+++ b/arch/arm/plat-samsung/include/plat/fimc-core.h
@@ -38,6 +38,11 @@ static inline void s3c_fimc_setname(int id, char *name)
s5p_device_fimc2.name = name;
break;
#endif
+#ifdef CONFIG_S5P_DEV_FIMC3
+ case 3:
+ s5p_device_fimc3.name = name;
+ break;
+#endif
}
}
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index e4b5cf126fa9..5e04fa6eda74 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -225,4 +225,20 @@ extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr);
*/
extern int s5p_register_gpio_interrupt(int pin);
+/** s5p_register_gpioint_bank() - add gpio bank for further gpio interrupt
+ * registration (see s5p_register_gpio_interrupt function)
+ * @chain_irq: chained irq number for the gpio int handler for this bank
+ * @start: start gpio group number of this bank
+ * @nr_groups: number of gpio groups handled by this bank
+ *
+ * This functions registers initial information about gpio banks that
+ * can be later used by the s5p_register_gpio_interrupt() function to
+ * enable support for gpio interrupt for particular gpio group.
+ */
+#ifdef CONFIG_S5P_GPIO_INT
+extern int s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups);
+#else
+#define s5p_register_gpioint_bank(chain_irq, start, nr_groups) do { } while (0)
+#endif
+
#endif /* __PLAT_GPIO_CFG_H */
diff --git a/arch/arm/plat-samsung/include/plat/pd.h b/arch/arm/plat-samsung/include/plat/pd.h
index 5f0ad85783db..abb4bc32716a 100644
--- a/arch/arm/plat-samsung/include/plat/pd.h
+++ b/arch/arm/plat-samsung/include/plat/pd.h
@@ -1,6 +1,6 @@
/* linux/arch/arm/plat-samsung/include/plat/pd.h
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
@@ -17,7 +17,7 @@ struct samsung_pd_info {
void __iomem *base;
};
-enum s5pv310_pd_block {
+enum exynos4_pd_block {
PD_MFC,
PD_G3D,
PD_LCD0,
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index 5a41a0b69eec..b0bdf16549d5 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -1,4 +1,7 @@
-/* linux/arch/arm/plat-s3c/include/plat/sdhci.h
+/* linux/arch/arm/plat-samsung/include/plat/sdhci.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
@@ -119,10 +122,10 @@ extern void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
-extern void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
-extern void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
-extern void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
-extern void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
+extern void exynos4_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void exynos4_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+extern void exynos4_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
+extern void exynos4_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
/* S3C2416 SDHCI setup */
@@ -334,57 +337,57 @@ static inline void s5pv210_default_sdhci3(void) { }
#endif /* CONFIG_S5PV210_SETUP_SDHCI */
-/* S5PV310 SDHCI setup */
-#ifdef CONFIG_S5PV310_SETUP_SDHCI
-extern char *s5pv310_hsmmc_clksrcs[4];
+/* EXYNOS4 SDHCI setup */
+#ifdef CONFIG_EXYNOS4_SETUP_SDHCI
+extern char *exynos4_hsmmc_clksrcs[4];
-extern void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev,
+extern void exynos4_setup_sdhci_cfg_card(struct platform_device *dev,
void __iomem *r,
struct mmc_ios *ios,
struct mmc_card *card);
-static inline void s5pv310_default_sdhci0(void)
+static inline void exynos4_default_sdhci0(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC
- s3c_hsmmc0_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
- s3c_hsmmc0_def_platdata.cfg_gpio = s5pv310_setup_sdhci0_cfg_gpio;
- s3c_hsmmc0_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+ s3c_hsmmc0_def_platdata.clocks = exynos4_hsmmc_clksrcs;
+ s3c_hsmmc0_def_platdata.cfg_gpio = exynos4_setup_sdhci0_cfg_gpio;
+ s3c_hsmmc0_def_platdata.cfg_card = exynos4_setup_sdhci_cfg_card;
#endif
}
-static inline void s5pv310_default_sdhci1(void)
+static inline void exynos4_default_sdhci1(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC1
- s3c_hsmmc1_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
- s3c_hsmmc1_def_platdata.cfg_gpio = s5pv310_setup_sdhci1_cfg_gpio;
- s3c_hsmmc1_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+ s3c_hsmmc1_def_platdata.clocks = exynos4_hsmmc_clksrcs;
+ s3c_hsmmc1_def_platdata.cfg_gpio = exynos4_setup_sdhci1_cfg_gpio;
+ s3c_hsmmc1_def_platdata.cfg_card = exynos4_setup_sdhci_cfg_card;
#endif
}
-static inline void s5pv310_default_sdhci2(void)
+static inline void exynos4_default_sdhci2(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC2
- s3c_hsmmc2_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
- s3c_hsmmc2_def_platdata.cfg_gpio = s5pv310_setup_sdhci2_cfg_gpio;
- s3c_hsmmc2_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+ s3c_hsmmc2_def_platdata.clocks = exynos4_hsmmc_clksrcs;
+ s3c_hsmmc2_def_platdata.cfg_gpio = exynos4_setup_sdhci2_cfg_gpio;
+ s3c_hsmmc2_def_platdata.cfg_card = exynos4_setup_sdhci_cfg_card;
#endif
}
-static inline void s5pv310_default_sdhci3(void)
+static inline void exynos4_default_sdhci3(void)
{
#ifdef CONFIG_S3C_DEV_HSMMC3
- s3c_hsmmc3_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
- s3c_hsmmc3_def_platdata.cfg_gpio = s5pv310_setup_sdhci3_cfg_gpio;
- s3c_hsmmc3_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+ s3c_hsmmc3_def_platdata.clocks = exynos4_hsmmc_clksrcs;
+ s3c_hsmmc3_def_platdata.cfg_gpio = exynos4_setup_sdhci3_cfg_gpio;
+ s3c_hsmmc3_def_platdata.cfg_card = exynos4_setup_sdhci_cfg_card;
#endif
}
#else
-static inline void s5pv310_default_sdhci0(void) { }
-static inline void s5pv310_default_sdhci1(void) { }
-static inline void s5pv310_default_sdhci2(void) { }
-static inline void s5pv310_default_sdhci3(void) { }
+static inline void exynos4_default_sdhci0(void) { }
+static inline void exynos4_default_sdhci1(void) { }
+static inline void exynos4_default_sdhci2(void) { }
+static inline void exynos4_default_sdhci3(void) { }
-#endif /* CONFIG_S5PV310_SETUP_SDHCI */
+#endif /* CONFIG_EXYNOS4_SETUP_SDHCI */
#endif /* __PLAT_S3C_SDHCI_H */
diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c
index 2eeb49fa056d..f37457c52064 100644
--- a/arch/arm/plat-samsung/pwm.c
+++ b/arch/arm/plat-samsung/pwm.c
@@ -20,10 +20,8 @@
#include <linux/io.h>
#include <linux/pwm.h>
-#include <mach/irqs.h>
#include <mach/map.h>
-#include <plat/devs.h>
#include <plat/regs-timer.h>
struct pwm_device {
@@ -47,37 +45,6 @@ struct pwm_device {
static struct clk *clk_scaler[2];
-/* Standard setup for a timer block. */
-
-#define TIMER_RESOURCE_SIZE (1)
-
-#define TIMER_RESOURCE(_tmr, _irq) \
- (struct resource [TIMER_RESOURCE_SIZE]) { \
- [0] = { \
- .start = _irq, \
- .end = _irq, \
- .flags = IORESOURCE_IRQ \
- } \
- }
-
-#define DEFINE_S3C_TIMER(_tmr_no, _irq) \
- .name = "s3c24xx-pwm", \
- .id = _tmr_no, \
- .num_resources = TIMER_RESOURCE_SIZE, \
- .resource = TIMER_RESOURCE(_tmr_no, _irq), \
-
-/* since we already have an static mapping for the timer, we do not
- * bother setting any IO resource for the base.
- */
-
-struct platform_device s3c_device_timer[] = {
- [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },
- [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },
- [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },
- [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
- [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
-};
-
static inline int pwm_is_tdiv(struct pwm_device *pwm)
{
return clk_get_parent(pwm->clk) == pwm->clk_div;
diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c
index 24a74d1ca7d9..6a46ecd56cfd 100644
--- a/arch/avr32/mm/cache.c
+++ b/arch/avr32/mm/cache.c
@@ -113,7 +113,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
}
/*
- * This one is called from do_no_page(), do_swap_page() and install_page().
+ * This one is called from __do_fault() and do_swap_page().
*/
void flush_icache_page(struct vm_area_struct *vma, struct page *page)
{
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 0a7a4c11d8b1..4db5b46e1eff 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -56,6 +56,7 @@ config CRIS
select HAVE_IDE
select HAVE_GENERIC_HARDIRQS
select GENERIC_HARDIRQS_NO_DEPRECATED
+ select GENERIC_IRQ_SHOW
config HZ
int
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index 7328a7cf7449..907cfb5a873d 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -199,7 +199,7 @@ init_IRQ(void)
/* Initialize IRQ handler descriptors. */
for(i = 2; i < NR_IRQS; i++) {
- set_irq_desc_and_handler(i, &crisv10_irq_type,
+ irq_set_chip_and_handler(i, &crisv10_irq_type,
handle_simple_irq);
set_int_vector(i, interrupt[i]);
}
diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c
index baa746ce4e74..e7f8066105aa 100644
--- a/arch/cris/arch-v10/mm/init.c
+++ b/arch/cris/arch-v10/mm/init.c
@@ -241,7 +241,7 @@ flush_etrax_cacherange(void *startadr, int length)
}
/* Due to a bug in Etrax100(LX) all versions, receiving DMA buffers
- * will occationally corrupt certain CPU writes if the DMA buffers
+ * will occasionally corrupt certain CPU writes if the DMA buffers
* happen to be hot in the cache.
*
* As a workaround, we have to flush the relevant parts of the cache
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index 0ad9db5126c7..8023176e19b2 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -451,16 +451,16 @@ init_IRQ(void)
/* Point all IRQ's to bad handlers. */
for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
- set_irq_chip_and_handler(j, &crisv32_irq_type,
+ irq_set_chip_and_handler(j, &crisv32_irq_type,
handle_simple_irq);
set_exception_vector(i, interrupt[j]);
}
- /* Mark Timer and IPI IRQs as CPU local */
+ /* Mark Timer and IPI IRQs as CPU local */
irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
- irq_desc[TIMER0_INTR_VECT].status |= IRQ_PER_CPU;
+ irq_set_status_flags(TIMER0_INTR_VECT, IRQ_PER_CPU);
irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
- irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU;
+ irq_set_status_flags(IPI_INTR_VECT, IRQ_PER_CPU);
set_exception_vector(0x00, nmi_interrupt);
set_exception_vector(0x30, multiple_interrupt);
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index c346952f06dc..788eb2248916 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -37,45 +37,6 @@
#include <asm/io.h>
-int show_interrupts(struct seq_file *p, void *v)
-{
- int i = *(loff_t *) v, j;
- struct irqaction * action;
- unsigned long flags;
-
- if (i == 0) {
- seq_printf(p, " ");
- for_each_online_cpu(j)
- seq_printf(p, "CPU%d ",j);
- seq_putc(p, '\n');
- }
-
- if (i < NR_IRQS) {
- raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
- action = irq_desc[i].action;
- if (!action)
- goto skip;
- seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
- seq_printf(p, "%10u ", kstat_irqs(i));
-#else
- for_each_online_cpu(j)
- seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-#endif
- seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
- seq_printf(p, " %s", action->name);
-
- for (action=action->next; action; action = action->next)
- seq_printf(p, ", %s", action->name);
-
- seq_putc(p, '\n');
-skip:
- raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
- }
- return 0;
-}
-
-
/* called by the assembler IRQ entry functions defined in irq.h
* to dispatch the interrupts to registered handlers
* interrupts are disabled upon entry - depending on if the
diff --git a/arch/ia64/include/asm/perfmon.h b/arch/ia64/include/asm/perfmon.h
index 7f3333dd00e4..d551183fee90 100644
--- a/arch/ia64/include/asm/perfmon.h
+++ b/arch/ia64/include/asm/perfmon.h
@@ -7,7 +7,7 @@
#define _ASM_IA64_PERFMON_H
/*
- * perfmon comamnds supported on all CPU models
+ * perfmon commands supported on all CPU models
*/
#define PFM_WRITE_PMCS 0x01
#define PFM_WRITE_PMDS 0x02
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 70d224d4264c..8213efe1998c 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -662,6 +662,7 @@ again:
goto vcpu_run_fail;
srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ vcpu->mode = IN_GUEST_MODE;
kvm_guest_enter();
/*
@@ -683,6 +684,7 @@ again:
*/
barrier();
kvm_guest_exit();
+ vcpu->mode = OUTSIDE_GUEST_MODE;
preempt_enable();
idx = srcu_read_lock(&vcpu->kvm->srcu);
diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h
index a0efc73819e4..6dcd3583ed04 100644
--- a/arch/mips/include/asm/errno.h
+++ b/arch/mips/include/asm/errno.h
@@ -121,6 +121,8 @@
#define ERFKILL 167 /* Operation not possible due to RF-kill */
+#define EHWPOISON 168 /* Memory page has hardware error */
+
#define EDQUOT 1133 /* Quota exceeded */
#ifdef __KERNEL__
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 8987a76e9676..564ab81d6cdc 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -30,6 +30,7 @@ extern struct platform_device jz4740_i2s_device;
extern struct platform_device jz4740_pcm_device;
extern struct platform_device jz4740_codec_device;
extern struct platform_device jz4740_adc_device;
+extern struct platform_device jz4740_wdt_device;
void jz4740_serial_device_register(void);
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index 1cc9e544d16b..10929e2bc6d8 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -289,3 +289,19 @@ void jz4740_serial_device_register(void)
platform_device_register(&jz4740_uart_device);
}
+
+/* Watchdog */
+static struct resource jz4740_wdt_resources[] = {
+ {
+ .start = JZ4740_WDT_BASE_ADDR,
+ .end = JZ4740_WDT_BASE_ADDR + 0x10 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device jz4740_wdt_device = {
+ .name = "jz4740-wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_wdt_resources),
+ .resource = jz4740_wdt_resources,
+};
diff --git a/arch/parisc/include/asm/errno.h b/arch/parisc/include/asm/errno.h
index 9992abdd782d..135ad6047e51 100644
--- a/arch/parisc/include/asm/errno.h
+++ b/arch/parisc/include/asm/errno.h
@@ -122,4 +122,6 @@
#define ERFKILL 256 /* Operation not possible due to RF-kill */
+#define EHWPOISON 257 /* Memory page has hardware error */
+
#endif
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7d69e9bf5e64..71ba04721beb 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -134,6 +134,7 @@ config PPC
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select IRQ_PER_CPU
+ select GENERIC_HARDIRQS_NO_DEPRECATED
config EARLY_PRINTK
bool
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 5b27a4b74b79..2779f08313a5 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -172,6 +172,19 @@
interrupts = <0x1e 4>;
};
+ USBOTG0: usbotg@bff80000 {
+ compatible = "amcc,dwc-otg";
+ reg = <0x4 0xbff80000 0x10000>;
+ interrupt-parent = <&USBOTG0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x1 0x2>;
+ interrupt-map = </* USB-OTG */ 0x0 &UIC2 0x1c 0x4
+ /* HIGH-POWER */ 0x1 &UIC1 0x1a 0x8
+ /* DMA */ 0x2 &UIC0 0xc 0x4>;
+ };
+
SATA0: sata@bffd1000 {
compatible = "amcc,sata-460ex";
reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>;
@@ -233,6 +246,11 @@
};
};
+ cpld@2,0 {
+ compatible = "amcc,ppc460ex-bcsr";
+ reg = <2 0x0 0x9>;
+ };
+
ndfc@3,0 {
compatible = "ibm,ndfc";
reg = <0x00000003 0x00000000 0x00002000>;
@@ -307,6 +325,12 @@
interrupts = <0x3 0x4>;
};
+ GPIO0: gpio@ef600b00 {
+ compatible = "ibm,ppc4xx-gpio";
+ reg = <0xef600b00 0x00000048>;
+ gpio-controller;
+ };
+
ZMII0: emac-zmii@ef600d00 {
compatible = "ibm,zmii-460ex", "ibm,zmii";
reg = <0xef600d00 0x0000000c>;
diff --git a/arch/powerpc/boot/dts/kmeter1.dts b/arch/powerpc/boot/dts/kmeter1.dts
index d8b5d12fb663..d16bae1230f7 100644
--- a/arch/powerpc/boot/dts/kmeter1.dts
+++ b/arch/powerpc/boot/dts/kmeter1.dts
@@ -1,7 +1,7 @@
/*
* Keymile KMETER1 Device Tree Source
*
- * 2008 DENX Software Engineering GmbH
+ * 2008-2011 DENX Software Engineering GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -70,11 +70,11 @@
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
- compatible = "fsl-i2c";
+ compatible = "fsl,mpc8313-i2c","fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
- dfsrr;
+ clock-frequency = <400000>;
};
serial0: serial@4500 {
@@ -137,6 +137,13 @@
compatible = "fsl,mpc8360-par_io";
num-ports = <7>;
+ qe_pio_c: gpio-controller@30 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8360-qe-pario-bank",
+ "fsl,mpc8323-qe-pario-bank";
+ reg = <0x1430 0x18>;
+ gpio-controller;
+ };
pio_ucc1: ucc_pin@0 {
reg = <0>;
@@ -472,7 +479,17 @@
#address-cells = <0>;
#interrupt-cells = <1>;
reg = <0x80 0x80>;
- interrupts = <32 8 33 8>;
+ big-endian;
+ interrupts = <
+ 32 0x8
+ 33 0x8
+ 34 0x8
+ 35 0x8
+ 40 0x8
+ 41 0x8
+ 42 0x8
+ 43 0x8
+ >;
interrupt-parent = <&ipic>;
};
};
@@ -484,43 +501,31 @@
compatible = "fsl,mpc8360-localbus", "fsl,pq2pro-localbus",
"simple-bus";
reg = <0xe0005000 0xd8>;
- ranges = <0 0 0xf0000000 0x04000000>; /* Filled in by U-Boot */
+ ranges = <0 0 0xf0000000 0x04000000 /* LB 0 */
+ 1 0 0xe8000000 0x01000000 /* LB 1 */
+ 3 0 0xa0000000 0x10000000>; /* LB 3 */
- flash@f0000000,0 {
+ flash@0,0 {
compatible = "cfi-flash";
- /*
- * The Intel P30 chip has 2 non-identical chips on
- * one die, so we need to define 2 separate regions
- * that are scanned by physmap_of independantly.
- */
- reg = <0 0x00000000 0x02000000
- 0 0x02000000 0x02000000>; /* Filled in by U-Boot */
- bank-width = <2>;
+ reg = <0 0 0x04000000>;
#address-cells = <1>;
#size-cells = <1>;
- partition@0 {
+ bank-width = <2>;
+ partition@0 { /* 768KB */
label = "u-boot";
- reg = <0 0x40000>;
+ reg = <0 0xC0000>;
};
- partition@40000 {
+ partition@c0000 { /* 128KB */
label = "env";
- reg = <0x40000 0x40000>;
- };
- partition@80000 {
- label = "dtb";
- reg = <0x80000 0x20000>;
- };
- partition@a0000 {
- label = "kernel";
- reg = <0xa0000 0x300000>;
+ reg = <0xC0000 0x20000>;
};
- partition@3a0000 {
- label = "ramdisk";
- reg = <0x3a0000 0x800000>;
+ partition@e0000 { /* 128KB */
+ label = "envred";
+ reg = <0xE0000 0x20000>;
};
- partition@ba0000 {
- label = "user";
- reg = <0xba0000 0x3460000>;
+ partition@100000 { /* 64512KB */
+ label = "ubi0";
+ reg = <0x100000 0x3F00000>;
};
};
};
diff --git a/arch/powerpc/boot/dts/mgcoge.dts b/arch/powerpc/boot/dts/mgcoge.dts
index 0ce96644176d..1360d2f69024 100644
--- a/arch/powerpc/boot/dts/mgcoge.dts
+++ b/arch/powerpc/boot/dts/mgcoge.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/ {
model = "MGCOGE";
- compatible = "keymile,mgcoge";
+ compatible = "keymile,km82xx";
#address-cells = <1>;
#size-cells = <1>;
@@ -48,8 +48,10 @@
reg = <0xf0010100 0x40>;
ranges = <0 0 0xfe000000 0x00400000
- 5 0 0x50000000 0x20000000
- >; /* Filled in by U-Boot */
+ 1 0 0x30000000 0x00010000
+ 2 0 0x40000000 0x00010000
+ 5 0 0x50000000 0x04000000
+ >;
flash@0,0 {
compatible = "cfi-flash";
@@ -60,36 +62,32 @@
device-width = <1>;
partition@0 {
label = "u-boot";
- reg = <0 0x40000>;
+ reg = <0x00000 0xC0000>;
};
- partition@40000 {
+ partition@1 {
label = "env";
- reg = <0x40000 0x20000>;
+ reg = <0xC0000 0x20000>;
};
- partition@60000 {
- label = "kernel";
- reg = <0x60000 0x220000>;
+ partition@2 {
+ label = "envred";
+ reg = <0xE0000 0x20000>;
};
- partition@280000 {
- label = "dtb";
- reg = <0x280000 0x20000>;
+ partition@3 {
+ label = "free";
+ reg = <0x100000 0x300000>;
};
};
flash@5,0 {
compatible = "cfi-flash";
- reg = <5 0x0 0x2000000>;
+ reg = <5 0x00000000 0x02000000
+ 5 0x02000000 0x02000000>;
#address-cells = <1>;
#size-cells = <1>;
bank-width = <2>;
- device-width = <2>;
- partition@0 {
- label = "ramdisk";
- reg = <0 0x7a0000>;
- };
- partition@7a0000 {
- label = "user";
- reg = <0x7a0000 0x1860000>;
+ partition@app { /* 64 MBytes */
+ label = "ubi0";
+ reg = <0x00000000 0x04000000>;
};
};
};
@@ -217,6 +215,13 @@
};
};
+ cpm2_pio_c: gpio-controller@10d40 {
+ #gpio-cells = <2>;
+ compatible = "fsl,cpm2-pario-bank";
+ reg = <0x10d40 0x14>;
+ gpio-controller;
+ };
+
PIC: interrupt-controller@10c00 {
#interrupt-cells = <2>;
interrupt-controller;
diff --git a/arch/powerpc/boot/dts/mgsuvd.dts b/arch/powerpc/boot/dts/mgsuvd.dts
deleted file mode 100644
index e4fc53ab42bd..000000000000
--- a/arch/powerpc/boot/dts/mgsuvd.dts
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * MGSUVD Device Tree Source
- *
- * Copyright 2008 DENX Software Engineering GmbH
- * Heiko Schocher <hs@denx.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-/dts-v1/;
-/ {
- model = "MGSUVD";
- compatible = "keymile,mgsuvd";
- #address-cells = <1>;
- #size-cells = <1>;
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,852@0 {
- device_type = "cpu";
- reg = <0>;
- d-cache-line-size = <16>;
- i-cache-line-size = <16>;
- d-cache-size = <8192>;
- i-cache-size = <8192>;
- timebase-frequency = <0>; /* Filled in by u-boot */
- bus-frequency = <0>; /* Filled in by u-boot */
- clock-frequency = <0>; /* Filled in by u-boot */
- interrupts = <15 2>; /* decrementer interrupt */
- interrupt-parent = <&PIC>;
- };
- };
-
- memory {
- device_type = "memory";
- reg = <00000000 0x4000000>; /* Filled in by u-boot */
- };
-
- localbus@fff00100 {
- compatible = "fsl,mpc852-localbus", "fsl,pq1-localbus", "simple-bus";
- #address-cells = <2>;
- #size-cells = <1>;
- reg = <0xfff00100 0x40>;
-
- ranges = <0 0 0xf0000000 0x01000000>; /* Filled in by u-boot */
-
- flash@0,0 {
- compatible = "cfi-flash";
- reg = <0 0 0x1000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- bank-width = <1>;
- device-width = <1>;
- partition@0 {
- label = "u-boot";
- reg = <0 0x80000>;
- };
- partition@80000 {
- label = "env";
- reg = <0x80000 0x20000>;
- };
- partition@a0000 {
- label = "kernel";
- reg = <0xa0000 0x1e0000>;
- };
- partition@280000 {
- label = "dtb";
- reg = <0x280000 0x20000>;
- };
- partition@2a0000 {
- label = "root";
- reg = <0x2a0000 0x500000>;
- };
- partition@7a0000 {
- label = "user";
- reg = <0x7a0000 0x860000>;
- };
- };
- };
-
- soc@fff00000 {
- compatible = "fsl,mpc852", "fsl,pq1-soc", "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- ranges = <0 0xfff00000 0x00004000>;
-
- PIC: interrupt-controller@0 {
- interrupt-controller;
- #interrupt-cells = <2>;
- reg = <0 24>;
- compatible = "fsl,mpc852-pic", "fsl,pq1-pic";
- };
-
- cpm@9c0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "fsl,mpc852-cpm", "fsl,cpm1", "simple-bus";
- interrupts = <0>; /* cpm error interrupt */
- interrupt-parent = <&CPM_PIC>;
- reg = <0x9c0 10>;
- ranges;
-
- muram@2000 {
- compatible = "fsl,cpm-muram";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0 0x2000 0x2000>;
-
- data@0 {
- compatible = "fsl,cpm-muram-data";
- reg = <0x800 0x1800>;
- };
- };
-
- brg@9f0 {
- compatible = "fsl,mpc852-brg",
- "fsl,cpm1-brg",
- "fsl,cpm-brg";
- reg = <0x9f0 0x10>;
- clock-frequency = <0>; /* Filled in by u-boot */
- };
-
- CPM_PIC: interrupt-controller@930 {
- interrupt-controller;
- #interrupt-cells = <1>;
- interrupts = <5 2 0 2>;
- interrupt-parent = <&PIC>;
- reg = <0x930 0x20>;
- compatible = "fsl,cpm1-pic";
- };
-
- /* MON-1 */
- serial@a80 {
- device_type = "serial";
- compatible = "fsl,cpm1-smc-uart";
- reg = <0xa80 0x10 0x3fc0 0x40>;
- interrupts = <4>;
- interrupt-parent = <&CPM_PIC>;
- fsl,cpm-brg = <1>;
- fsl,cpm-command = <0x0090>;
- current-speed = <0>; /* Filled in by u-boot */
- };
-
- ethernet@a40 {
- device_type = "network";
- compatible = "fsl,mpc866-scc-enet",
- "fsl,cpm1-scc-enet";
- reg = <0xa40 0x18 0x3e00 0x100>;
- local-mac-address = [ 00 00 00 00 00 00 ]; /* Filled in by u-boot */
- interrupts = <28>;
- interrupt-parent = <&CPM_PIC>;
- fsl,cpm-command = <0x80>;
- fixed-link = <0 0 10 0 0>;
- };
- };
- };
-};
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
index 69422eb24d97..59ef405c1c91 100644
--- a/arch/powerpc/boot/dts/p1022ds.dts
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -475,14 +475,14 @@
};
sata@18000 {
- compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+ compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
reg = <0x18000 0x1000>;
cell-index = <1>;
interrupts = <74 0x2>;
};
sata@19000 {
- compatible = "fsl,mpc8536-sata", "fsl,pq-sata";
+ compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
reg = <0x19000 0x1000>;
cell-index = <2>;
interrupts = <41 0x2>;
diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig
index 7a7b731c5735..07e1bbadebfe 100644
--- a/arch/powerpc/configs/83xx/kmeter1_defconfig
+++ b/arch/powerpc/configs/83xx/kmeter1_defconfig
@@ -2,6 +2,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
+CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
@@ -18,7 +19,6 @@ CONFIG_KMETER1=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
-CONFIG_SPARSE_IRQ=y
# CONFIG_SECCOMP is not set
CONFIG_NET=y
CONFIG_PACKET=y
@@ -37,7 +37,6 @@ CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
@@ -49,13 +48,12 @@ CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_GLUEBI=y
CONFIG_MTD_UBI_DEBUG=y
CONFIG_PROC_DEVICETREE=y
-# CONFIG_MISC_DEVICES is not set
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
+CONFIG_MII=y
CONFIG_MARVELL_PHY=y
CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
CONFIG_UCC_GETH=y
# CONFIG_NETDEV_10000 is not set
CONFIG_WAN=y
@@ -77,7 +75,6 @@ CONFIG_I2C_MPC=y
# CONFIG_USB_SUPPORT is not set
CONFIG_UIO=y
# CONFIG_DNOTIFY is not set
-CONFIG_INOTIFY=y
CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_NFS_FS=y
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
index 39518e91822f..6cb588a7d425 100644
--- a/arch/powerpc/configs/mgcoge_defconfig
+++ b/arch/powerpc/configs/mgcoge_defconfig
@@ -1,4 +1,5 @@
CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
@@ -10,7 +11,6 @@ CONFIG_SLAB=y
CONFIG_PPC_82xx=y
CONFIG_MGCOGE=y
CONFIG_BINFMT_MISC=y
-CONFIG_SPARSE_IRQ=y
# CONFIG_SECCOMP is not set
CONFIG_NET=y
CONFIG_PACKET=y
@@ -30,7 +30,6 @@ CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_CFI=y
@@ -43,7 +42,6 @@ CONFIG_MTD_PHYSMAP_OF=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
CONFIG_FIXED_PHY=y
@@ -67,7 +65,6 @@ CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
CONFIG_AUTOFS4_FS=y
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
@@ -88,13 +85,9 @@ CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_BDI_SWITCH=y
-CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig
deleted file mode 100644
index 2a490626015c..000000000000
--- a/arch/powerpc/configs/mgsuvd_defconfig
+++ /dev/null
@@ -1,81 +0,0 @@
-CONFIG_PPC_8xx=y
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_BUG is not set
-# CONFIG_BASE_FULL is not set
-# CONFIG_EPOLL is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PPC_MGSUVD=y
-CONFIG_8xx_COPYBACK=y
-CONFIG_8xx_CPU6=y
-CONFIG_I2C_SPI_SMC1_UCODE_PATCH=y
-CONFIG_HZ_1000=y
-CONFIG_MATH_EMULATION=y
-CONFIG_SPARSE_IRQ=y
-# CONFIG_SECCOMP is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_OF_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_STAA=y
-CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_FIXED_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FS_ENET=y
-# CONFIG_FS_ENET_HAS_FEC is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_CPM=y
-CONFIG_SERIAL_CPM_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_GEN_RTC=y
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_CRC_CCITT=y
-CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index f0a211d96923..be3cdf9134ce 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -154,6 +154,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_NAP_DISABLE_L2_PR ASM_CONST(0x0000000000002000)
#define CPU_FTR_DUAL_PLL_750FX ASM_CONST(0x0000000000004000)
#define CPU_FTR_NO_DPM ASM_CONST(0x0000000000008000)
+#define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000)
#define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000)
#define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000)
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000)
@@ -465,7 +466,7 @@ enum {
CPU_FTRS_44X | CPU_FTRS_440x6 |
#endif
#ifdef CONFIG_PPC_47x
- CPU_FTRS_47X |
+ CPU_FTRS_47X | CPU_FTR_476_DD2 |
#endif
#ifdef CONFIG_E200
CPU_FTRS_E200 |
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index ff08b70b36d4..bb712c9488b3 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -141,6 +141,8 @@ static inline bool arch_irqs_disabled(void)
#endif /* CONFIG_PPC64 */
+#define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST
+
/*
* interrupt-retrigger: should we handle this via lost interrupts and IPIs
* or should we not care like we do now ? --BenH.
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index e000cce8f6dd..946ec4947da2 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -467,11 +467,11 @@ extern void mpic_request_ipis(void);
void smp_mpic_message_pass(int target, int msg);
/* Unmask a specific virq */
-extern void mpic_unmask_irq(unsigned int irq);
+extern void mpic_unmask_irq(struct irq_data *d);
/* Mask a specific virq */
-extern void mpic_mask_irq(unsigned int irq);
+extern void mpic_mask_irq(struct irq_data *d);
/* EOI a specific virq */
-extern void mpic_end_irq(unsigned int irq);
+extern void mpic_end_irq(struct irq_data *d);
/* Fetch interrupt from a given mpic */
extern unsigned int mpic_get_one_irq(struct mpic *mpic);
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 92efe67d1c57..9d1aafe607c7 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -51,7 +51,8 @@ static inline int mmio_nvram_init(void)
extern int __init nvram_scan_partitions(void);
extern loff_t nvram_create_partition(const char *name, int sig,
int req_size, int min_size);
-extern int nvram_remove_partition(const char *name, int sig);
+extern int nvram_remove_partition(const char *name, int sig,
+ const char *exceptions[]);
extern int nvram_get_partition_size(loff_t data_index);
extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index 89f158731ce3..88b0bd925a8b 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -170,6 +170,7 @@ extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addre
#define pgprot_cached_wthru(prot) (__pgprot((pgprot_val(prot) & ~_PAGE_CACHE_CTL) | \
_PAGE_COHERENT | _PAGE_WRITETHRU))
+#define pgprot_writecombine pgprot_noncached_wc
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
diff --git a/arch/powerpc/include/asm/qe_ic.h b/arch/powerpc/include/asm/qe_ic.h
index cf519663a791..9e2cb2019161 100644
--- a/arch/powerpc/include/asm/qe_ic.h
+++ b/arch/powerpc/include/asm/qe_ic.h
@@ -81,7 +81,7 @@ int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
static inline void qe_ic_cascade_low_ipic(unsigned int irq,
struct irq_desc *desc)
{
- struct qe_ic *qe_ic = desc->handler_data;
+ struct qe_ic *qe_ic = get_irq_desc_data(desc);
unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
if (cascade_irq != NO_IRQ)
@@ -91,7 +91,7 @@ static inline void qe_ic_cascade_low_ipic(unsigned int irq,
static inline void qe_ic_cascade_high_ipic(unsigned int irq,
struct irq_desc *desc)
{
- struct qe_ic *qe_ic = desc->handler_data;
+ struct qe_ic *qe_ic = get_irq_desc_data(desc);
unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
if (cascade_irq != NO_IRQ)
@@ -101,32 +101,35 @@ static inline void qe_ic_cascade_high_ipic(unsigned int irq,
static inline void qe_ic_cascade_low_mpic(unsigned int irq,
struct irq_desc *desc)
{
- struct qe_ic *qe_ic = desc->handler_data;
+ struct qe_ic *qe_ic = get_irq_desc_data(desc);
unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+ struct irq_chip *chip = get_irq_desc_chip(desc);
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
static inline void qe_ic_cascade_high_mpic(unsigned int irq,
struct irq_desc *desc)
{
- struct qe_ic *qe_ic = desc->handler_data;
+ struct qe_ic *qe_ic = get_irq_desc_data(desc);
unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+ struct irq_chip *chip = get_irq_desc_chip(desc);
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
struct irq_desc *desc)
{
- struct qe_ic *qe_ic = desc->handler_data;
+ struct qe_ic *qe_ic = get_irq_desc_data(desc);
unsigned int cascade_irq;
+ struct irq_chip *chip = get_irq_desc_chip(desc);
cascade_irq = qe_ic_get_high_irq(qe_ic);
if (cascade_irq == NO_IRQ)
@@ -135,7 +138,7 @@ static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* _ASM_POWERPC_QE_IC_H */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 125fc1ad665d..7e4abebe76c0 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -170,6 +170,16 @@
#define SPEFSCR_FRMC 0x00000003 /* Embedded FP rounding mode control */
/* Special Purpose Registers (SPRNs)*/
+
+#ifdef CONFIG_40x
+#define SPRN_PID 0x3B1 /* Process ID */
+#else
+#define SPRN_PID 0x030 /* Process ID */
+#ifdef CONFIG_BOOKE
+#define SPRN_PID0 SPRN_PID/* Process ID Register 0 */
+#endif
+#endif
+
#define SPRN_CTR 0x009 /* Count Register */
#define SPRN_DSCR 0x11
#define SPRN_CTRLF 0x088
@@ -852,6 +862,8 @@
#define PVR_7450 0x80000000
#define PVR_8540 0x80200000
#define PVR_8560 0x80200000
+#define PVR_VER_E500V1 0x8020
+#define PVR_VER_E500V2 0x8021
/*
* For the 8xx processors, all of them report the same PVR family for
* the PowerPC core. The various versions of these processors must be
@@ -880,6 +892,7 @@
#define PV_970 0x0039
#define PV_POWER5 0x003A
#define PV_POWER5p 0x003B
+#define PV_POWER7 0x003F
#define PV_970FX 0x003C
#define PV_630 0x0040
#define PV_630p 0x0041
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index e68c69bf741a..86ad8128963a 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -150,8 +150,6 @@
* or IBM 40x.
*/
#ifdef CONFIG_BOOKE
-#define SPRN_PID 0x030 /* Process ID */
-#define SPRN_PID0 SPRN_PID/* Process ID Register 0 */
#define SPRN_CSRR0 0x03A /* Critical Save and Restore Register 0 */
#define SPRN_CSRR1 0x03B /* Critical Save and Restore Register 1 */
#define SPRN_DEAR 0x03D /* Data Error Address Register */
@@ -168,7 +166,6 @@
#define SPRN_TCR 0x154 /* Timer Control Register */
#endif /* Book E */
#ifdef CONFIG_40x
-#define SPRN_PID 0x3B1 /* Process ID */
#define SPRN_DBCR1 0x3BD /* Debug Control Register 1 */
#define SPRN_ESR 0x3D4 /* Exception Syndrome Register */
#define SPRN_DEAR 0x3D5 /* Data Error Address Register */
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index e8e915ce3d8d..c9b68d07ac4f 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1811,11 +1811,11 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_440A,
.platform = "ppc440",
},
- { /* 476 core */
- .pvr_mask = 0xffff0000,
- .pvr_value = 0x11a50000,
+ { /* 476 DD2 core */
+ .pvr_mask = 0xffffffff,
+ .pvr_value = 0x11a52080,
.cpu_name = "476",
- .cpu_features = CPU_FTRS_47X,
+ .cpu_features = CPU_FTRS_47X | CPU_FTR_476_DD2,
.cpu_user_features = COMMON_USER_BOOKE |
PPC_FEATURE_HAS_FPU,
.mmu_features = MMU_FTR_TYPE_47x |
@@ -1839,6 +1839,20 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_47x,
.platform = "ppc470",
},
+ { /* 476 others */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x11a50000,
+ .cpu_name = "476",
+ .cpu_features = CPU_FTRS_47X,
+ .cpu_user_features = COMMON_USER_BOOKE |
+ PPC_FEATURE_HAS_FPU,
+ .mmu_features = MMU_FTR_TYPE_47x |
+ MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL,
+ .icache_bsize = 32,
+ .dcache_bsize = 128,
+ .machine_check = machine_check_47x,
+ .platform = "ppc470",
+ },
{ /* default match */
.pvr_mask = 0x00000000,
.pvr_value = 0x00000000,
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index ce557f6f00fc..0a5570338b96 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -237,6 +237,7 @@ int show_interrupts(struct seq_file *p, void *v)
int i = *(loff_t *) v, j, prec;
struct irqaction *action;
struct irq_desc *desc;
+ struct irq_chip *chip;
if (i > nr_irqs)
return 0;
@@ -270,8 +271,9 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
- if (desc->chip)
- seq_printf(p, " %-16s", desc->chip->name);
+ chip = get_irq_desc_chip(desc);
+ if (chip)
+ seq_printf(p, " %-16s", chip->name);
else
seq_printf(p, " %-16s", "None");
seq_printf(p, " %-8s", (desc->status & IRQ_LEVEL) ? "Level" : "Edge");
@@ -313,6 +315,8 @@ void fixup_irqs(const struct cpumask *map)
alloc_cpumask_var(&mask, GFP_KERNEL);
for_each_irq(irq) {
+ struct irq_chip *chip;
+
desc = irq_to_desc(irq);
if (!desc)
continue;
@@ -320,13 +324,15 @@ void fixup_irqs(const struct cpumask *map)
if (desc->status & IRQ_PER_CPU)
continue;
- cpumask_and(mask, desc->affinity, map);
+ chip = get_irq_desc_chip(desc);
+
+ cpumask_and(mask, desc->irq_data.affinity, map);
if (cpumask_any(mask) >= nr_cpu_ids) {
printk("Breaking affinity for irq %i\n", irq);
cpumask_copy(mask, map);
}
- if (desc->chip->set_affinity)
- desc->chip->set_affinity(irq, mask);
+ if (chip->irq_set_affinity)
+ chip->irq_set_affinity(&desc->irq_data, mask, true);
else if (desc->action && !(warned++))
printk("Cannot set affinity for irq %i\n", irq);
}
@@ -678,16 +684,15 @@ void irq_set_virq_count(unsigned int count)
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
- struct irq_desc *desc;
+ int res;
- desc = irq_to_desc_alloc_node(virq, 0);
- if (!desc) {
+ res = irq_alloc_desc_at(virq, 0);
+ if (res != virq) {
pr_debug("irq: -> allocating desc failed\n");
goto error;
}
- /* Clear IRQ_NOREQUEST flag */
- desc->status &= ~IRQ_NOREQUEST;
+ irq_clear_status_flags(virq, IRQ_NOREQUEST);
/* map it */
smp_wmb();
@@ -696,11 +701,13 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
if (host->ops->map(host, virq, hwirq)) {
pr_debug("irq: -> mapping failed, freeing\n");
- goto error;
+ goto errdesc;
}
return 0;
+errdesc:
+ irq_free_descs(virq, 1);
error:
irq_free_virt(virq, 1);
return -1;
@@ -879,9 +886,9 @@ void irq_dispose_mapping(unsigned int virq)
smp_mb();
irq_map[virq].hwirq = host->inval_irq;
- /* Set some flags */
- irq_to_desc(virq)->status |= IRQ_NOREQUEST;
+ irq_set_status_flags(virq, IRQ_NOREQUEST);
+ irq_free_descs(virq, 1);
/* Free it */
irq_free_virt(virq, 1);
}
@@ -1074,21 +1081,6 @@ void irq_free_virt(unsigned int virq, unsigned int count)
int arch_early_irq_init(void)
{
- struct irq_desc *desc;
- int i;
-
- for (i = 0; i < NR_IRQS; i++) {
- desc = irq_to_desc(i);
- if (desc)
- desc->status |= IRQ_NOREQUEST;
- }
-
- return 0;
-}
-
-int arch_init_chip_data(struct irq_desc *desc, int node)
-{
- desc->status |= IRQ_NOREQUEST;
return 0;
}
@@ -1159,11 +1151,14 @@ static int virq_debug_show(struct seq_file *m, void *private)
raw_spin_lock_irqsave(&desc->lock, flags);
if (desc->action && desc->action->handler) {
+ struct irq_chip *chip;
+
seq_printf(m, "%5d ", i);
seq_printf(m, "0x%05lx ", virq_to_hw(i));
- if (desc->chip && desc->chip->name)
- p = desc->chip->name;
+ chip = get_irq_desc_chip(desc);
+ if (chip && chip->name)
+ p = chip->name;
else
p = none;
seq_printf(m, "%-15s ", p);
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index a5f8672eeff3..bd1e1ff17b2d 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -26,20 +26,23 @@ void machine_kexec_mask_interrupts(void) {
for_each_irq(i) {
struct irq_desc *desc = irq_to_desc(i);
+ struct irq_chip *chip;
- if (!desc || !desc->chip)
+ if (!desc)
continue;
- if (desc->chip->eoi &&
- desc->status & IRQ_INPROGRESS)
- desc->chip->eoi(i);
+ chip = get_irq_desc_chip(desc);
+ if (!chip)
+ continue;
+
+ if (chip->irq_eoi && desc->status & IRQ_INPROGRESS)
+ chip->irq_eoi(&desc->irq_data);
- if (desc->chip->mask)
- desc->chip->mask(i);
+ if (chip->irq_mask)
+ chip->irq_mask(&desc->irq_data);
- if (desc->chip->disable &&
- !(desc->status & IRQ_DISABLED))
- desc->chip->disable(i);
+ if (chip->irq_disable && !(desc->status & IRQ_DISABLED))
+ chip->irq_disable(&desc->irq_data);
}
}
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index bb12b3248f13..bec1e930ed73 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -237,22 +237,45 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
return c_sum;
}
+/*
+ * Per the criteria passed via nvram_remove_partition(), should this
+ * partition be removed? 1=remove, 0=keep
+ */
+static int nvram_can_remove_partition(struct nvram_partition *part,
+ const char *name, int sig, const char *exceptions[])
+{
+ if (part->header.signature != sig)
+ return 0;
+ if (name) {
+ if (strncmp(name, part->header.name, 12))
+ return 0;
+ } else if (exceptions) {
+ const char **except;
+ for (except = exceptions; *except; except++) {
+ if (!strncmp(*except, part->header.name, 12))
+ return 0;
+ }
+ }
+ return 1;
+}
+
/**
* nvram_remove_partition - Remove one or more partitions in nvram
* @name: name of the partition to remove, or NULL for a
* signature only match
* @sig: signature of the partition(s) to remove
+ * @exceptions: When removing all partitions with a matching signature,
+ * leave these alone.
*/
-int __init nvram_remove_partition(const char *name, int sig)
+int __init nvram_remove_partition(const char *name, int sig,
+ const char *exceptions[])
{
struct nvram_partition *part, *prev, *tmp;
int rc;
list_for_each_entry(part, &nvram_partitions, partition) {
- if (part->header.signature != sig)
- continue;
- if (name && strncmp(name, part->header.name, 12))
+ if (!nvram_can_remove_partition(part, name, sig, exceptions))
continue;
/* Make partition a free partition */
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index ab6f6beadb57..97e0ae414940 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -1269,6 +1269,28 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs)
return ip;
}
+static bool pmc_overflow(unsigned long val)
+{
+ if ((int)val < 0)
+ return true;
+
+ /*
+ * Events on POWER7 can roll back if a speculative event doesn't
+ * eventually complete. Unfortunately in some rare cases they will
+ * raise a performance monitor exception. We need to catch this to
+ * ensure we reset the PMC. In all cases the PMC will be 256 or less
+ * cycles from overflow.
+ *
+ * We only do this if the first pass fails to find any overflowing
+ * PMCs because a user might set a period of less than 256 and we
+ * don't want to mistakenly reset them.
+ */
+ if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
+ return true;
+
+ return false;
+}
+
/*
* Performance monitor interrupt stuff
*/
@@ -1316,7 +1338,7 @@ static void perf_event_interrupt(struct pt_regs *regs)
if (is_limited_pmc(i + 1))
continue;
val = read_pmc(i + 1);
- if ((int)val < 0)
+ if (pmc_overflow(val))
write_pmc(i + 1, 0);
}
}
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 7185f0da7dc3..05b7139d6a27 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -97,7 +97,7 @@ static void __init move_device_tree(void)
start = __pa(initial_boot_params);
size = be32_to_cpu(initial_boot_params->totalsize);
- if ((memory_limit && (start + size) > memory_limit) ||
+ if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
overlaps_crashkernel(start, size)) {
p = __va(memblock_alloc(size, PAGE_SIZE));
memcpy(p, initial_boot_params, size);
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 049dbecb5dbc..7980ec0e1e1a 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -412,7 +412,8 @@ static void rtas_event_scan(struct work_struct *w)
get_online_cpus();
- cpu = cpumask_next(smp_processor_id(), cpu_online_mask);
+ /* raw_ OK because just using CPU as starting point. */
+ cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask);
if (cpu >= nr_cpu_ids) {
cpu = cpumask_first(cpu_online_mask);
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index badc983031b3..c961de40c676 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -1141,9 +1141,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
regs->sprg1 = vcpu->arch.shared->sprg1;
regs->sprg2 = vcpu->arch.shared->sprg2;
regs->sprg3 = vcpu->arch.shared->sprg3;
- regs->sprg5 = vcpu->arch.sprg4;
- regs->sprg6 = vcpu->arch.sprg5;
- regs->sprg7 = vcpu->arch.sprg6;
+ regs->sprg4 = vcpu->arch.sprg4;
+ regs->sprg5 = vcpu->arch.sprg5;
+ regs->sprg6 = vcpu->arch.sprg6;
+ regs->sprg7 = vcpu->arch.sprg7;
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -1167,9 +1168,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.shared->sprg1 = regs->sprg1;
vcpu->arch.shared->sprg2 = regs->sprg2;
vcpu->arch.shared->sprg3 = regs->sprg3;
- vcpu->arch.sprg5 = regs->sprg4;
- vcpu->arch.sprg6 = regs->sprg5;
- vcpu->arch.sprg7 = regs->sprg6;
+ vcpu->arch.sprg4 = regs->sprg4;
+ vcpu->arch.sprg5 = regs->sprg5;
+ vcpu->arch.sprg6 = regs->sprg6;
+ vcpu->arch.sprg7 = regs->sprg7;
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 77575d08c818..ef76acb455c3 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -546,9 +546,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
regs->sprg1 = vcpu->arch.shared->sprg1;
regs->sprg2 = vcpu->arch.shared->sprg2;
regs->sprg3 = vcpu->arch.shared->sprg3;
- regs->sprg5 = vcpu->arch.sprg4;
- regs->sprg6 = vcpu->arch.sprg5;
- regs->sprg7 = vcpu->arch.sprg6;
+ regs->sprg4 = vcpu->arch.sprg4;
+ regs->sprg5 = vcpu->arch.sprg5;
+ regs->sprg6 = vcpu->arch.sprg6;
+ regs->sprg7 = vcpu->arch.sprg7;
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
@@ -572,9 +573,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
vcpu->arch.shared->sprg1 = regs->sprg1;
vcpu->arch.shared->sprg2 = regs->sprg2;
vcpu->arch.shared->sprg3 = regs->sprg3;
- vcpu->arch.sprg5 = regs->sprg4;
- vcpu->arch.sprg6 = regs->sprg5;
- vcpu->arch.sprg7 = regs->sprg6;
+ vcpu->arch.sprg4 = regs->sprg4;
+ vcpu->arch.sprg5 = regs->sprg5;
+ vcpu->arch.sprg6 = regs->sprg6;
+ vcpu->arch.sprg7 = regs->sprg7;
for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c
index 41f4ef30e480..62279200d965 100644
--- a/arch/powerpc/math-emu/math_efp.c
+++ b/arch/powerpc/math-emu/math_efp.c
@@ -1,7 +1,7 @@
/*
* arch/powerpc/math-emu/math_efp.c
*
- * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.
*
* Author: Ebony Zhu, <ebony.zhu@freescale.com>
* Yu Liu, <yu.liu@freescale.com>
@@ -104,6 +104,8 @@
#define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
+static int have_e500_cpu_a005_erratum;
+
union dw_union {
u64 dp[1];
u32 wp[2];
@@ -320,7 +322,8 @@ int do_spe_mathemu(struct pt_regs *regs)
} else {
_FP_ROUND_ZERO(1, SB);
}
- FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0));
+ FP_TO_INT_S(vc.wp[1], SB, 32,
+ (((func & 0x3) != 0) || SB_s));
goto update_regs;
default:
@@ -458,7 +461,8 @@ cmp_s:
} else {
_FP_ROUND_ZERO(2, DB);
}
- FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0));
+ FP_TO_INT_D(vc.wp[1], DB, 32,
+ (((func & 0x3) != 0) || DB_s));
goto update_regs;
default:
@@ -589,8 +593,10 @@ cmp_d:
_FP_ROUND_ZERO(1, SB0);
_FP_ROUND_ZERO(1, SB1);
}
- FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0));
- FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0));
+ FP_TO_INT_S(vc.wp[0], SB0, 32,
+ (((func & 0x3) != 0) || SB0_s));
+ FP_TO_INT_S(vc.wp[1], SB1, 32,
+ (((func & 0x3) != 0) || SB1_s));
goto update_regs;
default:
@@ -652,6 +658,15 @@ update_regs:
return 0;
illegal:
+ if (have_e500_cpu_a005_erratum) {
+ /* according to e500 cpu a005 erratum, reissue efp inst */
+ regs->nip -= 4;
+#ifdef DEBUG
+ printk(KERN_DEBUG "re-issue efp inst: %08lx\n", speinsn);
+#endif
+ return 0;
+ }
+
printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
return -ENOSYS;
}
@@ -718,3 +733,43 @@ int speround_handler(struct pt_regs *regs)
return 0;
}
+
+int __init spe_mathemu_init(void)
+{
+ u32 pvr, maj, min;
+
+ pvr = mfspr(SPRN_PVR);
+
+ if ((PVR_VER(pvr) == PVR_VER_E500V1) ||
+ (PVR_VER(pvr) == PVR_VER_E500V2)) {
+ maj = PVR_MAJ(pvr);
+ min = PVR_MIN(pvr);
+
+ /*
+ * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1
+ * need cpu a005 errata workaround
+ */
+ switch (maj) {
+ case 1:
+ if (min < 1)
+ have_e500_cpu_a005_erratum = 1;
+ break;
+ case 2:
+ if (min < 3)
+ have_e500_cpu_a005_erratum = 1;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ if (min < 1)
+ have_e500_cpu_a005_erratum = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+module_init(spe_mathemu_init);
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 742da43b4ab6..d65b591e5556 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -148,7 +148,7 @@ void __init MMU_init(void)
lowmem_end_addr = memstart_addr + total_lowmem;
#ifndef CONFIG_HIGHMEM
total_memory = total_lowmem;
- memblock_enforce_memory_limit(lowmem_end_addr);
+ memblock_enforce_memory_limit(total_lowmem);
memblock_analyze();
#endif /* CONFIG_HIGHMEM */
}
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index af405eefe48d..7c63c0ed4f1b 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -189,6 +189,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
blr
#ifdef CONFIG_PPC_47x
+
+/*
+ * 47x variant of icbt
+ */
+# define ICBT(CT,RA,RB) \
+ .long 0x7c00002c | ((CT) << 21) | ((RA) << 16) | ((RB) << 11)
+
/*
* _tlbivax_bcast is only on 47x. We don't bother doing a runtime
* check though, it will blow up soon enough if we mistakenly try
@@ -206,7 +213,35 @@ _GLOBAL(_tlbivax_bcast)
isync
eieio
tlbsync
+BEGIN_FTR_SECTION
+ b 1f
+END_FTR_SECTION_IFSET(CPU_FTR_476_DD2)
+ sync
+ wrtee r10
+ blr
+/*
+ * DD2 HW could hang if in instruction fetch happens before msync completes.
+ * Touch enough instruction cache lines to ensure cache hits
+ */
+1: mflr r9
+ bl 2f
+2: mflr r6
+ li r7,32
+ ICBT(0,r6,r7) /* touch next cache line */
+ add r6,r6,r7
+ ICBT(0,r6,r7) /* touch next cache line */
+ add r6,r6,r7
+ ICBT(0,r6,r7) /* touch next cache line */
sync
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ mtlr r9
wrtee r10
blr
#endif /* CONFIG_PPC_47x */
diff --git a/arch/powerpc/platforms/44x/44x.h b/arch/powerpc/platforms/44x/44x.h
index dbc4d2b4301a..63f703ecd23c 100644
--- a/arch/powerpc/platforms/44x/44x.h
+++ b/arch/powerpc/platforms/44x/44x.h
@@ -4,4 +4,8 @@
extern u8 as1_readb(volatile u8 __iomem *addr);
extern void as1_writeb(u8 data, volatile u8 __iomem *addr);
+#define GPIO0_OSRH 0xC
+#define GPIO0_TSRH 0x14
+#define GPIO0_ISR1H 0x34
+
#endif /* __POWERPC_PLATFORMS_44X_44X_H */
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 0f979c5c756b..f485fc5f6d5e 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -115,7 +115,6 @@ config CANYONLANDS
bool "Canyonlands"
depends on 44x
default n
- select PPC44x_SIMPLE
select 460EX
select PCI
select PPC4xx_PCI_EXPRESS
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index c04d16df8488..553db6007217 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_WARP) += warp.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o
obj-$(CONFIG_ISS4xx) += iss4xx.o
+obj-$(CONFIG_CANYONLANDS)+= canyonlands.o
diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c
new file mode 100644
index 000000000000..afc5e8ea3775
--- /dev/null
+++ b/arch/powerpc/platforms/44x/canyonlands.c
@@ -0,0 +1,134 @@
+/*
+ * This contain platform specific code for APM PPC460EX based Canyonlands
+ * board.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Author: Rupjyoti Sarmah <rsarmah@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc4xx.h>
+#include <asm/udbg.h>
+#include <asm/uic.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include "44x.h"
+
+#define BCSR_USB_EN 0x11
+
+static __initdata struct of_device_id ppc460ex_of_bus[] = {
+ { .compatible = "ibm,plb4", },
+ { .compatible = "ibm,opb", },
+ { .compatible = "ibm,ebc", },
+ { .compatible = "simple-bus", },
+ {},
+};
+
+static int __init ppc460ex_device_probe(void)
+{
+ of_platform_bus_probe(NULL, ppc460ex_of_bus, NULL);
+
+ return 0;
+}
+machine_device_initcall(canyonlands, ppc460ex_device_probe);
+
+/* Using this code only for the Canyonlands board. */
+
+static int __init ppc460ex_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+ if (of_flat_dt_is_compatible(root, "amcc,canyonlands")) {
+ ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
+ return 1;
+ }
+ return 0;
+}
+
+/* USB PHY fixup code on Canyonlands kit. */
+
+static int __init ppc460ex_canyonlands_fixup(void)
+{
+ u8 __iomem *bcsr ;
+ void __iomem *vaddr;
+ struct device_node *np;
+ int ret = 0;
+
+ np = of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-bcsr");
+ if (!np) {
+ printk(KERN_ERR "failed did not find amcc, ppc460ex bcsr node\n");
+ return -ENODEV;
+ }
+
+ bcsr = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (!bcsr) {
+ printk(KERN_CRIT "Could not remap bcsr\n");
+ ret = -ENODEV;
+ goto err_bcsr;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,ppc4xx-gpio");
+ if (!np) {
+ printk(KERN_ERR "failed did not find ibm,ppc4xx-gpio node\n");
+ return -ENODEV;
+ }
+
+ vaddr = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (!vaddr) {
+ printk(KERN_CRIT "Could not get gpio node address\n");
+ ret = -ENODEV;
+ goto err_gpio;
+ }
+ /* Disable USB, through the BCSR7 bits */
+ setbits8(&bcsr[7], BCSR_USB_EN);
+
+ /* Wait for a while after reset */
+ msleep(100);
+
+ /* Enable USB here */
+ clrbits8(&bcsr[7], BCSR_USB_EN);
+
+ /*
+ * Configure multiplexed gpio16 and gpio19 as alternate1 output
+ * source after USB reset. In this configuration gpio16 will be
+ * USB2HStop and gpio19 will be USB2DStop. For more details refer to
+ * table 34-7 of PPC460EX user manual.
+ */
+ setbits32((vaddr + GPIO0_OSRH), 0x42000000);
+ setbits32((vaddr + GPIO0_TSRH), 0x42000000);
+err_gpio:
+ iounmap(vaddr);
+err_bcsr:
+ iounmap(bcsr);
+ return ret;
+}
+machine_device_initcall(canyonlands, ppc460ex_canyonlands_fixup);
+define_machine(canyonlands) {
+ .name = "Canyonlands",
+ .probe = ppc460ex_probe,
+ .progress = udbg_progress,
+ .init_IRQ = uic_init_tree,
+ .get_irq = uic_get_irq,
+ .restart = ppc4xx_reset_system,
+ .calibrate_decr = generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index 7ddcba3b9397..c81c19c0b3d4 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -53,7 +53,6 @@ static char *board[] __initdata = {
"amcc,arches",
"amcc,bamboo",
"amcc,bluestone",
- "amcc,canyonlands",
"amcc,glacier",
"ibm,ebony",
"amcc,eiger",
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
index 4ecf4cf9a51b..fde0ea50c97d 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
@@ -59,9 +59,9 @@ irq_to_pic_bit(unsigned int irq)
}
static void
-cpld_mask_irq(unsigned int irq)
+cpld_mask_irq(struct irq_data *d)
{
- unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
out_8(pic_mask,
@@ -69,9 +69,9 @@ cpld_mask_irq(unsigned int irq)
}
static void
-cpld_unmask_irq(unsigned int irq)
+cpld_unmask_irq(struct irq_data *d)
{
- unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
out_8(pic_mask,
@@ -80,9 +80,9 @@ cpld_unmask_irq(unsigned int irq)
static struct irq_chip cpld_pic = {
.name = "CPLD PIC",
- .mask = cpld_mask_irq,
- .ack = cpld_mask_irq,
- .unmask = cpld_unmask_irq,
+ .irq_mask = cpld_mask_irq,
+ .irq_ack = cpld_mask_irq,
+ .irq_unmask = cpld_unmask_irq,
};
static int
diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
index 2c7780cb68e5..2bd1e6cf1f58 100644
--- a/arch/powerpc/platforms/52xx/media5200.c
+++ b/arch/powerpc/platforms/52xx/media5200.c
@@ -49,45 +49,46 @@ struct media5200_irq {
};
struct media5200_irq media5200_irq;
-static void media5200_irq_unmask(unsigned int virq)
+static void media5200_irq_unmask(struct irq_data *d)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&media5200_irq.lock, flags);
val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
- val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq);
+ val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq);
out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
spin_unlock_irqrestore(&media5200_irq.lock, flags);
}
-static void media5200_irq_mask(unsigned int virq)
+static void media5200_irq_mask(struct irq_data *d)
{
unsigned long flags;
u32 val;
spin_lock_irqsave(&media5200_irq.lock, flags);
val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
- val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[virq].hwirq));
+ val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq));
out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
spin_unlock_irqrestore(&media5200_irq.lock, flags);
}
static struct irq_chip media5200_irq_chip = {
.name = "Media5200 FPGA",
- .unmask = media5200_irq_unmask,
- .mask = media5200_irq_mask,
- .mask_ack = media5200_irq_mask,
+ .irq_unmask = media5200_irq_unmask,
+ .irq_mask = media5200_irq_mask,
+ .irq_mask_ack = media5200_irq_mask,
};
void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int sub_virq, val;
u32 status, enable;
/* Mask off the cascaded IRQ */
raw_spin_lock(&desc->lock);
- desc->chip->mask(virq);
+ chip->irq_mask(&desc->irq_data);
raw_spin_unlock(&desc->lock);
/* Ask the FPGA for IRQ status. If 'val' is 0, then no irqs
@@ -105,9 +106,9 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc)
/* Processing done; can reenable the cascade now */
raw_spin_lock(&desc->lock);
- desc->chip->ack(virq);
+ chip->irq_ack(&desc->irq_data);
if (!(desc->status & IRQ_DISABLED))
- desc->chip->unmask(virq);
+ chip->irq_unmask(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
index 859abf1c6d4b..6da44f0f2934 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
@@ -135,9 +135,9 @@ DEFINE_MUTEX(mpc52xx_gpt_list_mutex);
* Cascaded interrupt controller hooks
*/
-static void mpc52xx_gpt_irq_unmask(unsigned int virq)
+static void mpc52xx_gpt_irq_unmask(struct irq_data *d)
{
- struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+ struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d);
unsigned long flags;
spin_lock_irqsave(&gpt->lock, flags);
@@ -145,9 +145,9 @@ static void mpc52xx_gpt_irq_unmask(unsigned int virq)
spin_unlock_irqrestore(&gpt->lock, flags);
}
-static void mpc52xx_gpt_irq_mask(unsigned int virq)
+static void mpc52xx_gpt_irq_mask(struct irq_data *d)
{
- struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+ struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d);
unsigned long flags;
spin_lock_irqsave(&gpt->lock, flags);
@@ -155,20 +155,20 @@ static void mpc52xx_gpt_irq_mask(unsigned int virq)
spin_unlock_irqrestore(&gpt->lock, flags);
}
-static void mpc52xx_gpt_irq_ack(unsigned int virq)
+static void mpc52xx_gpt_irq_ack(struct irq_data *d)
{
- struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+ struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d);
out_be32(&gpt->regs->status, MPC52xx_GPT_STATUS_IRQMASK);
}
-static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type)
+static int mpc52xx_gpt_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq);
+ struct mpc52xx_gpt_priv *gpt = irq_data_get_irq_chip_data(d);
unsigned long flags;
u32 reg;
- dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, virq, flow_type);
+ dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, d->irq, flow_type);
spin_lock_irqsave(&gpt->lock, flags);
reg = in_be32(&gpt->regs->mode) & ~MPC52xx_GPT_MODE_ICT_MASK;
@@ -184,10 +184,10 @@ static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type)
static struct irq_chip mpc52xx_gpt_irq_chip = {
.name = "MPC52xx GPT",
- .unmask = mpc52xx_gpt_irq_unmask,
- .mask = mpc52xx_gpt_irq_mask,
- .ack = mpc52xx_gpt_irq_ack,
- .set_type = mpc52xx_gpt_irq_set_type,
+ .irq_unmask = mpc52xx_gpt_irq_unmask,
+ .irq_mask = mpc52xx_gpt_irq_mask,
+ .irq_ack = mpc52xx_gpt_irq_ack,
+ .irq_set_type = mpc52xx_gpt_irq_set_type,
};
void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc)
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 4bf4bf7b063e..9f3ed582d082 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -155,47 +155,47 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
/*
* IRQ[0-3] interrupt irq_chip
*/
-static void mpc52xx_extirq_mask(unsigned int virq)
+static void mpc52xx_extirq_mask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->ctrl, 11 - l2irq);
}
-static void mpc52xx_extirq_unmask(unsigned int virq)
+static void mpc52xx_extirq_unmask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->ctrl, 11 - l2irq);
}
-static void mpc52xx_extirq_ack(unsigned int virq)
+static void mpc52xx_extirq_ack(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->ctrl, 27-l2irq);
}
-static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
+static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
{
u32 ctrl_reg, type;
int irq;
int l2irq;
void *handler = handle_level_irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
@@ -214,44 +214,44 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type)
ctrl_reg |= (type << (22 - (l2irq * 2)));
out_be32(&intr->ctrl, ctrl_reg);
- __set_irq_handler_unlocked(virq, handler);
+ __set_irq_handler_unlocked(d->irq, handler);
return 0;
}
static struct irq_chip mpc52xx_extirq_irqchip = {
.name = "MPC52xx External",
- .mask = mpc52xx_extirq_mask,
- .unmask = mpc52xx_extirq_unmask,
- .ack = mpc52xx_extirq_ack,
- .set_type = mpc52xx_extirq_set_type,
+ .irq_mask = mpc52xx_extirq_mask,
+ .irq_unmask = mpc52xx_extirq_unmask,
+ .irq_ack = mpc52xx_extirq_ack,
+ .irq_set_type = mpc52xx_extirq_set_type,
};
/*
* Main interrupt irq_chip
*/
-static int mpc52xx_null_set_type(unsigned int virq, unsigned int flow_type)
+static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
{
return 0; /* Do nothing so that the sense mask will get updated */
}
-static void mpc52xx_main_mask(unsigned int virq)
+static void mpc52xx_main_mask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->main_mask, 16 - l2irq);
}
-static void mpc52xx_main_unmask(unsigned int virq)
+static void mpc52xx_main_unmask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->main_mask, 16 - l2irq);
@@ -259,32 +259,32 @@ static void mpc52xx_main_unmask(unsigned int virq)
static struct irq_chip mpc52xx_main_irqchip = {
.name = "MPC52xx Main",
- .mask = mpc52xx_main_mask,
- .mask_ack = mpc52xx_main_mask,
- .unmask = mpc52xx_main_unmask,
- .set_type = mpc52xx_null_set_type,
+ .irq_mask = mpc52xx_main_mask,
+ .irq_mask_ack = mpc52xx_main_mask,
+ .irq_unmask = mpc52xx_main_unmask,
+ .irq_set_type = mpc52xx_null_set_type,
};
/*
* Peripherals interrupt irq_chip
*/
-static void mpc52xx_periph_mask(unsigned int virq)
+static void mpc52xx_periph_mask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->per_mask, 31 - l2irq);
}
-static void mpc52xx_periph_unmask(unsigned int virq)
+static void mpc52xx_periph_unmask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->per_mask, 31 - l2irq);
@@ -292,43 +292,43 @@ static void mpc52xx_periph_unmask(unsigned int virq)
static struct irq_chip mpc52xx_periph_irqchip = {
.name = "MPC52xx Peripherals",
- .mask = mpc52xx_periph_mask,
- .mask_ack = mpc52xx_periph_mask,
- .unmask = mpc52xx_periph_unmask,
- .set_type = mpc52xx_null_set_type,
+ .irq_mask = mpc52xx_periph_mask,
+ .irq_mask_ack = mpc52xx_periph_mask,
+ .irq_unmask = mpc52xx_periph_unmask,
+ .irq_set_type = mpc52xx_null_set_type,
};
/*
* SDMA interrupt irq_chip
*/
-static void mpc52xx_sdma_mask(unsigned int virq)
+static void mpc52xx_sdma_mask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&sdma->IntMask, l2irq);
}
-static void mpc52xx_sdma_unmask(unsigned int virq)
+static void mpc52xx_sdma_unmask(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&sdma->IntMask, l2irq);
}
-static void mpc52xx_sdma_ack(unsigned int virq)
+static void mpc52xx_sdma_ack(struct irq_data *d)
{
int irq;
int l2irq;
- irq = irq_map[virq].hwirq;
+ irq = irq_map[d->irq].hwirq;
l2irq = irq & MPC52xx_IRQ_L2_MASK;
out_be32(&sdma->IntPend, 1 << l2irq);
@@ -336,10 +336,10 @@ static void mpc52xx_sdma_ack(unsigned int virq)
static struct irq_chip mpc52xx_sdma_irqchip = {
.name = "MPC52xx SDMA",
- .mask = mpc52xx_sdma_mask,
- .unmask = mpc52xx_sdma_unmask,
- .ack = mpc52xx_sdma_ack,
- .set_type = mpc52xx_null_set_type,
+ .irq_mask = mpc52xx_sdma_mask,
+ .irq_unmask = mpc52xx_sdma_unmask,
+ .irq_ack = mpc52xx_sdma_ack,
+ .irq_set_type = mpc52xx_null_set_type,
};
/**
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile
index d982793f4dbd..455fe21e37c4 100644
--- a/arch/powerpc/platforms/82xx/Makefile
+++ b/arch/powerpc/platforms/82xx/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_CPM2) += pq2.o
obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o
obj-$(CONFIG_PQ2FADS) += pq2fads.o
obj-$(CONFIG_EP8248E) += ep8248e.o
-obj-$(CONFIG_MGCOGE) += mgcoge.o
+obj-$(CONFIG_MGCOGE) += km82xx.o
diff --git a/arch/powerpc/platforms/82xx/mgcoge.c b/arch/powerpc/platforms/82xx/km82xx.c
index 7a5de9eb3c73..428c5e0a0e75 100644
--- a/arch/powerpc/platforms/82xx/mgcoge.c
+++ b/arch/powerpc/platforms/82xx/km82xx.c
@@ -1,6 +1,6 @@
/*
- * Keymile mgcoge support
- * Copyright 2008 DENX Software Engineering GmbH
+ * Keymile km82xx support
+ * Copyright 2008-2011 DENX Software Engineering GmbH
* Author: Heiko Schocher <hs@denx.de>
*
* based on code from:
@@ -31,9 +31,10 @@
#include "pq2.h"
-static void __init mgcoge_pic_init(void)
+static void __init km82xx_pic_init(void)
{
- struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic");
+ struct device_node *np = of_find_compatible_node(NULL, NULL,
+ "fsl,pq2-pic");
if (!np) {
printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
return;
@@ -47,12 +48,18 @@ struct cpm_pin {
int port, pin, flags;
};
-static __initdata struct cpm_pin mgcoge_pins[] = {
+static __initdata struct cpm_pin km82xx_pins[] = {
/* SMC2 */
{0, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
{0, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+ /* SCC1 */
+ {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
+
/* SCC4 */
{2, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
{2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
@@ -107,30 +114,49 @@ static __initdata struct cpm_pin mgcoge_pins[] = {
{3, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
{3, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_OPENDRAIN},
#endif
+
+ /* USB */
+ {0, 10, CPM_PIN_OUTPUT | CPM_PIN_GPIO}, /* FULL_SPEED */
+ {0, 11, CPM_PIN_OUTPUT | CPM_PIN_GPIO}, /*/SLAVE */
+ {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXN */
+ {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXP */
+ {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* /OE */
+ {2, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXCLK */
+ {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* TXP */
+ {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, /* TXN */
+ {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* RXD */
};
static void __init init_ioports(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(mgcoge_pins); i++) {
- const struct cpm_pin *pin = &mgcoge_pins[i];
+ for (i = 0; i < ARRAY_SIZE(km82xx_pins); i++) {
+ const struct cpm_pin *pin = &km82xx_pins[i];
cpm2_set_pin(pin->port, pin->pin, pin->flags);
}
cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8);
+ cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_RX);
+ cpm2_clk_setup(CPM_CLK_SCC1, CPM_CLK11, CPM_CLK_TX);
+ cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RTX);
cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK7, CPM_CLK_RX);
cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK8, CPM_CLK_TX);
cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_RX);
cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK9, CPM_CLK_TX);
cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX);
cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX);
+
+ /* Force USB FULL SPEED bit to '1' */
+ setbits32(&cpm2_immr->im_ioport.iop_pdata, 1 << (31 - 10));
+ /* clear USB_SLAVE */
+ clrbits32(&cpm2_immr->im_ioport.iop_pdata, 1 << (31 - 11));
}
-static void __init mgcoge_setup_arch(void)
+static void __init km82xx_setup_arch(void)
{
if (ppc_md.progress)
- ppc_md.progress("mgcoge_setup_arch()", 0);
+ ppc_md.progress("km82xx_setup_arch()", 0);
cpm2_reset();
@@ -142,7 +168,7 @@ static void __init mgcoge_setup_arch(void)
init_ioports();
if (ppc_md.progress)
- ppc_md.progress("mgcoge_setup_arch(), finish", 0);
+ ppc_md.progress("km82xx_setup_arch(), finish", 0);
}
static __initdata struct of_device_id of_bus_ids[] = {
@@ -156,23 +182,23 @@ static int __init declare_of_platform_devices(void)
return 0;
}
-machine_device_initcall(mgcoge, declare_of_platform_devices);
+machine_device_initcall(km82xx, declare_of_platform_devices);
/*
* Called very early, device-tree isn't unflattened
*/
-static int __init mgcoge_probe(void)
+static int __init km82xx_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- return of_flat_dt_is_compatible(root, "keymile,mgcoge");
+ return of_flat_dt_is_compatible(root, "keymile,km82xx");
}
-define_machine(mgcoge)
+define_machine(km82xx)
{
- .name = "Keymile MGCOGE",
- .probe = mgcoge_probe,
- .setup_arch = mgcoge_setup_arch,
- .init_IRQ = mgcoge_pic_init,
+ .name = "Keymile km82xx",
+ .probe = km82xx_probe,
+ .setup_arch = km82xx_setup_arch,
+ .init_IRQ = km82xx_pic_init,
.get_irq = cpm2_get_irq,
.calibrate_decr = generic_calibrate_decr,
.restart = pq2_restart,
diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
index 5a55d87d6bd6..926dfdaaf57a 100644
--- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
+++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
@@ -39,10 +39,10 @@ struct pq2ads_pci_pic {
#define NUM_IRQS 32
-static void pq2ads_pci_mask_irq(unsigned int virq)
+static void pq2ads_pci_mask_irq(struct irq_data *d)
{
- struct pq2ads_pci_pic *priv = get_irq_chip_data(virq);
- int irq = NUM_IRQS - virq_to_hw(virq) - 1;
+ struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
+ int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
if (irq != -1) {
unsigned long flags;
@@ -55,10 +55,10 @@ static void pq2ads_pci_mask_irq(unsigned int virq)
}
}
-static void pq2ads_pci_unmask_irq(unsigned int virq)
+static void pq2ads_pci_unmask_irq(struct irq_data *d)
{
- struct pq2ads_pci_pic *priv = get_irq_chip_data(virq);
- int irq = NUM_IRQS - virq_to_hw(virq) - 1;
+ struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
+ int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
if (irq != -1) {
unsigned long flags;
@@ -71,18 +71,17 @@ static void pq2ads_pci_unmask_irq(unsigned int virq)
static struct irq_chip pq2ads_pci_ic = {
.name = "PQ2 ADS PCI",
- .end = pq2ads_pci_unmask_irq,
- .mask = pq2ads_pci_mask_irq,
- .mask_ack = pq2ads_pci_mask_irq,
- .ack = pq2ads_pci_mask_irq,
- .unmask = pq2ads_pci_unmask_irq,
- .enable = pq2ads_pci_unmask_irq,
- .disable = pq2ads_pci_mask_irq
+ .irq_mask = pq2ads_pci_mask_irq,
+ .irq_mask_ack = pq2ads_pci_mask_irq,
+ .irq_ack = pq2ads_pci_mask_irq,
+ .irq_unmask = pq2ads_pci_unmask_irq,
+ .irq_enable = pq2ads_pci_unmask_irq,
+ .irq_disable = pq2ads_pci_mask_irq
};
static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
{
- struct pq2ads_pci_pic *priv = desc->handler_data;
+ struct pq2ads_pci_pic *priv = get_irq_desc_data(desc);
u32 stat, mask, pend;
int bit;
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 6e8bbbbcfdf8..ed95bfcbcbff 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -16,4 +16,4 @@ obj-$(CONFIG_MPC837x_MDS) += mpc837x_mds.o
obj-$(CONFIG_SBC834x) += sbc834x.o
obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o
obj-$(CONFIG_ASP834x) += asp834x.o
-obj-$(CONFIG_KMETER1) += kmeter1.o
+obj-$(CONFIG_KMETER1) += km83xx.o
diff --git a/arch/powerpc/platforms/83xx/kmeter1.c b/arch/powerpc/platforms/83xx/km83xx.c
index 903acfd851ac..a2b9b9ef1240 100644
--- a/arch/powerpc/platforms/83xx/kmeter1.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 DENX Software Engineering GmbH
+ * Copyright 2008-2011 DENX Software Engineering GmbH
* Author: Heiko Schocher <hs@denx.de>
*
* Description:
@@ -49,12 +49,12 @@
* Setup the architecture
*
*/
-static void __init kmeter1_setup_arch(void)
+static void __init mpc83xx_km_setup_arch(void)
{
struct device_node *np;
if (ppc_md.progress)
- ppc_md.progress("kmeter1_setup_arch()", 0);
+ ppc_md.progress("kmpbec83xx_setup_arch()", 0);
#ifdef CONFIG_PCI
for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
@@ -69,6 +69,9 @@ static void __init kmeter1_setup_arch(void)
par_io_init(np);
of_node_put(np);
+ for_each_node_by_name(np, "spi")
+ par_io_of_config(np);
+
for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
par_io_of_config(np);
}
@@ -119,7 +122,7 @@ static void __init kmeter1_setup_arch(void)
#endif /* CONFIG_QUICC_ENGINE */
}
-static struct of_device_id kmeter_ids[] = {
+static struct of_device_id kmpbec83xx_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
@@ -131,13 +134,13 @@ static struct of_device_id kmeter_ids[] = {
static int __init kmeter_declare_of_platform_devices(void)
{
/* Publish the QE devices */
- of_platform_bus_probe(NULL, kmeter_ids, NULL);
+ of_platform_bus_probe(NULL, kmpbec83xx_ids, NULL);
return 0;
}
-machine_device_initcall(kmeter1, kmeter_declare_of_platform_devices);
+machine_device_initcall(mpc83xx_km, kmeter_declare_of_platform_devices);
-static void __init kmeter1_init_IRQ(void)
+static void __init mpc83xx_km_init_IRQ(void)
{
struct device_node *np;
@@ -168,21 +171,34 @@ static void __init kmeter1_init_IRQ(void)
#endif /* CONFIG_QUICC_ENGINE */
}
+/* list of the supported boards */
+static char *board[] __initdata = {
+ "Keymile,KMETER1",
+ "Keymile,kmpbec8321",
+ NULL
+};
+
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
-static int __init kmeter1_probe(void)
+static int __init mpc83xx_km_probe(void)
{
- unsigned long root = of_get_flat_dt_root();
+ unsigned long node = of_get_flat_dt_root();
+ int i = 0;
- return of_flat_dt_is_compatible(root, "keymile,KMETER1");
+ while (board[i]) {
+ if (of_flat_dt_is_compatible(node, board[i]))
+ break;
+ i++;
+ }
+ return (board[i] != NULL);
}
-define_machine(kmeter1) {
- .name = "KMETER1",
- .probe = kmeter1_probe,
- .setup_arch = kmeter1_setup_arch,
- .init_IRQ = kmeter1_init_IRQ,
+define_machine(mpc83xx_km) {
+ .name = "mpc83xx-km-platform",
+ .probe = mpc83xx_km_probe,
+ .setup_arch = mpc83xx_km_setup_arch,
+ .init_IRQ = mpc83xx_km_init_IRQ,
.get_irq = ipic_get_irq,
.restart = mpc83xx_restart,
.time_init = mpc83xx_time_init,
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c
index f4d36b5a2e00..64447e48f3d5 100644
--- a/arch/powerpc/platforms/85xx/ksi8560.c
+++ b/arch/powerpc/platforms/85xx/ksi8560.c
@@ -56,12 +56,13 @@ static void machine_restart(char *cmd)
static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int cascade_irq;
while ((cascade_irq = cpm2_get_irq()) >= 0)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
static void __init ksi8560_pic_init(void)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 9438a892afc4..1352d1107bfd 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -50,12 +50,13 @@ static int mpc85xx_exclude_device(struct pci_controller *hose,
static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int cascade_irq;
while ((cascade_irq = cpm2_get_irq()) >= 0)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 8190bc25bf27..793ead7993ab 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -47,12 +47,13 @@
#ifdef CONFIG_PPC_I8259
static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ) {
generic_handle_irq(cascade_irq);
}
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_PPC_I8259 */
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
index a5ad1c7794bf..d7e28ec3e072 100644
--- a/arch/powerpc/platforms/85xx/sbc8560.c
+++ b/arch/powerpc/platforms/85xx/sbc8560.c
@@ -41,12 +41,13 @@
static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int cascade_irq;
while ((cascade_irq = cpm2_get_irq()) >= 0)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 5c91a992f02b..0d00ff9d05a0 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -91,10 +91,14 @@ smp_85xx_kick_cpu(int nr)
while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
mdelay(1);
#else
+ smp_generic_kick_cpu(nr);
+
out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
- smp_generic_kick_cpu(nr);
+ if (!ioremappable)
+ flush_dcache_range((ulong)bptr_vaddr,
+ (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
#endif
local_irq_restore(flags);
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
index d48527ffc425..79d85aca4767 100644
--- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -93,6 +93,7 @@ static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq;
/*
@@ -103,17 +104,16 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
-
+ chip->irq_eoi(&desc->irq_data);
}
-static void socrates_fpga_pic_ack(unsigned int virq)
+static void socrates_fpga_pic_ack(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq, irq_line;
uint32_t mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
@@ -124,14 +124,14 @@ static void socrates_fpga_pic_ack(unsigned int virq)
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
}
-static void socrates_fpga_pic_mask(unsigned int virq)
+static void socrates_fpga_pic_mask(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
@@ -142,14 +142,14 @@ static void socrates_fpga_pic_mask(unsigned int virq)
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
}
-static void socrates_fpga_pic_mask_ack(unsigned int virq)
+static void socrates_fpga_pic_mask_ack(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
@@ -161,14 +161,14 @@ static void socrates_fpga_pic_mask_ack(unsigned int virq)
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
}
-static void socrates_fpga_pic_unmask(unsigned int virq)
+static void socrates_fpga_pic_unmask(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
@@ -179,14 +179,14 @@ static void socrates_fpga_pic_unmask(unsigned int virq)
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
}
-static void socrates_fpga_pic_eoi(unsigned int virq)
+static void socrates_fpga_pic_eoi(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
@@ -197,7 +197,7 @@ static void socrates_fpga_pic_eoi(unsigned int virq)
raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
}
-static int socrates_fpga_pic_set_type(unsigned int virq,
+static int socrates_fpga_pic_set_type(struct irq_data *d,
unsigned int flow_type)
{
unsigned long flags;
@@ -205,7 +205,7 @@ static int socrates_fpga_pic_set_type(unsigned int virq,
int polarity;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(virq);
+ hwirq = socrates_fpga_irq_to_hw(d->irq);
if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
return -EINVAL;
@@ -233,12 +233,12 @@ static int socrates_fpga_pic_set_type(unsigned int virq,
static struct irq_chip socrates_fpga_pic_chip = {
.name = "FPGA-PIC",
- .ack = socrates_fpga_pic_ack,
- .mask = socrates_fpga_pic_mask,
- .mask_ack = socrates_fpga_pic_mask_ack,
- .unmask = socrates_fpga_pic_unmask,
- .eoi = socrates_fpga_pic_eoi,
- .set_type = socrates_fpga_pic_set_type,
+ .irq_ack = socrates_fpga_pic_ack,
+ .irq_mask = socrates_fpga_pic_mask,
+ .irq_mask_ack = socrates_fpga_pic_mask_ack,
+ .irq_unmask = socrates_fpga_pic_unmask,
+ .irq_eoi = socrates_fpga_pic_eoi,
+ .irq_set_type = socrates_fpga_pic_set_type,
};
static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq,
diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c
index bc33d1859ae7..2b62b064eac7 100644
--- a/arch/powerpc/platforms/85xx/stx_gp3.c
+++ b/arch/powerpc/platforms/85xx/stx_gp3.c
@@ -46,12 +46,13 @@
static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int cascade_irq;
while ((cascade_irq = cpm2_get_irq()) >= 0)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c
index 5e847d0b47c8..2265b68e3279 100644
--- a/arch/powerpc/platforms/85xx/tqm85xx.c
+++ b/arch/powerpc/platforms/85xx/tqm85xx.c
@@ -44,12 +44,13 @@
static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
int cascade_irq;
while ((cascade_irq = cpm2_get_irq()) >= 0)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
index 6df9e2561c06..0adfe3b740cd 100644
--- a/arch/powerpc/platforms/86xx/gef_pic.c
+++ b/arch/powerpc/platforms/86xx/gef_pic.c
@@ -95,6 +95,7 @@ static int gef_pic_cascade_irq;
void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq;
/*
@@ -106,17 +107,16 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
-
+ chip->irq_eoi(&desc->irq_data);
}
-static void gef_pic_mask(unsigned int virq)
+static void gef_pic_mask(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
u32 mask;
- hwirq = gef_irq_to_hw(virq);
+ hwirq = gef_irq_to_hw(d->irq);
raw_spin_lock_irqsave(&gef_pic_lock, flags);
mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
@@ -125,21 +125,21 @@ static void gef_pic_mask(unsigned int virq)
raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
}
-static void gef_pic_mask_ack(unsigned int virq)
+static void gef_pic_mask_ack(struct irq_data *d)
{
/* Don't think we actually have to do anything to ack an interrupt,
* we just need to clear down the devices interrupt and it will go away
*/
- gef_pic_mask(virq);
+ gef_pic_mask(d);
}
-static void gef_pic_unmask(unsigned int virq)
+static void gef_pic_unmask(struct irq_data *d)
{
unsigned long flags;
unsigned int hwirq;
u32 mask;
- hwirq = gef_irq_to_hw(virq);
+ hwirq = gef_irq_to_hw(d->irq);
raw_spin_lock_irqsave(&gef_pic_lock, flags);
mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
@@ -150,9 +150,9 @@ static void gef_pic_unmask(unsigned int virq)
static struct irq_chip gef_pic_chip = {
.name = "gefp",
- .mask = gef_pic_mask,
- .mask_ack = gef_pic_mask_ack,
- .unmask = gef_pic_unmask,
+ .irq_mask = gef_pic_mask,
+ .irq_mask_ack = gef_pic_mask_ack,
+ .irq_unmask = gef_pic_unmask,
};
diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c
index 668275d9e668..cbe33639b478 100644
--- a/arch/powerpc/platforms/86xx/pic.c
+++ b/arch/powerpc/platforms/86xx/pic.c
@@ -19,10 +19,13 @@
#ifdef CONFIG_PPC_I8259
static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = i8259_irq();
+
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
#endif /* CONFIG_PPC_I8259 */
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index dd35ce081cff..ee56a9ea6a79 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -49,12 +49,6 @@ config PPC_ADDER875
This enables support for the Analogue & Micro Adder 875
board.
-config PPC_MGSUVD
- bool "MGSUVD"
- select CPM1
- help
- This enables support for the Keymile MGSUVD board.
-
config TQM8XX
bool "TQM8XX"
select CPM1
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
index a491fe6b94fc..76a81c3350a8 100644
--- a/arch/powerpc/platforms/8xx/Makefile
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -6,5 +6,4 @@ obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
obj-$(CONFIG_PPC_EP88XC) += ep88xc.o
obj-$(CONFIG_PPC_ADDER875) += adder875.o
-obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o
obj-$(CONFIG_TQM8XX) += tqm8xx_setup.o
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 60168c1f98fe..fabb108e8744 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -218,15 +218,20 @@ void mpc8xx_restart(char *cmd)
static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip;
int cascade_irq;
if ((cascade_irq = cpm_get_irq()) >= 0) {
struct irq_desc *cdesc = irq_to_desc(cascade_irq);
generic_handle_irq(cascade_irq);
- cdesc->chip->eoi(cascade_irq);
+
+ chip = get_irq_desc_chip(cdesc);
+ chip->irq_eoi(&cdesc->irq_data);
}
- desc->chip->eoi(irq);
+
+ chip = get_irq_desc_chip(desc);
+ chip->irq_eoi(&desc->irq_data);
}
/* Initialize the internal interrupt controllers. The number of
diff --git a/arch/powerpc/platforms/8xx/mgsuvd.c b/arch/powerpc/platforms/8xx/mgsuvd.c
deleted file mode 100644
index ca3cb071772c..000000000000
--- a/arch/powerpc/platforms/8xx/mgsuvd.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- * Platform setup for the Keymile mgsuvd board
- *
- * Heiko Schocher <hs@denx.de>
- *
- * Copyright 2008 DENX Software Engineering GmbH
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/ioport.h>
-#include <linux/of_platform.h>
-
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/processor.h>
-#include <asm/cpm1.h>
-#include <asm/prom.h>
-#include <asm/fs_pd.h>
-
-#include "mpc8xx.h"
-
-struct cpm_pin {
- int port, pin, flags;
-};
-
-static __initdata struct cpm_pin mgsuvd_pins[] = {
- /* SMC1 */
- {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
- {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
-
- /* SCC3 */
- {CPM_PORTA, 10, CPM_PIN_INPUT},
- {CPM_PORTA, 11, CPM_PIN_INPUT},
- {CPM_PORTA, 3, CPM_PIN_INPUT},
- {CPM_PORTA, 2, CPM_PIN_INPUT},
- {CPM_PORTC, 13, CPM_PIN_INPUT},
-};
-
-static void __init init_ioports(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mgsuvd_pins); i++) {
- struct cpm_pin *pin = &mgsuvd_pins[i];
- cpm1_set_pin(pin->port, pin->pin, pin->flags);
- }
-
- setbits16(&mpc8xx_immr->im_ioport.iop_pcso, 0x300);
- cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RX);
- cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_TX);
- cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
-}
-
-static void __init mgsuvd_setup_arch(void)
-{
- cpm_reset();
- init_ioports();
-}
-
-static __initdata struct of_device_id of_bus_ids[] = {
- { .compatible = "simple-bus" },
- {},
-};
-
-static int __init declare_of_platform_devices(void)
-{
- of_platform_bus_probe(NULL, of_bus_ids, NULL);
- return 0;
-}
-machine_device_initcall(mgsuvd, declare_of_platform_devices);
-
-static int __init mgsuvd_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
- return of_flat_dt_is_compatible(root, "keymile,mgsuvd");
-}
-
-define_machine(mgsuvd) {
- .name = "MGSUVD",
- .probe = mgsuvd_probe,
- .setup_arch = mgsuvd_setup_arch,
- .init_IRQ = mpc8xx_pics_init,
- .get_irq = mpc8xx_get_irq,
- .restart = mpc8xx_restart,
- .calibrate_decr = mpc8xx_calibrate_decr,
- .set_rtc_time = mpc8xx_set_rtc_time,
- .get_rtc_time = mpc8xx_get_rtc_time,
-};
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index c35099af340e..c48b66a67e42 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -93,6 +93,7 @@ static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
struct axon_msic *msic = get_irq_data(irq);
u32 write_offset, msi;
int idx;
@@ -145,7 +146,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
msic->read_offset &= MSIC_FIFO_SIZE_MASK;
}
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
static struct axon_msic *find_msi_translator(struct pci_dev *dev)
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 682af97321a8..0b8f7d7135c5 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -61,59 +61,59 @@ static inline void beatic_update_irq_mask(unsigned int irq_plug)
panic("Failed to set mask IRQ!");
}
-static void beatic_mask_irq(unsigned int irq_plug)
+static void beatic_mask_irq(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
- beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
- beatic_update_irq_mask(irq_plug);
+ beatic_irq_mask_enable[d->irq/64] &= ~(1UL << (63 - (d->irq%64)));
+ beatic_update_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
}
-static void beatic_unmask_irq(unsigned int irq_plug)
+static void beatic_unmask_irq(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
- beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
- beatic_update_irq_mask(irq_plug);
+ beatic_irq_mask_enable[d->irq/64] |= 1UL << (63 - (d->irq%64));
+ beatic_update_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
}
-static void beatic_ack_irq(unsigned int irq_plug)
+static void beatic_ack_irq(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
- beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
- beatic_update_irq_mask(irq_plug);
+ beatic_irq_mask_ack[d->irq/64] &= ~(1UL << (63 - (d->irq%64)));
+ beatic_update_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
}
-static void beatic_end_irq(unsigned int irq_plug)
+static void beatic_end_irq(struct irq_data *d)
{
s64 err;
unsigned long flags;
- err = beat_downcount_of_interrupt(irq_plug);
+ err = beat_downcount_of_interrupt(d->irq);
if (err != 0) {
if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
panic("Failed to downcount IRQ! Error = %16llx", err);
- printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
+ printk(KERN_ERR "IRQ over-downcounted, plug %d\n", d->irq);
}
raw_spin_lock_irqsave(&beatic_irq_mask_lock, flags);
- beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
- beatic_update_irq_mask(irq_plug);
+ beatic_irq_mask_ack[d->irq/64] |= 1UL << (63 - (d->irq%64));
+ beatic_update_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
}
static struct irq_chip beatic_pic = {
.name = "CELL-BEAT",
- .unmask = beatic_unmask_irq,
- .mask = beatic_mask_irq,
- .eoi = beatic_end_irq,
+ .irq_unmask = beatic_unmask_irq,
+ .irq_mask = beatic_mask_irq,
+ .irq_eoi = beatic_end_irq,
};
/*
@@ -232,7 +232,7 @@ unsigned int beatic_get_irq(void)
ret = beatic_get_irq_plug();
if (ret != NO_IRQ)
- beatic_ack_irq(ret);
+ beatic_ack_irq(irq_get_irq_data(ret));
return ret;
}
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 10eb1a443626..624d26e72f1d 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -72,15 +72,15 @@ static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
}
-static void iic_mask(unsigned int irq)
+static void iic_mask(struct irq_data *d)
{
}
-static void iic_unmask(unsigned int irq)
+static void iic_unmask(struct irq_data *d)
{
}
-static void iic_eoi(unsigned int irq)
+static void iic_eoi(struct irq_data *d)
{
struct iic *iic = &__get_cpu_var(cpu_iic);
out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
@@ -89,19 +89,21 @@ static void iic_eoi(unsigned int irq)
static struct irq_chip iic_chip = {
.name = "CELL-IIC",
- .mask = iic_mask,
- .unmask = iic_unmask,
- .eoi = iic_eoi,
+ .irq_mask = iic_mask,
+ .irq_unmask = iic_unmask,
+ .irq_eoi = iic_eoi,
};
-static void iic_ioexc_eoi(unsigned int irq)
+static void iic_ioexc_eoi(struct irq_data *d)
{
}
static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
{
- struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data;
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ struct cbe_iic_regs __iomem *node_iic =
+ (void __iomem *)get_irq_desc_data(desc);
unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
unsigned long bits, ack;
int cascade;
@@ -128,15 +130,15 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
if (ack)
out_be64(&node_iic->iic_is, ack);
}
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
}
static struct irq_chip iic_ioexc_chip = {
.name = "CELL-IOEX",
- .mask = iic_mask,
- .unmask = iic_unmask,
- .eoi = iic_ioexc_eoi,
+ .irq_mask = iic_mask,
+ .irq_unmask = iic_unmask,
+ .irq_eoi = iic_ioexc_eoi,
};
/* Get an IRQ number from the pending state register of the IIC */
@@ -237,6 +239,8 @@ extern int noirqdebug;
static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+
raw_spin_lock(&desc->lock);
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
@@ -275,7 +279,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
desc->status &= ~IRQ_INPROGRESS;
out_eoi:
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 691995761b3d..6a28d027d959 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -187,13 +187,15 @@ machine_subsys_initcall(cell, cell_publish_devices);
static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
{
- struct mpic *mpic = desc->handler_data;
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ struct mpic *mpic = get_irq_desc_data(desc);
unsigned int virq;
virq = mpic_get_one_irq(mpic);
if (virq != NO_IRQ)
generic_handle_irq(virq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
static void __init mpic_init_IRQ(void)
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 3f2e557344a3..b38cdfc1deb8 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -79,30 +79,30 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic,
return pic->regs + TIR_CFGA + 8 * src;
}
-static void spider_unmask_irq(unsigned int virq)
+static void spider_unmask_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(virq);
- void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
+ struct spider_pic *pic = spider_virq_to_pic(d->irq);
+ void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
out_be32(cfg, in_be32(cfg) | 0x30000000u);
}
-static void spider_mask_irq(unsigned int virq)
+static void spider_mask_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(virq);
- void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
+ struct spider_pic *pic = spider_virq_to_pic(d->irq);
+ void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
out_be32(cfg, in_be32(cfg) & ~0x30000000u);
}
-static void spider_ack_irq(unsigned int virq)
+static void spider_ack_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(virq);
- unsigned int src = irq_map[virq].hwirq;
+ struct spider_pic *pic = spider_virq_to_pic(d->irq);
+ unsigned int src = irq_map[d->irq].hwirq;
/* Reset edge detection logic if necessary
*/
- if (irq_to_desc(virq)->status & IRQ_LEVEL)
+ if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
return;
/* Only interrupts 47 to 50 can be set to edge */
@@ -113,13 +113,13 @@ static void spider_ack_irq(unsigned int virq)
out_be32(pic->regs + TIR_EDC, 0x100 | (src & 0xf));
}
-static int spider_set_irq_type(unsigned int virq, unsigned int type)
+static int spider_set_irq_type(struct irq_data *d, unsigned int type)
{
unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
- struct spider_pic *pic = spider_virq_to_pic(virq);
- unsigned int hw = irq_map[virq].hwirq;
+ struct spider_pic *pic = spider_virq_to_pic(d->irq);
+ unsigned int hw = irq_map[d->irq].hwirq;
void __iomem *cfg = spider_get_irq_config(pic, hw);
- struct irq_desc *desc = irq_to_desc(virq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
u32 old_mask;
u32 ic;
@@ -169,10 +169,10 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type)
static struct irq_chip spider_pic = {
.name = "SPIDER",
- .unmask = spider_unmask_irq,
- .mask = spider_mask_irq,
- .ack = spider_ack_irq,
- .set_type = spider_set_irq_type,
+ .irq_unmask = spider_unmask_irq,
+ .irq_mask = spider_mask_irq,
+ .irq_ack = spider_ack_irq,
+ .irq_set_type = spider_set_irq_type,
};
static int spider_host_map(struct irq_host *h, unsigned int virq,
@@ -207,7 +207,8 @@ static struct irq_host_ops spider_host_ops = {
static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
{
- struct spider_pic *pic = desc->handler_data;
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ struct spider_pic *pic = get_irq_desc_data(desc);
unsigned int cs, virq;
cs = in_be32(pic->regs + TIR_CS) >> 24;
@@ -215,9 +216,11 @@ static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
virq = NO_IRQ;
else
virq = irq_linear_revmap(pic->host, cs);
+
if (virq != NO_IRQ)
generic_handle_irq(virq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
/* For hooking up the cascace we have a problem. Our device-tree is
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 8553cc49e0d6..4c1288451a21 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -365,10 +365,13 @@ void __init chrp_setup_arch(void)
static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = i8259_irq();
+
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
/*
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
index c278bd3a8fec..0aca0e28a8e5 100644
--- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
@@ -46,10 +46,10 @@
*
*/
-static void flipper_pic_mask_and_ack(unsigned int virq)
+static void flipper_pic_mask_and_ack(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
clrbits32(io_base + FLIPPER_IMR, mask);
@@ -57,27 +57,27 @@ static void flipper_pic_mask_and_ack(unsigned int virq)
out_be32(io_base + FLIPPER_ICR, mask);
}
-static void flipper_pic_ack(unsigned int virq)
+static void flipper_pic_ack(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
/* this is at least needed for RSW */
out_be32(io_base + FLIPPER_ICR, 1 << irq);
}
-static void flipper_pic_mask(unsigned int virq)
+static void flipper_pic_mask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + FLIPPER_IMR, 1 << irq);
}
-static void flipper_pic_unmask(unsigned int virq)
+static void flipper_pic_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + FLIPPER_IMR, 1 << irq);
}
@@ -85,10 +85,10 @@ static void flipper_pic_unmask(unsigned int virq)
static struct irq_chip flipper_pic = {
.name = "flipper-pic",
- .ack = flipper_pic_ack,
- .mask_ack = flipper_pic_mask_and_ack,
- .mask = flipper_pic_mask,
- .unmask = flipper_pic_unmask,
+ .irq_ack = flipper_pic_ack,
+ .irq_mask_ack = flipper_pic_mask_and_ack,
+ .irq_mask = flipper_pic_mask,
+ .irq_unmask = flipper_pic_unmask,
};
/*
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index a771f91e215b..35e448bd8479 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -41,36 +41,36 @@
*
*/
-static void hlwd_pic_mask_and_ack(unsigned int virq)
+static void hlwd_pic_mask_and_ack(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
clrbits32(io_base + HW_BROADWAY_IMR, mask);
out_be32(io_base + HW_BROADWAY_ICR, mask);
}
-static void hlwd_pic_ack(unsigned int virq)
+static void hlwd_pic_ack(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
out_be32(io_base + HW_BROADWAY_ICR, 1 << irq);
}
-static void hlwd_pic_mask(unsigned int virq)
+static void hlwd_pic_mask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
}
-static void hlwd_pic_unmask(unsigned int virq)
+static void hlwd_pic_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void __iomem *io_base = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
}
@@ -78,10 +78,10 @@ static void hlwd_pic_unmask(unsigned int virq)
static struct irq_chip hlwd_pic = {
.name = "hlwd-pic",
- .ack = hlwd_pic_ack,
- .mask_ack = hlwd_pic_mask_and_ack,
- .mask = hlwd_pic_mask,
- .unmask = hlwd_pic_unmask,
+ .irq_ack = hlwd_pic_ack,
+ .irq_mask_ack = hlwd_pic_mask_and_ack,
+ .irq_mask = hlwd_pic_mask,
+ .irq_unmask = hlwd_pic_unmask,
};
/*
@@ -129,11 +129,12 @@ static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
struct irq_host *irq_host = get_irq_data(cascade_virq);
unsigned int virq;
raw_spin_lock(&desc->lock);
- desc->chip->mask(cascade_virq); /* IRQ_LEVEL */
+ chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */
raw_spin_unlock(&desc->lock);
virq = __hlwd_pic_get_irq(irq_host);
@@ -143,9 +144,9 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
pr_err("spurious interrupt!\n");
raw_spin_lock(&desc->lock);
- desc->chip->ack(cascade_virq); /* IRQ_LEVEL */
- if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
- desc->chip->unmask(cascade_virq);
+ chip->irq_ack(&desc->irq_data); /* IRQ_LEVEL */
+ if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
+ chip->irq_unmask(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index ba446bf355a9..4fb96f0b2df6 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -167,11 +167,11 @@ static void pci_event_handler(struct HvLpEvent *event)
* This will be called by device drivers (via enable_IRQ)
* to enable INTA in the bridge interrupt status register.
*/
-static void iseries_enable_IRQ(unsigned int irq)
+static void iseries_enable_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -184,23 +184,23 @@ static void iseries_enable_IRQ(unsigned int irq)
}
/* This is called by iseries_activate_IRQs */
-static unsigned int iseries_startup_IRQ(unsigned int irq)
+static unsigned int iseries_startup_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
/* Link the IRQ number to the bridge */
- HvCallXm_connectBusUnit(bus, sub_bus, dev_id, irq);
+ HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);
/* Unmask bridge interrupts in the FISR */
mask = 0x01010000 << function;
HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
- iseries_enable_IRQ(irq);
+ iseries_enable_IRQ(d);
return 0;
}
@@ -215,21 +215,26 @@ void __init iSeries_activate_IRQs()
for_each_irq (irq) {
struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_chip *chip;
- if (desc && desc->chip && desc->chip->startup) {
+ if (!desc)
+ continue;
+
+ chip = get_irq_desc_chip(desc);
+ if (chip && chip->irq_startup) {
raw_spin_lock_irqsave(&desc->lock, flags);
- desc->chip->startup(irq);
+ chip->irq_startup(&desc->irq_data);
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
}
}
/* this is not called anywhere currently */
-static void iseries_shutdown_IRQ(unsigned int irq)
+static void iseries_shutdown_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
/* irq should be locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -248,11 +253,11 @@ static void iseries_shutdown_IRQ(unsigned int irq)
* This will be called by device drivers (via disable_IRQ)
* to disable INTA in the bridge interrupt status register.
*/
-static void iseries_disable_IRQ(unsigned int irq)
+static void iseries_disable_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -264,9 +269,9 @@ static void iseries_disable_IRQ(unsigned int irq)
HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
}
-static void iseries_end_IRQ(unsigned int irq)
+static void iseries_end_IRQ(struct irq_data *d)
{
- unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+ unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
@@ -274,11 +279,11 @@ static void iseries_end_IRQ(unsigned int irq)
static struct irq_chip iseries_pic = {
.name = "iSeries",
- .startup = iseries_startup_IRQ,
- .shutdown = iseries_shutdown_IRQ,
- .unmask = iseries_enable_IRQ,
- .mask = iseries_disable_IRQ,
- .eoi = iseries_end_IRQ
+ .irq_startup = iseries_startup_IRQ,
+ .irq_shutdown = iseries_shutdown_IRQ,
+ .irq_unmask = iseries_enable_IRQ,
+ .irq_mask = iseries_disable_IRQ,
+ .irq_eoi = iseries_end_IRQ
};
/*
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index f372ec1691a3..a6067b38d2ca 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -240,7 +240,7 @@ static __init void pas_init_IRQ(void)
nmi_virq = irq_create_mapping(NULL, *nmiprop);
mpic_irq_set_priority(nmi_virq, 15);
set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING);
- mpic_unmask_irq(nmi_virq);
+ mpic_unmask_irq(irq_get_irq_data(nmi_virq));
}
of_node_put(mpic_node);
@@ -266,7 +266,7 @@ static int pas_machine_check_handler(struct pt_regs *regs)
if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) {
printk(KERN_ERR "NMI delivered\n");
debugger(regs);
- mpic_end_irq(nmi_virq);
+ mpic_end_irq(irq_get_irq_data(nmi_virq));
goto out;
}
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 415ca6d6b273..04af5f48b4eb 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -429,7 +429,7 @@ static u32 read_gpio(struct device_node *np)
return offset;
}
-static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
+static int pmac_cpufreq_suspend(struct cpufreq_policy *policy)
{
/* Ok, this could be made a bit smarter, but let's be robust for now. We
* always force a speed change to high speed before sleep, to make sure
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 890d5f72b198..c55812bb6a51 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -82,9 +82,9 @@ static void __pmac_retrigger(unsigned int irq_nr)
}
}
-static void pmac_mask_and_ack_irq(unsigned int virq)
+static void pmac_mask_and_ack_irq(struct irq_data *d)
{
- unsigned int src = irq_map[virq].hwirq;
+ unsigned int src = irq_map[d->irq].hwirq;
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
unsigned long flags;
@@ -104,9 +104,9 @@ static void pmac_mask_and_ack_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_ack_irq(unsigned int virq)
+static void pmac_ack_irq(struct irq_data *d)
{
- unsigned int src = irq_map[virq].hwirq;
+ unsigned int src = irq_map[d->irq].hwirq;
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
unsigned long flags;
@@ -149,15 +149,15 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
/* When an irq gets requested for the first client, if it's an
* edge interrupt, we clear any previous one on the controller
*/
-static unsigned int pmac_startup_irq(unsigned int virq)
+static unsigned int pmac_startup_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[virq].hwirq;
+ unsigned int src = irq_map[d->irq].hwirq;
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
- if ((irq_to_desc(virq)->status & IRQ_LEVEL) == 0)
+ if ((irq_to_desc(d->irq)->status & IRQ_LEVEL) == 0)
out_le32(&pmac_irq_hw[i]->ack, bit);
__set_bit(src, ppc_cached_irq_mask);
__pmac_set_irq_mask(src, 0);
@@ -166,10 +166,10 @@ static unsigned int pmac_startup_irq(unsigned int virq)
return 0;
}
-static void pmac_mask_irq(unsigned int virq)
+static void pmac_mask_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[virq].hwirq;
+ unsigned int src = irq_map[d->irq].hwirq;
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
__clear_bit(src, ppc_cached_irq_mask);
@@ -177,10 +177,10 @@ static void pmac_mask_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static void pmac_unmask_irq(unsigned int virq)
+static void pmac_unmask_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[virq].hwirq;
+ unsigned int src = irq_map[d->irq].hwirq;
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
__set_bit(src, ppc_cached_irq_mask);
@@ -188,24 +188,24 @@ static void pmac_unmask_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
}
-static int pmac_retrigger(unsigned int virq)
+static int pmac_retrigger(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
- __pmac_retrigger(irq_map[virq].hwirq);
+ __pmac_retrigger(irq_map[d->irq].hwirq);
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 1;
}
static struct irq_chip pmac_pic = {
.name = "PMAC-PIC",
- .startup = pmac_startup_irq,
- .mask = pmac_mask_irq,
- .ack = pmac_ack_irq,
- .mask_ack = pmac_mask_and_ack_irq,
- .unmask = pmac_unmask_irq,
- .retrigger = pmac_retrigger,
+ .irq_startup = pmac_startup_irq,
+ .irq_mask = pmac_mask_irq,
+ .irq_ack = pmac_ack_irq,
+ .irq_mask_ack = pmac_mask_and_ack_irq,
+ .irq_unmask = pmac_unmask_irq,
+ .irq_retrigger = pmac_retrigger,
};
static irqreturn_t gatwick_action(int cpl, void *dev_id)
@@ -472,12 +472,14 @@ int of_irq_map_oldworld(struct device_node *device, int index,
static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
{
- struct mpic *mpic = desc->handler_data;
-
+ struct irq_chip *chip = get_irq_desc_chip(desc);
+ struct mpic *mpic = get_irq_desc_data(desc);
unsigned int cascade_irq = mpic_get_one_irq(mpic);
+
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
@@ -707,7 +709,7 @@ static int pmacpic_resume(struct sys_device *sysdev)
mb();
for (i = 0; i < max_real_irqs; ++i)
if (test_bit(i, sleep_save_mask))
- pmac_unmask_irq(i);
+ pmac_unmask_irq(irq_get_irq_data(i));
return 0;
}
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 92290ff4761a..3988c86682a5 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -99,16 +99,16 @@ static DEFINE_PER_CPU(struct ps3_private, ps3_private);
* Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
*/
-static void ps3_chip_mask(unsigned int virq)
+static void ps3_chip_mask(struct irq_data *d)
{
- struct ps3_private *pd = get_irq_chip_data(virq);
+ struct ps3_private *pd = irq_data_get_irq_chip_data(d);
unsigned long flags;
pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
- pd->thread_id, virq);
+ pd->thread_id, d->irq);
local_irq_save(flags);
- clear_bit(63 - virq, &pd->bmp.mask);
+ clear_bit(63 - d->irq, &pd->bmp.mask);
lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
local_irq_restore(flags);
}
@@ -120,16 +120,16 @@ static void ps3_chip_mask(unsigned int virq)
* Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
*/
-static void ps3_chip_unmask(unsigned int virq)
+static void ps3_chip_unmask(struct irq_data *d)
{
- struct ps3_private *pd = get_irq_chip_data(virq);
+ struct ps3_private *pd = irq_data_get_irq_chip_data(d);
unsigned long flags;
pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
- pd->thread_id, virq);
+ pd->thread_id, d->irq);
local_irq_save(flags);
- set_bit(63 - virq, &pd->bmp.mask);
+ set_bit(63 - d->irq, &pd->bmp.mask);
lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
local_irq_restore(flags);
}
@@ -141,10 +141,10 @@ static void ps3_chip_unmask(unsigned int virq)
* Calls lv1_end_of_interrupt_ext().
*/
-static void ps3_chip_eoi(unsigned int virq)
+static void ps3_chip_eoi(struct irq_data *d)
{
- const struct ps3_private *pd = get_irq_chip_data(virq);
- lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq);
+ const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
+ lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
}
/**
@@ -153,9 +153,9 @@ static void ps3_chip_eoi(unsigned int virq)
static struct irq_chip ps3_irq_chip = {
.name = "ps3",
- .mask = ps3_chip_mask,
- .unmask = ps3_chip_unmask,
- .eoi = ps3_chip_eoi,
+ .irq_mask = ps3_chip_mask,
+ .irq_unmask = ps3_chip_unmask,
+ .irq_eoi = ps3_chip_eoi,
};
/**
@@ -202,7 +202,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
goto fail_set;
}
- ps3_chip_mask(*virq);
+ ps3_chip_mask(irq_get_irq_data(*virq));
return result;
@@ -296,7 +296,7 @@ int ps3_irq_plug_destroy(unsigned int virq)
pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
__LINE__, pd->ppe_id, pd->thread_id, virq);
- ps3_chip_mask(virq);
+ ps3_chip_mask(irq_get_irq_data(virq));
result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
@@ -357,7 +357,7 @@ int ps3_event_receive_port_destroy(unsigned int virq)
pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
- ps3_chip_mask(virq);
+ ps3_chip_mask(irq_get_irq_data(virq));
result = lv1_destruct_event_receive_port(virq_to_hw(virq));
@@ -492,7 +492,7 @@ int ps3_io_irq_destroy(unsigned int virq)
int result;
unsigned long outlet = virq_to_hw(virq);
- ps3_chip_mask(virq);
+ ps3_chip_mask(irq_get_irq_data(virq));
/*
* lv1_destruct_io_irq_outlet() will destroy the IRQ plug,
@@ -553,7 +553,7 @@ int ps3_vuart_irq_destroy(unsigned int virq)
{
int result;
- ps3_chip_mask(virq);
+ ps3_chip_mask(irq_get_irq_data(virq));
result = lv1_deconfigure_virtual_uart_irq();
if (result) {
@@ -605,7 +605,7 @@ int ps3_spe_irq_destroy(unsigned int virq)
{
int result;
- ps3_chip_mask(virq);
+ ps3_chip_mask(irq_get_irq_data(virq));
result = ps3_irq_plug_destroy(virq);
BUG_ON(result);
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index f4803868642c..3cafc306b971 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -508,12 +508,7 @@ static int cmm_memory_isolate_cb(struct notifier_block *self,
if (action == MEM_ISOLATE_COUNT)
ret = cmm_count_pages(arg);
- if (ret)
- ret = notifier_from_errno(ret);
- else
- ret = NOTIFY_OK;
-
- return ret;
+ return notifier_from_errno(ret);
}
static struct notifier_block cmm_mem_isolate_nb = {
@@ -635,12 +630,7 @@ static int cmm_memory_cb(struct notifier_block *self,
break;
}
- if (ret)
- ret = notifier_from_errno(ret);
- else
- ret = NOTIFY_OK;
-
- return ret;
+ return notifier_from_errno(ret);
}
static struct notifier_block cmm_mem_nb = {
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 17a11c82e6f8..3cc4d102b1f1 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -876,7 +876,7 @@ void eeh_restore_bars(struct pci_dn *pdn)
*
* Save the values of the device bars. Unlike the restore
* routine, this routine is *not* recursive. This is because
- * PCI devices are added individuallly; but, for the restore,
+ * PCI devices are added individually; but, for the restore,
* an entire slot is reset at a time.
*/
static void eeh_save_bars(struct pci_dn *pdn)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index edea60b7ee90..154c464cdca5 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/crash_dump.h>
+#include <linux/memory.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -45,6 +46,7 @@
#include <asm/tce.h>
#include <asm/ppc-pci.h>
#include <asm/udbg.h>
+#include <asm/mmzone.h>
#include "plpar_wrappers.h"
@@ -270,6 +272,152 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
return tce_ret;
}
+/* this is compatable with cells for the device tree property */
+struct dynamic_dma_window_prop {
+ __be32 liobn; /* tce table number */
+ __be64 dma_base; /* address hi,lo */
+ __be32 tce_shift; /* ilog2(tce_page_size) */
+ __be32 window_shift; /* ilog2(tce_window_size) */
+};
+
+struct direct_window {
+ struct device_node *device;
+ const struct dynamic_dma_window_prop *prop;
+ struct list_head list;
+};
+
+/* Dynamic DMA Window support */
+struct ddw_query_response {
+ u32 windows_available;
+ u32 largest_available_block;
+ u32 page_size;
+ u32 migration_capable;
+};
+
+struct ddw_create_response {
+ u32 liobn;
+ u32 addr_hi;
+ u32 addr_lo;
+};
+
+static LIST_HEAD(direct_window_list);
+/* prevents races between memory on/offline and window creation */
+static DEFINE_SPINLOCK(direct_window_list_lock);
+/* protects initializing window twice for same device */
+static DEFINE_MUTEX(direct_window_init_mutex);
+#define DIRECT64_PROPNAME "linux,direct64-ddr-window-info"
+
+static int tce_clearrange_multi_pSeriesLP(unsigned long start_pfn,
+ unsigned long num_pfn, const void *arg)
+{
+ const struct dynamic_dma_window_prop *maprange = arg;
+ int rc;
+ u64 tce_size, num_tce, dma_offset, next;
+ u32 tce_shift;
+ long limit;
+
+ tce_shift = be32_to_cpu(maprange->tce_shift);
+ tce_size = 1ULL << tce_shift;
+ next = start_pfn << PAGE_SHIFT;
+ num_tce = num_pfn << PAGE_SHIFT;
+
+ /* round back to the beginning of the tce page size */
+ num_tce += next & (tce_size - 1);
+ next &= ~(tce_size - 1);
+
+ /* covert to number of tces */
+ num_tce |= tce_size - 1;
+ num_tce >>= tce_shift;
+
+ do {
+ /*
+ * Set up the page with TCE data, looping through and setting
+ * the values.
+ */
+ limit = min_t(long, num_tce, 512);
+ dma_offset = next + be64_to_cpu(maprange->dma_base);
+
+ rc = plpar_tce_stuff((u64)be32_to_cpu(maprange->liobn),
+ dma_offset,
+ 0, limit);
+ num_tce -= limit;
+ } while (num_tce > 0 && !rc);
+
+ return rc;
+}
+
+static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
+ unsigned long num_pfn, const void *arg)
+{
+ const struct dynamic_dma_window_prop *maprange = arg;
+ u64 *tcep, tce_size, num_tce, dma_offset, next, proto_tce, liobn;
+ u32 tce_shift;
+ u64 rc = 0;
+ long l, limit;
+
+ local_irq_disable(); /* to protect tcep and the page behind it */
+ tcep = __get_cpu_var(tce_page);
+
+ if (!tcep) {
+ tcep = (u64 *)__get_free_page(GFP_ATOMIC);
+ if (!tcep) {
+ local_irq_enable();
+ return -ENOMEM;
+ }
+ __get_cpu_var(tce_page) = tcep;
+ }
+
+ proto_tce = TCE_PCI_READ | TCE_PCI_WRITE;
+
+ liobn = (u64)be32_to_cpu(maprange->liobn);
+ tce_shift = be32_to_cpu(maprange->tce_shift);
+ tce_size = 1ULL << tce_shift;
+ next = start_pfn << PAGE_SHIFT;
+ num_tce = num_pfn << PAGE_SHIFT;
+
+ /* round back to the beginning of the tce page size */
+ num_tce += next & (tce_size - 1);
+ next &= ~(tce_size - 1);
+
+ /* covert to number of tces */
+ num_tce |= tce_size - 1;
+ num_tce >>= tce_shift;
+
+ /* We can map max one pageful of TCEs at a time */
+ do {
+ /*
+ * Set up the page with TCE data, looping through and setting
+ * the values.
+ */
+ limit = min_t(long, num_tce, 4096/TCE_ENTRY_SIZE);
+ dma_offset = next + be64_to_cpu(maprange->dma_base);
+
+ for (l = 0; l < limit; l++) {
+ tcep[l] = proto_tce | next;
+ next += tce_size;
+ }
+
+ rc = plpar_tce_put_indirect(liobn,
+ dma_offset,
+ (u64)virt_to_abs(tcep),
+ limit);
+
+ num_tce -= limit;
+ } while (num_tce > 0 && !rc);
+
+ /* error cleanup: caller will clear whole range */
+
+ local_irq_enable();
+ return rc;
+}
+
+static int tce_setrange_multi_pSeriesLP_walk(unsigned long start_pfn,
+ unsigned long num_pfn, void *arg)
+{
+ return tce_setrange_multi_pSeriesLP(start_pfn, num_pfn, arg);
+}
+
+
#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
@@ -495,6 +643,329 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
pci_name(dev));
}
+static int __read_mostly disable_ddw;
+
+static int __init disable_ddw_setup(char *str)
+{
+ disable_ddw = 1;
+ printk(KERN_INFO "ppc iommu: disabling ddw.\n");
+
+ return 0;
+}
+
+early_param("disable_ddw", disable_ddw_setup);
+
+static void remove_ddw(struct device_node *np)
+{
+ struct dynamic_dma_window_prop *dwp;
+ struct property *win64;
+ const u32 *ddr_avail;
+ u64 liobn;
+ int len, ret;
+
+ ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len);
+ win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
+ if (!win64 || !ddr_avail || len < 3 * sizeof(u32))
+ return;
+
+ dwp = win64->value;
+ liobn = (u64)be32_to_cpu(dwp->liobn);
+
+ /* clear the whole window, note the arg is in kernel pages */
+ ret = tce_clearrange_multi_pSeriesLP(0,
+ 1ULL << (be32_to_cpu(dwp->window_shift) - PAGE_SHIFT), dwp);
+ if (ret)
+ pr_warning("%s failed to clear tces in window.\n",
+ np->full_name);
+ else
+ pr_debug("%s successfully cleared tces in window.\n",
+ np->full_name);
+
+ ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn);
+ if (ret)
+ pr_warning("%s: failed to remove direct window: rtas returned "
+ "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+ np->full_name, ret, ddr_avail[2], liobn);
+ else
+ pr_debug("%s: successfully removed direct window: rtas returned "
+ "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+ np->full_name, ret, ddr_avail[2], liobn);
+}
+
+
+static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ struct direct_window *window;
+ const struct dynamic_dma_window_prop *direct64;
+ u64 dma_addr = 0;
+
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ spin_lock(&direct_window_list_lock);
+ /* check if we already created a window and dupe that config if so */
+ list_for_each_entry(window, &direct_window_list, list) {
+ if (window->device == pdn) {
+ direct64 = window->prop;
+ dma_addr = direct64->dma_base;
+ break;
+ }
+ }
+ spin_unlock(&direct_window_list_lock);
+
+ return dma_addr;
+}
+
+static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ int len;
+ struct direct_window *window;
+ const struct dynamic_dma_window_prop *direct64;
+ u64 dma_addr = 0;
+
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len);
+ if (direct64) {
+ window = kzalloc(sizeof(*window), GFP_KERNEL);
+ if (!window) {
+ remove_ddw(pdn);
+ } else {
+ window->device = pdn;
+ window->prop = direct64;
+ spin_lock(&direct_window_list_lock);
+ list_add(&window->list, &direct_window_list);
+ spin_unlock(&direct_window_list_lock);
+ dma_addr = direct64->dma_base;
+ }
+ }
+
+ return dma_addr;
+}
+
+static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+ struct ddw_query_response *query)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ u32 cfg_addr;
+ u64 buid;
+ int ret;
+
+ /*
+ * Get the config address and phb buid of the PE window.
+ * Rely on eeh to retrieve this for us.
+ * Retrieve them from the pci device, not the node with the
+ * dma-window property
+ */
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ cfg_addr = pcidn->eeh_config_addr;
+ if (pcidn->eeh_pe_config_addr)
+ cfg_addr = pcidn->eeh_pe_config_addr;
+ buid = pcidn->phb->buid;
+ ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query,
+ cfg_addr, BUID_HI(buid), BUID_LO(buid));
+ dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
+ " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid),
+ BUID_LO(buid), ret);
+ return ret;
+}
+
+static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+ struct ddw_create_response *create, int page_shift,
+ int window_shift)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ u32 cfg_addr;
+ u64 buid;
+ int ret;
+
+ /*
+ * Get the config address and phb buid of the PE window.
+ * Rely on eeh to retrieve this for us.
+ * Retrieve them from the pci device, not the node with the
+ * dma-window property
+ */
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ cfg_addr = pcidn->eeh_config_addr;
+ if (pcidn->eeh_pe_config_addr)
+ cfg_addr = pcidn->eeh_pe_config_addr;
+ buid = pcidn->phb->buid;
+
+ do {
+ /* extra outputs are LIOBN and dma-addr (hi, lo) */
+ ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr,
+ BUID_HI(buid), BUID_LO(buid), page_shift, window_shift);
+ } while (rtas_busy_delay(ret));
+ dev_info(&dev->dev,
+ "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
+ "(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1],
+ cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift,
+ window_shift, ret, create->liobn, create->addr_hi, create->addr_lo);
+
+ return ret;
+}
+
+/*
+ * If the PE supports dynamic dma windows, and there is space for a table
+ * that can map all pages in a linear offset, then setup such a table,
+ * and record the dma-offset in the struct device.
+ *
+ * dev: the pci device we are checking
+ * pdn: the parent pe node with the ibm,dma_window property
+ * Future: also check if we can remap the base window for our base page size
+ *
+ * returns the dma offset for use by dma_set_mask
+ */
+static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+{
+ int len, ret;
+ struct ddw_query_response query;
+ struct ddw_create_response create;
+ int page_shift;
+ u64 dma_addr, max_addr;
+ struct device_node *dn;
+ const u32 *uninitialized_var(ddr_avail);
+ struct direct_window *window;
+ struct property *uninitialized_var(win64);
+ struct dynamic_dma_window_prop *ddwprop;
+
+ mutex_lock(&direct_window_init_mutex);
+
+ dma_addr = dupe_ddw_if_already_created(dev, pdn);
+ if (dma_addr != 0)
+ goto out_unlock;
+
+ dma_addr = dupe_ddw_if_kexec(dev, pdn);
+ if (dma_addr != 0)
+ goto out_unlock;
+
+ /*
+ * the ibm,ddw-applicable property holds the tokens for:
+ * ibm,query-pe-dma-window
+ * ibm,create-pe-dma-window
+ * ibm,remove-pe-dma-window
+ * for the given node in that order.
+ * the property is actually in the parent, not the PE
+ */
+ ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
+ if (!ddr_avail || len < 3 * sizeof(u32))
+ goto out_unlock;
+
+ /*
+ * Query if there is a second window of size to map the
+ * whole partition. Query returns number of windows, largest
+ * block assigned to PE (partition endpoint), and two bitmasks
+ * of page sizes: supported and supported for migrate-dma.
+ */
+ dn = pci_device_to_OF_node(dev);
+ ret = query_ddw(dev, ddr_avail, &query);
+ if (ret != 0)
+ goto out_unlock;
+
+ if (query.windows_available == 0) {
+ /*
+ * no additional windows are available for this device.
+ * We might be able to reallocate the existing window,
+ * trading in for a larger page size.
+ */
+ dev_dbg(&dev->dev, "no free dynamic windows");
+ goto out_unlock;
+ }
+ if (query.page_size & 4) {
+ page_shift = 24; /* 16MB */
+ } else if (query.page_size & 2) {
+ page_shift = 16; /* 64kB */
+ } else if (query.page_size & 1) {
+ page_shift = 12; /* 4kB */
+ } else {
+ dev_dbg(&dev->dev, "no supported direct page size in mask %x",
+ query.page_size);
+ goto out_unlock;
+ }
+ /* verify the window * number of ptes will map the partition */
+ /* check largest block * page size > max memory hotplug addr */
+ max_addr = memory_hotplug_max();
+ if (query.largest_available_block < (max_addr >> page_shift)) {
+ dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u "
+ "%llu-sized pages\n", max_addr, query.largest_available_block,
+ 1ULL << page_shift);
+ goto out_unlock;
+ }
+ len = order_base_2(max_addr);
+ win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
+ if (!win64) {
+ dev_info(&dev->dev,
+ "couldn't allocate property for 64bit dma window\n");
+ goto out_unlock;
+ }
+ win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
+ win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
+ if (!win64->name || !win64->value) {
+ dev_info(&dev->dev,
+ "couldn't allocate property name and value\n");
+ goto out_free_prop;
+ }
+
+ ret = create_ddw(dev, ddr_avail, &create, page_shift, len);
+ if (ret != 0)
+ goto out_free_prop;
+
+ ddwprop->liobn = cpu_to_be32(create.liobn);
+ ddwprop->dma_base = cpu_to_be64(of_read_number(&create.addr_hi, 2));
+ ddwprop->tce_shift = cpu_to_be32(page_shift);
+ ddwprop->window_shift = cpu_to_be32(len);
+
+ dev_dbg(&dev->dev, "created tce table LIOBN 0x%x for %s\n",
+ create.liobn, dn->full_name);
+
+ window = kzalloc(sizeof(*window), GFP_KERNEL);
+ if (!window)
+ goto out_clear_window;
+
+ ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT,
+ win64->value, tce_setrange_multi_pSeriesLP_walk);
+ if (ret) {
+ dev_info(&dev->dev, "failed to map direct window for %s: %d\n",
+ dn->full_name, ret);
+ goto out_clear_window;
+ }
+
+ ret = prom_add_property(pdn, win64);
+ if (ret) {
+ dev_err(&dev->dev, "unable to add dma window property for %s: %d",
+ pdn->full_name, ret);
+ goto out_clear_window;
+ }
+
+ window->device = pdn;
+ window->prop = ddwprop;
+ spin_lock(&direct_window_list_lock);
+ list_add(&window->list, &direct_window_list);
+ spin_unlock(&direct_window_list_lock);
+
+ dma_addr = of_read_number(&create.addr_hi, 2);
+ goto out_unlock;
+
+out_clear_window:
+ remove_ddw(pdn);
+
+out_free_prop:
+ kfree(win64->name);
+ kfree(win64->value);
+ kfree(win64);
+
+out_unlock:
+ mutex_unlock(&direct_window_init_mutex);
+ return dma_addr;
+}
+
static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
@@ -541,23 +1012,137 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
set_iommu_table_base(&dev->dev, pci->iommu_table);
}
+
+static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
+{
+ bool ddw_enabled = false;
+ struct device_node *pdn, *dn;
+ struct pci_dev *pdev;
+ const void *dma_window = NULL;
+ u64 dma_offset;
+
+ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ /* only attempt to use a new window if 64-bit DMA is requested */
+ if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) {
+ pdev = to_pci_dev(dev);
+
+ dn = pci_device_to_OF_node(pdev);
+ dev_dbg(dev, "node is %s\n", dn->full_name);
+
+ /*
+ * the device tree might contain the dma-window properties
+ * per-device and not neccesarily for the bus. So we need to
+ * search upwards in the tree until we either hit a dma-window
+ * property, OR find a parent with a table already allocated.
+ */
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ pdn = pdn->parent) {
+ dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
+ if (dma_window)
+ break;
+ }
+ if (pdn && PCI_DN(pdn)) {
+ dma_offset = enable_ddw(pdev, pdn);
+ if (dma_offset != 0) {
+ dev_info(dev, "Using 64-bit direct DMA at offset %llx\n", dma_offset);
+ set_dma_offset(dev, dma_offset);
+ set_dma_ops(dev, &dma_direct_ops);
+ ddw_enabled = true;
+ }
+ }
+ }
+
+ /* fall-through to iommu ops */
+ if (!ddw_enabled) {
+ dev_info(dev, "Using 32-bit DMA via iommu\n");
+ set_dma_ops(dev, &dma_iommu_ops);
+ }
+
+ *dev->dma_mask = dma_mask;
+ return 0;
+}
+
#else /* CONFIG_PCI */
#define pci_dma_bus_setup_pSeries NULL
#define pci_dma_dev_setup_pSeries NULL
#define pci_dma_bus_setup_pSeriesLP NULL
#define pci_dma_dev_setup_pSeriesLP NULL
+#define dma_set_mask_pSeriesLP NULL
#endif /* !CONFIG_PCI */
+static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct direct_window *window;
+ struct memory_notify *arg = data;
+ int ret = 0;
+
+ switch (action) {
+ case MEM_GOING_ONLINE:
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ /* XXX log error */
+ }
+ spin_unlock(&direct_window_list_lock);
+ break;
+ case MEM_CANCEL_ONLINE:
+ case MEM_OFFLINE:
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ /* XXX log error */
+ }
+ spin_unlock(&direct_window_list_lock);
+ break;
+ default:
+ break;
+ }
+ if (ret && action != MEM_CANCEL_ONLINE)
+ return NOTIFY_BAD;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block iommu_mem_nb = {
+ .notifier_call = iommu_mem_notifier,
+};
+
static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
{
int err = NOTIFY_OK;
struct device_node *np = node;
struct pci_dn *pci = PCI_DN(np);
+ struct direct_window *window;
switch (action) {
case PSERIES_RECONFIG_REMOVE:
if (pci && pci->iommu_table)
iommu_free_table(pci->iommu_table, np->full_name);
+
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ if (window->device == np) {
+ list_del(&window->list);
+ kfree(window);
+ break;
+ }
+ }
+ spin_unlock(&direct_window_list_lock);
+
+ /*
+ * Because the notifier runs after isolation of the
+ * slot, we are guaranteed any DMA window has already
+ * been revoked and the TCEs have been marked invalid,
+ * so we don't need a call to remove_ddw(np). However,
+ * if an additional notifier action is added before the
+ * isolate call, we should update this code for
+ * completeness with such a call.
+ */
break;
default:
err = NOTIFY_DONE;
@@ -587,6 +1172,7 @@ void iommu_init_early_pSeries(void)
ppc_md.tce_get = tce_get_pSeriesLP;
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
+ ppc_md.dma_set_mask = dma_set_mask_pSeriesLP;
} else {
ppc_md.tce_build = tce_build_pSeries;
ppc_md.tce_free = tce_free_pSeries;
@@ -597,6 +1183,7 @@ void iommu_init_early_pSeries(void)
pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
+ register_memory_notifier(&iommu_mem_nb);
set_pci_dma_ops(&dma_iommu_ops);
}
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 1164c3430f2c..18ac801f8e90 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -93,8 +93,18 @@ static void rtas_disable_msi(struct pci_dev *pdev)
if (!pdn)
return;
- if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0)
- pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
+ /*
+ * disabling MSI with the explicit interface also disables MSI-X
+ */
+ if (rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0) != 0) {
+ /*
+ * may have failed because explicit interface is not
+ * present
+ */
+ if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0) {
+ pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
+ }
+ }
}
static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 7e828ba29bc3..419707b07248 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -16,6 +16,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/kmsg_dump.h>
#include <asm/uaccess.h>
#include <asm/nvram.h>
#include <asm/rtas.h>
@@ -30,17 +32,54 @@ static int nvram_fetch, nvram_store;
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
static DEFINE_SPINLOCK(nvram_lock);
-static long nvram_error_log_index = -1;
-static long nvram_error_log_size = 0;
-
struct err_log_info {
int error_type;
unsigned int seq_num;
};
-#define NVRAM_MAX_REQ 2079
-#define NVRAM_MIN_REQ 1055
-#define NVRAM_LOG_PART_NAME "ibm,rtas-log"
+struct nvram_os_partition {
+ const char *name;
+ int req_size; /* desired size, in bytes */
+ int min_size; /* minimum acceptable size (0 means req_size) */
+ long size; /* size of data portion (excluding err_log_info) */
+ long index; /* offset of data portion of partition */
+};
+
+static struct nvram_os_partition rtas_log_partition = {
+ .name = "ibm,rtas-log",
+ .req_size = 2079,
+ .min_size = 1055,
+ .index = -1
+};
+
+static struct nvram_os_partition oops_log_partition = {
+ .name = "lnx,oops-log",
+ .req_size = 4000,
+ .min_size = 2000,
+ .index = -1
+};
+
+static const char *pseries_nvram_os_partitions[] = {
+ "ibm,rtas-log",
+ "lnx,oops-log",
+ NULL
+};
+
+static void oops_to_nvram(struct kmsg_dumper *dumper,
+ enum kmsg_dump_reason reason,
+ const char *old_msgs, unsigned long old_len,
+ const char *new_msgs, unsigned long new_len);
+
+static struct kmsg_dumper nvram_kmsg_dumper = {
+ .dump = oops_to_nvram
+};
+
+/* See clobbering_unread_rtas_event() */
+#define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */
+static unsigned long last_unread_rtas_event; /* timestamp */
+
+/* We preallocate oops_buf during init to avoid kmalloc during oops/panic. */
+static char *oops_buf;
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
{
@@ -134,7 +173,7 @@ static ssize_t pSeries_nvram_get_size(void)
}
-/* nvram_write_error_log
+/* nvram_write_os_partition, nvram_write_error_log
*
* We need to buffer the error logs into nvram to ensure that we have
* the failure information to decode. If we have a severe error there
@@ -156,48 +195,58 @@ static ssize_t pSeries_nvram_get_size(void)
* The 'data' section would look like (in bytes):
* +--------------+------------+-----------------------------------+
* | event_logged | sequence # | error log |
- * |0 3|4 7|8 nvram_error_log_size-1|
+ * |0 3|4 7|8 error_log_size-1|
* +--------------+------------+-----------------------------------+
*
* event_logged: 0 if event has not been logged to syslog, 1 if it has
* sequence #: The unique sequence # for each event. (until it wraps)
* error log: The error log from event_scan
*/
-int nvram_write_error_log(char * buff, int length,
- unsigned int err_type, unsigned int error_log_cnt)
+int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
+ int length, unsigned int err_type, unsigned int error_log_cnt)
{
int rc;
loff_t tmp_index;
struct err_log_info info;
- if (nvram_error_log_index == -1) {
+ if (part->index == -1) {
return -ESPIPE;
}
- if (length > nvram_error_log_size) {
- length = nvram_error_log_size;
+ if (length > part->size) {
+ length = part->size;
}
info.error_type = err_type;
info.seq_num = error_log_cnt;
- tmp_index = nvram_error_log_index;
+ tmp_index = part->index;
rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
if (rc <= 0) {
- printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
+ pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
return rc;
}
rc = ppc_md.nvram_write(buff, length, &tmp_index);
if (rc <= 0) {
- printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
+ pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
return rc;
}
return 0;
}
+int nvram_write_error_log(char * buff, int length,
+ unsigned int err_type, unsigned int error_log_cnt)
+{
+ int rc = nvram_write_os_partition(&rtas_log_partition, buff, length,
+ err_type, error_log_cnt);
+ if (!rc)
+ last_unread_rtas_event = get_seconds();
+ return rc;
+}
+
/* nvram_read_error_log
*
* Reads nvram for error log for at most 'length'
@@ -209,13 +258,13 @@ int nvram_read_error_log(char * buff, int length,
loff_t tmp_index;
struct err_log_info info;
- if (nvram_error_log_index == -1)
+ if (rtas_log_partition.index == -1)
return -1;
- if (length > nvram_error_log_size)
- length = nvram_error_log_size;
+ if (length > rtas_log_partition.size)
+ length = rtas_log_partition.size;
- tmp_index = nvram_error_log_index;
+ tmp_index = rtas_log_partition.index;
rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
if (rc <= 0) {
@@ -244,37 +293,40 @@ int nvram_clear_error_log(void)
int clear_word = ERR_FLAG_ALREADY_LOGGED;
int rc;
- if (nvram_error_log_index == -1)
+ if (rtas_log_partition.index == -1)
return -1;
- tmp_index = nvram_error_log_index;
+ tmp_index = rtas_log_partition.index;
rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
if (rc <= 0) {
printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
return rc;
}
+ last_unread_rtas_event = 0;
return 0;
}
-/* pseries_nvram_init_log_partition
+/* pseries_nvram_init_os_partition
*
- * This will setup the partition we need for buffering the
- * error logs and cleanup partitions if needed.
+ * This sets up a partition with an "OS" signature.
*
* The general strategy is the following:
- * 1.) If there is log partition large enough then use it.
- * 2.) If there is none large enough, search
- * for a free partition that is large enough.
- * 3.) If there is not a free partition large enough remove
- * _all_ OS partitions and consolidate the space.
- * 4.) Will first try getting a chunk that will satisfy the maximum
- * error log size (NVRAM_MAX_REQ).
- * 5.) If the max chunk cannot be allocated then try finding a chunk
- * that will satisfy the minum needed (NVRAM_MIN_REQ).
+ * 1.) If a partition with the indicated name already exists...
+ * - If it's large enough, use it.
+ * - Otherwise, recycle it and keep going.
+ * 2.) Search for a free partition that is large enough.
+ * 3.) If there's not a free partition large enough, recycle any obsolete
+ * OS partitions and try again.
+ * 4.) Will first try getting a chunk that will satisfy the requested size.
+ * 5.) If a chunk of the requested size cannot be allocated, then try finding
+ * a chunk that will satisfy the minum needed.
+ *
+ * Returns 0 on success, else -1.
*/
-static int __init pseries_nvram_init_log_partition(void)
+static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
+ *part)
{
loff_t p;
int size;
@@ -282,47 +334,76 @@ static int __init pseries_nvram_init_log_partition(void)
/* Scan nvram for partitions */
nvram_scan_partitions();
- /* Lookg for ours */
- p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size);
+ /* Look for ours */
+ p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
/* Found one but too small, remove it */
- if (p && size < NVRAM_MIN_REQ) {
- pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition"
- ",removing it...");
- nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS);
+ if (p && size < part->min_size) {
+ pr_info("nvram: Found too small %s partition,"
+ " removing it...\n", part->name);
+ nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
p = 0;
}
/* Create one if we didn't find */
if (!p) {
- p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- /* No room for it, try to get rid of any OS partition
- * and try again
- */
+ p = nvram_create_partition(part->name, NVRAM_SIG_OS,
+ part->req_size, part->min_size);
if (p == -ENOSPC) {
- pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME
- " partition, deleting all OS partitions...");
- nvram_remove_partition(NULL, NVRAM_SIG_OS);
- p = nvram_create_partition(NVRAM_LOG_PART_NAME,
- NVRAM_SIG_OS, NVRAM_MAX_REQ,
- NVRAM_MIN_REQ);
+ pr_info("nvram: No room to create %s partition, "
+ "deleting any obsolete OS partitions...\n",
+ part->name);
+ nvram_remove_partition(NULL, NVRAM_SIG_OS,
+ pseries_nvram_os_partitions);
+ p = nvram_create_partition(part->name, NVRAM_SIG_OS,
+ part->req_size, part->min_size);
}
}
if (p <= 0) {
- pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME
- " partition, err %d\n", (int)p);
- return 0;
+ pr_err("nvram: Failed to find or create %s"
+ " partition, err %d\n", part->name, (int)p);
+ return -1;
}
- nvram_error_log_index = p;
- nvram_error_log_size = nvram_get_partition_size(p) -
- sizeof(struct err_log_info);
+ part->index = p;
+ part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
return 0;
}
-machine_arch_initcall(pseries, pseries_nvram_init_log_partition);
+
+static void __init nvram_init_oops_partition(int rtas_partition_exists)
+{
+ int rc;
+
+ rc = pseries_nvram_init_os_partition(&oops_log_partition);
+ if (rc != 0) {
+ if (!rtas_partition_exists)
+ return;
+ pr_notice("nvram: Using %s partition to log both"
+ " RTAS errors and oops/panic reports\n",
+ rtas_log_partition.name);
+ memcpy(&oops_log_partition, &rtas_log_partition,
+ sizeof(rtas_log_partition));
+ }
+ oops_buf = kmalloc(oops_log_partition.size, GFP_KERNEL);
+ rc = kmsg_dump_register(&nvram_kmsg_dumper);
+ if (rc != 0) {
+ pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
+ kfree(oops_buf);
+ return;
+ }
+}
+
+static int __init pseries_nvram_init_log_partitions(void)
+{
+ int rc;
+
+ rc = pseries_nvram_init_os_partition(&rtas_log_partition);
+ nvram_init_oops_partition(rc == 0);
+ return 0;
+}
+machine_arch_initcall(pseries, pseries_nvram_init_log_partitions);
int __init pSeries_nvram_init(void)
{
@@ -353,3 +434,59 @@ int __init pSeries_nvram_init(void)
return 0;
}
+
+/*
+ * Try to capture the last capture_len bytes of the printk buffer. Return
+ * the amount actually captured.
+ */
+static size_t capture_last_msgs(const char *old_msgs, size_t old_len,
+ const char *new_msgs, size_t new_len,
+ char *captured, size_t capture_len)
+{
+ if (new_len >= capture_len) {
+ memcpy(captured, new_msgs + (new_len - capture_len),
+ capture_len);
+ return capture_len;
+ } else {
+ /* Grab the end of old_msgs. */
+ size_t old_tail_len = min(old_len, capture_len - new_len);
+ memcpy(captured, old_msgs + (old_len - old_tail_len),
+ old_tail_len);
+ memcpy(captured + old_tail_len, new_msgs, new_len);
+ return old_tail_len + new_len;
+ }
+}
+
+/*
+ * Are we using the ibm,rtas-log for oops/panic reports? And if so,
+ * would logging this oops/panic overwrite an RTAS event that rtas_errd
+ * hasn't had a chance to read and process? Return 1 if so, else 0.
+ *
+ * We assume that if rtas_errd hasn't read the RTAS event in
+ * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
+ */
+static int clobbering_unread_rtas_event(void)
+{
+ return (oops_log_partition.index == rtas_log_partition.index
+ && last_unread_rtas_event
+ && get_seconds() - last_unread_rtas_event <=
+ NVRAM_RTAS_READ_TIMEOUT);
+}
+
+/* our kmsg_dump callback */
+static void oops_to_nvram(struct kmsg_dumper *dumper,
+ enum kmsg_dump_reason reason,
+ const char *old_msgs, unsigned long old_len,
+ const char *new_msgs, unsigned long new_len)
+{
+ static unsigned int oops_count = 0;
+ size_t text_len;
+
+ if (clobbering_unread_rtas_event())
+ return;
+
+ text_len = capture_last_msgs(old_msgs, old_len, new_msgs, new_len,
+ oops_buf, oops_log_partition.size);
+ (void) nvram_write_os_partition(&oops_log_partition, oops_buf,
+ (int) text_len, ERR_TYPE_KERNEL_PANIC, ++oops_count);
+}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index d345bfd56bbe..2a0089a2c829 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -114,10 +114,13 @@ static void __init fwnmi_init(void)
static void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = i8259_irq();
+
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
static void __init pseries_setup_i8259_cascade(void)
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 7b96e5a270ce..01fea46c0335 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -202,20 +202,20 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask,
#define get_irq_server(virq, cpumask, strict_check) (default_server)
#endif
-static void xics_unmask_irq(unsigned int virq)
+static void xics_unmask_irq(struct irq_data *d)
{
unsigned int irq;
int call_status;
int server;
- pr_devel("xics: unmask virq %d\n", virq);
+ pr_devel("xics: unmask virq %d\n", d->irq);
- irq = (unsigned int)irq_map[virq].hwirq;
+ irq = (unsigned int)irq_map[d->irq].hwirq;
pr_devel(" -> map to hwirq 0x%x\n", irq);
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
return;
- server = get_irq_server(virq, irq_to_desc(virq)->affinity, 0);
+ server = get_irq_server(d->irq, d->affinity, 0);
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
DEFAULT_PRIORITY);
@@ -235,61 +235,61 @@ static void xics_unmask_irq(unsigned int virq)
}
}
-static unsigned int xics_startup(unsigned int virq)
+static unsigned int xics_startup(struct irq_data *d)
{
/*
* The generic MSI code returns with the interrupt disabled on the
* card, using the MSI mask bits. Firmware doesn't appear to unmask
* at that level, so we do it here by hand.
*/
- if (irq_to_desc(virq)->msi_desc)
- unmask_msi_irq(irq_get_irq_data(virq));
+ if (d->msi_desc)
+ unmask_msi_irq(d);
/* unmask it */
- xics_unmask_irq(virq);
+ xics_unmask_irq(d);
return 0;
}
-static void xics_mask_real_irq(unsigned int irq)
+static void xics_mask_real_irq(struct irq_data *d)
{
int call_status;
- if (irq == XICS_IPI)
+ if (d->irq == XICS_IPI)
return;
- call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
+ call_status = rtas_call(ibm_int_off, 1, 1, NULL, d->irq);
if (call_status != 0) {
printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
- __func__, irq, call_status);
+ __func__, d->irq, call_status);
return;
}
/* Have to set XIVE to 0xff to be able to remove a slot */
- call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
+ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, d->irq,
default_server, 0xff);
if (call_status != 0) {
printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
- __func__, irq, call_status);
+ __func__, d->irq, call_status);
return;
}
}
-static void xics_mask_irq(unsigned int virq)
+static void xics_mask_irq(struct irq_data *d)
{
unsigned int irq;
- pr_devel("xics: mask virq %d\n", virq);
+ pr_devel("xics: mask virq %d\n", d->irq);
- irq = (unsigned int)irq_map[virq].hwirq;
+ irq = (unsigned int)irq_map[d->irq].hwirq;
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
return;
- xics_mask_real_irq(irq);
+ xics_mask_real_irq(d);
}
static void xics_mask_unknown_vec(unsigned int vec)
{
printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
- xics_mask_real_irq(vec);
+ xics_mask_real_irq(irq_get_irq_data(vec));
}
static inline unsigned int xics_xirr_vector(unsigned int xirr)
@@ -371,30 +371,31 @@ static unsigned char pop_cppr(void)
return os_cppr->stack[--os_cppr->index];
}
-static void xics_eoi_direct(unsigned int virq)
+static void xics_eoi_direct(struct irq_data *d)
{
- unsigned int irq = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq = (unsigned int)irq_map[d->irq].hwirq;
iosync();
direct_xirr_info_set((pop_cppr() << 24) | irq);
}
-static void xics_eoi_lpar(unsigned int virq)
+static void xics_eoi_lpar(struct irq_data *d)
{
- unsigned int irq = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq = (unsigned int)irq_map[d->irq].hwirq;
iosync();
lpar_xirr_info_set((pop_cppr() << 24) | irq);
}
-static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
+static int
+xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force)
{
unsigned int irq;
int status;
int xics_status[2];
int irq_server;
- irq = (unsigned int)irq_map[virq].hwirq;
+ irq = (unsigned int)irq_map[d->irq].hwirq;
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
return -1;
@@ -406,13 +407,13 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
return -1;
}
- irq_server = get_irq_server(virq, cpumask, 1);
+ irq_server = get_irq_server(d->irq, cpumask, 1);
if (irq_server == -1) {
char cpulist[128];
cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
printk(KERN_WARNING
"%s: No online cpus in the mask %s for irq %d\n",
- __func__, cpulist, virq);
+ __func__, cpulist, d->irq);
return -1;
}
@@ -430,20 +431,20 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
static struct irq_chip xics_pic_direct = {
.name = "XICS",
- .startup = xics_startup,
- .mask = xics_mask_irq,
- .unmask = xics_unmask_irq,
- .eoi = xics_eoi_direct,
- .set_affinity = xics_set_affinity
+ .irq_startup = xics_startup,
+ .irq_mask = xics_mask_irq,
+ .irq_unmask = xics_unmask_irq,
+ .irq_eoi = xics_eoi_direct,
+ .irq_set_affinity = xics_set_affinity
};
static struct irq_chip xics_pic_lpar = {
.name = "XICS",
- .startup = xics_startup,
- .mask = xics_mask_irq,
- .unmask = xics_unmask_irq,
- .eoi = xics_eoi_lpar,
- .set_affinity = xics_set_affinity
+ .irq_startup = xics_startup,
+ .irq_mask = xics_mask_irq,
+ .irq_unmask = xics_unmask_irq,
+ .irq_eoi = xics_eoi_lpar,
+ .irq_set_affinity = xics_set_affinity
};
@@ -890,6 +891,7 @@ void xics_migrate_irqs_away(void)
for_each_irq(virq) {
struct irq_desc *desc;
+ struct irq_chip *chip;
int xics_status[2];
int status;
unsigned long flags;
@@ -903,12 +905,15 @@ void xics_migrate_irqs_away(void)
/* We need to get IPIs still. */
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
continue;
+
desc = irq_to_desc(virq);
/* We only need to migrate enabled IRQS */
- if (desc == NULL || desc->chip == NULL
- || desc->action == NULL
- || desc->chip->set_affinity == NULL)
+ if (desc == NULL || desc->action == NULL)
+ continue;
+
+ chip = get_irq_desc_chip(desc);
+ if (chip == NULL || chip->irq_set_affinity == NULL)
continue;
raw_spin_lock_irqsave(&desc->lock, flags);
@@ -934,8 +939,8 @@ void xics_migrate_irqs_away(void)
virq, cpu);
/* Reset affinity to all cpus */
- cpumask_setall(irq_to_desc(virq)->affinity);
- desc->chip->set_affinity(virq, cpu_all_mask);
+ cpumask_setall(desc->irq_data.affinity);
+ chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true);
unlock:
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 00852124ff4a..0476bcc7c3e1 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -56,32 +56,32 @@ static cpic8xx_t __iomem *cpic_reg;
static struct irq_host *cpm_pic_host;
-static void cpm_mask_irq(unsigned int irq)
+static void cpm_mask_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
-static void cpm_unmask_irq(unsigned int irq)
+static void cpm_unmask_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
-static void cpm_end_irq(unsigned int irq)
+static void cpm_end_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
}
static struct irq_chip cpm_pic = {
.name = "CPM PIC",
- .mask = cpm_mask_irq,
- .unmask = cpm_unmask_irq,
- .eoi = cpm_end_irq,
+ .irq_mask = cpm_mask_irq,
+ .irq_unmask = cpm_unmask_irq,
+ .irq_eoi = cpm_end_irq,
};
int cpm_get_irq(void)
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index fcea4ff825dd..473032556715 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -78,10 +78,10 @@ static const u_char irq_to_siubit[] = {
24, 25, 26, 27, 28, 29, 30, 31,
};
-static void cpm2_mask_irq(unsigned int virq)
+static void cpm2_mask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(virq);
+ unsigned int irq_nr = virq_to_hw(d->irq);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -90,10 +90,10 @@ static void cpm2_mask_irq(unsigned int virq)
out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
}
-static void cpm2_unmask_irq(unsigned int virq)
+static void cpm2_unmask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(virq);
+ unsigned int irq_nr = virq_to_hw(d->irq);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -102,10 +102,10 @@ static void cpm2_unmask_irq(unsigned int virq)
out_be32(&cpm2_intctl->ic_simrh + word, ppc_cached_irq_mask[word]);
}
-static void cpm2_ack(unsigned int virq)
+static void cpm2_ack(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(virq);
+ unsigned int irq_nr = virq_to_hw(d->irq);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -113,11 +113,11 @@ static void cpm2_ack(unsigned int virq)
out_be32(&cpm2_intctl->ic_sipnrh + word, 1 << bit);
}
-static void cpm2_end_irq(unsigned int virq)
+static void cpm2_end_irq(struct irq_data *d)
{
struct irq_desc *desc;
int bit, word;
- unsigned int irq_nr = virq_to_hw(virq);
+ unsigned int irq_nr = virq_to_hw(d->irq);
desc = irq_to_desc(irq_nr);
if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))
@@ -137,10 +137,10 @@ static void cpm2_end_irq(unsigned int virq)
}
}
-static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
+static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- unsigned int src = virq_to_hw(virq);
- struct irq_desc *desc = irq_to_desc(virq);
+ unsigned int src = virq_to_hw(d->irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vold, vnew, edibit;
/* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
@@ -199,11 +199,11 @@ err_sense:
static struct irq_chip cpm2_pic = {
.name = "CPM2 SIU",
- .mask = cpm2_mask_irq,
- .unmask = cpm2_unmask_irq,
- .ack = cpm2_ack,
- .eoi = cpm2_end_irq,
- .set_type = cpm2_set_irq_type,
+ .irq_mask = cpm2_mask_irq,
+ .irq_unmask = cpm2_unmask_irq,
+ .irq_ack = cpm2_ack,
+ .irq_eoi = cpm2_end_irq,
+ .irq_set_type = cpm2_set_irq_type,
};
unsigned int cpm2_get_irq(void)
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
index 2b9f0c925326..5f88797dce73 100644
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -93,14 +93,14 @@ static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
l2cache_size = *prop;
sram_params.sram_size = get_cache_sram_size();
- if (sram_params.sram_size <= 0) {
+ if ((int)sram_params.sram_size <= 0) {
dev_err(&dev->dev,
"Entire L2 as cache, Aborting Cache-SRAM stuff\n");
return -EINVAL;
}
sram_params.sram_offset = get_cache_sram_offset();
- if (sram_params.sram_offset <= 0) {
+ if ((int64_t)sram_params.sram_offset <= 0) {
dev_err(&dev->dev,
"Entire L2 as cache, provide a valid sram offset\n");
return -EINVAL;
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index ee6a8a52ac71..58e09b2833f2 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007-2011 Freescale Semiconductor, Inc.
*
* Author: Tony Li <tony.li@freescale.com>
* Jason Jin <Jason.jin@freescale.com>
@@ -47,14 +47,14 @@ static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
* We do not need this actually. The MSIR register has been read once
* in the cascade interrupt. So, this MSI interrupt has been acked
*/
-static void fsl_msi_end_irq(unsigned int virq)
+static void fsl_msi_end_irq(struct irq_data *d)
{
}
static struct irq_chip fsl_msi_chip = {
.irq_mask = mask_msi_irq,
.irq_unmask = unmask_msi_irq,
- .ack = fsl_msi_end_irq,
+ .irq_ack = fsl_msi_end_irq,
.name = "FSL-MSI",
};
@@ -183,6 +183,7 @@ out_free:
static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq;
struct fsl_msi *msi_data;
int msir_index = -1;
@@ -196,11 +197,11 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
raw_spin_lock(&desc->lock);
if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
- if (desc->chip->mask_ack)
- desc->chip->mask_ack(irq);
+ if (chip->irq_mask_ack)
+ chip->irq_mask_ack(&desc->irq_data);
else {
- desc->chip->mask(irq);
- desc->chip->ack(irq);
+ chip->irq_mask(&desc->irq_data);
+ chip->irq_ack(&desc->irq_data);
}
}
@@ -238,11 +239,11 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
- desc->chip->eoi(irq);
+ chip->irq_eoi(&desc->irq_data);
break;
case FSL_PIC_IP_IPIC:
- if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
- desc->chip->unmask(irq);
+ if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
+ chip->irq_unmask(&desc->irq_data);
break;
}
unlock:
@@ -273,18 +274,46 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
return 0;
}
+static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi,
+ struct platform_device *dev,
+ int offset, int irq_index)
+{
+ struct fsl_msi_cascade_data *cascade_data = NULL;
+ int virt_msir;
+
+ virt_msir = irq_of_parse_and_map(dev->dev.of_node, irq_index);
+ if (virt_msir == NO_IRQ) {
+ dev_err(&dev->dev, "%s: Cannot translate IRQ index %d\n",
+ __func__, irq_index);
+ return 0;
+ }
+
+ cascade_data = kzalloc(sizeof(struct fsl_msi_cascade_data), GFP_KERNEL);
+ if (!cascade_data) {
+ dev_err(&dev->dev, "No memory for MSI cascade data\n");
+ return -ENOMEM;
+ }
+
+ msi->msi_virqs[irq_index] = virt_msir;
+ cascade_data->index = offset + irq_index;
+ cascade_data->msi_data = msi;
+ set_irq_data(virt_msir, cascade_data);
+ set_irq_chained_handler(virt_msir, fsl_msi_cascade);
+
+ return 0;
+}
+
static int __devinit fsl_of_msi_probe(struct platform_device *dev)
{
struct fsl_msi *msi;
struct resource res;
- int err, i, count;
+ int err, i, j, irq_index, count;
int rc;
- int virt_msir;
const u32 *p;
struct fsl_msi_feature *features;
- struct fsl_msi_cascade_data *cascade_data = NULL;
int len;
u32 offset;
+ static const u32 all_avail[] = { 0, NR_MSI_IRQS };
if (!dev->dev.of_match)
return -EINVAL;
@@ -335,42 +364,34 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
goto error_out;
}
- p = of_get_property(dev->dev.of_node, "interrupts", &count);
- if (!p) {
- dev_err(&dev->dev, "no interrupts property found on %s\n",
- dev->dev.of_node->full_name);
- err = -ENODEV;
- goto error_out;
- }
- if (count % 8 != 0) {
- dev_err(&dev->dev, "Malformed interrupts property on %s\n",
- dev->dev.of_node->full_name);
+ p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
+ if (p && len % (2 * sizeof(u32)) != 0) {
+ dev_err(&dev->dev, "%s: Malformed msi-available-ranges property\n",
+ __func__);
err = -EINVAL;
goto error_out;
}
- offset = 0;
- p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
- if (p)
- offset = *p / IRQS_PER_MSI_REG;
-
- count /= sizeof(u32);
- for (i = 0; i < min(count / 2, NR_MSI_REG); i++) {
- virt_msir = irq_of_parse_and_map(dev->dev.of_node, i);
- if (virt_msir != NO_IRQ) {
- cascade_data = kzalloc(
- sizeof(struct fsl_msi_cascade_data),
- GFP_KERNEL);
- if (!cascade_data) {
- dev_err(&dev->dev,
- "No memory for MSI cascade data\n");
- err = -ENOMEM;
+
+ if (!p)
+ p = all_avail;
+
+ for (irq_index = 0, i = 0; i < len / (2 * sizeof(u32)); i++) {
+ if (p[i * 2] % IRQS_PER_MSI_REG ||
+ p[i * 2 + 1] % IRQS_PER_MSI_REG) {
+ printk(KERN_WARNING "%s: %s: msi available range of %u at %u is not IRQ-aligned\n",
+ __func__, dev->dev.of_node->full_name,
+ p[i * 2 + 1], p[i * 2]);
+ err = -EINVAL;
+ goto error_out;
+ }
+
+ offset = p[i * 2] / IRQS_PER_MSI_REG;
+ count = p[i * 2 + 1] / IRQS_PER_MSI_REG;
+
+ for (j = 0; j < count; j++, irq_index++) {
+ err = fsl_msi_setup_hwirq(msi, dev, offset, irq_index);
+ if (err)
goto error_out;
- }
- msi->msi_virqs[i] = virt_msir;
- cascade_data->index = i + offset;
- cascade_data->msi_data = msi;
- set_irq_data(virt_msir, (void *)cascade_data);
- set_irq_chained_handler(virt_msir, fsl_msi_cascade);
}
}
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 818f7c6c8fa1..f8f7f28c6343 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1,7 +1,7 @@
/*
* MPC83xx/85xx/86xx PCI/PCIE support routing.
*
- * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ * Copyright 2007-2011 Freescale Semiconductor, Inc.
* Copyright 2008-2009 MontaVista Software, Inc.
*
* Initial author: Xianghua Xiao <x.xiao@freescale.com>
@@ -99,7 +99,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
struct resource *rsrc)
{
struct ccsr_pci __iomem *pci;
- int i, j, n, mem_log, win_idx = 2;
+ int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
u64 mem, sz, paddr_hi = 0;
u64 paddr_lo = ULLONG_MAX;
u32 pcicsrbar = 0, pcicsrbar_sz;
@@ -109,6 +109,13 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
(u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1);
+
+ if (of_device_is_compatible(hose->dn, "fsl,qoriq-pcie-v2.2")) {
+ win_idx = 2;
+ start_idx = 0;
+ end_idx = 3;
+ }
+
pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1);
if (!pci) {
dev_err(hose->parent, "Unable to map ATMU registers\n");
@@ -118,7 +125,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
/* Disable all windows (except powar0 since it's ignored) */
for(i = 1; i < 5; i++)
out_be32(&pci->pow[i].powar, 0);
- for(i = 0; i < 3; i++)
+ for (i = start_idx; i < end_idx; i++)
out_be32(&pci->piw[i].piwar, 0);
/* Setup outbound MEM window */
@@ -204,7 +211,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
mem_log++;
}
- piwar |= (mem_log - 1);
+ piwar |= ((mem_log - 1) & PIWAR_SZ_MASK);
/* Setup inbound memory window */
out_be32(&pci->piw[win_idx].pitar, 0x00000000);
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 8ad72a11f77b..a39ed5cc2c5a 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -1,7 +1,7 @@
/*
* MPC85xx/86xx PCI Express structure define
*
- * Copyright 2007 Freescale Semiconductor, Inc
+ * Copyright 2007,2011 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 the
@@ -21,6 +21,7 @@
#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */
#define PIWAR_READ_SNOOP 0x00050000
#define PIWAR_WRITE_SNOOP 0x00005000
+#define PIWAR_SZ_MASK 0x0000003f
/* PCI/PCI Express outbound window reg */
struct pci_outbound_window_regs {
@@ -49,7 +50,9 @@ struct ccsr_pci {
__be32 int_ack; /* 0x.008 - PCI Interrupt Acknowledge Register */
__be32 pex_otb_cpl_tor; /* 0x.00c - PCIE Outbound completion timeout register */
__be32 pex_conf_tor; /* 0x.010 - PCIE configuration timeout register */
- u8 res2[12];
+ __be32 pex_config; /* 0x.014 - PCIE CONFIG Register */
+ __be32 pex_int_status; /* 0x.018 - PCIE interrupt status */
+ u8 res2[4];
__be32 pex_pme_mes_dr; /* 0x.020 - PCIE PME and message detect register */
__be32 pex_pme_mes_disr; /* 0x.024 - PCIE PME and message disable register */
__be32 pex_pme_mes_ier; /* 0x.028 - PCIE PME and message interrupt enable register */
@@ -62,14 +65,14 @@ struct ccsr_pci {
* in all of the other outbound windows.
*/
struct pci_outbound_window_regs pow[5];
-
- u8 res14[256];
-
-/* PCI/PCI Express inbound window 3-1
+ u8 res14[96];
+ struct pci_inbound_window_regs pmit; /* 0xd00 - 0xd9c Inbound MSI */
+ u8 res6[96];
+/* PCI/PCI Express inbound window 3-0
* inbound window 1 supports only a 32-bit base address and does not
* define an inbound window base extended address register.
*/
- struct pci_inbound_window_regs piw[3];
+ struct pci_inbound_window_regs piw[4];
__be32 pex_err_dr; /* 0x.e00 - PCI/PCIE error detect register */
u8 res21[4];
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 6323e70e6bf4..aeda4c8d0a0a 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -78,19 +78,19 @@ unsigned int i8259_irq(void)
return irq;
}
-static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+static void i8259_mask_and_ack_irq(struct irq_data *d)
{
unsigned long flags;
raw_spin_lock_irqsave(&i8259_lock, flags);
- if (irq_nr > 7) {
- cached_A1 |= 1 << (irq_nr-8);
+ if (d->irq > 7) {
+ cached_A1 |= 1 << (d->irq-8);
inb(0xA1); /* DUMMY */
outb(cached_A1, 0xA1);
outb(0x20, 0xA0); /* Non-specific EOI */
outb(0x20, 0x20); /* Non-specific EOI to cascade */
} else {
- cached_21 |= 1 << irq_nr;
+ cached_21 |= 1 << d->irq;
inb(0x21); /* DUMMY */
outb(cached_21, 0x21);
outb(0x20, 0x20); /* Non-specific EOI */
@@ -104,42 +104,42 @@ static void i8259_set_irq_mask(int irq_nr)
outb(cached_21,0x21);
}
-static void i8259_mask_irq(unsigned int irq_nr)
+static void i8259_mask_irq(struct irq_data *d)
{
unsigned long flags;
- pr_debug("i8259_mask_irq(%d)\n", irq_nr);
+ pr_debug("i8259_mask_irq(%d)\n", d->irq);
raw_spin_lock_irqsave(&i8259_lock, flags);
- if (irq_nr < 8)
- cached_21 |= 1 << irq_nr;
+ if (d->irq < 8)
+ cached_21 |= 1 << d->irq;
else
- cached_A1 |= 1 << (irq_nr-8);
- i8259_set_irq_mask(irq_nr);
+ cached_A1 |= 1 << (d->irq-8);
+ i8259_set_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&i8259_lock, flags);
}
-static void i8259_unmask_irq(unsigned int irq_nr)
+static void i8259_unmask_irq(struct irq_data *d)
{
unsigned long flags;
- pr_debug("i8259_unmask_irq(%d)\n", irq_nr);
+ pr_debug("i8259_unmask_irq(%d)\n", d->irq);
raw_spin_lock_irqsave(&i8259_lock, flags);
- if (irq_nr < 8)
- cached_21 &= ~(1 << irq_nr);
+ if (d->irq < 8)
+ cached_21 &= ~(1 << d->irq);
else
- cached_A1 &= ~(1 << (irq_nr-8));
- i8259_set_irq_mask(irq_nr);
+ cached_A1 &= ~(1 << (d->irq-8));
+ i8259_set_irq_mask(d->irq);
raw_spin_unlock_irqrestore(&i8259_lock, flags);
}
static struct irq_chip i8259_pic = {
.name = "i8259",
- .mask = i8259_mask_irq,
- .disable = i8259_mask_irq,
- .unmask = i8259_unmask_irq,
- .mask_ack = i8259_mask_and_ack_irq,
+ .irq_mask = i8259_mask_irq,
+ .irq_disable = i8259_mask_irq,
+ .irq_unmask = i8259_unmask_irq,
+ .irq_mask_ack = i8259_mask_and_ack_irq,
};
static struct resource pic1_iores = {
@@ -188,7 +188,7 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
static void i8259_host_unmap(struct irq_host *h, unsigned int virq)
{
/* Make sure irq is masked in hardware */
- i8259_mask_irq(virq);
+ i8259_mask_irq(irq_get_irq_data(virq));
/* remove chip and handler */
set_irq_chip_and_handler(virq, NULL, NULL);
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index d7b9b9c69287..497047dc986e 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -523,10 +523,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq)
#define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-static void ipic_unmask_irq(unsigned int virq)
+static void ipic_unmask_irq(struct irq_data *d)
{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ struct ipic *ipic = ipic_from_irq(d->irq);
+ unsigned int src = ipic_irq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -539,10 +539,10 @@ static void ipic_unmask_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&ipic_lock, flags);
}
-static void ipic_mask_irq(unsigned int virq)
+static void ipic_mask_irq(struct irq_data *d)
{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ struct ipic *ipic = ipic_from_irq(d->irq);
+ unsigned int src = ipic_irq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -559,10 +559,10 @@ static void ipic_mask_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&ipic_lock, flags);
}
-static void ipic_ack_irq(unsigned int virq)
+static void ipic_ack_irq(struct irq_data *d)
{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ struct ipic *ipic = ipic_from_irq(d->irq);
+ unsigned int src = ipic_irq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -578,10 +578,10 @@ static void ipic_ack_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&ipic_lock, flags);
}
-static void ipic_mask_irq_and_ack(unsigned int virq)
+static void ipic_mask_irq_and_ack(struct irq_data *d)
{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ struct ipic *ipic = ipic_from_irq(d->irq);
+ unsigned int src = ipic_irq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -601,11 +601,11 @@ static void ipic_mask_irq_and_ack(unsigned int virq)
raw_spin_unlock_irqrestore(&ipic_lock, flags);
}
-static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
+static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
- struct irq_desc *desc = irq_to_desc(virq);
+ struct ipic *ipic = ipic_from_irq(d->irq);
+ unsigned int src = ipic_irq_to_hw(d->irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vold, vnew, edibit;
if (flow_type == IRQ_TYPE_NONE)
@@ -630,10 +630,10 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
if (flow_type & IRQ_TYPE_LEVEL_LOW) {
desc->status |= IRQ_LEVEL;
desc->handle_irq = handle_level_irq;
- desc->chip = &ipic_level_irq_chip;
+ desc->irq_data.chip = &ipic_level_irq_chip;
} else {
desc->handle_irq = handle_edge_irq;
- desc->chip = &ipic_edge_irq_chip;
+ desc->irq_data.chip = &ipic_edge_irq_chip;
}
/* only EXT IRQ senses are programmable on ipic
@@ -661,19 +661,19 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type)
/* level interrupts and edge interrupts have different ack operations */
static struct irq_chip ipic_level_irq_chip = {
.name = "IPIC",
- .unmask = ipic_unmask_irq,
- .mask = ipic_mask_irq,
- .mask_ack = ipic_mask_irq,
- .set_type = ipic_set_irq_type,
+ .irq_unmask = ipic_unmask_irq,
+ .irq_mask = ipic_mask_irq,
+ .irq_mask_ack = ipic_mask_irq,
+ .irq_set_type = ipic_set_irq_type,
};
static struct irq_chip ipic_edge_irq_chip = {
.name = "IPIC",
- .unmask = ipic_unmask_irq,
- .mask = ipic_mask_irq,
- .mask_ack = ipic_mask_irq_and_ack,
- .ack = ipic_ack_irq,
- .set_type = ipic_set_irq_type,
+ .irq_unmask = ipic_unmask_irq,
+ .irq_mask = ipic_mask_irq,
+ .irq_mask_ack = ipic_mask_irq_and_ack,
+ .irq_ack = ipic_ack_irq,
+ .irq_set_type = ipic_set_irq_type,
};
static int ipic_host_match(struct irq_host *h, struct device_node *node)
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index 8c27d261aba8..1a75a7fb4a99 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -25,10 +25,10 @@ static sysconf8xx_t __iomem *siu_reg;
int cpm_get_irq(struct pt_regs *regs);
-static void mpc8xx_unmask_irq(unsigned int virq)
+static void mpc8xx_unmask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -37,10 +37,10 @@ static void mpc8xx_unmask_irq(unsigned int virq)
out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
}
-static void mpc8xx_mask_irq(unsigned int virq)
+static void mpc8xx_mask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -49,19 +49,19 @@ static void mpc8xx_mask_irq(unsigned int virq)
out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
}
-static void mpc8xx_ack(unsigned int virq)
+static void mpc8xx_ack(struct irq_data *d)
{
int bit;
- unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
bit = irq_nr & 0x1f;
out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
}
-static void mpc8xx_end_irq(unsigned int virq)
+static void mpc8xx_end_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
+ unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -70,9 +70,9 @@ static void mpc8xx_end_irq(unsigned int virq)
out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
}
-static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
+static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- struct irq_desc *desc = irq_to_desc(virq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
@@ -80,7 +80,7 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
desc->status |= IRQ_LEVEL;
if (flow_type & IRQ_TYPE_EDGE_FALLING) {
- irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
+ irq_hw_number_t hw = (unsigned int)irq_map[d->irq].hwirq;
unsigned int siel = in_be32(&siu_reg->sc_siel);
/* only external IRQ senses are programmable */
@@ -95,11 +95,11 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
static struct irq_chip mpc8xx_pic = {
.name = "MPC8XX SIU",
- .unmask = mpc8xx_unmask_irq,
- .mask = mpc8xx_mask_irq,
- .ack = mpc8xx_ack,
- .eoi = mpc8xx_end_irq,
- .set_type = mpc8xx_set_irq_type,
+ .irq_unmask = mpc8xx_unmask_irq,
+ .irq_mask = mpc8xx_mask_irq,
+ .irq_ack = mpc8xx_ack,
+ .irq_eoi = mpc8xx_end_irq,
+ .irq_set_type = mpc8xx_set_irq_type,
};
unsigned int mpc8xx_get_irq(void)
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
index c48cd8178079..232e701245d7 100644
--- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -155,43 +155,43 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
32 - ffs(mask)));
}
-static void mpc8xxx_irq_unmask(unsigned int virq)
+static void mpc8xxx_irq_unmask(struct irq_data *d)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
unsigned long flags;
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
- setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq)));
+ setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
-static void mpc8xxx_irq_mask(unsigned int virq)
+static void mpc8xxx_irq_mask(struct irq_data *d)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
unsigned long flags;
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
- clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(virq)));
+ clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
-static void mpc8xxx_irq_ack(unsigned int virq)
+static void mpc8xxx_irq_ack(struct irq_data *d)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
- out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(virq)));
+ out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
}
-static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
+static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
unsigned long flags;
@@ -199,14 +199,14 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
case IRQ_TYPE_EDGE_FALLING:
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
setbits32(mm->regs + GPIO_ICR,
- mpc8xxx_gpio2mask(virq_to_hw(virq)));
+ mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break;
case IRQ_TYPE_EDGE_BOTH:
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(mm->regs + GPIO_ICR,
- mpc8xxx_gpio2mask(virq_to_hw(virq)));
+ mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break;
@@ -217,11 +217,11 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
return 0;
}
-static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
+static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
- unsigned long gpio = virq_to_hw(virq);
+ unsigned long gpio = virq_to_hw(d->irq);
void __iomem *reg;
unsigned int shift;
unsigned long flags;
@@ -264,10 +264,10 @@ static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
static struct irq_chip mpc8xxx_irq_chip = {
.name = "mpc8xxx-gpio",
- .unmask = mpc8xxx_irq_unmask,
- .mask = mpc8xxx_irq_mask,
- .ack = mpc8xxx_irq_ack,
- .set_type = mpc8xxx_irq_set_type,
+ .irq_unmask = mpc8xxx_irq_unmask,
+ .irq_mask = mpc8xxx_irq_mask,
+ .irq_ack = mpc8xxx_irq_ack,
+ .irq_set_type = mpc8xxx_irq_set_type,
};
static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
@@ -276,7 +276,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
if (mpc8xxx_gc->of_dev_id_data)
- mpc8xxx_irq_chip.set_type = mpc8xxx_gc->of_dev_id_data;
+ mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
set_irq_chip_data(virq, h->host_data);
set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
@@ -310,6 +310,7 @@ static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
{ .compatible = "fsl,mpc8572-gpio", },
{ .compatible = "fsl,mpc8610-gpio", },
{ .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
+ { .compatible = "fsl,qoriq-gpio", },
{}
};
@@ -389,9 +390,6 @@ static int __init mpc8xxx_add_gpiochips(void)
for_each_matching_node(np, mpc8xxx_gpio_ids)
mpc8xxx_add_controller(np);
- for_each_compatible_node(np, NULL, "fsl,qoriq-gpio")
- mpc8xxx_add_controller(np);
-
return 0;
}
arch_initcall(mpc8xxx_add_gpiochips);
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index b0c8469e5ddd..eb7021815e2d 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -611,7 +611,7 @@ static struct mpic *mpic_find(unsigned int irq)
if (irq < NUM_ISA_INTERRUPTS)
return NULL;
- return irq_to_desc(irq)->chip_data;
+ return get_irq_chip_data(irq);
}
/* Determine if the linux irq is an IPI */
@@ -636,16 +636,22 @@ static inline u32 mpic_physmask(u32 cpumask)
#ifdef CONFIG_SMP
/* Get the mpic structure from the IPI number */
-static inline struct mpic * mpic_from_ipi(unsigned int ipi)
+static inline struct mpic * mpic_from_ipi(struct irq_data *d)
{
- return irq_to_desc(ipi)->chip_data;
+ return irq_data_get_irq_chip_data(d);
}
#endif
/* Get the mpic structure from the irq number */
static inline struct mpic * mpic_from_irq(unsigned int irq)
{
- return irq_to_desc(irq)->chip_data;
+ return get_irq_chip_data(irq);
+}
+
+/* Get the mpic structure from the irq data */
+static inline struct mpic * mpic_from_irq_data(struct irq_data *d)
+{
+ return irq_data_get_irq_chip_data(d);
}
/* Send an EOI */
@@ -660,13 +666,13 @@ static inline void mpic_eoi(struct mpic *mpic)
*/
-void mpic_unmask_irq(unsigned int irq)
+void mpic_unmask_irq(struct irq_data *d)
{
unsigned int loops = 100000;
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
- DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
+ DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src);
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
@@ -681,13 +687,13 @@ void mpic_unmask_irq(unsigned int irq)
} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
}
-void mpic_mask_irq(unsigned int irq)
+void mpic_mask_irq(struct irq_data *d)
{
unsigned int loops = 100000;
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
- DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
+ DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src);
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
@@ -703,12 +709,12 @@ void mpic_mask_irq(unsigned int irq)
} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
}
-void mpic_end_irq(unsigned int irq)
+void mpic_end_irq(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_irq(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
#ifdef DEBUG_IRQ
- DBG("%s: end_irq: %d\n", mpic->name, irq);
+ DBG("%s: end_irq: %d\n", mpic->name, d->irq);
#endif
/* We always EOI on end_irq() even for edge interrupts since that
* should only lower the priority, the MPIC should have properly
@@ -720,51 +726,51 @@ void mpic_end_irq(unsigned int irq)
#ifdef CONFIG_MPIC_U3_HT_IRQS
-static void mpic_unmask_ht_irq(unsigned int irq)
+static void mpic_unmask_ht_irq(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
- mpic_unmask_irq(irq);
+ mpic_unmask_irq(d);
- if (irq_to_desc(irq)->status & IRQ_LEVEL)
+ if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
mpic_ht_end_irq(mpic, src);
}
-static unsigned int mpic_startup_ht_irq(unsigned int irq)
+static unsigned int mpic_startup_ht_irq(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
- mpic_unmask_irq(irq);
- mpic_startup_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
+ mpic_unmask_irq(d);
+ mpic_startup_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
return 0;
}
-static void mpic_shutdown_ht_irq(unsigned int irq)
+static void mpic_shutdown_ht_irq(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
- mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
- mpic_mask_irq(irq);
+ mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
+ mpic_mask_irq(d);
}
-static void mpic_end_ht_irq(unsigned int irq)
+static void mpic_end_ht_irq(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
#ifdef DEBUG_IRQ
- DBG("%s: end_irq: %d\n", mpic->name, irq);
+ DBG("%s: end_irq: %d\n", mpic->name, d->irq);
#endif
/* We always EOI on end_irq() even for edge interrupts since that
* should only lower the priority, the MPIC should have properly
* latched another edge interrupt coming in anyway
*/
- if (irq_to_desc(irq)->status & IRQ_LEVEL)
+ if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
mpic_ht_end_irq(mpic, src);
mpic_eoi(mpic);
}
@@ -772,23 +778,23 @@ static void mpic_end_ht_irq(unsigned int irq)
#ifdef CONFIG_SMP
-static void mpic_unmask_ipi(unsigned int irq)
+static void mpic_unmask_ipi(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_ipi(irq);
- unsigned int src = mpic_irq_to_hw(irq) - mpic->ipi_vecs[0];
+ struct mpic *mpic = mpic_from_ipi(d);
+ unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0];
- DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src);
+ DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src);
mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
}
-static void mpic_mask_ipi(unsigned int irq)
+static void mpic_mask_ipi(struct irq_data *d)
{
/* NEVER disable an IPI... that's just plain wrong! */
}
-static void mpic_end_ipi(unsigned int irq)
+static void mpic_end_ipi(struct irq_data *d)
{
- struct mpic *mpic = mpic_from_ipi(irq);
+ struct mpic *mpic = mpic_from_ipi(d);
/*
* IPIs are marked IRQ_PER_CPU. This has the side effect of
@@ -802,10 +808,11 @@ static void mpic_end_ipi(unsigned int irq)
#endif /* CONFIG_SMP */
-int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
+ bool force)
{
- struct mpic *mpic = mpic_from_irq(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
int cpuid = irq_choose_cpu(cpumask);
@@ -848,15 +855,15 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
}
}
-int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
+int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- struct mpic *mpic = mpic_from_irq(virq);
- unsigned int src = mpic_irq_to_hw(virq);
- struct irq_desc *desc = irq_to_desc(virq);
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = mpic_irq_to_hw(d->irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vecpri, vold, vnew;
DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
- mpic, virq, src, flow_type);
+ mpic, d->irq, src, flow_type);
if (src >= mpic->irq_count)
return -EINVAL;
@@ -907,28 +914,28 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
}
static struct irq_chip mpic_irq_chip = {
- .mask = mpic_mask_irq,
- .unmask = mpic_unmask_irq,
- .eoi = mpic_end_irq,
- .set_type = mpic_set_irq_type,
+ .irq_mask = mpic_mask_irq,
+ .irq_unmask = mpic_unmask_irq,
+ .irq_eoi = mpic_end_irq,
+ .irq_set_type = mpic_set_irq_type,
};
#ifdef CONFIG_SMP
static struct irq_chip mpic_ipi_chip = {
- .mask = mpic_mask_ipi,
- .unmask = mpic_unmask_ipi,
- .eoi = mpic_end_ipi,
+ .irq_mask = mpic_mask_ipi,
+ .irq_unmask = mpic_unmask_ipi,
+ .irq_eoi = mpic_end_ipi,
};
#endif /* CONFIG_SMP */
#ifdef CONFIG_MPIC_U3_HT_IRQS
static struct irq_chip mpic_irq_ht_chip = {
- .startup = mpic_startup_ht_irq,
- .shutdown = mpic_shutdown_ht_irq,
- .mask = mpic_mask_irq,
- .unmask = mpic_unmask_ht_irq,
- .eoi = mpic_end_ht_irq,
- .set_type = mpic_set_irq_type,
+ .irq_startup = mpic_startup_ht_irq,
+ .irq_shutdown = mpic_shutdown_ht_irq,
+ .irq_mask = mpic_mask_irq,
+ .irq_unmask = mpic_unmask_ht_irq,
+ .irq_eoi = mpic_end_ht_irq,
+ .irq_set_type = mpic_set_irq_type,
};
#endif /* CONFIG_MPIC_U3_HT_IRQS */
@@ -1060,12 +1067,12 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->hc_irq = mpic_irq_chip;
mpic->hc_irq.name = name;
if (flags & MPIC_PRIMARY)
- mpic->hc_irq.set_affinity = mpic_set_affinity;
+ mpic->hc_irq.irq_set_affinity = mpic_set_affinity;
#ifdef CONFIG_MPIC_U3_HT_IRQS
mpic->hc_ht_irq = mpic_irq_ht_chip;
mpic->hc_ht_irq.name = name;
if (flags & MPIC_PRIMARY)
- mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
+ mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;
#endif /* CONFIG_MPIC_U3_HT_IRQS */
#ifdef CONFIG_SMP
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index e4a6df77b8d7..13f3e8913a93 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -34,9 +34,10 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic)
}
#endif
-extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type);
extern void mpic_set_vector(unsigned int virq, unsigned int vector);
-extern int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask);
+extern int mpic_set_affinity(struct irq_data *d,
+ const struct cpumask *cpumask, bool force);
extern void mpic_reset_core(int cpu);
#endif /* _POWERPC_SYSDEV_MPIC_H */
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
index 320ad5a9a25d..0b7794acfce1 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
@@ -43,24 +43,24 @@ static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
mask_msi_irq(data);
- mpic_mask_irq(data->irq);
+ mpic_mask_irq(data);
}
static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
- mpic_unmask_irq(data->irq);
+ mpic_unmask_irq(data);
unmask_msi_irq(data);
}
static struct irq_chip mpic_pasemi_msi_chip = {
- .irq_shutdown = mpic_pasemi_msi_mask_irq,
- .irq_mask = mpic_pasemi_msi_mask_irq,
- .irq_unmask = mpic_pasemi_msi_unmask_irq,
- .eoi = mpic_end_irq,
- .set_type = mpic_set_irq_type,
- .set_affinity = mpic_set_affinity,
- .name = "PASEMI-MSI",
+ .irq_shutdown = mpic_pasemi_msi_mask_irq,
+ .irq_mask = mpic_pasemi_msi_mask_irq,
+ .irq_unmask = mpic_pasemi_msi_unmask_irq,
+ .irq_eoi = mpic_end_irq,
+ .irq_set_type = mpic_set_irq_type,
+ .irq_set_affinity = mpic_set_affinity,
+ .name = "PASEMI-MSI",
};
static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index a2b028b4a202..71900ac78270 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -26,23 +26,23 @@ static struct mpic *msi_mpic;
static void mpic_u3msi_mask_irq(struct irq_data *data)
{
mask_msi_irq(data);
- mpic_mask_irq(data->irq);
+ mpic_mask_irq(data);
}
static void mpic_u3msi_unmask_irq(struct irq_data *data)
{
- mpic_unmask_irq(data->irq);
+ mpic_unmask_irq(data);
unmask_msi_irq(data);
}
static struct irq_chip mpic_u3msi_chip = {
- .irq_shutdown = mpic_u3msi_mask_irq,
- .irq_mask = mpic_u3msi_mask_irq,
- .irq_unmask = mpic_u3msi_unmask_irq,
- .eoi = mpic_end_irq,
- .set_type = mpic_set_irq_type,
- .set_affinity = mpic_set_affinity,
- .name = "MPIC-U3MSI",
+ .irq_shutdown = mpic_u3msi_mask_irq,
+ .irq_mask = mpic_u3msi_mask_irq,
+ .irq_unmask = mpic_u3msi_unmask_irq,
+ .irq_eoi = mpic_end_irq,
+ .irq_set_type = mpic_set_irq_type,
+ .irq_set_affinity = mpic_set_affinity,
+ .name = "MPIC-U3MSI",
};
static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index feaee402e2d6..0f6af41ebb44 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -346,7 +346,7 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)
if (prop)
pdata.freq_m = *prop;
- pdata.freq_m = 3; /* default */
+ pdata.freq_n = 3; /* default */
prop = of_get_property(np, "freq_n", NULL);
if (prop)
pdata.freq_n = *prop;
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
index 485b92477d7c..bc61ebb8987c 100644
--- a/arch/powerpc/sysdev/mv64x60_pic.c
+++ b/arch/powerpc/sysdev/mv64x60_pic.c
@@ -76,9 +76,9 @@ static struct irq_host *mv64x60_irq_host;
* mv64x60_chip_low functions
*/
-static void mv64x60_mask_low(unsigned int virq)
+static void mv64x60_mask_low(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -89,9 +89,9 @@ static void mv64x60_mask_low(unsigned int virq)
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_LO);
}
-static void mv64x60_unmask_low(unsigned int virq)
+static void mv64x60_unmask_low(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -104,18 +104,18 @@ static void mv64x60_unmask_low(unsigned int virq)
static struct irq_chip mv64x60_chip_low = {
.name = "mv64x60_low",
- .mask = mv64x60_mask_low,
- .mask_ack = mv64x60_mask_low,
- .unmask = mv64x60_unmask_low,
+ .irq_mask = mv64x60_mask_low,
+ .irq_mask_ack = mv64x60_mask_low,
+ .irq_unmask = mv64x60_unmask_low,
};
/*
* mv64x60_chip_high functions
*/
-static void mv64x60_mask_high(unsigned int virq)
+static void mv64x60_mask_high(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -126,9 +126,9 @@ static void mv64x60_mask_high(unsigned int virq)
(void)in_le32(mv64x60_irq_reg_base + MV64X60_IC_CPU0_INTR_MASK_HI);
}
-static void mv64x60_unmask_high(unsigned int virq)
+static void mv64x60_unmask_high(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -141,18 +141,18 @@ static void mv64x60_unmask_high(unsigned int virq)
static struct irq_chip mv64x60_chip_high = {
.name = "mv64x60_high",
- .mask = mv64x60_mask_high,
- .mask_ack = mv64x60_mask_high,
- .unmask = mv64x60_unmask_high,
+ .irq_mask = mv64x60_mask_high,
+ .irq_mask_ack = mv64x60_mask_high,
+ .irq_unmask = mv64x60_unmask_high,
};
/*
* mv64x60_chip_gpp functions
*/
-static void mv64x60_mask_gpp(unsigned int virq)
+static void mv64x60_mask_gpp(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -163,9 +163,9 @@ static void mv64x60_mask_gpp(unsigned int virq)
(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK);
}
-static void mv64x60_mask_ack_gpp(unsigned int virq)
+static void mv64x60_mask_ack_gpp(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -178,9 +178,9 @@ static void mv64x60_mask_ack_gpp(unsigned int virq)
(void)in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_CAUSE);
}
-static void mv64x60_unmask_gpp(unsigned int virq)
+static void mv64x60_unmask_gpp(struct irq_data *d)
{
- int level2 = irq_map[virq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -193,9 +193,9 @@ static void mv64x60_unmask_gpp(unsigned int virq)
static struct irq_chip mv64x60_chip_gpp = {
.name = "mv64x60_gpp",
- .mask = mv64x60_mask_gpp,
- .mask_ack = mv64x60_mask_ack_gpp,
- .unmask = mv64x60_unmask_gpp,
+ .irq_mask = mv64x60_mask_gpp,
+ .irq_mask_ack = mv64x60_mask_ack_gpp,
+ .irq_unmask = mv64x60_unmask_gpp,
};
/*
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 541ba9863647..8c9ded8ea07c 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -189,15 +189,20 @@ static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg
static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
{
- return irq_to_desc(virq)->chip_data;
+ return get_irq_chip_data(virq);
+}
+
+static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
+{
+ return irq_data_get_irq_chip_data(d);
}
#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-static void qe_ic_unmask_irq(unsigned int virq)
+static void qe_ic_unmask_irq(struct irq_data *d)
{
- struct qe_ic *qe_ic = qe_ic_from_irq(virq);
- unsigned int src = virq_to_hw(virq);
+ struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
+ unsigned int src = virq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -210,10 +215,10 @@ static void qe_ic_unmask_irq(unsigned int virq)
raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
}
-static void qe_ic_mask_irq(unsigned int virq)
+static void qe_ic_mask_irq(struct irq_data *d)
{
- struct qe_ic *qe_ic = qe_ic_from_irq(virq);
- unsigned int src = virq_to_hw(virq);
+ struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
+ unsigned int src = virq_to_hw(d->irq);
unsigned long flags;
u32 temp;
@@ -238,9 +243,9 @@ static void qe_ic_mask_irq(unsigned int virq)
static struct irq_chip qe_ic_irq_chip = {
.name = "QEIC",
- .unmask = qe_ic_unmask_irq,
- .mask = qe_ic_mask_irq,
- .mask_ack = qe_ic_mask_irq,
+ .irq_unmask = qe_ic_unmask_irq,
+ .irq_mask = qe_ic_mask_irq,
+ .irq_mask_ack = qe_ic_mask_irq,
};
static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 0ab9281e49ae..02c91db90037 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -343,24 +343,9 @@ static inline unsigned int get_pci_source(void)
* Linux descriptor level callbacks
*/
-static void tsi108_pci_irq_enable(u_int irq)
+static void tsi108_pci_irq_unmask(struct irq_data *d)
{
- tsi108_pci_int_unmask(irq);
-}
-
-static void tsi108_pci_irq_disable(u_int irq)
-{
- tsi108_pci_int_mask(irq);
-}
-
-static void tsi108_pci_irq_ack(u_int irq)
-{
- tsi108_pci_int_mask(irq);
-}
-
-static void tsi108_pci_irq_end(u_int irq)
-{
- tsi108_pci_int_unmask(irq);
+ tsi108_pci_int_unmask(d->irq);
/* Enable interrupts from PCI block */
tsi108_write_reg(TSI108_PCI_OFFSET + TSI108_PCI_IRP_ENABLE,
@@ -370,16 +355,25 @@ static void tsi108_pci_irq_end(u_int irq)
mb();
}
+static void tsi108_pci_irq_mask(struct irq_data *d)
+{
+ tsi108_pci_int_mask(d->irq);
+}
+
+static void tsi108_pci_irq_ack(struct irq_data *d)
+{
+ tsi108_pci_int_mask(d->irq);
+}
+
/*
* Interrupt controller descriptor for cascaded PCI interrupt controller.
*/
static struct irq_chip tsi108_pci_irq = {
.name = "tsi108_PCI_int",
- .mask = tsi108_pci_irq_disable,
- .ack = tsi108_pci_irq_ack,
- .end = tsi108_pci_irq_end,
- .unmask = tsi108_pci_irq_enable,
+ .irq_mask = tsi108_pci_irq_mask,
+ .irq_ack = tsi108_pci_irq_ack,
+ .irq_unmask = tsi108_pci_irq_unmask,
};
static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct,
@@ -437,8 +431,11 @@ void __init tsi108_pci_int_init(struct device_node *node)
void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = get_pci_source();
+
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+
+ chip->irq_eoi(&desc->irq_data);
}
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 0038fb78f094..835f7958b237 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -55,11 +55,11 @@ struct uic {
struct irq_host *irqhost;
};
-static void uic_unmask_irq(unsigned int virq)
+static void uic_unmask_irq(struct irq_data *d)
{
- struct irq_desc *desc = irq_to_desc(virq);
- struct uic *uic = get_irq_chip_data(virq);
- unsigned int src = uic_irq_to_hw(virq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
+ struct uic *uic = irq_data_get_irq_chip_data(d);
+ unsigned int src = uic_irq_to_hw(d->irq);
unsigned long flags;
u32 er, sr;
@@ -74,10 +74,10 @@ static void uic_unmask_irq(unsigned int virq)
spin_unlock_irqrestore(&uic->lock, flags);
}
-static void uic_mask_irq(unsigned int virq)
+static void uic_mask_irq(struct irq_data *d)
{
- struct uic *uic = get_irq_chip_data(virq);
- unsigned int src = uic_irq_to_hw(virq);
+ struct uic *uic = irq_data_get_irq_chip_data(d);
+ unsigned int src = uic_irq_to_hw(d->irq);
unsigned long flags;
u32 er;
@@ -88,10 +88,10 @@ static void uic_mask_irq(unsigned int virq)
spin_unlock_irqrestore(&uic->lock, flags);
}
-static void uic_ack_irq(unsigned int virq)
+static void uic_ack_irq(struct irq_data *d)
{
- struct uic *uic = get_irq_chip_data(virq);
- unsigned int src = uic_irq_to_hw(virq);
+ struct uic *uic = irq_data_get_irq_chip_data(d);
+ unsigned int src = uic_irq_to_hw(d->irq);
unsigned long flags;
spin_lock_irqsave(&uic->lock, flags);
@@ -99,11 +99,11 @@ static void uic_ack_irq(unsigned int virq)
spin_unlock_irqrestore(&uic->lock, flags);
}
-static void uic_mask_ack_irq(unsigned int virq)
+static void uic_mask_ack_irq(struct irq_data *d)
{
- struct irq_desc *desc = irq_to_desc(virq);
- struct uic *uic = get_irq_chip_data(virq);
- unsigned int src = uic_irq_to_hw(virq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
+ struct uic *uic = irq_data_get_irq_chip_data(d);
+ unsigned int src = uic_irq_to_hw(d->irq);
unsigned long flags;
u32 er, sr;
@@ -125,18 +125,18 @@ static void uic_mask_ack_irq(unsigned int virq)
spin_unlock_irqrestore(&uic->lock, flags);
}
-static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
+static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- struct uic *uic = get_irq_chip_data(virq);
- unsigned int src = uic_irq_to_hw(virq);
- struct irq_desc *desc = irq_to_desc(virq);
+ struct uic *uic = irq_data_get_irq_chip_data(d);
+ unsigned int src = uic_irq_to_hw(d->irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
unsigned long flags;
int trigger, polarity;
u32 tr, pr, mask;
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_NONE:
- uic_mask_irq(virq);
+ uic_mask_irq(d);
return 0;
case IRQ_TYPE_EDGE_RISING:
@@ -178,11 +178,11 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
static struct irq_chip uic_irq_chip = {
.name = "UIC",
- .unmask = uic_unmask_irq,
- .mask = uic_mask_irq,
- .mask_ack = uic_mask_ack_irq,
- .ack = uic_ack_irq,
- .set_type = uic_set_irq_type,
+ .irq_unmask = uic_unmask_irq,
+ .irq_mask = uic_mask_irq,
+ .irq_mask_ack = uic_mask_ack_irq,
+ .irq_ack = uic_ack_irq,
+ .irq_set_type = uic_set_irq_type,
};
static int uic_host_map(struct irq_host *h, unsigned int virq,
@@ -220,6 +220,7 @@ static struct irq_host_ops uic_host_ops = {
void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
struct uic *uic = get_irq_data(virq);
u32 msr;
int src;
@@ -227,9 +228,9 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
raw_spin_lock(&desc->lock);
if (desc->status & IRQ_LEVEL)
- desc->chip->mask(virq);
+ chip->irq_mask(&desc->irq_data);
else
- desc->chip->mask_ack(virq);
+ chip->irq_mask_ack(&desc->irq_data);
raw_spin_unlock(&desc->lock);
msr = mfdcr(uic->dcrbase + UIC_MSR);
@@ -244,9 +245,9 @@ void uic_irq_cascade(unsigned int virq, struct irq_desc *desc)
uic_irq_ret:
raw_spin_lock(&desc->lock);
if (desc->status & IRQ_LEVEL)
- desc->chip->ack(virq);
- if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
- desc->chip->unmask(virq);
+ chip->irq_ack(&desc->irq_data);
+ if (!(desc->status & IRQ_DISABLED) && chip->irq_unmask)
+ chip->irq_unmask(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 1e0ccfaf403e..7436f3ed4df6 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -69,17 +69,17 @@ static unsigned char xilinx_intc_map_senses[] = {
*
* IRQ Chip common (across level and edge) operations
*/
-static void xilinx_intc_mask(unsigned int virq)
+static void xilinx_intc_mask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void * regs = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void * regs = irq_data_get_irq_chip_data(d);
pr_debug("mask: %d\n", irq);
out_be32(regs + XINTC_CIE, 1 << irq);
}
-static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type)
+static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type)
{
- struct irq_desc *desc = irq_to_desc(virq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
@@ -91,10 +91,10 @@ static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type)
/*
* IRQ Chip level operations
*/
-static void xilinx_intc_level_unmask(unsigned int virq)
+static void xilinx_intc_level_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void * regs = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void * regs = irq_data_get_irq_chip_data(d);
pr_debug("unmask: %d\n", irq);
out_be32(regs + XINTC_SIE, 1 << irq);
@@ -107,37 +107,37 @@ static void xilinx_intc_level_unmask(unsigned int virq)
static struct irq_chip xilinx_intc_level_irqchip = {
.name = "Xilinx Level INTC",
- .mask = xilinx_intc_mask,
- .mask_ack = xilinx_intc_mask,
- .unmask = xilinx_intc_level_unmask,
- .set_type = xilinx_intc_set_type,
+ .irq_mask = xilinx_intc_mask,
+ .irq_mask_ack = xilinx_intc_mask,
+ .irq_unmask = xilinx_intc_level_unmask,
+ .irq_set_type = xilinx_intc_set_type,
};
/*
* IRQ Chip edge operations
*/
-static void xilinx_intc_edge_unmask(unsigned int virq)
+static void xilinx_intc_edge_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void *regs = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void *regs = irq_data_get_irq_chip_data(d);
pr_debug("unmask: %d\n", irq);
out_be32(regs + XINTC_SIE, 1 << irq);
}
-static void xilinx_intc_edge_ack(unsigned int virq)
+static void xilinx_intc_edge_ack(struct irq_data *d)
{
- int irq = virq_to_hw(virq);
- void * regs = get_irq_chip_data(virq);
+ int irq = virq_to_hw(d->irq);
+ void * regs = irq_data_get_irq_chip_data(d);
pr_debug("ack: %d\n", irq);
out_be32(regs + XINTC_IAR, 1 << irq);
}
static struct irq_chip xilinx_intc_edge_irqchip = {
.name = "Xilinx Edge INTC",
- .mask = xilinx_intc_mask,
- .unmask = xilinx_intc_edge_unmask,
- .ack = xilinx_intc_edge_ack,
- .set_type = xilinx_intc_set_type,
+ .irq_mask = xilinx_intc_mask,
+ .irq_unmask = xilinx_intc_edge_unmask,
+ .irq_ack = xilinx_intc_edge_ack,
+ .irq_set_type = xilinx_intc_set_type,
};
/*
@@ -229,12 +229,14 @@ int xilinx_intc_get_irq(void)
*/
static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = get_irq_desc_chip(desc);
unsigned int cascade_irq = i8259_irq();
+
if (cascade_irq)
generic_handle_irq(cascade_irq);
/* Let xilinx_intc end the interrupt */
- desc->chip->unmask(irq);
+ chip->irq_unmask(&desc->irq_data);
}
static void __init xilinx_i8259_setup_cascade(void)
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile
index 537b2d840e69..d698cddcfbdd 100644
--- a/arch/s390/oprofile/Makefile
+++ b/arch/s390/oprofile/Makefile
@@ -6,4 +6,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o \
timer_int.o )
-oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
+oprofile-y := $(DRIVER_OBJS) init.o backtrace.o hwsampler.o
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c
new file mode 100644
index 000000000000..3d48f4db246d
--- /dev/null
+++ b/arch/s390/oprofile/hwsampler.c
@@ -0,0 +1,1256 @@
+/**
+ * arch/s390/oprofile/hwsampler.c
+ *
+ * Copyright IBM Corp. 2010
+ * Author: Heinz Graalfs <graalfs@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/semaphore.h>
+#include <linux/oom.h>
+#include <linux/oprofile.h>
+
+#include <asm/lowcore.h>
+#include <asm/s390_ext.h>
+
+#include "hwsampler.h"
+
+#define MAX_NUM_SDB 511
+#define MIN_NUM_SDB 1
+
+#define ALERT_REQ_MASK 0x4000000000000000ul
+#define BUFFER_FULL_MASK 0x8000000000000000ul
+
+#define EI_IEA (1 << 31) /* invalid entry address */
+#define EI_ISE (1 << 30) /* incorrect SDBT entry */
+#define EI_PRA (1 << 29) /* program request alert */
+#define EI_SACA (1 << 23) /* sampler authorization change alert */
+#define EI_LSDA (1 << 22) /* loss of sample data alert */
+
+DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
+
+struct hws_execute_parms {
+ void *buffer;
+ signed int rc;
+};
+
+DEFINE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
+EXPORT_PER_CPU_SYMBOL(sampler_cpu_buffer);
+
+static DEFINE_MUTEX(hws_sem);
+static DEFINE_MUTEX(hws_sem_oom);
+
+static unsigned char hws_flush_all;
+static unsigned int hws_oom;
+static struct workqueue_struct *hws_wq;
+
+static unsigned int hws_state;
+enum {
+ HWS_INIT = 1,
+ HWS_DEALLOCATED,
+ HWS_STOPPED,
+ HWS_STARTED,
+ HWS_STOPPING };
+
+/* set to 1 if called by kernel during memory allocation */
+static unsigned char oom_killer_was_active;
+/* size of SDBT and SDB as of allocate API */
+static unsigned long num_sdbt = 100;
+static unsigned long num_sdb = 511;
+/* sampling interval (machine cycles) */
+static unsigned long interval;
+
+static unsigned long min_sampler_rate;
+static unsigned long max_sampler_rate;
+
+static int ssctl(void *buffer)
+{
+ int cc;
+
+ /* set in order to detect a program check */
+ cc = 1;
+
+ asm volatile(
+ "0: .insn s,0xB2870000,0(%1)\n"
+ "1: ipm %0\n"
+ " srl %0,28\n"
+ "2:\n"
+ EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
+ : "+d" (cc), "+a" (buffer)
+ : "m" (*((struct hws_ssctl_request_block *)buffer))
+ : "cc", "memory");
+
+ return cc ? -EINVAL : 0 ;
+}
+
+static int qsi(void *buffer)
+{
+ int cc;
+ cc = 1;
+
+ asm volatile(
+ "0: .insn s,0xB2860000,0(%1)\n"
+ "1: lhi %0,0\n"
+ "2:\n"
+ EX_TABLE(0b, 2b) EX_TABLE(1b, 2b)
+ : "=d" (cc), "+a" (buffer)
+ : "m" (*((struct hws_qsi_info_block *)buffer))
+ : "cc", "memory");
+
+ return cc ? -EINVAL : 0;
+}
+
+static void execute_qsi(void *parms)
+{
+ struct hws_execute_parms *ep = parms;
+
+ ep->rc = qsi(ep->buffer);
+}
+
+static void execute_ssctl(void *parms)
+{
+ struct hws_execute_parms *ep = parms;
+
+ ep->rc = ssctl(ep->buffer);
+}
+
+static int smp_ctl_ssctl_stop(int cpu)
+{
+ int rc;
+ struct hws_execute_parms ep;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ cb->ssctl.es = 0;
+ cb->ssctl.cs = 0;
+
+ ep.buffer = &cb->ssctl;
+ smp_call_function_single(cpu, execute_ssctl, &ep, 1);
+ rc = ep.rc;
+ if (rc) {
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF SSCTL failed.\n", cpu);
+ dump_stack();
+ }
+
+ ep.buffer = &cb->qsi;
+ smp_call_function_single(cpu, execute_qsi, &ep, 1);
+
+ if (cb->qsi.es || cb->qsi.cs) {
+ printk(KERN_EMERG "CPUMF sampling did not stop properly.\n");
+ dump_stack();
+ }
+
+ return rc;
+}
+
+static int smp_ctl_ssctl_deactivate(int cpu)
+{
+ int rc;
+ struct hws_execute_parms ep;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ cb->ssctl.es = 1;
+ cb->ssctl.cs = 0;
+
+ ep.buffer = &cb->ssctl;
+ smp_call_function_single(cpu, execute_ssctl, &ep, 1);
+ rc = ep.rc;
+ if (rc)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF SSCTL failed.\n", cpu);
+
+ ep.buffer = &cb->qsi;
+ smp_call_function_single(cpu, execute_qsi, &ep, 1);
+
+ if (cb->qsi.cs)
+ printk(KERN_EMERG "CPUMF sampling was not set inactive.\n");
+
+ return rc;
+}
+
+static int smp_ctl_ssctl_enable_activate(int cpu, unsigned long interval)
+{
+ int rc;
+ struct hws_execute_parms ep;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ cb->ssctl.h = 1;
+ cb->ssctl.tear = cb->first_sdbt;
+ cb->ssctl.dear = *(unsigned long *) cb->first_sdbt;
+ cb->ssctl.interval = interval;
+ cb->ssctl.es = 1;
+ cb->ssctl.cs = 1;
+
+ ep.buffer = &cb->ssctl;
+ smp_call_function_single(cpu, execute_ssctl, &ep, 1);
+ rc = ep.rc;
+ if (rc)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF SSCTL failed.\n", cpu);
+
+ ep.buffer = &cb->qsi;
+ smp_call_function_single(cpu, execute_qsi, &ep, 1);
+ if (ep.rc)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF QSI failed.\n", cpu);
+
+ return rc;
+}
+
+static int smp_ctl_qsi(int cpu)
+{
+ struct hws_execute_parms ep;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ ep.buffer = &cb->qsi;
+ smp_call_function_single(cpu, execute_qsi, &ep, 1);
+
+ return ep.rc;
+}
+
+static inline unsigned long *trailer_entry_ptr(unsigned long v)
+{
+ void *ret;
+
+ ret = (void *)v;
+ ret += PAGE_SIZE;
+ ret -= sizeof(struct hws_trailer_entry);
+
+ return (unsigned long *) ret;
+}
+
+/* prototypes for external interrupt handler and worker */
+static void hws_ext_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64);
+
+static void worker(struct work_struct *work);
+
+static void add_samples_to_oprofile(unsigned cpu, unsigned long *,
+ unsigned long *dear);
+
+static void init_all_cpu_buffers(void)
+{
+ int cpu;
+ struct hws_cpu_buffer *cb;
+
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ memset(cb, 0, sizeof(struct hws_cpu_buffer));
+ }
+}
+
+static int is_link_entry(unsigned long *s)
+{
+ return *s & 0x1ul ? 1 : 0;
+}
+
+static unsigned long *get_next_sdbt(unsigned long *s)
+{
+ return (unsigned long *) (*s & ~0x1ul);
+}
+
+static int prepare_cpu_buffers(void)
+{
+ int cpu;
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ rc = 0;
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ atomic_set(&cb->ext_params, 0);
+ cb->worker_entry = 0;
+ cb->sample_overflow = 0;
+ cb->req_alert = 0;
+ cb->incorrect_sdbt_entry = 0;
+ cb->invalid_entry_address = 0;
+ cb->loss_of_sample_data = 0;
+ cb->sample_auth_change_alert = 0;
+ cb->finish = 0;
+ cb->oom = 0;
+ cb->stop_mode = 0;
+ }
+
+ return rc;
+}
+
+/*
+ * allocate_sdbt() - allocate sampler memory
+ * @cpu: the cpu for which sampler memory is allocated
+ *
+ * A 4K page is allocated for each requested SDBT.
+ * A maximum of 511 4K pages are allocated for the SDBs in each of the SDBTs.
+ * Set ALERT_REQ mask in each SDBs trailer.
+ * Returns zero if successful, <0 otherwise.
+ */
+static int allocate_sdbt(int cpu)
+{
+ int j, k, rc;
+ unsigned long *sdbt;
+ unsigned long sdb;
+ unsigned long *tail;
+ unsigned long *trailer;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ if (cb->first_sdbt)
+ return -EINVAL;
+
+ sdbt = NULL;
+ tail = sdbt;
+
+ for (j = 0; j < num_sdbt; j++) {
+ sdbt = (unsigned long *)get_zeroed_page(GFP_KERNEL);
+
+ mutex_lock(&hws_sem_oom);
+ /* OOM killer might have been activated */
+ barrier();
+ if (oom_killer_was_active || !sdbt) {
+ if (sdbt)
+ free_page((unsigned long)sdbt);
+
+ goto allocate_sdbt_error;
+ }
+ if (cb->first_sdbt == 0)
+ cb->first_sdbt = (unsigned long)sdbt;
+
+ /* link current page to tail of chain */
+ if (tail)
+ *tail = (unsigned long)(void *)sdbt + 1;
+
+ mutex_unlock(&hws_sem_oom);
+
+ for (k = 0; k < num_sdb; k++) {
+ /* get and set SDB page */
+ sdb = get_zeroed_page(GFP_KERNEL);
+
+ mutex_lock(&hws_sem_oom);
+ /* OOM killer might have been activated */
+ barrier();
+ if (oom_killer_was_active || !sdb) {
+ if (sdb)
+ free_page(sdb);
+
+ goto allocate_sdbt_error;
+ }
+ *sdbt = sdb;
+ trailer = trailer_entry_ptr(*sdbt);
+ *trailer = ALERT_REQ_MASK;
+ sdbt++;
+ mutex_unlock(&hws_sem_oom);
+ }
+ tail = sdbt;
+ }
+ mutex_lock(&hws_sem_oom);
+ if (oom_killer_was_active)
+ goto allocate_sdbt_error;
+
+ rc = 0;
+ if (tail)
+ *tail = (unsigned long)
+ ((void *)cb->first_sdbt) + 1;
+
+allocate_sdbt_exit:
+ mutex_unlock(&hws_sem_oom);
+ return rc;
+
+allocate_sdbt_error:
+ rc = -ENOMEM;
+ goto allocate_sdbt_exit;
+}
+
+/*
+ * deallocate_sdbt() - deallocate all sampler memory
+ *
+ * For each online CPU all SDBT trees are deallocated.
+ * Returns the number of freed pages.
+ */
+static int deallocate_sdbt(void)
+{
+ int cpu;
+ int counter;
+
+ counter = 0;
+
+ for_each_online_cpu(cpu) {
+ unsigned long start;
+ unsigned long sdbt;
+ unsigned long *curr;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ if (!cb->first_sdbt)
+ continue;
+
+ sdbt = cb->first_sdbt;
+ curr = (unsigned long *) sdbt;
+ start = sdbt;
+
+ /* we'll free the SDBT after all SDBs are processed... */
+ while (1) {
+ if (!*curr || !sdbt)
+ break;
+
+ /* watch for link entry reset if found */
+ if (is_link_entry(curr)) {
+ curr = get_next_sdbt(curr);
+ if (sdbt)
+ free_page(sdbt);
+
+ /* we are done if we reach the start */
+ if ((unsigned long) curr == start)
+ break;
+ else
+ sdbt = (unsigned long) curr;
+ } else {
+ /* process SDB pointer */
+ if (*curr) {
+ free_page(*curr);
+ curr++;
+ }
+ }
+ counter++;
+ }
+ cb->first_sdbt = 0;
+ }
+ return counter;
+}
+
+static int start_sampling(int cpu)
+{
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ rc = smp_ctl_ssctl_enable_activate(cpu, interval);
+ if (rc) {
+ printk(KERN_INFO "hwsampler: CPU %d ssctl failed.\n", cpu);
+ goto start_exit;
+ }
+
+ rc = -EINVAL;
+ if (!cb->qsi.es) {
+ printk(KERN_INFO "hwsampler: CPU %d ssctl not enabled.\n", cpu);
+ goto start_exit;
+ }
+
+ if (!cb->qsi.cs) {
+ printk(KERN_INFO "hwsampler: CPU %d ssctl not active.\n", cpu);
+ goto start_exit;
+ }
+
+ printk(KERN_INFO
+ "hwsampler: CPU %d, CPUMF Sampling started, interval %lu.\n",
+ cpu, interval);
+
+ rc = 0;
+
+start_exit:
+ return rc;
+}
+
+static int stop_sampling(int cpu)
+{
+ unsigned long v;
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ if (!rc && !cb->qsi.es)
+ printk(KERN_INFO "hwsampler: CPU %d, already stopped.\n", cpu);
+
+ rc = smp_ctl_ssctl_stop(cpu);
+ if (rc) {
+ printk(KERN_INFO "hwsampler: CPU %d, ssctl stop error %d.\n",
+ cpu, rc);
+ goto stop_exit;
+ }
+
+ printk(KERN_INFO "hwsampler: CPU %d, CPUMF Sampling stopped.\n", cpu);
+
+stop_exit:
+ v = cb->req_alert;
+ if (v)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF Request alert,"
+ " count=%lu.\n", cpu, v);
+
+ v = cb->loss_of_sample_data;
+ if (v)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF Loss of sample data,"
+ " count=%lu.\n", cpu, v);
+
+ v = cb->invalid_entry_address;
+ if (v)
+ printk(KERN_ERR "hwsampler: CPU %d CPUMF Invalid entry address,"
+ " count=%lu.\n", cpu, v);
+
+ v = cb->incorrect_sdbt_entry;
+ if (v)
+ printk(KERN_ERR
+ "hwsampler: CPU %d CPUMF Incorrect SDBT address,"
+ " count=%lu.\n", cpu, v);
+
+ v = cb->sample_auth_change_alert;
+ if (v)
+ printk(KERN_ERR
+ "hwsampler: CPU %d CPUMF Sample authorization change,"
+ " count=%lu.\n", cpu, v);
+
+ return rc;
+}
+
+static int check_hardware_prerequisites(void)
+{
+ unsigned long long facility_bits[2];
+
+ memcpy(facility_bits, S390_lowcore.stfle_fac_list, 32);
+ if (!(facility_bits[1] & (1ULL << 59)))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+/*
+ * hws_oom_callback() - the OOM callback function
+ *
+ * In case the callback is invoked during memory allocation for the
+ * hw sampler, all obtained memory is deallocated and a flag is set
+ * so main sampler memory allocation can exit with a failure code.
+ * In case the callback is invoked during sampling the hw sampler
+ * is deactivated for all CPUs.
+ */
+static int hws_oom_callback(struct notifier_block *nfb,
+ unsigned long dummy, void *parm)
+{
+ unsigned long *freed;
+ int cpu;
+ struct hws_cpu_buffer *cb;
+
+ freed = parm;
+
+ mutex_lock(&hws_sem_oom);
+
+ if (hws_state == HWS_DEALLOCATED) {
+ /* during memory allocation */
+ if (oom_killer_was_active == 0) {
+ oom_killer_was_active = 1;
+ *freed += deallocate_sdbt();
+ }
+ } else {
+ int i;
+ cpu = get_cpu();
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ if (!cb->oom) {
+ for_each_online_cpu(i) {
+ smp_ctl_ssctl_deactivate(i);
+ cb->oom = 1;
+ }
+ cb->finish = 1;
+
+ printk(KERN_INFO
+ "hwsampler: CPU %d, OOM notify during CPUMF Sampling.\n",
+ cpu);
+ }
+ }
+
+ mutex_unlock(&hws_sem_oom);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hws_oom_notifier = {
+ .notifier_call = hws_oom_callback
+};
+
+static int hws_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ /* We do not have sampler space available for all possible CPUs.
+ All CPUs should be online when hw sampling is activated. */
+ return NOTIFY_BAD;
+}
+
+static struct notifier_block hws_cpu_notifier = {
+ .notifier_call = hws_cpu_callback
+};
+
+/**
+ * hwsampler_deactivate() - set hardware sampling temporarily inactive
+ * @cpu: specifies the CPU to be set inactive.
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_deactivate(unsigned int cpu)
+{
+ /*
+ * Deactivate hw sampling temporarily and flush the buffer
+ * by pushing all the pending samples to oprofile buffer.
+ *
+ * This function can be called under one of the following conditions:
+ * Memory unmap, task is exiting.
+ */
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ rc = 0;
+ mutex_lock(&hws_sem);
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ if (hws_state == HWS_STARTED) {
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+ if (cb->qsi.cs) {
+ rc = smp_ctl_ssctl_deactivate(cpu);
+ if (rc) {
+ printk(KERN_INFO
+ "hwsampler: CPU %d, CPUMF Deactivation failed.\n", cpu);
+ cb->finish = 1;
+ hws_state = HWS_STOPPING;
+ } else {
+ hws_flush_all = 1;
+ /* Add work to queue to read pending samples.*/
+ queue_work_on(cpu, hws_wq, &cb->worker);
+ }
+ }
+ }
+ mutex_unlock(&hws_sem);
+
+ if (hws_wq)
+ flush_workqueue(hws_wq);
+
+ return rc;
+}
+
+/**
+ * hwsampler_activate() - activate/resume hardware sampling which was deactivated
+ * @cpu: specifies the CPU to be set active.
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_activate(unsigned int cpu)
+{
+ /*
+ * Re-activate hw sampling. This should be called in pair with
+ * hwsampler_deactivate().
+ */
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ rc = 0;
+ mutex_lock(&hws_sem);
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ if (hws_state == HWS_STARTED) {
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+ if (!cb->qsi.cs) {
+ hws_flush_all = 0;
+ rc = smp_ctl_ssctl_enable_activate(cpu, interval);
+ if (rc) {
+ printk(KERN_ERR
+ "CPU %d, CPUMF activate sampling failed.\n",
+ cpu);
+ }
+ }
+ }
+
+ mutex_unlock(&hws_sem);
+
+ return rc;
+}
+
+static void hws_ext_handler(unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
+{
+ int cpu;
+ struct hws_cpu_buffer *cb;
+
+ cpu = smp_processor_id();
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ atomic_xchg(
+ &cb->ext_params,
+ atomic_read(&cb->ext_params)
+ | S390_lowcore.ext_params);
+
+ if (hws_wq)
+ queue_work(hws_wq, &cb->worker);
+}
+
+static int check_qsi_on_setup(void)
+{
+ int rc;
+ unsigned int cpu;
+ struct hws_cpu_buffer *cb;
+
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+ if (rc)
+ return -EOPNOTSUPP;
+
+ if (!cb->qsi.as) {
+ printk(KERN_INFO "hwsampler: CPUMF sampling is not authorized.\n");
+ return -EINVAL;
+ }
+
+ if (cb->qsi.es) {
+ printk(KERN_WARNING "hwsampler: CPUMF is still enabled.\n");
+ rc = smp_ctl_ssctl_stop(cpu);
+ if (rc)
+ return -EINVAL;
+
+ printk(KERN_INFO
+ "CPU %d, CPUMF Sampling stopped now.\n", cpu);
+ }
+ }
+ return 0;
+}
+
+static int check_qsi_on_start(void)
+{
+ unsigned int cpu;
+ int rc;
+ struct hws_cpu_buffer *cb;
+
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+
+ if (!cb->qsi.as)
+ return -EINVAL;
+
+ if (cb->qsi.es)
+ return -EINVAL;
+
+ if (cb->qsi.cs)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void worker_on_start(unsigned int cpu)
+{
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ cb->worker_entry = cb->first_sdbt;
+}
+
+static int worker_check_error(unsigned int cpu, int ext_params)
+{
+ int rc;
+ unsigned long *sdbt;
+ struct hws_cpu_buffer *cb;
+
+ rc = 0;
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ sdbt = (unsigned long *) cb->worker_entry;
+
+ if (!sdbt || !*sdbt)
+ return -EINVAL;
+
+ if (ext_params & EI_IEA)
+ cb->req_alert++;
+
+ if (ext_params & EI_LSDA)
+ cb->loss_of_sample_data++;
+
+ if (ext_params & EI_IEA) {
+ cb->invalid_entry_address++;
+ rc = -EINVAL;
+ }
+
+ if (ext_params & EI_ISE) {
+ cb->incorrect_sdbt_entry++;
+ rc = -EINVAL;
+ }
+
+ if (ext_params & EI_SACA) {
+ cb->sample_auth_change_alert++;
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void worker_on_finish(unsigned int cpu)
+{
+ int rc, i;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ if (cb->finish) {
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+ if (cb->qsi.es) {
+ printk(KERN_INFO
+ "hwsampler: CPU %d, CPUMF Stop/Deactivate sampling.\n",
+ cpu);
+ rc = smp_ctl_ssctl_stop(cpu);
+ if (rc)
+ printk(KERN_INFO
+ "hwsampler: CPU %d, CPUMF Deactivation failed.\n",
+ cpu);
+
+ for_each_online_cpu(i) {
+ if (i == cpu)
+ continue;
+ if (!cb->finish) {
+ cb->finish = 1;
+ queue_work_on(i, hws_wq,
+ &cb->worker);
+ }
+ }
+ }
+ }
+}
+
+static void worker_on_interrupt(unsigned int cpu)
+{
+ unsigned long *sdbt;
+ unsigned char done;
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ sdbt = (unsigned long *) cb->worker_entry;
+
+ done = 0;
+ /* do not proceed if stop was entered,
+ * forget the buffers not yet processed */
+ while (!done && !cb->stop_mode) {
+ unsigned long *trailer;
+ struct hws_trailer_entry *te;
+ unsigned long *dear = 0;
+
+ trailer = trailer_entry_ptr(*sdbt);
+ /* leave loop if no more work to do */
+ if (!(*trailer & BUFFER_FULL_MASK)) {
+ done = 1;
+ if (!hws_flush_all)
+ continue;
+ }
+
+ te = (struct hws_trailer_entry *)trailer;
+ cb->sample_overflow += te->overflow;
+
+ add_samples_to_oprofile(cpu, sdbt, dear);
+
+ /* reset trailer */
+ xchg((unsigned char *) te, 0x40);
+
+ /* advance to next sdb slot in current sdbt */
+ sdbt++;
+ /* in case link bit is set use address w/o link bit */
+ if (is_link_entry(sdbt))
+ sdbt = get_next_sdbt(sdbt);
+
+ cb->worker_entry = (unsigned long)sdbt;
+ }
+}
+
+static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt,
+ unsigned long *dear)
+{
+ struct hws_data_entry *sample_data_ptr;
+ unsigned long *trailer;
+
+ trailer = trailer_entry_ptr(*sdbt);
+ if (dear) {
+ if (dear > trailer)
+ return;
+ trailer = dear;
+ }
+
+ sample_data_ptr = (struct hws_data_entry *)(*sdbt);
+
+ while ((unsigned long *)sample_data_ptr < trailer) {
+ struct pt_regs *regs = NULL;
+ struct task_struct *tsk = NULL;
+
+ /*
+ * Check sampling mode, 1 indicates basic (=customer) sampling
+ * mode.
+ */
+ if (sample_data_ptr->def != 1) {
+ /* sample slot is not yet written */
+ break;
+ } else {
+ /* make sure we don't use it twice,
+ * the next time the sampler will set it again */
+ sample_data_ptr->def = 0;
+ }
+
+ /* Get pt_regs. */
+ if (sample_data_ptr->P == 1) {
+ /* userspace sample */
+ unsigned int pid = sample_data_ptr->prim_asn;
+ rcu_read_lock();
+ tsk = pid_task(find_vpid(pid), PIDTYPE_PID);
+ if (tsk)
+ regs = task_pt_regs(tsk);
+ rcu_read_unlock();
+ } else {
+ /* kernelspace sample */
+ regs = task_pt_regs(current);
+ }
+
+ mutex_lock(&hws_sem);
+ oprofile_add_ext_hw_sample(sample_data_ptr->ia, regs, 0,
+ !sample_data_ptr->P, tsk);
+ mutex_unlock(&hws_sem);
+
+ sample_data_ptr++;
+ }
+}
+
+static void worker(struct work_struct *work)
+{
+ unsigned int cpu;
+ int ext_params;
+ struct hws_cpu_buffer *cb;
+
+ cb = container_of(work, struct hws_cpu_buffer, worker);
+ cpu = smp_processor_id();
+ ext_params = atomic_xchg(&cb->ext_params, 0);
+
+ if (!cb->worker_entry)
+ worker_on_start(cpu);
+
+ if (worker_check_error(cpu, ext_params))
+ return;
+
+ if (!cb->finish)
+ worker_on_interrupt(cpu);
+
+ if (cb->finish)
+ worker_on_finish(cpu);
+}
+
+/**
+ * hwsampler_allocate() - allocate memory for the hardware sampler
+ * @sdbt: number of SDBTs per online CPU (must be > 0)
+ * @sdb: number of SDBs per SDBT (minimum 1, maximum 511)
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_allocate(unsigned long sdbt, unsigned long sdb)
+{
+ int cpu, rc;
+ mutex_lock(&hws_sem);
+
+ rc = -EINVAL;
+ if (hws_state != HWS_DEALLOCATED)
+ goto allocate_exit;
+
+ if (sdbt < 1)
+ goto allocate_exit;
+
+ if (sdb > MAX_NUM_SDB || sdb < MIN_NUM_SDB)
+ goto allocate_exit;
+
+ num_sdbt = sdbt;
+ num_sdb = sdb;
+
+ oom_killer_was_active = 0;
+ register_oom_notifier(&hws_oom_notifier);
+
+ for_each_online_cpu(cpu) {
+ if (allocate_sdbt(cpu)) {
+ unregister_oom_notifier(&hws_oom_notifier);
+ goto allocate_error;
+ }
+ }
+ unregister_oom_notifier(&hws_oom_notifier);
+ if (oom_killer_was_active)
+ goto allocate_error;
+
+ hws_state = HWS_STOPPED;
+ rc = 0;
+
+allocate_exit:
+ mutex_unlock(&hws_sem);
+ return rc;
+
+allocate_error:
+ rc = -ENOMEM;
+ printk(KERN_ERR "hwsampler: CPUMF Memory allocation failed.\n");
+ goto allocate_exit;
+}
+
+/**
+ * hwsampler_deallocate() - deallocate hardware sampler memory
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_deallocate()
+{
+ int rc;
+
+ mutex_lock(&hws_sem);
+
+ rc = -EINVAL;
+ if (hws_state != HWS_STOPPED)
+ goto deallocate_exit;
+
+ smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+ deallocate_sdbt();
+
+ hws_state = HWS_DEALLOCATED;
+ rc = 0;
+
+deallocate_exit:
+ mutex_unlock(&hws_sem);
+
+ return rc;
+}
+
+long hwsampler_query_min_interval(void)
+{
+ if (min_sampler_rate)
+ return min_sampler_rate;
+ else
+ return -EINVAL;
+}
+
+long hwsampler_query_max_interval(void)
+{
+ if (max_sampler_rate)
+ return max_sampler_rate;
+ else
+ return -EINVAL;
+}
+
+unsigned long hwsampler_get_sample_overflow_count(unsigned int cpu)
+{
+ struct hws_cpu_buffer *cb;
+
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+
+ return cb->sample_overflow;
+}
+
+int hwsampler_setup()
+{
+ int rc;
+ int cpu;
+ struct hws_cpu_buffer *cb;
+
+ mutex_lock(&hws_sem);
+
+ rc = -EINVAL;
+ if (hws_state)
+ goto setup_exit;
+
+ hws_state = HWS_INIT;
+
+ init_all_cpu_buffers();
+
+ rc = check_hardware_prerequisites();
+ if (rc)
+ goto setup_exit;
+
+ rc = check_qsi_on_setup();
+ if (rc)
+ goto setup_exit;
+
+ rc = -EINVAL;
+ hws_wq = create_workqueue("hwsampler");
+ if (!hws_wq)
+ goto setup_exit;
+
+ register_cpu_notifier(&hws_cpu_notifier);
+
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ INIT_WORK(&cb->worker, worker);
+ rc = smp_ctl_qsi(cpu);
+ WARN_ON(rc);
+ if (min_sampler_rate != cb->qsi.min_sampl_rate) {
+ if (min_sampler_rate) {
+ printk(KERN_WARNING
+ "hwsampler: different min sampler rate values.\n");
+ if (min_sampler_rate < cb->qsi.min_sampl_rate)
+ min_sampler_rate =
+ cb->qsi.min_sampl_rate;
+ } else
+ min_sampler_rate = cb->qsi.min_sampl_rate;
+ }
+ if (max_sampler_rate != cb->qsi.max_sampl_rate) {
+ if (max_sampler_rate) {
+ printk(KERN_WARNING
+ "hwsampler: different max sampler rate values.\n");
+ if (max_sampler_rate > cb->qsi.max_sampl_rate)
+ max_sampler_rate =
+ cb->qsi.max_sampl_rate;
+ } else
+ max_sampler_rate = cb->qsi.max_sampl_rate;
+ }
+ }
+ register_external_interrupt(0x1407, hws_ext_handler);
+
+ hws_state = HWS_DEALLOCATED;
+ rc = 0;
+
+setup_exit:
+ mutex_unlock(&hws_sem);
+ return rc;
+}
+
+int hwsampler_shutdown()
+{
+ int rc;
+
+ mutex_lock(&hws_sem);
+
+ rc = -EINVAL;
+ if (hws_state == HWS_DEALLOCATED || hws_state == HWS_STOPPED) {
+ mutex_unlock(&hws_sem);
+
+ if (hws_wq)
+ flush_workqueue(hws_wq);
+
+ mutex_lock(&hws_sem);
+
+ if (hws_state == HWS_STOPPED) {
+ smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+ deallocate_sdbt();
+ }
+ if (hws_wq) {
+ destroy_workqueue(hws_wq);
+ hws_wq = NULL;
+ }
+
+ unregister_external_interrupt(0x1407, hws_ext_handler);
+ hws_state = HWS_INIT;
+ rc = 0;
+ }
+ mutex_unlock(&hws_sem);
+
+ unregister_cpu_notifier(&hws_cpu_notifier);
+
+ return rc;
+}
+
+/**
+ * hwsampler_start_all() - start hardware sampling on all online CPUs
+ * @rate: specifies the used interval when samples are taken
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_start_all(unsigned long rate)
+{
+ int rc, cpu;
+
+ mutex_lock(&hws_sem);
+
+ hws_oom = 0;
+
+ rc = -EINVAL;
+ if (hws_state != HWS_STOPPED)
+ goto start_all_exit;
+
+ interval = rate;
+
+ /* fail if rate is not valid */
+ if (interval < min_sampler_rate || interval > max_sampler_rate)
+ goto start_all_exit;
+
+ rc = check_qsi_on_start();
+ if (rc)
+ goto start_all_exit;
+
+ rc = prepare_cpu_buffers();
+ if (rc)
+ goto start_all_exit;
+
+ for_each_online_cpu(cpu) {
+ rc = start_sampling(cpu);
+ if (rc)
+ break;
+ }
+ if (rc) {
+ for_each_online_cpu(cpu) {
+ stop_sampling(cpu);
+ }
+ goto start_all_exit;
+ }
+ hws_state = HWS_STARTED;
+ rc = 0;
+
+start_all_exit:
+ mutex_unlock(&hws_sem);
+
+ if (rc)
+ return rc;
+
+ register_oom_notifier(&hws_oom_notifier);
+ hws_oom = 1;
+ hws_flush_all = 0;
+ /* now let them in, 1407 CPUMF external interrupts */
+ smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */
+
+ return 0;
+}
+
+/**
+ * hwsampler_stop_all() - stop hardware sampling on all online CPUs
+ *
+ * Returns 0 on success, !0 on failure.
+ */
+int hwsampler_stop_all()
+{
+ int tmp_rc, rc, cpu;
+ struct hws_cpu_buffer *cb;
+
+ mutex_lock(&hws_sem);
+
+ rc = 0;
+ if (hws_state == HWS_INIT) {
+ mutex_unlock(&hws_sem);
+ return rc;
+ }
+ hws_state = HWS_STOPPING;
+ mutex_unlock(&hws_sem);
+
+ for_each_online_cpu(cpu) {
+ cb = &per_cpu(sampler_cpu_buffer, cpu);
+ cb->stop_mode = 1;
+ tmp_rc = stop_sampling(cpu);
+ if (tmp_rc)
+ rc = tmp_rc;
+ }
+
+ if (hws_wq)
+ flush_workqueue(hws_wq);
+
+ mutex_lock(&hws_sem);
+ if (hws_oom) {
+ unregister_oom_notifier(&hws_oom_notifier);
+ hws_oom = 0;
+ }
+ hws_state = HWS_STOPPED;
+ mutex_unlock(&hws_sem);
+
+ return rc;
+}
diff --git a/arch/s390/oprofile/hwsampler.h b/arch/s390/oprofile/hwsampler.h
new file mode 100644
index 000000000000..8c72b59316b5
--- /dev/null
+++ b/arch/s390/oprofile/hwsampler.h
@@ -0,0 +1,113 @@
+/*
+ * CPUMF HW sampler functions and internal structures
+ *
+ * Copyright IBM Corp. 2010
+ * Author(s): Heinz Graalfs <graalfs@de.ibm.com>
+ */
+
+#ifndef HWSAMPLER_H_
+#define HWSAMPLER_H_
+
+#include <linux/workqueue.h>
+
+struct hws_qsi_info_block /* QUERY SAMPLING information block */
+{ /* Bit(s) */
+ unsigned int b0_13:14; /* 0-13: zeros */
+ unsigned int as:1; /* 14: sampling authorisation control*/
+ unsigned int b15_21:7; /* 15-21: zeros */
+ unsigned int es:1; /* 22: sampling enable control */
+ unsigned int b23_29:7; /* 23-29: zeros */
+ unsigned int cs:1; /* 30: sampling activation control */
+ unsigned int:1; /* 31: reserved */
+ unsigned int bsdes:16; /* 4-5: size of sampling entry */
+ unsigned int:16; /* 6-7: reserved */
+ unsigned long min_sampl_rate; /* 8-15: minimum sampling interval */
+ unsigned long max_sampl_rate; /* 16-23: maximum sampling interval*/
+ unsigned long tear; /* 24-31: TEAR contents */
+ unsigned long dear; /* 32-39: DEAR contents */
+ unsigned int rsvrd0; /* 40-43: reserved */
+ unsigned int cpu_speed; /* 44-47: CPU speed */
+ unsigned long long rsvrd1; /* 48-55: reserved */
+ unsigned long long rsvrd2; /* 56-63: reserved */
+};
+
+struct hws_ssctl_request_block /* SET SAMPLING CONTROLS req block */
+{ /* bytes 0 - 7 Bit(s) */
+ unsigned int s:1; /* 0: maximum buffer indicator */
+ unsigned int h:1; /* 1: part. level reserved for VM use*/
+ unsigned long b2_53:52; /* 2-53: zeros */
+ unsigned int es:1; /* 54: sampling enable control */
+ unsigned int b55_61:7; /* 55-61: - zeros */
+ unsigned int cs:1; /* 62: sampling activation control */
+ unsigned int b63:1; /* 63: zero */
+ unsigned long interval; /* 8-15: sampling interval */
+ unsigned long tear; /* 16-23: TEAR contents */
+ unsigned long dear; /* 24-31: DEAR contents */
+ /* 32-63: */
+ unsigned long rsvrd1; /* reserved */
+ unsigned long rsvrd2; /* reserved */
+ unsigned long rsvrd3; /* reserved */
+ unsigned long rsvrd4; /* reserved */
+};
+
+struct hws_cpu_buffer {
+ unsigned long first_sdbt; /* @ of 1st SDB-Table for this CP*/
+ unsigned long worker_entry;
+ unsigned long sample_overflow; /* taken from SDB ... */
+ struct hws_qsi_info_block qsi;
+ struct hws_ssctl_request_block ssctl;
+ struct work_struct worker;
+ atomic_t ext_params;
+ unsigned long req_alert;
+ unsigned long loss_of_sample_data;
+ unsigned long invalid_entry_address;
+ unsigned long incorrect_sdbt_entry;
+ unsigned long sample_auth_change_alert;
+ unsigned int finish:1;
+ unsigned int oom:1;
+ unsigned int stop_mode:1;
+};
+
+struct hws_data_entry {
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int R:4; /* 16-19 reserved */
+ unsigned int U:4; /* 20-23 Number of unique instruct. */
+ unsigned int z:2; /* zeros */
+ unsigned int T:1; /* 26 PSW DAT mode */
+ unsigned int W:1; /* 27 PSW wait state */
+ unsigned int P:1; /* 28 PSW Problem state */
+ unsigned int AS:2; /* 29-30 PSW address-space control */
+ unsigned int I:1; /* 31 entry valid or invalid */
+ unsigned int:16;
+ unsigned int prim_asn:16; /* primary ASN */
+ unsigned long long ia; /* Instruction Address */
+ unsigned long long lpp; /* Logical-Partition Program Param. */
+ unsigned long long vpp; /* Virtual-Machine Program Param. */
+};
+
+struct hws_trailer_entry {
+ unsigned int f:1; /* 0 - Block Full Indicator */
+ unsigned int a:1; /* 1 - Alert request control */
+ unsigned long:62; /* 2 - 63: Reserved */
+ unsigned long overflow; /* 64 - sample Overflow count */
+ unsigned long timestamp; /* 16 - time-stamp */
+ unsigned long timestamp1; /* */
+ unsigned long reserved1; /* 32 -Reserved */
+ unsigned long reserved2; /* */
+ unsigned long progusage1; /* 48 - reserved for programming use */
+ unsigned long progusage2; /* */
+};
+
+int hwsampler_setup(void);
+int hwsampler_shutdown(void);
+int hwsampler_allocate(unsigned long sdbt, unsigned long sdb);
+int hwsampler_deallocate(void);
+long hwsampler_query_min_interval(void);
+long hwsampler_query_max_interval(void);
+int hwsampler_start_all(unsigned long interval);
+int hwsampler_stop_all(void);
+int hwsampler_deactivate(unsigned int cpu);
+int hwsampler_activate(unsigned int cpu);
+unsigned long hwsampler_get_sample_overflow_count(unsigned int cpu);
+
+#endif /*HWSAMPLER_H_*/
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
index 7a995113b918..16c76def4a9d 100644
--- a/arch/s390/oprofile/init.c
+++ b/arch/s390/oprofile/init.c
@@ -4,23 +4,182 @@
* S390 Version
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ * Author(s): Mahesh Salgaonkar (mahesh@linux.vnet.ibm.com)
+ * Author(s): Heinz Graalfs (graalfs@linux.vnet.ibm.com)
*
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2011 OProfile authors
*/
#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+
+#include "../../../drivers/oprofile/oprof.h"
+#include "hwsampler.h"
+
+#define DEFAULT_INTERVAL 4096
+
+#define DEFAULT_SDBT_BLOCKS 1
+#define DEFAULT_SDB_BLOCKS 511
+
+static unsigned long oprofile_hw_interval = DEFAULT_INTERVAL;
+static unsigned long oprofile_min_interval;
+static unsigned long oprofile_max_interval;
+
+static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS;
+static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS;
+static int hwsampler_file;
+static int hwsampler_running; /* start_mutex must be held to change */
+
+static struct oprofile_operations timer_ops;
extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
-int __init oprofile_arch_init(struct oprofile_operations* ops)
+static int oprofile_hwsampler_start(void)
+{
+ int retval;
+
+ hwsampler_running = hwsampler_file;
+
+ if (!hwsampler_running)
+ return timer_ops.start();
+
+ retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
+ if (retval)
+ return retval;
+
+ retval = hwsampler_start_all(oprofile_hw_interval);
+ if (retval)
+ hwsampler_deallocate();
+
+ return retval;
+}
+
+static void oprofile_hwsampler_stop(void)
+{
+ if (!hwsampler_running) {
+ timer_ops.stop();
+ return;
+ }
+
+ hwsampler_stop_all();
+ hwsampler_deallocate();
+ return;
+}
+
+static ssize_t hwsampler_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ return oprofilefs_ulong_to_user(hwsampler_file, buf, count, offset);
+}
+
+static ssize_t hwsampler_write(struct file *file, char const __user *buf,
+ size_t count, loff_t *offset)
+{
+ unsigned long val;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = oprofilefs_ulong_from_user(&val, buf, count);
+ if (retval)
+ return retval;
+
+ if (oprofile_started)
+ /*
+ * save to do without locking as we set
+ * hwsampler_running in start() when start_mutex is
+ * held
+ */
+ return -EBUSY;
+
+ hwsampler_file = val;
+
+ return count;
+}
+
+static const struct file_operations hwsampler_fops = {
+ .read = hwsampler_read,
+ .write = hwsampler_write,
+};
+
+static int oprofile_create_hwsampling_files(struct super_block *sb,
+ struct dentry *root)
+{
+ struct dentry *hw_dir;
+
+ /* reinitialize default values */
+ hwsampler_file = 1;
+
+ hw_dir = oprofilefs_mkdir(sb, root, "hwsampling");
+ if (!hw_dir)
+ return -EINVAL;
+
+ oprofilefs_create_file(sb, hw_dir, "hwsampler", &hwsampler_fops);
+ oprofilefs_create_ulong(sb, hw_dir, "hw_interval",
+ &oprofile_hw_interval);
+ oprofilefs_create_ro_ulong(sb, hw_dir, "hw_min_interval",
+ &oprofile_min_interval);
+ oprofilefs_create_ro_ulong(sb, hw_dir, "hw_max_interval",
+ &oprofile_max_interval);
+ oprofilefs_create_ulong(sb, hw_dir, "hw_sdbt_blocks",
+ &oprofile_sdbt_blocks);
+
+ return 0;
+}
+
+static int oprofile_hwsampler_init(struct oprofile_operations *ops)
+{
+ if (hwsampler_setup())
+ return -ENODEV;
+
+ /*
+ * create hwsampler files only if hwsampler_setup() succeeds.
+ */
+ oprofile_min_interval = hwsampler_query_min_interval();
+ if (oprofile_min_interval < 0) {
+ oprofile_min_interval = 0;
+ return -ENODEV;
+ }
+ oprofile_max_interval = hwsampler_query_max_interval();
+ if (oprofile_max_interval < 0) {
+ oprofile_max_interval = 0;
+ return -ENODEV;
+ }
+
+ if (oprofile_timer_init(ops))
+ return -ENODEV;
+
+ printk(KERN_INFO "oprofile: using hardware sampling\n");
+
+ memcpy(&timer_ops, ops, sizeof(timer_ops));
+
+ ops->start = oprofile_hwsampler_start;
+ ops->stop = oprofile_hwsampler_stop;
+ ops->create_files = oprofile_create_hwsampling_files;
+
+ return 0;
+}
+
+static void oprofile_hwsampler_exit(void)
+{
+ oprofile_timer_exit();
+ hwsampler_shutdown();
+}
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
{
ops->backtrace = s390_backtrace;
- return -ENODEV;
+
+ return oprofile_hwsampler_init(ops);
}
void oprofile_arch_exit(void)
{
+ oprofile_hwsampler_exit();
}
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 3b71d2190de1..e44480ce2ea8 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -725,11 +725,7 @@ static struct platform_device camera_devices[] = {
/* FSI */
static struct sh_fsi_platform_info fsi_info = {
- .portb_flags = SH_FSI_BRS_INV |
- SH_FSI_OUT_SLAVE_MODE |
- SH_FSI_IN_SLAVE_MODE |
- SH_FSI_OFMT(I2S) |
- SH_FSI_IFMT(I2S),
+ .portb_flags = SH_FSI_BRS_INV,
};
static struct resource fsi_resources[] = {
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 527679394a25..c8bcf6a19b55 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -286,11 +286,7 @@ static struct platform_device ceu1_device = {
/* FSI */
/* change J20, J21, J22 pin to 1-2 connection to use slave mode */
static struct sh_fsi_platform_info fsi_info = {
- .porta_flags = SH_FSI_BRS_INV |
- SH_FSI_OUT_SLAVE_MODE |
- SH_FSI_IN_SLAVE_MODE |
- SH_FSI_OFMT(PCM) |
- SH_FSI_IFMT(PCM),
+ .porta_flags = SH_FSI_BRS_INV,
};
static struct resource fsi_resources[] = {
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h
index 4e2bc490d714..c351aba997b7 100644
--- a/arch/sparc/include/asm/errno.h
+++ b/arch/sparc/include/asm/errno.h
@@ -112,4 +112,6 @@
#define ERFKILL 134 /* Operation not possible due to RF-kill */
+#define EHWPOISON 135 /* Memory page has hardware error */
+
#endif
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 08948e4e1503..f3b78701c219 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -1,5 +1,5 @@
# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
config TILE
def_bool y
@@ -11,17 +11,18 @@ config TILE
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select GENERIC_PENDING_IRQ if SMP
+ select GENERIC_HARDIRQS_NO_DEPRECATED
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
-# select HAVE_OPTPROBES
-# select HAVE_REGS_AND_STACK_ACCESS_API
-# select HAVE_HW_BREAKPOINT
-# select PERF_EVENTS
-# select HAVE_USER_RETURN_NOTIFIER
-# config NO_BOOTMEM
-# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
-# config HUGETLB_PAGE_SIZE_VARIABLE
+# select HAVE_OPTPROBES
+# select HAVE_REGS_AND_STACK_ACCESS_API
+# select HAVE_HW_BREAKPOINT
+# select PERF_EVENTS
+# select HAVE_USER_RETURN_NOTIFIER
+# config NO_BOOTMEM
+# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+# config HUGETLB_PAGE_SIZE_VARIABLE
config MMU
def_bool y
@@ -39,7 +40,7 @@ config HAVE_SETUP_PER_CPU_AREA
def_bool y
config NEED_PER_CPU_PAGE_FIRST_CHUNK
- def_bool y
+ def_bool y
config SYS_SUPPORTS_HUGETLBFS
def_bool y
@@ -201,12 +202,6 @@ config NODES_SHIFT
By default, 2, i.e. 2^2 == 4 DDR2 controllers.
In a system with more controllers, this value should be raised.
-# Need 16MB areas to enable hugetlb
-# See build-time check in arch/tile/mm/init.c.
-config FORCE_MAX_ZONEORDER
- int
- default 9
-
choice
depends on !TILEGX
prompt "Memory split" if EXPERT
@@ -233,8 +228,12 @@ choice
bool "3.5G/0.5G user/kernel split"
config VMSPLIT_3G
bool "3G/1G user/kernel split"
- config VMSPLIT_3G_OPT
- bool "3G/1G user/kernel split (for full 1G low memory)"
+ config VMSPLIT_2_75G
+ bool "2.75G/1.25G user/kernel split (for full 1G low memory)"
+ config VMSPLIT_2_5G
+ bool "2.5G/1.5G user/kernel split"
+ config VMSPLIT_2_25G
+ bool "2.25G/1.75G user/kernel split"
config VMSPLIT_2G
bool "2G/2G user/kernel split"
config VMSPLIT_1G
@@ -245,7 +244,9 @@ config PAGE_OFFSET
hex
default 0xF0000000 if VMSPLIT_3_75G
default 0xE0000000 if VMSPLIT_3_5G
- default 0xB0000000 if VMSPLIT_3G_OPT
+ default 0xB0000000 if VMSPLIT_2_75G
+ default 0xA0000000 if VMSPLIT_2_5G
+ default 0x90000000 if VMSPLIT_2_25G
default 0x80000000 if VMSPLIT_2G
default 0x40000000 if VMSPLIT_1G
default 0xC0000000
diff --git a/arch/tile/include/arch/interrupts_32.h b/arch/tile/include/arch/interrupts_32.h
index 9d0bfa7e59be..96b5710505b6 100644
--- a/arch/tile/include/arch/interrupts_32.h
+++ b/arch/tile/include/arch/interrupts_32.h
@@ -16,10 +16,11 @@
#define __ARCH_INTERRUPTS_H__
/** Mask for an interrupt. */
-#ifdef __ASSEMBLER__
/* Note: must handle breaking interrupts into high and low words manually. */
-#define INT_MASK(intno) (1 << (intno))
-#else
+#define INT_MASK_LO(intno) (1 << (intno))
+#define INT_MASK_HI(intno) (1 << ((intno) - 32))
+
+#ifndef __ASSEMBLER__
#define INT_MASK(intno) (1ULL << (intno))
#endif
@@ -89,6 +90,7 @@
#define NUM_INTERRUPTS 49
+#ifndef __ASSEMBLER__
#define QUEUED_INTERRUPTS ( \
INT_MASK(INT_MEM_ERROR) | \
INT_MASK(INT_DMATLB_MISS) | \
@@ -301,4 +303,5 @@
INT_MASK(INT_DOUBLE_FAULT) | \
INT_MASK(INT_AUX_PERF_COUNT) | \
0)
+#endif /* !__ASSEMBLER__ */
#endif /* !__ARCH_INTERRUPTS_H__ */
diff --git a/arch/tile/include/arch/sim.h b/arch/tile/include/arch/sim.h
index 74b7c1624d34..e54b7b0527f3 100644
--- a/arch/tile/include/arch/sim.h
+++ b/arch/tile/include/arch/sim.h
@@ -152,16 +152,33 @@ sim_dump(unsigned int mask)
/**
* Print a string to the simulator stdout.
*
- * @param str The string to be written; a newline is automatically added.
+ * @param str The string to be written.
+ */
+static __inline void
+sim_print(const char* str)
+{
+ for ( ; *str != '\0'; str++)
+ {
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (*str << _SIM_CONTROL_OPERATOR_BITS));
+ }
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+ (SIM_PUTC_FLUSH_BINARY << _SIM_CONTROL_OPERATOR_BITS));
+}
+
+
+/**
+ * Print a string to the simulator stdout.
+ *
+ * @param str The string to be written (a newline is automatically added).
*/
static __inline void
sim_print_string(const char* str)
{
- int i;
- for (i = 0; str[i] != 0; i++)
+ for ( ; *str != '\0'; str++)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
- (str[i] << _SIM_CONTROL_OPERATOR_BITS));
+ (*str << _SIM_CONTROL_OPERATOR_BITS));
}
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
(SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS));
@@ -203,7 +220,7 @@ sim_command(const char* str)
* we are passing to the simulator are actually valid in the registers
* (i.e. returned from memory) prior to the SIM_CONTROL spr.
*/
-static __inline int _sim_syscall0(int val)
+static __inline long _sim_syscall0(int val)
{
long result;
__asm__ __volatile__ ("mtspr SIM_CONTROL, r0"
@@ -211,7 +228,7 @@ static __inline int _sim_syscall0(int val)
return result;
}
-static __inline int _sim_syscall1(int val, long arg1)
+static __inline long _sim_syscall1(int val, long arg1)
{
long result;
__asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
@@ -219,7 +236,7 @@ static __inline int _sim_syscall1(int val, long arg1)
return result;
}
-static __inline int _sim_syscall2(int val, long arg1, long arg2)
+static __inline long _sim_syscall2(int val, long arg1, long arg2)
{
long result;
__asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
@@ -233,7 +250,7 @@ static __inline int _sim_syscall2(int val, long arg1, long arg2)
the register values for arguments 3 and up may still be in flight
to the core from a stack frame reload. */
-static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
+static __inline long _sim_syscall3(int val, long arg1, long arg2, long arg3)
{
long result;
__asm__ __volatile__ ("{ and zero, r3, r3 };"
@@ -244,7 +261,7 @@ static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
return result;
}
-static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
+static __inline long _sim_syscall4(int val, long arg1, long arg2, long arg3,
long arg4)
{
long result;
@@ -256,7 +273,7 @@ static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
return result;
}
-static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
+static __inline long _sim_syscall5(int val, long arg1, long arg2, long arg3,
long arg4, long arg5)
{
long result;
@@ -268,7 +285,6 @@ static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
return result;
}
-
/**
* Make a special syscall to the simulator itself, if running under
* simulation. This is used as the implementation of other functions
@@ -281,7 +297,8 @@ static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
*/
#define _sim_syscall(syscall_num, nr, args...) \
_sim_syscall##nr( \
- ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, args)
+ ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, \
+ ##args)
/* Values for the "access_mask" parameters below. */
@@ -365,6 +382,13 @@ sim_validate_lines_evicted(unsigned long long pa, unsigned long length)
}
+/* Return the current CPU speed in cycles per second. */
+static __inline long
+sim_query_cpu_speed(void)
+{
+ return _sim_syscall(SIM_SYSCALL_QUERY_CPU_SPEED, 0);
+}
+
#endif /* !__DOXYGEN__ */
diff --git a/arch/tile/include/arch/sim_def.h b/arch/tile/include/arch/sim_def.h
index 7a17082c3773..4b44a2b6a09a 100644
--- a/arch/tile/include/arch/sim_def.h
+++ b/arch/tile/include/arch/sim_def.h
@@ -243,6 +243,9 @@
*/
#define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5
+/** Syscall number for sim_query_cpu_speed(). */
+#define SIM_SYSCALL_QUERY_CPU_SPEED 6
+
/*
* Bit masks which can be shifted by 8, combined with
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index 3b8f55b82dee..849ab2fa1f5c 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
@@ -1,3 +1,4 @@
include include/asm-generic/Kbuild.asm
header-y += ucontext.h
+header-y += hardwall.h
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
index b8c49f98a44c..75a16028a952 100644
--- a/arch/tile/include/asm/atomic.h
+++ b/arch/tile/include/asm/atomic.h
@@ -32,7 +32,7 @@
*/
static inline int atomic_read(const atomic_t *v)
{
- return v->counter;
+ return ACCESS_ONCE(v->counter);
}
/**
diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h
index 7a93c001ac19..2638be51a164 100644
--- a/arch/tile/include/asm/bitops_32.h
+++ b/arch/tile/include/asm/bitops_32.h
@@ -122,7 +122,7 @@ static inline int test_and_change_bit(unsigned nr,
return (_atomic_xor(addr, mask) & mask) != 0;
}
-/* See discussion at smp_mb__before_atomic_dec() in <asm/atomic.h>. */
+/* See discussion at smp_mb__before_atomic_dec() in <asm/atomic_32.h>. */
#define smp_mb__before_clear_bit() smp_mb()
#define smp_mb__after_clear_bit() do {} while (0)
diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h
index 08a2815b5e4e..392e5333dd8b 100644
--- a/arch/tile/include/asm/cache.h
+++ b/arch/tile/include/asm/cache.h
@@ -40,7 +40,7 @@
#define INTERNODE_CACHE_BYTES L2_CACHE_BYTES
/* Group together read-mostly things to avoid cache false sharing */
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
/*
* Attribute for data that is kept read/write coherent until the end of
diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h
index 14a3f8556ace..12fb0fb330ee 100644
--- a/arch/tile/include/asm/cacheflush.h
+++ b/arch/tile/include/asm/cacheflush.h
@@ -138,55 +138,12 @@ static inline void finv_buffer(void *buffer, size_t size)
}
/*
- * Flush & invalidate a VA range that is homed remotely on a single core,
- * waiting until the memory controller holds the flushed values.
+ * Flush and invalidate a VA range that is homed remotely, waiting
+ * until the memory controller holds the flushed values. If "hfh" is
+ * true, we will do a more expensive flush involving additional loads
+ * to make sure we have touched all the possible home cpus of a buffer
+ * that is homed with "hash for home".
*/
-static inline void finv_buffer_remote(void *buffer, size_t size)
-{
- char *p;
- int i;
-
- /*
- * Flush and invalidate the buffer out of the local L1/L2
- * and request the home cache to flush and invalidate as well.
- */
- __finv_buffer(buffer, size);
-
- /*
- * Wait for the home cache to acknowledge that it has processed
- * all the flush-and-invalidate requests. This does not mean
- * that the flushed data has reached the memory controller yet,
- * but it does mean the home cache is processing the flushes.
- */
- __insn_mf();
-
- /*
- * Issue a load to the last cache line, which can't complete
- * until all the previously-issued flushes to the same memory
- * controller have also completed. If we weren't striping
- * memory, that one load would be sufficient, but since we may
- * be, we also need to back up to the last load issued to
- * another memory controller, which would be the point where
- * we crossed an 8KB boundary (the granularity of striping
- * across memory controllers). Keep backing up and doing this
- * until we are before the beginning of the buffer, or have
- * hit all the controllers.
- */
- for (i = 0, p = (char *)buffer + size - 1;
- i < (1 << CHIP_LOG_NUM_MSHIMS()) && p >= (char *)buffer;
- ++i) {
- const unsigned long STRIPE_WIDTH = 8192;
-
- /* Force a load instruction to issue. */
- *(volatile char *)p;
-
- /* Jump to end of previous stripe. */
- p -= STRIPE_WIDTH;
- p = (char *)((unsigned long)p | (STRIPE_WIDTH - 1));
- }
-
- /* Wait for the loads (and thus flushes) to have completed. */
- __insn_mf();
-}
+void finv_buffer_remote(void *buffer, size_t size, int hfh);
#endif /* _ASM_TILE_CACHEFLUSH_H */
diff --git a/arch/tile/include/asm/edac.h b/arch/tile/include/asm/edac.h
new file mode 100644
index 000000000000..87fc83eeaffd
--- /dev/null
+++ b/arch/tile/include/asm/edac.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_EDAC_H
+#define _ASM_TILE_EDAC_H
+
+/* ECC atomic, DMA, SMP and interrupt safe scrub function */
+
+static inline void atomic_scrub(void *va, u32 size)
+{
+ /*
+ * These is nothing to be done here because CE is
+ * corrected by the mshim.
+ */
+ return;
+}
+
+#endif /* _ASM_TILE_EDAC_H */
diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h
index 0521c277bbde..d396d1805163 100644
--- a/arch/tile/include/asm/hugetlb.h
+++ b/arch/tile/include/asm/hugetlb.h
@@ -54,7 +54,7 @@ static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
- set_pte_order(ptep, pte, HUGETLB_PAGE_ORDER);
+ set_pte(ptep, pte);
}
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
index 641e4ff3d805..5db0ce54284d 100644
--- a/arch/tile/include/asm/irqflags.h
+++ b/arch/tile/include/asm/irqflags.h
@@ -18,6 +18,8 @@
#include <arch/interrupts.h>
#include <arch/chip.h>
+#if !defined(__tilegx__) && defined(__ASSEMBLY__)
+
/*
* The set of interrupts we want to allow when interrupts are nominally
* disabled. The remainder are effectively "NMI" interrupts from
@@ -25,6 +27,16 @@
* interrupts (aka "non-queued") are not blocked by the mask in any case.
*/
#if CHIP_HAS_AUX_PERF_COUNTERS()
+#define LINUX_MASKABLE_INTERRUPTS_HI \
+ (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT)))
+#else
+#define LINUX_MASKABLE_INTERRUPTS_HI \
+ (~(INT_MASK_HI(INT_PERF_COUNT)))
+#endif
+
+#else
+
+#if CHIP_HAS_AUX_PERF_COUNTERS()
#define LINUX_MASKABLE_INTERRUPTS \
(~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT)))
#else
@@ -32,6 +44,8 @@
(~(INT_MASK(INT_PERF_COUNT)))
#endif
+#endif
+
#ifndef __ASSEMBLY__
/* NOTE: we can't include <linux/percpu.h> due to #include dependencies. */
@@ -224,11 +238,11 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
#define IRQ_DISABLE(tmp0, tmp1) \
{ \
movei tmp0, -1; \
- moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS) \
+ moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI) \
}; \
{ \
mtspr SPR_INTERRUPT_MASK_SET_K_0, tmp0; \
- auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS) \
+ auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS_HI) \
}; \
mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp1
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 7979a45430d3..3eb53525bf9d 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -16,10 +16,11 @@
#define _ASM_TILE_PAGE_H
#include <linux/const.h>
+#include <hv/pagesize.h>
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
-#define PAGE_SHIFT 16
-#define HPAGE_SHIFT 24
+#define PAGE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
+#define HPAGE_SHIFT HV_LOG2_PAGE_SIZE_LARGE
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
@@ -29,25 +30,18 @@
#ifdef __KERNEL__
-#include <hv/hypervisor.h>
-#include <arch/chip.h>
-
/*
- * The {,H}PAGE_SHIFT values must match the HV_LOG2_PAGE_SIZE_xxx
- * definitions in <hv/hypervisor.h>. We validate this at build time
- * here, and again at runtime during early boot. We provide a
- * separate definition since userspace doesn't have <hv/hypervisor.h>.
- *
- * Be careful to distinguish PAGE_SHIFT from HV_PTE_INDEX_PFN, since
- * they are the same on i386 but not TILE.
+ * If the Kconfig doesn't specify, set a maximum zone order that
+ * is enough so that we can create huge pages from small pages given
+ * the respective sizes of the two page types. See <linux/mmzone.h>.
*/
-#if HV_LOG2_PAGE_SIZE_SMALL != PAGE_SHIFT
-# error Small page size mismatch in Linux
-#endif
-#if HV_LOG2_PAGE_SIZE_LARGE != HPAGE_SHIFT
-# error Huge page size mismatch in Linux
+#ifndef CONFIG_FORCE_MAX_ZONEORDER
+#define CONFIG_FORCE_MAX_ZONEORDER (HPAGE_SHIFT - PAGE_SHIFT + 1)
#endif
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+
#ifndef __ASSEMBLY__
#include <linux/types.h>
@@ -81,12 +75,6 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
* Hypervisor page tables are made of the same basic structure.
*/
-typedef __u64 pteval_t;
-typedef __u64 pmdval_t;
-typedef __u64 pudval_t;
-typedef __u64 pgdval_t;
-typedef __u64 pgprotval_t;
-
typedef HV_PTE pte_t;
typedef HV_PTE pgd_t;
typedef HV_PTE pgprot_t;
diff --git a/arch/tile/include/asm/pgalloc.h b/arch/tile/include/asm/pgalloc.h
index cf52791a5501..e919c0bdc22d 100644
--- a/arch/tile/include/asm/pgalloc.h
+++ b/arch/tile/include/asm/pgalloc.h
@@ -41,9 +41,9 @@
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
#ifdef CONFIG_64BIT
- set_pte_order(pmdp, pmd, L2_USER_PGTABLE_ORDER);
+ set_pte(pmdp, pmd);
#else
- set_pte_order(&pmdp->pud.pgd, pmd.pud.pgd, L2_USER_PGTABLE_ORDER);
+ set_pte(&pmdp->pud.pgd, pmd.pud.pgd);
#endif
}
@@ -100,6 +100,9 @@ pte_t *get_prealloc_pte(unsigned long pfn);
/* During init, we can shatter kernel huge pages if needed. */
void shatter_pmd(pmd_t *pmd);
+/* After init, a more complex technique is required. */
+void shatter_huge_page(unsigned long addr);
+
#ifdef __tilegx__
/* We share a single page allocator for both L1 and L2 page tables. */
#if HV_L1_SIZE != HV_L2_SIZE
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index a6604e9485da..1a20b7ef8ea2 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
@@ -233,15 +233,23 @@ static inline void __pte_clear(pte_t *ptep)
#define pgd_ERROR(e) \
pr_err("%s:%d: bad pgd 0x%016llx.\n", __FILE__, __LINE__, pgd_val(e))
+/* Return PA and protection info for a given kernel VA. */
+int va_to_cpa_and_pte(void *va, phys_addr_t *cpa, pte_t *pte);
+
+/*
+ * __set_pte() ensures we write the 64-bit PTE with 32-bit words in
+ * the right order on 32-bit platforms and also allows us to write
+ * hooks to check valid PTEs, etc., if we want.
+ */
+void __set_pte(pte_t *ptep, pte_t pte);
+
/*
- * set_pte_order() sets the given PTE and also sanity-checks the
+ * set_pte() sets the given PTE and also sanity-checks the
* requested PTE against the page homecaching. Unspecified parts
* of the PTE are filled in when it is written to memory, i.e. all
* caching attributes if "!forcecache", or the home cpu if "anyhome".
*/
-extern void set_pte_order(pte_t *ptep, pte_t pte, int order);
-
-#define set_pte(ptep, pteval) set_pte_order(ptep, pteval, 0)
+extern void set_pte(pte_t *ptep, pte_t pte);
#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
@@ -293,21 +301,6 @@ extern void check_mm_caching(struct mm_struct *prev, struct mm_struct *next);
#define __swp_entry_to_pte(swp) ((pte_t) { (((long long) ((swp).val)) << 32) })
/*
- * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
- *
- * dst - pointer to pgd range anwhere on a pgd page
- * src - ""
- * count - the number of pgds to copy.
- *
- * dst and src can be on the same page, but the range must not overlap,
- * and must not cross a page boundary.
- */
-static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
-{
- memcpy(dst, src, count * sizeof(pgd_t));
-}
-
-/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h
index 53ec34884744..9f98529761fd 100644
--- a/arch/tile/include/asm/pgtable_32.h
+++ b/arch/tile/include/asm/pgtable_32.h
@@ -24,6 +24,7 @@
#define PGDIR_SIZE HV_PAGE_SIZE_LARGE
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
+#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t))
/*
* The level-2 index is defined by the difference between the huge
@@ -33,6 +34,7 @@
* this nomenclature is somewhat confusing.
*/
#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
+#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
#ifndef __ASSEMBLY__
@@ -94,7 +96,6 @@ static inline int pgd_addr_invalid(unsigned long addr)
*/
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
extern int ptep_test_and_clear_young(struct vm_area_struct *,
unsigned long addr, pte_t *);
@@ -110,6 +111,11 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
return pte;
}
+static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ set_pte(&pmdp->pud.pgd, pmdval.pud.pgd);
+}
+
/* Create a pmd from a PTFN. */
static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot)
{
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index a9e7c8760334..e6889474038a 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -269,7 +269,6 @@ extern char chip_model[64];
/* Data on which physical memory controller corresponds to which NUMA node. */
extern int node_controller[];
-
/* Do we dump information to the console when a user application crashes? */
extern int show_crashinfo;
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h
index ac6d343129d3..6be2246e015c 100644
--- a/arch/tile/include/asm/ptrace.h
+++ b/arch/tile/include/asm/ptrace.h
@@ -141,6 +141,9 @@ struct single_step_state {
/* Single-step the instruction at regs->pc */
extern void single_step_once(struct pt_regs *regs);
+/* Clean up after execve(). */
+extern void single_step_execve(void);
+
struct task_struct;
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index 88efdde8dd2b..a8f2c6e31a87 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -78,13 +78,6 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock);
#define _RD_COUNT_SHIFT 24
#define _RD_COUNT_WIDTH 8
-/* Internal functions; do not use. */
-void arch_read_lock_slow(arch_rwlock_t *, u32);
-int arch_read_trylock_slow(arch_rwlock_t *);
-void arch_read_unlock_slow(arch_rwlock_t *);
-void arch_write_lock_slow(arch_rwlock_t *, u32);
-void arch_write_unlock_slow(arch_rwlock_t *, u32);
-
/**
* arch_read_can_lock() - would read_trylock() succeed?
*/
@@ -104,94 +97,32 @@ static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
/**
* arch_read_lock() - acquire a read lock.
*/
-static inline void arch_read_lock(arch_rwlock_t *rwlock)
-{
- u32 val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val << _RD_COUNT_WIDTH)) {
- arch_read_lock_slow(rwlock, val);
- return;
- }
- rwlock->lock = val + (1 << _RD_COUNT_SHIFT);
-}
+void arch_read_lock(arch_rwlock_t *rwlock);
/**
- * arch_read_lock() - acquire a write lock.
+ * arch_write_lock() - acquire a write lock.
*/
-static inline void arch_write_lock(arch_rwlock_t *rwlock)
-{
- u32 val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val != 0)) {
- arch_write_lock_slow(rwlock, val);
- return;
- }
- rwlock->lock = 1 << _WR_NEXT_SHIFT;
-}
+void arch_write_lock(arch_rwlock_t *rwlock);
/**
* arch_read_trylock() - try to acquire a read lock.
*/
-static inline int arch_read_trylock(arch_rwlock_t *rwlock)
-{
- int locked;
- u32 val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val & 1))
- return arch_read_trylock_slow(rwlock);
- locked = (val << _RD_COUNT_WIDTH) == 0;
- rwlock->lock = val + (locked << _RD_COUNT_SHIFT);
- return locked;
-}
+int arch_read_trylock(arch_rwlock_t *rwlock);
/**
* arch_write_trylock() - try to acquire a write lock.
*/
-static inline int arch_write_trylock(arch_rwlock_t *rwlock)
-{
- u32 val = __insn_tns((int *)&rwlock->lock);
-
- /*
- * If a tns is in progress, or there's a waiting or active locker,
- * or active readers, we can't take the lock, so give up.
- */
- if (unlikely(val != 0)) {
- if (!(val & 1))
- rwlock->lock = val;
- return 0;
- }
-
- /* Set the "next" field to mark it locked. */
- rwlock->lock = 1 << _WR_NEXT_SHIFT;
- return 1;
-}
+int arch_write_trylock(arch_rwlock_t *rwlock);
/**
* arch_read_unlock() - release a read lock.
*/
-static inline void arch_read_unlock(arch_rwlock_t *rwlock)
-{
- u32 val;
- mb(); /* guarantee anything modified under the lock is visible */
- val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val & 1)) {
- arch_read_unlock_slow(rwlock);
- return;
- }
- rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
-}
+void arch_read_unlock(arch_rwlock_t *rwlock);
/**
* arch_write_unlock() - release a write lock.
*/
-static inline void arch_write_unlock(arch_rwlock_t *rwlock)
-{
- u32 val;
- mb(); /* guarantee anything modified under the lock is visible */
- val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val != (1 << _WR_NEXT_SHIFT))) {
- arch_write_unlock_slow(rwlock, val);
- return;
- }
- rwlock->lock = 0;
-}
+void arch_write_unlock(arch_rwlock_t *rwlock);
#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
diff --git a/arch/tile/include/asm/stack.h b/arch/tile/include/asm/stack.h
index f908473c322d..4d97a2db932e 100644
--- a/arch/tile/include/asm/stack.h
+++ b/arch/tile/include/asm/stack.h
@@ -18,13 +18,14 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <asm/backtrace.h>
+#include <asm/page.h>
#include <hv/hypervisor.h>
/* Everything we need to keep track of a backtrace iteration */
struct KBacktraceIterator {
BacktraceIterator it;
struct task_struct *task; /* task we are backtracing */
- HV_PTE *pgtable; /* page table for user space access */
+ pte_t *pgtable; /* page table for user space access */
int end; /* iteration complete. */
int new_context; /* new context is starting */
int profile; /* profiling, so stop on async intrpt */
diff --git a/arch/tile/include/asm/system.h b/arch/tile/include/asm/system.h
index 5388850deeb2..23d1842f4839 100644
--- a/arch/tile/include/asm/system.h
+++ b/arch/tile/include/asm/system.h
@@ -90,7 +90,24 @@
#endif
#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
-int __mb_incoherent(void); /* Helper routine for mb_incoherent(). */
+#include <hv/syscall_public.h>
+/*
+ * Issue an uncacheable load to each memory controller, then
+ * wait until those loads have completed.
+ */
+static inline void __mb_incoherent(void)
+{
+ long clobber_r10;
+ asm volatile("swint2"
+ : "=R10" (clobber_r10)
+ : "R10" (HV_SYS_fence_incoherent)
+ : "r0", "r1", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9",
+ "r11", "r12", "r13", "r14",
+ "r15", "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29");
+}
#endif
/* Fence to guarantee visibility of stores to incoherent memory. */
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
index 3872f2b345d2..9e8e9c4dfa2a 100644
--- a/arch/tile/include/asm/thread_info.h
+++ b/arch/tile/include/asm/thread_info.h
@@ -68,6 +68,7 @@ struct thread_info {
#else
#define THREAD_SIZE_ORDER (0)
#endif
+#define THREAD_SIZE_PAGES (1 << THREAD_SIZE_ORDER)
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
#define LOG2_THREAD_SIZE (PAGE_SHIFT + THREAD_SIZE_ORDER)
diff --git a/arch/tile/include/asm/timex.h b/arch/tile/include/asm/timex.h
index 3baf5fc4c0a1..29921f0b86da 100644
--- a/arch/tile/include/asm/timex.h
+++ b/arch/tile/include/asm/timex.h
@@ -38,6 +38,9 @@ static inline cycles_t get_cycles(void)
cycles_t get_clock_rate(void);
+/* Convert nanoseconds to core clock cycles. */
+cycles_t ns2cycles(unsigned long nsecs);
+
/* Called at cpu initialization to set some low-level constants. */
void setup_clock(void);
diff --git a/arch/tile/include/hv/drv_mshim_intf.h b/arch/tile/include/hv/drv_mshim_intf.h
new file mode 100644
index 000000000000..c6ef3bdc55cf
--- /dev/null
+++ b/arch/tile/include/hv/drv_mshim_intf.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file drv_mshim_intf.h
+ * Interface definitions for the Linux EDAC memory controller driver.
+ */
+
+#ifndef _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H
+#define _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H
+
+/** Number of memory controllers in the public API. */
+#define TILE_MAX_MSHIMS 4
+
+/** Memory info under each memory controller. */
+struct mshim_mem_info
+{
+ uint64_t mem_size; /**< Total memory size in bytes. */
+ uint8_t mem_type; /**< Memory type, DDR2 or DDR3. */
+ uint8_t mem_ecc; /**< Memory supports ECC. */
+};
+
+/**
+ * DIMM error structure.
+ * For now, only correctable errors are counted and the mshim doesn't record
+ * the error PA. HV takes panic upon uncorrectable errors.
+ */
+struct mshim_mem_error
+{
+ uint32_t sbe_count; /**< Number of single-bit errors. */
+};
+
+/** Read this offset to get the memory info per mshim. */
+#define MSHIM_MEM_INFO_OFF 0x100
+
+/** Read this offset to check DIMM error. */
+#define MSHIM_MEM_ERROR_OFF 0x200
+
+#endif /* _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H */
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index f672544cd4f9..1b8bf03d62a0 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -338,9 +338,10 @@ typedef int HV_Errno;
#define HV_ENOTREADY -812 /**< Device not ready */
#define HV_EIO -813 /**< I/O error */
#define HV_ENOMEM -814 /**< Out of memory */
+#define HV_EAGAIN -815 /**< Try again */
#define HV_ERR_MAX -801 /**< Largest HV error code */
-#define HV_ERR_MIN -814 /**< Smallest HV error code */
+#define HV_ERR_MIN -815 /**< Smallest HV error code */
#ifndef __ASSEMBLER__
@@ -867,6 +868,43 @@ typedef struct
*/
HV_PhysAddrRange hv_inquire_physical(int idx);
+/** Possible DIMM types. */
+typedef enum
+{
+ NO_DIMM = 0, /**< No DIMM */
+ DDR2 = 1, /**< DDR2 */
+ DDR3 = 2 /**< DDR3 */
+} HV_DIMM_Type;
+
+#ifdef __tilegx__
+
+/** Log2 of minimum DIMM bytes supported by the memory controller. */
+#define HV_MSH_MIN_DIMM_SIZE_SHIFT 29
+
+/** Max number of DIMMs contained by one memory controller. */
+#define HV_MSH_MAX_DIMMS 8
+
+#else
+
+/** Log2 of minimum DIMM bytes supported by the memory controller. */
+#define HV_MSH_MIN_DIMM_SIZE_SHIFT 26
+
+/** Max number of DIMMs contained by one memory controller. */
+#define HV_MSH_MAX_DIMMS 2
+
+#endif
+
+/** Number of bits to right-shift to get the DIMM type. */
+#define HV_DIMM_TYPE_SHIFT 0
+
+/** Bits to mask to get the DIMM type. */
+#define HV_DIMM_TYPE_MASK 0xf
+
+/** Number of bits to right-shift to get the DIMM size. */
+#define HV_DIMM_SIZE_SHIFT 4
+
+/** Bits to mask to get the DIMM size. */
+#define HV_DIMM_SIZE_MASK 0xf
/** Memory controller information. */
typedef struct
@@ -964,6 +1002,11 @@ HV_ASIDRange hv_inquire_asid(int idx);
/** Waits for at least the specified number of nanoseconds then returns.
*
+ * NOTE: this deprecated function currently assumes a 750 MHz clock,
+ * and is thus not generally suitable for use. New code should call
+ * hv_sysconf(HV_SYSCONF_CPU_SPEED), compute a cycle count to wait for,
+ * and delay by looping while checking the cycle counter SPR.
+ *
* @param nanosecs The number of nanoseconds to sleep.
*/
void hv_nanosleep(int nanosecs);
@@ -1038,6 +1081,7 @@ int hv_console_write(HV_VirtAddr bytes, int len);
* downcall:
*
* INT_MESSAGE_RCV_DWNCL (hypervisor message available)
+ * INT_DEV_INTR_DWNCL (device interrupt)
* INT_DMATLB_MISS_DWNCL (DMA TLB miss)
* INT_SNITLB_MISS_DWNCL (SNI TLB miss)
* INT_DMATLB_ACCESS_DWNCL (DMA TLB access violation)
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index fd8dc42abdcb..431e9ae60488 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -38,12 +38,6 @@ STD_ENTRY(kernel_execve)
jrp lr
STD_ENDPROC(kernel_execve)
-/* Delay a fixed number of cycles. */
-STD_ENTRY(__delay)
- { addi r0, r0, -1; bnzt r0, . }
- jrp lr
- STD_ENDPROC(__delay)
-
/*
* We don't run this function directly, but instead copy it to a page
* we map into every user process. See vdso_setup().
@@ -97,23 +91,17 @@ STD_ENTRY(smp_nap)
/*
* Enable interrupts racelessly and then nap until interrupted.
+ * Architecturally, we are guaranteed that enabling interrupts via
+ * mtspr to INTERRUPT_CRITICAL_SECTION only interrupts at the next PC.
* This function's _cpu_idle_nap address is special; see intvec.S.
* When interrupted at _cpu_idle_nap, we bump the PC forward 8, and
* as a result return to the function that called _cpu_idle().
*/
STD_ENTRY(_cpu_idle)
- {
- lnk r0
- movei r1, KERNEL_PL
- }
- {
- addli r0, r0, _cpu_idle_nap - .
- mtspr INTERRUPT_CRITICAL_SECTION, r1
- }
+ movei r1, 1
+ mtspr INTERRUPT_CRITICAL_SECTION, r1
IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */
- mtspr SPR_EX_CONTEXT_K_1, r1 /* Kernel PL, ICS clear */
- mtspr SPR_EX_CONTEXT_K_0, r0
- iret
+ mtspr INTERRUPT_CRITICAL_SECTION, zero
.global _cpu_idle_nap
_cpu_idle_nap:
nap
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S
index 90e7c4435693..1a39b7c1c87e 100644
--- a/arch/tile/kernel/head_32.S
+++ b/arch/tile/kernel/head_32.S
@@ -133,7 +133,7 @@ ENTRY(_start)
}
ENDPROC(_start)
-.section ".bss.page_aligned","w"
+__PAGE_ALIGNED_BSS
.align PAGE_SIZE
ENTRY(empty_zero_page)
.fill PAGE_SIZE,1,0
@@ -145,10 +145,10 @@ ENTRY(empty_zero_page)
.endif
.word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \
(HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
- .word (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
+ .word (\bits1) | (HV_CPA_TO_PFN(\cpa) << (HV_PTE_INDEX_PFN - 32))
.endm
-.section ".data.page_aligned","wa"
+__PAGE_ALIGNED_DATA
.align PAGE_SIZE
ENTRY(swapper_pg_dir)
/*
@@ -158,12 +158,14 @@ ENTRY(swapper_pg_dir)
*/
.set addr, 0
.rept (MEM_USER_INTRPT - PAGE_OFFSET) >> PGDIR_SHIFT
- PTE addr + PAGE_OFFSET, addr, HV_PTE_READABLE | HV_PTE_WRITABLE
+ PTE addr + PAGE_OFFSET, addr, (1 << (HV_PTE_INDEX_READABLE - 32)) | \
+ (1 << (HV_PTE_INDEX_WRITABLE - 32))
.set addr, addr + PGDIR_SIZE
.endr
/* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */
- PTE MEM_SV_INTRPT, 0, HV_PTE_READABLE | HV_PTE_EXECUTABLE
+ PTE MEM_SV_INTRPT, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \
+ (1 << (HV_PTE_INDEX_EXECUTABLE - 32))
.org swapper_pg_dir + HV_L1_SIZE
END(swapper_pg_dir)
@@ -176,6 +178,7 @@ ENTRY(swapper_pg_dir)
__INITDATA
.align CHIP_L2_LINE_SIZE()
ENTRY(swapper_pgprot)
- PTE 0, 0, HV_PTE_READABLE | HV_PTE_WRITABLE, 1
+ PTE 0, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \
+ (1 << (HV_PTE_INDEX_WRITABLE - 32)), 1
.align CHIP_L2_LINE_SIZE()
END(swapper_pgprot)
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index 5eed4a02bf62..fffcfa6b3a62 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -32,10 +32,6 @@
# error "No support for kernel preemption currently"
#endif
-#if INT_INTCTRL_K < 32 || INT_INTCTRL_K >= 48
-# error INT_INTCTRL_K coded to set high interrupt mask
-#endif
-
#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR)
@@ -1199,46 +1195,6 @@ STD_ENTRY(interrupt_return)
STD_ENDPROC(interrupt_return)
/*
- * This interrupt variant clears the INT_INTCTRL_K interrupt mask bit
- * before returning, so we can properly get more downcalls.
- */
- .pushsection .text.handle_interrupt_downcall,"ax"
-handle_interrupt_downcall:
- finish_interrupt_save handle_interrupt_downcall
- check_single_stepping normal, .Ldispatch_downcall
-.Ldispatch_downcall:
-
- /* Clear INTCTRL_K from the set of interrupts we ever enable. */
- GET_INTERRUPTS_ENABLED_MASK_PTR(r30)
- {
- addi r30, r30, 4
- movei r31, INT_MASK(INT_INTCTRL_K)
- }
- {
- lw r20, r30
- nor r21, r31, zero
- }
- and r20, r20, r21
- sw r30, r20
-
- {
- jalr r0
- PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
- }
- FEEDBACK_REENTER(handle_interrupt_downcall)
-
- /* Allow INTCTRL_K to be enabled next time we enable interrupts. */
- lw r20, r30
- or r20, r20, r31
- sw r30, r20
-
- {
- movei r30, 0 /* not an NMI */
- j interrupt_return
- }
- STD_ENDPROC(handle_interrupt_downcall)
-
- /*
* Some interrupts don't check for single stepping
*/
.pushsection .text.handle_interrupt_no_single_step,"ax"
@@ -1600,7 +1556,10 @@ STD_ENTRY(_sys_clone)
.align 64
/* Align much later jump on the start of a cache line. */
#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
- nop; nop
+ nop
+#if PAGE_SIZE >= 0x10000
+ nop
+#endif
#endif
ENTRY(sys_cmpxchg)
@@ -1628,9 +1587,13 @@ ENTRY(sys_cmpxchg)
* about aliasing among multiple mappings of the same physical page,
* and we ignore the low 3 bits so we have one lock that covers
* both a cmpxchg64() and a cmpxchg() on either its low or high word.
- * NOTE: this code must match __atomic_hashed_lock() in lib/atomic.c.
+ * NOTE: this must match __atomic_hashed_lock() in lib/atomic_32.c.
*/
+#if (PAGE_OFFSET & 0xffff) != 0
+# error Code here assumes PAGE_OFFSET can be loaded with just hi16()
+#endif
+
#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
{
/* Check for unaligned input. */
@@ -1723,11 +1686,14 @@ ENTRY(sys_cmpxchg)
lw r26, r0
}
{
- /* atomic_locks is page aligned so this suffices to get its addr. */
- auli r21, zero, hi16(atomic_locks)
+ auli r21, zero, ha16(atomic_locks)
bbns r23, .Lcmpxchg_badaddr
}
+#if PAGE_SIZE < 0x10000
+ /* atomic_locks is page-aligned so for big pages we don't need this. */
+ addli r21, r21, lo16(atomic_locks)
+#endif
{
/*
* Insert the hash bits into the page-aligned pointer.
@@ -1762,7 +1728,7 @@ ENTRY(sys_cmpxchg)
/*
* Perform the actual cmpxchg or atomic_update.
- * Note that __futex_mark_unlocked() in uClibc relies on
+ * Note that the system <arch/atomic.h> header relies on
* atomic_update() to always perform an "mf", so don't make
* it optional or conditional without modifying that code.
*/
@@ -2014,17 +1980,17 @@ int_unalign:
#endif
int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr
int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
- hv_message_intr, handle_interrupt_downcall
+ hv_message_intr
int_hand INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, \
- tile_dev_intr, handle_interrupt_downcall
+ tile_dev_intr
int_hand INT_I_ASID, I_ASID, bad_intr
int_hand INT_D_ASID, D_ASID, bad_intr
int_hand INT_DMATLB_MISS_DWNCL, DMATLB_MISS_DWNCL, \
- do_page_fault, handle_interrupt_downcall
+ do_page_fault
int_hand INT_SNITLB_MISS_DWNCL, SNITLB_MISS_DWNCL, \
- do_page_fault, handle_interrupt_downcall
+ do_page_fault
int_hand INT_DMATLB_ACCESS_DWNCL, DMATLB_ACCESS_DWNCL, \
- do_page_fault, handle_interrupt_downcall
+ do_page_fault
int_hand INT_SN_CPL, SN_CPL, bad_intr
int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap
#if CHIP_HAS_AUX_PERF_COUNTERS()
diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c
index 128805ef8f2c..0baa7580121f 100644
--- a/arch/tile/kernel/irq.c
+++ b/arch/tile/kernel/irq.c
@@ -176,43 +176,43 @@ void disable_percpu_irq(unsigned int irq)
EXPORT_SYMBOL(disable_percpu_irq);
/* Mask an interrupt. */
-static void tile_irq_chip_mask(unsigned int irq)
+static void tile_irq_chip_mask(struct irq_data *d)
{
- mask_irqs(1UL << irq);
+ mask_irqs(1UL << d->irq);
}
/* Unmask an interrupt. */
-static void tile_irq_chip_unmask(unsigned int irq)
+static void tile_irq_chip_unmask(struct irq_data *d)
{
- unmask_irqs(1UL << irq);
+ unmask_irqs(1UL << d->irq);
}
/*
* Clear an interrupt before processing it so that any new assertions
* will trigger another irq.
*/
-static void tile_irq_chip_ack(unsigned int irq)
+static void tile_irq_chip_ack(struct irq_data *d)
{
- if ((unsigned long)get_irq_chip_data(irq) != IS_HW_CLEARED)
- clear_irqs(1UL << irq);
+ if ((unsigned long)irq_data_get_irq_chip_data(d) != IS_HW_CLEARED)
+ clear_irqs(1UL << d->irq);
}
/*
* For per-cpu interrupts, we need to avoid unmasking any interrupts
* that we disabled via disable_percpu_irq().
*/
-static void tile_irq_chip_eoi(unsigned int irq)
+static void tile_irq_chip_eoi(struct irq_data *d)
{
- if (!(__get_cpu_var(irq_disable_mask) & (1UL << irq)))
- unmask_irqs(1UL << irq);
+ if (!(__get_cpu_var(irq_disable_mask) & (1UL << d->irq)))
+ unmask_irqs(1UL << d->irq);
}
static struct irq_chip tile_irq_chip = {
.name = "tile_irq_chip",
- .ack = tile_irq_chip_ack,
- .eoi = tile_irq_chip_eoi,
- .mask = tile_irq_chip_mask,
- .unmask = tile_irq_chip_unmask,
+ .irq_ack = tile_irq_chip_ack,
+ .irq_eoi = tile_irq_chip_eoi,
+ .irq_mask = tile_irq_chip_mask,
+ .irq_unmask = tile_irq_chip_unmask,
};
void __init init_IRQ(void)
@@ -277,8 +277,10 @@ int show_interrupts(struct seq_file *p, void *v)
}
if (i < NR_IRQS) {
- raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
- action = irq_desc[i].action;
+ struct irq_desc *desc = irq_to_desc(i);
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ action = desc->action;
if (!action)
goto skip;
seq_printf(p, "%3d: ", i);
@@ -288,7 +290,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, " %14s", get_irq_desc_chip(desc)->name);
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
@@ -296,7 +298,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
skip:
- raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
}
return 0;
}
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
index 0d8b9e933487..e00d7179989e 100644
--- a/arch/tile/kernel/machine_kexec.c
+++ b/arch/tile/kernel/machine_kexec.c
@@ -240,8 +240,11 @@ static void setup_quasi_va_is_pa(void)
pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE);
pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
- for (i = 0; i < pgd_index(PAGE_OFFSET); i++)
- pgtable[i] = pfn_pte(i << (HPAGE_SHIFT - PAGE_SHIFT), pte);
+ for (i = 0; i < pgd_index(PAGE_OFFSET); i++) {
+ unsigned long pfn = i << (HPAGE_SHIFT - PAGE_SHIFT);
+ if (pfn_valid(pfn))
+ __set_pte(&pgtable[i], pfn_pte(pfn, pte));
+ }
}
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
index 5ad5e13b0fa6..658752b2835e 100644
--- a/arch/tile/kernel/pci-dma.c
+++ b/arch/tile/kernel/pci-dma.c
@@ -86,6 +86,21 @@ EXPORT_SYMBOL(dma_free_coherent);
* can count on nothing having been touched.
*/
+/* Flush a PA range from cache page by page. */
+static void __dma_map_pa_range(dma_addr_t dma_addr, size_t size)
+{
+ struct page *page = pfn_to_page(PFN_DOWN(dma_addr));
+ size_t bytesleft = PAGE_SIZE - (dma_addr & (PAGE_SIZE - 1));
+
+ while ((ssize_t)size > 0) {
+ /* Flush the page. */
+ homecache_flush_cache(page++, 0);
+
+ /* Figure out if we need to continue on the next page. */
+ size -= bytesleft;
+ bytesleft = PAGE_SIZE;
+ }
+}
/*
* dma_map_single can be passed any memory address, and there appear
@@ -97,26 +112,12 @@ EXPORT_SYMBOL(dma_free_coherent);
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- struct page *page;
- dma_addr_t dma_addr;
- int thispage;
+ dma_addr_t dma_addr = __pa(ptr);
BUG_ON(!valid_dma_direction(direction));
WARN_ON(size == 0);
- dma_addr = __pa(ptr);
-
- /* We might have been handed a buffer that wraps a page boundary */
- while ((int)size > 0) {
- /* The amount to flush that's on this page */
- thispage = PAGE_SIZE - ((unsigned long)ptr & (PAGE_SIZE - 1));
- thispage = min((int)thispage, (int)size);
- /* Is this valid for any page we could be handed? */
- page = pfn_to_page(kaddr_to_pfn(ptr));
- homecache_flush_cache(page, 0);
- ptr += thispage;
- size -= thispage;
- }
+ __dma_map_pa_range(dma_addr, size);
return dma_addr;
}
@@ -140,10 +141,8 @@ int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
WARN_ON(nents == 0 || sglist->length == 0);
for_each_sg(sglist, sg, nents, i) {
- struct page *page;
sg->dma_address = sg_phys(sg);
- page = pfn_to_page(sg->dma_address >> PAGE_SHIFT);
- homecache_flush_cache(page, 0);
+ __dma_map_pa_range(sg->dma_address, sg->length);
}
return nents;
@@ -163,6 +162,7 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
{
BUG_ON(!valid_dma_direction(direction));
+ BUG_ON(offset + size > PAGE_SIZE);
homecache_flush_cache(page, 0);
return page_to_pa(page) + offset;
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index e90eb53173b0..b9cd962e1d30 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -165,7 +165,7 @@ void free_thread_info(struct thread_info *info)
kfree(step_state);
}
- free_page((unsigned long)info);
+ free_pages((unsigned long)info, THREAD_SIZE_ORDER);
}
static void save_arch_state(struct thread_struct *t);
@@ -574,6 +574,8 @@ SYSCALL_DEFINE4(execve, const char __user *, path,
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
+ if (error == 0)
+ single_step_execve();
out:
return error;
}
@@ -593,6 +595,8 @@ long compat_sys_execve(const char __user *path,
goto out;
error = compat_do_execve(filename, argv, envp, regs);
putname(filename);
+ if (error == 0)
+ single_step_execve();
out:
return error;
}
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index f18573643ed1..3696b1832566 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -59,6 +59,8 @@ unsigned long __initdata node_memmap_pfn[MAX_NUMNODES];
unsigned long __initdata node_percpu_pfn[MAX_NUMNODES];
unsigned long __initdata node_free_pfn[MAX_NUMNODES];
+static unsigned long __initdata node_percpu[MAX_NUMNODES];
+
#ifdef CONFIG_HIGHMEM
/* Page frame index of end of lowmem on each controller. */
unsigned long __cpuinitdata node_lowmem_end_pfn[MAX_NUMNODES];
@@ -554,7 +556,6 @@ static void __init setup_bootmem_allocator(void)
reserve_bootmem(crashk_res.start,
crashk_res.end - crashk_res.start + 1, 0);
#endif
-
}
void *__init alloc_remap(int nid, unsigned long size)
@@ -568,11 +569,13 @@ void *__init alloc_remap(int nid, unsigned long size)
static int __init percpu_size(void)
{
- int size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
-#ifdef CONFIG_MODULES
- if (size < PERCPU_ENOUGH_ROOM)
- size = PERCPU_ENOUGH_ROOM;
-#endif
+ int size = __per_cpu_end - __per_cpu_start;
+ size += PERCPU_MODULE_RESERVE;
+ size += PERCPU_DYNAMIC_EARLY_SIZE;
+ if (size < PCPU_MIN_UNIT_SIZE)
+ size = PCPU_MIN_UNIT_SIZE;
+ size = roundup(size, PAGE_SIZE);
+
/* In several places we assume the per-cpu data fits on a huge page. */
BUG_ON(kdata_huge && size > HPAGE_SIZE);
return size;
@@ -589,7 +592,6 @@ static inline unsigned long alloc_bootmem_pfn(int size, unsigned long goal)
static void __init zone_sizes_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = { 0 };
- unsigned long node_percpu[MAX_NUMNODES] = { 0 };
int size = percpu_size();
int num_cpus = smp_height * smp_width;
int i;
@@ -674,7 +676,7 @@ static void __init zone_sizes_init(void)
NODE_DATA(i)->bdata = NODE_DATA(0)->bdata;
free_area_init_node(i, zones_size, start, NULL);
- printk(KERN_DEBUG " DMA zone: %ld per-cpu pages\n",
+ printk(KERN_DEBUG " Normal zone: %ld per-cpu pages\n",
PFN_UP(node_percpu[i]));
/* Track the type of memory on each node */
@@ -1312,6 +1314,8 @@ static void *__init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
BUG_ON(size % PAGE_SIZE != 0);
pfn_offset[nid] += size / PAGE_SIZE;
+ BUG_ON(node_percpu[nid] < size);
+ node_percpu[nid] -= size;
if (percpu_pfn[cpu] == 0)
percpu_pfn[cpu] = pfn;
return pfn_to_kaddr(pfn);
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 1eb3b39e36c7..84a729e06ec4 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -56,7 +56,7 @@ enum mem_op {
MEMOP_STORE_POSTINCR
};
-static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, int32_t offset)
+static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, s32 offset)
{
tile_bundle_bits result;
@@ -254,6 +254,18 @@ P("\n");
return bundle;
}
+/*
+ * Called after execve() has started the new image. This allows us
+ * to reset the info state. Note that the the mmap'ed memory, if there
+ * was any, has already been unmapped by the exec.
+ */
+void single_step_execve(void)
+{
+ struct thread_info *ti = current_thread_info();
+ kfree(ti->step_state);
+ ti->step_state = NULL;
+}
+
/**
* single_step_once() - entry point when single stepping has been triggered.
* @regs: The machine register state
@@ -373,7 +385,7 @@ void single_step_once(struct pt_regs *regs)
/* branches */
case BRANCH_OPCODE_X1:
{
- int32_t offset = signExtend17(get_BrOff_X1(bundle));
+ s32 offset = signExtend17(get_BrOff_X1(bundle));
/*
* For branches, we use a rewriting trick to let the
@@ -731,4 +743,9 @@ void single_step_once(struct pt_regs *regs)
__insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL);
}
+void single_step_execve(void)
+{
+ /* Nothing */
+}
+
#endif /* !__tilegx__ */
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index 9575b37a8b75..a4293102ef81 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -36,6 +36,22 @@ static unsigned long __iomem *ipi_mappings[NR_CPUS];
/* Set by smp_send_stop() to avoid recursive panics. */
static int stopping_cpus;
+static void __send_IPI_many(HV_Recipient *recip, int nrecip, int tag)
+{
+ int sent = 0;
+ while (sent < nrecip) {
+ int rc = hv_send_message(recip, nrecip,
+ (HV_VirtAddr)&tag, sizeof(tag));
+ if (rc < 0) {
+ if (!stopping_cpus) /* avoid recursive panic */
+ panic("hv_send_message returned %d", rc);
+ break;
+ }
+ WARN_ONCE(rc == 0, "hv_send_message() returned zero\n");
+ sent += rc;
+ }
+}
+
void send_IPI_single(int cpu, int tag)
{
HV_Recipient recip = {
@@ -43,14 +59,13 @@ void send_IPI_single(int cpu, int tag)
.x = cpu % smp_width,
.state = HV_TO_BE_SENT
};
- int rc = hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag));
- BUG_ON(rc <= 0);
+ __send_IPI_many(&recip, 1, tag);
}
void send_IPI_many(const struct cpumask *mask, int tag)
{
HV_Recipient recip[NR_CPUS];
- int cpu, sent;
+ int cpu;
int nrecip = 0;
int my_cpu = smp_processor_id();
for_each_cpu(cpu, mask) {
@@ -61,17 +76,7 @@ void send_IPI_many(const struct cpumask *mask, int tag)
r->x = cpu % smp_width;
r->state = HV_TO_BE_SENT;
}
- sent = 0;
- while (sent < nrecip) {
- int rc = hv_send_message(recip, nrecip,
- (HV_VirtAddr)&tag, sizeof(tag));
- if (rc <= 0) {
- if (!stopping_cpus) /* avoid recursive panic */
- panic("hv_send_message returned %d", rc);
- break;
- }
- sent += rc;
- }
+ __send_IPI_many(recip, nrecip, tag);
}
void send_IPI_allbutself(int tag)
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index 0d54106be3d6..dd81713a90dc 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -44,13 +44,6 @@ static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
return sp >= kstack_base && sp < kstack_base + THREAD_SIZE;
}
-/* Is address in the specified kernel code? */
-static int in_kernel_text(VirtualAddress address)
-{
- return (address >= MEM_SV_INTRPT &&
- address < MEM_SV_INTRPT + HPAGE_SIZE);
-}
-
/* Is address valid for reading? */
static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
{
@@ -63,6 +56,23 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
if (l1_pgtable == NULL)
return 0; /* can't read user space in other tasks */
+#ifdef CONFIG_64BIT
+ /* Find the real l1_pgtable by looking in the l0_pgtable. */
+ pte = l1_pgtable[HV_L0_INDEX(address)];
+ if (!hv_pte_get_present(pte))
+ return 0;
+ pfn = hv_pte_get_pfn(pte);
+ if (pte_huge(pte)) {
+ if (!pfn_valid(pfn)) {
+ pr_err("L0 huge page has bad pfn %#lx\n", pfn);
+ return 0;
+ }
+ return hv_pte_get_present(pte) && hv_pte_get_readable(pte);
+ }
+ page = pfn_to_page(pfn);
+ BUG_ON(PageHighMem(page)); /* No HIGHMEM on 64-bit. */
+ l1_pgtable = (HV_PTE *)pfn_to_kaddr(pfn);
+#endif
pte = l1_pgtable[HV_L1_INDEX(address)];
if (!hv_pte_get_present(pte))
return 0;
@@ -92,7 +102,7 @@ static bool read_memory_func(void *result, VirtualAddress address,
{
int retval;
struct KBacktraceIterator *kbt = (struct KBacktraceIterator *)vkbt;
- if (in_kernel_text(address)) {
+ if (__kernel_text_address(address)) {
/* OK to read kernel code. */
} else if (address >= PAGE_OFFSET) {
/* We only tolerate kernel-space reads of this task's stack */
@@ -132,7 +142,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
}
}
if (EX1_PL(p->ex1) == KERNEL_PL &&
- in_kernel_text(p->pc) &&
+ __kernel_text_address(p->pc) &&
in_kernel_stack(kbt, p->sp) &&
p->sp >= sp) {
if (kbt->verbose)
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
index f2e156e44692..49a605be94c5 100644
--- a/arch/tile/kernel/time.c
+++ b/arch/tile/kernel/time.c
@@ -224,3 +224,13 @@ int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
}
+
+/*
+ * Use the tile timer to convert nsecs to core clock cycles, relying
+ * on it having the same frequency as SPR_CYCLE.
+ */
+cycles_t ns2cycles(unsigned long nsecs)
+{
+ struct clock_event_device *dev = &__get_cpu_var(tile_timer);
+ return ((u64)nsecs * dev->mult) >> dev->shift;
+}
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
index c6ce378e0678..38f64fafdc10 100644
--- a/arch/tile/kernel/vmlinux.lds.S
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -59,10 +59,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_sinitdata) = .;
- .init.page : AT (ADDR(.init.page) - LOAD_OFFSET) {
- *(.init.page)
- } :data =0
- INIT_DATA_SECTION(16)
+ INIT_DATA_SECTION(16) :data =0
PERCPU(L2_CACHE_BYTES, PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_einitdata) = .;
diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile
index 93122d5b1558..0c26086ecbef 100644
--- a/arch/tile/lib/Makefile
+++ b/arch/tile/lib/Makefile
@@ -2,9 +2,8 @@
# Makefile for TILE-specific library files..
#
-lib-y = cacheflush.o checksum.o cpumask.o delay.o \
- mb_incoherent.o uaccess.o memmove.o \
- memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
+lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \
+ memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
strchr_$(BITS).o strlen_$(BITS).o
ifeq ($(CONFIG_TILEGX),y)
diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c
index 7a5cc706ab62..f02040d3614e 100644
--- a/arch/tile/lib/atomic_32.c
+++ b/arch/tile/lib/atomic_32.c
@@ -46,14 +46,13 @@ struct atomic_locks_on_cpu *atomic_lock_ptr[ATOMIC_HASH_L1_SIZE]
#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
/* This page is remapped on startup to be hash-for-home. */
-int atomic_locks[PAGE_SIZE / sizeof(int) /* Only ATOMIC_HASH_SIZE is used */]
- __attribute__((aligned(PAGE_SIZE), section(".bss.page_aligned")));
+int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss;
#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
static inline int *__atomic_hashed_lock(volatile void *v)
{
- /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec.S */
+ /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */
#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
unsigned long i =
(unsigned long) v & ((PAGE_SIZE-1) & -sizeof(long long));
diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S
index 5a5514b77e78..82f64cc63658 100644
--- a/arch/tile/lib/atomic_asm_32.S
+++ b/arch/tile/lib/atomic_asm_32.S
@@ -14,7 +14,7 @@
* Support routines for atomic operations. Each function takes:
*
* r0: address to manipulate
- * r1: pointer to atomic lock guarding this operation (for FUTEX_LOCK_REG)
+ * r1: pointer to atomic lock guarding this operation (for ATOMIC_LOCK_REG)
* r2: new value to write, or for cmpxchg/add_unless, value to compare against
* r3: (cmpxchg/xchg_add_unless) new value to write or add;
* (atomic64 ops) high word of value to write
diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c
index 11b6164c2097..35c1d8ca5f38 100644
--- a/arch/tile/lib/cacheflush.c
+++ b/arch/tile/lib/cacheflush.c
@@ -21,3 +21,105 @@ void __flush_icache_range(unsigned long start, unsigned long end)
{
invalidate_icache((const void *)start, end - start, PAGE_SIZE);
}
+
+
+/* Force a load instruction to issue. */
+static inline void force_load(char *p)
+{
+ *(volatile char *)p;
+}
+
+/*
+ * Flush and invalidate a VA range that is homed remotely on a single
+ * core (if "!hfh") or homed via hash-for-home (if "hfh"), waiting
+ * until the memory controller holds the flushed values.
+ */
+void finv_buffer_remote(void *buffer, size_t size, int hfh)
+{
+ char *p, *base;
+ size_t step_size, load_count;
+ const unsigned long STRIPE_WIDTH = 8192;
+
+ /*
+ * Flush and invalidate the buffer out of the local L1/L2
+ * and request the home cache to flush and invalidate as well.
+ */
+ __finv_buffer(buffer, size);
+
+ /*
+ * Wait for the home cache to acknowledge that it has processed
+ * all the flush-and-invalidate requests. This does not mean
+ * that the flushed data has reached the memory controller yet,
+ * but it does mean the home cache is processing the flushes.
+ */
+ __insn_mf();
+
+ /*
+ * Issue a load to the last cache line, which can't complete
+ * until all the previously-issued flushes to the same memory
+ * controller have also completed. If we weren't striping
+ * memory, that one load would be sufficient, but since we may
+ * be, we also need to back up to the last load issued to
+ * another memory controller, which would be the point where
+ * we crossed an 8KB boundary (the granularity of striping
+ * across memory controllers). Keep backing up and doing this
+ * until we are before the beginning of the buffer, or have
+ * hit all the controllers.
+ *
+ * If we are flushing a hash-for-home buffer, it's even worse.
+ * Each line may be homed on a different tile, and each tile
+ * may have up to four lines that are on different
+ * controllers. So as we walk backwards, we have to touch
+ * enough cache lines to satisfy these constraints. In
+ * practice this ends up being close enough to "load from
+ * every cache line on a full memory stripe on each
+ * controller" that we simply do that, to simplify the logic.
+ *
+ * FIXME: See bug 9535 for some issues with this code.
+ */
+ if (hfh) {
+ step_size = L2_CACHE_BYTES;
+ load_count = (STRIPE_WIDTH / L2_CACHE_BYTES) *
+ (1 << CHIP_LOG_NUM_MSHIMS());
+ } else {
+ step_size = STRIPE_WIDTH;
+ load_count = (1 << CHIP_LOG_NUM_MSHIMS());
+ }
+
+ /* Load the last byte of the buffer. */
+ p = (char *)buffer + size - 1;
+ force_load(p);
+
+ /* Bump down to the end of the previous stripe or cache line. */
+ p -= step_size;
+ p = (char *)((unsigned long)p | (step_size - 1));
+
+ /* Figure out how far back we need to go. */
+ base = p - (step_size * (load_count - 2));
+ if ((long)base < (long)buffer)
+ base = buffer;
+
+ /*
+ * Fire all the loads we need. The MAF only has eight entries
+ * so we can have at most eight outstanding loads, so we
+ * unroll by that amount.
+ */
+#pragma unroll 8
+ for (; p >= base; p -= step_size)
+ force_load(p);
+
+ /*
+ * Repeat, but with inv's instead of loads, to get rid of the
+ * data we just loaded into our own cache and the old home L3.
+ * No need to unroll since inv's don't target a register.
+ */
+ p = (char *)buffer + size - 1;
+ __insn_inv(p);
+ p -= step_size;
+ p = (char *)((unsigned long)p | (step_size - 1));
+ for (; p >= base; p -= step_size)
+ __insn_inv(p);
+
+ /* Wait for the load+inv's (and thus finvs) to have completed. */
+ __insn_mf();
+}
diff --git a/arch/tile/lib/delay.c b/arch/tile/lib/delay.c
index 5801b03c13ef..cdacdd11d360 100644
--- a/arch/tile/lib/delay.c
+++ b/arch/tile/lib/delay.c
@@ -15,20 +15,31 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/thread_info.h>
-#include <asm/fixmap.h>
-#include <hv/hypervisor.h>
+#include <asm/timex.h>
void __udelay(unsigned long usecs)
{
- hv_nanosleep(usecs * 1000);
+ if (usecs > ULONG_MAX / 1000) {
+ WARN_ON_ONCE(usecs > ULONG_MAX / 1000);
+ usecs = ULONG_MAX / 1000;
+ }
+ __ndelay(usecs * 1000);
}
EXPORT_SYMBOL(__udelay);
void __ndelay(unsigned long nsecs)
{
- hv_nanosleep(nsecs);
+ cycles_t target = get_cycles();
+ target += ns2cycles(nsecs);
+ while (get_cycles() < target)
+ cpu_relax();
}
EXPORT_SYMBOL(__ndelay);
-/* FIXME: should be declared in a header somewhere. */
+void __delay(unsigned long cycles)
+{
+ cycles_t target = get_cycles() + cycles;
+ while (get_cycles() < target)
+ cpu_relax();
+}
EXPORT_SYMBOL(__delay);
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c
index 1509c5597653..49284fae9d09 100644
--- a/arch/tile/lib/exports.c
+++ b/arch/tile/lib/exports.c
@@ -29,6 +29,9 @@ EXPORT_SYMBOL(__put_user_8);
EXPORT_SYMBOL(strnlen_user_asm);
EXPORT_SYMBOL(strncpy_from_user_asm);
EXPORT_SYMBOL(clear_user_asm);
+EXPORT_SYMBOL(flush_user_asm);
+EXPORT_SYMBOL(inv_user_asm);
+EXPORT_SYMBOL(finv_user_asm);
/* arch/tile/kernel/entry.S */
#include <linux/kernel.h>
@@ -45,9 +48,6 @@ EXPORT_SYMBOL(__copy_from_user_zeroing);
EXPORT_SYMBOL(__copy_in_user_inatomic);
#endif
-/* arch/tile/lib/mb_incoherent.S */
-EXPORT_SYMBOL(__mb_incoherent);
-
/* hypervisor glue */
#include <hv/hypervisor.h>
EXPORT_SYMBOL(hv_dev_open);
@@ -85,4 +85,8 @@ int64_t __muldi3(int64_t, int64_t);
EXPORT_SYMBOL(__muldi3);
uint64_t __lshrdi3(uint64_t, unsigned int);
EXPORT_SYMBOL(__lshrdi3);
+uint64_t __ashrdi3(uint64_t, unsigned int);
+EXPORT_SYMBOL(__ashrdi3);
+uint64_t __ashldi3(uint64_t, unsigned int);
+EXPORT_SYMBOL(__ashldi3);
#endif
diff --git a/arch/tile/lib/mb_incoherent.S b/arch/tile/lib/mb_incoherent.S
deleted file mode 100644
index 989ad7b68d5a..000000000000
--- a/arch/tile/lib/mb_incoherent.S
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- *
- * Assembly code for invoking the HV's fence_incoherent syscall.
- */
-
-#include <linux/linkage.h>
-#include <hv/syscall_public.h>
-#include <arch/abi.h>
-#include <arch/chip.h>
-
-#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
-
-/*
- * Invoke the hypervisor's fence_incoherent syscall, which guarantees
- * that all victims for cachelines homed on this tile have reached memory.
- */
-STD_ENTRY(__mb_incoherent)
- moveli TREG_SYSCALL_NR_NAME, HV_SYS_fence_incoherent
- swint2
- jrp lr
- STD_ENDPROC(__mb_incoherent)
-
-#endif
diff --git a/arch/tile/lib/memcpy_tile64.c b/arch/tile/lib/memcpy_tile64.c
index f7d4a6ad61e8..b2fe15e01075 100644
--- a/arch/tile/lib/memcpy_tile64.c
+++ b/arch/tile/lib/memcpy_tile64.c
@@ -96,7 +96,7 @@ static void memcpy_multicache(void *dest, const void *source,
newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
pmdp = pmd_offset(pud_offset(pgd_offset_k(newsrc), newsrc), newsrc);
ptep = pte_offset_kernel(pmdp, newsrc);
- *ptep = src_pte; /* set_pte() would be confused by this */
+ __set_pte(ptep, src_pte); /* set_pte() would be confused by this */
local_flush_tlb_page(NULL, newsrc, PAGE_SIZE);
/* Actually move the data. */
@@ -109,7 +109,7 @@ static void memcpy_multicache(void *dest, const void *source,
*/
src_pte = hv_pte_set_mode(src_pte, HV_PTE_MODE_CACHE_NO_L3);
src_pte = hv_pte_set_writable(src_pte); /* need write access for inv */
- *ptep = src_pte; /* set_pte() would be confused by this */
+ __set_pte(ptep, src_pte); /* set_pte() would be confused by this */
local_flush_tlb_page(NULL, newsrc, PAGE_SIZE);
/*
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 5cd1c4004eca..cb0999fb64b4 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/module.h>
#include <asm/processor.h>
+#include <arch/spr_def.h>
#include "spinlock_common.h"
@@ -91,75 +92,75 @@ EXPORT_SYMBOL(arch_spin_unlock_wait);
#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1)
-/* Lock the word, spinning until there are no tns-ers. */
-static inline u32 get_rwlock(arch_rwlock_t *rwlock)
-{
- u32 iterations = 0;
- for (;;) {
- u32 val = __insn_tns((int *)&rwlock->lock);
- if (unlikely(val & 1)) {
- delay_backoff(iterations++);
- continue;
- }
- return val;
- }
-}
-
-int arch_read_trylock_slow(arch_rwlock_t *rwlock)
-{
- u32 val = get_rwlock(rwlock);
- int locked = (val << RD_COUNT_WIDTH) == 0;
- rwlock->lock = val + (locked << RD_COUNT_SHIFT);
- return locked;
-}
-EXPORT_SYMBOL(arch_read_trylock_slow);
-
-void arch_read_unlock_slow(arch_rwlock_t *rwlock)
-{
- u32 val = get_rwlock(rwlock);
- rwlock->lock = val - (1 << RD_COUNT_SHIFT);
-}
-EXPORT_SYMBOL(arch_read_unlock_slow);
-
-void arch_write_unlock_slow(arch_rwlock_t *rwlock, u32 val)
+/*
+ * We can get the read lock if everything but the reader bits (which
+ * are in the high part of the word) is zero, i.e. no active or
+ * waiting writers, no tns.
+ *
+ * We guard the tns/store-back with an interrupt critical section to
+ * preserve the semantic that the same read lock can be acquired in an
+ * interrupt context.
+ */
+inline int arch_read_trylock(arch_rwlock_t *rwlock)
{
- u32 eq, mask = 1 << WR_CURR_SHIFT;
- while (unlikely(val & 1)) {
- /* Limited backoff since we are the highest-priority task. */
- relax(4);
- val = __insn_tns((int *)&rwlock->lock);
+ u32 val;
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
+ val = __insn_tns((int *)&rwlock->lock);
+ if (likely((val << _RD_COUNT_WIDTH) == 0)) {
+ val += 1 << RD_COUNT_SHIFT;
+ rwlock->lock = val;
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+ BUG_ON(val == 0); /* we don't expect wraparound */
+ return 1;
}
- val = __insn_addb(val, mask);
- eq = __insn_seqb(val, val << (WR_CURR_SHIFT - WR_NEXT_SHIFT));
- val = __insn_mz(eq & mask, val);
- rwlock->lock = val;
+ if ((val & 1) == 0)
+ rwlock->lock = val;
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+ return 0;
}
-EXPORT_SYMBOL(arch_write_unlock_slow);
+EXPORT_SYMBOL(arch_read_trylock);
/*
- * We spin until everything but the reader bits (which are in the high
- * part of the word) are zero, i.e. no active or waiting writers, no tns.
- *
+ * Spin doing arch_read_trylock() until we acquire the lock.
* ISSUE: This approach can permanently starve readers. A reader who sees
* a writer could instead take a ticket lock (just like a writer would),
* and atomically enter read mode (with 1 reader) when it gets the ticket.
- * This way both readers and writers will always make forward progress
+ * This way both readers and writers would always make forward progress
* in a finite time.
*/
-void arch_read_lock_slow(arch_rwlock_t *rwlock, u32 val)
+void arch_read_lock(arch_rwlock_t *rwlock)
{
u32 iterations = 0;
- do {
- if (!(val & 1))
- rwlock->lock = val;
+ while (unlikely(!arch_read_trylock(rwlock)))
delay_backoff(iterations++);
+}
+EXPORT_SYMBOL(arch_read_lock);
+
+void arch_read_unlock(arch_rwlock_t *rwlock)
+{
+ u32 val, iterations = 0;
+
+ mb(); /* guarantee anything modified under the lock is visible */
+ for (;;) {
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
val = __insn_tns((int *)&rwlock->lock);
- } while ((val << RD_COUNT_WIDTH) != 0);
- rwlock->lock = val + (1 << RD_COUNT_SHIFT);
+ if (likely(val & 1) == 0) {
+ rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+ break;
+ }
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+ delay_backoff(iterations++);
+ }
}
-EXPORT_SYMBOL(arch_read_lock_slow);
+EXPORT_SYMBOL(arch_read_unlock);
-void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val)
+/*
+ * We don't need an interrupt critical section here (unlike for
+ * arch_read_lock) since we should never use a bare write lock where
+ * it could be interrupted by code that could try to re-acquire it.
+ */
+void arch_write_lock(arch_rwlock_t *rwlock)
{
/*
* The trailing underscore on this variable (and curr_ below)
@@ -168,6 +169,12 @@ void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val)
*/
u32 my_ticket_;
u32 iterations = 0;
+ u32 val = __insn_tns((int *)&rwlock->lock);
+
+ if (likely(val == 0)) {
+ rwlock->lock = 1 << _WR_NEXT_SHIFT;
+ return;
+ }
/*
* Wait until there are no readers, then bump up the next
@@ -206,23 +213,47 @@ void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val)
relax(4);
}
}
-EXPORT_SYMBOL(arch_write_lock_slow);
+EXPORT_SYMBOL(arch_write_lock);
-int __tns_atomic_acquire(atomic_t *lock)
+int arch_write_trylock(arch_rwlock_t *rwlock)
{
- int ret;
- u32 iterations = 0;
+ u32 val = __insn_tns((int *)&rwlock->lock);
- BUG_ON(__insn_mfspr(SPR_INTERRUPT_CRITICAL_SECTION));
- __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
+ /*
+ * If a tns is in progress, or there's a waiting or active locker,
+ * or active readers, we can't take the lock, so give up.
+ */
+ if (unlikely(val != 0)) {
+ if (!(val & 1))
+ rwlock->lock = val;
+ return 0;
+ }
- while ((ret = __insn_tns((void *)&lock->counter)) == 1)
- delay_backoff(iterations++);
- return ret;
+ /* Set the "next" field to mark it locked. */
+ rwlock->lock = 1 << _WR_NEXT_SHIFT;
+ return 1;
}
+EXPORT_SYMBOL(arch_write_trylock);
-void __tns_atomic_release(atomic_t *p, int v)
+void arch_write_unlock(arch_rwlock_t *rwlock)
{
- p->counter = v;
- __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+ u32 val, eq, mask;
+
+ mb(); /* guarantee anything modified under the lock is visible */
+ val = __insn_tns((int *)&rwlock->lock);
+ if (likely(val == (1 << _WR_NEXT_SHIFT))) {
+ rwlock->lock = 0;
+ return;
+ }
+ while (unlikely(val & 1)) {
+ /* Limited backoff since we are the highest-priority task. */
+ relax(4);
+ val = __insn_tns((int *)&rwlock->lock);
+ }
+ mask = 1 << WR_CURR_SHIFT;
+ val = __insn_addb(val, mask);
+ eq = __insn_seqb(val, val << (WR_CURR_SHIFT - WR_NEXT_SHIFT));
+ val = __insn_mz(eq & mask, val);
+ rwlock->lock = val;
}
+EXPORT_SYMBOL(arch_write_unlock);
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index dcebfc831cd6..758f597f488c 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -655,14 +655,6 @@ struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
}
/*
- * NOTE: the one other type of access that might bring us here
- * are the memory ops in __tns_atomic_acquire/__tns_atomic_release,
- * but we don't have to check specially for them since we can
- * always safely return to the address of the fault and retry,
- * since no separate atomic locks are involved.
- */
-
- /*
* Now that we have released the atomic lock (if necessary),
* it's safe to spin if the PTE that caused the fault was migrating.
*/
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index d78df3a6ee15..cbe6f4f9eca3 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
@@ -179,23 +179,46 @@ void flush_remote(unsigned long cache_pfn, unsigned long cache_control,
panic("Unsafe to continue.");
}
+void flush_remote_page(struct page *page, int order)
+{
+ int i, pages = (1 << order);
+ for (i = 0; i < pages; ++i, ++page) {
+ void *p = kmap_atomic(page);
+ int hfh = 0;
+ int home = page_home(page);
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (home == PAGE_HOME_HASH)
+ hfh = 1;
+ else
+#endif
+ BUG_ON(home < 0 || home >= NR_CPUS);
+ finv_buffer_remote(p, PAGE_SIZE, hfh);
+ kunmap_atomic(p);
+ }
+}
+
void homecache_evict(const struct cpumask *mask)
{
flush_remote(0, HV_FLUSH_EVICT_L2, mask, 0, 0, 0, NULL, NULL, 0);
}
-/* Return a mask of the cpus whose caches currently own these pages. */
-static void homecache_mask(struct page *page, int pages,
- struct cpumask *home_mask)
+/*
+ * Return a mask of the cpus whose caches currently own these pages.
+ * The return value is whether the pages are all coherently cached
+ * (i.e. none are immutable, incoherent, or uncached).
+ */
+static int homecache_mask(struct page *page, int pages,
+ struct cpumask *home_mask)
{
int i;
+ int cached_coherently = 1;
cpumask_clear(home_mask);
for (i = 0; i < pages; ++i) {
int home = page_home(&page[i]);
if (home == PAGE_HOME_IMMUTABLE ||
home == PAGE_HOME_INCOHERENT) {
cpumask_copy(home_mask, cpu_possible_mask);
- return;
+ return 0;
}
#if CHIP_HAS_CBOX_HOME_MAP()
if (home == PAGE_HOME_HASH) {
@@ -203,11 +226,14 @@ static void homecache_mask(struct page *page, int pages,
continue;
}
#endif
- if (home == PAGE_HOME_UNCACHED)
+ if (home == PAGE_HOME_UNCACHED) {
+ cached_coherently = 0;
continue;
+ }
BUG_ON(home < 0 || home >= NR_CPUS);
cpumask_set_cpu(home, home_mask);
}
+ return cached_coherently;
}
/*
@@ -386,7 +412,7 @@ void homecache_change_page_home(struct page *page, int order, int home)
pte_t *ptep = virt_to_pte(NULL, kva);
pte_t pteval = *ptep;
BUG_ON(!pte_present(pteval) || pte_huge(pteval));
- *ptep = pte_set_home(pteval, home);
+ __set_pte(ptep, pte_set_home(pteval, home));
}
}
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 0b9ce69b0ee5..d6e87fda2fb2 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -53,22 +53,11 @@
#include "migrate.h"
-/*
- * We could set FORCE_MAX_ZONEORDER to "(HPAGE_SHIFT - PAGE_SHIFT + 1)"
- * in the Tile Kconfig, but this generates configure warnings.
- * Do it here and force people to get it right to compile this file.
- * The problem is that with 4KB small pages and 16MB huge pages,
- * the default value doesn't allow us to group enough small pages
- * together to make up a huge page.
- */
-#if CONFIG_FORCE_MAX_ZONEORDER < HPAGE_SHIFT - PAGE_SHIFT + 1
-# error "Change FORCE_MAX_ZONEORDER in arch/tile/Kconfig to match page size"
-#endif
-
#define clear_pgd(pmdptr) (*(pmdptr) = hv_pte(0))
#ifndef __tilegx__
unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE;
+EXPORT_SYMBOL(VMALLOC_RESERVE);
#endif
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -445,7 +434,7 @@ static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
/* Temporary page table we use for staging. */
static pgd_t pgtables[PTRS_PER_PGD]
- __attribute__((section(".init.page")));
+ __attribute__((aligned(HV_PAGE_TABLE_ALIGN)));
/*
* This maps the physical memory to kernel virtual address space, a total
@@ -653,6 +642,17 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
memcpy(pgd_base, pgtables, sizeof(pgtables));
__install_page_table(pgd_base, __get_cpu_var(current_asid),
swapper_pgprot);
+
+ /*
+ * We just read swapper_pgprot and thus brought it into the cache,
+ * with its new home & caching mode. When we start the other CPUs,
+ * they're going to reference swapper_pgprot via their initial fake
+ * VA-is-PA mappings, which cache everything locally. At that
+ * time, if it's in our cache with a conflicting home, the
+ * simulator's coherence checker will complain. So, flush it out
+ * of our cache; we're not going to ever use it again anyway.
+ */
+ __insn_finv(&swapper_pgprot);
}
/*
@@ -950,11 +950,7 @@ struct kmem_cache *pgd_cache;
void __init pgtable_cache_init(void)
{
- pgd_cache = kmem_cache_create("pgd",
- PTRS_PER_PGD*sizeof(pgd_t),
- PTRS_PER_PGD*sizeof(pgd_t),
- 0,
- NULL);
+ pgd_cache = kmem_cache_create("pgd", SIZEOF_PGD, SIZEOF_PGD, 0, NULL);
if (!pgd_cache)
panic("pgtable_cache_init(): Cannot create pgd cache");
}
@@ -989,7 +985,7 @@ static long __write_once initfree = 1;
static int __init set_initfree(char *str)
{
long val;
- if (strict_strtol(str, 0, &val)) {
+ if (strict_strtol(str, 0, &val) == 0) {
initfree = val;
pr_info("initfree: %s free init pages\n",
initfree ? "will" : "won't");
diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S
index f738765cd1e6..ac01a7cdf77f 100644
--- a/arch/tile/mm/migrate_32.S
+++ b/arch/tile/mm/migrate_32.S
@@ -18,6 +18,7 @@
#include <linux/linkage.h>
#include <linux/threads.h>
#include <asm/page.h>
+#include <asm/thread_info.h>
#include <asm/types.h>
#include <asm/asm-offsets.h>
#include <hv/hypervisor.h>
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 1f5430c53d0d..1a2b36f8866d 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -142,6 +142,76 @@ pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
}
#endif
+/**
+ * shatter_huge_page() - ensure a given address is mapped by a small page.
+ *
+ * This function converts a huge PTE mapping kernel LOWMEM into a bunch
+ * of small PTEs with the same caching. No cache flush required, but we
+ * must do a global TLB flush.
+ *
+ * Any caller that wishes to modify a kernel mapping that might
+ * have been made with a huge page should call this function,
+ * since doing so properly avoids race conditions with installing the
+ * newly-shattered page and then flushing all the TLB entries.
+ *
+ * @addr: Address at which to shatter any existing huge page.
+ */
+void shatter_huge_page(unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned long flags = 0; /* happy compiler */
+#ifdef __PAGETABLE_PMD_FOLDED
+ struct list_head *pos;
+#endif
+
+ /* Get a pointer to the pmd entry that we need to change. */
+ addr &= HPAGE_MASK;
+ BUG_ON(pgd_addr_invalid(addr));
+ BUG_ON(addr < PAGE_OFFSET); /* only for kernel LOWMEM */
+ pgd = swapper_pg_dir + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ BUG_ON(!pud_present(*pud));
+ pmd = pmd_offset(pud, addr);
+ BUG_ON(!pmd_present(*pmd));
+ if (!pmd_huge_page(*pmd))
+ return;
+
+ /*
+ * Grab the pgd_lock, since we may need it to walk the pgd_list,
+ * and since we need some kind of lock here to avoid races.
+ */
+ spin_lock_irqsave(&pgd_lock, flags);
+ if (!pmd_huge_page(*pmd)) {
+ /* Lost the race to convert the huge page. */
+ spin_unlock_irqrestore(&pgd_lock, flags);
+ return;
+ }
+
+ /* Shatter the huge page into the preallocated L2 page table. */
+ pmd_populate_kernel(&init_mm, pmd,
+ get_prealloc_pte(pte_pfn(*(pte_t *)pmd)));
+
+#ifdef __PAGETABLE_PMD_FOLDED
+ /* Walk every pgd on the system and update the pmd there. */
+ list_for_each(pos, &pgd_list) {
+ pmd_t *copy_pmd;
+ pgd = list_to_pgd(pos) + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ copy_pmd = pmd_offset(pud, addr);
+ __set_pmd(copy_pmd, *pmd);
+ }
+#endif
+
+ /* Tell every cpu to notice the change. */
+ flush_remote(0, 0, NULL, addr, HPAGE_SIZE, HPAGE_SIZE,
+ cpu_possible_mask, NULL, 0);
+
+ /* Hold the lock until the TLB flush is finished to avoid races. */
+ spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
/*
* List of all pgd's needed so it can invalidate entries in both cached
* and uncached pgd's. This is essentially codepath-based locking
@@ -184,9 +254,9 @@ static void pgd_ctor(pgd_t *pgd)
BUG_ON(((u64 *)swapper_pg_dir)[pgd_index(MEM_USER_INTRPT)] != 0);
#endif
- clone_pgd_range(pgd + KERNEL_PGD_INDEX_START,
- swapper_pg_dir + KERNEL_PGD_INDEX_START,
- KERNEL_PGD_PTRS);
+ memcpy(pgd + KERNEL_PGD_INDEX_START,
+ swapper_pg_dir + KERNEL_PGD_INDEX_START,
+ KERNEL_PGD_PTRS * sizeof(pgd_t));
pgd_list_add(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
@@ -220,8 +290,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
- gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO|__GFP_COMP;
+ gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO;
struct page *p;
+#if L2_USER_PGTABLE_ORDER > 0
+ int i;
+#endif
#ifdef CONFIG_HIGHPTE
flags |= __GFP_HIGHMEM;
@@ -231,6 +304,18 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
if (p == NULL)
return NULL;
+#if L2_USER_PGTABLE_ORDER > 0
+ /*
+ * Make every page have a page_count() of one, not just the first.
+ * We don't use __GFP_COMP since it doesn't look like it works
+ * correctly with tlb_remove_page().
+ */
+ for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
+ init_page_count(p+i);
+ inc_zone_page_state(p+i, NR_PAGETABLE);
+ }
+#endif
+
pgtable_page_ctor(p);
return p;
}
@@ -242,8 +327,15 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
*/
void pte_free(struct mm_struct *mm, struct page *p)
{
+ int i;
+
pgtable_page_dtor(p);
- __free_pages(p, L2_USER_PGTABLE_ORDER);
+ __free_page(p);
+
+ for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
+ __free_page(p+i);
+ dec_zone_page_state(p+i, NR_PAGETABLE);
+ }
}
void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
@@ -252,18 +344,11 @@ void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
int i;
pgtable_page_dtor(pte);
- tlb->need_flush = 1;
- if (tlb_fast_mode(tlb)) {
- struct page *pte_pages[L2_USER_PGTABLE_PAGES];
- for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i)
- pte_pages[i] = pte + i;
- free_pages_and_swap_cache(pte_pages, L2_USER_PGTABLE_PAGES);
- return;
- }
- for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i) {
- tlb->pages[tlb->nr++] = pte + i;
- if (tlb->nr >= FREE_PTE_NR)
- tlb_flush_mmu(tlb, 0, 0);
+ tlb_remove_page(tlb, pte);
+
+ for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) {
+ tlb_remove_page(tlb, pte + i);
+ dec_zone_page_state(pte + i, NR_PAGETABLE);
}
}
@@ -346,35 +431,51 @@ int get_remote_cache_cpu(pgprot_t prot)
return x + y * smp_width;
}
-void set_pte_order(pte_t *ptep, pte_t pte, int order)
+/*
+ * Convert a kernel VA to a PA and homing information.
+ */
+int va_to_cpa_and_pte(void *va, unsigned long long *cpa, pte_t *pte)
{
- unsigned long pfn = pte_pfn(pte);
- struct page *page = pfn_to_page(pfn);
+ struct page *page = virt_to_page(va);
+ pte_t null_pte = { 0 };
- /* Update the home of a PTE if necessary */
- pte = pte_set_home(pte, page_home(page));
+ *cpa = __pa(va);
+ /* Note that this is not writing a page table, just returning a pte. */
+ *pte = pte_set_home(null_pte, page_home(page));
+
+ return 0; /* return non-zero if not hfh? */
+}
+EXPORT_SYMBOL(va_to_cpa_and_pte);
+
+void __set_pte(pte_t *ptep, pte_t pte)
+{
#ifdef __tilegx__
*ptep = pte;
#else
- /*
- * When setting a PTE, write the high bits first, then write
- * the low bits. This sets the "present" bit only after the
- * other bits are in place. If a particular PTE update
- * involves transitioning from one valid PTE to another, it
- * may be necessary to call set_pte_order() more than once,
- * transitioning via a suitable intermediate state.
- * Note that this sequence also means that if we are transitioning
- * from any migrating PTE to a non-migrating one, we will not
- * see a half-updated PTE with the migrating bit off.
- */
-#if HV_PTE_INDEX_PRESENT >= 32 || HV_PTE_INDEX_MIGRATING >= 32
-# error Must write the present and migrating bits last
-#endif
- ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32);
- barrier();
- ((u32 *)ptep)[0] = (u32)(pte_val(pte));
-#endif
+# if HV_PTE_INDEX_PRESENT >= 32 || HV_PTE_INDEX_MIGRATING >= 32
+# error Must write the present and migrating bits last
+# endif
+ if (pte_present(pte)) {
+ ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32);
+ barrier();
+ ((u32 *)ptep)[0] = (u32)(pte_val(pte));
+ } else {
+ ((u32 *)ptep)[0] = (u32)(pte_val(pte));
+ barrier();
+ ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32);
+ }
+#endif /* __tilegx__ */
+}
+
+void set_pte(pte_t *ptep, pte_t pte)
+{
+ struct page *page = pfn_to_page(pte_pfn(pte));
+
+ /* Update the home of a PTE if necessary */
+ pte = pte_set_home(pte, page_home(page));
+
+ __set_pte(ptep, pte);
}
/* Can this mm load a PTE with cached_priority set? */
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index ed47e6e1747f..d161e939df62 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -326,7 +326,7 @@ config X86_PPRO_FENCE
Old PentiumPro multiprocessor systems had errata that could cause
memory operations to violate the x86 ordering standard in rare cases.
Enabling this option will attempt to work around some (but not all)
- occurances of this problem, at the cost of much heavier spinlock and
+ occurrences of this problem, at the cost of much heavier spinlock and
memory barrier operations.
If unsure, say n here. Even distro kernels should think twice before
@@ -366,7 +366,7 @@ config X86_INTEL_USERCOPY
config X86_USE_PPRO_CHECKSUM
def_bool y
- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
+ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
config X86_USE_3DNOW
def_bool y
diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S
index 8fe2a4966b7a..adcf794b22e2 100644
--- a/arch/x86/crypto/aesni-intel_asm.S
+++ b/arch/x86/crypto/aesni-intel_asm.S
@@ -1346,7 +1346,7 @@ _zero_cipher_left_decrypt:
and $15, %r13 # %r13 = arg4 (mod 16)
je _multiple_of_16_bytes_decrypt
- # Handle the last <16 byte block seperately
+ # Handle the last <16 byte block separately
paddd ONE(%rip), %xmm0 # increment CNT to get Yn
movdqa SHUF_MASK(%rip), %xmm10
@@ -1355,7 +1355,7 @@ _zero_cipher_left_decrypt:
ENCRYPT_SINGLE_BLOCK %xmm0, %xmm1 # E(K, Yn)
sub $16, %r11
add %r13, %r11
- movdqu (%arg3,%r11,1), %xmm1 # recieve the last <16 byte block
+ movdqu (%arg3,%r11,1), %xmm1 # receive the last <16 byte block
lea SHIFT_MASK+16(%rip), %r12
sub %r13, %r12
# adjust the shuffle mask pointer to be able to shift 16-%r13 bytes
@@ -1607,7 +1607,7 @@ _zero_cipher_left_encrypt:
and $15, %r13 # %r13 = arg4 (mod 16)
je _multiple_of_16_bytes_encrypt
- # Handle the last <16 Byte block seperately
+ # Handle the last <16 Byte block separately
paddd ONE(%rip), %xmm0 # INCR CNT to get Yn
movdqa SHUF_MASK(%rip), %xmm10
PSHUFB_XMM %xmm10, %xmm0
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 62f084478f7e..4e12668711e5 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -71,7 +71,7 @@ static inline void set_page_memtype(struct page *pg, unsigned long memtype) { }
* Read/Write : ReadOnly, ReadWrite
* Presence : NotPresent
*
- * Within a catagory, the attributes are mutually exclusive.
+ * Within a category, the attributes are mutually exclusive.
*
* The implementation of this API will take care of various aspects that
* are associated with changing such attributes, such as:
diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h
index 518bbbb9ee59..fe2cc6e105fa 100644
--- a/arch/x86/include/asm/kdebug.h
+++ b/arch/x86/include/asm/kdebug.h
@@ -26,7 +26,7 @@ extern void die(const char *, struct pt_regs *,long);
extern int __must_check __die(const char *, struct pt_regs *, long);
extern void show_registers(struct pt_regs *regs);
extern void show_trace(struct task_struct *t, struct pt_regs *regs,
- unsigned long *sp);
+ unsigned long *sp, unsigned long bp);
extern void __show_regs(struct pt_regs *regs, int all);
extern void show_regs(struct pt_regs *regs);
extern unsigned long oops_begin(void);
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 8e37deb1eb38..0f5213564326 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -142,9 +142,9 @@ struct x86_emulate_ops {
int (*pio_out_emulated)(int size, unsigned short port, const void *val,
unsigned int count, struct kvm_vcpu *vcpu);
- bool (*get_cached_descriptor)(struct desc_struct *desc,
+ bool (*get_cached_descriptor)(struct desc_struct *desc, u32 *base3,
int seg, struct kvm_vcpu *vcpu);
- void (*set_cached_descriptor)(struct desc_struct *desc,
+ void (*set_cached_descriptor)(struct desc_struct *desc, u32 base3,
int seg, struct kvm_vcpu *vcpu);
u16 (*get_segment_selector)(int seg, struct kvm_vcpu *vcpu);
void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
@@ -239,6 +239,7 @@ struct x86_emulate_ctxt {
int interruptibility;
bool perm_ok; /* do not check permissions if true */
+ bool only_vendor_specific_insn;
bool have_exception;
struct x86_exception exception;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ffd7f8d29187..c8af0991fdf0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -85,7 +85,7 @@
#define ASYNC_PF_PER_VCPU 64
-extern spinlock_t kvm_lock;
+extern raw_spinlock_t kvm_lock;
extern struct list_head vm_list;
struct kvm_vcpu;
@@ -255,6 +255,8 @@ struct kvm_mmu {
int (*sync_page)(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp);
void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
+ void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+ u64 *spte, const void *pte, unsigned long mmu_seq);
hpa_t root_hpa;
int root_level;
int shadow_root_level;
@@ -335,12 +337,6 @@ struct kvm_vcpu_arch {
u64 *last_pte_updated;
gfn_t last_pte_gfn;
- struct {
- gfn_t gfn; /* presumed gfn during guest pte update */
- pfn_t pfn; /* pfn corresponding to that gfn */
- unsigned long mmu_seq;
- } update_pte;
-
struct fpu guest_fpu;
u64 xcr0;
@@ -448,7 +444,7 @@ struct kvm_arch {
unsigned long irq_sources_bitmap;
s64 kvmclock_offset;
- spinlock_t tsc_write_lock;
+ raw_spinlock_t tsc_write_lock;
u64 last_tsc_nsec;
u64 last_tsc_offset;
u64 last_tsc_write;
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 823d48223400..fd5a1f365c95 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -43,6 +43,7 @@
#define MSR_MTRRcap 0x000000fe
#define MSR_IA32_BBL_CR_CTL 0x00000119
+#define MSR_IA32_BBL_CR_CTL3 0x0000011e
#define MSR_IA32_SYSENTER_CS 0x00000174
#define MSR_IA32_SYSENTER_ESP 0x00000175
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 07f46016d3ff..4886a68f267e 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -29,8 +29,8 @@ void arch_trigger_all_cpu_backtrace(void);
* external nmis, because the local ones are more frequent.
*
* Also setup some default high/normal/low settings for
- * subsystems to registers with. Using 4 bits to seperate
- * the priorities. This can go alot higher if needed be.
+ * subsystems to registers with. Using 4 bits to separate
+ * the priorities. This can go a lot higher if needed be.
*/
#define NMI_LOCAL_SHIFT 16 /* randomly picked */
diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h
index 6d8723a766cc..af788496020b 100644
--- a/arch/x86/include/asm/nops.h
+++ b/arch/x86/include/asm/nops.h
@@ -38,7 +38,7 @@
#define K8_NOP8 K8_NOP4 K8_NOP4
/* K7 nops
- uses eax dependencies (arbitary choice)
+ uses eax dependencies (arbitrary choice)
1: nop
2: movl %eax,%eax
3: leal (,%eax,1),%eax
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index f482010350fb..5ca6801b75f3 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -20,7 +20,7 @@ extern struct olpc_platform_t olpc_platform_info;
/*
* OLPC board IDs contain the major build number within the mask 0x0ff0,
- * and the minor build number withing 0x000f. Pre-builds have a minor
+ * and the minor build number within 0x000f. Pre-builds have a minor
* number less than 8, and normal builds start at 8. For example, 0x0B10
* is a PreB1, and 0x0C18 is a C1.
*/
diff --git a/arch/x86/include/asm/perf_event_p4.h b/arch/x86/include/asm/perf_event_p4.h
index cc29086e30cd..56fd9e3abbda 100644
--- a/arch/x86/include/asm/perf_event_p4.h
+++ b/arch/x86/include/asm/perf_event_p4.h
@@ -1,5 +1,5 @@
/*
- * Netburst Perfomance Events (P4, old Xeon)
+ * Netburst Performance Events (P4, old Xeon)
*/
#ifndef PERF_EVENT_P4_H
@@ -9,7 +9,7 @@
#include <linux/bitops.h>
/*
- * NetBurst has perfomance MSRs shared between
+ * NetBurst has performance MSRs shared between
* threads if HT is turned on, ie for both logical
* processors (mem: in turn in Atom with HT support
* perf-MSRs are not shared and every thread has its
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h
index 94b979d1b58d..effff47a3c82 100644
--- a/arch/x86/include/asm/pgtable-3level.h
+++ b/arch/x86/include/asm/pgtable-3level.h
@@ -69,8 +69,6 @@ static inline void native_pmd_clear(pmd_t *pmd)
static inline void pud_clear(pud_t *pudp)
{
- unsigned long pgd;
-
set_pud(pudp, __pud(0));
/*
@@ -79,13 +77,10 @@ static inline void pud_clear(pud_t *pudp)
* section 8.1: in PAE mode we explicitly have to flush the
* TLB via cr3 if the top-level pgd is changed...
*
- * Make sure the pud entry we're updating is within the
- * current pgd to avoid unnecessary TLB flushes.
+ * Currently all places where pud_clear() is called either have
+ * flush_tlb_mm() followed or don't need TLB flush (x86_64 code or
+ * pud_clear_bad()), so we don't need TLB flush here.
*/
- pgd = read_cr3();
- if (__pa(pudp) >= pgd && __pa(pudp) <
- (pgd + sizeof(pgd_t)*PTRS_PER_PGD))
- write_cr3(pgd);
}
#ifdef CONFIG_SMP
diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h
index 7a3e836eb2a9..a898a2b6e10c 100644
--- a/arch/x86/include/asm/processor-flags.h
+++ b/arch/x86/include/asm/processor-flags.h
@@ -7,7 +7,7 @@
*/
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxiliary carry Flag */
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
diff --git a/arch/x86/include/asm/ptrace-abi.h b/arch/x86/include/asm/ptrace-abi.h
index 52b098a6eebb..7b0a55a88851 100644
--- a/arch/x86/include/asm/ptrace-abi.h
+++ b/arch/x86/include/asm/ptrace-abi.h
@@ -31,7 +31,7 @@
#define R12 24
#define RBP 32
#define RBX 40
-/* arguments: interrupts/non tracing syscalls only save upto here*/
+/* arguments: interrupts/non tracing syscalls only save up to here*/
#define R11 48
#define R10 56
#define R9 64
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 78cd1ea94500..1babf8adecdf 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -73,7 +73,7 @@ struct pt_regs {
unsigned long r12;
unsigned long rbp;
unsigned long rbx;
-/* arguments: non interrupts/non tracing syscalls only save upto here*/
+/* arguments: non interrupts/non tracing syscalls only save up to here*/
unsigned long r11;
unsigned long r10;
unsigned long r9;
@@ -103,7 +103,7 @@ struct pt_regs {
unsigned long r12;
unsigned long bp;
unsigned long bx;
-/* arguments: non interrupts/non tracing syscalls only save upto here*/
+/* arguments: non interrupts/non tracing syscalls only save up to here*/
unsigned long r11;
unsigned long r10;
unsigned long r9;
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index 52b5c7ed3608..d7e89c83645d 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -47,7 +47,7 @@ struct stacktrace_ops {
};
void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
- unsigned long *stack,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data);
#ifdef CONFIG_X86_32
@@ -86,11 +86,11 @@ stack_frame(struct task_struct *task, struct pt_regs *regs)
extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, char *log_lvl);
+ unsigned long *stack, unsigned long bp, char *log_lvl);
extern void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl);
+ unsigned long *sp, unsigned long bp, char *log_lvl);
extern unsigned int code_bytes;
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 1ca132fc0d03..83e2efd181e2 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -35,7 +35,7 @@ static inline cycles_t get_cycles(void)
static __always_inline cycles_t vget_cycles(void)
{
/*
- * We only do VDSOs on TSC capable CPUs, so this shouldnt
+ * We only do VDSOs on TSC capable CPUs, so this shouldn't
* access boot_cpu_data (which is not VDSO-safe):
*/
#ifndef CONFIG_X86_TSC
diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h
index 1c10c88ee4e1..5d4922ad4b9b 100644
--- a/arch/x86/include/asm/xen/interface.h
+++ b/arch/x86/include/asm/xen/interface.h
@@ -86,7 +86,7 @@ DEFINE_GUEST_HANDLE(void);
* The privilege level specifies which modes may enter a trap via a software
* interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
* privilege levels as follows:
- * Level == 0: Noone may enter
+ * Level == 0: No one may enter
* Level == 1: Kernel may enter
* Level == 2: Kernel may enter
* Level == 3: Everyone may enter
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 4db35544de73..4a234677e213 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -199,7 +199,7 @@ void *text_poke_early(void *addr, const void *opcode, size_t len);
/* Replace instructions with better alternatives for this CPU type.
This runs before SMP is initialized to avoid SMP problems with
- self modifying code. This implies that assymetric systems where
+ self modifying code. This implies that asymmetric systems where
APs have less capabilities than the boot processor are not handled.
Tough. Make sure you disable such features by hand. */
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 65634190ffd6..6801959a8b2a 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -15,7 +15,7 @@ static u32 *flush_words;
const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 7b1e8e10b89c..86d1ad4962a7 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -73,7 +73,7 @@ static u32 __init allocate_aperture(void)
/*
* using 512M as goal, in case kexec will load kernel_big
* that will do the on position decompress, and could overlap with
- * that positon with gart that is used.
+ * that position with gart that is used.
* sequende:
* kernel_small
* ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 4b5ebd26f565..180ca240e03c 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1886,7 +1886,7 @@ void disable_IO_APIC(void)
*
* With interrupt-remapping, for now we will use virtual wire A mode,
* as virtual wire B is little complex (need to configure both
- * IOAPIC RTE aswell as interrupt-remapping table entry).
+ * IOAPIC RTE as well as interrupt-remapping table entry).
* As this gets called during crash dump, keep this simple for now.
*/
if (ioapic_i8259.pin != -1 && !intr_remapping_enabled) {
@@ -2905,7 +2905,7 @@ void __init setup_IO_APIC(void)
}
/*
- * Called after all the initialization is done. If we didnt find any
+ * Called after all the initialization is done. If we didn't find any
* APIC bugs then we can allow the modify fast path
*/
@@ -3983,7 +3983,7 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)
static __init int bad_ioapic(unsigned long address)
{
if (nr_ioapics >= MAX_IO_APICS) {
- printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
+ printk(KERN_WARNING "WARNING: Max # of I/O APICs (%d) exceeded "
"(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
return 1;
}
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 9079926a5b18..0b4be431c620 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -66,7 +66,7 @@
* 1.5: Fix segment register reloading (in case of bad segments saved
* across BIOS call).
* Stephen Rothwell
- * 1.6: Cope with complier/assembler differences.
+ * 1.6: Cope with compiler/assembler differences.
* Only try to turn off the first display device.
* Fix OOPS at power off with no APM BIOS by Jan Echternach
* <echter@informatik.uni-rostock.de>
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c
index 03162dac6271..cf48cdd6907d 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -444,7 +444,7 @@ static int __cpuinit longhaul_get_ranges(void)
return -EINVAL;
}
/* Get max multiplier - as we always did.
- * Longhaul MSR is usefull only when voltage scaling is enabled.
+ * Longhaul MSR is useful only when voltage scaling is enabled.
* C3 is booting at max anyway. */
maxmult = mult;
/* Get min multiplier */
@@ -1011,7 +1011,7 @@ static void __exit longhaul_exit(void)
* trigger frequency transition in some cases. */
module_param(disable_acpi_c3, int, 0644);
MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
-/* Change CPU voltage with frequency. Very usefull to save
+/* Change CPU voltage with frequency. Very useful to save
* power, but most VIA C3 processors aren't supporting it. */
module_param(scale_voltage, int, 0644);
MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
index 4a5a42b842ad..755a31e0f5b0 100644
--- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
@@ -315,8 +315,6 @@ static int __init pcc_cpufreq_do_osc(acpi_handle *handle)
input.count = 4;
input.pointer = in_params;
- input.count = 4;
- input.pointer = in_params;
in_params[0].type = ACPI_TYPE_BUFFER;
in_params[0].buffer.length = 16;
in_params[0].buffer.pointer = OSC_UUID;
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index c567dec854f6..2368e38327b3 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -630,8 +630,7 @@ static void print_basics(struct powernow_k8_data *data)
data->powernow_table[j].frequency/1000);
} else {
printk(KERN_INFO PFX
- " %d : fid 0x%x (%d MHz), vid 0x%x\n",
- j,
+ "fid 0x%x (%d MHz), vid 0x%x\n",
data->powernow_table[j].index & 0xff,
data->powernow_table[j].frequency/1000,
data->powernow_table[j].index >> 8);
@@ -1276,7 +1275,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
if (powernow_k8_cpu_init_acpi(data)) {
/*
- * Use the PSB BIOS structure. This is only availabe on
+ * Use the PSB BIOS structure. This is only available on
* an UP version, and is deprecated by AMD.
*/
if (num_online_cpus() != 1) {
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
index 8abd869baabf..91bc25b67bc1 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
@@ -292,7 +292,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
result = speedstep_smi_ownership();
if (result) {
- dprintk("fails in aquiring ownership of a SMI interface.\n");
+ dprintk("fails in acquiring ownership of a SMI interface.\n");
return -EINVAL;
}
@@ -360,7 +360,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
int result = speedstep_smi_ownership();
if (result)
- dprintk("fails in re-aquiring ownership of a SMI interface.\n");
+ dprintk("fails in re-acquiring ownership of a SMI interface.\n");
return result;
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
index a77971979564..0ed633c5048b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-inject.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -32,7 +32,7 @@ static void inject_mce(struct mce *m)
{
struct mce *i = &per_cpu(injectm, m->extcpu);
- /* Make sure noone reads partially written injectm */
+ /* Make sure no one reads partially written injectm */
i->finished = 0;
mb();
m->finished = 0;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index d916183b7f9c..ab1122998dba 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -881,7 +881,7 @@ reset:
* Check if the address reported by the CPU is in a format we can parse.
* It would be possible to add code for most other cases, but all would
* be somewhat complicated (e.g. segment offset would require an instruction
- * parser). So only support physical addresses upto page granuality for now.
+ * parser). So only support physical addresses up to page granuality for now.
*/
static int mce_usable_address(struct mce *m)
{
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 9f27228ceffd..a71efcdbb092 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -1,6 +1,6 @@
/*
* This only handles 32bit MTRR on 32bit hosts. This is strictly wrong
- * because MTRRs can span upto 40 bits (36bits on most modern x86)
+ * because MTRRs can span up to 40 bits (36bits on most modern x86)
*/
#define DEBUG
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 26604188aa49..87eab4a27dfc 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -178,8 +178,6 @@ struct cpu_hw_events {
*/
#define INTEL_UEVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
-#define PEBS_EVENT_CONSTRAINT(c, n) \
- INTEL_UEVENT_CONSTRAINT(c, n)
#define EVENT_CONSTRAINT_END \
EVENT_CONSTRAINT(0, 0, 0)
@@ -1111,7 +1109,7 @@ static int x86_pmu_add(struct perf_event *event, int flags)
/*
* If group events scheduling transaction was started,
- * skip the schedulability test here, it will be peformed
+ * skip the schedulability test here, it will be performed
* at commit time (->commit_txn) as a whole
*/
if (cpuc->group_flag & PERF_EVENT_TXN)
@@ -1792,7 +1790,7 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
perf_callchain_store(entry, regs->ip);
- dump_trace(NULL, regs, NULL, &backtrace_ops, entry);
+ dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry);
}
#ifdef CONFIG_COMPAT
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index b95c66ae4a2a..bab491b8ee25 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -362,87 +362,69 @@ static int intel_pmu_drain_bts_buffer(void)
* PEBS
*/
static struct event_constraint intel_core2_pebs_event_constraints[] = {
- PEBS_EVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
- PEBS_EVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
- PEBS_EVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
- PEBS_EVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
- INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+ INTEL_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
+ INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
+ INTEL_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
+ INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
EVENT_CONSTRAINT_END
};
static struct event_constraint intel_atom_pebs_event_constraints[] = {
- PEBS_EVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
- PEBS_EVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+ INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
+ INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
EVENT_CONSTRAINT_END
};
static struct event_constraint intel_nehalem_pebs_event_constraints[] = {
- INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
- PEBS_EVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
- INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */
- INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
- PEBS_EVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
- INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
- PEBS_EVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
+ INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+ INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */
+ INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
+ INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+ INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
EVENT_CONSTRAINT_END
};
static struct event_constraint intel_westmere_pebs_event_constraints[] = {
- INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
- PEBS_EVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
- INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
-
- INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
- PEBS_EVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
+ INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+ INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+ INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
EVENT_CONSTRAINT_END
};
static struct event_constraint intel_snb_pebs_events[] = {
- PEBS_EVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
- PEBS_EVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
- PEBS_EVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
- PEBS_EVENT_CONSTRAINT(0x01c4, 0xf), /* BR_INST_RETIRED.CONDITIONAL */
- PEBS_EVENT_CONSTRAINT(0x02c4, 0xf), /* BR_INST_RETIRED.NEAR_CALL */
- PEBS_EVENT_CONSTRAINT(0x04c4, 0xf), /* BR_INST_RETIRED.ALL_BRANCHES */
- PEBS_EVENT_CONSTRAINT(0x08c4, 0xf), /* BR_INST_RETIRED.NEAR_RETURN */
- PEBS_EVENT_CONSTRAINT(0x10c4, 0xf), /* BR_INST_RETIRED.NOT_TAKEN */
- PEBS_EVENT_CONSTRAINT(0x20c4, 0xf), /* BR_INST_RETIRED.NEAR_TAKEN */
- PEBS_EVENT_CONSTRAINT(0x40c4, 0xf), /* BR_INST_RETIRED.FAR_BRANCH */
- PEBS_EVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */
- PEBS_EVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
- PEBS_EVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */
- PEBS_EVENT_CONSTRAINT(0x10c5, 0xf), /* BR_MISP_RETIRED.NOT_TAKEN */
- PEBS_EVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.TAKEN */
- PEBS_EVENT_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
- PEBS_EVENT_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORE */
- PEBS_EVENT_CONSTRAINT(0x11d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_LOADS */
- PEBS_EVENT_CONSTRAINT(0x12d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_STORES */
- PEBS_EVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOP_RETIRED.LOCK_LOADS */
- PEBS_EVENT_CONSTRAINT(0x22d0, 0xf), /* MEM_UOP_RETIRED.LOCK_STORES */
- PEBS_EVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_LOADS */
- PEBS_EVENT_CONSTRAINT(0x42d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_STORES */
- PEBS_EVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOP_RETIRED.ANY_LOADS */
- PEBS_EVENT_CONSTRAINT(0x82d0, 0xf), /* MEM_UOP_RETIRED.ANY_STORES */
- PEBS_EVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */
- PEBS_EVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */
- PEBS_EVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.LLC_HIT */
- PEBS_EVENT_CONSTRAINT(0x40d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */
- PEBS_EVENT_CONSTRAINT(0x01d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */
- PEBS_EVENT_CONSTRAINT(0x02d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */
- PEBS_EVENT_CONSTRAINT(0x04d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM */
- PEBS_EVENT_CONSTRAINT(0x08d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_NONE */
- PEBS_EVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
+ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+ INTEL_UEVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+ INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
+ INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x11d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_LOADS */
+ INTEL_UEVENT_CONSTRAINT(0x12d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_STORES */
+ INTEL_UEVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOP_RETIRED.LOCK_LOADS */
+ INTEL_UEVENT_CONSTRAINT(0x22d0, 0xf), /* MEM_UOP_RETIRED.LOCK_STORES */
+ INTEL_UEVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_LOADS */
+ INTEL_UEVENT_CONSTRAINT(0x42d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_STORES */
+ INTEL_UEVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOP_RETIRED.ANY_LOADS */
+ INTEL_UEVENT_CONSTRAINT(0x82d0, 0xf), /* MEM_UOP_RETIRED.ANY_STORES */
+ INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
+ INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+ INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
EVENT_CONSTRAINT_END
};
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index 3769ac822f96..0811f5ebfba6 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1,5 +1,5 @@
/*
- * Netburst Perfomance Events (P4, old Xeon)
+ * Netburst Performance Events (P4, old Xeon)
*
* Copyright (C) 2010 Parallels, Inc., Cyrill Gorcunov <gorcunov@openvz.org>
* Copyright (C) 2010 Intel Corporation, Lin Ming <ming.m.lin@intel.com>
@@ -679,7 +679,7 @@ static int p4_validate_raw_event(struct perf_event *event)
*/
/*
- * if an event is shared accross the logical threads
+ * if an event is shared across the logical threads
* the user needs special permissions to be able to use it
*/
if (p4_ht_active() && p4_event_bind_map[v].shared) {
@@ -790,13 +790,13 @@ static void p4_pmu_disable_pebs(void)
*
* It's still allowed that two threads setup same cache
* events so we can't simply clear metrics until we knew
- * noone is depending on us, so we need kind of counter
+ * no one is depending on us, so we need kind of counter
* for "ReplayEvent" users.
*
* What is more complex -- RAW events, if user (for some
* reason) will pass some cache event metric with improper
* event opcode -- it's fine from hardware point of view
- * but completely nonsence from "meaning" of such action.
+ * but completely nonsense from "meaning" of such action.
*
* So at moment let leave metrics turned on forever -- it's
* ok for now but need to be revisited!
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 227b0448960d..d22d0c4edcfd 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -86,7 +86,7 @@ static void __init vmware_platform_setup(void)
}
/*
- * While checking the dmi string infomation, just checking the product
+ * While checking the dmi string information, just checking the product
* serial key should be enough, as this will always have a VMware
* specific string when running under VMware hypervisor.
*/
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 220a1c11cfde..999e2793590b 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -175,21 +175,21 @@ static const struct stacktrace_ops print_trace_ops = {
void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, char *log_lvl)
+ unsigned long *stack, unsigned long bp, char *log_lvl)
{
printk("%sCall Trace:\n", log_lvl);
- dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
+ dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
}
void show_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack)
+ unsigned long *stack, unsigned long bp)
{
- show_trace_log_lvl(task, regs, stack, "");
+ show_trace_log_lvl(task, regs, stack, bp, "");
}
void show_stack(struct task_struct *task, unsigned long *sp)
{
- show_stack_log_lvl(task, NULL, sp, "");
+ show_stack_log_lvl(task, NULL, sp, 0, "");
}
/*
@@ -197,14 +197,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
*/
void dump_stack(void)
{
+ unsigned long bp;
unsigned long stack;
+ bp = stack_frame(current, NULL);
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm, print_tainted(),
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
- show_trace(NULL, NULL, &stack);
+ show_trace(NULL, NULL, &stack, bp);
}
EXPORT_SYMBOL(dump_stack);
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 74cc1eda384b..3b97a80ce329 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -17,12 +17,11 @@
#include <asm/stacktrace.h>
-void dump_trace(struct task_struct *task,
- struct pt_regs *regs, unsigned long *stack,
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
int graph = 0;
- unsigned long bp;
if (!task)
task = current;
@@ -35,7 +34,9 @@ void dump_trace(struct task_struct *task,
stack = (unsigned long *)task->thread.sp;
}
- bp = stack_frame(task, regs);
+ if (!bp)
+ bp = stack_frame(task, regs);
+
for (;;) {
struct thread_info *context;
@@ -55,7 +56,7 @@ EXPORT_SYMBOL(dump_trace);
void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl)
+ unsigned long *sp, unsigned long bp, char *log_lvl)
{
unsigned long *stack;
int i;
@@ -77,7 +78,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
touch_nmi_watchdog();
}
printk(KERN_CONT "\n");
- show_trace_log_lvl(task, regs, sp, log_lvl);
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
@@ -102,7 +103,7 @@ void show_registers(struct pt_regs *regs)
u8 *ip;
printk(KERN_EMERG "Stack:\n");
- show_stack_log_lvl(NULL, regs, &regs->sp, KERN_EMERG);
+ show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
printk(KERN_EMERG "Code: ");
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index a6b6fcf7f0ae..e71c98d3c0d2 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -139,8 +139,8 @@ fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
*/
-void dump_trace(struct task_struct *task,
- struct pt_regs *regs, unsigned long *stack,
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
const unsigned cpu = get_cpu();
@@ -150,7 +150,6 @@ void dump_trace(struct task_struct *task,
struct thread_info *tinfo;
int graph = 0;
unsigned long dummy;
- unsigned long bp;
if (!task)
task = current;
@@ -161,7 +160,8 @@ void dump_trace(struct task_struct *task,
stack = (unsigned long *)task->thread.sp;
}
- bp = stack_frame(task, regs);
+ if (!bp)
+ bp = stack_frame(task, regs);
/*
* Print function call entries in all stacks, starting at the
* current stack address. If the stacks consist of nested
@@ -225,7 +225,7 @@ EXPORT_SYMBOL(dump_trace);
void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl)
+ unsigned long *sp, unsigned long bp, char *log_lvl)
{
unsigned long *irq_stack_end;
unsigned long *irq_stack;
@@ -269,7 +269,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
preempt_enable();
printk(KERN_CONT "\n");
- show_trace_log_lvl(task, regs, sp, log_lvl);
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
void show_registers(struct pt_regs *regs)
@@ -298,7 +298,7 @@ void show_registers(struct pt_regs *regs)
printk(KERN_EMERG "Stack:\n");
show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
- KERN_EMERG);
+ 0, KERN_EMERG);
printk(KERN_EMERG "Code: ");
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b72b4a6466a9..8a445a0c989e 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -18,7 +18,7 @@
* A note on terminology:
* - top of stack: Architecture defined interrupt frame from SS to RIP
* at the top of the kernel process stack.
- * - partial stack frame: partially saved registers upto R11.
+ * - partial stack frame: partially saved registers up to R11.
* - full stack frame: Like partial stack frame, but all register saved.
*
* Some macro usage:
@@ -422,7 +422,7 @@ ENTRY(ret_from_fork)
END(ret_from_fork)
/*
- * System call entry. Upto 6 arguments in registers are supported.
+ * System call entry. Up to 6 arguments in registers are supported.
*
* SYSCALL does not save anything on the stack and does not change the
* stack pointer.
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index e60c38cc0eed..12aff2537682 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -145,7 +145,7 @@ EXPORT_SYMBOL_GPL(fpu_finit);
* The _current_ task is using the FPU for the first time
* so initialize it and set the mxcsr to its default
* value at reset if we support XMM instructions and then
- * remeber the current task has used the FPU.
+ * remember the current task has used the FPU.
*/
int init_fpu(struct task_struct *tsk)
{
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 9974d21048fd..72090705a656 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -172,7 +172,7 @@ asmlinkage void do_softirq(void)
call_on_stack(__do_softirq, isp);
/*
- * Shouldnt happen, we returned above if in_interrupt():
+ * Shouldn't happen, we returned above if in_interrupt():
*/
WARN_ON_ONCE(softirq_count());
}
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 7c64c420a9f6..dba0b36941a5 100644
--- a/arch/x86/kernel/kgdb.c
+++ b/arch/x86/kernel/kgdb.c
@@ -278,7 +278,7 @@ static int hw_break_release_slot(int breakno)
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
if (dbg_release_bp_slot(*pevent))
/*
- * The debugger is responisble for handing the retry on
+ * The debugger is responsible for handing the retry on
* remove failure.
*/
return -1;
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 8dc44662394b..33c07b0b122e 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -493,7 +493,7 @@ static void __init kvm_smp_prepare_boot_cpu(void)
native_smp_prepare_boot_cpu();
}
-static void kvm_guest_cpu_online(void *dummy)
+static void __cpuinit kvm_guest_cpu_online(void *dummy)
{
kvm_guest_cpu_init();
}
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c
index 63eaf6596233..177183cbb6ae 100644
--- a/arch/x86/kernel/mca_32.c
+++ b/arch/x86/kernel/mca_32.c
@@ -259,7 +259,7 @@ static int __init mca_init(void)
/*
* WARNING: Be careful when making changes here. Putting an adapter
* and the motherboard simultaneously into setup mode may result in
- * damage to chips (according to The Indispensible PC Hardware Book
+ * damage to chips (according to The Indispensable PC Hardware Book
* by Hans-Peter Messmer). Also, we disable system interrupts (so
* that we are not disturbed in the middle of this).
*/
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 01b0f6d06451..6f789a887c06 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -883,7 +883,7 @@ static int __init update_mp_table(void)
if (!mpc_new_phys) {
unsigned char old, new;
- /* check if we can change the postion */
+ /* check if we can change the position */
mpc->checksum = 0;
old = mpf_checksum((unsigned char *)mpc, mpc->length);
mpc->checksum = 0xff;
@@ -892,7 +892,7 @@ static int __init update_mp_table(void)
printk(KERN_INFO "mpc is readonly, please try alloc_mptable instead\n");
return 0;
}
- printk(KERN_INFO "use in-positon replacing\n");
+ printk(KERN_INFO "use in-position replacing\n");
} else {
mpf->physptr = mpc_new_phys;
mpc_new = phys_to_virt(mpc_new_phys);
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index f56a117cef68..e8c33a302006 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1279,7 +1279,7 @@ static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
if (pci_dev == PCI_DEVICE_ID_IBM_CALIOC2) {
/*
- * FIXME: properly scan for devices accross the
+ * FIXME: properly scan for devices across the
* PCI-to-PCI bridge on every CalIOC2 port.
*/
return 1;
@@ -1295,7 +1295,7 @@ static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
/*
* calgary_init_bitmap_from_tce_table():
- * Funtion for kdump case. In the second/kdump kernel initialize
+ * Function for kdump case. In the second/kdump kernel initialize
* the bitmap based on the tce table entries obtained from first kernel
*/
static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 99fa3adf0141..d46cbe46b7ab 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -87,7 +87,7 @@ void exit_thread(void)
void show_regs(struct pt_regs *regs)
{
show_registers(regs);
- show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs));
+ show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), 0);
}
void show_regs_common(void)
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index 938c8e10a19a..6515733a289d 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -73,7 +73,7 @@ static const struct stacktrace_ops save_stack_ops_nosched = {
*/
void save_stack_trace(struct stack_trace *trace)
{
- dump_trace(current, NULL, NULL, &save_stack_ops, trace);
+ dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
@@ -81,14 +81,14 @@ EXPORT_SYMBOL_GPL(save_stack_trace);
void save_stack_trace_regs(struct stack_trace *trace, struct pt_regs *regs)
{
- dump_trace(current, regs, NULL, &save_stack_ops, trace);
+ dump_trace(current, regs, NULL, 0, &save_stack_ops, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
- dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
+ dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c
index 58de45ee08b6..7977f0cfe339 100644
--- a/arch/x86/kernel/step.c
+++ b/arch/x86/kernel/step.c
@@ -166,7 +166,7 @@ static void enable_step(struct task_struct *child, bool block)
* Make sure block stepping (BTF) is not enabled unless it should be.
* Note that we don't try to worry about any is_setting_trap_flag()
* instructions after the first when using block stepping.
- * So noone should try to use debugger block stepping in a program
+ * So no one should try to use debugger block stepping in a program
* that uses user-mode single stepping itself.
*/
if (enable_single_step(child) && block) {
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index 7e4515957a1c..8927486a4649 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -39,7 +39,7 @@ int __ref arch_register_cpu(int num)
/*
* CPU0 cannot be offlined due to several
* restrictions and assumptions in kernel. This basically
- * doesnt add a control file, one cannot attempt to offline
+ * doesn't add a control file, one cannot attempt to offline
* BSP.
*
* Also certain PCI quirks require not to enable hotplug control
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index ffe5755caa8b..9335bf7dd2e7 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -427,7 +427,7 @@ unsigned long native_calibrate_tsc(void)
* the delta to the previous read. We keep track of the min
* and max values of that delta. The delta is mostly defined
* by the IO time of the PIT access, so we can detect when a
- * SMI/SMM disturbance happend between the two reads. If the
+ * SMI/SMM disturbance happened between the two reads. If the
* maximum time is significantly larger than the minimum time,
* then we discard the result and have another try.
*
@@ -900,7 +900,7 @@ static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
* timer based, instead of loop based, we don't block the boot
* process while this longer calibration is done.
*
- * If there are any calibration anomolies (too many SMIs, etc),
+ * If there are any calibration anomalies (too many SMIs, etc),
* or the refined calibration is off by 1% of the fast early
* calibration, we throw out the new calibration and use the
* early calibration.
diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S
index 0edefc19a113..b9242bacbe59 100644
--- a/arch/x86/kernel/verify_cpu.S
+++ b/arch/x86/kernel/verify_cpu.S
@@ -18,7 +18,7 @@
* This file is expected to run in 32bit code. Currently:
*
* arch/x86/boot/compressed/head_64.S: Boot cpu verification
- * arch/x86/kernel/trampoline_64.S: secondary processor verfication
+ * arch/x86/kernel/trampoline_64.S: secondary processor verification
* arch/x86/kernel/head_32.S: processor startup
*
* verify_cpu, returns the status of longmode and SSE in register %eax.
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 547128546cc3..a3911343976b 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -53,7 +53,7 @@ void __sanitize_i387_state(struct task_struct *tsk)
/*
* None of the feature bits are in init state. So nothing else
- * to do for us, as the memory layout is upto date.
+ * to do for us, as the memory layout is up to date.
*/
if ((xstate_bv & pcntxt_mask) == pcntxt_mask)
return;
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index caf966781d25..0ad47b819a8b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -76,6 +76,7 @@
#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
/* Misc flags */
+#define VendorSpecific (1<<22) /* Vendor specific instruction */
#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */
#define Undefined (1<<25) /* No Such Instruction */
@@ -877,7 +878,8 @@ static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
if (selector & 1 << 2) {
struct desc_struct desc;
memset (dt, 0, sizeof *dt);
- if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu))
+ if (!ops->get_cached_descriptor(&desc, NULL, VCPU_SREG_LDTR,
+ ctxt->vcpu))
return;
dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
@@ -929,6 +931,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
return ret;
}
+/* Does not support long mode */
static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
u16 selector, int seg)
@@ -1040,7 +1043,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
}
load:
ops->set_segment_selector(selector, seg, ctxt->vcpu);
- ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
+ ops->set_cached_descriptor(&seg_desc, 0, seg, ctxt->vcpu);
return X86EMUL_CONTINUE;
exception:
emulate_exception(ctxt, err_vec, err_code, true);
@@ -1560,7 +1563,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
struct desc_struct *ss)
{
memset(cs, 0, sizeof(struct desc_struct));
- ops->get_cached_descriptor(cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->get_cached_descriptor(cs, NULL, VCPU_SREG_CS, ctxt->vcpu);
memset(ss, 0, sizeof(struct desc_struct));
cs->l = 0; /* will be adjusted later */
@@ -1607,9 +1610,9 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cs.d = 0;
cs.l = 1;
}
- ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
c->regs[VCPU_REGS_RCX] = c->eip;
@@ -1679,9 +1682,9 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cs.l = 1;
}
- ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
@@ -1736,9 +1739,9 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cs_sel |= SELECTOR_RPL_MASK;
ss_sel |= SELECTOR_RPL_MASK;
- ops->set_cached_descriptor(&cs, VCPU_SREG_CS, ctxt->vcpu);
+ ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
c->eip = c->regs[VCPU_REGS_RDX];
@@ -1764,24 +1767,28 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
u16 port, u16 len)
{
struct desc_struct tr_seg;
+ u32 base3;
int r;
- u16 io_bitmap_ptr;
- u8 perm, bit_idx = port & 0x7;
+ u16 io_bitmap_ptr, perm, bit_idx = port & 0x7;
unsigned mask = (1 << len) - 1;
+ unsigned long base;
- ops->get_cached_descriptor(&tr_seg, VCPU_SREG_TR, ctxt->vcpu);
+ ops->get_cached_descriptor(&tr_seg, &base3, VCPU_SREG_TR, ctxt->vcpu);
if (!tr_seg.p)
return false;
if (desc_limit_scaled(&tr_seg) < 103)
return false;
- r = ops->read_std(get_desc_base(&tr_seg) + 102, &io_bitmap_ptr, 2,
- ctxt->vcpu, NULL);
+ base = get_desc_base(&tr_seg);
+#ifdef CONFIG_X86_64
+ base |= ((u64)base3) << 32;
+#endif
+ r = ops->read_std(base + 102, &io_bitmap_ptr, 2, ctxt->vcpu, NULL);
if (r != X86EMUL_CONTINUE)
return false;
if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
return false;
- r = ops->read_std(get_desc_base(&tr_seg) + io_bitmap_ptr + port/8,
- &perm, 1, ctxt->vcpu, NULL);
+ r = ops->read_std(base + io_bitmap_ptr + port/8, &perm, 2, ctxt->vcpu,
+ NULL);
if (r != X86EMUL_CONTINUE)
return false;
if ((perm >> bit_idx) & mask)
@@ -2126,7 +2133,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
}
ops->set_cr(0, ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu);
- ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu);
+ ops->set_cached_descriptor(&next_tss_desc, 0, VCPU_SREG_TR, ctxt->vcpu);
ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu);
if (has_error_code) {
@@ -2365,7 +2372,8 @@ static struct group_dual group7 = { {
D(SrcMem16 | ModRM | Mov | Priv),
D(SrcMem | ModRM | ByteOp | Priv | NoAccess),
}, {
- D(SrcNone | ModRM | Priv), N, N, D(SrcNone | ModRM | Priv),
+ D(SrcNone | ModRM | Priv | VendorSpecific), N,
+ N, D(SrcNone | ModRM | Priv | VendorSpecific),
D(SrcNone | ModRM | DstMem | Mov), N,
D(SrcMem16 | ModRM | Mov | Priv), N,
} };
@@ -2489,7 +2497,7 @@ static struct opcode opcode_table[256] = {
static struct opcode twobyte_table[256] = {
/* 0x00 - 0x0F */
N, GD(0, &group7), N, N,
- N, D(ImplicitOps), D(ImplicitOps | Priv), N,
+ N, D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv), N,
D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N,
N, D(ImplicitOps | ModRM), N, N,
/* 0x10 - 0x1F */
@@ -2502,7 +2510,8 @@ static struct opcode twobyte_table[256] = {
/* 0x30 - 0x3F */
D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
D(ImplicitOps | Priv), N,
- D(ImplicitOps), D(ImplicitOps | Priv), N, N,
+ D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv | VendorSpecific),
+ N, N,
N, N, N, N, N, N, N, N,
/* 0x40 - 0x4F */
X16(D(DstReg | SrcMem | ModRM | Mov)),
@@ -2741,6 +2750,9 @@ done_prefixes:
if (c->d == 0 || (c->d & Undefined))
return -1;
+ if (!(c->d & VendorSpecific) && ctxt->only_vendor_specific_insn)
+ return -1;
+
if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
c->op_bytes = 8;
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 3cece05e4ac4..19fe855e7953 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -62,9 +62,6 @@ static void pic_unlock(struct kvm_pic *s)
}
if (!found)
- found = s->kvm->bsp_vcpu;
-
- if (!found)
return;
kvm_make_request(KVM_REQ_EVENT, found);
@@ -75,7 +72,6 @@ static void pic_unlock(struct kvm_pic *s)
static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
{
s->isr &= ~(1 << irq);
- s->isr_ack |= (1 << irq);
if (s != &s->pics_state->pics[0])
irq += 8;
/*
@@ -89,16 +85,6 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
pic_lock(s->pics_state);
}
-void kvm_pic_clear_isr_ack(struct kvm *kvm)
-{
- struct kvm_pic *s = pic_irqchip(kvm);
-
- pic_lock(s);
- s->pics[0].isr_ack = 0xff;
- s->pics[1].isr_ack = 0xff;
- pic_unlock(s);
-}
-
/*
* set irq level. If an edge is detected, then the IRR is set to 1
*/
@@ -281,7 +267,6 @@ void kvm_pic_reset(struct kvm_kpic_state *s)
s->irr = 0;
s->imr = 0;
s->isr = 0;
- s->isr_ack = 0xff;
s->priority_add = 0;
s->irq_base = 0;
s->read_reg_select = 0;
@@ -545,15 +530,11 @@ static int picdev_read(struct kvm_io_device *this,
*/
static void pic_irq_request(struct kvm *kvm, int level)
{
- struct kvm_vcpu *vcpu = kvm->bsp_vcpu;
struct kvm_pic *s = pic_irqchip(kvm);
- int irq = pic_get_irq(&s->pics[0]);
- s->output = level;
- if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) {
- s->pics[0].isr_ack &= ~(1 << irq);
+ if (!s->output)
s->wakeup_needed = true;
- }
+ s->output = level;
}
static const struct kvm_io_device_ops picdev_ops = {
@@ -575,8 +556,6 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
s->pics[1].elcr_mask = 0xde;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
- s->pics[0].isr_ack = 0xff;
- s->pics[1].isr_ack = 0xff;
/*
* Initialize PIO device
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 93cf9d0d3653..2b2255b1f04b 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -417,10 +417,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
case APIC_DM_INIT:
if (level) {
result = 1;
- if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
- printk(KERN_DEBUG
- "INIT on a runnable vcpu %d\n",
- vcpu->vcpu_id);
vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
@@ -875,8 +871,8 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer);
- if (vcpu->arch.apic->regs_page)
- __free_page(vcpu->arch.apic->regs_page);
+ if (vcpu->arch.apic->regs)
+ free_page((unsigned long)vcpu->arch.apic->regs);
kfree(vcpu->arch.apic);
}
@@ -1065,13 +1061,12 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
vcpu->arch.apic = apic;
- apic->regs_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
- if (apic->regs_page == NULL) {
+ apic->regs = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!apic->regs) {
printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
vcpu->vcpu_id);
goto nomem_free_apic;
}
- apic->regs = page_address(apic->regs_page);
apic->vcpu = vcpu;
hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index f5fe32c5edad..52c9e6b9e725 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -13,7 +13,6 @@ struct kvm_lapic {
u32 divide_count;
struct kvm_vcpu *vcpu;
bool irr_pending;
- struct page *regs_page;
void *regs;
gpa_t vapic_addr;
struct page *vapic_page;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index f02b8edc3d44..22fae7593ee7 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -111,9 +111,6 @@ module_param(oos_shadow, bool, 0644);
#define PT64_LEVEL_SHIFT(level) \
(PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS)
-#define PT64_LEVEL_MASK(level) \
- (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level))
-
#define PT64_INDEX(address, level)\
(((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1))
@@ -123,8 +120,6 @@ module_param(oos_shadow, bool, 0644);
#define PT32_LEVEL_SHIFT(level) \
(PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS)
-#define PT32_LEVEL_MASK(level) \
- (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level))
#define PT32_LVL_OFFSET_MASK(level) \
(PT32_BASE_ADDR_MASK & ((1ULL << (PAGE_SHIFT + (((level) - 1) \
* PT32_LEVEL_BITS))) - 1))
@@ -379,15 +374,15 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc,
static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
int min)
{
- struct page *page;
+ void *page;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- page = alloc_page(GFP_KERNEL);
+ page = (void *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- cache->objects[cache->nobjs++] = page_address(page);
+ cache->objects[cache->nobjs++] = page;
}
return 0;
}
@@ -554,13 +549,23 @@ static int host_mapping_level(struct kvm *kvm, gfn_t gfn)
return ret;
}
-static bool mapping_level_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t large_gfn)
+static struct kvm_memory_slot *
+gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t gfn,
+ bool no_dirty_log)
{
struct kvm_memory_slot *slot;
- slot = gfn_to_memslot(vcpu->kvm, large_gfn);
- if (slot && slot->dirty_bitmap)
- return true;
- return false;
+
+ slot = gfn_to_memslot(vcpu->kvm, gfn);
+ if (!slot || slot->flags & KVM_MEMSLOT_INVALID ||
+ (no_dirty_log && slot->dirty_bitmap))
+ slot = NULL;
+
+ return slot;
+}
+
+static bool mapping_level_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t large_gfn)
+{
+ return gfn_to_memslot_dirty_bitmap(vcpu, large_gfn, true);
}
static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn)
@@ -1032,9 +1037,9 @@ static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
ASSERT(is_empty_shadow_page(sp->spt));
hlist_del(&sp->hash_link);
list_del(&sp->link);
- __free_page(virt_to_page(sp->spt));
+ free_page((unsigned long)sp->spt);
if (!sp->role.direct)
- __free_page(virt_to_page(sp->gfns));
+ free_page((unsigned long)sp->gfns);
kmem_cache_free(mmu_page_header_cache, sp);
kvm_mod_used_mmu_pages(kvm, -1);
}
@@ -1199,6 +1204,13 @@ static void nonpaging_invlpg(struct kvm_vcpu *vcpu, gva_t gva)
{
}
+static void nonpaging_update_pte(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *sp, u64 *spte,
+ const void *pte, unsigned long mmu_seq)
+{
+ WARN_ON(1);
+}
+
#define KVM_PAGE_ARRAY_NR 16
struct kvm_mmu_pages {
@@ -2150,26 +2162,13 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
{
}
-static struct kvm_memory_slot *
-pte_prefetch_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn, bool no_dirty_log)
-{
- struct kvm_memory_slot *slot;
-
- slot = gfn_to_memslot(vcpu->kvm, gfn);
- if (!slot || slot->flags & KVM_MEMSLOT_INVALID ||
- (no_dirty_log && slot->dirty_bitmap))
- slot = NULL;
-
- return slot;
-}
-
static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
bool no_dirty_log)
{
struct kvm_memory_slot *slot;
unsigned long hva;
- slot = pte_prefetch_gfn_to_memslot(vcpu, gfn, no_dirty_log);
+ slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log);
if (!slot) {
get_page(bad_page);
return page_to_pfn(bad_page);
@@ -2190,7 +2189,7 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
gfn_t gfn;
gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt);
- if (!pte_prefetch_gfn_to_memslot(vcpu, gfn, access & ACC_WRITE_MASK))
+ if (!gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK))
return -1;
ret = gfn_to_page_many_atomic(vcpu->kvm, gfn, pages, end - start);
@@ -2804,6 +2803,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu,
context->prefetch_page = nonpaging_prefetch_page;
context->sync_page = nonpaging_sync_page;
context->invlpg = nonpaging_invlpg;
+ context->update_pte = nonpaging_update_pte;
context->root_level = 0;
context->shadow_root_level = PT32E_ROOT_LEVEL;
context->root_hpa = INVALID_PAGE;
@@ -2933,6 +2933,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu,
context->prefetch_page = paging64_prefetch_page;
context->sync_page = paging64_sync_page;
context->invlpg = paging64_invlpg;
+ context->update_pte = paging64_update_pte;
context->free = paging_free;
context->root_level = level;
context->shadow_root_level = level;
@@ -2961,6 +2962,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu,
context->prefetch_page = paging32_prefetch_page;
context->sync_page = paging32_sync_page;
context->invlpg = paging32_invlpg;
+ context->update_pte = paging32_update_pte;
context->root_level = PT32_ROOT_LEVEL;
context->shadow_root_level = PT32E_ROOT_LEVEL;
context->root_hpa = INVALID_PAGE;
@@ -2985,6 +2987,7 @@ static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
context->prefetch_page = nonpaging_prefetch_page;
context->sync_page = nonpaging_sync_page;
context->invlpg = nonpaging_invlpg;
+ context->update_pte = nonpaging_update_pte;
context->shadow_root_level = kvm_x86_ops->get_tdp_level();
context->root_hpa = INVALID_PAGE;
context->direct_map = true;
@@ -3089,8 +3092,6 @@ static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
static int init_kvm_mmu(struct kvm_vcpu *vcpu)
{
- vcpu->arch.update_pte.pfn = bad_pfn;
-
if (mmu_is_nested(vcpu))
return init_kvm_nested_mmu(vcpu);
else if (tdp_enabled)
@@ -3164,7 +3165,7 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp,
u64 *spte,
- const void *new)
+ const void *new, unsigned long mmu_seq)
{
if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
++vcpu->kvm->stat.mmu_pde_zapped;
@@ -3172,10 +3173,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
}
++vcpu->kvm->stat.mmu_pte_updated;
- if (!sp->role.cr4_pae)
- paging32_update_pte(vcpu, sp, spte, new);
- else
- paging64_update_pte(vcpu, sp, spte, new);
+ vcpu->arch.mmu.update_pte(vcpu, sp, spte, new, mmu_seq);
}
static bool need_remote_flush(u64 old, u64 new)
@@ -3210,28 +3208,6 @@ static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu)
return !!(spte && (*spte & shadow_accessed_mask));
}
-static void mmu_guess_page_from_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
- u64 gpte)
-{
- gfn_t gfn;
- pfn_t pfn;
-
- if (!is_present_gpte(gpte))
- return;
- gfn = (gpte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
-
- vcpu->arch.update_pte.mmu_seq = vcpu->kvm->mmu_notifier_seq;
- smp_rmb();
- pfn = gfn_to_pfn(vcpu->kvm, gfn);
-
- if (is_error_pfn(pfn)) {
- kvm_release_pfn_clean(pfn);
- return;
- }
- vcpu->arch.update_pte.gfn = gfn;
- vcpu->arch.update_pte.pfn = pfn;
-}
-
static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn)
{
u64 *spte = vcpu->arch.last_pte_updated;
@@ -3253,21 +3229,14 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
struct kvm_mmu_page *sp;
struct hlist_node *node;
LIST_HEAD(invalid_list);
- u64 entry, gentry;
- u64 *spte;
- unsigned offset = offset_in_page(gpa);
- unsigned pte_size;
- unsigned page_offset;
- unsigned misaligned;
- unsigned quadrant;
- int level;
- int flooded = 0;
- int npte;
- int r;
- int invlpg_counter;
+ unsigned long mmu_seq;
+ u64 entry, gentry, *spte;
+ unsigned pte_size, page_offset, misaligned, quadrant, offset;
+ int level, npte, invlpg_counter, r, flooded = 0;
bool remote_flush, local_flush, zap_page;
zap_page = remote_flush = local_flush = false;
+ offset = offset_in_page(gpa);
pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes);
@@ -3275,9 +3244,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
/*
* Assume that the pte write on a page table of the same type
- * as the current vcpu paging mode. This is nearly always true
- * (might be false while changing modes). Note it is verified later
- * by update_pte().
+ * as the current vcpu paging mode since we update the sptes only
+ * when they have the same mode.
*/
if ((is_pae(vcpu) && bytes == 4) || !new) {
/* Handle a 32-bit guest writing two halves of a 64-bit gpte */
@@ -3303,15 +3271,17 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
break;
}
- mmu_guess_page_from_pte_write(vcpu, gpa, gentry);
+ mmu_seq = vcpu->kvm->mmu_notifier_seq;
+ smp_rmb();
+
spin_lock(&vcpu->kvm->mmu_lock);
if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter)
gentry = 0;
- kvm_mmu_access_page(vcpu, gfn);
kvm_mmu_free_some_pages(vcpu);
++vcpu->kvm->stat.mmu_pte_write;
trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
if (guest_initiated) {
+ kvm_mmu_access_page(vcpu, gfn);
if (gfn == vcpu->arch.last_pt_write_gfn
&& !last_updated_pte_accessed(vcpu)) {
++vcpu->arch.last_pt_write_count;
@@ -3375,7 +3345,8 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
if (gentry &&
!((sp->role.word ^ vcpu->arch.mmu.base_role.word)
& mask.word))
- mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
+ mmu_pte_write_new_pte(vcpu, sp, spte, &gentry,
+ mmu_seq);
if (!remote_flush && need_remote_flush(entry, *spte))
remote_flush = true;
++spte;
@@ -3385,10 +3356,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE);
spin_unlock(&vcpu->kvm->mmu_lock);
- if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
- kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
- vcpu->arch.update_pte.pfn = bad_pfn;
- }
}
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
@@ -3538,14 +3505,23 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
if (!test_bit(slot, sp->slot_bitmap))
continue;
- if (sp->role.level != PT_PAGE_TABLE_LEVEL)
- continue;
-
pt = sp->spt;
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
+ for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+ if (!is_shadow_present_pte(pt[i]) ||
+ !is_last_spte(pt[i], sp->role.level))
+ continue;
+
+ if (is_large_pte(pt[i])) {
+ drop_spte(kvm, &pt[i],
+ shadow_trap_nonpresent_pte);
+ --kvm->stat.lpages;
+ continue;
+ }
+
/* avoid RMW */
if (is_writable_pte(pt[i]))
update_spte(&pt[i], pt[i] & ~PT_WRITABLE_MASK);
+ }
}
kvm_flush_remote_tlbs(kvm);
}
@@ -3583,7 +3559,7 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
if (nr_to_scan == 0)
goto out;
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
int idx, freed_pages;
@@ -3606,7 +3582,7 @@ static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
if (kvm_freed)
list_move_tail(&kvm_freed->vm_list, &vm_list);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
out:
return percpu_counter_read_positive(&kvm_total_used_mmu_pages);
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 6bccc24c4181..c6397795d865 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -31,7 +31,6 @@
#define PT_LVL_ADDR_MASK(lvl) PT64_LVL_ADDR_MASK(lvl)
#define PT_LVL_OFFSET_MASK(lvl) PT64_LVL_OFFSET_MASK(lvl)
#define PT_INDEX(addr, level) PT64_INDEX(addr, level)
- #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
#define PT_LEVEL_BITS PT64_LEVEL_BITS
#ifdef CONFIG_X86_64
#define PT_MAX_FULL_LEVELS 4
@@ -48,7 +47,6 @@
#define PT_LVL_ADDR_MASK(lvl) PT32_LVL_ADDR_MASK(lvl)
#define PT_LVL_OFFSET_MASK(lvl) PT32_LVL_OFFSET_MASK(lvl)
#define PT_INDEX(addr, level) PT32_INDEX(addr, level)
- #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
#define PT_LEVEL_BITS PT32_LEVEL_BITS
#define PT_MAX_FULL_LEVELS 2
#define CMPXCHG cmpxchg
@@ -327,7 +325,7 @@ no_present:
}
static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
- u64 *spte, const void *pte)
+ u64 *spte, const void *pte, unsigned long mmu_seq)
{
pt_element_t gpte;
unsigned pte_access;
@@ -339,16 +337,16 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
- if (gpte_to_gfn(gpte) != vcpu->arch.update_pte.gfn)
+ pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
+ if (is_error_pfn(pfn)) {
+ kvm_release_pfn_clean(pfn);
return;
- pfn = vcpu->arch.update_pte.pfn;
- if (is_error_pfn(pfn))
- return;
- if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq))
+ }
+ if (mmu_notifier_retry(vcpu, mmu_seq))
return;
- kvm_get_pfn(pfn);
+
/*
- * we call mmu_set_spte() with host_writable = true beacuse that
+ * we call mmu_set_spte() with host_writable = true because that
* vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
*/
mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
@@ -829,7 +827,6 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
#undef FNAME
#undef PT_BASE_ADDR_MASK
#undef PT_INDEX
-#undef PT_LEVEL_MASK
#undef PT_LVL_ADDR_MASK
#undef PT_LVL_OFFSET_MASK
#undef PT_LEVEL_BITS
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 63fec1531e89..6bb15d583e47 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -135,6 +135,8 @@ struct vcpu_svm {
u32 *msrpm;
+ ulong nmi_iret_rip;
+
struct nested_state nested;
bool nmi_singlestep;
@@ -1153,8 +1155,10 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
load_gs_index(svm->host.gs);
#else
+#ifdef CONFIG_X86_32_LAZY_GS
loadsegment(gs, svm->host.gs);
#endif
+#endif
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
}
@@ -2653,6 +2657,7 @@ static int iret_interception(struct vcpu_svm *svm)
++svm->vcpu.stat.nmi_window_exits;
clr_intercept(svm, INTERCEPT_IRET);
svm->vcpu.arch.hflags |= HF_IRET_MASK;
+ svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
return 1;
}
@@ -3474,7 +3479,12 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
svm->int3_injected = 0;
- if (svm->vcpu.arch.hflags & HF_IRET_MASK) {
+ /*
+ * If we've made progress since setting HF_IRET_MASK, we've
+ * executed an IRET and can allow NMI injection.
+ */
+ if ((svm->vcpu.arch.hflags & HF_IRET_MASK)
+ && kvm_rip_read(&svm->vcpu) != svm->nmi_iret_rip) {
svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
}
@@ -3641,19 +3651,30 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
wrmsrl(MSR_GS_BASE, svm->host.gs_base);
#else
loadsegment(fs, svm->host.fs);
+#ifndef CONFIG_X86_32_LAZY_GS
+ loadsegment(gs, svm->host.gs);
+#endif
#endif
reload_tss(vcpu);
local_irq_disable();
- stgi();
-
vcpu->arch.cr2 = svm->vmcb->save.cr2;
vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
+ if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
+ kvm_before_handle_nmi(&svm->vcpu);
+
+ stgi();
+
+ /* Any pending NMI will happen here */
+
+ if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
+ kvm_after_handle_nmi(&svm->vcpu);
+
sync_cr8_to_lapic(vcpu);
svm->next_rip = 0;
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
index fc7a101c4a35..abd86e865be3 100644
--- a/arch/x86/kvm/timer.c
+++ b/arch/x86/kvm/timer.c
@@ -25,7 +25,7 @@ static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
/*
* There is a race window between reading and incrementing, but we do
- * not care about potentially loosing timer events in the !reinject
+ * not care about potentially losing timer events in the !reinject
* case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
* in vcpu_enter_guest.
*/
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index bf89ec2cfb82..5b4cdcbd154c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -93,14 +93,14 @@ module_param(yield_on_hlt, bool, S_IRUGO);
* These 2 parameters are used to config the controls for Pause-Loop Exiting:
* ple_gap: upper bound on the amount of time between two successive
* executions of PAUSE in a loop. Also indicate if ple enabled.
- * According to test, this time is usually small than 41 cycles.
+ * According to test, this time is usually smaller than 128 cycles.
* ple_window: upper bound on the amount of time a guest is allowed to execute
* in a PAUSE loop. Tests indicate that most spinlocks are held for
* less than 2^12 cycles
* Time is measured based on a counter that runs at the same rate as the TSC,
* refer SDM volume 3b section 21.6.13 & 22.1.3.
*/
-#define KVM_VMX_DEFAULT_PLE_GAP 41
+#define KVM_VMX_DEFAULT_PLE_GAP 128
#define KVM_VMX_DEFAULT_PLE_WINDOW 4096
static int ple_gap = KVM_VMX_DEFAULT_PLE_GAP;
module_param(ple_gap, int, S_IRUGO);
@@ -176,11 +176,11 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
return container_of(vcpu, struct vcpu_vmx, vcpu);
}
-static int init_rmode(struct kvm *kvm);
static u64 construct_eptp(unsigned long root_hpa);
static void kvm_cpu_vmxon(u64 addr);
static void kvm_cpu_vmxoff(void);
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
+static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
@@ -1333,19 +1333,25 @@ static __init int vmx_disabled_by_bios(void)
rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
if (msr & FEATURE_CONTROL_LOCKED) {
+ /* launched w/ TXT and VMX disabled */
if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX)
&& tboot_enabled())
return 1;
+ /* launched w/o TXT and VMX only enabled w/ TXT */
if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX)
+ && (msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX)
&& !tboot_enabled()) {
printk(KERN_WARNING "kvm: disable TXT in the BIOS or "
- " activate TXT before enabling KVM\n");
+ "activate TXT before enabling KVM\n");
return 1;
}
+ /* launched w/o TXT and VMX disabled */
+ if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX)
+ && !tboot_enabled())
+ return 1;
}
return 0;
- /* locked but not enabled */
}
static void kvm_cpu_vmxon(u64 addr)
@@ -1683,6 +1689,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
vmx->emulation_required = 1;
vmx->rmode.vm86_active = 0;
+ vmcs_write16(GUEST_TR_SELECTOR, vmx->rmode.tr.selector);
vmcs_writel(GUEST_TR_BASE, vmx->rmode.tr.base);
vmcs_write32(GUEST_TR_LIMIT, vmx->rmode.tr.limit);
vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar);
@@ -1756,6 +1763,19 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmx->emulation_required = 1;
vmx->rmode.vm86_active = 1;
+ /*
+ * Very old userspace does not call KVM_SET_TSS_ADDR before entering
+ * vcpu. Call it here with phys address pointing 16M below 4G.
+ */
+ if (!vcpu->kvm->arch.tss_addr) {
+ printk_once(KERN_WARNING "kvm: KVM_SET_TSS_ADDR need to be "
+ "called before entering vcpu\n");
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+ vmx_set_tss_addr(vcpu->kvm, 0xfeffd000);
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+ }
+
+ vmx->rmode.tr.selector = vmcs_read16(GUEST_TR_SELECTOR);
vmx->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
@@ -1794,7 +1814,6 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
continue_rmode:
kvm_mmu_reset_context(vcpu);
- init_rmode(vcpu->kvm);
}
static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
@@ -2030,23 +2049,40 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
vmcs_writel(GUEST_CR4, hw_cr4);
}
-static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
-{
- struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
- return vmcs_readl(sf->base);
-}
-
static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ struct kvm_save_segment *save;
u32 ar;
+ if (vmx->rmode.vm86_active
+ && (seg == VCPU_SREG_TR || seg == VCPU_SREG_ES
+ || seg == VCPU_SREG_DS || seg == VCPU_SREG_FS
+ || seg == VCPU_SREG_GS)
+ && !emulate_invalid_guest_state) {
+ switch (seg) {
+ case VCPU_SREG_TR: save = &vmx->rmode.tr; break;
+ case VCPU_SREG_ES: save = &vmx->rmode.es; break;
+ case VCPU_SREG_DS: save = &vmx->rmode.ds; break;
+ case VCPU_SREG_FS: save = &vmx->rmode.fs; break;
+ case VCPU_SREG_GS: save = &vmx->rmode.gs; break;
+ default: BUG();
+ }
+ var->selector = save->selector;
+ var->base = save->base;
+ var->limit = save->limit;
+ ar = save->ar;
+ if (seg == VCPU_SREG_TR
+ || var->selector == vmcs_read16(sf->selector))
+ goto use_saved_rmode_seg;
+ }
var->base = vmcs_readl(sf->base);
var->limit = vmcs_read32(sf->limit);
var->selector = vmcs_read16(sf->selector);
ar = vmcs_read32(sf->ar_bytes);
+use_saved_rmode_seg:
if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state)
ar = 0;
var->type = ar & 15;
@@ -2060,6 +2096,18 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
var->unusable = (ar >> 16) & 1;
}
+static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ struct kvm_segment s;
+
+ if (to_vmx(vcpu)->rmode.vm86_active) {
+ vmx_get_segment(vcpu, &s, seg);
+ return s.base;
+ }
+ return vmcs_readl(sf->base);
+}
+
static int vmx_get_cpl(struct kvm_vcpu *vcpu)
{
if (!is_protmode(vcpu))
@@ -2101,6 +2149,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
u32 ar;
if (vmx->rmode.vm86_active && seg == VCPU_SREG_TR) {
+ vmcs_write16(sf->selector, var->selector);
vmx->rmode.tr.selector = var->selector;
vmx->rmode.tr.base = var->base;
vmx->rmode.tr.limit = var->limit;
@@ -2361,11 +2410,12 @@ static bool guest_state_valid(struct kvm_vcpu *vcpu)
static int init_rmode_tss(struct kvm *kvm)
{
- gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
+ gfn_t fn;
u16 data = 0;
- int ret = 0;
- int r;
+ int r, idx, ret = 0;
+ idx = srcu_read_lock(&kvm->srcu);
+ fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE);
if (r < 0)
goto out;
@@ -2389,12 +2439,13 @@ static int init_rmode_tss(struct kvm *kvm)
ret = 1;
out:
+ srcu_read_unlock(&kvm->srcu, idx);
return ret;
}
static int init_rmode_identity_map(struct kvm *kvm)
{
- int i, r, ret;
+ int i, idx, r, ret;
pfn_t identity_map_pfn;
u32 tmp;
@@ -2409,6 +2460,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
return 1;
ret = 0;
identity_map_pfn = kvm->arch.ept_identity_map_addr >> PAGE_SHIFT;
+ idx = srcu_read_lock(&kvm->srcu);
r = kvm_clear_guest_page(kvm, identity_map_pfn, 0, PAGE_SIZE);
if (r < 0)
goto out;
@@ -2424,6 +2476,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
kvm->arch.ept_identity_pagetable_done = true;
ret = 1;
out:
+ srcu_read_unlock(&kvm->srcu, idx);
return ret;
}
@@ -2699,22 +2752,6 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
return 0;
}
-static int init_rmode(struct kvm *kvm)
-{
- int idx, ret = 0;
-
- idx = srcu_read_lock(&kvm->srcu);
- if (!init_rmode_tss(kvm))
- goto exit;
- if (!init_rmode_identity_map(kvm))
- goto exit;
-
- ret = 1;
-exit:
- srcu_read_unlock(&kvm->srcu, idx);
- return ret;
-}
-
static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -2722,10 +2759,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
int ret;
vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP));
- if (!init_rmode(vmx->vcpu.kvm)) {
- ret = -ENOMEM;
- goto out;
- }
vmx->rmode.vm86_active = 0;
@@ -2805,7 +2838,7 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
if (vm_need_tpr_shadow(vmx->vcpu.kvm))
vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
- page_to_phys(vmx->vcpu.arch.apic->regs_page));
+ __pa(vmx->vcpu.arch.apic->regs));
vmcs_write32(TPR_THRESHOLD, 0);
}
@@ -2971,6 +3004,9 @@ static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
if (ret)
return ret;
kvm->arch.tss_addr = addr;
+ if (!init_rmode_tss(kvm))
+ return -ENOMEM;
+
return 0;
}
@@ -3962,7 +3998,7 @@ static void vmx_cancel_injection(struct kvm_vcpu *vcpu)
#define Q "l"
#endif
-static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
+static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3991,6 +4027,7 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
asm(
/* Store host registers */
"push %%"R"dx; push %%"R"bp;"
+ "push %%"R"cx \n\t" /* placeholder for guest rcx */
"push %%"R"cx \n\t"
"cmp %%"R"sp, %c[host_rsp](%0) \n\t"
"je 1f \n\t"
@@ -4032,10 +4069,11 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t"
".Lkvm_vmx_return: "
/* Save guest registers, load host registers, keep flags */
- "xchg %0, (%%"R"sp) \n\t"
+ "mov %0, %c[wordsize](%%"R"sp) \n\t"
+ "pop %0 \n\t"
"mov %%"R"ax, %c[rax](%0) \n\t"
"mov %%"R"bx, %c[rbx](%0) \n\t"
- "push"Q" (%%"R"sp); pop"Q" %c[rcx](%0) \n\t"
+ "pop"Q" %c[rcx](%0) \n\t"
"mov %%"R"dx, %c[rdx](%0) \n\t"
"mov %%"R"si, %c[rsi](%0) \n\t"
"mov %%"R"di, %c[rdi](%0) \n\t"
@@ -4053,7 +4091,7 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
"mov %%cr2, %%"R"ax \n\t"
"mov %%"R"ax, %c[cr2](%0) \n\t"
- "pop %%"R"bp; pop %%"R"bp; pop %%"R"dx \n\t"
+ "pop %%"R"bp; pop %%"R"dx \n\t"
"setbe %c[fail](%0) \n\t"
: : "c"(vmx), "d"((unsigned long)HOST_RSP),
[launched]"i"(offsetof(struct vcpu_vmx, launched)),
@@ -4076,7 +4114,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
[r14]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R14])),
[r15]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_R15])),
#endif
- [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2))
+ [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)),
+ [wordsize]"i"(sizeof(ulong))
: "cc", "memory"
, R"ax", R"bx", R"di", R"si"
#ifdef CONFIG_X86_64
@@ -4183,8 +4222,11 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (!kvm->arch.ept_identity_map_addr)
kvm->arch.ept_identity_map_addr =
VMX_EPT_IDENTITY_PAGETABLE_ADDR;
+ err = -ENOMEM;
if (alloc_identity_pagetable(kvm) != 0)
goto free_vmcs;
+ if (!init_rmode_identity_map(kvm))
+ goto free_vmcs;
}
return &vmx->vcpu;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bcc0efce85bf..58f517b59645 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -81,9 +81,10 @@
* - enable LME and LMA per default on 64 bit KVM
*/
#ifdef CONFIG_X86_64
-static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffafeULL;
+static
+u64 __read_mostly efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA));
#else
-static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL;
+static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
#endif
#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
@@ -360,8 +361,8 @@ void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault)
void kvm_inject_nmi(struct kvm_vcpu *vcpu)
{
+ kvm_make_request(KVM_REQ_NMI, vcpu);
kvm_make_request(KVM_REQ_EVENT, vcpu);
- vcpu->arch.nmi_pending = 1;
}
EXPORT_SYMBOL_GPL(kvm_inject_nmi);
@@ -525,8 +526,10 @@ int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
kvm_x86_ops->set_cr0(vcpu, cr0);
- if ((cr0 ^ old_cr0) & X86_CR0_PG)
+ if ((cr0 ^ old_cr0) & X86_CR0_PG) {
kvm_clear_async_pf_completion_queue(vcpu);
+ kvm_async_pf_hash_reset(vcpu);
+ }
if ((cr0 ^ old_cr0) & update_bits)
kvm_mmu_reset_context(vcpu);
@@ -1017,7 +1020,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
unsigned long flags;
s64 sdiff;
- spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
+ raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
offset = data - native_read_tsc();
ns = get_kernel_ns();
elapsed = ns - kvm->arch.last_tsc_nsec;
@@ -1028,7 +1031,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
/*
* Special case: close write to TSC within 5 seconds of
* another CPU is interpreted as an attempt to synchronize
- * The 5 seconds is to accomodate host load / swapping as
+ * The 5 seconds is to accommodate host load / swapping as
* well as any reset of TSC during the boot process.
*
* In that case, for a reliable TSC, we can match TSC offsets,
@@ -1050,7 +1053,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
kvm->arch.last_tsc_write = data;
kvm->arch.last_tsc_offset = offset;
kvm_x86_ops->write_tsc_offset(vcpu, offset);
- spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+ raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
/* Reset of TSC must disable overshoot protection below */
vcpu->arch.hv_clock.tsc_timestamp = 0;
@@ -1453,6 +1456,14 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
return 0;
}
+static void kvmclock_reset(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.time_page) {
+ kvm_release_page_dirty(vcpu->arch.time_page);
+ vcpu->arch.time_page = NULL;
+ }
+}
+
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
{
switch (msr) {
@@ -1510,10 +1521,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
break;
case MSR_KVM_SYSTEM_TIME_NEW:
case MSR_KVM_SYSTEM_TIME: {
- if (vcpu->arch.time_page) {
- kvm_release_page_dirty(vcpu->arch.time_page);
- vcpu->arch.time_page = NULL;
- }
+ kvmclock_reset(vcpu);
vcpu->arch.time = data;
kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
@@ -1592,6 +1600,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
} else
return set_msr_hyperv(vcpu, msr, data);
break;
+ case MSR_IA32_BBL_CR_CTL3:
+ /* Drop writes to this legacy MSR -- see rdmsr
+ * counterpart for further detail.
+ */
+ pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data);
+ break;
default:
if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr))
return xen_hvm_config(vcpu, data);
@@ -1846,6 +1860,19 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
} else
return get_msr_hyperv(vcpu, msr, pdata);
break;
+ case MSR_IA32_BBL_CR_CTL3:
+ /* This legacy MSR exists but isn't fully documented in current
+ * silicon. It is however accessed by winxp in very narrow
+ * scenarios where it sets bit #19, itself documented as
+ * a "reserved" bit. Best effort attempt to source coherent
+ * read data here should the balance of the register be
+ * interpreted by the guest:
+ *
+ * L2 cache control register 3: 64GB range, 256KB size,
+ * enabled, latency 0x1, configured
+ */
+ data = 0xbe702111;
+ break;
default:
if (!ignore_msrs) {
pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
@@ -2100,8 +2127,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (check_tsc_unstable()) {
kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta);
vcpu->arch.tsc_catchup = 1;
- kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
}
+ kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
if (vcpu->cpu != cpu)
kvm_migrate_timers(vcpu);
vcpu->cpu = cpu;
@@ -2575,9 +2602,6 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu,
if (mce->status & MCI_STATUS_UC) {
if ((vcpu->arch.mcg_status & MCG_STATUS_MCIP) ||
!kvm_read_cr4_bits(vcpu, X86_CR4_MCE)) {
- printk(KERN_DEBUG "kvm: set_mce: "
- "injects mce exception while "
- "previous one is in progress!\n");
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return 0;
}
@@ -2648,8 +2672,6 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
vcpu->arch.interrupt.pending = events->interrupt.injected;
vcpu->arch.interrupt.nr = events->interrupt.nr;
vcpu->arch.interrupt.soft = events->interrupt.soft;
- if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
- kvm_pic_clear_isr_ack(vcpu->kvm);
if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
kvm_x86_ops->set_interrupt_shadow(vcpu,
events->interrupt.shadow);
@@ -4140,8 +4162,8 @@ static unsigned long emulator_get_cached_segment_base(int seg,
return get_segment_base(vcpu, seg);
}
-static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
- struct kvm_vcpu *vcpu)
+static bool emulator_get_cached_descriptor(struct desc_struct *desc, u32 *base3,
+ int seg, struct kvm_vcpu *vcpu)
{
struct kvm_segment var;
@@ -4154,6 +4176,10 @@ static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
var.limit >>= 12;
set_desc_limit(desc, var.limit);
set_desc_base(desc, (unsigned long)var.base);
+#ifdef CONFIG_X86_64
+ if (base3)
+ *base3 = var.base >> 32;
+#endif
desc->type = var.type;
desc->s = var.s;
desc->dpl = var.dpl;
@@ -4166,8 +4192,8 @@ static bool emulator_get_cached_descriptor(struct desc_struct *desc, int seg,
return true;
}
-static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg,
- struct kvm_vcpu *vcpu)
+static void emulator_set_cached_descriptor(struct desc_struct *desc, u32 base3,
+ int seg, struct kvm_vcpu *vcpu)
{
struct kvm_segment var;
@@ -4175,6 +4201,9 @@ static void emulator_set_cached_descriptor(struct desc_struct *desc, int seg,
kvm_get_segment(vcpu, &var, seg);
var.base = get_desc_base(desc);
+#ifdef CONFIG_X86_64
+ var.base |= ((u64)base3) << 32;
+#endif
var.limit = get_desc_limit(desc);
if (desc->g)
var.limit = (var.limit << 12) | 0xfff;
@@ -4390,41 +4419,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
vcpu->arch.emulate_ctxt.have_exception = false;
vcpu->arch.emulate_ctxt.perm_ok = false;
+ vcpu->arch.emulate_ctxt.only_vendor_specific_insn
+ = emulation_type & EMULTYPE_TRAP_UD;
+
r = x86_decode_insn(&vcpu->arch.emulate_ctxt, insn, insn_len);
- if (r == X86EMUL_PROPAGATE_FAULT)
- goto done;
trace_kvm_emulate_insn_start(vcpu);
-
- /* Only allow emulation of specific instructions on #UD
- * (namely VMMCALL, sysenter, sysexit, syscall)*/
- if (emulation_type & EMULTYPE_TRAP_UD) {
- if (!c->twobyte)
- return EMULATE_FAIL;
- switch (c->b) {
- case 0x01: /* VMMCALL */
- if (c->modrm_mod != 3 || c->modrm_rm != 1)
- return EMULATE_FAIL;
- break;
- case 0x34: /* sysenter */
- case 0x35: /* sysexit */
- if (c->modrm_mod != 0 || c->modrm_rm != 0)
- return EMULATE_FAIL;
- break;
- case 0x05: /* syscall */
- if (c->modrm_mod != 0 || c->modrm_rm != 0)
- return EMULATE_FAIL;
- break;
- default:
- return EMULATE_FAIL;
- }
-
- if (!(c->modrm_reg == 0 || c->modrm_reg == 3))
- return EMULATE_FAIL;
- }
-
++vcpu->stat.insn_emulation;
if (r) {
+ if (emulation_type & EMULTYPE_TRAP_UD)
+ return EMULATE_FAIL;
if (reexecute_instruction(vcpu, cr2))
return EMULATE_DONE;
if (emulation_type & EMULTYPE_SKIP)
@@ -4452,7 +4456,6 @@ restart:
return handle_emulation_failure(vcpu);
}
-done:
if (vcpu->arch.emulate_ctxt.have_exception) {
inject_emulated_exception(vcpu);
r = EMULATE_DONE;
@@ -4562,7 +4565,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) {
kvm_for_each_vcpu(i, vcpu, kvm) {
if (vcpu->cpu != freq->cpu)
@@ -4572,7 +4575,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long va
send_ipi = 1;
}
}
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
if (freq->old < freq->new && send_ipi) {
/*
@@ -5185,6 +5188,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 1;
goto out;
}
+ if (kvm_check_request(KVM_REQ_NMI, vcpu))
+ vcpu->arch.nmi_pending = true;
}
r = kvm_mmu_reload(vcpu);
@@ -5213,14 +5218,18 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_load_guest_fpu(vcpu);
kvm_load_guest_xcr0(vcpu);
- atomic_set(&vcpu->guest_mode, 1);
- smp_wmb();
+ vcpu->mode = IN_GUEST_MODE;
+
+ /* We should set ->mode before check ->requests,
+ * see the comment in make_all_cpus_request.
+ */
+ smp_mb();
local_irq_disable();
- if (!atomic_read(&vcpu->guest_mode) || vcpu->requests
+ if (vcpu->mode == EXITING_GUEST_MODE || vcpu->requests
|| need_resched() || signal_pending(current)) {
- atomic_set(&vcpu->guest_mode, 0);
+ vcpu->mode = OUTSIDE_GUEST_MODE;
smp_wmb();
local_irq_enable();
preempt_enable();
@@ -5256,7 +5265,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
- atomic_set(&vcpu->guest_mode, 0);
+ vcpu->mode = OUTSIDE_GUEST_MODE;
smp_wmb();
local_irq_enable();
@@ -5574,7 +5583,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
int mmu_reset_needed = 0;
- int pending_vec, max_bits;
+ int pending_vec, max_bits, idx;
struct desc_ptr dt;
dt.size = sregs->idt.limit;
@@ -5603,10 +5612,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
if (sregs->cr4 & X86_CR4_OSXSAVE)
update_cpuid(vcpu);
+
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
if (!is_long_mode(vcpu) && is_pae(vcpu)) {
load_pdptrs(vcpu, vcpu->arch.walk_mmu, kvm_read_cr3(vcpu));
mmu_reset_needed = 1;
}
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
if (mmu_reset_needed)
kvm_mmu_reset_context(vcpu);
@@ -5617,8 +5629,6 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
if (pending_vec < max_bits) {
kvm_queue_interrupt(vcpu, pending_vec, false);
pr_debug("Set back pending irq %d\n", pending_vec);
- if (irqchip_in_kernel(vcpu->kvm))
- kvm_pic_clear_isr_ack(vcpu->kvm);
}
kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
@@ -5814,10 +5824,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
{
- if (vcpu->arch.time_page) {
- kvm_release_page_dirty(vcpu->arch.time_page);
- vcpu->arch.time_page = NULL;
- }
+ kvmclock_reset(vcpu);
free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
fx_free(vcpu);
@@ -5878,6 +5885,8 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
kvm_make_request(KVM_REQ_EVENT, vcpu);
vcpu->arch.apf.msr_val = 0;
+ kvmclock_reset(vcpu);
+
kvm_clear_async_pf_completion_queue(vcpu);
kvm_async_pf_hash_reset(vcpu);
vcpu->arch.apf.halted = false;
@@ -6005,7 +6014,7 @@ int kvm_arch_init_vm(struct kvm *kvm)
/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
- spin_lock_init(&kvm->arch.tsc_write_lock);
+ raw_spin_lock_init(&kvm->arch.tsc_write_lock);
return 0;
}
@@ -6103,7 +6112,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
int user_alloc)
{
- int npages = mem->memory_size >> PAGE_SHIFT;
+ int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT;
if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
int ret;
@@ -6118,12 +6127,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
"failed to munmap memory\n");
}
+ if (!kvm->arch.n_requested_mmu_pages)
+ nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
+
spin_lock(&kvm->mmu_lock);
- if (!kvm->arch.n_requested_mmu_pages) {
- unsigned int nr_mmu_pages = kvm_mmu_calculate_mmu_pages(kvm);
+ if (nr_mmu_pages)
kvm_mmu_change_mmu_pages(kvm, nr_mmu_pages);
- }
-
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
spin_unlock(&kvm->mmu_lock);
}
@@ -6157,7 +6166,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
me = get_cpu();
if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
- if (atomic_xchg(&vcpu->guest_mode, 0))
+ if (kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE)
smp_send_reschedule(cpu);
put_cpu();
}
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index b9ec1c74943c..1cd608973ce5 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -397,7 +397,7 @@ static void lguest_load_tr_desc(void)
* instead we just use the real "cpuid" instruction. Then I pretty much turned
* off feature bits until the Guest booted. (Don't say that: you'll damage
* lguest sales!) Shut up, inner voice! (Hey, just pointing out that this is
- * hardly future proof.) Noone's listening! They don't like you anyway,
+ * hardly future proof.) No one's listening! They don't like you anyway,
* parenthetic weirdo!
*
* Replacing the cpuid so we can turn features off is great for the kernel, but
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index a460158b5ac5..99e482615195 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -117,7 +117,7 @@ ENDPROC(bad_from_user)
* rdx count
*
* Output:
- * eax uncopied bytes or 0 if successfull.
+ * eax uncopied bytes or 0 if successful.
*/
ENTRY(copy_user_generic_unrolled)
CFI_STARTPROC
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index f0dba36578ea..fb903b758da8 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -1,6 +1,6 @@
/*
- * Copyright 2002,2003 Andi Kleen, SuSE Labs.
- *
+ * Copyright 2002, 2003 Andi Kleen, SuSE Labs.
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details. No warranty for anything given at all.
@@ -11,82 +11,82 @@
/*
* Checksum copy with exception handling.
- * On exceptions src_err_ptr or dst_err_ptr is set to -EFAULT and the
+ * On exceptions src_err_ptr or dst_err_ptr is set to -EFAULT and the
* destination is zeroed.
- *
+ *
* Input
* rdi source
* rsi destination
* edx len (32bit)
- * ecx sum (32bit)
+ * ecx sum (32bit)
* r8 src_err_ptr (int)
* r9 dst_err_ptr (int)
*
* Output
* eax 64bit sum. undefined in case of exception.
- *
- * Wrappers need to take care of valid exception sum and zeroing.
+ *
+ * Wrappers need to take care of valid exception sum and zeroing.
* They also should align source or destination to 8 bytes.
*/
.macro source
10:
- .section __ex_table,"a"
+ .section __ex_table, "a"
.align 8
- .quad 10b,.Lbad_source
+ .quad 10b, .Lbad_source
.previous
.endm
-
+
.macro dest
20:
- .section __ex_table,"a"
+ .section __ex_table, "a"
.align 8
- .quad 20b,.Lbad_dest
+ .quad 20b, .Lbad_dest
.previous
.endm
-
+
.macro ignore L=.Lignore
30:
- .section __ex_table,"a"
+ .section __ex_table, "a"
.align 8
- .quad 30b,\L
+ .quad 30b, \L
.previous
.endm
-
-
+
+
ENTRY(csum_partial_copy_generic)
CFI_STARTPROC
- cmpl $3*64,%edx
- jle .Lignore
+ cmpl $3*64, %edx
+ jle .Lignore
-.Lignore:
- subq $7*8,%rsp
+.Lignore:
+ subq $7*8, %rsp
CFI_ADJUST_CFA_OFFSET 7*8
- movq %rbx,2*8(%rsp)
+ movq %rbx, 2*8(%rsp)
CFI_REL_OFFSET rbx, 2*8
- movq %r12,3*8(%rsp)
+ movq %r12, 3*8(%rsp)
CFI_REL_OFFSET r12, 3*8
- movq %r14,4*8(%rsp)
+ movq %r14, 4*8(%rsp)
CFI_REL_OFFSET r14, 4*8
- movq %r13,5*8(%rsp)
+ movq %r13, 5*8(%rsp)
CFI_REL_OFFSET r13, 5*8
- movq %rbp,6*8(%rsp)
+ movq %rbp, 6*8(%rsp)
CFI_REL_OFFSET rbp, 6*8
- movq %r8,(%rsp)
- movq %r9,1*8(%rsp)
-
- movl %ecx,%eax
- movl %edx,%ecx
+ movq %r8, (%rsp)
+ movq %r9, 1*8(%rsp)
- xorl %r9d,%r9d
- movq %rcx,%r12
+ movl %ecx, %eax
+ movl %edx, %ecx
- shrq $6,%r12
- jz .Lhandle_tail /* < 64 */
+ xorl %r9d, %r9d
+ movq %rcx, %r12
+
+ shrq $6, %r12
+ jz .Lhandle_tail /* < 64 */
clc
-
+
/* main loop. clear in 64 byte blocks */
/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
/* r11: temp3, rdx: temp4, r12 loopcnt */
@@ -94,156 +94,156 @@ ENTRY(csum_partial_copy_generic)
.p2align 4
.Lloop:
source
- movq (%rdi),%rbx
+ movq (%rdi), %rbx
source
- movq 8(%rdi),%r8
+ movq 8(%rdi), %r8
source
- movq 16(%rdi),%r11
+ movq 16(%rdi), %r11
source
- movq 24(%rdi),%rdx
+ movq 24(%rdi), %rdx
source
- movq 32(%rdi),%r10
+ movq 32(%rdi), %r10
source
- movq 40(%rdi),%rbp
+ movq 40(%rdi), %rbp
source
- movq 48(%rdi),%r14
+ movq 48(%rdi), %r14
source
- movq 56(%rdi),%r13
-
+ movq 56(%rdi), %r13
+
ignore 2f
prefetcht0 5*64(%rdi)
-2:
- adcq %rbx,%rax
- adcq %r8,%rax
- adcq %r11,%rax
- adcq %rdx,%rax
- adcq %r10,%rax
- adcq %rbp,%rax
- adcq %r14,%rax
- adcq %r13,%rax
+2:
+ adcq %rbx, %rax
+ adcq %r8, %rax
+ adcq %r11, %rax
+ adcq %rdx, %rax
+ adcq %r10, %rax
+ adcq %rbp, %rax
+ adcq %r14, %rax
+ adcq %r13, %rax
decl %r12d
-
+
dest
- movq %rbx,(%rsi)
+ movq %rbx, (%rsi)
dest
- movq %r8,8(%rsi)
+ movq %r8, 8(%rsi)
dest
- movq %r11,16(%rsi)
+ movq %r11, 16(%rsi)
dest
- movq %rdx,24(%rsi)
+ movq %rdx, 24(%rsi)
dest
- movq %r10,32(%rsi)
+ movq %r10, 32(%rsi)
dest
- movq %rbp,40(%rsi)
+ movq %rbp, 40(%rsi)
dest
- movq %r14,48(%rsi)
+ movq %r14, 48(%rsi)
dest
- movq %r13,56(%rsi)
-
+ movq %r13, 56(%rsi)
+
3:
-
- leaq 64(%rdi),%rdi
- leaq 64(%rsi),%rsi
- jnz .Lloop
+ leaq 64(%rdi), %rdi
+ leaq 64(%rsi), %rsi
- adcq %r9,%rax
+ jnz .Lloop
- /* do last upto 56 bytes */
+ adcq %r9, %rax
+
+ /* do last up to 56 bytes */
.Lhandle_tail:
/* ecx: count */
- movl %ecx,%r10d
- andl $63,%ecx
- shrl $3,%ecx
- jz .Lfold
+ movl %ecx, %r10d
+ andl $63, %ecx
+ shrl $3, %ecx
+ jz .Lfold
clc
.p2align 4
-.Lloop_8:
+.Lloop_8:
source
- movq (%rdi),%rbx
- adcq %rbx,%rax
+ movq (%rdi), %rbx
+ adcq %rbx, %rax
decl %ecx
dest
- movq %rbx,(%rsi)
- leaq 8(%rsi),%rsi /* preserve carry */
- leaq 8(%rdi),%rdi
+ movq %rbx, (%rsi)
+ leaq 8(%rsi), %rsi /* preserve carry */
+ leaq 8(%rdi), %rdi
jnz .Lloop_8
- adcq %r9,%rax /* add in carry */
+ adcq %r9, %rax /* add in carry */
.Lfold:
/* reduce checksum to 32bits */
- movl %eax,%ebx
- shrq $32,%rax
- addl %ebx,%eax
- adcl %r9d,%eax
+ movl %eax, %ebx
+ shrq $32, %rax
+ addl %ebx, %eax
+ adcl %r9d, %eax
- /* do last upto 6 bytes */
+ /* do last up to 6 bytes */
.Lhandle_7:
- movl %r10d,%ecx
- andl $7,%ecx
- shrl $1,%ecx
+ movl %r10d, %ecx
+ andl $7, %ecx
+ shrl $1, %ecx
jz .Lhandle_1
- movl $2,%edx
- xorl %ebx,%ebx
- clc
+ movl $2, %edx
+ xorl %ebx, %ebx
+ clc
.p2align 4
-.Lloop_1:
+.Lloop_1:
source
- movw (%rdi),%bx
- adcl %ebx,%eax
+ movw (%rdi), %bx
+ adcl %ebx, %eax
decl %ecx
dest
- movw %bx,(%rsi)
- leaq 2(%rdi),%rdi
- leaq 2(%rsi),%rsi
+ movw %bx, (%rsi)
+ leaq 2(%rdi), %rdi
+ leaq 2(%rsi), %rsi
jnz .Lloop_1
- adcl %r9d,%eax /* add in carry */
-
+ adcl %r9d, %eax /* add in carry */
+
/* handle last odd byte */
.Lhandle_1:
- testl $1,%r10d
+ testl $1, %r10d
jz .Lende
- xorl %ebx,%ebx
+ xorl %ebx, %ebx
source
- movb (%rdi),%bl
+ movb (%rdi), %bl
dest
- movb %bl,(%rsi)
- addl %ebx,%eax
- adcl %r9d,%eax /* carry */
-
+ movb %bl, (%rsi)
+ addl %ebx, %eax
+ adcl %r9d, %eax /* carry */
+
CFI_REMEMBER_STATE
.Lende:
- movq 2*8(%rsp),%rbx
+ movq 2*8(%rsp), %rbx
CFI_RESTORE rbx
- movq 3*8(%rsp),%r12
+ movq 3*8(%rsp), %r12
CFI_RESTORE r12
- movq 4*8(%rsp),%r14
+ movq 4*8(%rsp), %r14
CFI_RESTORE r14
- movq 5*8(%rsp),%r13
+ movq 5*8(%rsp), %r13
CFI_RESTORE r13
- movq 6*8(%rsp),%rbp
+ movq 6*8(%rsp), %rbp
CFI_RESTORE rbp
- addq $7*8,%rsp
+ addq $7*8, %rsp
CFI_ADJUST_CFA_OFFSET -7*8
ret
CFI_RESTORE_STATE
/* Exception handlers. Very simple, zeroing is done in the wrappers */
.Lbad_source:
- movq (%rsp),%rax
- testq %rax,%rax
+ movq (%rsp), %rax
+ testq %rax, %rax
jz .Lende
- movl $-EFAULT,(%rax)
+ movl $-EFAULT, (%rax)
jmp .Lende
-
+
.Lbad_dest:
- movq 8(%rsp),%rax
- testq %rax,%rax
- jz .Lende
- movl $-EFAULT,(%rax)
+ movq 8(%rsp), %rax
+ testq %rax, %rax
+ jz .Lende
+ movl $-EFAULT, (%rax)
jmp .Lende
CFI_ENDPROC
ENDPROC(csum_partial_copy_generic)
diff --git a/arch/x86/lib/csum-partial_64.c b/arch/x86/lib/csum-partial_64.c
index bf51144d97e1..9845371c5c36 100644
--- a/arch/x86/lib/csum-partial_64.c
+++ b/arch/x86/lib/csum-partial_64.c
@@ -84,7 +84,7 @@ static unsigned do_csum(const unsigned char *buff, unsigned len)
count64--;
}
- /* last upto 7 8byte blocks */
+ /* last up to 7 8byte blocks */
count %= 8;
while (count) {
asm("addq %1,%0\n\t"
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index 069ce7c37c01..d4203988504a 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -326,7 +326,7 @@ try_again:
if (mm->free_area_cache < len)
goto fail;
- /* either no address requested or cant fit in requested address hole */
+ /* either no address requested or can't fit in requested address hole */
addr = (mm->free_area_cache - len) & huge_page_mask(h);
do {
/*
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 73ad7ebd6e9c..80088f994193 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -917,7 +917,7 @@ static void mark_nxdata_nx(void)
{
/*
* When this called, init has already been executed and released,
- * so everything past _etext sould be NX.
+ * so everything past _etext should be NX.
*/
unsigned long start = PFN_ALIGN(_etext);
/*
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 9ec0f209a6a4..e8c00cc72033 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -446,7 +446,7 @@ static int __init numa_alloc_distance(void)
* @distance: NUMA distance
*
* Set the distance from node @from to @to to @distance. If distance table
- * doesn't exist, one which is large enough to accomodate all the currently
+ * doesn't exist, one which is large enough to accommodate all the currently
* known nodes will be created.
*
* If such table cannot be allocated, a warning is printed and further
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 90825f2eb0f4..f9e526742fa1 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -310,7 +310,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
* these shared mappings are made of small page mappings.
* Thus this don't enforce !RW mapping for small page kernel
* text mapping logic will help Linux Xen parvirt guest boot
- * aswell.
+ * as well.
*/
if (lookup_address(address, &level) && (level != PG_LEVEL_4K))
pgprot_val(forbidden) |= _PAGE_RW;
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 0113d19c8aa6..8573b83a63d0 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -168,8 +168,7 @@ void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd)
* section 8.1: in PAE mode we explicitly have to flush the
* TLB via cr3 if the top-level pgd is changed...
*/
- if (mm == current->active_mm)
- write_cr3(read_cr3());
+ flush_tlb_mm(mm);
}
#else /* !CONFIG_X86_PAE */
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 72cbec14d783..2d49d4e19a36 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -126,7 +126,7 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
if (!user_mode_vm(regs)) {
unsigned long stack = kernel_stack_pointer(regs);
if (depth)
- dump_trace(NULL, regs, (unsigned long *)stack,
+ dump_trace(NULL, regs, (unsigned long *)stack, 0,
&backtrace_ops, &depth);
return;
}
diff --git a/arch/x86/oprofile/op_model_p4.c b/arch/x86/oprofile/op_model_p4.c
index 9fadec074142..98ab13058f89 100644
--- a/arch/x86/oprofile/op_model_p4.c
+++ b/arch/x86/oprofile/op_model_p4.c
@@ -50,7 +50,7 @@ static inline void setup_num_counters(void)
#endif
}
-static int inline addr_increment(void)
+static inline int addr_increment(void)
{
#ifdef CONFIG_SMP
return smp_num_siblings == 2 ? 2 : 1;
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index b1805b78842f..494f2e7ea2b4 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -241,7 +241,7 @@ void __init pcibios_resource_survey(void)
e820_reserve_resources_late();
/*
* Insert the IO APIC resources after PCI initialization has
- * occured to handle IO APICS that are mapped in on a BAR in
+ * occurred to handle IO APICS that are mapped in on a BAR in
* PCI space, but before trying to assign unassigned pci res.
*/
ioapic_insert_resources();
@@ -304,7 +304,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
/*
* ioremap() and ioremap_nocache() defaults to UC MINUS for now.
* To avoid attribute conflicts, request UC MINUS here
- * aswell.
+ * as well.
*/
prot |= _PAGE_CACHE_UC_MINUS;
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 8c4085a95ef1..e37b407a0ee8 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -50,7 +50,7 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
name = "ioapic-level";
}
- irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
+ irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name);
printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
@@ -237,6 +237,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
{
int rc;
int share = 1;
+ int pirq;
u8 gsi;
rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi);
@@ -246,13 +247,21 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
return rc;
}
+ rc = xen_allocate_pirq_gsi(gsi);
+ if (rc < 0) {
+ dev_warn(&dev->dev, "Xen PCI: failed to allocate a PIRQ for GSI%d: %d\n",
+ gsi, rc);
+ return rc;
+ }
+ pirq = rc;
+
if (gsi < NR_IRQS_LEGACY)
share = 0;
- rc = xen_allocate_pirq(gsi, share, "pcifront");
+ rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront");
if (rc < 0) {
- dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n",
- gsi, rc);
+ dev_warn(&dev->dev, "Xen PCI: failed to bind GSI%d (PIRQ%d) to IRQ: %d\n",
+ gsi, pirq, rc);
return rc;
}
@@ -309,7 +318,7 @@ int __init pci_xen_hvm_init(void)
#ifdef CONFIG_XEN_DOM0
static int xen_register_pirq(u32 gsi, int triggering)
{
- int rc, irq;
+ int rc, pirq, irq = -1;
struct physdev_map_pirq map_irq;
int shareable = 0;
char *name;
@@ -325,17 +334,20 @@ static int xen_register_pirq(u32 gsi, int triggering)
name = "ioapic-level";
}
- irq = xen_allocate_pirq(gsi, shareable, name);
-
- printk(KERN_DEBUG "xen: --> irq=%d\n", irq);
+ pirq = xen_allocate_pirq_gsi(gsi);
+ if (pirq < 0)
+ goto out;
+ irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name);
if (irq < 0)
goto out;
+ printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d\n", pirq, irq);
+
map_irq.domid = DOMID_SELF;
map_irq.type = MAP_PIRQ_TYPE_GSI;
map_irq.index = gsi;
- map_irq.pirq = irq;
+ map_irq.pirq = pirq;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
if (rc) {
@@ -422,13 +434,18 @@ static int __init pci_xen_initial_domain(void)
void __init xen_setup_pirqs(void)
{
- int irq;
+ int pirq, irq;
pci_xen_initial_domain();
if (0 == nr_ioapics) {
- for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
- xen_allocate_pirq(irq, 0, "xt-pic");
+ for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
+ pirq = xen_allocate_pirq_gsi(irq);
+ if (WARN(pirq < 0,
+ "Could not allocate PIRQ for legacy interrupt\n"))
+ break;
+ irq = xen_bind_pirq_gsi_to_irq(irq, pirq, 0, "xt-pic");
+ }
return;
}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 3f6f3347aa17..39ee7182fd18 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -79,8 +79,7 @@
/*
* Protects atomic reservation decrease/increase against concurrent increases.
- * Also protects non-atomic updates of current_pages and driver_pages, and
- * balloon lists.
+ * Also protects non-atomic updates of current_pages and balloon lists.
*/
DEFINE_SPINLOCK(xen_reservation_lock);
@@ -1745,7 +1744,7 @@ static void convert_pfn_mfn(void *v)
}
/*
- * Set up the inital kernel pagetable.
+ * Set up the initial kernel pagetable.
*
* We can construct this by grafting the Xen provided pagetable into
* head_64.S's preconstructed pagetables. We copy the Xen L2's into
diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
index 095cd8084164..42b7feba71b7 100644
--- a/arch/xtensa/configs/s6105_defconfig
+++ b/arch/xtensa/configs/s6105_defconfig
@@ -598,7 +598,7 @@ CONFIG_DEBUG_NOMMU_REGIONS=y
# CONFIG_CONTEXT_SWITCH_TRACER is not set
# CONFIG_BOOT_TRACER is not set
# CONFIG_TRACE_BRANCH_PROFILING is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
#
diff --git a/block/blk-core.c b/block/blk-core.c
index 518dd423a5fe..a63336d49f30 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2045,9 +2045,26 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
if (error && req->cmd_type == REQ_TYPE_FS &&
!(req->cmd_flags & REQ_QUIET)) {
- printk(KERN_ERR "end_request: I/O error, dev %s, sector %llu\n",
- req->rq_disk ? req->rq_disk->disk_name : "?",
- (unsigned long long)blk_rq_pos(req));
+ char *error_type;
+
+ switch (error) {
+ case -ENOLINK:
+ error_type = "recoverable transport";
+ break;
+ case -EREMOTEIO:
+ error_type = "critical target";
+ break;
+ case -EBADE:
+ error_type = "critical nexus";
+ break;
+ case -EIO:
+ default:
+ error_type = "I/O";
+ break;
+ }
+ printk(KERN_ERR "end_request: %s error, dev %s, sector %llu\n",
+ error_type, req->rq_disk ? req->rq_disk->disk_name : "?",
+ (unsigned long long)blk_rq_pos(req));
}
blk_account_io_completion(req, nr_bytes);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 9bfb71ff3a6a..177c7d156933 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -117,4 +117,6 @@ source "drivers/staging/Kconfig"
source "drivers/platform/Kconfig"
source "drivers/clk/Kconfig"
+
+source "drivers/hwspinlock/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index b423bb16c3a8..3f135b6fb014 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -117,3 +117,5 @@ obj-y += platform/
obj-y += ieee802154/
#common clk code
obj-y += clk/
+
+obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index e7df019d29d4..6d2bb2524b6e 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -13,16 +13,17 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/amba/bus.h>
#include <asm/irq.h>
#include <asm/sizes.h>
-#define to_amba_device(d) container_of(d, struct amba_device, dev)
#define to_amba_driver(d) container_of(d, struct amba_driver, drv)
-static struct amba_id *
-amba_lookup(struct amba_id *table, struct amba_device *dev)
+static const struct amba_id *
+amba_lookup(const struct amba_id *table, struct amba_device *dev)
{
int ret = 0;
@@ -57,26 +58,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
#define amba_uevent NULL
#endif
-static int amba_suspend(struct device *dev, pm_message_t state)
-{
- struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = 0;
-
- if (dev->driver && drv->suspend)
- ret = drv->suspend(to_amba_device(dev), state);
- return ret;
-}
-
-static int amba_resume(struct device *dev)
-{
- struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = 0;
-
- if (dev->driver && drv->resume)
- ret = drv->resume(to_amba_device(dev));
- return ret;
-}
-
#define amba_attr_func(name,fmt,arg...) \
static ssize_t name##_show(struct device *_dev, \
struct device_attribute *attr, char *buf) \
@@ -102,17 +83,330 @@ static struct device_attribute amba_dev_attrs[] = {
__ATTR_NULL,
};
+#ifdef CONFIG_PM_SLEEP
+
+static int amba_legacy_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct amba_driver *adrv = to_amba_driver(dev->driver);
+ struct amba_device *adev = to_amba_device(dev);
+ int ret = 0;
+
+ if (dev->driver && adrv->suspend)
+ ret = adrv->suspend(adev, mesg);
+
+ return ret;
+}
+
+static int amba_legacy_resume(struct device *dev)
+{
+ struct amba_driver *adrv = to_amba_driver(dev->driver);
+ struct amba_device *adev = to_amba_device(dev);
+ int ret = 0;
+
+ if (dev->driver && adrv->resume)
+ ret = adrv->resume(adev);
+
+ return ret;
+}
+
+static int amba_pm_prepare(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (drv && drv->pm && drv->pm->prepare)
+ ret = drv->pm->prepare(dev);
+
+ return ret;
+}
+
+static void amba_pm_complete(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+
+ if (drv && drv->pm && drv->pm->complete)
+ drv->pm->complete(dev);
+}
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define amba_pm_prepare NULL
+#define amba_pm_complete NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_SUSPEND
+
+static int amba_pm_suspend(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->suspend)
+ ret = drv->pm->suspend(dev);
+ } else {
+ ret = amba_legacy_suspend(dev, PMSG_SUSPEND);
+ }
+
+ return ret;
+}
+
+static int amba_pm_suspend_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->suspend_noirq)
+ ret = drv->pm->suspend_noirq(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_resume(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->resume)
+ ret = drv->pm->resume(dev);
+ } else {
+ ret = amba_legacy_resume(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_resume_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->resume_noirq)
+ ret = drv->pm->resume_noirq(dev);
+ }
+
+ return ret;
+}
+
+#else /* !CONFIG_SUSPEND */
+
+#define amba_pm_suspend NULL
+#define amba_pm_resume NULL
+#define amba_pm_suspend_noirq NULL
+#define amba_pm_resume_noirq NULL
+
+#endif /* !CONFIG_SUSPEND */
+
+#ifdef CONFIG_HIBERNATION
+
+static int amba_pm_freeze(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->freeze)
+ ret = drv->pm->freeze(dev);
+ } else {
+ ret = amba_legacy_suspend(dev, PMSG_FREEZE);
+ }
+
+ return ret;
+}
+
+static int amba_pm_freeze_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->freeze_noirq)
+ ret = drv->pm->freeze_noirq(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_thaw(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->thaw)
+ ret = drv->pm->thaw(dev);
+ } else {
+ ret = amba_legacy_resume(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_thaw_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->thaw_noirq)
+ ret = drv->pm->thaw_noirq(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_poweroff(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->poweroff)
+ ret = drv->pm->poweroff(dev);
+ } else {
+ ret = amba_legacy_suspend(dev, PMSG_HIBERNATE);
+ }
+
+ return ret;
+}
+
+static int amba_pm_poweroff_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->poweroff_noirq)
+ ret = drv->pm->poweroff_noirq(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_restore(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->restore)
+ ret = drv->pm->restore(dev);
+ } else {
+ ret = amba_legacy_resume(dev);
+ }
+
+ return ret;
+}
+
+static int amba_pm_restore_noirq(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (!drv)
+ return 0;
+
+ if (drv->pm) {
+ if (drv->pm->restore_noirq)
+ ret = drv->pm->restore_noirq(dev);
+ }
+
+ return ret;
+}
+
+#else /* !CONFIG_HIBERNATION */
+
+#define amba_pm_freeze NULL
+#define amba_pm_thaw NULL
+#define amba_pm_poweroff NULL
+#define amba_pm_restore NULL
+#define amba_pm_freeze_noirq NULL
+#define amba_pm_thaw_noirq NULL
+#define amba_pm_poweroff_noirq NULL
+#define amba_pm_restore_noirq NULL
+
+#endif /* !CONFIG_HIBERNATION */
+
+#ifdef CONFIG_PM
+
+static const struct dev_pm_ops amba_pm = {
+ .prepare = amba_pm_prepare,
+ .complete = amba_pm_complete,
+ .suspend = amba_pm_suspend,
+ .resume = amba_pm_resume,
+ .freeze = amba_pm_freeze,
+ .thaw = amba_pm_thaw,
+ .poweroff = amba_pm_poweroff,
+ .restore = amba_pm_restore,
+ .suspend_noirq = amba_pm_suspend_noirq,
+ .resume_noirq = amba_pm_resume_noirq,
+ .freeze_noirq = amba_pm_freeze_noirq,
+ .thaw_noirq = amba_pm_thaw_noirq,
+ .poweroff_noirq = amba_pm_poweroff_noirq,
+ .restore_noirq = amba_pm_restore_noirq,
+ SET_RUNTIME_PM_OPS(
+ pm_generic_runtime_suspend,
+ pm_generic_runtime_resume,
+ pm_generic_runtime_idle
+ )
+};
+
+#define AMBA_PM (&amba_pm)
+
+#else /* !CONFIG_PM */
+
+#define AMBA_PM NULL
+
+#endif /* !CONFIG_PM */
+
/*
* Primecells are part of the Advanced Microcontroller Bus Architecture,
* so we call the bus "amba".
*/
-static struct bus_type amba_bustype = {
+struct bus_type amba_bustype = {
.name = "amba",
.dev_attrs = amba_dev_attrs,
.match = amba_match,
.uevent = amba_uevent,
- .suspend = amba_suspend,
- .resume = amba_resume,
+ .pm = AMBA_PM,
};
static int __init amba_init(void)
@@ -188,7 +482,7 @@ static int amba_probe(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *pcdrv = to_amba_driver(dev->driver);
- struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
+ const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
int ret;
do {
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index ef3ce26bb1f0..0f91e583892e 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -6,7 +6,7 @@
* Author: Ashish Kalra <ashish.kalra@freescale.com>
* Li Yang <leoli@freescale.com>
*
- * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2007, 2011 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 the
@@ -157,7 +157,8 @@ enum {
IE_ON_SINGL_DEVICE_ERR | IE_ON_CMD_COMPLETE,
EXT_INDIRECT_SEG_PRD_FLAG = (1 << 31),
- DATA_SNOOP_ENABLE = (1 << 22),
+ DATA_SNOOP_ENABLE_V1 = (1 << 22),
+ DATA_SNOOP_ENABLE_V2 = (1 << 28),
};
/*
@@ -260,6 +261,7 @@ struct sata_fsl_host_priv {
void __iomem *ssr_base;
void __iomem *csr_base;
int irq;
+ int data_snoop;
};
static inline unsigned int sata_fsl_tag(unsigned int tag,
@@ -312,7 +314,8 @@ static void sata_fsl_setup_cmd_hdr_entry(struct sata_fsl_port_priv *pp,
}
static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
- u32 *ttl, dma_addr_t cmd_desc_paddr)
+ u32 *ttl, dma_addr_t cmd_desc_paddr,
+ int data_snoop)
{
struct scatterlist *sg;
unsigned int num_prde = 0;
@@ -362,8 +365,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
ttl_dwords += sg_len;
prd->dba = cpu_to_le32(sg_addr);
- prd->ddc_and_ext =
- cpu_to_le32(DATA_SNOOP_ENABLE | (sg_len & ~0x03));
+ prd->ddc_and_ext = cpu_to_le32(data_snoop | (sg_len & ~0x03));
VPRINTK("sg_fill, ttl=%d, dba=0x%x, ddc=0x%x\n",
ttl_dwords, prd->dba, prd->ddc_and_ext);
@@ -378,7 +380,7 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
/* set indirect extension flag along with indirect ext. size */
prd_ptr_to_indirect_ext->ddc_and_ext =
cpu_to_le32((EXT_INDIRECT_SEG_PRD_FLAG |
- DATA_SNOOP_ENABLE |
+ data_snoop |
(indirect_ext_segment_sz & ~0x03)));
}
@@ -421,7 +423,8 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
if (qc->flags & ATA_QCFLAG_DMAMAP)
num_prde = sata_fsl_fill_sg(qc, (void *)cd,
- &ttl_dwords, cd_paddr);
+ &ttl_dwords, cd_paddr,
+ host_priv->data_snoop);
if (qc->tf.protocol == ATA_PROT_NCQ)
desc_info |= FPDMA_QUEUED_CMD;
@@ -1349,6 +1352,11 @@ static int sata_fsl_probe(struct platform_device *ofdev)
}
host_priv->irq = irq;
+ if (of_device_is_compatible(ofdev->dev.of_node, "fsl,pq-sata-v2"))
+ host_priv->data_snoop = DATA_SNOOP_ENABLE_V2;
+ else
+ host_priv->data_snoop = DATA_SNOOP_ENABLE_V1;
+
/* allocate host structure */
host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);
@@ -1431,6 +1439,9 @@ static struct of_device_id fsl_sata_match[] = {
{
.compatible = "fsl,pq-sata",
},
+ {
+ .compatible = "fsl,pq-sata-v2",
+ },
{},
};
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 7d912baf01d4..049650d42c88 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1031,7 +1031,7 @@ static int fs_open(struct atm_vcc *atm_vcc)
/* We now use the "submit_command" function to submit commands to
the firestream. There is a define up near the definition of
that routine that switches this routine between immediate write
- to the immediate comamnd registers and queuing the commands in
+ to the immediate command registers and queuing the commands in
the HPTXQ for execution. This last technique might be more
efficient if we know we're going to submit a whole lot of
commands in one go, but this driver is not setup to be able to
diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h
index a0b403a6b4ed..e5565fbaeb30 100644
--- a/drivers/block/smart1,2.h
+++ b/drivers/block/smart1,2.h
@@ -95,7 +95,7 @@ static unsigned long smart4_completed(ctlr_info_t *h)
/*
* This hardware returns interrupt pending at a different place and
* it does not tell us if the fifo is empty, we will have check
- * that by getting a 0 back from the comamnd_completed call.
+ * that by getting a 0 back from the command_completed call.
*/
static unsigned long smart4_intr_pending(ctlr_info_t *h)
{
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7e0ebd4a1a74..866811428e20 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -433,7 +433,7 @@ static void btusb_isoc_complete(struct urb *urb)
}
}
-static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
+static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
{
int i, offset = 0;
@@ -780,7 +780,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
}
}
-static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
+static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
{
struct btusb_data *data = hdev->driver_data;
struct usb_interface *intf = data->isoc;
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index a348c7e9aa0b..dd1d143eb8ea 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -39,7 +39,7 @@ static struct hwrng nmk_rng = {
.read = nmk_rng_read,
};
-static int nmk_rng_probe(struct amba_device *dev, struct amba_id *id)
+static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
{
void __iomem *base;
int ret;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 5cb4d09919d6..0f17ad8585d7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1371,7 +1371,7 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg)
goto out;
if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(cpu_policy, pmsg);
+ ret = cpufreq_driver->suspend(cpu_policy);
if (ret)
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
"step on CPU %u\n", cpu_policy->cpu);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 94284c8473b1..33b56e5c5c14 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -76,8 +76,7 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
/*
- * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
- * different CPUs. It protects dbs_enable in governor start/stop.
+ * dbs_mutex protects dbs_enable in governor start/stop.
*/
static DEFINE_MUTEX(dbs_mutex);
@@ -116,7 +115,7 @@ static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
if (wall)
*wall = (cputime64_t)jiffies_to_usecs(cur_wall_time);
- return (cputime64_t)jiffies_to_usecs(idle_time);;
+ return (cputime64_t)jiffies_to_usecs(idle_time);
}
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
@@ -162,21 +161,12 @@ static struct notifier_block dbs_cpufreq_notifier_block = {
};
/************************** sysfs interface ************************/
-static ssize_t show_sampling_rate_max(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- printk_once(KERN_INFO "CPUFREQ: conservative sampling_rate_max "
- "sysfs file is deprecated - used by: %s\n", current->comm);
- return sprintf(buf, "%u\n", -1U);
-}
-
static ssize_t show_sampling_rate_min(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", min_sampling_rate);
}
-define_one_global_ro(sampling_rate_max);
define_one_global_ro(sampling_rate_min);
/* cpufreq_conservative Governor Tunables */
@@ -193,33 +183,6 @@ show_one(down_threshold, down_threshold);
show_one(ignore_nice_load, ignore_nice);
show_one(freq_step, freq_step);
-/*** delete after deprecation time ***/
-#define DEPRECATION_MSG(file_name) \
- printk_once(KERN_INFO "CPUFREQ: Per core conservative sysfs " \
- "interface is deprecated - " #file_name "\n");
-
-#define show_one_old(file_name) \
-static ssize_t show_##file_name##_old \
-(struct cpufreq_policy *unused, char *buf) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core conservative sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return show_##file_name(NULL, NULL, buf); \
-}
-show_one_old(sampling_rate);
-show_one_old(sampling_down_factor);
-show_one_old(up_threshold);
-show_one_old(down_threshold);
-show_one_old(ignore_nice_load);
-show_one_old(freq_step);
-show_one_old(sampling_rate_min);
-show_one_old(sampling_rate_max);
-
-cpufreq_freq_attr_ro_old(sampling_rate_min);
-cpufreq_freq_attr_ro_old(sampling_rate_max);
-
-/*** delete after deprecation time ***/
-
static ssize_t store_sampling_down_factor(struct kobject *a,
struct attribute *b,
const char *buf, size_t count)
@@ -231,10 +194,7 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.sampling_down_factor = input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -248,10 +208,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
if (ret != 1)
return -EINVAL;
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -262,16 +219,11 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
int ret;
ret = sscanf(buf, "%u", &input);
- mutex_lock(&dbs_mutex);
if (ret != 1 || input > 100 ||
- input <= dbs_tuners_ins.down_threshold) {
- mutex_unlock(&dbs_mutex);
+ input <= dbs_tuners_ins.down_threshold)
return -EINVAL;
- }
dbs_tuners_ins.up_threshold = input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -282,17 +234,12 @@ static ssize_t store_down_threshold(struct kobject *a, struct attribute *b,
int ret;
ret = sscanf(buf, "%u", &input);
- mutex_lock(&dbs_mutex);
/* cannot be lower than 11 otherwise freq will not fall */
if (ret != 1 || input < 11 || input > 100 ||
- input >= dbs_tuners_ins.up_threshold) {
- mutex_unlock(&dbs_mutex);
+ input >= dbs_tuners_ins.up_threshold)
return -EINVAL;
- }
dbs_tuners_ins.down_threshold = input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -311,11 +258,9 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
if (input > 1)
input = 1;
- mutex_lock(&dbs_mutex);
- if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
- mutex_unlock(&dbs_mutex);
+ if (input == dbs_tuners_ins.ignore_nice) /* nothing to do */
return count;
- }
+
dbs_tuners_ins.ignore_nice = input;
/* we need to re-evaluate prev_cpu_idle */
@@ -327,8 +272,6 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
if (dbs_tuners_ins.ignore_nice)
dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
}
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -347,10 +290,7 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
/* no need to test here if freq_step is zero as the user might actually
* want this, they would be crazy though :) */
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.freq_step = input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -362,7 +302,6 @@ define_one_global_rw(ignore_nice_load);
define_one_global_rw(freq_step);
static struct attribute *dbs_attributes[] = {
- &sampling_rate_max.attr,
&sampling_rate_min.attr,
&sampling_rate.attr,
&sampling_down_factor.attr,
@@ -378,49 +317,6 @@ static struct attribute_group dbs_attr_group = {
.name = "conservative",
};
-/*** delete after deprecation time ***/
-
-#define write_one_old(file_name) \
-static ssize_t store_##file_name##_old \
-(struct cpufreq_policy *unused, const char *buf, size_t count) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core conservative sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return store_##file_name(NULL, NULL, buf, count); \
-}
-write_one_old(sampling_rate);
-write_one_old(sampling_down_factor);
-write_one_old(up_threshold);
-write_one_old(down_threshold);
-write_one_old(ignore_nice_load);
-write_one_old(freq_step);
-
-cpufreq_freq_attr_rw_old(sampling_rate);
-cpufreq_freq_attr_rw_old(sampling_down_factor);
-cpufreq_freq_attr_rw_old(up_threshold);
-cpufreq_freq_attr_rw_old(down_threshold);
-cpufreq_freq_attr_rw_old(ignore_nice_load);
-cpufreq_freq_attr_rw_old(freq_step);
-
-static struct attribute *dbs_attributes_old[] = {
- &sampling_rate_max_old.attr,
- &sampling_rate_min_old.attr,
- &sampling_rate_old.attr,
- &sampling_down_factor_old.attr,
- &up_threshold_old.attr,
- &down_threshold_old.attr,
- &ignore_nice_load_old.attr,
- &freq_step_old.attr,
- NULL
-};
-
-static struct attribute_group dbs_attr_group_old = {
- .attrs = dbs_attributes_old,
- .name = "conservative",
-};
-
-/*** delete after deprecation time ***/
-
/************************** sysfs end ************************/
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
@@ -596,12 +492,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex);
- rc = sysfs_create_group(&policy->kobj, &dbs_attr_group_old);
- if (rc) {
- mutex_unlock(&dbs_mutex);
- return rc;
- }
-
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cs_cpu_dbs_info, j);
@@ -664,7 +554,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_timer_exit(this_dbs_info);
mutex_lock(&dbs_mutex);
- sysfs_remove_group(&policy->kobj, &dbs_attr_group_old);
dbs_enable--;
mutex_destroy(&this_dbs_info->timer_mutex);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 58aa85ea5ec6..891360edecdd 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -99,8 +99,7 @@ static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info);
static unsigned int dbs_enable; /* number of CPUs using this policy */
/*
- * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
- * different CPUs. It protects dbs_enable in governor start/stop.
+ * dbs_mutex protects dbs_enable in governor start/stop.
*/
static DEFINE_MUTEX(dbs_mutex);
@@ -235,21 +234,12 @@ static void ondemand_powersave_bias_init(void)
/************************** sysfs interface ************************/
-static ssize_t show_sampling_rate_max(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- printk_once(KERN_INFO "CPUFREQ: ondemand sampling_rate_max "
- "sysfs file is deprecated - used by: %s\n", current->comm);
- return sprintf(buf, "%u\n", -1U);
-}
-
static ssize_t show_sampling_rate_min(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", min_sampling_rate);
}
-define_one_global_ro(sampling_rate_max);
define_one_global_ro(sampling_rate_min);
/* cpufreq_ondemand Governor Tunables */
@@ -266,32 +256,6 @@ show_one(sampling_down_factor, sampling_down_factor);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
-/*** delete after deprecation time ***/
-
-#define DEPRECATION_MSG(file_name) \
- printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
- "interface is deprecated - " #file_name "\n");
-
-#define show_one_old(file_name) \
-static ssize_t show_##file_name##_old \
-(struct cpufreq_policy *unused, char *buf) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return show_##file_name(NULL, NULL, buf); \
-}
-show_one_old(sampling_rate);
-show_one_old(up_threshold);
-show_one_old(ignore_nice_load);
-show_one_old(powersave_bias);
-show_one_old(sampling_rate_min);
-show_one_old(sampling_rate_max);
-
-cpufreq_freq_attr_ro_old(sampling_rate_min);
-cpufreq_freq_attr_ro_old(sampling_rate_max);
-
-/*** delete after deprecation time ***/
-
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -300,11 +264,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
-
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate);
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -317,11 +277,7 @@ static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
-
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.io_is_busy = !!input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -336,11 +292,7 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
input < MIN_FREQUENCY_UP_THRESHOLD) {
return -EINVAL;
}
-
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.up_threshold = input;
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -353,7 +305,6 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.sampling_down_factor = input;
/* Reset down sampling multiplier in case it was active */
@@ -362,8 +313,6 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->rate_mult = 1;
}
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -382,9 +331,7 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
if (input > 1)
input = 1;
- mutex_lock(&dbs_mutex);
if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
- mutex_unlock(&dbs_mutex);
return count;
}
dbs_tuners_ins.ignore_nice = input;
@@ -399,8 +346,6 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
}
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -417,11 +362,8 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
if (input > 1000)
input = 1000;
- mutex_lock(&dbs_mutex);
dbs_tuners_ins.powersave_bias = input;
ondemand_powersave_bias_init();
- mutex_unlock(&dbs_mutex);
-
return count;
}
@@ -433,7 +375,6 @@ define_one_global_rw(ignore_nice_load);
define_one_global_rw(powersave_bias);
static struct attribute *dbs_attributes[] = {
- &sampling_rate_max.attr,
&sampling_rate_min.attr,
&sampling_rate.attr,
&up_threshold.attr,
@@ -449,43 +390,6 @@ static struct attribute_group dbs_attr_group = {
.name = "ondemand",
};
-/*** delete after deprecation time ***/
-
-#define write_one_old(file_name) \
-static ssize_t store_##file_name##_old \
-(struct cpufreq_policy *unused, const char *buf, size_t count) \
-{ \
- printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
- "interface is deprecated - " #file_name "\n"); \
- return store_##file_name(NULL, NULL, buf, count); \
-}
-write_one_old(sampling_rate);
-write_one_old(up_threshold);
-write_one_old(ignore_nice_load);
-write_one_old(powersave_bias);
-
-cpufreq_freq_attr_rw_old(sampling_rate);
-cpufreq_freq_attr_rw_old(up_threshold);
-cpufreq_freq_attr_rw_old(ignore_nice_load);
-cpufreq_freq_attr_rw_old(powersave_bias);
-
-static struct attribute *dbs_attributes_old[] = {
- &sampling_rate_max_old.attr,
- &sampling_rate_min_old.attr,
- &sampling_rate_old.attr,
- &up_threshold_old.attr,
- &ignore_nice_load_old.attr,
- &powersave_bias_old.attr,
- NULL
-};
-
-static struct attribute_group dbs_attr_group_old = {
- .attrs = dbs_attributes_old,
- .name = "ondemand",
-};
-
-/*** delete after deprecation time ***/
-
/************************** sysfs end ************************/
static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
@@ -642,12 +546,7 @@ static void do_dbs_timer(struct work_struct *work)
unsigned int cpu = dbs_info->cpu;
int sample_type = dbs_info->sample_type;
- /* We want all CPUs to do sampling nearly on same jiffy */
- int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
- * dbs_info->rate_mult);
-
- if (num_online_cpus() > 1)
- delay -= jiffies % delay;
+ int delay;
mutex_lock(&dbs_info->timer_mutex);
@@ -660,10 +559,20 @@ static void do_dbs_timer(struct work_struct *work)
/* Setup timer for SUB_SAMPLE */
dbs_info->sample_type = DBS_SUB_SAMPLE;
delay = dbs_info->freq_hi_jiffies;
+ } else {
+ /* We want all CPUs to do sampling nearly on
+ * same jiffy
+ */
+ delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
+ * dbs_info->rate_mult);
+
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
}
} else {
__cpufreq_driver_target(dbs_info->cur_policy,
dbs_info->freq_lo, CPUFREQ_RELATION_H);
+ delay = dbs_info->freq_lo_jiffies;
}
schedule_delayed_work_on(cpu, &dbs_info->work, delay);
mutex_unlock(&dbs_info->timer_mutex);
@@ -727,12 +636,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex);
- rc = sysfs_create_group(&policy->kobj, &dbs_attr_group_old);
- if (rc) {
- mutex_unlock(&dbs_mutex);
- return rc;
- }
-
dbs_enable++;
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
@@ -785,7 +688,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_timer_exit(this_dbs_info);
mutex_lock(&dbs_mutex);
- sysfs_remove_group(&policy->kobj, &dbs_attr_group_old);
mutex_destroy(&this_dbs_info->timer_mutex);
dbs_enable--;
mutex_unlock(&dbs_mutex);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 0310ffaec9df..be7917ec40c9 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -300,7 +300,7 @@ static struct kobj_type ktype_state_cpuidle = {
.release = cpuidle_state_sysfs_release,
};
-static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
+static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
{
kobject_put(&device->kobjs[i]->kobj);
wait_for_completion(&device->kobjs[i]->kobj_unregister);
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 07bca4970e50..e6d7228b1479 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1845,7 +1845,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
}
#endif
-static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
+static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
{
struct pl08x_driver_data *pl08x;
const struct vendor_data *vd = id->data;
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index a6656834f0ff..00deabd9a04b 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -849,7 +849,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
/* Must clear TC interrupt before calling
* dma_tc_handle
- * in case tc_handle initate a new dma job
+ * in case tc_handle initiate a new dma job
*/
__set_bit(i, virtbase + COH901318_TC_INT_CLEAR1);
@@ -894,7 +894,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
}
/* Must clear TC interrupt before calling
* dma_tc_handle
- * in case tc_handle initate a new dma job
+ * in case tc_handle initiate a new dma job
*/
__set_bit(i, virtbase + COH901318_TC_INT_CLEAR2);
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 7c50f6dfd3f4..6abe1ec1f2ce 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -657,7 +657,7 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
}
static int __devinit
-pl330_probe(struct amba_device *adev, struct amba_id *id)
+pl330_probe(struct amba_device *adev, const struct amba_id *id)
{
struct dma_pl330_platdata *pdat;
struct dma_pl330_dmac *pdmac;
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 28720d3103c4..6451b581a70b 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -750,7 +750,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
return;
}
- /* Find the first not transferred desciptor */
+ /* Find the first not transferred descriptor */
list_for_each_entry(desc, &sh_chan->ld_queue, node)
if (desc->mark == DESC_SUBMITTED) {
dev_dbg(sh_chan->dev, "Queue #%d to %d: %u@%x -> %x\n",
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 3b88a4e7c98a..f69f90a61873 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -629,7 +629,7 @@ static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
desc_node)
list_move(&td_desc->desc_node, &td_chan->free_list);
- /* now tear down the runnning */
+ /* now tear down the running */
__td_finish(td_chan);
spin_unlock_bh(&td_chan->lock);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index fe70a341bd8b..fac1a2002e67 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -7,7 +7,7 @@
menuconfig EDAC
bool "EDAC (Error Detection And Correction) reporting"
depends on HAS_IOMEM
- depends on X86 || PPC
+ depends on X86 || PPC || TILE
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
@@ -282,4 +282,12 @@ config EDAC_CPC925
a companion chip to the PowerPC 970 family of
processors.
+config EDAC_TILE
+ tristate "Tilera Memory Controller"
+ depends on EDAC_MM_EDAC && TILE
+ default y
+ help
+ Support for error detection and correction on the
+ Tilera memory controller.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index ba2898b3639b..3e239133e29e 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o
obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o
obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o
+obj-$(CONFIG_EDAC_TILE) += tile_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 23e03554f0d3..0be30e978c85 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -25,59 +25,12 @@ static struct mem_ctl_info **mcis;
static struct ecc_settings **ecc_stngs;
/*
- * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
- * later.
- */
-static int ddr2_dbam_revCG[] = {
- [0] = 32,
- [1] = 64,
- [2] = 128,
- [3] = 256,
- [4] = 512,
- [5] = 1024,
- [6] = 2048,
-};
-
-static int ddr2_dbam_revD[] = {
- [0] = 32,
- [1] = 64,
- [2 ... 3] = 128,
- [4] = 256,
- [5] = 512,
- [6] = 256,
- [7] = 512,
- [8 ... 9] = 1024,
- [10] = 2048,
-};
-
-static int ddr2_dbam[] = { [0] = 128,
- [1] = 256,
- [2 ... 4] = 512,
- [5 ... 6] = 1024,
- [7 ... 8] = 2048,
- [9 ... 10] = 4096,
- [11] = 8192,
-};
-
-static int ddr3_dbam[] = { [0] = -1,
- [1] = 256,
- [2] = 512,
- [3 ... 4] = -1,
- [5 ... 6] = 1024,
- [7 ... 8] = 2048,
- [9 ... 10] = 4096,
- [11] = 8192,
-};
-
-/*
* Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
* bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
* or higher value'.
*
*FIXME: Produce a better mapping/linearisation.
*/
-
-
struct scrubrate {
u32 scrubval; /* bit pattern for scrub rate */
u32 bandwidth; /* bandwidth consumed (bytes/sec) */
@@ -107,6 +60,79 @@ struct scrubrate {
{ 0x00, 0UL}, /* scrubbing off */
};
+static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
+ u32 *val, const char *func)
+{
+ int err = 0;
+
+ err = pci_read_config_dword(pdev, offset, val);
+ if (err)
+ amd64_warn("%s: error reading F%dx%03x.\n",
+ func, PCI_FUNC(pdev->devfn), offset);
+
+ return err;
+}
+
+int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
+ u32 val, const char *func)
+{
+ int err = 0;
+
+ err = pci_write_config_dword(pdev, offset, val);
+ if (err)
+ amd64_warn("%s: error writing to F%dx%03x.\n",
+ func, PCI_FUNC(pdev->devfn), offset);
+
+ return err;
+}
+
+/*
+ *
+ * Depending on the family, F2 DCT reads need special handling:
+ *
+ * K8: has a single DCT only
+ *
+ * F10h: each DCT has its own set of regs
+ * DCT0 -> F2x040..
+ * DCT1 -> F2x140..
+ *
+ * F15h: we select which DCT we access using F1x10C[DctCfgSel]
+ *
+ */
+static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
+ const char *func)
+{
+ if (addr >= 0x100)
+ return -EINVAL;
+
+ return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
+}
+
+static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
+ const char *func)
+{
+ return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
+}
+
+static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
+ const char *func)
+{
+ u32 reg = 0;
+ u8 dct = 0;
+
+ if (addr >= 0x140 && addr <= 0x1a0) {
+ dct = 1;
+ addr -= 0x100;
+ }
+
+ amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
+ reg &= 0xfffffffe;
+ reg |= dct;
+ amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
+
+ return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
+}
+
/*
* Memory scrubber control interface. For K8, memory scrubbing is handled by
* hardware and can involve L2 cache, dcache as well as the main memory. With
@@ -156,7 +182,7 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
scrubval = scrubrates[i].scrubval;
- pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F);
+ pci_write_bits32(ctl, SCRCTRL, scrubval, 0x001F);
if (scrubval)
return scrubrates[i].bandwidth;
@@ -167,8 +193,12 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
{
struct amd64_pvt *pvt = mci->pvt_info;
+ u32 min_scrubrate = 0x5;
+
+ if (boot_cpu_data.x86 == 0xf)
+ min_scrubrate = 0x0;
- return __amd64_set_scrub_rate(pvt->F3, bw, pvt->min_scrubrate);
+ return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
}
static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
@@ -177,7 +207,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
u32 scrubval = 0;
int i, retval = -EINVAL;
- amd64_read_pci_cfg(pvt->F3, K8_SCRCTRL, &scrubval);
+ amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
scrubval = scrubval & 0x001F;
@@ -192,63 +222,14 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
return retval;
}
-/* Map from a CSROW entry to the mask entry that operates on it */
-static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow)
-{
- if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F)
- return csrow;
- else
- return csrow >> 1;
-}
-
-/* return the 'base' address the i'th CS entry of the 'dct' DRAM controller */
-static u32 amd64_get_dct_base(struct amd64_pvt *pvt, int dct, int csrow)
-{
- if (dct == 0)
- return pvt->dcsb0[csrow];
- else
- return pvt->dcsb1[csrow];
-}
-
-/*
- * Return the 'mask' address the i'th CS entry. This function is needed because
- * there number of DCSM registers on Rev E and prior vs Rev F and later is
- * different.
- */
-static u32 amd64_get_dct_mask(struct amd64_pvt *pvt, int dct, int csrow)
-{
- if (dct == 0)
- return pvt->dcsm0[amd64_map_to_dcs_mask(pvt, csrow)];
- else
- return pvt->dcsm1[amd64_map_to_dcs_mask(pvt, csrow)];
-}
-
-
/*
- * In *base and *limit, pass back the full 40-bit base and limit physical
- * addresses for the node given by node_id. This information is obtained from
- * DRAM Base (section 3.4.4.1) and DRAM Limit (section 3.4.4.2) registers. The
- * base and limit addresses are of type SysAddr, as defined at the start of
- * section 3.4.4 (p. 70). They are the lowest and highest physical addresses
- * in the address range they represent.
+ * returns true if the SysAddr given by sys_addr matches the
+ * DRAM base/limit associated with node_id
*/
-static void amd64_get_base_and_limit(struct amd64_pvt *pvt, int node_id,
- u64 *base, u64 *limit)
+static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
+ unsigned nid)
{
- *base = pvt->dram_base[node_id];
- *limit = pvt->dram_limit[node_id];
-}
-
-/*
- * Return 1 if the SysAddr given by sys_addr matches the base/limit associated
- * with node_id
- */
-static int amd64_base_limit_match(struct amd64_pvt *pvt,
- u64 sys_addr, int node_id)
-{
- u64 base, limit, addr;
-
- amd64_get_base_and_limit(pvt, node_id, &base, &limit);
+ u64 addr;
/* The K8 treats this as a 40-bit value. However, bits 63-40 will be
* all ones if the most significant implemented address bit is 1.
@@ -258,7 +239,8 @@ static int amd64_base_limit_match(struct amd64_pvt *pvt,
*/
addr = sys_addr & 0x000000ffffffffffull;
- return (addr >= base) && (addr <= limit);
+ return ((addr >= get_dram_base(pvt, nid)) &&
+ (addr <= get_dram_limit(pvt, nid)));
}
/*
@@ -271,7 +253,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
u64 sys_addr)
{
struct amd64_pvt *pvt;
- int node_id;
+ unsigned node_id;
u32 intlv_en, bits;
/*
@@ -285,10 +267,10 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
* registers. Therefore we arbitrarily choose to read it from the
* register for node 0.
*/
- intlv_en = pvt->dram_IntlvEn[0];
+ intlv_en = dram_intlv_en(pvt, 0);
if (intlv_en == 0) {
- for (node_id = 0; node_id < DRAM_REG_COUNT; node_id++) {
+ for (node_id = 0; node_id < DRAM_RANGES; node_id++) {
if (amd64_base_limit_match(pvt, sys_addr, node_id))
goto found;
}
@@ -305,10 +287,10 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
bits = (((u32) sys_addr) >> 12) & intlv_en;
for (node_id = 0; ; ) {
- if ((pvt->dram_IntlvSel[node_id] & intlv_en) == bits)
+ if ((dram_intlv_sel(pvt, node_id) & intlv_en) == bits)
break; /* intlv_sel field matches */
- if (++node_id >= DRAM_REG_COUNT)
+ if (++node_id >= DRAM_RANGES)
goto err_no_match;
}
@@ -321,7 +303,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
}
found:
- return edac_mc_find(node_id);
+ return edac_mc_find((int)node_id);
err_no_match:
debugf2("sys_addr 0x%lx doesn't match any node\n",
@@ -331,37 +313,50 @@ err_no_match:
}
/*
- * Extract the DRAM CS base address from selected csrow register.
+ * compute the CS base address of the @csrow on the DRAM controller @dct.
+ * For details see F2x[5C:40] in the processor's BKDG
*/
-static u64 base_from_dct_base(struct amd64_pvt *pvt, int csrow)
+static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
+ u64 *base, u64 *mask)
{
- return ((u64) (amd64_get_dct_base(pvt, 0, csrow) & pvt->dcsb_base)) <<
- pvt->dcs_shift;
-}
+ u64 csbase, csmask, base_bits, mask_bits;
+ u8 addr_shift;
-/*
- * Extract the mask from the dcsb0[csrow] entry in a CPU revision-specific way.
- */
-static u64 mask_from_dct_mask(struct amd64_pvt *pvt, int csrow)
-{
- u64 dcsm_bits, other_bits;
- u64 mask;
-
- /* Extract bits from DRAM CS Mask. */
- dcsm_bits = amd64_get_dct_mask(pvt, 0, csrow) & pvt->dcsm_mask;
+ if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
+ csbase = pvt->csels[dct].csbases[csrow];
+ csmask = pvt->csels[dct].csmasks[csrow];
+ base_bits = GENMASK(21, 31) | GENMASK(9, 15);
+ mask_bits = GENMASK(21, 29) | GENMASK(9, 15);
+ addr_shift = 4;
+ } else {
+ csbase = pvt->csels[dct].csbases[csrow];
+ csmask = pvt->csels[dct].csmasks[csrow >> 1];
+ addr_shift = 8;
- other_bits = pvt->dcsm_mask;
- other_bits = ~(other_bits << pvt->dcs_shift);
+ if (boot_cpu_data.x86 == 0x15)
+ base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13);
+ else
+ base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13);
+ }
- /*
- * The extracted bits from DCSM belong in the spaces represented by
- * the cleared bits in other_bits.
- */
- mask = (dcsm_bits << pvt->dcs_shift) | other_bits;
+ *base = (csbase & base_bits) << addr_shift;
- return mask;
+ *mask = ~0ULL;
+ /* poke holes for the csmask */
+ *mask &= ~(mask_bits << addr_shift);
+ /* OR them in */
+ *mask |= (csmask & mask_bits) << addr_shift;
}
+#define for_each_chip_select(i, dct, pvt) \
+ for (i = 0; i < pvt->csels[dct].b_cnt; i++)
+
+#define chip_select_base(i, dct, pvt) \
+ pvt->csels[dct].csbases[i]
+
+#define for_each_chip_select_mask(i, dct, pvt) \
+ for (i = 0; i < pvt->csels[dct].m_cnt; i++)
+
/*
* @input_addr is an InputAddr associated with the node given by mci. Return the
* csrow that input_addr maps to, or -1 on failure (no csrow claims input_addr).
@@ -374,19 +369,13 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
pvt = mci->pvt_info;
- /*
- * Here we use the DRAM CS Base and DRAM CS Mask registers. For each CS
- * base/mask register pair, test the condition shown near the start of
- * section 3.5.4 (p. 84, BKDG #26094, K8, revA-E).
- */
- for (csrow = 0; csrow < pvt->cs_count; csrow++) {
-
- /* This DRAM chip select is disabled on this node */
- if ((pvt->dcsb0[csrow] & K8_DCSB_CS_ENABLE) == 0)
+ for_each_chip_select(csrow, 0, pvt) {
+ if (!csrow_enabled(csrow, 0, pvt))
continue;
- base = base_from_dct_base(pvt, csrow);
- mask = ~mask_from_dct_mask(pvt, csrow);
+ get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
+
+ mask = ~mask;
if ((input_addr & mask) == (base & mask)) {
debugf2("InputAddr 0x%lx matches csrow %d (node %d)\n",
@@ -396,7 +385,6 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
return csrow;
}
}
-
debugf2("no matching csrow for InputAddr 0x%lx (MC node %d)\n",
(unsigned long)input_addr, pvt->mc_node_id);
@@ -404,19 +392,6 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
}
/*
- * Return the base value defined by the DRAM Base register for the node
- * represented by mci. This function returns the full 40-bit value despite the
- * fact that the register only stores bits 39-24 of the value. See section
- * 3.4.4.1 (BKDG #26094, K8, revA-E)
- */
-static inline u64 get_dram_base(struct mem_ctl_info *mci)
-{
- struct amd64_pvt *pvt = mci->pvt_info;
-
- return pvt->dram_base[pvt->mc_node_id];
-}
-
-/*
* Obtain info from the DRAM Hole Address Register (section 3.4.8, pub #26094)
* for the node represented by mci. Info is passed back in *hole_base,
* *hole_offset, and *hole_size. Function returns 0 if info is valid or 1 if
@@ -445,14 +420,13 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
return 1;
}
- /* only valid for Fam10h */
- if (boot_cpu_data.x86 == 0x10 &&
- (pvt->dhar & F10_DRAM_MEM_HOIST_VALID) == 0) {
+ /* valid for Fam10h and above */
+ if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
debugf1(" Dram Memory Hoisting is DISABLED on this system\n");
return 1;
}
- if ((pvt->dhar & DHAR_VALID) == 0) {
+ if (!dhar_valid(pvt)) {
debugf1(" Dram Memory Hoisting is DISABLED on this node %d\n",
pvt->mc_node_id);
return 1;
@@ -476,15 +450,15 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
* addresses in the hole so that they start at 0x100000000.
*/
- base = dhar_base(pvt->dhar);
+ base = dhar_base(pvt);
*hole_base = base;
*hole_size = (0x1ull << 32) - base;
if (boot_cpu_data.x86 > 0xf)
- *hole_offset = f10_dhar_offset(pvt->dhar);
+ *hole_offset = f10_dhar_offset(pvt);
else
- *hole_offset = k8_dhar_offset(pvt->dhar);
+ *hole_offset = k8_dhar_offset(pvt);
debugf1(" DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
pvt->mc_node_id, (unsigned long)*hole_base,
@@ -525,10 +499,11 @@ EXPORT_SYMBOL_GPL(amd64_get_dram_hole_info);
*/
static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
{
+ struct amd64_pvt *pvt = mci->pvt_info;
u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
int ret = 0;
- dram_base = get_dram_base(mci);
+ dram_base = get_dram_base(pvt, pvt->mc_node_id);
ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
&hole_size);
@@ -556,7 +531,7 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
* section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture
* Programmer's Manual Volume 1 Application Programming.
*/
- dram_addr = (sys_addr & 0xffffffffffull) - dram_base;
+ dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base;
debugf2("using DRAM Base register to translate SysAddr 0x%lx to "
"DramAddr 0x%lx\n", (unsigned long)sys_addr,
@@ -592,9 +567,9 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr)
* See the start of section 3.4.4 (p. 70, BKDG #26094, K8, revA-E)
* concerning translating a DramAddr to an InputAddr.
*/
- intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]);
- input_addr = ((dram_addr >> intlv_shift) & 0xffffff000ull) +
- (dram_addr & 0xfff);
+ intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
+ input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) +
+ (dram_addr & 0xfff);
debugf2(" Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n",
intlv_shift, (unsigned long)dram_addr,
@@ -628,7 +603,7 @@ static u64 sys_addr_to_input_addr(struct mem_ctl_info *mci, u64 sys_addr)
static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
{
struct amd64_pvt *pvt;
- int node_id, intlv_shift;
+ unsigned node_id, intlv_shift;
u64 bits, dram_addr;
u32 intlv_sel;
@@ -642,10 +617,10 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
*/
pvt = mci->pvt_info;
node_id = pvt->mc_node_id;
- BUG_ON((node_id < 0) || (node_id > 7));
- intlv_shift = num_node_interleave_bits(pvt->dram_IntlvEn[0]);
+ BUG_ON(node_id > 7);
+ intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0));
if (intlv_shift == 0) {
debugf1(" InputAddr 0x%lx translates to DramAddr of "
"same value\n", (unsigned long)input_addr);
@@ -653,10 +628,10 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
return input_addr;
}
- bits = ((input_addr & 0xffffff000ull) << intlv_shift) +
- (input_addr & 0xfff);
+ bits = ((input_addr & GENMASK(12, 35)) << intlv_shift) +
+ (input_addr & 0xfff);
- intlv_sel = pvt->dram_IntlvSel[node_id] & ((1 << intlv_shift) - 1);
+ intlv_sel = dram_intlv_sel(pvt, node_id) & ((1 << intlv_shift) - 1);
dram_addr = bits + (intlv_sel << 12);
debugf1("InputAddr 0x%lx translates to DramAddr 0x%lx "
@@ -673,7 +648,7 @@ static u64 input_addr_to_dram_addr(struct mem_ctl_info *mci, u64 input_addr)
static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u64 hole_base, hole_offset, hole_size, base, limit, sys_addr;
+ u64 hole_base, hole_offset, hole_size, base, sys_addr;
int ret = 0;
ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
@@ -691,7 +666,7 @@ static u64 dram_addr_to_sys_addr(struct mem_ctl_info *mci, u64 dram_addr)
}
}
- amd64_get_base_and_limit(pvt, pvt->mc_node_id, &base, &limit);
+ base = get_dram_base(pvt, pvt->mc_node_id);
sys_addr = dram_addr + base;
/*
@@ -736,13 +711,12 @@ static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
u64 base, mask;
pvt = mci->pvt_info;
- BUG_ON((csrow < 0) || (csrow >= pvt->cs_count));
+ BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt));
- base = base_from_dct_base(pvt, csrow);
- mask = mask_from_dct_mask(pvt, csrow);
+ get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
*input_addr_min = base & ~mask;
- *input_addr_max = base | mask | pvt->dcs_mask_notused;
+ *input_addr_max = base | mask;
}
/* Map the Error address to a PAGE and PAGE OFFSET. */
@@ -775,18 +749,13 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
-static u16 extract_syndrome(struct err_regs *err)
-{
- return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
-}
-
/*
* Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
* are ECC capable.
*/
static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
{
- int bit;
+ u8 bit;
enum dev_type edac_cap = EDAC_FLAG_NONE;
bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
@@ -799,8 +768,7 @@ static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
return edac_cap;
}
-
-static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt);
+static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
static void amd64_dump_dramcfg_low(u32 dclr, int chan)
{
@@ -813,8 +781,9 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)
debugf1(" PAR/ERR parity: %s\n",
(dclr & BIT(8)) ? "enabled" : "disabled");
- debugf1(" DCT 128bit mode width: %s\n",
- (dclr & BIT(11)) ? "128b" : "64b");
+ if (boot_cpu_data.x86 == 0x10)
+ debugf1(" DCT 128bit mode width: %s\n",
+ (dclr & BIT(11)) ? "128b" : "64b");
debugf1(" x4 logical DIMMs present: L0: %s L1: %s L2: %s L3: %s\n",
(dclr & BIT(12)) ? "yes" : "no",
@@ -824,16 +793,16 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)
}
/* Display and decode various NB registers for debug purposes. */
-static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
+static void dump_misc_regs(struct amd64_pvt *pvt)
{
debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
debugf1(" NB two channel DRAM capable: %s\n",
- (pvt->nbcap & K8_NBCAP_DCT_DUAL) ? "yes" : "no");
+ (pvt->nbcap & NBCAP_DCT_DUAL) ? "yes" : "no");
debugf1(" ECC capable: %s, ChipKill ECC capable: %s\n",
- (pvt->nbcap & K8_NBCAP_SECDED) ? "yes" : "no",
- (pvt->nbcap & K8_NBCAP_CHIPKILL) ? "yes" : "no");
+ (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
+ (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
amd64_dump_dramcfg_low(pvt->dclr0, 0);
@@ -841,130 +810,84 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
debugf1("F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, "
"offset: 0x%08x\n",
- pvt->dhar,
- dhar_base(pvt->dhar),
- (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt->dhar)
- : f10_dhar_offset(pvt->dhar));
+ pvt->dhar, dhar_base(pvt),
+ (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
+ : f10_dhar_offset(pvt));
- debugf1(" DramHoleValid: %s\n",
- (pvt->dhar & DHAR_VALID) ? "yes" : "no");
+ debugf1(" DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
- amd64_debug_display_dimm_sizes(0, pvt);
+ amd64_debug_display_dimm_sizes(pvt, 0);
/* everything below this point is Fam10h and above */
if (boot_cpu_data.x86 == 0xf)
return;
- amd64_debug_display_dimm_sizes(1, pvt);
+ amd64_debug_display_dimm_sizes(pvt, 1);
- amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4"));
+ amd64_info("using %s syndromes.\n", ((pvt->ecc_sym_sz == 8) ? "x8" : "x4"));
/* Only if NOT ganged does dclr1 have valid info */
if (!dct_ganging_enabled(pvt))
amd64_dump_dramcfg_low(pvt->dclr1, 1);
}
-/* Read in both of DBAM registers */
-static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
-{
- amd64_read_pci_cfg(pvt->F2, DBAM0, &pvt->dbam0);
-
- if (boot_cpu_data.x86 >= 0x10)
- amd64_read_pci_cfg(pvt->F2, DBAM1, &pvt->dbam1);
-}
-
/*
- * NOTE: CPU Revision Dependent code: Rev E and Rev F
- *
- * Set the DCSB and DCSM mask values depending on the CPU revision value. Also
- * set the shift factor for the DCSB and DCSM values.
- *
- * ->dcs_mask_notused, RevE:
- *
- * To find the max InputAddr for the csrow, start with the base address and set
- * all bits that are "don't care" bits in the test at the start of section
- * 3.5.4 (p. 84).
- *
- * The "don't care" bits are all set bits in the mask and all bits in the gaps
- * between bit ranges [35:25] and [19:13]. The value REV_E_DCS_NOTUSED_BITS
- * represents bits [24:20] and [12:0], which are all bits in the above-mentioned
- * gaps.
- *
- * ->dcs_mask_notused, RevF and later:
- *
- * To find the max InputAddr for the csrow, start with the base address and set
- * all bits that are "don't care" bits in the test at the start of NPT section
- * 4.5.4 (p. 87).
- *
- * The "don't care" bits are all set bits in the mask and all bits in the gaps
- * between bit ranges [36:27] and [21:13].
- *
- * The value REV_F_F1Xh_DCS_NOTUSED_BITS represents bits [26:22] and [12:0],
- * which are all bits in the above-mentioned gaps.
+ * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
*/
-static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
+static void prep_chip_selects(struct amd64_pvt *pvt)
{
-
if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
- pvt->dcsb_base = REV_E_DCSB_BASE_BITS;
- pvt->dcsm_mask = REV_E_DCSM_MASK_BITS;
- pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS;
- pvt->dcs_shift = REV_E_DCS_SHIFT;
- pvt->cs_count = 8;
- pvt->num_dcsm = 8;
+ pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
+ pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
} else {
- pvt->dcsb_base = REV_F_F1Xh_DCSB_BASE_BITS;
- pvt->dcsm_mask = REV_F_F1Xh_DCSM_MASK_BITS;
- pvt->dcs_mask_notused = REV_F_F1Xh_DCS_NOTUSED_BITS;
- pvt->dcs_shift = REV_F_F1Xh_DCS_SHIFT;
- pvt->cs_count = 8;
- pvt->num_dcsm = 4;
+ pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
+ pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
}
}
/*
- * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask hw registers
+ * Function 2 Offset F10_DCSB0; read in the DCS Base and DCS Mask registers
*/
-static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
+static void read_dct_base_mask(struct amd64_pvt *pvt)
{
- int cs, reg;
+ int cs;
- amd64_set_dct_base_and_mask(pvt);
+ prep_chip_selects(pvt);
- for (cs = 0; cs < pvt->cs_count; cs++) {
- reg = K8_DCSB0 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsb0[cs]))
+ for_each_chip_select(cs, 0, pvt) {
+ int reg0 = DCSB0 + (cs * 4);
+ int reg1 = DCSB1 + (cs * 4);
+ u32 *base0 = &pvt->csels[0].csbases[cs];
+ u32 *base1 = &pvt->csels[1].csbases[cs];
+
+ if (!amd64_read_dct_pci_cfg(pvt, reg0, base0))
debugf0(" DCSB0[%d]=0x%08x reg: F2x%x\n",
- cs, pvt->dcsb0[cs], reg);
-
- /* If DCT are NOT ganged, then read in DCT1's base */
- if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
- reg = F10_DCSB1 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->F2, reg,
- &pvt->dcsb1[cs]))
- debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n",
- cs, pvt->dcsb1[cs], reg);
- } else {
- pvt->dcsb1[cs] = 0;
- }
+ cs, *base0, reg0);
+
+ if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
+ continue;
+
+ if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
+ debugf0(" DCSB1[%d]=0x%08x reg: F2x%x\n",
+ cs, *base1, reg1);
}
- for (cs = 0; cs < pvt->num_dcsm; cs++) {
- reg = K8_DCSM0 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsm0[cs]))
+ for_each_chip_select_mask(cs, 0, pvt) {
+ int reg0 = DCSM0 + (cs * 4);
+ int reg1 = DCSM1 + (cs * 4);
+ u32 *mask0 = &pvt->csels[0].csmasks[cs];
+ u32 *mask1 = &pvt->csels[1].csmasks[cs];
+
+ if (!amd64_read_dct_pci_cfg(pvt, reg0, mask0))
debugf0(" DCSM0[%d]=0x%08x reg: F2x%x\n",
- cs, pvt->dcsm0[cs], reg);
-
- /* If DCT are NOT ganged, then read in DCT1's mask */
- if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
- reg = F10_DCSM1 + (cs * 4);
- if (!amd64_read_pci_cfg(pvt->F2, reg,
- &pvt->dcsm1[cs]))
- debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n",
- cs, pvt->dcsm1[cs], reg);
- } else {
- pvt->dcsm1[cs] = 0;
- }
+ cs, *mask0, reg0);
+
+ if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
+ continue;
+
+ if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
+ debugf0(" DCSM1[%d]=0x%08x reg: F2x%x\n",
+ cs, *mask1, reg1);
}
}
@@ -972,7 +895,10 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
{
enum mem_type type;
- if (boot_cpu_data.x86 >= 0x10 || pvt->ext_model >= K8_REV_F) {
+ /* F15h supports only DDR3 */
+ if (boot_cpu_data.x86 >= 0x15)
+ type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
+ else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) {
if (pvt->dchr0 & DDR3_MODE)
type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
else
@@ -986,26 +912,14 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
return type;
}
-/*
- * Read the DRAM Configuration Low register. It differs between CG, D & E revs
- * and the later RevF memory controllers (DDR vs DDR2)
- *
- * Return:
- * number of memory channels in operation
- * Pass back:
- * contents of the DCL0_LOW register
- */
+/* Get the number of DCT channels the memory controller is using. */
static int k8_early_channel_count(struct amd64_pvt *pvt)
{
- int flag, err = 0;
-
- err = amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
- if (err)
- return err;
+ int flag;
if (pvt->ext_model >= K8_REV_F)
/* RevF (NPT) and later */
- flag = pvt->dclr0 & F10_WIDTH_128;
+ flag = pvt->dclr0 & WIDTH_128;
else
/* RevE and earlier */
flag = pvt->dclr0 & REVE_WIDTH_128;
@@ -1016,55 +930,47 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
return (flag) ? 2 : 1;
}
-/* extract the ERROR ADDRESS for the K8 CPUs */
-static u64 k8_get_error_address(struct mem_ctl_info *mci,
- struct err_regs *info)
+/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
+static u64 get_error_address(struct mce *m)
{
- return (((u64) (info->nbeah & 0xff)) << 32) +
- (info->nbeal & ~0x03);
+ u8 start_bit = 1;
+ u8 end_bit = 47;
+
+ if (boot_cpu_data.x86 == 0xf) {
+ start_bit = 3;
+ end_bit = 39;
+ }
+
+ return m->addr & GENMASK(start_bit, end_bit);
}
-/*
- * Read the Base and Limit registers for K8 based Memory controllers; extract
- * fields from the 'raw' reg into separate data fields
- *
- * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN
- */
-static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
+static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
{
- u32 low;
- u32 off = dram << 3; /* 8 bytes between DRAM entries */
+ int off = range << 3;
- amd64_read_pci_cfg(pvt->F1, K8_DRAM_BASE_LOW + off, &low);
+ amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
+ amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
- /* Extract parts into separate data entries */
- pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8;
- pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
- pvt->dram_rw_en[dram] = (low & 0x3);
+ if (boot_cpu_data.x86 == 0xf)
+ return;
- amd64_read_pci_cfg(pvt->F1, K8_DRAM_LIMIT_LOW + off, &low);
+ if (!dram_rw(pvt, range))
+ return;
- /*
- * Extract parts into separate data entries. Limit is the HIGHEST memory
- * location of the region, so lower 24 bits need to be all ones
- */
- pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 8) | 0x00FFFFFF;
- pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7;
- pvt->dram_DstNode[dram] = (low & 0x7);
+ amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
+ amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
}
-static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct err_regs *err_info, u64 sys_addr)
+static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
+ u16 syndrome)
{
struct mem_ctl_info *src_mci;
+ struct amd64_pvt *pvt = mci->pvt_info;
int channel, csrow;
u32 page, offset;
- u16 syndrome;
-
- syndrome = extract_syndrome(err_info);
/* CHIPKILL enabled */
- if (err_info->nbcfg & K8_NBCFG_CHIPKILL) {
+ if (pvt->nbcfg & NBCFG_CHIPKILL) {
channel = get_channel_from_ecc_syndrome(mci, syndrome);
if (channel < 0) {
/*
@@ -1113,18 +1019,41 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
}
}
-static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr2_cs_size(unsigned i, bool dct_width)
{
- int *dbam_map;
+ unsigned shift = 0;
- if (pvt->ext_model >= K8_REV_F)
- dbam_map = ddr2_dbam;
- else if (pvt->ext_model >= K8_REV_D)
- dbam_map = ddr2_dbam_revD;
+ if (i <= 2)
+ shift = i;
+ else if (!(i & 0x1))
+ shift = i >> 1;
else
- dbam_map = ddr2_dbam_revCG;
+ shift = (i + 1) >> 1;
- return dbam_map[cs_mode];
+ return 128 << (shift + !!dct_width);
+}
+
+static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode)
+{
+ u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
+
+ if (pvt->ext_model >= K8_REV_F) {
+ WARN_ON(cs_mode > 11);
+ return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
+ }
+ else if (pvt->ext_model >= K8_REV_D) {
+ WARN_ON(cs_mode > 10);
+
+ if (cs_mode == 3 || cs_mode == 8)
+ return 32 << (cs_mode - 1);
+ else
+ return 32 << cs_mode;
+ }
+ else {
+ WARN_ON(cs_mode > 6);
+ return 32 << cs_mode;
+ }
}
/*
@@ -1135,17 +1064,13 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
* Pass back:
* contents of the DCL0_LOW register
*/
-static int f10_early_channel_count(struct amd64_pvt *pvt)
+static int f1x_early_channel_count(struct amd64_pvt *pvt)
{
- int dbams[] = { DBAM0, DBAM1 };
int i, j, channels = 0;
- u32 dbam;
- /* If we are in 128 bit mode, then we are using 2 channels */
- if (pvt->dclr0 & F10_WIDTH_128) {
- channels = 2;
- return channels;
- }
+ /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
+ if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
+ return 2;
/*
* Need to check if in unganged mode: In such, there are 2 channels,
@@ -1162,9 +1087,8 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
* is more than just one DIMM present in unganged mode. Need to check
* both controllers since DIMMs can be placed in either one.
*/
- for (i = 0; i < ARRAY_SIZE(dbams); i++) {
- if (amd64_read_pci_cfg(pvt->F2, dbams[i], &dbam))
- goto err_reg;
+ for (i = 0; i < 2; i++) {
+ u32 dbam = (i ? pvt->dbam1 : pvt->dbam0);
for (j = 0; j < 4; j++) {
if (DBAM_DIMM(j, dbam) > 0) {
@@ -1180,216 +1104,191 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
amd64_info("MCT channel count: %d\n", channels);
return channels;
-
-err_reg:
- return -1;
-
}
-static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr3_cs_size(unsigned i, bool dct_width)
{
- int *dbam_map;
+ unsigned shift = 0;
+ int cs_size = 0;
- if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
- dbam_map = ddr3_dbam;
+ if (i == 0 || i == 3 || i == 4)
+ cs_size = -1;
+ else if (i <= 2)
+ shift = i;
+ else if (i == 12)
+ shift = 7;
+ else if (!(i & 0x1))
+ shift = i >> 1;
else
- dbam_map = ddr2_dbam;
+ shift = (i + 1) >> 1;
+
+ if (cs_size != -1)
+ cs_size = (128 * (1 << !!dct_width)) << shift;
- return dbam_map[cs_mode];
+ return cs_size;
}
-static u64 f10_get_error_address(struct mem_ctl_info *mci,
- struct err_regs *info)
+static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode)
{
- return (((u64) (info->nbeah & 0xffff)) << 32) +
- (info->nbeal & ~0x01);
+ u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
+
+ WARN_ON(cs_mode > 11);
+
+ if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
+ return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
+ else
+ return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
}
/*
- * Read the Base and Limit registers for F10 based Memory controllers. Extract
- * fields from the 'raw' reg into separate data fields.
- *
- * Isolates: BASE, LIMIT, IntlvEn, IntlvSel, RW_EN.
+ * F15h supports only 64bit DCT interfaces
*/
-static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
+static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode)
{
- u32 high_offset, low_offset, high_base, low_base, high_limit, low_limit;
-
- low_offset = K8_DRAM_BASE_LOW + (dram << 3);
- high_offset = F10_DRAM_BASE_HIGH + (dram << 3);
-
- /* read the 'raw' DRAM BASE Address register */
- amd64_read_pci_cfg(pvt->F1, low_offset, &low_base);
- amd64_read_pci_cfg(pvt->F1, high_offset, &high_base);
-
- /* Extract parts into separate data entries */
- pvt->dram_rw_en[dram] = (low_base & 0x3);
-
- if (pvt->dram_rw_en[dram] == 0)
- return;
-
- pvt->dram_IntlvEn[dram] = (low_base >> 8) & 0x7;
-
- pvt->dram_base[dram] = (((u64)high_base & 0x000000FF) << 40) |
- (((u64)low_base & 0xFFFF0000) << 8);
-
- low_offset = K8_DRAM_LIMIT_LOW + (dram << 3);
- high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
-
- /* read the 'raw' LIMIT registers */
- amd64_read_pci_cfg(pvt->F1, low_offset, &low_limit);
- amd64_read_pci_cfg(pvt->F1, high_offset, &high_limit);
-
- pvt->dram_DstNode[dram] = (low_limit & 0x7);
- pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7;
+ WARN_ON(cs_mode > 12);
- /*
- * Extract address values and form a LIMIT address. Limit is the HIGHEST
- * memory location of the region, so low 24 bits need to be all ones.
- */
- pvt->dram_limit[dram] = (((u64)high_limit & 0x000000FF) << 40) |
- (((u64) low_limit & 0xFFFF0000) << 8) |
- 0x00FFFFFF;
+ return ddr3_cs_size(cs_mode, false);
}
-static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
+static void read_dram_ctl_register(struct amd64_pvt *pvt)
{
- if (!amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_LOW,
- &pvt->dram_ctl_select_low)) {
- debugf0("F2x110 (DCTL Sel. Low): 0x%08x, "
- "High range addresses at: 0x%x\n",
- pvt->dram_ctl_select_low,
- dct_sel_baseaddr(pvt));
+ if (boot_cpu_data.x86 == 0xf)
+ return;
+
+ if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
+ debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
+ pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
- debugf0(" DCT mode: %s, All DCTs on: %s\n",
- (dct_ganging_enabled(pvt) ? "ganged" : "unganged"),
- (dct_dram_enabled(pvt) ? "yes" : "no"));
+ debugf0(" DCTs operate in %s mode.\n",
+ (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
if (!dct_ganging_enabled(pvt))
debugf0(" Address range split per DCT: %s\n",
(dct_high_range_enabled(pvt) ? "yes" : "no"));
- debugf0(" DCT data interleave for ECC: %s, "
+ debugf0(" data interleave for ECC: %s, "
"DRAM cleared since last warm reset: %s\n",
(dct_data_intlv_enabled(pvt) ? "enabled" : "disabled"),
(dct_memory_cleared(pvt) ? "yes" : "no"));
- debugf0(" DCT channel interleave: %s, "
- "DCT interleave bits selector: 0x%x\n",
+ debugf0(" channel interleave: %s, "
+ "interleave bits selector: 0x%x\n",
(dct_interleave_enabled(pvt) ? "enabled" : "disabled"),
dct_sel_interleave_addr(pvt));
}
- amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_HIGH,
- &pvt->dram_ctl_select_high);
+ amd64_read_dct_pci_cfg(pvt, DCT_SEL_HI, &pvt->dct_sel_hi);
}
/*
- * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory
+ * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
* Interleaving Modes.
*/
-static u32 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
- int hi_range_sel, u32 intlv_en)
+static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
+ bool hi_range_sel, u8 intlv_en)
{
- u32 cs, temp, dct_sel_high = (pvt->dram_ctl_select_low >> 1) & 1;
+ u8 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
if (dct_ganging_enabled(pvt))
- cs = 0;
- else if (hi_range_sel)
- cs = dct_sel_high;
- else if (dct_interleave_enabled(pvt)) {
- /*
- * see F2x110[DctSelIntLvAddr] - channel interleave mode
- */
- if (dct_sel_interleave_addr(pvt) == 0)
- cs = sys_addr >> 6 & 1;
- else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) {
- temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
+ return 0;
- if (dct_sel_interleave_addr(pvt) & 1)
- cs = (sys_addr >> 9 & 1) ^ temp;
- else
- cs = (sys_addr >> 6 & 1) ^ temp;
- } else if (intlv_en & 4)
- cs = sys_addr >> 15 & 1;
- else if (intlv_en & 2)
- cs = sys_addr >> 14 & 1;
- else if (intlv_en & 1)
- cs = sys_addr >> 13 & 1;
- else
- cs = sys_addr >> 12 & 1;
- } else if (dct_high_range_enabled(pvt) && !dct_ganging_enabled(pvt))
- cs = ~dct_sel_high & 1;
- else
- cs = 0;
+ if (hi_range_sel)
+ return dct_sel_high;
- return cs;
-}
+ /*
+ * see F2x110[DctSelIntLvAddr] - channel interleave mode
+ */
+ if (dct_interleave_enabled(pvt)) {
+ u8 intlv_addr = dct_sel_interleave_addr(pvt);
-static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en)
-{
- if (intlv_en == 1)
- return 1;
- else if (intlv_en == 3)
- return 2;
- else if (intlv_en == 7)
- return 3;
+ /* return DCT select function: 0=DCT0, 1=DCT1 */
+ if (!intlv_addr)
+ return sys_addr >> 6 & 1;
+
+ if (intlv_addr & 0x2) {
+ u8 shift = intlv_addr & 0x1 ? 9 : 6;
+ u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
+
+ return ((sys_addr >> shift) & 1) ^ temp;
+ }
+
+ return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
+ }
+
+ if (dct_high_range_enabled(pvt))
+ return ~dct_sel_high & 1;
return 0;
}
-/* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */
-static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel,
- u32 dct_sel_base_addr,
- u64 dct_sel_base_off,
- u32 hole_valid, u32 hole_off,
- u64 dram_base)
+/* Convert the sys_addr to the normalized DCT address */
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
+ u64 sys_addr, bool hi_rng,
+ u32 dct_sel_base_addr)
{
u64 chan_off;
+ u64 dram_base = get_dram_base(pvt, range);
+ u64 hole_off = f10_dhar_offset(pvt);
+ u64 dct_sel_base_off = (pvt->dct_sel_hi & 0xFFFFFC00) << 16;
- if (hi_range_sel) {
- if (!(dct_sel_base_addr & 0xFFFF0000) &&
- hole_valid && (sys_addr >= 0x100000000ULL))
- chan_off = hole_off << 16;
+ if (hi_rng) {
+ /*
+ * if
+ * base address of high range is below 4Gb
+ * (bits [47:27] at [31:11])
+ * DRAM address space on this DCT is hoisted above 4Gb &&
+ * sys_addr > 4Gb
+ *
+ * remove hole offset from sys_addr
+ * else
+ * remove high range offset from sys_addr
+ */
+ if ((!(dct_sel_base_addr >> 16) ||
+ dct_sel_base_addr < dhar_base(pvt)) &&
+ dhar_valid(pvt) &&
+ (sys_addr >= BIT_64(32)))
+ chan_off = hole_off;
else
chan_off = dct_sel_base_off;
} else {
- if (hole_valid && (sys_addr >= 0x100000000ULL))
- chan_off = hole_off << 16;
+ /*
+ * if
+ * we have a valid hole &&
+ * sys_addr > 4Gb
+ *
+ * remove hole
+ * else
+ * remove dram base to normalize to DCT address
+ */
+ if (dhar_valid(pvt) && (sys_addr >= BIT_64(32)))
+ chan_off = hole_off;
else
- chan_off = dram_base & 0xFFFFF8000000ULL;
+ chan_off = dram_base;
}
- return (sys_addr & 0x0000FFFFFFFFFFC0ULL) -
- (chan_off & 0x0000FFFFFF800000ULL);
+ return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47));
}
-/* Hack for the time being - Can we get this from BIOS?? */
-#define CH0SPARE_RANK 0
-#define CH1SPARE_RANK 1
-
/*
* checks if the csrow passed in is marked as SPARED, if so returns the new
* spare row
*/
-static inline int f10_process_possible_spare(int csrow,
- u32 cs, struct amd64_pvt *pvt)
-{
- u32 swap_done;
- u32 bad_dram_cs;
-
- /* Depending on channel, isolate respective SPARING info */
- if (cs) {
- swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare);
- bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare);
- if (swap_done && (csrow == bad_dram_cs))
- csrow = CH1SPARE_RANK;
- } else {
- swap_done = F10_ONLINE_SPARE_SWAPDONE0(pvt->online_spare);
- bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS0(pvt->online_spare);
- if (swap_done && (csrow == bad_dram_cs))
- csrow = CH0SPARE_RANK;
+static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
+{
+ int tmp_cs;
+
+ if (online_spare_swap_done(pvt, dct) &&
+ csrow == online_spare_bad_dramcs(pvt, dct)) {
+
+ for_each_chip_select(tmp_cs, dct, pvt) {
+ if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
+ csrow = tmp_cs;
+ break;
+ }
+ }
}
return csrow;
}
@@ -1402,11 +1301,11 @@ static inline int f10_process_possible_spare(int csrow,
* -EINVAL: NOT FOUND
* 0..csrow = Chip-Select Row
*/
-static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
{
struct mem_ctl_info *mci;
struct amd64_pvt *pvt;
- u32 cs_base, cs_mask;
+ u64 cs_base, cs_mask;
int cs_found = -EINVAL;
int csrow;
@@ -1416,39 +1315,25 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
pvt = mci->pvt_info;
- debugf1("InputAddr=0x%x channelselect=%d\n", in_addr, cs);
-
- for (csrow = 0; csrow < pvt->cs_count; csrow++) {
+ debugf1("input addr: 0x%llx, DCT: %d\n", in_addr, dct);
- cs_base = amd64_get_dct_base(pvt, cs, csrow);
- if (!(cs_base & K8_DCSB_CS_ENABLE))
+ for_each_chip_select(csrow, dct, pvt) {
+ if (!csrow_enabled(csrow, dct, pvt))
continue;
- /*
- * We have an ENABLED CSROW, Isolate just the MASK bits of the
- * target: [28:19] and [13:5], which map to [36:27] and [21:13]
- * of the actual address.
- */
- cs_base &= REV_F_F1Xh_DCSB_BASE_BITS;
-
- /*
- * Get the DCT Mask, and ENABLE the reserved bits: [18:16] and
- * [4:0] to become ON. Then mask off bits [28:0] ([36:8])
- */
- cs_mask = amd64_get_dct_mask(pvt, cs, csrow);
+ get_cs_base_and_mask(pvt, csrow, dct, &cs_base, &cs_mask);
- debugf1(" CSROW=%d CSBase=0x%x RAW CSMask=0x%x\n",
- csrow, cs_base, cs_mask);
+ debugf1(" CSROW=%d CSBase=0x%llx CSMask=0x%llx\n",
+ csrow, cs_base, cs_mask);
- cs_mask = (cs_mask | 0x0007C01F) & 0x1FFFFFFF;
+ cs_mask = ~cs_mask;
- debugf1(" Final CSMask=0x%x\n", cs_mask);
- debugf1(" (InputAddr & ~CSMask)=0x%x "
- "(CSBase & ~CSMask)=0x%x\n",
- (in_addr & ~cs_mask), (cs_base & ~cs_mask));
+ debugf1(" (InputAddr & ~CSMask)=0x%llx "
+ "(CSBase & ~CSMask)=0x%llx\n",
+ (in_addr & cs_mask), (cs_base & cs_mask));
- if ((in_addr & ~cs_mask) == (cs_base & ~cs_mask)) {
- cs_found = f10_process_possible_spare(csrow, cs, pvt);
+ if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
+ cs_found = f10_process_possible_spare(pvt, dct, csrow);
debugf1(" MATCH csrow=%d\n", cs_found);
break;
@@ -1457,38 +1342,75 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
return cs_found;
}
-/* For a given @dram_range, check if @sys_addr falls within it. */
-static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
- u64 sys_addr, int *nid, int *chan_sel)
+/*
+ * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
+ * swapped with a region located at the bottom of memory so that the GPU can use
+ * the interleaved region and thus two channels.
+ */
+static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
{
- int node_id, cs_found = -EINVAL, high_range = 0;
- u32 intlv_en, intlv_sel, intlv_shift, hole_off;
- u32 hole_valid, tmp, dct_sel_base, channel;
- u64 dram_base, chan_addr, dct_sel_base_off;
+ u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
- dram_base = pvt->dram_base[dram_range];
- intlv_en = pvt->dram_IntlvEn[dram_range];
+ if (boot_cpu_data.x86 == 0x10) {
+ /* only revC3 and revE have that feature */
+ if (boot_cpu_data.x86_model < 4 ||
+ (boot_cpu_data.x86_model < 0xa &&
+ boot_cpu_data.x86_mask < 3))
+ return sys_addr;
+ }
- node_id = pvt->dram_DstNode[dram_range];
- intlv_sel = pvt->dram_IntlvSel[dram_range];
+ amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg);
- debugf1("(dram=%d) Base=0x%llx SystemAddr= 0x%llx Limit=0x%llx\n",
- dram_range, dram_base, sys_addr, pvt->dram_limit[dram_range]);
+ if (!(swap_reg & 0x1))
+ return sys_addr;
- /*
- * This assumes that one node's DHAR is the same as all the other
- * nodes' DHAR.
- */
- hole_off = (pvt->dhar & 0x0000FF80);
- hole_valid = (pvt->dhar & 0x1);
- dct_sel_base_off = (pvt->dram_ctl_select_high & 0xFFFFFC00) << 16;
+ swap_base = (swap_reg >> 3) & 0x7f;
+ swap_limit = (swap_reg >> 11) & 0x7f;
+ rgn_size = (swap_reg >> 20) & 0x7f;
+ tmp_addr = sys_addr >> 27;
- debugf1(" HoleOffset=0x%x HoleValid=0x%x IntlvSel=0x%x\n",
- hole_off, hole_valid, intlv_sel);
+ if (!(sys_addr >> 34) &&
+ (((tmp_addr >= swap_base) &&
+ (tmp_addr <= swap_limit)) ||
+ (tmp_addr < rgn_size)))
+ return sys_addr ^ (u64)swap_base << 27;
+
+ return sys_addr;
+}
+
+/* For a given @dram_range, check if @sys_addr falls within it. */
+static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
+ u64 sys_addr, int *nid, int *chan_sel)
+{
+ int cs_found = -EINVAL;
+ u64 chan_addr;
+ u32 dct_sel_base;
+ u8 channel;
+ bool high_range = false;
+
+ u8 node_id = dram_dst_node(pvt, range);
+ u8 intlv_en = dram_intlv_en(pvt, range);
+ u32 intlv_sel = dram_intlv_sel(pvt, range);
+
+ debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
+ range, sys_addr, get_dram_limit(pvt, range));
+
+ if (dhar_valid(pvt) &&
+ dhar_base(pvt) <= sys_addr &&
+ sys_addr < BIT_64(32)) {
+ amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
+ sys_addr);
+ return -EINVAL;
+ }
if (intlv_en &&
- (intlv_sel != ((sys_addr >> 12) & intlv_en)))
+ (intlv_sel != ((sys_addr >> 12) & intlv_en))) {
+ amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n",
+ intlv_en, intlv_sel);
return -EINVAL;
+ }
+
+ sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
dct_sel_base = dct_sel_baseaddr(pvt);
@@ -1499,38 +1421,41 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
if (dct_high_range_enabled(pvt) &&
!dct_ganging_enabled(pvt) &&
((sys_addr >> 27) >= (dct_sel_base >> 11)))
- high_range = 1;
-
- channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en);
+ high_range = true;
- chan_addr = f10_get_base_addr_offset(sys_addr, high_range, dct_sel_base,
- dct_sel_base_off, hole_valid,
- hole_off, dram_base);
+ channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
- intlv_shift = f10_map_intlv_en_to_shift(intlv_en);
+ chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
+ high_range, dct_sel_base);
- /* remove Node ID (in case of memory interleaving) */
- tmp = chan_addr & 0xFC0;
+ /* Remove node interleaving, see F1x120 */
+ if (intlv_en)
+ chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
+ (chan_addr & 0xfff);
- chan_addr = ((chan_addr >> intlv_shift) & 0xFFFFFFFFF000ULL) | tmp;
-
- /* remove channel interleave and hash */
+ /* remove channel interleave */
if (dct_interleave_enabled(pvt) &&
!dct_high_range_enabled(pvt) &&
!dct_ganging_enabled(pvt)) {
- if (dct_sel_interleave_addr(pvt) != 1)
- chan_addr = (chan_addr >> 1) & 0xFFFFFFFFFFFFFFC0ULL;
- else {
- tmp = chan_addr & 0xFC0;
- chan_addr = ((chan_addr & 0xFFFFFFFFFFFFC000ULL) >> 1)
- | tmp;
- }
+
+ if (dct_sel_interleave_addr(pvt) != 1) {
+ if (dct_sel_interleave_addr(pvt) == 0x3)
+ /* hash 9 */
+ chan_addr = ((chan_addr >> 10) << 9) |
+ (chan_addr & 0x1ff);
+ else
+ /* A[6] or hash 6 */
+ chan_addr = ((chan_addr >> 7) << 6) |
+ (chan_addr & 0x3f);
+ } else
+ /* A[12] */
+ chan_addr = ((chan_addr >> 13) << 12) |
+ (chan_addr & 0xfff);
}
- debugf1(" (ChannelAddrLong=0x%llx) >> 8 becomes InputAddr=0x%x\n",
- chan_addr, (u32)(chan_addr >> 8));
+ debugf1(" Normalized DCT addr: 0x%llx\n", chan_addr);
- cs_found = f10_lookup_addr_in_dct(chan_addr >> 8, node_id, channel);
+ cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
if (cs_found >= 0) {
*nid = node_id;
@@ -1539,23 +1464,21 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int dram_range,
return cs_found;
}
-static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
+static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
int *node, int *chan_sel)
{
- int dram_range, cs_found = -EINVAL;
- u64 dram_base, dram_limit;
+ int cs_found = -EINVAL;
+ unsigned range;
- for (dram_range = 0; dram_range < DRAM_REG_COUNT; dram_range++) {
+ for (range = 0; range < DRAM_RANGES; range++) {
- if (!pvt->dram_rw_en[dram_range])
+ if (!dram_rw(pvt, range))
continue;
- dram_base = pvt->dram_base[dram_range];
- dram_limit = pvt->dram_limit[dram_range];
+ if ((get_dram_base(pvt, range) <= sys_addr) &&
+ (get_dram_limit(pvt, range) >= sys_addr)) {
- if ((dram_base <= sys_addr) && (sys_addr <= dram_limit)) {
-
- cs_found = f10_match_to_this_node(pvt, dram_range,
+ cs_found = f1x_match_to_this_node(pvt, range,
sys_addr, node,
chan_sel);
if (cs_found >= 0)
@@ -1572,16 +1495,14 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
* The @sys_addr is usually an error address received from the hardware
* (MCX_ADDR).
*/
-static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
- struct err_regs *err_info,
- u64 sys_addr)
+static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
+ u16 syndrome)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 page, offset;
int nid, csrow, chan = 0;
- u16 syndrome;
- csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
+ csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
if (csrow < 0) {
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
@@ -1590,14 +1511,12 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
error_address_to_page_and_offset(sys_addr, &page, &offset);
- syndrome = extract_syndrome(err_info);
-
/*
* We need the syndromes for channel detection only when we're
* ganged. Otherwise @chan should already contain the channel at
* this point.
*/
- if (dct_ganging_enabled(pvt) && (pvt->nbcfg & K8_NBCFG_CHIPKILL))
+ if (dct_ganging_enabled(pvt))
chan = get_channel_from_ecc_syndrome(mci, syndrome);
if (chan >= 0)
@@ -1614,16 +1533,16 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
/*
* debug routine to display the memory sizes of all logical DIMMs and its
- * CSROWs as well
+ * CSROWs
*/
-static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
+static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
{
int dimm, size0, size1, factor = 0;
- u32 dbam;
- u32 *dcsb;
+ u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
+ u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
if (boot_cpu_data.x86 == 0xf) {
- if (pvt->dclr0 & F10_WIDTH_128)
+ if (pvt->dclr0 & WIDTH_128)
factor = 1;
/* K8 families < revF not supported yet */
@@ -1634,7 +1553,8 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
}
dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
- dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0;
+ dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->csels[1].csbases
+ : pvt->csels[0].csbases;
debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
@@ -1644,12 +1564,14 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
for (dimm = 0; dimm < 4; dimm++) {
size0 = 0;
- if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE)
- size0 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+ if (dcsb[dimm*2] & DCSB_CS_ENABLE)
+ size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
+ DBAM_DIMM(dimm, dbam));
size1 = 0;
- if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
- size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+ if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
+ size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
+ DBAM_DIMM(dimm, dbam));
amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
dimm * 2, size0 << factor,
@@ -1664,10 +1586,9 @@ static struct amd64_family_type amd64_family_types[] = {
.f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
.ops = {
.early_channel_count = k8_early_channel_count,
- .get_error_address = k8_get_error_address,
- .read_dram_base_limit = k8_read_dram_base_limit,
.map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
.dbam_to_cs = k8_dbam_to_chip_select,
+ .read_dct_pci_cfg = k8_read_dct_pci_cfg,
}
},
[F10_CPUS] = {
@@ -1675,12 +1596,21 @@ static struct amd64_family_type amd64_family_types[] = {
.f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
.f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
.ops = {
- .early_channel_count = f10_early_channel_count,
- .get_error_address = f10_get_error_address,
- .read_dram_base_limit = f10_read_dram_base_limit,
- .read_dram_ctl_register = f10_read_dram_ctl_register,
- .map_sysaddr_to_csrow = f10_map_sysaddr_to_csrow,
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
.dbam_to_cs = f10_dbam_to_chip_select,
+ .read_dct_pci_cfg = f10_read_dct_pci_cfg,
+ }
+ },
+ [F15_CPUS] = {
+ .ctl_name = "F15h",
+ .f1_id = PCI_DEVICE_ID_AMD_15H_NB_F1,
+ .f3_id = PCI_DEVICE_ID_AMD_15H_NB_F3,
+ .ops = {
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
+ .dbam_to_cs = f15_dbam_to_chip_select,
+ .read_dct_pci_cfg = f15_read_dct_pci_cfg,
}
},
};
@@ -1770,15 +1700,15 @@ static u16 x8_vectors[] = {
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
};
-static int decode_syndrome(u16 syndrome, u16 *vectors, int num_vecs,
- int v_dim)
+static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
+ unsigned v_dim)
{
unsigned int i, err_sym;
for (err_sym = 0; err_sym < num_vecs / v_dim; err_sym++) {
u16 s = syndrome;
- int v_idx = err_sym * v_dim;
- int v_end = (err_sym + 1) * v_dim;
+ unsigned v_idx = err_sym * v_dim;
+ unsigned v_end = (err_sym + 1) * v_dim;
/* walk over all 16 bits of the syndrome */
for (i = 1; i < (1U << 16); i <<= 1) {
@@ -1850,51 +1780,50 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
struct amd64_pvt *pvt = mci->pvt_info;
int err_sym = -1;
- if (pvt->syn_type == 8)
+ if (pvt->ecc_sym_sz == 8)
err_sym = decode_syndrome(syndrome, x8_vectors,
ARRAY_SIZE(x8_vectors),
- pvt->syn_type);
- else if (pvt->syn_type == 4)
+ pvt->ecc_sym_sz);
+ else if (pvt->ecc_sym_sz == 4)
err_sym = decode_syndrome(syndrome, x4_vectors,
ARRAY_SIZE(x4_vectors),
- pvt->syn_type);
+ pvt->ecc_sym_sz);
else {
- amd64_warn("Illegal syndrome type: %u\n", pvt->syn_type);
+ amd64_warn("Illegal syndrome type: %u\n", pvt->ecc_sym_sz);
return err_sym;
}
- return map_err_sym_to_channel(err_sym, pvt->syn_type);
+ return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
}
/*
* Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
* ADDRESS and process.
*/
-static void amd64_handle_ce(struct mem_ctl_info *mci,
- struct err_regs *info)
+static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
{
struct amd64_pvt *pvt = mci->pvt_info;
u64 sys_addr;
+ u16 syndrome;
/* Ensure that the Error Address is VALID */
- if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+ if (!(m->status & MCI_STATUS_ADDRV)) {
amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
return;
}
- sys_addr = pvt->ops->get_error_address(mci, info);
+ sys_addr = get_error_address(m);
+ syndrome = extract_syndrome(m->status);
amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
- pvt->ops->map_sysaddr_to_csrow(mci, info, sys_addr);
+ pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome);
}
/* Handle any Un-correctable Errors (UEs) */
-static void amd64_handle_ue(struct mem_ctl_info *mci,
- struct err_regs *info)
+static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
{
- struct amd64_pvt *pvt = mci->pvt_info;
struct mem_ctl_info *log_mci, *src_mci = NULL;
int csrow;
u64 sys_addr;
@@ -1902,13 +1831,13 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
log_mci = mci;
- if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+ if (!(m->status & MCI_STATUS_ADDRV)) {
amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
return;
}
- sys_addr = pvt->ops->get_error_address(mci, info);
+ sys_addr = get_error_address(m);
/*
* Find out which node the error address belongs to. This may be
@@ -1936,14 +1865,14 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
}
static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
- struct err_regs *info)
+ struct mce *m)
{
- u16 ec = EC(info->nbsl);
- u8 xec = XEC(info->nbsl, 0x1f);
- int ecc_type = (info->nbsh >> 13) & 0x3;
+ u16 ec = EC(m->status);
+ u8 xec = XEC(m->status, 0x1f);
+ u8 ecc_type = (m->status >> 45) & 0x3;
/* Bail early out if this was an 'observed' error */
- if (PP(ec) == K8_NBSL_PP_OBS)
+ if (PP(ec) == NBSL_PP_OBS)
return;
/* Do only ECC errors */
@@ -1951,34 +1880,16 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
return;
if (ecc_type == 2)
- amd64_handle_ce(mci, info);
+ amd64_handle_ce(mci, m);
else if (ecc_type == 1)
- amd64_handle_ue(mci, info);
+ amd64_handle_ue(mci, m);
}
void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
{
struct mem_ctl_info *mci = mcis[node_id];
- struct err_regs regs;
-
- regs.nbsl = (u32) m->status;
- regs.nbsh = (u32)(m->status >> 32);
- regs.nbeal = (u32) m->addr;
- regs.nbeah = (u32)(m->addr >> 32);
- regs.nbcfg = nbcfg;
-
- __amd64_decode_bus_error(mci, &regs);
-
- /*
- * Check the UE bit of the NB status high register, if set generate some
- * logs. If NOT a GART error, then process the event as a NO-INFO event.
- * If it was a GART error, skip that process.
- *
- * FIXME: this should go somewhere else, if at all.
- */
- if (regs.nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
- edac_mc_handle_ue_no_info(mci, "UE bit is set");
+ __amd64_decode_bus_error(mci, m);
}
/*
@@ -2027,9 +1938,10 @@ static void free_mc_sibling_devs(struct amd64_pvt *pvt)
*/
static void read_mc_regs(struct amd64_pvt *pvt)
{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
u64 msr_val;
u32 tmp;
- int dram;
+ unsigned range;
/*
* Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
@@ -2046,75 +1958,66 @@ static void read_mc_regs(struct amd64_pvt *pvt)
} else
debugf0(" TOP_MEM2 disabled.\n");
- amd64_read_pci_cfg(pvt->F3, K8_NBCAP, &pvt->nbcap);
+ amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
- if (pvt->ops->read_dram_ctl_register)
- pvt->ops->read_dram_ctl_register(pvt);
+ read_dram_ctl_register(pvt);
- for (dram = 0; dram < DRAM_REG_COUNT; dram++) {
- /*
- * Call CPU specific READ function to get the DRAM Base and
- * Limit values from the DCT.
- */
- pvt->ops->read_dram_base_limit(pvt, dram);
+ for (range = 0; range < DRAM_RANGES; range++) {
+ u8 rw;
- /*
- * Only print out debug info on rows with both R and W Enabled.
- * Normal processing, compiler should optimize this whole 'if'
- * debug output block away.
- */
- if (pvt->dram_rw_en[dram] != 0) {
- debugf1(" DRAM-BASE[%d]: 0x%016llx "
- "DRAM-LIMIT: 0x%016llx\n",
- dram,
- pvt->dram_base[dram],
- pvt->dram_limit[dram]);
-
- debugf1(" IntlvEn=%s %s %s "
- "IntlvSel=%d DstNode=%d\n",
- pvt->dram_IntlvEn[dram] ?
- "Enabled" : "Disabled",
- (pvt->dram_rw_en[dram] & 0x2) ? "W" : "!W",
- (pvt->dram_rw_en[dram] & 0x1) ? "R" : "!R",
- pvt->dram_IntlvSel[dram],
- pvt->dram_DstNode[dram]);
- }
+ /* read settings for this DRAM range */
+ read_dram_base_limit_regs(pvt, range);
+
+ rw = dram_rw(pvt, range);
+ if (!rw)
+ continue;
+
+ debugf1(" DRAM range[%d], base: 0x%016llx; limit: 0x%016llx\n",
+ range,
+ get_dram_base(pvt, range),
+ get_dram_limit(pvt, range));
+
+ debugf1(" IntlvEn=%s; Range access: %s%s IntlvSel=%d DstNode=%d\n",
+ dram_intlv_en(pvt, range) ? "Enabled" : "Disabled",
+ (rw & 0x1) ? "R" : "-",
+ (rw & 0x2) ? "W" : "-",
+ dram_intlv_sel(pvt, range),
+ dram_dst_node(pvt, range));
}
- amd64_read_dct_base_mask(pvt);
+ read_dct_base_mask(pvt);
- amd64_read_pci_cfg(pvt->F1, K8_DHAR, &pvt->dhar);
- amd64_read_dbam_reg(pvt);
+ amd64_read_pci_cfg(pvt->F1, DHAR, &pvt->dhar);
+ amd64_read_dct_pci_cfg(pvt, DBAM0, &pvt->dbam0);
amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
- amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
- amd64_read_pci_cfg(pvt->F2, F10_DCHR_0, &pvt->dchr0);
+ amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0);
+ amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0);
- if (boot_cpu_data.x86 >= 0x10) {
- if (!dct_ganging_enabled(pvt)) {
- amd64_read_pci_cfg(pvt->F2, F10_DCLR_1, &pvt->dclr1);
- amd64_read_pci_cfg(pvt->F2, F10_DCHR_1, &pvt->dchr1);
- }
- amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
+ if (!dct_ganging_enabled(pvt)) {
+ amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1);
+ amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1);
}
- if (boot_cpu_data.x86 == 0x10 &&
- boot_cpu_data.x86_model > 7 &&
- /* F3x180[EccSymbolSize]=1 => x8 symbols */
- tmp & BIT(25))
- pvt->syn_type = 8;
- else
- pvt->syn_type = 4;
+ pvt->ecc_sym_sz = 4;
- amd64_dump_misc_regs(pvt);
+ if (c->x86 >= 0x10) {
+ amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
+ amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
+
+ /* F10h, revD and later can do x8 ECC too */
+ if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
+ pvt->ecc_sym_sz = 8;
+ }
+ dump_misc_regs(pvt);
}
/*
* NOTE: CPU Revision Dependent code
*
* Input:
- * @csrow_nr ChipSelect Row Number (0..pvt->cs_count-1)
+ * @csrow_nr ChipSelect Row Number (0..NUM_CHIPSELECTS-1)
* k8 private pointer to -->
* DRAM Bank Address mapping register
* node_id
@@ -2144,7 +2047,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
* encompasses
*
*/
-static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
+static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
{
u32 cs_mode, nr_pages;
@@ -2157,7 +2060,7 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
*/
cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
- nr_pages = pvt->ops->dbam_to_cs(pvt, cs_mode) << (20 - PAGE_SHIFT);
+ nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
/*
* If dual channel then double the memory size of single channel.
@@ -2180,23 +2083,22 @@ static int init_csrows(struct mem_ctl_info *mci)
{
struct csrow_info *csrow;
struct amd64_pvt *pvt = mci->pvt_info;
- u64 input_addr_min, input_addr_max, sys_addr;
+ u64 input_addr_min, input_addr_max, sys_addr, base, mask;
u32 val;
int i, empty = 1;
- amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &val);
+ amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
pvt->nbcfg = val;
- pvt->ctl_error_info.nbcfg = val;
debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
pvt->mc_node_id, val,
- !!(val & K8_NBCFG_CHIPKILL), !!(val & K8_NBCFG_ECC_ENABLE));
+ !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
- for (i = 0; i < pvt->cs_count; i++) {
+ for_each_chip_select(i, 0, pvt) {
csrow = &mci->csrows[i];
- if ((pvt->dcsb0[i] & K8_DCSB_CS_ENABLE) == 0) {
+ if (!csrow_enabled(i, 0, pvt)) {
debugf1("----CSROW %d EMPTY for node %d\n", i,
pvt->mc_node_id);
continue;
@@ -2206,13 +2108,15 @@ static int init_csrows(struct mem_ctl_info *mci)
i, pvt->mc_node_id);
empty = 0;
- csrow->nr_pages = amd64_csrow_nr_pages(i, pvt);
+ csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
sys_addr = input_addr_to_sys_addr(mci, input_addr_max);
csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT);
- csrow->page_mask = ~mask_from_dct_mask(pvt, i);
+
+ get_cs_base_and_mask(pvt, i, 0, &base, &mask);
+ csrow->page_mask = ~mask;
/* 8 bytes of resolution */
csrow->mtype = amd64_determine_memory_type(pvt, i);
@@ -2231,9 +2135,9 @@ static int init_csrows(struct mem_ctl_info *mci)
/*
* determine whether CHIPKILL or JUST ECC or NO ECC is operating
*/
- if (pvt->nbcfg & K8_NBCFG_ECC_ENABLE)
+ if (pvt->nbcfg & NBCFG_ECC_ENABLE)
csrow->edac_mode =
- (pvt->nbcfg & K8_NBCFG_CHIPKILL) ?
+ (pvt->nbcfg & NBCFG_CHIPKILL) ?
EDAC_S4ECD4ED : EDAC_SECDED;
else
csrow->edac_mode = EDAC_NONE;
@@ -2243,7 +2147,7 @@ static int init_csrows(struct mem_ctl_info *mci)
}
/* get all cores on this DCT */
-static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid)
+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
{
int cpu;
@@ -2253,7 +2157,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, int nid)
}
/* check MCG_CTL on all the cpus on this node */
-static bool amd64_nb_mce_bank_enabled_on_node(int nid)
+static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
{
cpumask_var_t mask;
int cpu, nbe;
@@ -2270,7 +2174,7 @@ static bool amd64_nb_mce_bank_enabled_on_node(int nid)
for_each_cpu(cpu, mask) {
struct msr *reg = per_cpu_ptr(msrs, cpu);
- nbe = reg->l & K8_MSR_MCGCTL_NBE;
+ nbe = reg->l & MSR_MCGCTL_NBE;
debugf0("core: %u, MCG_CTL: 0x%llx, NB MSR is %s\n",
cpu, reg->q,
@@ -2305,16 +2209,16 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
struct msr *reg = per_cpu_ptr(msrs, cpu);
if (on) {
- if (reg->l & K8_MSR_MCGCTL_NBE)
+ if (reg->l & MSR_MCGCTL_NBE)
s->flags.nb_mce_enable = 1;
- reg->l |= K8_MSR_MCGCTL_NBE;
+ reg->l |= MSR_MCGCTL_NBE;
} else {
/*
* Turn off NB MCE reporting only when it was off before
*/
if (!s->flags.nb_mce_enable)
- reg->l &= ~K8_MSR_MCGCTL_NBE;
+ reg->l &= ~MSR_MCGCTL_NBE;
}
}
wrmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
@@ -2328,40 +2232,38 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
struct pci_dev *F3)
{
bool ret = true;
- u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
+ u32 value, mask = 0x3; /* UECC/CECC enable */
if (toggle_ecc_err_reporting(s, nid, ON)) {
amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
return false;
}
- amd64_read_pci_cfg(F3, K8_NBCTL, &value);
+ amd64_read_pci_cfg(F3, NBCTL, &value);
- /* turn on UECCEn and CECCEn bits */
s->old_nbctl = value & mask;
s->nbctl_valid = true;
value |= mask;
- pci_write_config_dword(F3, K8_NBCTL, value);
+ amd64_write_pci_cfg(F3, NBCTL, value);
- amd64_read_pci_cfg(F3, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, NBCFG, &value);
- debugf0("1: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
- nid, value,
- !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
+ debugf0("1: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+ nid, value, !!(value & NBCFG_ECC_ENABLE));
- if (!(value & K8_NBCFG_ECC_ENABLE)) {
+ if (!(value & NBCFG_ECC_ENABLE)) {
amd64_warn("DRAM ECC disabled on this node, enabling...\n");
s->flags.nb_ecc_prev = 0;
/* Attempt to turn on DRAM ECC Enable */
- value |= K8_NBCFG_ECC_ENABLE;
- pci_write_config_dword(F3, K8_NBCFG, value);
+ value |= NBCFG_ECC_ENABLE;
+ amd64_write_pci_cfg(F3, NBCFG, value);
- amd64_read_pci_cfg(F3, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, NBCFG, &value);
- if (!(value & K8_NBCFG_ECC_ENABLE)) {
+ if (!(value & NBCFG_ECC_ENABLE)) {
amd64_warn("Hardware rejected DRAM ECC enable,"
"check memory DIMM configuration.\n");
ret = false;
@@ -2372,9 +2274,8 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
s->flags.nb_ecc_prev = 1;
}
- debugf0("2: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
- nid, value,
- !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
+ debugf0("2: node %d, NBCFG=0x%08x[DramEccEn: %d]\n",
+ nid, value, !!(value & NBCFG_ECC_ENABLE));
return ret;
}
@@ -2382,22 +2283,23 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
struct pci_dev *F3)
{
- u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
+ u32 value, mask = 0x3; /* UECC/CECC enable */
+
if (!s->nbctl_valid)
return;
- amd64_read_pci_cfg(F3, K8_NBCTL, &value);
+ amd64_read_pci_cfg(F3, NBCTL, &value);
value &= ~mask;
value |= s->old_nbctl;
- pci_write_config_dword(F3, K8_NBCTL, value);
+ amd64_write_pci_cfg(F3, NBCTL, value);
/* restore previous BIOS DRAM ECC "off" setting we force-enabled */
if (!s->flags.nb_ecc_prev) {
- amd64_read_pci_cfg(F3, K8_NBCFG, &value);
- value &= ~K8_NBCFG_ECC_ENABLE;
- pci_write_config_dword(F3, K8_NBCFG, value);
+ amd64_read_pci_cfg(F3, NBCFG, &value);
+ value &= ~NBCFG_ECC_ENABLE;
+ amd64_write_pci_cfg(F3, NBCFG, value);
}
/* restore the NB Enable MCGCTL bit */
@@ -2423,9 +2325,9 @@ static bool ecc_enabled(struct pci_dev *F3, u8 nid)
u8 ecc_en = 0;
bool nb_mce_en = false;
- amd64_read_pci_cfg(F3, K8_NBCFG, &value);
+ amd64_read_pci_cfg(F3, NBCFG, &value);
- ecc_en = !!(value & K8_NBCFG_ECC_ENABLE);
+ ecc_en = !!(value & NBCFG_ECC_ENABLE);
amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
@@ -2463,23 +2365,24 @@ static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
mci->mc_driver_sysfs_attributes = sysfs_attrs;
}
-static void setup_mci_misc_attrs(struct mem_ctl_info *mci)
+static void setup_mci_misc_attrs(struct mem_ctl_info *mci,
+ struct amd64_family_type *fam)
{
struct amd64_pvt *pvt = mci->pvt_info;
mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
mci->edac_ctl_cap = EDAC_FLAG_NONE;
- if (pvt->nbcap & K8_NBCAP_SECDED)
+ if (pvt->nbcap & NBCAP_SECDED)
mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
- if (pvt->nbcap & K8_NBCAP_CHIPKILL)
+ if (pvt->nbcap & NBCAP_CHIPKILL)
mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
mci->edac_cap = amd64_determine_edac_cap(pvt);
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = EDAC_AMD64_VERSION;
- mci->ctl_name = pvt->ctl_name;
+ mci->ctl_name = fam->ctl_name;
mci->dev_name = pci_name(pvt->F2);
mci->ctl_page_to_phys = NULL;
@@ -2500,14 +2403,16 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
case 0xf:
fam_type = &amd64_family_types[K8_CPUS];
pvt->ops = &amd64_family_types[K8_CPUS].ops;
- pvt->ctl_name = fam_type->ctl_name;
- pvt->min_scrubrate = K8_MIN_SCRUB_RATE_BITS;
break;
+
case 0x10:
fam_type = &amd64_family_types[F10_CPUS];
pvt->ops = &amd64_family_types[F10_CPUS].ops;
- pvt->ctl_name = fam_type->ctl_name;
- pvt->min_scrubrate = F10_MIN_SCRUB_RATE_BITS;
+ break;
+
+ case 0x15:
+ fam_type = &amd64_family_types[F15_CPUS];
+ pvt->ops = &amd64_family_types[F15_CPUS].ops;
break;
default:
@@ -2517,7 +2422,7 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
pvt->ext_model = boot_cpu_data.x86_model >> 4;
- amd64_info("%s %sdetected (node %d).\n", pvt->ctl_name,
+ amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
(fam == 0xf ?
(pvt->ext_model >= K8_REV_F ? "revF or later "
: "revE or earlier ")
@@ -2564,14 +2469,14 @@ static int amd64_init_one_instance(struct pci_dev *F2)
goto err_siblings;
ret = -ENOMEM;
- mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, nid);
+ mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid);
if (!mci)
goto err_siblings;
mci->pvt_info = pvt;
mci->dev = &pvt->F2->dev;
- setup_mci_misc_attrs(mci);
+ setup_mci_misc_attrs(mci, fam_type);
if (init_csrows(mci))
mci->edac_cap = EDAC_FLAG_NONE;
@@ -2714,6 +2619,15 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = {
.class = 0,
.class_mask = 0,
},
+ {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_15H_NB_F2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ },
+
{0, }
};
MODULE_DEVICE_TABLE(pci, amd64_pci_table);
@@ -2754,7 +2668,7 @@ static int __init amd64_edac_init(void)
{
int err = -ENODEV;
- edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n");
+ printk(KERN_INFO "AMD64 EDAC driver v%s\n", EDAC_AMD64_VERSION);
opstate_init();
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 613ec72b0f65..11be36a311eb 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -144,7 +144,7 @@
* sections 3.5.4 and 3.5.5 for more information.
*/
-#define EDAC_AMD64_VERSION "v3.3.0"
+#define EDAC_AMD64_VERSION "3.4.0"
#define EDAC_MOD_STR "amd64_edac"
/* Extended Model from CPUID, for CPU Revision numbers */
@@ -153,85 +153,64 @@
#define K8_REV_F 4
/* Hardware limit on ChipSelect rows per MC and processors per system */
-#define MAX_CS_COUNT 8
-#define DRAM_REG_COUNT 8
+#define NUM_CHIPSELECTS 8
+#define DRAM_RANGES 8
#define ON true
#define OFF false
/*
+ * Create a contiguous bitmask starting at bit position @lo and ending at
+ * position @hi. For example
+ *
+ * GENMASK(21, 39) gives us the 64bit vector 0x000000ffffe00000.
+ */
+#define GENMASK(lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo))
+
+/*
* PCI-defined configuration space registers
*/
+#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
+#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
/*
* Function 1 - Address Map
*/
-#define K8_DRAM_BASE_LOW 0x40
-#define K8_DRAM_LIMIT_LOW 0x44
-#define K8_DHAR 0xf0
-
-#define DHAR_VALID BIT(0)
-#define F10_DRAM_MEM_HOIST_VALID BIT(1)
+#define DRAM_BASE_LO 0x40
+#define DRAM_LIMIT_LO 0x44
-#define DHAR_BASE_MASK 0xff000000
-#define dhar_base(dhar) (dhar & DHAR_BASE_MASK)
+#define dram_intlv_en(pvt, i) ((u8)((pvt->ranges[i].base.lo >> 8) & 0x7))
+#define dram_rw(pvt, i) ((u8)(pvt->ranges[i].base.lo & 0x3))
+#define dram_intlv_sel(pvt, i) ((u8)((pvt->ranges[i].lim.lo >> 8) & 0x7))
+#define dram_dst_node(pvt, i) ((u8)(pvt->ranges[i].lim.lo & 0x7))
-#define K8_DHAR_OFFSET_MASK 0x0000ff00
-#define k8_dhar_offset(dhar) ((dhar & K8_DHAR_OFFSET_MASK) << 16)
+#define DHAR 0xf0
+#define dhar_valid(pvt) ((pvt)->dhar & BIT(0))
+#define dhar_mem_hoist_valid(pvt) ((pvt)->dhar & BIT(1))
+#define dhar_base(pvt) ((pvt)->dhar & 0xff000000)
+#define k8_dhar_offset(pvt) (((pvt)->dhar & 0x0000ff00) << 16)
-#define F10_DHAR_OFFSET_MASK 0x0000ff80
/* NOTE: Extra mask bit vs K8 */
-#define f10_dhar_offset(dhar) ((dhar & F10_DHAR_OFFSET_MASK) << 16)
+#define f10_dhar_offset(pvt) (((pvt)->dhar & 0x0000ff80) << 16)
+#define DCT_CFG_SEL 0x10C
-/* F10 High BASE/LIMIT registers */
-#define F10_DRAM_BASE_HIGH 0x140
-#define F10_DRAM_LIMIT_HIGH 0x144
+#define DRAM_BASE_HI 0x140
+#define DRAM_LIMIT_HI 0x144
/*
* Function 2 - DRAM controller
*/
-#define K8_DCSB0 0x40
-#define F10_DCSB1 0x140
+#define DCSB0 0x40
+#define DCSB1 0x140
+#define DCSB_CS_ENABLE BIT(0)
-#define K8_DCSB_CS_ENABLE BIT(0)
-#define K8_DCSB_NPT_SPARE BIT(1)
-#define K8_DCSB_NPT_TESTFAIL BIT(2)
+#define DCSM0 0x60
+#define DCSM1 0x160
-/*
- * REV E: select [31:21] and [15:9] from DCSB and the shift amount to form
- * the address
- */
-#define REV_E_DCSB_BASE_BITS (0xFFE0FE00ULL)
-#define REV_E_DCS_SHIFT 4
-
-#define REV_F_F1Xh_DCSB_BASE_BITS (0x1FF83FE0ULL)
-#define REV_F_F1Xh_DCS_SHIFT 8
-
-/*
- * REV F and later: selects [28:19] and [13:5] from DCSB and the shift amount
- * to form the address
- */
-#define REV_F_DCSB_BASE_BITS (0x1FF83FE0ULL)
-#define REV_F_DCS_SHIFT 8
-
-/* DRAM CS Mask Registers */
-#define K8_DCSM0 0x60
-#define F10_DCSM1 0x160
-
-/* REV E: select [29:21] and [15:9] from DCSM */
-#define REV_E_DCSM_MASK_BITS 0x3FE0FE00
-
-/* unused bits [24:20] and [12:0] */
-#define REV_E_DCS_NOTUSED_BITS 0x01F01FFF
-
-/* REV F and later: select [28:19] and [13:5] from DCSM */
-#define REV_F_F1Xh_DCSM_MASK_BITS 0x1FF83FE0
-
-/* unused bits [26:22] and [12:0] */
-#define REV_F_F1Xh_DCS_NOTUSED_BITS 0x07C01FFF
+#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE)
#define DBAM0 0x80
#define DBAM1 0x180
@@ -241,148 +220,84 @@
#define DBAM_MAX_VALUE 11
-
-#define F10_DCLR_0 0x90
-#define F10_DCLR_1 0x190
+#define DCLR0 0x90
+#define DCLR1 0x190
#define REVE_WIDTH_128 BIT(16)
-#define F10_WIDTH_128 BIT(11)
+#define WIDTH_128 BIT(11)
+#define DCHR0 0x94
+#define DCHR1 0x194
+#define DDR3_MODE BIT(8)
-#define F10_DCHR_0 0x94
-#define F10_DCHR_1 0x194
+#define DCT_SEL_LO 0x110
+#define dct_sel_baseaddr(pvt) ((pvt)->dct_sel_lo & 0xFFFFF800)
+#define dct_sel_interleave_addr(pvt) (((pvt)->dct_sel_lo >> 6) & 0x3)
+#define dct_high_range_enabled(pvt) ((pvt)->dct_sel_lo & BIT(0))
+#define dct_interleave_enabled(pvt) ((pvt)->dct_sel_lo & BIT(2))
-#define F10_DCHR_FOUR_RANK_DIMM BIT(18)
-#define DDR3_MODE BIT(8)
-#define F10_DCHR_MblMode BIT(6)
+#define dct_ganging_enabled(pvt) ((boot_cpu_data.x86 == 0x10) && ((pvt)->dct_sel_lo & BIT(4)))
+#define dct_data_intlv_enabled(pvt) ((pvt)->dct_sel_lo & BIT(5))
+#define dct_memory_cleared(pvt) ((pvt)->dct_sel_lo & BIT(10))
-#define F10_DCTL_SEL_LOW 0x110
-#define dct_sel_baseaddr(pvt) ((pvt->dram_ctl_select_low) & 0xFFFFF800)
-#define dct_sel_interleave_addr(pvt) (((pvt->dram_ctl_select_low) >> 6) & 0x3)
-#define dct_high_range_enabled(pvt) (pvt->dram_ctl_select_low & BIT(0))
-#define dct_interleave_enabled(pvt) (pvt->dram_ctl_select_low & BIT(2))
-#define dct_ganging_enabled(pvt) (pvt->dram_ctl_select_low & BIT(4))
-#define dct_data_intlv_enabled(pvt) (pvt->dram_ctl_select_low & BIT(5))
-#define dct_dram_enabled(pvt) (pvt->dram_ctl_select_low & BIT(8))
-#define dct_memory_cleared(pvt) (pvt->dram_ctl_select_low & BIT(10))
+#define SWAP_INTLV_REG 0x10c
-#define F10_DCTL_SEL_HIGH 0x114
+#define DCT_SEL_HI 0x114
/*
* Function 3 - Misc Control
*/
-#define K8_NBCTL 0x40
-
-/* Correctable ECC error reporting enable */
-#define K8_NBCTL_CECCEn BIT(0)
-
-/* UnCorrectable ECC error reporting enable */
-#define K8_NBCTL_UECCEn BIT(1)
+#define NBCTL 0x40
-#define K8_NBCFG 0x44
-#define K8_NBCFG_CHIPKILL BIT(23)
-#define K8_NBCFG_ECC_ENABLE BIT(22)
+#define NBCFG 0x44
+#define NBCFG_CHIPKILL BIT(23)
+#define NBCFG_ECC_ENABLE BIT(22)
-#define K8_NBSL 0x48
-
-
-/* Family F10h: Normalized Extended Error Codes */
-#define F10_NBSL_EXT_ERR_RES 0x0
+/* F3x48: NBSL */
#define F10_NBSL_EXT_ERR_ECC 0x8
+#define NBSL_PP_OBS 0x2
-/* Next two are overloaded values */
-#define F10_NBSL_EXT_ERR_LINK_PROTO 0xB
-#define F10_NBSL_EXT_ERR_L3_PROTO 0xB
-
-#define F10_NBSL_EXT_ERR_NB_ARRAY 0xC
-#define F10_NBSL_EXT_ERR_DRAM_PARITY 0xD
-#define F10_NBSL_EXT_ERR_LINK_RETRY 0xE
-
-/* Next two are overloaded values */
-#define F10_NBSL_EXT_ERR_GART_WALK 0xF
-#define F10_NBSL_EXT_ERR_DEV_WALK 0xF
-
-/* 0x10 to 0x1B: Reserved */
-#define F10_NBSL_EXT_ERR_L3_DATA 0x1C
-#define F10_NBSL_EXT_ERR_L3_TAG 0x1D
-#define F10_NBSL_EXT_ERR_L3_LRU 0x1E
-
-/* K8: Normalized Extended Error Codes */
-#define K8_NBSL_EXT_ERR_ECC 0x0
-#define K8_NBSL_EXT_ERR_CRC 0x1
-#define K8_NBSL_EXT_ERR_SYNC 0x2
-#define K8_NBSL_EXT_ERR_MST 0x3
-#define K8_NBSL_EXT_ERR_TGT 0x4
-#define K8_NBSL_EXT_ERR_GART 0x5
-#define K8_NBSL_EXT_ERR_RMW 0x6
-#define K8_NBSL_EXT_ERR_WDT 0x7
-#define K8_NBSL_EXT_ERR_CHIPKILL_ECC 0x8
-#define K8_NBSL_EXT_ERR_DRAM_PARITY 0xD
-
-/*
- * The following are for BUS type errors AFTER values have been normalized by
- * shifting right
- */
-#define K8_NBSL_PP_SRC 0x0
-#define K8_NBSL_PP_RES 0x1
-#define K8_NBSL_PP_OBS 0x2
-#define K8_NBSL_PP_GENERIC 0x3
-
-#define EXTRACT_ERR_CPU_MAP(x) ((x) & 0xF)
-
-#define K8_NBEAL 0x50
-#define K8_NBEAH 0x54
-#define K8_SCRCTRL 0x58
-
-#define F10_NB_CFG_LOW 0x88
+#define SCRCTRL 0x58
#define F10_ONLINE_SPARE 0xB0
-#define F10_ONLINE_SPARE_SWAPDONE0(x) ((x) & BIT(1))
-#define F10_ONLINE_SPARE_SWAPDONE1(x) ((x) & BIT(3))
-#define F10_ONLINE_SPARE_BADDRAM_CS0(x) (((x) >> 4) & 0x00000007)
-#define F10_ONLINE_SPARE_BADDRAM_CS1(x) (((x) >> 8) & 0x00000007)
+#define online_spare_swap_done(pvt, c) (((pvt)->online_spare >> (1 + 2 * (c))) & 0x1)
+#define online_spare_bad_dramcs(pvt, c) (((pvt)->online_spare >> (4 + 4 * (c))) & 0x7)
#define F10_NB_ARRAY_ADDR 0xB8
-
-#define F10_NB_ARRAY_DRAM_ECC 0x80000000
+#define F10_NB_ARRAY_DRAM_ECC BIT(31)
/* Bits [2:1] are used to select 16-byte section within a 64-byte cacheline */
#define SET_NB_ARRAY_ADDRESS(section) (((section) & 0x3) << 1)
#define F10_NB_ARRAY_DATA 0xBC
-
#define SET_NB_DRAM_INJECTION_WRITE(word, bits) \
(BIT(((word) & 0xF) + 20) | \
BIT(17) | bits)
-
#define SET_NB_DRAM_INJECTION_READ(word, bits) \
(BIT(((word) & 0xF) + 20) | \
BIT(16) | bits)
-#define K8_NBCAP 0xE8
-#define K8_NBCAP_CORES (BIT(12)|BIT(13))
-#define K8_NBCAP_CHIPKILL BIT(4)
-#define K8_NBCAP_SECDED BIT(3)
-#define K8_NBCAP_DCT_DUAL BIT(0)
+#define NBCAP 0xE8
+#define NBCAP_CHIPKILL BIT(4)
+#define NBCAP_SECDED BIT(3)
+#define NBCAP_DCT_DUAL BIT(0)
#define EXT_NB_MCA_CFG 0x180
/* MSRs */
-#define K8_MSR_MCGCTL_NBE BIT(4)
-
-#define K8_MSR_MC4CTL 0x0410
-#define K8_MSR_MC4STAT 0x0411
-#define K8_MSR_MC4ADDR 0x0412
+#define MSR_MCGCTL_NBE BIT(4)
/* AMD sets the first MC device at device ID 0x18. */
-static inline int get_node_id(struct pci_dev *pdev)
+static inline u8 get_node_id(struct pci_dev *pdev)
{
return PCI_SLOT(pdev->devfn) - 0x18;
}
-enum amd64_chipset_families {
+enum amd_families {
K8_CPUS = 0,
F10_CPUS,
+ F15_CPUS,
+ NUM_FAMILIES,
};
/* Error injection control structure */
@@ -392,13 +307,35 @@ struct error_injection {
u32 bit_map;
};
+/* low and high part of PCI config space regs */
+struct reg_pair {
+ u32 lo, hi;
+};
+
+/*
+ * See F1x[1, 0][7C:40] DRAM Base/Limit Registers
+ */
+struct dram_range {
+ struct reg_pair base;
+ struct reg_pair lim;
+};
+
+/* A DCT chip selects collection */
+struct chip_select {
+ u32 csbases[NUM_CHIPSELECTS];
+ u8 b_cnt;
+
+ u32 csmasks[NUM_CHIPSELECTS];
+ u8 m_cnt;
+};
+
struct amd64_pvt {
struct low_ops *ops;
/* pci_device handles which we utilize */
struct pci_dev *F1, *F2, *F3;
- int mc_node_id; /* MC index of this MC node */
+ unsigned mc_node_id; /* MC index of this MC node */
int ext_model; /* extended model value of this node */
int channel_count;
@@ -414,60 +351,50 @@ struct amd64_pvt {
u32 dbam0; /* DRAM Base Address Mapping reg for DCT0 */
u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */
- /* DRAM CS Base Address Registers F2x[1,0][5C:40] */
- u32 dcsb0[MAX_CS_COUNT];
- u32 dcsb1[MAX_CS_COUNT];
-
- /* DRAM CS Mask Registers F2x[1,0][6C:60] */
- u32 dcsm0[MAX_CS_COUNT];
- u32 dcsm1[MAX_CS_COUNT];
-
- /*
- * Decoded parts of DRAM BASE and LIMIT Registers
- * F1x[78,70,68,60,58,50,48,40]
- */
- u64 dram_base[DRAM_REG_COUNT];
- u64 dram_limit[DRAM_REG_COUNT];
- u8 dram_IntlvSel[DRAM_REG_COUNT];
- u8 dram_IntlvEn[DRAM_REG_COUNT];
- u8 dram_DstNode[DRAM_REG_COUNT];
- u8 dram_rw_en[DRAM_REG_COUNT];
-
- /*
- * The following fields are set at (load) run time, after CPU revision
- * has been determined, since the dct_base and dct_mask registers vary
- * based on revision
- */
- u32 dcsb_base; /* DCSB base bits */
- u32 dcsm_mask; /* DCSM mask bits */
- u32 cs_count; /* num chip selects (== num DCSB registers) */
- u32 num_dcsm; /* Number of DCSM registers */
- u32 dcs_mask_notused; /* DCSM notused mask bits */
- u32 dcs_shift; /* DCSB and DCSM shift value */
+ /* one for each DCT */
+ struct chip_select csels[2];
+
+ /* DRAM base and limit pairs F1x[78,70,68,60,58,50,48,40] */
+ struct dram_range ranges[DRAM_RANGES];
u64 top_mem; /* top of memory below 4GB */
u64 top_mem2; /* top of memory above 4GB */
- u32 dram_ctl_select_low; /* DRAM Controller Select Low Reg */
- u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */
- u32 online_spare; /* On-Line spare Reg */
+ u32 dct_sel_lo; /* DRAM Controller Select Low */
+ u32 dct_sel_hi; /* DRAM Controller Select High */
+ u32 online_spare; /* On-Line spare Reg */
/* x4 or x8 syndromes in use */
- u8 syn_type;
-
- /* temp storage for when input is received from sysfs */
- struct err_regs ctl_error_info;
+ u8 ecc_sym_sz;
/* place to store error injection parameters prior to issue */
struct error_injection injection;
+};
- /* DCT per-family scrubrate setting */
- u32 min_scrubrate;
+static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
+{
+ u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
- /* family name this instance is running on */
- const char *ctl_name;
+ if (boot_cpu_data.x86 == 0xf)
+ return addr;
-};
+ return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr;
+}
+
+static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)
+{
+ u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff;
+
+ if (boot_cpu_data.x86 == 0xf)
+ return lim;
+
+ return (((u64)pvt->ranges[i].lim.hi & 0x000000ff) << 40) | lim;
+}
+
+static inline u16 extract_syndrome(u64 status)
+{
+ return ((status >> 47) & 0xff) | ((status >> 16) & 0xff00);
+}
/*
* per-node ECC settings descriptor
@@ -482,14 +409,6 @@ struct ecc_settings {
} flags;
};
-extern const char *tt_msgs[4];
-extern const char *ll_msgs[4];
-extern const char *rrrr_msgs[16];
-extern const char *to_msgs[2];
-extern const char *pp_msgs[4];
-extern const char *ii_msgs[4];
-extern const char *htlink_msgs[8];
-
#ifdef CONFIG_EDAC_DEBUG
#define NUM_DBG_ATTRS 5
#else
@@ -511,14 +430,11 @@ extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
*/
struct low_ops {
int (*early_channel_count) (struct amd64_pvt *pvt);
-
- u64 (*get_error_address) (struct mem_ctl_info *mci,
- struct err_regs *info);
- void (*read_dram_base_limit) (struct amd64_pvt *pvt, int dram);
- void (*read_dram_ctl_register) (struct amd64_pvt *pvt);
- void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci,
- struct err_regs *info, u64 SystemAddr);
- int (*dbam_to_cs) (struct amd64_pvt *pvt, int cs_mode);
+ void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr,
+ u16 syndrome);
+ int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode);
+ int (*read_dct_pci_cfg) (struct amd64_pvt *pvt, int offset,
+ u32 *val, const char *func);
};
struct amd64_family_type {
@@ -527,28 +443,17 @@ struct amd64_family_type {
struct low_ops ops;
};
-static inline int amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
- u32 *val, const char *func)
-{
- int err = 0;
-
- err = pci_read_config_dword(pdev, offset, val);
- if (err)
- amd64_warn("%s: error reading F%dx%x.\n",
- func, PCI_FUNC(pdev->devfn), offset);
-
- return err;
-}
+int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
+ u32 val, const char *func);
#define amd64_read_pci_cfg(pdev, offset, val) \
- amd64_read_pci_cfg_dword(pdev, offset, val, __func__)
+ __amd64_read_pci_cfg_dword(pdev, offset, val, __func__)
-/*
- * For future CPU versions, verify the following as new 'slow' rates appear and
- * modify the necessary skip values for the supported CPU.
- */
-#define K8_MIN_SCRUB_RATE_BITS 0x0
-#define F10_MIN_SCRUB_RATE_BITS 0x5
+#define amd64_write_pci_cfg(pdev, offset, val) \
+ __amd64_write_pci_cfg_dword(pdev, offset, val, __func__)
+
+#define amd64_read_dct_pci_cfg(pvt, offset, val) \
+ pvt->ops->read_dct_pci_cfg(pvt, offset, val, __func__)
int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size);
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 688478de1cbd..303f10e03dda 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -117,13 +117,13 @@ static ssize_t amd64_inject_read_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
- pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
@@ -150,13 +150,13 @@ static ssize_t amd64_inject_write_store(struct mem_ctl_info *mci,
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM_ECC |
SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- pci_write_config_dword(pvt->F3, F10_NB_ARRAY_ADDR, section);
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
pvt->injection.bit_map);
/* Issue 'word' and 'bit' along with the READ request */
- pci_write_config_dword(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
debugf0("section=0x%x word_bits=0x%x\n", section, word_bits);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 39d97cfdf58c..73196f7b7229 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -785,10 +785,10 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
{
int err;
- debugf1("%s()\n", __func__);
+ debugf4("%s()\n", __func__);
while (sysfs_attrib) {
- debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
+ debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
if (sysfs_attrib->grp) {
struct mcidev_sysfs_group_kobj *grp_kobj;
@@ -818,7 +818,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
if (err < 0)
return err;
} else if (sysfs_attrib->attr.name) {
- debugf0("%s() file %s\n", __func__,
+ debugf4("%s() file %s\n", __func__,
sysfs_attrib->attr.name);
err = sysfs_create_file(kobj, &sysfs_attrib->attr);
@@ -853,26 +853,26 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
* Remove first all the atributes
*/
while (sysfs_attrib) {
- debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
+ debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
if (sysfs_attrib->grp) {
- debugf1("%s() seeking for group %s\n",
+ debugf4("%s() seeking for group %s\n",
__func__, sysfs_attrib->grp->name);
list_for_each_entry(grp_kobj,
&mci->grp_kobj_list, list) {
- debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
+ debugf4("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
if (grp_kobj->grp == sysfs_attrib->grp) {
edac_remove_mci_instance_attributes(mci,
grp_kobj->grp->mcidev_attr,
&grp_kobj->kobj, count + 1);
- debugf0("%s() group %s\n", __func__,
+ debugf4("%s() group %s\n", __func__,
sysfs_attrib->grp->name);
kobject_put(&grp_kobj->kobj);
}
}
- debugf1("%s() end of seeking for group %s\n",
+ debugf4("%s() end of seeking for group %s\n",
__func__, sysfs_attrib->grp->name);
} else if (sysfs_attrib->attr.name) {
- debugf0("%s() file %s\n", __func__,
+ debugf4("%s() file %s\n", __func__,
sysfs_attrib->attr.name);
sysfs_remove_file(kobj, &sysfs_attrib->attr);
} else
@@ -979,7 +979,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s()\n", __func__);
/* remove all csrow kobjects */
- debugf0("%s() unregister this mci kobj\n", __func__);
+ debugf4("%s() unregister this mci kobj\n", __func__);
for (i = 0; i < mci->nr_csrows; i++) {
if (mci->csrows[i].nr_pages > 0) {
debugf0("%s() unreg csrow-%d\n", __func__, i);
@@ -989,18 +989,18 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
/* remove this mci instance's attribtes */
if (mci->mc_driver_sysfs_attributes) {
- debugf0("%s() unregister mci private attributes\n", __func__);
+ debugf4("%s() unregister mci private attributes\n", __func__);
edac_remove_mci_instance_attributes(mci,
mci->mc_driver_sysfs_attributes,
&mci->edac_mci_kobj, 0);
}
/* remove the symlink */
- debugf0("%s() remove_link\n", __func__);
+ debugf4("%s() remove_link\n", __func__);
sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
/* unregister this instance's kobject */
- debugf0("%s() remove_mci_instance\n", __func__);
+ debugf4("%s() remove_mci_instance\n", __func__);
kobject_put(&mci->edac_mci_kobj);
}
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 05523b504271..76d1f576cdc8 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -162,7 +162,7 @@ static struct edac_pci_ctl_info *i7300_pci;
#define AMBPRESENT_0 0x64
#define AMBPRESENT_1 0x66
-const static u16 mtr_regs[MAX_SLOTS] = {
+static const u16 mtr_regs[MAX_SLOTS] = {
0x80, 0x84, 0x88, 0x8c,
0x82, 0x86, 0x8a, 0x8e
};
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 3218819b7286..92e65e7038e9 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -160,8 +160,8 @@ NOTE: Only ONE of the three must be enabled
* 3:2 Rank 1 architecture
* 1:0 Rank 0 architecture
*
- * 00 => x16 devices; i.e 4 banks
- * 01 => x8 devices; i.e 8 banks
+ * 00 => 4 banks
+ * 01 => 8 banks
*/
#define I82975X_C0BNKARC 0x10e
#define I82975X_C1BNKARC 0x18e
@@ -278,6 +278,7 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
struct i82975x_error_info *info, int handle_errors)
{
int row, multi_chan, chan;
+ unsigned long offst, page;
multi_chan = mci->csrows[0].nr_channels - 1;
@@ -292,17 +293,19 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
info->errsts = info->errsts2;
}
- chan = info->eap & 1;
- info->eap >>= 1;
- if (info->xeap )
- info->eap |= 0x80000000;
- info->eap >>= PAGE_SHIFT;
- row = edac_mc_find_csrow_by_page(mci, info->eap);
+ page = (unsigned long) info->eap;
+ if (info->xeap & 1)
+ page |= 0x100000000ul;
+ chan = page & 1;
+ page >>= 1;
+ offst = page & ((1 << PAGE_SHIFT) - 1);
+ page >>= PAGE_SHIFT;
+ row = edac_mc_find_csrow_by_page(mci, page);
if (info->errsts & 0x0002)
- edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");
+ edac_mc_handle_ue(mci, page, offst , row, "i82975x UE");
else
- edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
+ edac_mc_handle_ce(mci, page, offst, info->derrsyn, row,
multi_chan ? chan : 0,
"i82975x CE");
@@ -344,11 +347,7 @@ static int dual_channel_active(void __iomem *mch_window)
static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
{
/*
- * ASUS P5W DH either does not program this register or programs
- * it wrong!
- * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val'
- * for each rank should be 01b - the LSB of the word should be 0x55;
- * but it reads 0!
+ * ECC is possible on i92975x ONLY with DEV_X8
*/
return DEV_X8;
}
@@ -356,11 +355,15 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct pci_dev *pdev, void __iomem *mch_window)
{
+ static const char *labels[4] = {
+ "DIMM A1", "DIMM A2",
+ "DIMM B1", "DIMM B2"
+ };
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
u32 cumul_size;
- int index;
+ int index, chan;
last_cumul_size = 0;
@@ -369,11 +372,7 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
* The dram row boundary (DRB) reg values are boundary address
* for each DRAM row with a granularity of 32 or 64MB (single/dual
* channel operation). DRB regs are cumulative; therefore DRB7 will
- * contain the total memory contained in all eight rows.
- *
- * FIXME:
- * EDAC currently works for Dual-channel Interleaved configuration.
- * Other configurations, which the chip supports, need fixing/testing.
+ * contain the total memory contained in all rows.
*
*/
@@ -384,8 +383,26 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
((index >= 4) ? 0x80 : 0));
cumul_size = value;
cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT);
+ /*
+ * Adjust cumul_size w.r.t number of channels
+ *
+ */
+ if (csrow->nr_channels > 1)
+ cumul_size <<= 1;
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
+
+ /*
+ * Initialise dram labels
+ * index values:
+ * [0-7] for single-channel; i.e. csrow->nr_channels = 1
+ * [0-3] for dual-channel; i.e. csrow->nr_channels = 2
+ */
+ for (chan = 0; chan < csrow->nr_channels; chan++)
+ strncpy(csrow->channels[chan].label,
+ labels[(index >> 1) + (chan * 2)],
+ EDAC_MC_LABEL_LEN);
+
if (cumul_size == last_cumul_size)
continue; /* not populated */
@@ -393,8 +410,8 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
- csrow->grain = 1 << 7; /* I82975X_EAP has 128B resolution */
- csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */
+ csrow->grain = 1 << 6; /* I82975X_EAP has 64B resolution */
+ csrow->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
csrow->dtype = i82975x_dram_type(mch_window, index);
csrow->edac_mode = EDAC_SECDED; /* only supported */
}
@@ -515,18 +532,20 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): init mci\n", __func__);
mci->dev = &pdev->dev;
- mci->mtype_cap = MEM_FLAG_DDR;
+ mci->mtype_cap = MEM_FLAG_DDR2;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82975X_REVISION;
mci->ctl_name = i82975x_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = i82975x_check;
mci->ctl_page_to_phys = NULL;
debugf3("%s(): init pvt\n", __func__);
pvt = (struct i82975x_pvt *) mci->pvt_info;
pvt->mch_window = mch_window;
i82975x_init_csrows(mci, pdev, mch_window);
+ mci->scrub_mode = SCRUB_HW_SRC;
i82975x_get_error_info(mci, &discard); /* clear counters */
/* finalize this instance of memory controller with edac core */
@@ -664,7 +683,7 @@ module_init(i82975x_init);
module_exit(i82975x_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
+MODULE_AUTHOR("Arvind R. <arvino55@gmail.com>");
MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
module_param(edac_op_state, int, 0444);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index f6cf73d93359..795cfbc0bf50 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -594,6 +594,7 @@ static bool nb_noop_mce(u16 ec, u8 xec)
void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
u16 ec = EC(m->status);
u8 xec = XEC(m->status, 0x1f);
u32 nbsh = (u32)(m->status >> 32);
@@ -602,9 +603,8 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
pr_emerg(HW_ERR "Northbridge Error (node %d", node_id);
/* F10h, revD can disable ErrCpu[3:0] through ErrCpuVal */
- if ((boot_cpu_data.x86 == 0x10) &&
- (boot_cpu_data.x86_model > 7)) {
- if (nbsh & K8_NBSH_ERR_CPU_VAL)
+ if (c->x86 == 0x10 && c->x86_model > 7) {
+ if (nbsh & NBSH_ERR_CPU_VAL)
core = nbsh & nb_err_cpumask;
} else {
u8 assoc_cpus = nbsh & nb_err_cpumask;
@@ -646,7 +646,7 @@ void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
if (!fam_ops->nb_mce(ec, xec))
goto wrong_nb_mce;
- if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10)
+ if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x15)
if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
nb_bus_decoder(node_id, m, nbcfg);
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 45dda47173f2..795a3206acf5 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -31,19 +31,10 @@
#define R4(x) (((x) >> 4) & 0xf)
#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!")
-#define K8_NBSH 0x4C
-
-#define K8_NBSH_VALID_BIT BIT(31)
-#define K8_NBSH_OVERFLOW BIT(30)
-#define K8_NBSH_UC_ERR BIT(29)
-#define K8_NBSH_ERR_EN BIT(28)
-#define K8_NBSH_MISCV BIT(27)
-#define K8_NBSH_VALID_ERROR_ADDR BIT(26)
-#define K8_NBSH_PCC BIT(25)
-#define K8_NBSH_ERR_CPU_VAL BIT(24)
-#define K8_NBSH_CECC BIT(14)
-#define K8_NBSH_UECC BIT(13)
-#define K8_NBSH_ERR_SCRUBER BIT(8)
+/*
+ * F3x4C bits (MCi_STATUS' high half)
+ */
+#define NBSH_ERR_CPU_VAL BIT(24)
enum tt_ids {
TT_INSTR = 0,
@@ -86,17 +77,6 @@ extern const char *to_msgs[];
extern const char *ii_msgs[];
/*
- * relevant NB regs
- */
-struct err_regs {
- u32 nbcfg;
- u32 nbsh;
- u32 nbsl;
- u32 nbeah;
- u32 nbeal;
-};
-
-/*
* per-family decoder ops
*/
struct amd_decoder_ops {
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c
new file mode 100644
index 000000000000..1d5cf06f6c6b
--- /dev/null
+++ b/drivers/edac/tile_edac.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * Tilera-specific EDAC driver.
+ *
+ * This source code is derived from the following driver:
+ *
+ * Cell MIC driver for ECC counting
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/edac.h>
+#include <hv/hypervisor.h>
+#include <hv/drv_mshim_intf.h>
+
+#include "edac_core.h"
+
+#define DRV_NAME "tile-edac"
+
+/* Number of cs_rows needed per memory controller on TILEPro. */
+#define TILE_EDAC_NR_CSROWS 1
+
+/* Number of channels per memory controller on TILEPro. */
+#define TILE_EDAC_NR_CHANS 1
+
+/* Granularity of reported error in bytes on TILEPro. */
+#define TILE_EDAC_ERROR_GRAIN 8
+
+/* TILE processor has multiple independent memory controllers. */
+struct platform_device *mshim_pdev[TILE_MAX_MSHIMS];
+
+struct tile_edac_priv {
+ int hv_devhdl; /* Hypervisor device handle. */
+ int node; /* Memory controller instance #. */
+ unsigned int ce_count; /*
+ * Correctable-error counter
+ * kept by the driver.
+ */
+};
+
+static void tile_edac_check(struct mem_ctl_info *mci)
+{
+ struct tile_edac_priv *priv = mci->pvt_info;
+ struct mshim_mem_error mem_error;
+
+ if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_error,
+ sizeof(struct mshim_mem_error), MSHIM_MEM_ERROR_OFF) !=
+ sizeof(struct mshim_mem_error)) {
+ pr_err(DRV_NAME ": MSHIM_MEM_ERROR_OFF pread failure.\n");
+ return;
+ }
+
+ /* Check if the current error count is different from the saved one. */
+ if (mem_error.sbe_count != priv->ce_count) {
+ dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node);
+ priv->ce_count = mem_error.sbe_count;
+ edac_mc_handle_ce(mci, 0, 0, 0, 0, 0, mci->ctl_name);
+ }
+}
+
+/*
+ * Initialize the 'csrows' table within the mci control structure with the
+ * addressing of memory.
+ */
+static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
+{
+ struct csrow_info *csrow = &mci->csrows[0];
+ struct tile_edac_priv *priv = mci->pvt_info;
+ struct mshim_mem_info mem_info;
+
+ if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
+ sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
+ sizeof(struct mshim_mem_info)) {
+ pr_err(DRV_NAME ": MSHIM_MEM_INFO_OFF pread failure.\n");
+ return -1;
+ }
+
+ if (mem_info.mem_ecc)
+ csrow->edac_mode = EDAC_SECDED;
+ else
+ csrow->edac_mode = EDAC_NONE;
+ switch (mem_info.mem_type) {
+ case DDR2:
+ csrow->mtype = MEM_DDR2;
+ break;
+
+ case DDR3:
+ csrow->mtype = MEM_DDR3;
+ break;
+
+ default:
+ return -1;
+ }
+
+ csrow->first_page = 0;
+ csrow->nr_pages = mem_info.mem_size >> PAGE_SHIFT;
+ csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+ csrow->grain = TILE_EDAC_ERROR_GRAIN;
+ csrow->dtype = DEV_UNKNOWN;
+
+ return 0;
+}
+
+static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
+{
+ char hv_file[32];
+ int hv_devhdl;
+ struct mem_ctl_info *mci;
+ struct tile_edac_priv *priv;
+ int rc;
+
+ sprintf(hv_file, "mshim/%d", pdev->id);
+ hv_devhdl = hv_dev_open((HV_VirtAddr)hv_file, 0);
+ if (hv_devhdl < 0)
+ return -EINVAL;
+
+ /* A TILE MC has a single channel and one chip-select row. */
+ mci = edac_mc_alloc(sizeof(struct tile_edac_priv),
+ TILE_EDAC_NR_CSROWS, TILE_EDAC_NR_CHANS, pdev->id);
+ if (mci == NULL)
+ return -ENOMEM;
+ priv = mci->pvt_info;
+ priv->node = pdev->id;
+ priv->hv_devhdl = hv_devhdl;
+
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR2;
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+
+ mci->mod_name = DRV_NAME;
+ mci->ctl_name = "TILEPro_Memory_Controller";
+ mci->dev_name = dev_name(&pdev->dev);
+ mci->edac_check = tile_edac_check;
+
+ /*
+ * Initialize the MC control structure 'csrows' table
+ * with the mapping and control information.
+ */
+ if (tile_edac_init_csrows(mci)) {
+ /* No csrows found. */
+ mci->edac_cap = EDAC_FLAG_NONE;
+ } else {
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ }
+
+ platform_set_drvdata(pdev, mci);
+
+ /* Register with EDAC core */
+ rc = edac_mc_add_mc(mci);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to register with EDAC core\n");
+ edac_mc_free(mci);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devexit tile_edac_mc_remove(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+ edac_mc_del_mc(&pdev->dev);
+ if (mci)
+ edac_mc_free(mci);
+ return 0;
+}
+
+static struct platform_driver tile_edac_mc_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tile_edac_mc_probe,
+ .remove = __devexit_p(tile_edac_mc_remove),
+};
+
+/*
+ * Driver init routine.
+ */
+static int __init tile_edac_init(void)
+{
+ char hv_file[32];
+ struct platform_device *pdev;
+ int i, err, num = 0;
+
+ /* Only support POLL mode. */
+ edac_op_state = EDAC_OPSTATE_POLL;
+
+ err = platform_driver_register(&tile_edac_mc_driver);
+ if (err)
+ return err;
+
+ for (i = 0; i < TILE_MAX_MSHIMS; i++) {
+ /*
+ * Not all memory controllers are configured such as in the
+ * case of a simulator. So we register only those mshims
+ * that are configured by the hypervisor.
+ */
+ sprintf(hv_file, "mshim/%d", i);
+ if (hv_dev_open((HV_VirtAddr)hv_file, 0) < 0)
+ continue;
+
+ pdev = platform_device_register_simple(DRV_NAME, i, NULL, 0);
+ if (IS_ERR(pdev))
+ continue;
+ mshim_pdev[i] = pdev;
+ num++;
+ }
+
+ if (num == 0) {
+ platform_driver_unregister(&tile_edac_mc_driver);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/*
+ * Driver cleanup routine.
+ */
+static void __exit tile_edac_exit(void)
+{
+ int i;
+
+ for (i = 0; i < TILE_MAX_MSHIMS; i++) {
+ struct platform_device *pdev = mshim_pdev[i];
+ if (!pdev)
+ continue;
+
+ platform_set_drvdata(pdev, NULL);
+ platform_device_unregister(pdev);
+ }
+ platform_driver_unregister(&tile_edac_mc_driver);
+}
+
+module_init(tile_edac_init);
+module_exit(tile_edac_exit);
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index c003fa4e2db1..c8658888e67b 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -362,3 +362,4 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
*channel = ret;
}
}
+EXPORT_SYMBOL(fw_iso_resource_manage);
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index f8dfcf1c6cbe..25e729cde2f7 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -147,9 +147,6 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
/* -iso */
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
-void fw_iso_resource_manage(struct fw_card *card, int generation,
- u64 channels_mask, int *channel, int *bandwidth,
- bool allocate, __be32 buffer[2]);
/* -topology */
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 69ad529d92fb..ea5ac2dc1233 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -268,8 +268,10 @@ int dcdbas_smi_request(struct smi_cmd *smi_cmd)
}
/* generate SMI */
+ /* inb to force posted write through and make SMI happen now */
asm volatile (
- "outb %b0,%w1"
+ "outb %b0,%w1\n"
+ "inb %w1"
: /* no output args */
: "a" (smi_cmd->command_code),
"d" (smi_cmd->command_address),
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c
index 2975d22daffe..838ddbdf90cc 100644
--- a/drivers/gpio/pl061.c
+++ b/drivers/gpio/pl061.c
@@ -232,7 +232,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
-static int pl061_probe(struct amba_device *dev, struct amba_id *id)
+static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
{
struct pl061_platform_data *pdata;
struct pl061_gpio *chip;
diff --git a/drivers/gpu/drm/drm_sman.c b/drivers/gpu/drm/drm_sman.c
index 463aed9403db..34664587a74e 100644
--- a/drivers/gpu/drm/drm_sman.c
+++ b/drivers/gpu/drm/drm_sman.c
@@ -59,9 +59,7 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
{
int ret = 0;
- sman->mm = (struct drm_sman_mm *) kcalloc(num_managers,
- sizeof(*sman->mm),
- GFP_KERNEL);
+ sman->mm = kcalloc(num_managers, sizeof(*sman->mm), GFP_KERNEL);
if (!sman->mm) {
ret = -ENOMEM;
goto out;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index b9427e689cf3..941080a77940 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2987,7 +2987,7 @@ int evergreen_resume(struct radeon_device *rdev)
r = r600_ib_test(rdev);
if (r) {
- DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+ DRM_ERROR("radeon: failed testing IB (%d).\n", r);
return r;
}
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index fcc23e4e0b3c..f2204cb1ccdf 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3617,7 +3617,7 @@ int r100_ib_test(struct radeon_device *rdev)
if (i < rdev->usec_timeout) {
DRM_INFO("ib test succeeded in %u usecs\n", i);
} else {
- DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n",
+ DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
scratch, tmp);
r = -EINVAL;
}
@@ -3637,13 +3637,13 @@ int r100_ib_init(struct radeon_device *rdev)
r = radeon_ib_pool_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB pool (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB pool (%d).\n", r);
r100_ib_fini(rdev);
return r;
}
r = r100_ib_test(rdev);
if (r) {
- dev_err(rdev->dev, "failled testing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed testing IB (%d).\n", r);
r100_ib_fini(rdev);
return r;
}
@@ -3799,12 +3799,12 @@ static int r100_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 069efa8c8ecf..8713731fa014 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1401,12 +1401,12 @@ static int r300_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 0b59ed7c7d2c..417fab81812f 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -260,13 +260,13 @@ static int r420_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r420_cp_errata_init(rdev);
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 2ce80d976568..3081d07f8de5 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -193,12 +193,12 @@ static int r520_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 12fdebf9aed8..be271c42de4d 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -2464,7 +2464,7 @@ int r600_resume(struct radeon_device *rdev)
r = r600_ib_test(rdev);
if (r) {
- DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+ DRM_ERROR("radeon: failed testing IB (%d).\n", r);
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 992d99d13fc5..bbc9cd823334 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -151,7 +151,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
/* 64 dwords should be enough for fence too */
r = radeon_ring_lock(rdev, 64);
if (r) {
- DRM_ERROR("radeon: scheduling IB failled (%d).\n", r);
+ DRM_ERROR("radeon: scheduling IB failed (%d).\n", r);
return r;
}
radeon_ring_ib_execute(rdev, ib);
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index c76283d9eb3d..aa6a66eeb4ec 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -412,12 +412,12 @@ static int rs400_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 8af4679db23e..19763f5df5e1 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -865,12 +865,12 @@ static int rs600_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 66c949b7c18c..a9049ed1a519 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -627,12 +627,12 @@ static int rs690_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 64b57af93714..6613ee9ecca3 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -398,12 +398,12 @@ static int rv515_startup(struct radeon_device *rdev)
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
- dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing CP (%d).\n", r);
return r;
}
r = r100_ib_init(rdev);
if (r) {
- dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ dev_err(rdev->dev, "failed initializing IB (%d).\n", r);
return r;
}
return 0;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 4cc7b717fedd..b974ac7df8df 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1209,7 +1209,7 @@ int rv770_resume(struct radeon_device *rdev)
r = r600_ib_test(rdev);
if (r) {
- DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+ DRM_ERROR("radeon: failed testing IB (%d).\n", r);
return r;
}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 2560f01c1a63..b7ec4057841d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -68,9 +68,15 @@ config HID_A4TECH
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
-config HID_ACRUX_FF
- tristate "ACRUX force feedback"
+config HID_ACRUX
+ tristate "ACRUX game controller support"
depends on USB_HID
+ ---help---
+ Say Y here if you want to enable support for ACRUX game controllers.
+
+config HID_ACRUX_FF
+ tristate "ACRUX force feedback support"
+ depends on HID_ACRUX
select INPUT_FF_MEMLESS
---help---
Say Y here if you want to enable force feedback support for ACRUX
@@ -140,7 +146,12 @@ config HID_DRAGONRISE
tristate "DragonRise Inc. game controller"
depends on USB_HID
---help---
- Say Y here if you have DragonRise Inc.game controllers.
+ Say Y here if you have DragonRise Inc. game controllers.
+ These might be branded as:
+ - Tesun USB-703
+ - Media-tech MT1504 "Rogue"
+ - DVTech JS19 "Gear"
+ - Defender Game Master
config DRAGONRISE_FF
bool "DragonRise Inc. force feedback"
@@ -160,13 +171,6 @@ config HID_EMS_FF
Currently the following devices are known to be supported:
- Trio Linker Plus II
-config HID_EGALAX
- tristate "eGalax multi-touch panel"
- depends on USB_HID
- ---help---
- Support for the eGalax dual-touch panels, including the
- Joojoo and Wetab tablets.
-
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
depends on BT_HIDP
@@ -180,6 +184,14 @@ config HID_EZKEY
---help---
Support for Ezkey BTC 8193 keyboard.
+config HID_KEYTOUCH
+ tristate "Keyoutch HID devices"
+ depends on USB_HID
+ ---help---
+ Support for Keytouch HID devices not fully compliant with
+ the specification. Currently supported:
+ - Keytouch IEC 60945
+
config HID_KYE
tristate "Kye/Genius Ergo Mouse" if EXPERT
depends on USB_HID
@@ -218,6 +230,12 @@ config HID_KENSINGTON
---help---
Support for Kensington Slimblade Trackball.
+config HID_LCPOWER
+ tristate "LC-Power"
+ depends on USB_HID
+ ---help---
+ Support for LC-Power RC1000MCE RF remote control.
+
config HID_LOGITECH
tristate "Logitech devices" if EXPERT
depends on USB_HID
@@ -304,8 +322,11 @@ config HID_MULTITOUCH
Say Y here if you have one of the following devices:
- Cypress TrueTouch panels
- Hanvon dual touch panels
+ - IrTouch Infrared USB panels
- Pixcir dual touch panels
- 'Sensing Win7-TwoFinger' panel by GeneralTouch
+ - eGalax dual-touch panels, including the
+ Joojoo and Wetab tablets
If unsure, say N.
@@ -319,10 +340,10 @@ config HID_NTRIG
Support for N-Trig touch screen.
config HID_ORTEK
- tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad"
+ tristate "Ortek PKB-1700/WKB-2000 wireless keyboard and mouse trackpad"
depends on USB_HID
---help---
- Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
+ Support for Ortek PKB-1700/WKB-2000 wireless keyboard + mouse trackpad.
config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller"
@@ -417,10 +438,22 @@ config HID_ROCCAT
Say Y here if you have a Roccat mouse or keyboard and want OSD or
macro execution support.
+config HID_ROCCAT_COMMON
+ tristate
+
+config HID_ROCCAT_ARVO
+ tristate "Roccat Arvo keyboard support"
+ depends on USB_HID
+ select HID_ROCCAT
+ select HID_ROCCAT_COMMON
+ ---help---
+ Support for Roccat Arvo keyboard.
+
config HID_ROCCAT_KONE
tristate "Roccat Kone Mouse support"
depends on USB_HID
select HID_ROCCAT
+ select HID_ROCCAT_COMMON
---help---
Support for Roccat Kone mouse.
@@ -428,13 +461,23 @@ config HID_ROCCAT_KONEPLUS
tristate "Roccat Kone[+] mouse support"
depends on USB_HID
select HID_ROCCAT
+ select HID_ROCCAT_COMMON
---help---
Support for Roccat Kone[+] mouse.
+config HID_ROCCAT_KOVAPLUS
+ tristate "Roccat Kova[+] mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ select HID_ROCCAT_COMMON
+ ---help---
+ Support for Roccat Kova[+] mouse.
+
config HID_ROCCAT_PYRA
tristate "Roccat Pyra mouse support"
depends on USB_HID
select HID_ROCCAT
+ select HID_ROCCAT_COMMON
---help---
Support for Roccat Pyra mouse.
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 6efc2a0370ad..06c68ae3abee 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -27,21 +27,22 @@ endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
-obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o
+obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
-obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o
+obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
-obj-$(CONFIG_HID_EGALAX) += hid-egalax.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
+obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
+obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
@@ -56,8 +57,11 @@ obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
+obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
+obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
+obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index e5b961d6ff22..b4554288de00 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -33,6 +33,8 @@
#include <linux/hid.h>
#include "hid-ids.h"
+
+#ifdef CONFIG_HID_ACRUX_FF
#include "usbhid/usbhid.h"
struct axff_device {
@@ -109,6 +111,12 @@ err_free_mem:
kfree(axff);
return error;
}
+#else
+static inline int axff_init(struct hid_device *hid)
+{
+ return 0;
+}
+#endif
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
@@ -139,9 +147,25 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
error);
}
+ /*
+ * We need to start polling device right away, otherwise
+ * it will go into a coma.
+ */
+ error = hid_hw_open(hdev);
+ if (error) {
+ dev_err(&hdev->dev, "hw open failed\n");
+ return error;
+ }
+
return 0;
}
+static void ax_remove(struct hid_device *hdev)
+{
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+}
+
static const struct hid_device_id ax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
{ }
@@ -149,9 +173,10 @@ static const struct hid_device_id ax_devices[] = {
MODULE_DEVICE_TABLE(hid, ax_devices);
static struct hid_driver ax_driver = {
- .name = "acrux",
- .id_table = ax_devices,
- .probe = ax_probe,
+ .name = "acrux",
+ .id_table = ax_devices,
+ .probe = ax_probe,
+ .remove = ax_remove,
};
static int __init ax_init(void)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index d678cf3d33d5..c3d66269ed7d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1159,6 +1159,32 @@ static bool hid_hiddev(struct hid_device *hdev)
return !!hid_match_id(hdev, hid_hiddev_list);
}
+
+static ssize_t
+read_report_descriptor(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+ if (off >= hdev->rsize)
+ return 0;
+
+ if (off + count > hdev->rsize)
+ count = hdev->rsize - off;
+
+ memcpy(buf, hdev->rdesc + off, count);
+
+ return count;
+}
+
+static struct bin_attribute dev_bin_attr_report_desc = {
+ .attr = { .name = "report_descriptor", .mode = 0444 },
+ .read = read_report_descriptor,
+ .size = HID_MAX_DESCRIPTOR_SIZE,
+};
+
int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
{
static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
@@ -1169,6 +1195,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
char buf[64];
unsigned int i;
int len;
+ int ret;
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
@@ -1230,6 +1257,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
bus = "<UNKNOWN>";
}
+ ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
+ if (ret)
+ hid_warn(hdev,
+ "can't create sysfs report descriptor attribute err: %d\n", ret);
+
hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
buf, bus, hdev->version >> 8, hdev->version & 0xff,
type, hdev->name, hdev->phys);
@@ -1240,6 +1272,7 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev)
{
+ device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev);
if (hdev->claimed & HID_CLAIMED_HIDDEV)
@@ -1256,9 +1289,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
-#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
-#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1328,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
@@ -1345,9 +1377,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1368,6 +1403,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
@@ -1400,12 +1436,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-dr.c
index afcf3d67eb02..61eece47204d 100644
--- a/drivers/hid/hid-drff.c
+++ b/drivers/hid/hid-dr.c
@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid)
}
#endif
+/*
+ * The original descriptor of joystick with PID 0x0011, represented by DVTech PC
+ * JS19. It seems both copied from another device and a result of confusion
+ * either about the specification or about the program used to create the
+ * descriptor. In any case, it's a wonder it works on Windows.
+ *
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Joystik), ; Joystik (04h, application collection)
+ * Collection (Application),
+ * Collection (Logical),
+ * Report Size (8),
+ * Report Count (5),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Physical Minimum (0),
+ * Physical Maximum (255),
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Input (Variable),
+ * Report Size (4),
+ * Report Count (1),
+ * Logical Maximum (7),
+ * Physical Maximum (315),
+ * Unit (Degrees),
+ * Usage (00h),
+ * Input (Variable, Null State),
+ * Unit,
+ * Report Size (1),
+ * Report Count (10),
+ * Logical Maximum (1),
+ * Physical Maximum (1),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (0Ah),
+ * Input (Variable),
+ * Usage Page (FF00h), ; FF00h, vendor-defined
+ * Report Size (1),
+ * Report Count (10),
+ * Logical Maximum (1),
+ * Physical Maximum (1),
+ * Usage (01h),
+ * Input (Variable),
+ * End Collection,
+ * Collection (Logical),
+ * Report Size (8),
+ * Report Count (4),
+ * Physical Maximum (255),
+ * Logical Maximum (255),
+ * Usage (02h),
+ * Output (Variable),
+ * End Collection,
+ * End Collection
+ */
+
+/* Size of the original descriptor of the PID 0x0011 joystick */
+#define PID0011_RDESC_ORIG_SIZE 101
+
+/* Fixed report descriptor for PID 0x011 joystick */
+static __u8 pid0011_rdesc_fixed[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x04, /* Usage (Joystik), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x0A, /* Report Count (10), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x0A, /* Usage Maximum (0Ah), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x0A, /* Report Count (10), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case 0x0011:
+ if (*rsize == PID0011_RDESC_ORIG_SIZE) {
+ rdesc = pid0011_rdesc_fixed;
+ *rsize = sizeof(pid0011_rdesc_fixed);
+ }
+ break;
+ }
+ return rdesc;
+}
+
static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -163,7 +267,16 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err;
}
- drff_init(hdev);
+ switch (hdev->product) {
+ case 0x0006:
+ ret = drff_init(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "force feedback init failed\n");
+ hid_hw_stop(hdev);
+ goto err;
+ }
+ break;
+ }
return 0;
err:
@@ -172,6 +285,7 @@ err:
static const struct hid_device_id dr_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), },
{ }
};
MODULE_DEVICE_TABLE(hid, dr_devices);
@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices);
static struct hid_driver dr_driver = {
.name = "dragonrise",
.id_table = dr_devices,
+ .report_fixup = dr_report_fixup,
.probe = dr_probe,
};
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
deleted file mode 100644
index 03bee1970d70..000000000000
--- a/drivers/hid/hid-egalax.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * HID driver for eGalax dual-touch panels
- *
- * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
- * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
- * Copyright (c) 2010 Canonical, Ltd.
- *
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/input/mt.h>
-#include <linux/slab.h>
-#include "usbhid/usbhid.h"
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("eGalax dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-#define MAX_SLOTS 2
-
-/* estimated signal-to-noise ratios */
-#define SN_MOVE 4096
-#define SN_PRESSURE 32
-
-struct egalax_data {
- int valid;
- int slot;
- int touch;
- int x, y, z;
-};
-
-static void set_abs(struct input_dev *input, unsigned int code,
- struct hid_field *field, int snratio)
-{
- int fmin = field->logical_minimum;
- int fmax = field->logical_maximum;
- int fuzz = snratio ? (fmax - fmin) / snratio : 0;
- input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
-}
-
-static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- struct input_dev *input = hi->input;
-
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- field->logical_maximum = 32760;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
- /* touchscreen emulation */
- set_abs(input, ABS_X, field, SN_MOVE);
- return 1;
- case HID_GD_Y:
- field->logical_maximum = 32760;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
- /* touchscreen emulation */
- set_abs(input, ABS_Y, field, SN_MOVE);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- case HID_DG_TIPSWITCH:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- input_set_capability(input, EV_KEY, BTN_TOUCH);
- return 1;
- case HID_DG_INRANGE:
- case HID_DG_CONFIDENCE:
- case HID_DG_CONTACTCOUNT:
- case HID_DG_CONTACTMAX:
- return -1;
- case HID_DG_CONTACTID:
- input_mt_init_slots(input, MAX_SLOTS);
- return 1;
- case HID_DG_TIPPRESSURE:
- field->logical_minimum = 0;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_PRESSURE);
- set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
- /* touchscreen emulation */
- set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
- return 1;
- }
- return 0;
- }
-
- /* ignore others (from other reports we won't get anyway) */
- return -1;
-}
-
-static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- /* tell hid-input to skip setup of these event types */
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- set_bit(usage->type, hi->input->evbit);
- return -1;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
-{
- input_mt_slot(input, td->slot);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
- if (td->touch) {
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
- input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
- }
- input_mt_report_pointer_emulation(input, true);
-}
-
-static int egalax_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct egalax_data *td = hid_get_drvdata(hid);
-
- /* Note, eGalax has two product lines: the first is resistive and
- * uses a standard parallel multitouch protocol (product ID ==
- * 48xx). The second is capacitive and uses an unusual "serial"
- * protocol with a different message for each multitouch finger
- * (product ID == 72xx).
- */
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
-
- switch (usage->hid) {
- case HID_DG_INRANGE:
- td->valid = value;
- break;
- case HID_DG_CONFIDENCE:
- /* avoid interference from generic hidinput handling */
- break;
- case HID_DG_TIPSWITCH:
- td->touch = value;
- break;
- case HID_DG_TIPPRESSURE:
- td->z = value;
- break;
- case HID_DG_CONTACTID:
- td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
- break;
- case HID_GD_X:
- td->x = value;
- break;
- case HID_GD_Y:
- td->y = value;
- /* this is the last field in a finger */
- if (td->valid)
- egalax_filter_event(td, input);
- break;
- case HID_DG_CONTACTCOUNT:
- /* touch emulation: this is the last field in a frame */
- break;
-
- default:
- /* fallback to the generic hidinput handling */
- return 0;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct egalax_data *td;
- struct hid_report *report;
-
- td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
- if (!td) {
- hid_err(hdev, "cannot allocate eGalax data\n");
- return -ENOMEM;
- }
- hid_set_drvdata(hdev, td);
-
- ret = hid_parse(hdev);
- if (ret)
- goto end;
-
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret)
- goto end;
-
- report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5];
- if (report) {
- report->field[0]->value[0] = 2;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
- }
-
-end:
- if (ret)
- kfree(td);
-
- return ret;
-}
-
-static void egalax_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id egalax_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, egalax_devices);
-
-static const struct hid_usage_id egalax_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver egalax_driver = {
- .name = "egalax-touch",
- .id_table = egalax_devices,
- .probe = egalax_probe,
- .remove = egalax_remove,
- .input_mapping = egalax_input_mapping,
- .input_mapped = egalax_input_mapped,
- .usage_table = egalax_grabbed_usages,
- .event = egalax_event,
-};
-
-static int __init egalax_init(void)
-{
- return hid_register_driver(&egalax_driver);
-}
-
-static void __exit egalax_exit(void)
-{
- hid_unregister_driver(&egalax_driver);
-}
-
-module_init(egalax_init);
-module_exit(egalax_exit);
-
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index 3975e039c3dd..e88b951cd10d 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -43,6 +43,11 @@ static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0x048: gy_map_key_clear(KEY_MEDIA); break;
case 0x049: gy_map_key_clear(KEY_CAMERA); break;
case 0x04a: gy_map_key_clear(KEY_VIDEO); break;
+ case 0x05a: gy_map_key_clear(KEY_TEXT); break;
+ case 0x05b: gy_map_key_clear(KEY_RED); break;
+ case 0x05c: gy_map_key_clear(KEY_GREEN); break;
+ case 0x05d: gy_map_key_clear(KEY_YELLOW); break;
+ case 0x05e: gy_map_key_clear(KEY_BLUE); break;
default:
return 0;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 92a0d61a7379..d485894ff4db 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -333,6 +333,9 @@
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
+#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
+
#define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010
@@ -345,6 +348,9 @@
#define USB_VENDOR_ID_KWORLD 0x1b80
#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
+#define USB_VENDOR_ID_KEYTOUCH 0x0926
+#define USB_DEVICE_ID_KEYTOUCH_IEC 0x3333
+
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
@@ -352,6 +358,9 @@
#define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+#define USB_VENDOR_ID_LCPOWER 0x1241
+#define USB_DEVICE_ID_LCPOWER_LC1000 0xf767
+
#define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_LD_CASSY 0x1000
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
@@ -383,6 +392,7 @@
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
+#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
@@ -466,6 +476,7 @@
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
#define USB_VENDOR_ID_ORTEK 0x05a4
+#define USB_DEVICE_ID_ORTEK_PKB1700 0x1700
#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
#define USB_VENDOR_ID_PANJIT 0x134c
@@ -496,8 +507,10 @@
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
#define USB_VENDOR_ID_ROCCAT 0x1e7d
+#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
+#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 7f552bfad32c..cd74203c8178 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -290,14 +290,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
}
- if (field->report_type == HID_FEATURE_REPORT) {
- if (device->driver->feature_mapping) {
- device->driver->feature_mapping(device, hidinput, field,
- usage);
- }
- goto ignore;
- }
-
if (device->driver->input_mapping) {
int ret = device->driver->input_mapping(device, hidinput, field,
usage, &bit, &max);
@@ -835,6 +827,24 @@ static void hidinput_close(struct input_dev *dev)
hid_hw_close(hid);
}
+static void report_features(struct hid_device *hid)
+{
+ struct hid_driver *drv = hid->driver;
+ struct hid_report_enum *rep_enum;
+ struct hid_report *rep;
+ int i, j;
+
+ if (!drv->feature_mapping)
+ return;
+
+ rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(rep, &rep_enum->report_list, list)
+ for (i = 0; i < rep->maxfield; i++)
+ for (j = 0; j < rep->field[i]->maxusage; j++)
+ drv->feature_mapping(hid, rep->field[i],
+ rep->field[i]->usage + j);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -863,7 +873,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return -1;
}
- for (k = HID_INPUT_REPORT; k <= HID_FEATURE_REPORT; k++) {
+ report_features(hid);
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
if (k == HID_OUTPUT_REPORT &&
hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
continue;
@@ -928,6 +940,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return 0;
out_cleanup:
+ list_del(&hidinput->list);
input_free_device(hidinput->input);
kfree(hidinput);
out_unwind:
diff --git a/drivers/hid/hid-keytouch.c b/drivers/hid/hid-keytouch.c
new file mode 100644
index 000000000000..07cd825f6f01
--- /dev/null
+++ b/drivers/hid/hid-keytouch.c
@@ -0,0 +1,66 @@
+/*
+ * HID driver for Keytouch devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2011 Jiri Kosina
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* Replace the broken report descriptor of this device with rather
+ * a default one */
+static __u8 keytouch_fixed_rdesc[] = {
+0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15,
+0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08,
+0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91,
+0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00,
+0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0
+};
+
+static __u8 *keytouch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ hid_info(hdev, "fixing up Keytouch IEC report descriptor\n");
+
+ rdesc = keytouch_fixed_rdesc;
+ *rsize = sizeof(keytouch_fixed_rdesc);
+
+ return rdesc;
+}
+
+static const struct hid_device_id keytouch_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, keytouch_devices);
+
+static struct hid_driver keytouch_driver = {
+ .name = "keytouch",
+ .id_table = keytouch_devices,
+ .report_fixup = keytouch_report_fixup,
+};
+
+static int __init keytouch_init(void)
+{
+ return hid_register_driver(&keytouch_driver);
+}
+
+static void __exit keytouch_exit(void)
+{
+ hid_unregister_driver(&keytouch_driver);
+}
+
+module_init(keytouch_init);
+module_exit(keytouch_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jiri Kosina");
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c
new file mode 100644
index 000000000000..c4fe9bd095b7
--- /dev/null
+++ b/drivers/hid/hid-lcpower.c
@@ -0,0 +1,70 @@
+/*
+ * HID driver for LC Power Model RC1000MCE
+ *
+ * Copyright (c) 2011 Chris Schlund
+ * based on hid-topseed module
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ts_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x046: ts_map_key_clear(KEY_YELLOW); break;
+ case 0x047: ts_map_key_clear(KEY_GREEN); break;
+ case 0x049: ts_map_key_clear(KEY_BLUE); break;
+ case 0x04a: ts_map_key_clear(KEY_RED); break;
+ case 0x00d: ts_map_key_clear(KEY_HOME); break;
+ case 0x025: ts_map_key_clear(KEY_TV); break;
+ case 0x048: ts_map_key_clear(KEY_VCR); break;
+ case 0x024: ts_map_key_clear(KEY_MENU); break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct hid_device_id ts_devices[] = {
+ { HID_USB_DEVICE( USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ts_devices);
+
+static struct hid_driver ts_driver = {
+ .name = "LC RC1000MCE",
+ .id_table = ts_devices,
+ .input_mapping = ts_input_mapping,
+};
+
+static int __init ts_init(void)
+{
+ return hid_register_driver(&ts_driver);
+}
+
+static void __exit ts_exit(void)
+{
+ hid_unregister_driver(&ts_driver);
+}
+
+module_init(ts_init);
+module_exit(ts_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index aef4104da141..3da90402ee81 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
+ .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 698e6459fd0b..318cc40df92d 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -258,7 +258,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
input_report_abs(input, ABS_MT_TRACKING_ID, id);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
- input_report_abs(input, ABS_MT_ORIENTATION, orientation);
+ input_report_abs(input, ABS_MT_ORIENTATION, -orientation);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
@@ -397,7 +397,7 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
- input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 07d3183fdde5..ee01e65e22d6 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -5,6 +5,12 @@
* Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France
*
+ * This code is partly based on hid-egalax.c:
+ *
+ * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
+ *
*/
/*
@@ -24,6 +30,7 @@
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_DESCRIPTION("HID multitouch panels");
MODULE_LICENSE("GPL");
@@ -36,6 +43,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
+#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
struct mt_slot {
__s32 x, y, p, w, h;
@@ -65,10 +73,11 @@ struct mt_class {
};
/* classes of device behavior */
-#define MT_CLS_DEFAULT 1
-#define MT_CLS_DUAL1 2
-#define MT_CLS_DUAL2 3
-#define MT_CLS_CYPRESS 4
+#define MT_CLS_DEFAULT 1
+#define MT_CLS_DUAL_INRANGE_CONTACTID 2
+#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3
+#define MT_CLS_CYPRESS 4
+#define MT_CLS_EGALAX 5
/*
* these device-dependent functions determine what slot corresponds
@@ -104,13 +113,13 @@ static int find_slot_from_contactid(struct mt_device *td)
struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
- .quirks = MT_QUIRK_VALID_IS_INRANGE,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
.maxcontacts = 10 },
- { .name = MT_CLS_DUAL1,
+ { .name = MT_CLS_DUAL_INRANGE_CONTACTID,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTID,
.maxcontacts = 2 },
- { .name = MT_CLS_DUAL2,
+ { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
.maxcontacts = 2 },
@@ -119,10 +128,18 @@ struct mt_class mt_classes[] = {
MT_QUIRK_CYPRESS,
.maxcontacts = 10 },
+ { .name = MT_CLS_EGALAX,
+ .quirks = MT_QUIRK_SLOT_IS_CONTACTID |
+ MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_EGALAX_XYZ_FIXUP,
+ .maxcontacts = 2,
+ .sn_move = 4096,
+ .sn_pressure = 32,
+ },
{ }
};
-static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi,
+static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage)
{
if (usage->hid == HID_DG_INPUTMODE) {
@@ -146,11 +163,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = td->mtclass;
+ __s32 quirks = cls->quirks;
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
set_abs(hi->input, ABS_MT_POSITION_X, field,
@@ -160,6 +181,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid;
return 1;
case HID_GD_Y:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
set_abs(hi->input, ABS_MT_POSITION_Y, field,
@@ -203,6 +226,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid;
return 1;
case HID_DG_TIPPRESSURE:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
set_abs(hi->input, ABS_MT_PRESSURE, field,
@@ -363,8 +388,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
return 0;
}
- if (usage->hid == td->last_slot_field)
+ if (usage->hid == td->last_slot_field) {
mt_complete_slot(td);
+ if (!td->last_field_index)
+ mt_emit_event(td, field->hidinput->input);
+ }
if (field->index == td->last_field_index
&& td->num_received >= td->num_expected)
@@ -466,18 +494,42 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
/* GeneralTouch panel */
- { .driver_data = MT_CLS_DUAL2,
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+ /* IRTOUCH panels */
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
+ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+ USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
+
/* PixCir-based panels */
- { .driver_data = MT_CLS_DUAL1,
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
USB_DEVICE_ID_HANVON_MULTITOUCH) },
- { .driver_data = MT_CLS_DUAL1,
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
+ /* Resistive eGalax devices */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+
+ /* Capacitive eGalax devices */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+
{ }
};
MODULE_DEVICE_TABLE(hid, mt_devices);
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index beb403421e72..9fae2ebdd758 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -110,6 +110,36 @@ static int ntrig_version_string(unsigned char *raw, char *buf)
return sprintf(buf, "%u.%u.%u.%u.%u", a, b, c, d, e);
}
+static inline int ntrig_get_mode(struct hid_device *hdev)
+{
+ struct hid_report *report = hdev->report_enum[HID_FEATURE_REPORT].
+ report_id_hash[0x0d];
+
+ if (!report)
+ return -EINVAL;
+
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+ usbhid_wait_io(hdev);
+ return (int)report->field[0]->value[0];
+}
+
+static inline void ntrig_set_mode(struct hid_device *hdev, const int mode)
+{
+ struct hid_report *report;
+ __u8 mode_commands[4] = { 0xe, 0xf, 0x1b, 0x10 };
+
+ if (mode < 0 || mode > 3)
+ return;
+
+ report = hdev->report_enum[HID_FEATURE_REPORT].
+ report_id_hash[mode_commands[mode]];
+
+ if (!report)
+ return;
+
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+}
+
static void ntrig_report_version(struct hid_device *hdev)
{
int ret;
@@ -539,277 +569,288 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int ntrig_event (struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
- struct input_dev *input = field->hidinput->input;
struct ntrig_data *nd = hid_get_drvdata(hid);
+ struct input_dev *input;
+
+ /* Skip processing if not a claimed input */
+ if (!(hid->claimed & HID_CLAIMED_INPUT))
+ goto not_claimed_input;
+
+ /* This function is being called before the structures are fully
+ * initialized */
+ if(!(field->hidinput && field->hidinput->input))
+ return -EINVAL;
+
+ input = field->hidinput->input;
/* No special handling needed for the pen */
if (field->application == HID_DG_PEN)
return 0;
- if (hid->claimed & HID_CLAIMED_INPUT) {
- switch (usage->hid) {
- case 0xff000001:
- /* Tag indicating the start of a multitouch group */
- nd->reading_mt = 1;
- nd->first_contact_touch = 0;
- break;
- case HID_DG_TIPSWITCH:
- nd->tipswitch = value;
- /* Prevent emission of touch until validated */
- return 1;
- case HID_DG_CONFIDENCE:
- nd->confidence = value;
- break;
- case HID_GD_X:
- nd->x = value;
- /* Clear the contact footer */
- nd->mt_foot_count = 0;
- break;
- case HID_GD_Y:
- nd->y = value;
- break;
- case HID_DG_CONTACTID:
- nd->id = value;
- break;
- case HID_DG_WIDTH:
- nd->w = value;
- break;
- case HID_DG_HEIGHT:
- nd->h = value;
+ switch (usage->hid) {
+ case 0xff000001:
+ /* Tag indicating the start of a multitouch group */
+ nd->reading_mt = 1;
+ nd->first_contact_touch = 0;
+ break;
+ case HID_DG_TIPSWITCH:
+ nd->tipswitch = value;
+ /* Prevent emission of touch until validated */
+ return 1;
+ case HID_DG_CONFIDENCE:
+ nd->confidence = value;
+ break;
+ case HID_GD_X:
+ nd->x = value;
+ /* Clear the contact footer */
+ nd->mt_foot_count = 0;
+ break;
+ case HID_GD_Y:
+ nd->y = value;
+ break;
+ case HID_DG_CONTACTID:
+ nd->id = value;
+ break;
+ case HID_DG_WIDTH:
+ nd->w = value;
+ break;
+ case HID_DG_HEIGHT:
+ nd->h = value;
+ /*
+ * when in single touch mode, this is the last
+ * report received in a finger event. We want
+ * to emit a normal (X, Y) position
+ */
+ if (!nd->reading_mt) {
/*
- * when in single touch mode, this is the last
- * report received in a finger event. We want
- * to emit a normal (X, Y) position
+ * TipSwitch indicates the presence of a
+ * finger in single touch mode.
*/
- if (!nd->reading_mt) {
- /*
- * TipSwitch indicates the presence of a
- * finger in single touch mode.
- */
- input_report_key(input, BTN_TOUCH,
- nd->tipswitch);
- input_report_key(input, BTN_TOOL_DOUBLETAP,
- nd->tipswitch);
- input_event(input, EV_ABS, ABS_X, nd->x);
- input_event(input, EV_ABS, ABS_Y, nd->y);
- }
+ input_report_key(input, BTN_TOUCH,
+ nd->tipswitch);
+ input_report_key(input, BTN_TOOL_DOUBLETAP,
+ nd->tipswitch);
+ input_event(input, EV_ABS, ABS_X, nd->x);
+ input_event(input, EV_ABS, ABS_Y, nd->y);
+ }
+ break;
+ case 0xff000002:
+ /*
+ * we receive this when the device is in multitouch
+ * mode. The first of the three values tagged with
+ * this usage tells if the contact point is real
+ * or a placeholder
+ */
+
+ /* Shouldn't get more than 4 footer packets, so skip */
+ if (nd->mt_foot_count >= 4)
break;
- case 0xff000002:
- /*
- * we receive this when the device is in multitouch
- * mode. The first of the three values tagged with
- * this usage tells if the contact point is real
- * or a placeholder
- */
- /* Shouldn't get more than 4 footer packets, so skip */
- if (nd->mt_foot_count >= 4)
- break;
+ nd->mt_footer[nd->mt_foot_count++] = value;
- nd->mt_footer[nd->mt_foot_count++] = value;
+ /* if the footer isn't complete break */
+ if (nd->mt_foot_count != 4)
+ break;
- /* if the footer isn't complete break */
- if (nd->mt_foot_count != 4)
- break;
+ /* Pen activity signal. */
+ if (nd->mt_footer[2]) {
+ /*
+ * When the pen deactivates touch, we see a
+ * bogus frame with ContactCount > 0.
+ * We can
+ * save a bit of work by ensuring act_state < 0
+ * even if deactivation slack is turned off.
+ */
+ nd->act_state = deactivate_slack - 1;
+ nd->confidence = 0;
+ break;
+ }
- /* Pen activity signal. */
- if (nd->mt_footer[2]) {
- /*
- * When the pen deactivates touch, we see a
- * bogus frame with ContactCount > 0.
- * We can
- * save a bit of work by ensuring act_state < 0
- * even if deactivation slack is turned off.
- */
- nd->act_state = deactivate_slack - 1;
+ /*
+ * The first footer value indicates the presence of a
+ * finger.
+ */
+ if (nd->mt_footer[0]) {
+ /*
+ * We do not want to process contacts under
+ * the size threshold, but do not want to
+ * ignore them for activation state
+ */
+ if (nd->w < nd->min_width ||
+ nd->h < nd->min_height)
nd->confidence = 0;
- break;
- }
+ } else
+ break;
+ if (nd->act_state > 0) {
/*
- * The first footer value indicates the presence of a
- * finger.
+ * Contact meets the activation size threshold
*/
- if (nd->mt_footer[0]) {
- /*
- * We do not want to process contacts under
- * the size threshold, but do not want to
- * ignore them for activation state
- */
- if (nd->w < nd->min_width ||
- nd->h < nd->min_height)
- nd->confidence = 0;
- } else
- break;
-
- if (nd->act_state > 0) {
- /*
- * Contact meets the activation size threshold
- */
- if (nd->w >= nd->activation_width &&
- nd->h >= nd->activation_height) {
- if (nd->id)
- /*
- * first contact, activate now
- */
- nd->act_state = 0;
- else {
- /*
- * avoid corrupting this frame
- * but ensure next frame will
- * be active
- */
- nd->act_state = 1;
- break;
- }
- } else
+ if (nd->w >= nd->activation_width &&
+ nd->h >= nd->activation_height) {
+ if (nd->id)
/*
- * Defer adjusting the activation state
- * until the end of the frame.
+ * first contact, activate now
*/
+ nd->act_state = 0;
+ else {
+ /*
+ * avoid corrupting this frame
+ * but ensure next frame will
+ * be active
+ */
+ nd->act_state = 1;
break;
- }
-
- /* Discarding this contact */
- if (!nd->confidence)
- break;
-
- /* emit a normal (X, Y) for the first point only */
- if (nd->id == 0) {
+ }
+ } else
/*
- * TipSwitch is superfluous in multitouch
- * mode. The footer events tell us
- * if there is a finger on the screen or
- * not.
+ * Defer adjusting the activation state
+ * until the end of the frame.
*/
- nd->first_contact_touch = nd->confidence;
- input_event(input, EV_ABS, ABS_X, nd->x);
- input_event(input, EV_ABS, ABS_Y, nd->y);
- }
+ break;
+ }
- /* Emit MT events */
- input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+ /* Discarding this contact */
+ if (!nd->confidence)
+ break;
+ /* emit a normal (X, Y) for the first point only */
+ if (nd->id == 0) {
/*
- * Translate from height and width to size
- * and orientation.
+ * TipSwitch is superfluous in multitouch
+ * mode. The footer events tell us
+ * if there is a finger on the screen or
+ * not.
*/
- if (nd->w > nd->h) {
- input_event(input, EV_ABS,
- ABS_MT_ORIENTATION, 1);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MAJOR, nd->w);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MINOR, nd->h);
- } else {
- input_event(input, EV_ABS,
- ABS_MT_ORIENTATION, 0);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MAJOR, nd->h);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MINOR, nd->w);
- }
- input_mt_sync(field->hidinput->input);
- break;
+ nd->first_contact_touch = nd->confidence;
+ input_event(input, EV_ABS, ABS_X, nd->x);
+ input_event(input, EV_ABS, ABS_Y, nd->y);
+ }
- case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
- if (!nd->reading_mt) /* Just to be sure */
- break;
+ /* Emit MT events */
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+
+ /*
+ * Translate from height and width to size
+ * and orientation.
+ */
+ if (nd->w > nd->h) {
+ input_event(input, EV_ABS,
+ ABS_MT_ORIENTATION, 1);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MAJOR, nd->w);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MINOR, nd->h);
+ } else {
+ input_event(input, EV_ABS,
+ ABS_MT_ORIENTATION, 0);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MAJOR, nd->h);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MINOR, nd->w);
+ }
+ input_mt_sync(field->hidinput->input);
+ break;
- nd->reading_mt = 0;
+ case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
+ if (!nd->reading_mt) /* Just to be sure */
+ break;
+ nd->reading_mt = 0;
+
+
+ /*
+ * Activation state machine logic:
+ *
+ * Fundamental states:
+ * state > 0: Inactive
+ * state <= 0: Active
+ * state < -deactivate_slack:
+ * Pen termination of touch
+ *
+ * Specific values of interest
+ * state == activate_slack
+ * no valid input since the last reset
+ *
+ * state == 0
+ * general operational state
+ *
+ * state == -deactivate_slack
+ * read sufficient empty frames to accept
+ * the end of input and reset
+ */
+
+ if (nd->act_state > 0) { /* Currently inactive */
+ if (value)
+ /*
+ * Consider each live contact as
+ * evidence of intentional activity.
+ */
+ nd->act_state = (nd->act_state > value)
+ ? nd->act_state - value
+ : 0;
+ else
+ /*
+ * Empty frame before we hit the
+ * activity threshold, reset.
+ */
+ nd->act_state = nd->activate_slack;
/*
- * Activation state machine logic:
- *
- * Fundamental states:
- * state > 0: Inactive
- * state <= 0: Active
- * state < -deactivate_slack:
- * Pen termination of touch
- *
- * Specific values of interest
- * state == activate_slack
- * no valid input since the last reset
- *
- * state == 0
- * general operational state
- *
- * state == -deactivate_slack
- * read sufficient empty frames to accept
- * the end of input and reset
+ * Entered this block inactive and no
+ * coordinates sent this frame, so hold off
+ * on button state.
*/
-
- if (nd->act_state > 0) { /* Currently inactive */
- if (value)
- /*
- * Consider each live contact as
- * evidence of intentional activity.
- */
- nd->act_state = (nd->act_state > value)
- ? nd->act_state - value
- : 0;
- else
- /*
- * Empty frame before we hit the
- * activity threshold, reset.
- */
- nd->act_state = nd->activate_slack;
-
+ break;
+ } else { /* Currently active */
+ if (value && nd->act_state >=
+ nd->deactivate_slack)
/*
- * Entered this block inactive and no
- * coordinates sent this frame, so hold off
- * on button state.
+ * Live point: clear accumulated
+ * deactivation count.
*/
- break;
- } else { /* Currently active */
- if (value && nd->act_state >=
- nd->deactivate_slack)
- /*
- * Live point: clear accumulated
- * deactivation count.
- */
- nd->act_state = 0;
- else if (nd->act_state <= nd->deactivate_slack)
- /*
- * We've consumed the deactivation
- * slack, time to deactivate and reset.
- */
- nd->act_state =
- nd->activate_slack;
- else { /* Move towards deactivation */
- nd->act_state--;
- break;
- }
- }
-
- if (nd->first_contact_touch && nd->act_state <= 0) {
+ nd->act_state = 0;
+ else if (nd->act_state <= nd->deactivate_slack)
/*
- * Check to see if we're ready to start
- * emitting touch events.
- *
- * Note: activation slack will decrease over
- * the course of the frame, and it will be
- * inconsistent from the start to the end of
- * the frame. However if the frame starts
- * with slack, first_contact_touch will still
- * be 0 and we will not get to this point.
+ * We've consumed the deactivation
+ * slack, time to deactivate and reset.
*/
- input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
- input_report_key(input, BTN_TOUCH, 1);
- } else {
- input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
- input_report_key(input, BTN_TOUCH, 0);
+ nd->act_state =
+ nd->activate_slack;
+ else { /* Move towards deactivation */
+ nd->act_state--;
+ break;
}
- break;
+ }
- default:
- /* fall-back to the generic hidinput handling */
- return 0;
+ if (nd->first_contact_touch && nd->act_state <= 0) {
+ /*
+ * Check to see if we're ready to start
+ * emitting touch events.
+ *
+ * Note: activation slack will decrease over
+ * the course of the frame, and it will be
+ * inconsistent from the start to the end of
+ * the frame. However if the frame starts
+ * with slack, first_contact_touch will still
+ * be 0 and we will not get to this point.
+ */
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
+ input_report_key(input, BTN_TOUCH, 1);
+ } else {
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
+ input_report_key(input, BTN_TOUCH, 0);
}
+ break;
+
+ default:
+ /* fall-back to the generic hidinput handling */
+ return 0;
}
+not_claimed_input:
+
/* we have handled the hidinput part, now remains hiddev */
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
@@ -826,7 +867,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct hid_report *report;
if (id->driver_data)
- hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT
+ | HID_QUIRK_NO_INIT_REPORTS;
nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
if (!nd) {
@@ -893,8 +935,19 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
/* This is needed for devices with more recent firmware versions */
report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
- if (report)
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ if (report) {
+ /* Let the device settle to ensure the wakeup message gets
+ * through */
+ usbhid_wait_io(hdev);
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+
+ /*
+ * Sanity check: if the current mode is invalid reset it to
+ * something reasonable.
+ */
+ if (ntrig_get_mode(hdev) >= 4)
+ ntrig_set_mode(hdev, 3);
+ }
ntrig_report_version(hdev);
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
index e90edfc63051..f9b7dd4f607f 100644
--- a/drivers/hid/hid-ortek.c
+++ b/drivers/hid/hid-ortek.c
@@ -1,7 +1,6 @@
/*
- * HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad).
- * Fixes LogicalMaximum error in USB report description, see
- * http://bugzilla.kernel.org/show_bug.cgi?id=14787
+ * HID driver for Ortek PKB-1700/WKB-2000 (wireless keyboard + mouse trackpad).
+ * Fixes LogicalMaximum error in HID report description.
*
* Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
*/
@@ -30,6 +29,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
}
static const struct hid_device_id ortek_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ }
};
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
new file mode 100644
index 000000000000..2307471d96dc
--- /dev/null
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -0,0 +1,450 @@
+/*
+ * Roccat Arvo driver for Linux
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Roccat Arvo is a gamer keyboard with 5 macro keys that can be configured in
+ * 5 profiles.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-arvo.h"
+
+static struct class *arvo_class;
+
+static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_mode_key temp_buf;
+ int retval;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+ &temp_buf, sizeof(struct arvo_mode_key));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_buf.state);
+}
+
+static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_mode_key temp_buf;
+ unsigned long state;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &state);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_MODE_KEY;
+ temp_buf.state = state;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+ &temp_buf, sizeof(struct arvo_mode_key));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_key_mask temp_buf;
+ int retval;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+ &temp_buf, sizeof(struct arvo_key_mask));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_buf.key_mask);
+}
+
+static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_key_mask temp_buf;
+ unsigned long key_mask;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &key_mask);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_KEY_MASK;
+ temp_buf.key_mask = key_mask;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+ &temp_buf, sizeof(struct arvo_key_mask));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+/* retval is 1-5 on success, < 0 on error */
+static int arvo_get_actual_profile(struct usb_device *usb_dev)
+{
+ struct arvo_actual_profile temp_buf;
+ int retval;
+
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+ &temp_buf, sizeof(struct arvo_actual_profile));
+
+ if (retval)
+ return retval;
+
+ return temp_buf.actual_profile;
+}
+
+static ssize_t arvo_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", arvo->actual_profile);
+}
+
+static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_actual_profile temp_buf;
+ unsigned long profile;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE;
+ temp_buf.actual_profile = profile;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+ &temp_buf, sizeof(struct arvo_actual_profile));
+ if (!retval) {
+ arvo->actual_profile = profile;
+ retval = size;
+ }
+ mutex_unlock(&arvo->arvo_lock);
+ return retval;
+}
+
+static ssize_t arvo_sysfs_write(struct file *fp,
+ struct kobject *kobj, void const *buf,
+ loff_t off, size_t count, size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, command, buf, real_size);
+ mutex_unlock(&arvo->arvo_lock);
+
+ return (retval ? retval : real_size);
+}
+
+static ssize_t arvo_sysfs_read(struct file *fp,
+ struct kobject *kobj, void *buf, loff_t off,
+ size_t count, size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off >= real_size)
+ return 0;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, command, buf, real_size);
+ mutex_unlock(&arvo->arvo_lock);
+
+ return (retval ? retval : real_size);
+}
+
+static ssize_t arvo_sysfs_write_button(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return arvo_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON);
+}
+
+static ssize_t arvo_sysfs_read_info(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return arvo_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO);
+}
+
+
+static struct device_attribute arvo_attributes[] = {
+ __ATTR(mode_key, 0660,
+ arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key),
+ __ATTR(key_mask, 0660,
+ arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask),
+ __ATTR(actual_profile, 0660,
+ arvo_sysfs_show_actual_profile,
+ arvo_sysfs_set_actual_profile),
+ __ATTR_NULL
+};
+
+static struct bin_attribute arvo_bin_attributes[] = {
+ {
+ .attr = { .name = "button", .mode = 0220 },
+ .size = sizeof(struct arvo_button),
+ .write = arvo_sysfs_write_button
+ },
+ {
+ .attr = { .name = "info", .mode = 0440 },
+ .size = sizeof(struct arvo_info),
+ .read = arvo_sysfs_read_info
+ },
+ __ATTR_NULL
+};
+
+static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
+ struct arvo_device *arvo)
+{
+ int retval;
+
+ mutex_init(&arvo->arvo_lock);
+
+ retval = arvo_get_actual_profile(usb_dev);
+ if (retval < 0)
+ return retval;
+ arvo->actual_profile = retval;
+
+ return 0;
+}
+
+static int arvo_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct arvo_device *arvo;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_KEYBOARD) {
+ hid_set_drvdata(hdev, NULL);
+ return 0;
+ }
+
+ arvo = kzalloc(sizeof(*arvo), GFP_KERNEL);
+ if (!arvo) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, arvo);
+
+ retval = arvo_init_arvo_device_struct(usb_dev, arvo);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct arvo_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(arvo_class, hdev,
+ sizeof(struct arvo_roccat_report));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ arvo->chrdev_minor = retval;
+ arvo->roccat_claimed = 1;
+ }
+
+ return 0;
+exit_free:
+ kfree(arvo);
+ return retval;
+}
+
+static void arvo_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct arvo_device *arvo;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_KEYBOARD)
+ return;
+
+ arvo = hid_get_drvdata(hdev);
+ if (arvo->roccat_claimed)
+ roccat_disconnect(arvo->chrdev_minor);
+ kfree(arvo);
+}
+
+static int arvo_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = arvo_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install keyboard\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void arvo_remove(struct hid_device *hdev)
+{
+ arvo_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void arvo_report_to_chrdev(struct arvo_device const *arvo,
+ u8 const *data)
+{
+ struct arvo_special_report const *special_report;
+ struct arvo_roccat_report roccat_report;
+
+ special_report = (struct arvo_special_report const *)data;
+
+ roccat_report.profile = arvo->actual_profile;
+ roccat_report.button = special_report->event &
+ ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON;
+ if ((special_report->event & ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION) ==
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS)
+ roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_PRESS;
+ else
+ roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_RELEASE;
+
+ roccat_report_event(arvo->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+}
+
+static int arvo_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct arvo_device *arvo = hid_get_drvdata(hdev);
+
+ if (size != 3)
+ return 0;
+
+ if (arvo->roccat_claimed)
+ arvo_report_to_chrdev(arvo, data);
+
+ return 0;
+}
+
+static const struct hid_device_id arvo_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, arvo_devices);
+
+static struct hid_driver arvo_driver = {
+ .name = "arvo",
+ .id_table = arvo_devices,
+ .probe = arvo_probe,
+ .remove = arvo_remove,
+ .raw_event = arvo_raw_event
+};
+
+static int __init arvo_init(void)
+{
+ int retval;
+
+ arvo_class = class_create(THIS_MODULE, "arvo");
+ if (IS_ERR(arvo_class))
+ return PTR_ERR(arvo_class);
+ arvo_class->dev_attrs = arvo_attributes;
+ arvo_class->dev_bin_attrs = arvo_bin_attributes;
+
+ retval = hid_register_driver(&arvo_driver);
+ if (retval)
+ class_destroy(arvo_class);
+ return retval;
+}
+
+static void __exit arvo_exit(void)
+{
+ hid_unregister_driver(&arvo_driver);
+ class_destroy(arvo_class);
+}
+
+module_init(arvo_init);
+module_exit(arvo_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Arvo driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-arvo.h b/drivers/hid/hid-roccat-arvo.h
new file mode 100644
index 000000000000..d284a781c99e
--- /dev/null
+++ b/drivers/hid/hid-roccat-arvo.h
@@ -0,0 +1,98 @@
+#ifndef __HID_ROCCAT_ARVO_H
+#define __HID_ROCCAT_ARVO_H
+
+/*
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/types.h>
+
+struct arvo_mode_key { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_MODE_KEY */
+ uint8_t state;
+} __packed;
+
+struct arvo_button {
+ uint8_t unknown[24];
+} __packed;
+
+struct arvo_info {
+ uint8_t unknown[8];
+} __packed;
+
+struct arvo_key_mask { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_KEY_MASK */
+ uint8_t key_mask;
+} __packed;
+
+/* selected profile is persistent */
+struct arvo_actual_profile { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_ACTUAL_PROFILE */
+ uint8_t actual_profile;
+} __packed;
+
+enum arvo_commands {
+ ARVO_COMMAND_MODE_KEY = 0x3,
+ ARVO_COMMAND_BUTTON = 0x4,
+ ARVO_COMMAND_INFO = 0x5,
+ ARVO_COMMAND_KEY_MASK = 0x6,
+ ARVO_COMMAND_ACTUAL_PROFILE = 0x7,
+};
+
+enum arvo_usb_commands {
+ ARVO_USB_COMMAND_MODE_KEY = 0x303,
+ /*
+ * read/write
+ * Read uses both index bytes as profile/key indexes
+ * Write has index 0, profile/key is determined by payload
+ */
+ ARVO_USB_COMMAND_BUTTON = 0x304,
+ ARVO_USB_COMMAND_INFO = 0x305,
+ ARVO_USB_COMMAND_KEY_MASK = 0x306,
+ ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307,
+};
+
+struct arvo_special_report {
+ uint8_t unknown1; /* always 0x01 */
+ uint8_t event;
+ uint8_t unknown2; /* always 0x70 */
+} __packed;
+
+enum arvo_special_report_events {
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS = 0x10,
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_RELEASE = 0x0,
+};
+
+enum arvo_special_report_event_masks {
+ ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION = 0xf0,
+ ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON = 0x0f,
+};
+
+struct arvo_roccat_report {
+ uint8_t profile;
+ uint8_t button;
+ uint8_t action;
+} __packed;
+
+enum arvo_roccat_report_action {
+ ARVO_ROCCAT_REPORT_ACTION_RELEASE = 0,
+ ARVO_ROCCAT_REPORT_ACTION_PRESS = 1,
+};
+
+struct arvo_device {
+ int roccat_claimed;
+ int chrdev_minor;
+
+ struct mutex arvo_lock;
+
+ int actual_profile;
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c
new file mode 100644
index 000000000000..13b1eb0c8c65
--- /dev/null
+++ b/drivers/hid/hid-roccat-common.c
@@ -0,0 +1,62 @@
+/*
+ * Roccat common functions for device specific drivers
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/slab.h>
+#include "hid-roccat-common.h"
+
+int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+ void *data, uint size)
+{
+ char *buf;
+ int len;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ memcpy(data, buf, size);
+ kfree(buf);
+ return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+EXPORT_SYMBOL_GPL(roccat_common_receive);
+
+int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+ void const *data, uint size)
+{
+ char *buf;
+ int len;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memcpy(buf, data, size);
+
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ kfree(buf);
+ return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+EXPORT_SYMBOL_GPL(roccat_common_send);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat common driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h
new file mode 100644
index 000000000000..fe45fae05bb9
--- /dev/null
+++ b/drivers/hid/hid-roccat-common.h
@@ -0,0 +1,23 @@
+#ifndef __HID_ROCCAT_COMMON_H
+#define __HID_ROCCAT_COMMON_H
+
+/*
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/usb.h>
+#include <linux/types.h>
+
+int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+ void *data, uint size);
+int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+ void const *data, uint size);
+
+#endif
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index cbd8cc42e75a..a57838d15267 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -28,11 +28,11 @@
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hid-roccat.h>
#include "hid-ids.h"
-#include "hid-roccat.h"
+#include "hid-roccat-common.h"
#include "hid-roccat-kone.h"
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
@@ -58,12 +58,8 @@ static void kone_set_settings_checksum(struct kone_settings *settings)
*/
static int kone_check_write(struct usb_device *usb_dev)
{
- int len;
- unsigned char *data;
-
- data = kmalloc(1, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ int retval;
+ uint8_t data;
do {
/*
@@ -72,56 +68,36 @@ static int kone_check_write(struct usb_device *usb_dev)
*/
msleep(80);
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE |
- USB_DIR_IN,
- kone_command_confirm_write, 0, data, 1,
- USB_CTRL_SET_TIMEOUT);
-
- if (len != 1) {
- kfree(data);
- return -EIO;
- }
+ retval = roccat_common_receive(usb_dev,
+ kone_command_confirm_write, &data, 1);
+ if (retval)
+ return retval;
/*
* value of 3 seems to mean something like
* "not finished yet, but it looks good"
* So check again after a moment.
*/
- } while (*data == 3);
+ } while (data == 3);
- if (*data == 1) { /* everything alright */
- kfree(data);
+ if (data == 1) /* everything alright */
return 0;
- } else { /* unknown answer */
- hid_err(usb_dev, "got retval %d when checking write\n", *data);
- kfree(data);
- return -EIO;
- }
+
+ /* unknown answer */
+ hid_err(usb_dev, "got retval %d when checking write\n", data);
+ return -EIO;
}
/*
* Reads settings from mouse and stores it in @buf
- * @buf has to be alloced with GFP_KERNEL
* On success returns 0
* On failure returns errno
*/
static int kone_get_settings(struct usb_device *usb_dev,
struct kone_settings *buf)
{
- int len;
-
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_settings, 0, buf,
- sizeof(struct kone_settings), USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct kone_settings))
- return -EIO;
-
- return 0;
+ return roccat_common_receive(usb_dev, kone_command_settings, buf,
+ sizeof(struct kone_settings));
}
/*
@@ -132,22 +108,12 @@ static int kone_get_settings(struct usb_device *usb_dev,
static int kone_set_settings(struct usb_device *usb_dev,
struct kone_settings const *settings)
{
- int len;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_settings, 0, (char *)settings,
- sizeof(struct kone_settings),
- USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct kone_settings))
- return -EIO;
-
- if (kone_check_write(usb_dev))
- return -EIO;
-
- return 0;
+ int retval;
+ retval = roccat_common_send(usb_dev, kone_command_settings,
+ settings, sizeof(struct kone_settings));
+ if (retval)
+ return retval;
+ return kone_check_write(usb_dev);
}
/*
@@ -193,7 +159,7 @@ static int kone_set_profile(struct usb_device *usb_dev,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_profile, number, (char *)profile,
+ kone_command_profile, number, (void *)profile,
sizeof(struct kone_profile),
USB_CTRL_SET_TIMEOUT);
@@ -213,24 +179,15 @@ static int kone_set_profile(struct usb_device *usb_dev,
*/
static int kone_get_weight(struct usb_device *usb_dev, int *result)
{
- int len;
- uint8_t *data;
+ int retval;
+ uint8_t data;
- data = kmalloc(1, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1);
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_weight, 0, data, 1, USB_CTRL_SET_TIMEOUT);
+ if (retval)
+ return retval;
- if (len != 1) {
- kfree(data);
- return -EIO;
- }
- *result = (int)*data;
- kfree(data);
+ *result = (int)data;
return 0;
}
@@ -241,25 +198,15 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result)
*/
static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
{
- int len;
- unsigned char *data;
-
- data = kmalloc(2, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ int retval;
+ uint16_t data;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_firmware_version, 0, data, 2,
- USB_CTRL_SET_TIMEOUT);
+ retval = roccat_common_receive(usb_dev, kone_command_firmware_version,
+ &data, 2);
+ if (retval)
+ return retval;
- if (len != 2) {
- kfree(data);
- return -EIO;
- }
- *result = le16_to_cpu(*data);
- kfree(data);
+ *result = le16_to_cpu(data);
return 0;
}
@@ -435,23 +382,9 @@ static ssize_t kone_sysfs_show_tcu(struct device *dev,
static int kone_tcu_command(struct usb_device *usb_dev, int number)
{
- int len;
- char *value;
-
- value = kmalloc(1, GFP_KERNEL);
- if (!value)
- return -ENOMEM;
-
- *value = number;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_calibrate, 0, value, 1,
- USB_CTRL_SET_TIMEOUT);
-
- kfree(value);
- return ((len != 1) ? -EIO : 0);
+ unsigned char value;
+ value = number;
+ return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1);
}
/*
@@ -727,7 +660,8 @@ static int kone_init_specials(struct hid_device *hdev)
goto exit_free;
}
- retval = roccat_connect(kone_class, hdev);
+ retval = roccat_connect(kone_class, hdev,
+ sizeof(struct kone_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */
@@ -827,8 +761,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = event->value;
roccat_report.key = 0;
roccat_report_event(kone->chrdev_minor,
- (uint8_t *)&roccat_report,
- sizeof(struct kone_roccat_report));
+ (uint8_t *)&roccat_report);
break;
case kone_mouse_event_call_overlong_macro:
if (event->value == kone_keystroke_action_press) {
@@ -836,8 +769,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor,
- (uint8_t *)&roccat_report,
- sizeof(struct kone_roccat_report));
+ (uint8_t *)&roccat_report);
}
break;
}
@@ -912,8 +844,8 @@ static int __init kone_init(void)
static void __exit kone_exit(void)
{
- class_destroy(kone_class);
hid_unregister_driver(&kone_driver);
+ class_destroy(kone_class);
}
module_init(kone_init);
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 1608c8d1efd6..33eec74e0615 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -19,11 +19,11 @@
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hid-roccat.h>
#include "hid-ids.h"
-#include "hid-roccat.h"
+#include "hid-roccat-common.h"
#include "hid-roccat-koneplus.h"
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
@@ -39,110 +39,63 @@ static void koneplus_profile_activated(struct koneplus_device *koneplus,
static int koneplus_send_control(struct usb_device *usb_dev, uint value,
enum koneplus_control_requests request)
{
- int len;
- struct koneplus_control *control;
+ struct koneplus_control control;
if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
value > 4)
return -EINVAL;
- control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
- if (!control)
- return -ENOMEM;
+ control.command = KONEPLUS_COMMAND_CONTROL;
+ control.value = value;
+ control.request = request;
- control->command = KONEPLUS_COMMAND_CONTROL;
- control->value = value;
- control->request = request;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- KONEPLUS_USB_COMMAND_CONTROL, 0, control,
- sizeof(struct koneplus_control),
- USB_CTRL_SET_TIMEOUT);
-
- kfree(control);
-
- if (len != sizeof(struct koneplus_control))
- return len;
-
- return 0;
-}
-
-static int koneplus_receive(struct usb_device *usb_dev, uint usb_command,
- void *buf, uint size) {
- int len;
-
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
-
- return (len != size) ? -EIO : 0;
+ return roccat_common_send(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct koneplus_control));
}
static int koneplus_receive_control_status(struct usb_device *usb_dev)
{
int retval;
- struct koneplus_control *control;
-
- control = kmalloc(sizeof(struct koneplus_control), GFP_KERNEL);
- if (!control)
- return -ENOMEM;
+ struct koneplus_control control;
do {
- retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
- control, sizeof(struct koneplus_control));
+ retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct koneplus_control));
/* check if we get a completely wrong answer */
if (retval)
- goto out;
+ return retval;
- if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OK) {
- retval = 0;
- goto out;
- }
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OK)
+ return 0;
/* indicates that hardware needs some more time to complete action */
- if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
msleep(500); /* windows driver uses 1000 */
continue;
}
/* seems to be critical - replug necessary */
- if (control->value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) {
- retval = -EINVAL;
- goto out;
- }
-
- dev_err(&usb_dev->dev, "koneplus_receive_control_status: "
- "unknown response value 0x%x\n", control->value);
- retval = -EINVAL;
- goto out;
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
+ return -EINVAL;
+ hid_err(usb_dev, "koneplus_receive_control_status: "
+ "unknown response value 0x%x\n", control.value);
+ return -EINVAL;
} while (1);
-out:
- kfree(control);
- return retval;
}
static int koneplus_send(struct usb_device *usb_dev, uint command,
- void *buf, uint size) {
- int len;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
-
- if (len != size)
- return -EIO;
+ void const *buf, uint size)
+{
+ int retval;
- if (koneplus_receive_control_status(usb_dev))
- return -EIO;
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
- return 0;
+ return koneplus_receive_control_status(usb_dev);
}
static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
@@ -167,7 +120,7 @@ static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
static int koneplus_get_info(struct usb_device *usb_dev,
struct koneplus_info *buf)
{
- return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
buf, sizeof(struct koneplus_info));
}
@@ -181,7 +134,7 @@ static int koneplus_get_profile_settings(struct usb_device *usb_dev,
if (retval)
return retval;
- return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
buf, sizeof(struct koneplus_profile_settings));
}
@@ -189,7 +142,7 @@ static int koneplus_set_profile_settings(struct usb_device *usb_dev,
struct koneplus_profile_settings const *settings)
{
return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
- (void *)settings, sizeof(struct koneplus_profile_settings));
+ settings, sizeof(struct koneplus_profile_settings));
}
static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
@@ -202,7 +155,7 @@ static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
if (retval)
return retval;
- return koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
buf, sizeof(struct koneplus_profile_buttons));
}
@@ -210,27 +163,19 @@ static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
struct koneplus_profile_buttons const *buttons)
{
return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
- (void *)buttons, sizeof(struct koneplus_profile_buttons));
+ buttons, sizeof(struct koneplus_profile_buttons));
}
/* retval is 0-4 on success, < 0 on error */
static int koneplus_get_startup_profile(struct usb_device *usb_dev)
{
- struct koneplus_startup_profile *buf;
+ struct koneplus_startup_profile buf;
int retval;
- buf = kmalloc(sizeof(struct koneplus_startup_profile), GFP_KERNEL);
+ retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+ &buf, sizeof(struct koneplus_startup_profile));
- retval = koneplus_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
- buf, sizeof(struct koneplus_startup_profile));
-
- if (retval)
- goto out;
-
- retval = buf->startup_profile;
-out:
- kfree(buf);
- return retval;
+ return retval ? retval : buf.startup_profile;
}
static int koneplus_set_startup_profile(struct usb_device *usb_dev,
@@ -243,7 +188,7 @@ static int koneplus_set_startup_profile(struct usb_device *usb_dev,
buf.startup_profile = startup_profile;
return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
- (char *)&buf, sizeof(struct koneplus_profile_buttons));
+ &buf, sizeof(struct koneplus_profile_buttons));
}
static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
@@ -256,11 +201,14 @@ static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
+ if (off >= real_size)
+ return 0;
+
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&koneplus->koneplus_lock);
- retval = koneplus_receive(usb_dev, command, buf, real_size);
+ retval = roccat_common_receive(usb_dev, command, buf, real_size);
mutex_unlock(&koneplus->koneplus_lock);
if (retval)
@@ -283,7 +231,7 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
return -EINVAL;
mutex_lock(&koneplus->koneplus_lock);
- retval = koneplus_send(usb_dev, command, (void *)buf, real_size);
+ retval = koneplus_send(usb_dev, command, buf, real_size);
mutex_unlock(&koneplus->koneplus_lock);
if (retval)
@@ -347,7 +295,7 @@ static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
count = sizeof(struct koneplus_profile_settings) - off;
mutex_lock(&koneplus->koneplus_lock);
- memcpy(buf, ((void const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
+ memcpy(buf, ((char const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&koneplus->koneplus_lock);
@@ -406,7 +354,7 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
count = sizeof(struct koneplus_profile_buttons) - off;
mutex_lock(&koneplus->koneplus_lock);
- memcpy(buf, ((void const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
+ memcpy(buf, ((char const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&koneplus->koneplus_lock);
@@ -512,7 +460,7 @@ static struct device_attribute koneplus_attributes[] = {
static struct bin_attribute koneplus_bin_attributes[] = {
{
- .attr = { .name = "sensor", .mode = 0220 },
+ .attr = { .name = "sensor", .mode = 0660 },
.size = sizeof(struct koneplus_sensor),
.read = koneplus_sysfs_read_sensor,
.write = koneplus_sysfs_write_sensor
@@ -609,11 +557,13 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus)
{
int retval, i;
- static uint wait = 70; /* device will freeze with just 60 */
+ static uint wait = 100; /* device will freeze with just 60 */
mutex_init(&koneplus->koneplus_lock);
koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
+ if (koneplus->startup_profile < 0)
+ return koneplus->startup_profile;
msleep(wait);
retval = koneplus_get_info(usb_dev, &koneplus->info);
@@ -651,21 +601,21 @@ static int koneplus_init_specials(struct hid_device *hdev)
koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
if (!koneplus) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, koneplus);
retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
if (retval) {
- dev_err(&hdev->dev,
- "couldn't init struct koneplus_device\n");
+ hid_err(hdev, "couldn't init struct koneplus_device\n");
goto exit_free;
}
- retval = roccat_connect(koneplus_class, hdev);
+ retval = roccat_connect(koneplus_class, hdev,
+ sizeof(struct koneplus_roccat_report));
if (retval < 0) {
- dev_err(&hdev->dev, "couldn't init char dev\n");
+ hid_err(hdev, "couldn't init char dev\n");
} else {
koneplus->chrdev_minor = retval;
koneplus->roccat_claimed = 1;
@@ -701,19 +651,19 @@ static int koneplus_probe(struct hid_device *hdev,
retval = hid_parse(hdev);
if (retval) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = koneplus_init_specials(hdev);
if (retval) {
- dev_err(&hdev->dev, "couldn't install mouse\n");
+ hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
@@ -769,8 +719,7 @@ static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
roccat_report.data2 = button_report->data2;
roccat_report.profile = koneplus->actual_profile + 1;
roccat_report_event(koneplus->chrdev_minor,
- (uint8_t const *)&roccat_report,
- sizeof(struct koneplus_roccat_report));
+ (uint8_t const *)&roccat_report);
}
static int koneplus_raw_event(struct hid_device *hdev,
@@ -825,8 +774,8 @@ static int __init koneplus_init(void)
static void __exit koneplus_exit(void)
{
- class_destroy(koneplus_class);
hid_unregister_driver(&koneplus_driver);
+ class_destroy(koneplus_class);
}
module_init(koneplus_init);
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
new file mode 100644
index 000000000000..984be2f8967e
--- /dev/null
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -0,0 +1,715 @@
+/*
+ * Roccat Kova[+] driver for Linux
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-kovaplus.h"
+
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+static struct class *kovaplus_class;
+
+static uint kovaplus_convert_event_cpi(uint value)
+{
+ return (value == 7 ? 4 : (value == 4 ? 3 : value));
+}
+
+static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
+ uint new_profile_index)
+{
+ kovaplus->actual_profile = new_profile_index;
+ kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
+ kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
+ kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y;
+}
+
+static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
+ enum kovaplus_control_requests request)
+{
+ int retval;
+ struct kovaplus_control control;
+
+ if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
+ request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+ value > 4)
+ return -EINVAL;
+
+ control.command = KOVAPLUS_COMMAND_CONTROL;
+ control.value = value;
+ control.request = request;
+
+ retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct kovaplus_control));
+
+ return retval;
+}
+
+static int kovaplus_receive_control_status(struct usb_device *usb_dev)
+{
+ int retval;
+ struct kovaplus_control control;
+
+ do {
+ retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct kovaplus_control));
+
+ /* check if we get a completely wrong answer */
+ if (retval)
+ return retval;
+
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK)
+ return 0;
+
+ /* indicates that hardware needs some more time to complete action */
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+ msleep(500); /* windows driver uses 1000 */
+ continue;
+ }
+
+ /* seems to be critical - replug necessary */
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
+ return -EINVAL;
+
+ hid_err(usb_dev, "kovaplus_receive_control_status: "
+ "unknown response value 0x%x\n", control.value);
+ return -EINVAL;
+ } while (1);
+}
+
+static int kovaplus_send(struct usb_device *usb_dev, uint command,
+ void const *buf, uint size)
+{
+ int retval;
+
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
+
+ msleep(100);
+
+ return kovaplus_receive_control_status(usb_dev);
+}
+
+static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
+ enum kovaplus_control_requests request)
+{
+ return kovaplus_send_control(usb_dev, number, request);
+}
+
+static int kovaplus_get_info(struct usb_device *usb_dev,
+ struct kovaplus_info *buf)
+{
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO,
+ buf, sizeof(struct kovaplus_info));
+}
+
+static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
+ struct kovaplus_profile_settings *buf, uint number)
+{
+ int retval;
+
+ retval = kovaplus_select_profile(usb_dev, number,
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct kovaplus_profile_settings));
+}
+
+static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
+ struct kovaplus_profile_settings const *settings)
+{
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ settings, sizeof(struct kovaplus_profile_settings));
+}
+
+static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
+ struct kovaplus_profile_buttons *buf, int number)
+{
+ int retval;
+
+ retval = kovaplus_select_profile(usb_dev, number,
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct kovaplus_profile_buttons));
+}
+
+static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
+ struct kovaplus_profile_buttons const *buttons)
+{
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buttons, sizeof(struct kovaplus_profile_buttons));
+}
+
+/* retval is 0-4 on success, < 0 on error */
+static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
+{
+ struct kovaplus_actual_profile buf;
+ int retval;
+
+ retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct kovaplus_actual_profile));
+
+ return retval ? retval : buf.actual_profile;
+}
+
+static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
+ int new_profile)
+{
+ struct kovaplus_actual_profile buf;
+
+ buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE;
+ buf.size = sizeof(struct kovaplus_actual_profile);
+ buf.actual_profile = new_profile;
+
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct kovaplus_actual_profile));
+}
+
+static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct kovaplus_profile_settings))
+ return 0;
+
+ if (off + count > sizeof(struct kovaplus_profile_settings))
+ count = sizeof(struct kovaplus_profile_settings) - off;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ return count;
+}
+
+static ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_index;
+ struct kovaplus_profile_settings *profile_settings;
+
+ if (off != 0 || count != sizeof(struct kovaplus_profile_settings))
+ return -EINVAL;
+
+ profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index;
+ profile_settings = &kovaplus->profile_settings[profile_index];
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ difference = memcmp(buf, profile_settings,
+ sizeof(struct kovaplus_profile_settings));
+ if (difference) {
+ retval = kovaplus_set_profile_settings(usb_dev,
+ (struct kovaplus_profile_settings const *)buf);
+ if (!retval)
+ memcpy(profile_settings, buf,
+ sizeof(struct kovaplus_profile_settings));
+ }
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct kovaplus_profile_settings);
+}
+
+static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct kovaplus_profile_buttons))
+ return 0;
+
+ if (off + count > sizeof(struct kovaplus_profile_buttons))
+ count = sizeof(struct kovaplus_profile_buttons) - off;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ return count;
+}
+
+static ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ uint profile_index;
+ struct kovaplus_profile_buttons *profile_buttons;
+
+ if (off != 0 || count != sizeof(struct kovaplus_profile_buttons))
+ return -EINVAL;
+
+ profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index;
+ profile_buttons = &kovaplus->profile_buttons[profile_index];
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ difference = memcmp(buf, profile_buttons,
+ sizeof(struct kovaplus_profile_buttons));
+ if (difference) {
+ retval = kovaplus_set_profile_buttons(usb_dev,
+ (struct kovaplus_profile_buttons const *)buf);
+ if (!retval)
+ memcpy(profile_buttons, buf,
+ sizeof(struct kovaplus_profile_buttons));
+ }
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct kovaplus_profile_buttons);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile);
+}
+
+static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct kovaplus_device *kovaplus;
+ struct usb_device *usb_dev;
+ unsigned long profile;
+ int retval;
+
+ dev = dev->parent->parent;
+ kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ if (profile >= 5)
+ return -EINVAL;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ retval = kovaplus_set_actual_profile(usb_dev, profile);
+ kovaplus->actual_profile = profile;
+ mutex_unlock(&kovaplus->kovaplus_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
+}
+
+static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version);
+}
+
+static struct device_attribute kovaplus_attributes[] = {
+ __ATTR(actual_cpi, 0440,
+ kovaplus_sysfs_show_actual_cpi, NULL),
+ __ATTR(firmware_version, 0440,
+ kovaplus_sysfs_show_firmware_version, NULL),
+ __ATTR(actual_profile, 0660,
+ kovaplus_sysfs_show_actual_profile,
+ kovaplus_sysfs_set_actual_profile),
+ __ATTR(actual_sensitivity_x, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_x, NULL),
+ __ATTR(actual_sensitivity_y, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_y, NULL),
+ __ATTR_NULL
+};
+
+static struct bin_attribute kovaplus_bin_attributes[] = {
+ {
+ .attr = { .name = "profile_settings", .mode = 0220 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .write = kovaplus_sysfs_write_profile_settings
+ },
+ {
+ .attr = { .name = "profile1_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "profile_buttons", .mode = 0220 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .write = kovaplus_sysfs_write_profile_buttons
+ },
+ {
+ .attr = { .name = "profile1_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ __ATTR_NULL
+};
+
+static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
+ struct kovaplus_device *kovaplus)
+{
+ int retval, i;
+ static uint wait = 70; /* device will freeze with just 60 */
+
+ mutex_init(&kovaplus->kovaplus_lock);
+
+ retval = kovaplus_get_info(usb_dev, &kovaplus->info);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < 5; ++i) {
+ msleep(wait);
+ retval = kovaplus_get_profile_settings(usb_dev,
+ &kovaplus->profile_settings[i], i);
+ if (retval)
+ return retval;
+
+ msleep(wait);
+ retval = kovaplus_get_profile_buttons(usb_dev,
+ &kovaplus->profile_buttons[i], i);
+ if (retval)
+ return retval;
+ }
+
+ msleep(wait);
+ retval = kovaplus_get_actual_profile(usb_dev);
+ if (retval < 0)
+ return retval;
+ kovaplus_profile_activated(kovaplus, retval);
+
+ return 0;
+}
+
+static int kovaplus_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct kovaplus_device *kovaplus;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+ kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL);
+ if (!kovaplus) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, kovaplus);
+
+ retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct kovaplus_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(kovaplus_class, hdev,
+ sizeof(struct kovaplus_roccat_report));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ kovaplus->chrdev_minor = retval;
+ kovaplus->roccat_claimed = 1;
+ }
+
+ } else {
+ hid_set_drvdata(hdev, NULL);
+ }
+
+ return 0;
+exit_free:
+ kfree(kovaplus);
+ return retval;
+}
+
+static void kovaplus_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct kovaplus_device *kovaplus;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+ kovaplus = hid_get_drvdata(hdev);
+ if (kovaplus->roccat_claimed)
+ roccat_disconnect(kovaplus->chrdev_minor);
+ kfree(kovaplus);
+ }
+}
+
+static int kovaplus_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = kovaplus_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void kovaplus_remove(struct hid_device *hdev)
+{
+ kovaplus_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
+ u8 const *data)
+{
+ struct kovaplus_mouse_report_button const *button_report;
+
+ if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct kovaplus_mouse_report_button const *)data;
+
+ switch (button_report->type) {
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1:
+ kovaplus_profile_activated(kovaplus, button_report->data1 - 1);
+ break;
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
+ kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
+ kovaplus->actual_x_sensitivity = button_report->data1;
+ kovaplus->actual_y_sensitivity = button_report->data2;
+ }
+}
+
+static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus,
+ u8 const *data)
+{
+ struct kovaplus_roccat_report roccat_report;
+ struct kovaplus_mouse_report_button const *button_report;
+
+ if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct kovaplus_mouse_report_button const *)data;
+
+ if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2)
+ return;
+
+ roccat_report.type = button_report->type;
+ roccat_report.profile = kovaplus->actual_profile + 1;
+
+ if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER)
+ roccat_report.button = button_report->data1;
+ else
+ roccat_report.button = 0;
+
+ if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI)
+ roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1);
+ else
+ roccat_report.data1 = button_report->data1;
+
+ roccat_report.data2 = button_report->data2;
+
+ roccat_report_event(kovaplus->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+}
+
+static int kovaplus_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct kovaplus_device *kovaplus = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ kovaplus_keep_values_up_to_date(kovaplus, data);
+
+ if (kovaplus->roccat_claimed)
+ kovaplus_report_to_chrdev(kovaplus, data);
+
+ return 0;
+}
+
+static const struct hid_device_id kovaplus_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, kovaplus_devices);
+
+static struct hid_driver kovaplus_driver = {
+ .name = "kovaplus",
+ .id_table = kovaplus_devices,
+ .probe = kovaplus_probe,
+ .remove = kovaplus_remove,
+ .raw_event = kovaplus_raw_event
+};
+
+static int __init kovaplus_init(void)
+{
+ int retval;
+
+ kovaplus_class = class_create(THIS_MODULE, "kovaplus");
+ if (IS_ERR(kovaplus_class))
+ return PTR_ERR(kovaplus_class);
+ kovaplus_class->dev_attrs = kovaplus_attributes;
+ kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
+
+ retval = hid_register_driver(&kovaplus_driver);
+ if (retval)
+ class_destroy(kovaplus_class);
+ return retval;
+}
+
+static void __exit kovaplus_exit(void)
+{
+ hid_unregister_driver(&kovaplus_driver);
+ class_destroy(kovaplus_class);
+}
+
+module_init(kovaplus_init);
+module_exit(kovaplus_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-kovaplus.h b/drivers/hid/hid-roccat-kovaplus.h
new file mode 100644
index 000000000000..ce40607d21c7
--- /dev/null
+++ b/drivers/hid/hid-roccat-kovaplus.h
@@ -0,0 +1,157 @@
+#ifndef __HID_ROCCAT_KOVAPLUS_H
+#define __HID_ROCCAT_KOVAPLUS_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/types.h>
+
+struct kovaplus_control {
+ uint8_t command; /* KOVAPLUS_COMMAND_CONTROL */
+ uint8_t value;
+ uint8_t request;
+} __packed;
+
+enum kovaplus_control_requests {
+ /* read after write; value = 1 */
+ KOVAPLUS_CONTROL_REQUEST_STATUS = 0x0,
+ /* write; value = profile number range 0-4 */
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
+ /* write; value = profile number range 0-4 */
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20,
+};
+
+enum kovaplus_control_values {
+ KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, /* supposed */
+ KOVAPLUS_CONTROL_REQUEST_STATUS_OK = 1,
+ KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, /* supposed */
+};
+
+struct kovaplus_actual_profile {
+ uint8_t command; /* KOVAPLUS_COMMAND_ACTUAL_PROFILE */
+ uint8_t size; /* always 3 */
+ uint8_t actual_profile; /* Range 0-4! */
+} __packed;
+
+struct kovaplus_profile_settings {
+ uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_SETTINGS */
+ uint8_t size; /* 16 */
+ uint8_t profile_index; /* range 0-4 */
+ uint8_t unknown1;
+ uint8_t sensitivity_x; /* range 1-10 */
+ uint8_t sensitivity_y; /* range 1-10 */
+ uint8_t cpi_levels_enabled;
+ uint8_t cpi_startup_level; /* range 1-4 */
+ uint8_t data[8];
+} __packed;
+
+struct kovaplus_profile_buttons {
+ uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_BUTTONS */
+ uint8_t size; /* 23 */
+ uint8_t profile_index; /* range 0-4 */
+ uint8_t data[20];
+} __packed;
+
+struct kovaplus_info {
+ uint8_t command; /* KOVAPLUS_COMMAND_INFO */
+ uint8_t size; /* 6 */
+ uint8_t firmware_version;
+ uint8_t unknown[3];
+} __packed;
+
+/* writes 1 on plugin */
+struct kovaplus_a {
+ uint8_t command; /* KOVAPLUS_COMMAND_A */
+ uint8_t size; /* 3 */
+ uint8_t unknown;
+} __packed;
+
+enum kovaplus_commands {
+ KOVAPLUS_COMMAND_CONTROL = 0x4,
+ KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
+ KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
+ KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
+ KOVAPLUS_COMMAND_INFO = 0x9,
+ KOVAPLUS_COMMAND_A = 0xa,
+};
+
+enum kovaplus_usb_commands {
+ KOVAPLUS_USB_COMMAND_CONTROL = 0x304,
+ KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
+ KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+ KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+ KOVAPLUS_USB_COMMAND_INFO = 0x309,
+ KOVAPLUS_USB_COMMAND_A = 0x30a,
+};
+
+enum kovaplus_mouse_report_numbers {
+ KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_KBD = 4,
+};
+
+struct kovaplus_mouse_report_button {
+ uint8_t report_number; /* KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON */
+ uint8_t unknown1;
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+} __packed;
+
+enum kovaplus_mouse_report_button_types {
+ /* data1 = profile_number range 1-5; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1 = 0x20,
+ /* data1 = profile_number range 1-5; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2 = 0x30,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO = 0x40,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT = 0x50,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
+ /* data1 = 1 = 400, 2 = 800, 4 = 1600, 7 = 3200; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
+ /* data1 + data2 = sense range 1-10; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+ /* data1 = type as in profile_buttons; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum kovaplus_mouse_report_button_actions {
+ KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
+ KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
+};
+
+struct kovaplus_roccat_report {
+ uint8_t type;
+ uint8_t profile;
+ uint8_t button;
+ uint8_t data1;
+ uint8_t data2;
+} __packed;
+
+struct kovaplus_device {
+ int actual_profile;
+ int actual_cpi;
+ int actual_x_sensitivity;
+ int actual_y_sensitivity;
+ int roccat_claimed;
+ int chrdev_minor;
+ struct mutex kovaplus_lock;
+ struct kovaplus_info info;
+ struct kovaplus_profile_settings profile_settings[5];
+ struct kovaplus_profile_buttons profile_buttons[5];
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 02c58e015bee..160f481344f6 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -20,11 +20,11 @@
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hid-roccat.h>
#include "hid-ids.h"
-#include "hid-roccat.h"
+#include "hid-roccat-common.h"
#include "hid-roccat-pyra.h"
static uint profile_numbers[5] = {0, 1, 2, 3, 4};
@@ -42,7 +42,6 @@ static void profile_activated(struct pyra_device *pyra,
static int pyra_send_control(struct usb_device *usb_dev, int value,
enum pyra_control_requests request)
{
- int len;
struct pyra_control control;
if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
@@ -54,47 +53,31 @@ static int pyra_send_control(struct usb_device *usb_dev, int value,
control.value = value;
control.request = request;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
- sizeof(struct pyra_control),
- USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct pyra_control))
- return len;
-
- return 0;
+ return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL,
+ &control, sizeof(struct pyra_control));
}
static int pyra_receive_control_status(struct usb_device *usb_dev)
{
- int len;
+ int retval;
struct pyra_control control;
do {
msleep(10);
-
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE |
- USB_DIR_IN,
- PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
- sizeof(struct pyra_control),
- USB_CTRL_SET_TIMEOUT);
+ retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL,
+ &control, sizeof(struct pyra_control));
/* requested too early, try again */
- } while (len == -EPROTO);
+ } while (retval == -EPROTO);
- if (len == sizeof(struct pyra_control) &&
- control.command == PYRA_COMMAND_CONTROL &&
+ if (!retval && control.command == PYRA_COMMAND_CONTROL &&
control.request == PYRA_CONTROL_REQUEST_STATUS &&
control.value == 1)
- return 0;
+ return 0;
else {
hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n",
control.request, control.value);
- return -EINVAL;
+ return retval ? retval : -EINVAL;
}
}
@@ -102,125 +85,72 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings *buf, int number)
{
int retval;
-
retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
-
if (retval)
return retval;
-
- retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf,
- sizeof(struct pyra_profile_settings),
- USB_CTRL_SET_TIMEOUT);
-
- if (retval != sizeof(struct pyra_profile_settings))
- return retval;
-
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct pyra_profile_settings));
}
static int pyra_get_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons *buf, int number)
{
int retval;
-
retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
-
if (retval)
return retval;
-
- retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf,
- sizeof(struct pyra_profile_buttons),
- USB_CTRL_SET_TIMEOUT);
-
- if (retval != sizeof(struct pyra_profile_buttons))
- return retval;
-
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct pyra_profile_buttons));
}
static int pyra_get_settings(struct usb_device *usb_dev,
struct pyra_settings *buf)
{
- int len;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_SETTINGS, 0, buf,
- sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_settings))
- return -EIO;
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS,
+ buf, sizeof(struct pyra_settings));
}
static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
{
- int len;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_INFO, 0, buf,
- sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_info))
- return -EIO;
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO,
+ buf, sizeof(struct pyra_info));
+}
+
+static int pyra_send(struct usb_device *usb_dev, uint command,
+ void const *buf, uint size)
+{
+ int retval;
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
+ return pyra_receive_control_status(usb_dev);
}
static int pyra_set_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings const *settings)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings,
- sizeof(struct pyra_profile_settings),
- USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_profile_settings))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings,
+ sizeof(struct pyra_profile_settings));
}
static int pyra_set_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons const *buttons)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons,
- sizeof(struct pyra_profile_buttons),
- USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_profile_buttons))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons,
+ sizeof(struct pyra_profile_buttons));
}
static int pyra_set_settings(struct usb_device *usb_dev,
struct pyra_settings const *settings)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings,
- sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_settings))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ int retval;
+ retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings,
+ sizeof(struct pyra_settings));
+ if (retval)
+ return retval;
+ return pyra_receive_control_status(usb_dev);
}
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
@@ -521,21 +451,16 @@ static struct bin_attribute pyra_bin_attributes[] = {
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra)
{
- struct pyra_info *info;
+ struct pyra_info info;
int retval, i;
mutex_init(&pyra->pyra_lock);
- info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- retval = pyra_get_info(usb_dev, info);
- if (retval) {
- kfree(info);
+ retval = pyra_get_info(usb_dev, &info);
+ if (retval)
return retval;
- }
- pyra->firmware_version = info->firmware_version;
- kfree(info);
+
+ pyra->firmware_version = info.firmware_version;
retval = pyra_get_settings(usb_dev, &pyra->settings);
if (retval)
@@ -581,7 +506,8 @@ static int pyra_init_specials(struct hid_device *hdev)
goto exit_free;
}
- retval = roccat_connect(pyra_class, hdev);
+ retval = roccat_connect(pyra_class, hdev,
+ sizeof(struct pyra_roccat_report));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
@@ -685,8 +611,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
roccat_report.value = button_event->data1;
roccat_report.key = 0;
roccat_report_event(pyra->chrdev_minor,
- (uint8_t const *)&roccat_report,
- sizeof(struct pyra_roccat_report));
+ (uint8_t const *)&roccat_report);
break;
case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
@@ -700,8 +625,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
*/
roccat_report.value = pyra->actual_profile + 1;
roccat_report_event(pyra->chrdev_minor,
- (uint8_t const *)&roccat_report,
- sizeof(struct pyra_roccat_report));
+ (uint8_t const *)&roccat_report);
}
break;
}
@@ -761,8 +685,8 @@ static int __init pyra_init(void)
static void __exit pyra_exit(void)
{
- class_destroy(pyra_class);
hid_unregister_driver(&pyra_driver);
+ class_destroy(pyra_class);
}
module_init(pyra_init);
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index a14c579ea781..5666e7587b18 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -26,8 +26,7 @@
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/sched.h>
-
-#include "hid-roccat.h"
+#include <linux/hid-roccat.h>
#define ROCCAT_FIRST_MINOR 0
#define ROCCAT_MAX_DEVICES 8
@@ -37,11 +36,11 @@
struct roccat_report {
uint8_t *value;
- int len;
};
struct roccat_device {
unsigned int minor;
+ int report_size;
int open;
int exist;
wait_queue_head_t wait;
@@ -123,7 +122,7 @@ static ssize_t roccat_read(struct file *file, char __user *buffer,
* If report is larger than requested amount of data, rest of report
* is lost!
*/
- len = report->len > count ? count : report->len;
+ len = device->report_size > count ? count : device->report_size;
if (copy_to_user(buffer, report->value, len)) {
retval = -EFAULT;
@@ -248,26 +247,25 @@ static int roccat_release(struct inode *inode, struct file *file)
*
* This is called from interrupt handler.
*/
-int roccat_report_event(int minor, u8 const *data, int len)
+int roccat_report_event(int minor, u8 const *data)
{
struct roccat_device *device;
struct roccat_reader *reader;
struct roccat_report *report;
uint8_t *new_value;
- new_value = kmemdup(data, len, GFP_ATOMIC);
+ device = devices[minor];
+
+ new_value = kmemdup(data, device->report_size, GFP_ATOMIC);
if (!new_value)
return -ENOMEM;
- device = devices[minor];
-
report = &device->cbuf[device->cbuf_end];
/* passing NULL is safe */
kfree(report->value);
report->value = new_value;
- report->len = len;
device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
list_for_each_entry(reader, &device->readers, node) {
@@ -295,7 +293,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.
*/
-int roccat_connect(struct class *klass, struct hid_device *hid)
+int roccat_connect(struct class *klass, struct hid_device *hid, int report_size)
{
unsigned int minor;
struct roccat_device *device;
@@ -343,6 +341,7 @@ int roccat_connect(struct class *klass, struct hid_device *hid)
device->hid = hid;
device->exist = 1;
device->cbuf_end = 0;
+ device->report_size = report_size;
return minor;
}
@@ -357,13 +356,16 @@ void roccat_disconnect(int minor)
mutex_lock(&devices_lock);
device = devices[minor];
- devices[minor] = NULL;
mutex_unlock(&devices_lock);
device->exist = 0; /* TODO exist maybe not needed */
device_destroy(device->dev->class, MKDEV(roccat_major, minor));
+ mutex_lock(&devices_lock);
+ devices[minor] = NULL;
+ mutex_unlock(&devices_lock);
+
if (device->open) {
hid_hw_close(device->hid);
wake_up_interruptible(&device->wait);
@@ -373,6 +375,34 @@ void roccat_disconnect(int minor)
}
EXPORT_SYMBOL_GPL(roccat_disconnect);
+static long roccat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct roccat_device *device;
+ unsigned int minor = iminor(inode);
+ long retval = 0;
+
+ mutex_lock(&devices_lock);
+
+ device = devices[minor];
+ if (!device) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
+ case ROCCATIOCGREPSIZE:
+ if (put_user(device->report_size, (int __user *)arg))
+ retval = -EFAULT;
+ break;
+ default:
+ retval = -ENOTTY;
+ }
+out:
+ mutex_unlock(&devices_lock);
+ return retval;
+}
+
static const struct file_operations roccat_ops = {
.owner = THIS_MODULE,
.read = roccat_read,
@@ -380,6 +410,7 @@ static const struct file_operations roccat_ops = {
.open = roccat_open,
.release = roccat_release,
.llseek = noop_llseek,
+ .unlocked_ioctl = roccat_ioctl,
};
static int __init roccat_init(void)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 68d7b36e31e4..93819a08121a 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -46,6 +46,16 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+/*
+ * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
+ * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
+ * so we need to override that forcing HID Output Reports on the Control EP.
+ *
+ * There is also another issue about HID Output Reports via USB, the Sixaxis
+ * does not want the report_id as part of the data packet, so we have to
+ * discard buf[0] when sending the actual control message, even for numbered
+ * reports, humpf!
+ */
static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type)
{
@@ -55,6 +65,12 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
int report_id = buf[0];
int ret;
+ if (report_type == HID_OUTPUT_REPORT) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ }
+
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
@@ -62,6 +78,10 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
+ /* Count also the Report ID, in case of an Output report. */
+ if (ret > 0 && report_type == HID_OUTPUT_REPORT)
+ ret++;
+
return ret;
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 468e87b53ed2..54409cba018c 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -91,7 +91,7 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
ret = -EFAULT;
goto out;
}
- ret += len;
+ ret = len;
kfree(list->buffer[list->tail].value);
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -102,15 +102,14 @@ out:
}
/* the first byte is expected to be a report number */
-static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+/* This function is to be called with the minors_lock mutex held */
+static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct hid_device *dev;
__u8 *buf;
int ret = 0;
- mutex_lock(&minors_lock);
-
if (!hidraw_table[minor]) {
ret = -ENODEV;
goto out;
@@ -148,14 +147,92 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
goto out_free;
}
- ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
+ ret = dev->hid_output_raw_report(dev, buf, count, report_type);
out_free:
kfree(buf);
out:
+ return ret;
+}
+
+/* the first byte is expected to be a report number */
+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ mutex_lock(&minors_lock);
+ ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
mutex_unlock(&minors_lock);
return ret;
}
+
+/* This function performs a Get_Report transfer over the control endpoint
+ per section 7.2.1 of the HID specification, version 1.1. The first byte
+ of buffer is the report number to request, or 0x0 if the defice does not
+ use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
+ or HID_INPUT_REPORT. This function is to be called with the minors_lock
+ mutex held. */
+static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ struct hid_device *dev;
+ __u8 *buf;
+ int ret = 0, len;
+ unsigned char report_number;
+
+ dev = hidraw_table[minor]->hid;
+
+ if (!dev->hid_get_raw_report) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (count > HID_MAX_BUFFER_SIZE) {
+ printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
+ task_pid_nr(current));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (count < 2) {
+ printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
+ task_pid_nr(current));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Read the first byte from the user. This is the report number,
+ which is passed to dev->hid_get_raw_report(). */
+ if (copy_from_user(&report_number, buffer, 1)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
+
+ if (ret < 0)
+ goto out_free;
+
+ len = (ret < count) ? ret : count;
+
+ if (copy_to_user(buffer, buf, len)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ ret = len;
+
+out_free:
+ kfree(buf);
+out:
+ return ret;
+}
+
static unsigned int hidraw_poll(struct file *file, poll_table *wait)
{
struct hidraw_list *list = file->private_data;
@@ -295,7 +372,24 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
default:
{
struct hid_device *hid = dev->hid;
- if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) {
+ if (_IOC_TYPE(cmd) != 'H') {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
+ int len = _IOC_SIZE(cmd);
+ ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
+ break;
+ }
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
+ int len = _IOC_SIZE(cmd);
+ ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
+ break;
+ }
+
+ /* Begin Read-only ioctls. */
+ if (_IOC_DIR(cmd) != _IOC_READ) {
ret = -EINVAL;
break;
}
@@ -327,7 +421,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
-EFAULT : len;
break;
}
- }
+ }
ret = -ENOTTY;
}
@@ -428,12 +522,12 @@ void hidraw_disconnect(struct hid_device *hid)
hidraw->exist = 0;
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
mutex_lock(&minors_lock);
hidraw_table[hidraw->minor] = NULL;
mutex_unlock(&minors_lock);
- device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-
if (hidraw->open) {
hid_hw_close(hid);
wake_up_interruptible(&hidraw->wait);
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b336dd84036f..38c261a40c74 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -799,6 +799,40 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
+static int usbhid_get_raw_report(struct hid_device *hid,
+ unsigned char report_number, __u8 *buf, size_t count,
+ unsigned char report_type)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = usbhid->intf;
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int skipped_report_id = 0;
+ int ret;
+
+ /* Byte 0 is the report number. Report data starts at byte 1.*/
+ buf[0] = report_number;
+ if (report_number == 0x0) {
+ /* Offset the return buffer by 1, so that the report ID
+ will remain in byte 0. */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((report_type + 1) << 8) | report_number,
+ interface->desc.bInterfaceNumber, buf, count,
+ USB_CTRL_SET_TIMEOUT);
+
+ /* count also the report id */
+ if (ret > 0 && skipped_report_id)
+ ret++;
+
+ return ret;
+}
+
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type)
{
@@ -1139,6 +1173,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
+ hid->hid_get_raw_report = usbhid_get_raw_report;
hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 297bc9a7d6e6..1bfb4439e4e1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -467,6 +467,17 @@ config SENSORS_JC42
This driver can also be built as a module. If so, the module
will be called jc42.
+config SENSORS_LINEAGE
+ tristate "Lineage Compact Power Line Power Entry Module"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Lineage Compact Power Line
+ series of DC/DC and AC/DC converters such as CP1800, CP2000AC,
+ CP2000DC, CP2725, and others.
+
+ This driver can also be built as a module. If so, the module
+ will be called lineage-pem.
+
config SENSORS_LM63
tristate "National Semiconductor LM63 and LM64"
depends on I2C
@@ -625,6 +636,17 @@ config SENSORS_LM93
This driver can also be built as a module. If so, the module
will be called lm93.
+config SENSORS_LTC4151
+ tristate "Linear Technology LTC4151"
+ depends on I2C
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4151
+ High Voltage I2C Current and Voltage Monitor interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4151.
+
config SENSORS_LTC4215
tristate "Linear Technology LTC4215"
depends on I2C && EXPERIMENTAL
@@ -685,6 +707,16 @@ config SENSORS_MAX1619
This driver can also be built as a module. If so, the module
will be called max1619.
+config SENSORS_MAX6639
+ tristate "Maxim MAX6639 sensor chip"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the MAX6639
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6639.
+
config SENSORS_MAX6650
tristate "Maxim MAX6650 sensor chip"
depends on I2C && EXPERIMENTAL
@@ -735,6 +767,61 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config PMBUS
+ tristate "PMBus support"
+ depends on I2C && EXPERIMENTAL
+ default n
+ help
+ Say yes here if you want to enable PMBus support.
+
+ This driver can also be built as a module. If so, the module will
+ be called pmbus_core.
+
+if PMBUS
+
+config SENSORS_PMBUS
+ tristate "Generic PMBus devices"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for generic
+ PMBus devices, including but not limited to BMR450, BMR451, BMR453,
+ BMR454, and LTC2978.
+
+ This driver can also be built as a module. If so, the module will
+ be called pmbus.
+
+config SENSORS_MAX16064
+ tristate "Maxim MAX16064"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Maxim
+ MAX16064.
+
+ This driver can also be built as a module. If so, the module will
+ be called max16064.
+
+config SENSORS_MAX34440
+ tristate "Maxim MAX34440/MAX34441"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Maxim
+ MAX34440 and MAX34441.
+
+ This driver can also be built as a module. If so, the module will
+ be called max34440.
+
+config SENSORS_MAX8688
+ tristate "Maxim MAX8688"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Maxim
+ MAX8688.
+
+ This driver can also be built as a module. If so, the module will
+ be called max8688.
+
+endif # PMBUS
+
config SENSORS_SHT15
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
depends on GENERIC_GPIO
@@ -1083,7 +1170,7 @@ config SENSORS_W83627HF
will be called w83627hf.
config SENSORS_W83627EHF
- tristate "Winbond W83627EHF/EHG/DHG, W83667HG"
+ tristate "Winbond W83627EHF/EHG/DHG, W83667HG, NCT6775F, NCT6776F"
select HWMON_VID
help
If you say yes here you get support for the hardware
@@ -1094,7 +1181,8 @@ config SENSORS_W83627EHF
chip suited for specific Intel processors that use PECI such as
the Core 2 Duo.
- This driver also supports the W83667HG chip.
+ This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F
+ (also known as W83667HG-I), and NCT6776F.
This driver can also be built as a module. If so, the module
will be called w83627ehf.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index dde02d99c238..bd0410e4b44f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
+obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o
obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o
@@ -79,11 +80,13 @@ obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
+obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
+obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
@@ -112,6 +115,13 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
+# PMBus drivers
+obj-$(CONFIG_PMBUS) += pmbus_core.o
+obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
+obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
+obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
+obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
+
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 6e06019015a5..a4d430ee7e20 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
- * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> *
+ * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
* *
* 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 *
@@ -47,22 +47,23 @@
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
+#define SIO_F71808E_ID 0x0901 /* Chipset ID */
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
+#define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
+#define SIO_F71889E_ID 0x0909 /* Chipset ID */
#define SIO_F8000_ID 0x0581 /* Chipset ID */
#define REGION_LENGTH 8
#define ADDR_REG_OFFSET 5
#define DATA_REG_OFFSET 6
-#define F71882FG_REG_PECI 0x0A
-
-#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
-#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
+#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
+#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
#define F71882FG_REG_IN(nr) (0x20 + (nr))
-#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
+#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
@@ -86,28 +87,71 @@
#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
+#define F71882FG_REG_FAN_FAULT_T 0x9F
+#define F71882FG_FAN_NEG_TEMP_EN 0x20
+#define F71882FG_FAN_PROG_SEL 0x80
+
#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
#define F71882FG_REG_START 0x01
+#define F71882FG_MAX_INS 9
+
#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
+enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
+ f71889ed, f8000 };
static const char *f71882fg_names[] = {
+ "f71808e",
"f71858fg",
"f71862fg",
+ "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
"f71882fg",
"f71889fg",
+ "f71889ed",
"f8000",
};
+static const char f71882fg_has_in[8][F71882FG_MAX_INS] = {
+ { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* f71808e */
+ { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71869 */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889ed */
+ { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */
+};
+
+static const char f71882fg_has_in1_alarm[8] = {
+ 0, /* f71808e */
+ 0, /* f71858fg */
+ 0, /* f71862fg */
+ 0, /* f71869 */
+ 1, /* f71882fg */
+ 1, /* f71889fg */
+ 1, /* f71889ed */
+ 0, /* f8000 */
+};
+
+static const char f71882fg_has_beep[8] = {
+ 0, /* f71808e */
+ 0, /* f71858fg */
+ 1, /* f71862fg */
+ 1, /* f71869 */
+ 1, /* f71882fg */
+ 1, /* f71889fg */
+ 1, /* f71889ed */
+ 0, /* f8000 */
+};
+
static struct platform_device *f71882fg_pdev;
/* Super-I/O Function prototypes */
@@ -129,11 +173,12 @@ struct f71882fg_data {
struct mutex update_lock;
int temp_start; /* temp numbering start (0 or 1) */
char valid; /* !=0 if following fields are valid */
+ char auto_point_temp_signed;
unsigned long last_updated; /* In jiffies */
unsigned long last_limits; /* In jiffies */
/* Register Values */
- u8 in[9];
+ u8 in[F71882FG_MAX_INS];
u8 in1_max;
u8 in_status;
u8 in_beep;
@@ -142,7 +187,7 @@ struct f71882fg_data {
u16 fan_full_speed[4];
u8 fan_status;
u8 fan_beep;
- /* Note: all models have only 3 temperature channels, but on some
+ /* Note: all models have max 3 temperature channels, but on some
they are addressed as 0-2 and on others as 1-3, so for coding
convenience we reserve space for 4 channels */
u16 temp[4];
@@ -262,13 +307,9 @@ static struct platform_driver f71882fg_driver = {
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-/* Temp and in attr for the f71858fg, the f71858fg is special as it
- has its temperature indexes start at 0 (the others start at 1) and
- it only has 3 voltage inputs */
-static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+/* Temp attr for the f71858fg, the f71858fg is special as it has its
+ temperature indexes start at 0 (the others start at 1) */
+static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
store_temp_max, 0, 0),
@@ -292,7 +333,6 @@ static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
0, 1),
SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
- SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
@@ -308,17 +348,8 @@ static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
};
-/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
-static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
- SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
- SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
- SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
- SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
- SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
- SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
+/* Temp attr for the standard models */
+static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
store_temp_max, 0, 1),
@@ -328,17 +359,14 @@ static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
the max and crit alarms separately and lm_sensors v2 depends on the
presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
- SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 1),
SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
store_temp_crit, 0, 1),
SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
0, 1),
SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
- SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 5),
SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+}, {
SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
store_temp_max, 0, 2),
@@ -346,17 +374,14 @@ static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
store_temp_max_hyst, 0, 2),
/* Should be temp2_max_alarm, see temp1_alarm note */
SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
- SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 2),
SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
store_temp_crit, 0, 2),
SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
0, 2),
SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
- SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 6),
SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+}, {
SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
store_temp_max, 0, 3),
@@ -364,37 +389,39 @@ static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
store_temp_max_hyst, 0, 3),
/* Should be temp3_max_alarm, see temp1_alarm note */
SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
- SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 3),
SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
store_temp_crit, 0, 3),
SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
0, 3),
SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
- SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0, 7),
SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
-};
+} };
-/* For models with in1 alarm capability */
-static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
- SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
- 0, 1),
- SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
- 0, 1),
- SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
-};
+/* Temp attr for models which can beep on temp alarm */
+static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
+ SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 1),
+ SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 5),
+}, {
+ SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 2),
+ SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 6),
+}, {
+ SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 3),
+ SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 7),
+} };
-/* Temp and in attr for the f8000
+/* Temp attr for the f8000
Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
is used as hysteresis value to clear alarms
Also like the f71858fg its temperature indexes start at 0
*/
-static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
- SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
- SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
- SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+static struct sensor_device_attribute_2 f8000_temp_attr[] = {
SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
store_temp_crit, 0, 0),
@@ -408,7 +435,6 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
store_temp_max, 0, 1),
SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
- SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
@@ -419,6 +445,28 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
};
+/* in attr for all models */
+static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
+ SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+ SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+ SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+ SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
+ SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
+ SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
+ SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
+ SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
+ SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
+};
+
+/* For models with in1 alarm capability */
+static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
+ SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
+ 0, 1),
+ SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
+ 0, 1),
+ SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
+};
+
/* Fan / PWM attr common to all models */
static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
@@ -479,7 +527,7 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
};
/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
- f71858fg / f71882fg / f71889fg */
+ standard models */
static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
@@ -548,7 +596,87 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
show_pwm_auto_point_temp_hyst, NULL, 3, 2),
};
-/* PWM attr common to the f71858fg, f71882fg and f71889fg */
+/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
+ pwm setting when the temperature is above the pwmX_auto_point1_temp can be
+ programmed instead of being hardcoded to 0xff */
+static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
+ SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 0),
+ SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+
+ SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+
+ SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 2),
+ SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+};
+
+/* PWM attr for the standard models */
static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
show_pwm_auto_point_channel,
@@ -943,16 +1071,16 @@ static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
static struct f71882fg_data *f71882fg_update_device(struct device *dev)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr, reg = 0, reg2;
+ int nr, reg, point;
int nr_fans = (data->type == f71882fg) ? 4 : 3;
- int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
+ int nr_temps = (data->type == f71808e) ? 2 : 3;
mutex_lock(&data->update_lock);
/* Update once every 60 seconds */
if (time_after(jiffies, data->last_limits + 60 * HZ) ||
!data->valid) {
- if (data->type == f71882fg || data->type == f71889fg) {
+ if (f71882fg_has_in1_alarm[data->type]) {
data->in1_max =
f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
data->in_beep =
@@ -960,7 +1088,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
}
/* Get High & boundary temps*/
- for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
+ for (nr = data->temp_start; nr < nr_temps + data->temp_start;
+ nr++) {
data->temp_ovt[nr] = f71882fg_read8(data,
F71882FG_REG_TEMP_OVT(nr));
data->temp_high[nr] = f71882fg_read8(data,
@@ -973,44 +1102,19 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
data->temp_hyst[1] = f71882fg_read8(data,
F71882FG_REG_TEMP_HYST(1));
}
+ /* All but the f71858fg / f8000 have this register */
+ if ((data->type != f71858fg) && (data->type != f8000)) {
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+ data->temp_type[1] = (reg & 0x02) ? 2 : 4;
+ data->temp_type[2] = (reg & 0x04) ? 2 : 4;
+ data->temp_type[3] = (reg & 0x08) ? 2 : 4;
+ }
- if (data->type == f71862fg || data->type == f71882fg ||
- data->type == f71889fg) {
+ if (f71882fg_has_beep[data->type]) {
data->fan_beep = f71882fg_read8(data,
F71882FG_REG_FAN_BEEP);
data->temp_beep = f71882fg_read8(data,
F71882FG_REG_TEMP_BEEP);
- /* Have to hardcode type, because temp1 is special */
- reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
- data->temp_type[2] = (reg & 0x04) ? 2 : 4;
- data->temp_type[3] = (reg & 0x08) ? 2 : 4;
- }
- /* Determine temp index 1 sensor type */
- if (data->type == f71889fg) {
- reg2 = f71882fg_read8(data, F71882FG_REG_START);
- switch ((reg2 & 0x60) >> 5) {
- case 0x00: /* BJT / Thermistor */
- data->temp_type[1] = (reg & 0x02) ? 2 : 4;
- break;
- case 0x01: /* AMDSI */
- data->temp_type[1] = 5;
- break;
- case 0x02: /* PECI */
- case 0x03: /* Ibex Peak ?? Report as PECI for now */
- data->temp_type[1] = 6;
- break;
- }
- } else {
- reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
- if ((reg2 & 0x03) == 0x01)
- data->temp_type[1] = 6; /* PECI */
- else if ((reg2 & 0x03) == 0x02)
- data->temp_type[1] = 5; /* AMDSI */
- else if (data->type == f71862fg ||
- data->type == f71882fg)
- data->temp_type[1] = (reg & 0x02) ? 2 : 4;
- else /* f71858fg and f8000 only support BJT */
- data->temp_type[1] = 2;
}
data->pwm_enable = f71882fg_read8(data,
@@ -1025,8 +1129,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
f71882fg_read8(data,
F71882FG_REG_POINT_MAPPING(nr));
- if (data->type != f71862fg) {
- int point;
+ switch (data->type) {
+ default:
for (point = 0; point < 5; point++) {
data->pwm_auto_point_pwm[nr][point] =
f71882fg_read8(data,
@@ -1039,7 +1143,14 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
F71882FG_REG_POINT_TEMP
(nr, point));
}
- } else {
+ break;
+ case f71808e:
+ case f71869:
+ data->pwm_auto_point_pwm[nr][0] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_PWM(nr, 0));
+ /* Fall through */
+ case f71862fg:
data->pwm_auto_point_pwm[nr][1] =
f71882fg_read8(data,
F71882FG_REG_POINT_PWM
@@ -1056,6 +1167,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
f71882fg_read8(data,
F71882FG_REG_POINT_TEMP
(nr, 3));
+ break;
}
}
data->last_limits = jiffies;
@@ -1067,7 +1179,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
F71882FG_REG_TEMP_STATUS);
data->temp_diode_open = f71882fg_read8(data,
F71882FG_REG_TEMP_DIODE_OPEN);
- for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
+ for (nr = data->temp_start; nr < nr_temps + data->temp_start;
+ nr++)
data->temp[nr] = f71882fg_read_temp(data, nr);
data->fan_status = f71882fg_read8(data,
@@ -1083,17 +1196,18 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
data->pwm[nr] =
f71882fg_read8(data, F71882FG_REG_PWM(nr));
}
-
/* The f8000 can monitor 1 more fan, but has no pwm for it */
if (data->type == f8000)
data->fan[3] = f71882fg_read16(data,
F71882FG_REG_FAN(3));
- if (data->type == f71882fg || data->type == f71889fg)
+
+ if (f71882fg_has_in1_alarm[data->type])
data->in_status = f71882fg_read8(data,
F71882FG_REG_IN_STATUS);
- for (nr = 0; nr < nr_ins; nr++)
- data->in[nr] = f71882fg_read8(data,
- F71882FG_REG_IN(nr));
+ for (nr = 0; nr < F71882FG_MAX_INS; nr++)
+ if (f71882fg_has_in[data->type][nr])
+ data->in[nr] = f71882fg_read8(data,
+ F71882FG_REG_IN(nr));
data->last_updated = jiffies;
data->valid = 1;
@@ -1882,7 +1996,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev,
val /= 1000;
- if (data->type == f71889fg)
+ if (data->auto_point_temp_signed)
val = SENSORS_LIMIT(val, -128, 127);
else
val = SENSORS_LIMIT(val, 0, 127);
@@ -1929,7 +2043,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
struct f71882fg_data *data;
struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
- u8 start_reg;
+ int nr_temps = (sio_data->type == f71808e) ? 2 : 3;
+ u8 start_reg, reg;
data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
if (!data)
@@ -1968,37 +2083,72 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
/* The f71858fg temperature alarms behave as
the f8000 alarms in this mode */
err = f71882fg_create_sysfs_files(pdev,
- f8000_in_temp_attr,
- ARRAY_SIZE(f8000_in_temp_attr));
+ f8000_temp_attr,
+ ARRAY_SIZE(f8000_temp_attr));
else
err = f71882fg_create_sysfs_files(pdev,
- f71858fg_in_temp_attr,
- ARRAY_SIZE(f71858fg_in_temp_attr));
- break;
- case f71882fg:
- case f71889fg:
- err = f71882fg_create_sysfs_files(pdev,
- fxxxx_in1_alarm_attr,
- ARRAY_SIZE(fxxxx_in1_alarm_attr));
- if (err)
- goto exit_unregister_sysfs;
- /* fall through! */
- case f71862fg:
- err = f71882fg_create_sysfs_files(pdev,
- fxxxx_in_temp_attr,
- ARRAY_SIZE(fxxxx_in_temp_attr));
+ f71858fg_temp_attr,
+ ARRAY_SIZE(f71858fg_temp_attr));
break;
case f8000:
err = f71882fg_create_sysfs_files(pdev,
- f8000_in_temp_attr,
- ARRAY_SIZE(f8000_in_temp_attr));
+ f8000_temp_attr,
+ ARRAY_SIZE(f8000_temp_attr));
break;
+ default:
+ err = f71882fg_create_sysfs_files(pdev,
+ &fxxxx_temp_attr[0][0],
+ ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
}
if (err)
goto exit_unregister_sysfs;
+
+ if (f71882fg_has_beep[data->type]) {
+ err = f71882fg_create_sysfs_files(pdev,
+ &fxxxx_temp_beep_attr[0][0],
+ ARRAY_SIZE(fxxxx_temp_beep_attr[0])
+ * nr_temps);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+
+ for (i = 0; i < F71882FG_MAX_INS; i++) {
+ if (f71882fg_has_in[data->type][i]) {
+ err = device_create_file(&pdev->dev,
+ &fxxxx_in_attr[i].dev_attr);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+ }
+ if (f71882fg_has_in1_alarm[data->type]) {
+ err = f71882fg_create_sysfs_files(pdev,
+ fxxxx_in1_alarm_attr,
+ ARRAY_SIZE(fxxxx_in1_alarm_attr));
+ if (err)
+ goto exit_unregister_sysfs;
+ }
}
if (start_reg & 0x02) {
+ switch (data->type) {
+ case f71808e:
+ case f71869:
+ /* These always have signed auto point temps */
+ data->auto_point_temp_signed = 1;
+ /* Fall through to select correct fan/pwm reg bank! */
+ case f71889fg:
+ case f71889ed:
+ reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
+ if (reg & F71882FG_FAN_NEG_TEMP_EN)
+ data->auto_point_temp_signed = 1;
+ /* Ensure banked pwm registers point to right bank */
+ reg &= ~F71882FG_FAN_PROG_SEL;
+ f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
+ break;
+ default:
+ break;
+ }
+
data->pwm_enable =
f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
@@ -2013,8 +2163,11 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
case f71862fg:
err = (data->pwm_enable & 0x15) != 0x15;
break;
+ case f71808e:
+ case f71869:
case f71882fg:
case f71889fg:
+ case f71889ed:
err = 0;
break;
case f8000:
@@ -2034,8 +2187,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (err)
goto exit_unregister_sysfs;
- if (data->type == f71862fg || data->type == f71882fg ||
- data->type == f71889fg) {
+ if (f71882fg_has_beep[data->type]) {
err = f71882fg_create_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);
if (err)
@@ -2043,11 +2195,42 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
}
switch (data->type) {
+ case f71808e:
+ case f71869:
+ case f71889fg:
+ case f71889ed:
+ for (i = 0; i < nr_fans; i++) {
+ data->pwm_auto_point_mapping[i] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_MAPPING(i));
+ if ((data->pwm_auto_point_mapping[i] & 0x80) ||
+ (data->pwm_auto_point_mapping[i] & 3) == 0)
+ break;
+ }
+ if (i != nr_fans) {
+ dev_warn(&pdev->dev,
+ "Auto pwm controlled by raw digital "
+ "data, disabling pwm auto_point "
+ "sysfs attributes\n");
+ goto no_pwm_auto_point;
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (data->type) {
case f71862fg:
err = f71882fg_create_sysfs_files(pdev,
f71862fg_auto_pwm_attr,
ARRAY_SIZE(f71862fg_auto_pwm_attr));
break;
+ case f71808e:
+ case f71869:
+ err = f71882fg_create_sysfs_files(pdev,
+ f71869_auto_pwm_attr,
+ ARRAY_SIZE(f71869_auto_pwm_attr));
+ break;
case f8000:
err = f71882fg_create_sysfs_files(pdev,
f8000_fan_attr,
@@ -2058,23 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
f8000_auto_pwm_attr,
ARRAY_SIZE(f8000_auto_pwm_attr));
break;
- case f71889fg:
- for (i = 0; i < nr_fans; i++) {
- data->pwm_auto_point_mapping[i] =
- f71882fg_read8(data,
- F71882FG_REG_POINT_MAPPING(i));
- if (data->pwm_auto_point_mapping[i] & 0x80)
- break;
- }
- if (i != nr_fans) {
- dev_warn(&pdev->dev,
- "Auto pwm controlled by raw digital "
- "data, disabling pwm auto_point "
- "sysfs attributes\n");
- break;
- }
- /* fall through */
- default: /* f71858fg / f71882fg */
+ default:
err = f71882fg_create_sysfs_files(pdev,
&fxxxx_auto_pwm_attr[0][0],
ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
@@ -2082,6 +2249,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (err)
goto exit_unregister_sysfs;
+no_pwm_auto_point:
for (i = 0; i < nr_fans; i++)
dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
(data->pwm_enable & (1 << 2 * i)) ?
@@ -2108,7 +2276,8 @@ exit_free:
static int f71882fg_remove(struct platform_device *pdev)
{
struct f71882fg_data *data = platform_get_drvdata(pdev);
- int nr_fans = (data->type == f71882fg) ? 4 : 3;
+ int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
+ int nr_temps = (data->type == f71808e) ? 2 : 3;
u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
if (data->hwmon_dev)
@@ -2121,29 +2290,39 @@ static int f71882fg_remove(struct platform_device *pdev)
case f71858fg:
if (data->temp_config & 0x10)
f71882fg_remove_sysfs_files(pdev,
- f8000_in_temp_attr,
- ARRAY_SIZE(f8000_in_temp_attr));
+ f8000_temp_attr,
+ ARRAY_SIZE(f8000_temp_attr));
else
f71882fg_remove_sysfs_files(pdev,
- f71858fg_in_temp_attr,
- ARRAY_SIZE(f71858fg_in_temp_attr));
- break;
- case f71882fg:
- case f71889fg:
- f71882fg_remove_sysfs_files(pdev,
- fxxxx_in1_alarm_attr,
- ARRAY_SIZE(fxxxx_in1_alarm_attr));
- /* fall through! */
- case f71862fg:
- f71882fg_remove_sysfs_files(pdev,
- fxxxx_in_temp_attr,
- ARRAY_SIZE(fxxxx_in_temp_attr));
+ f71858fg_temp_attr,
+ ARRAY_SIZE(f71858fg_temp_attr));
break;
case f8000:
f71882fg_remove_sysfs_files(pdev,
- f8000_in_temp_attr,
- ARRAY_SIZE(f8000_in_temp_attr));
+ f8000_temp_attr,
+ ARRAY_SIZE(f8000_temp_attr));
break;
+ default:
+ f71882fg_remove_sysfs_files(pdev,
+ &fxxxx_temp_attr[0][0],
+ ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
+ }
+ if (f71882fg_has_beep[data->type]) {
+ f71882fg_remove_sysfs_files(pdev,
+ &fxxxx_temp_beep_attr[0][0],
+ ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
+ }
+
+ for (i = 0; i < F71882FG_MAX_INS; i++) {
+ if (f71882fg_has_in[data->type][i]) {
+ device_remove_file(&pdev->dev,
+ &fxxxx_in_attr[i].dev_attr);
+ }
+ }
+ if (f71882fg_has_in1_alarm[data->type]) {
+ f71882fg_remove_sysfs_files(pdev,
+ fxxxx_in1_alarm_attr,
+ ARRAY_SIZE(fxxxx_in1_alarm_attr));
}
}
@@ -2151,10 +2330,10 @@ static int f71882fg_remove(struct platform_device *pdev)
f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
- if (data->type == f71862fg || data->type == f71882fg ||
- data->type == f71889fg)
+ if (f71882fg_has_beep[data->type]) {
f71882fg_remove_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);
+ }
switch (data->type) {
case f71862fg:
@@ -2162,6 +2341,12 @@ static int f71882fg_remove(struct platform_device *pdev)
f71862fg_auto_pwm_attr,
ARRAY_SIZE(f71862fg_auto_pwm_attr));
break;
+ case f71808e:
+ case f71869:
+ f71882fg_remove_sysfs_files(pdev,
+ f71869_auto_pwm_attr,
+ ARRAY_SIZE(f71869_auto_pwm_attr));
+ break;
case f8000:
f71882fg_remove_sysfs_files(pdev,
f8000_fan_attr,
@@ -2170,7 +2355,7 @@ static int f71882fg_remove(struct platform_device *pdev)
f8000_auto_pwm_attr,
ARRAY_SIZE(f8000_auto_pwm_attr));
break;
- default: /* f71858fg / f71882fg / f71889fg */
+ default:
f71882fg_remove_sysfs_files(pdev,
&fxxxx_auto_pwm_attr[0][0],
ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
@@ -2200,18 +2385,27 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
switch (devid) {
+ case SIO_F71808E_ID:
+ sio_data->type = f71808e;
+ break;
case SIO_F71858_ID:
sio_data->type = f71858fg;
break;
case SIO_F71862_ID:
sio_data->type = f71862fg;
break;
+ case SIO_F71869_ID:
+ sio_data->type = f71869;
+ break;
case SIO_F71882_ID:
sio_data->type = f71882fg;
break;
case SIO_F71889_ID:
sio_data->type = f71889fg;
break;
+ case SIO_F71889E_ID:
+ sio_data->type = f71889ed;
+ break;
case SIO_F8000_ID:
sio_data->type = f8000;
break;
diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c
new file mode 100644
index 000000000000..58eded27f385
--- /dev/null
+++ b/drivers/hwmon/lineage-pem.c
@@ -0,0 +1,586 @@
+/*
+ * Driver for Lineage Compact Power Line series of power entry modules.
+ *
+ * Copyright (C) 2010, 2011 Ericsson AB.
+ *
+ * Documentation:
+ * http://www.lineagepower.com/oem/pdf/CPLI2C.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/*
+ * This driver supports various Lineage Compact Power Line DC/DC and AC/DC
+ * converters such as CP1800, CP2000AC, CP2000DC, CP2100DC, and others.
+ *
+ * The devices are nominally PMBus compliant. However, most standard PMBus
+ * commands are not supported. Specifically, all hardware monitoring and
+ * status reporting commands are non-standard. For this reason, a standard
+ * PMBus driver can not be used.
+ *
+ * All Lineage CPL devices have a built-in I2C bus master selector (PCA9541).
+ * To ensure device access, this driver should only be used as client driver
+ * to the pca9541 I2C master selector driver.
+ */
+
+/* Command codes */
+#define PEM_OPERATION 0x01
+#define PEM_CLEAR_INFO_FLAGS 0x03
+#define PEM_VOUT_COMMAND 0x21
+#define PEM_VOUT_OV_FAULT_LIMIT 0x40
+#define PEM_READ_DATA_STRING 0xd0
+#define PEM_READ_INPUT_STRING 0xdc
+#define PEM_READ_FIRMWARE_REV 0xdd
+#define PEM_READ_RUN_TIMER 0xde
+#define PEM_FAN_HI_SPEED 0xdf
+#define PEM_FAN_NORMAL_SPEED 0xe0
+#define PEM_READ_FAN_SPEED 0xe1
+
+/* offsets in data string */
+#define PEM_DATA_STATUS_2 0
+#define PEM_DATA_STATUS_1 1
+#define PEM_DATA_ALARM_2 2
+#define PEM_DATA_ALARM_1 3
+#define PEM_DATA_VOUT_LSB 4
+#define PEM_DATA_VOUT_MSB 5
+#define PEM_DATA_CURRENT 6
+#define PEM_DATA_TEMP 7
+
+/* Virtual entries, to report constants */
+#define PEM_DATA_TEMP_MAX 10
+#define PEM_DATA_TEMP_CRIT 11
+
+/* offsets in input string */
+#define PEM_INPUT_VOLTAGE 0
+#define PEM_INPUT_POWER_LSB 1
+#define PEM_INPUT_POWER_MSB 2
+
+/* offsets in fan data */
+#define PEM_FAN_ADJUSTMENT 0
+#define PEM_FAN_FAN1 1
+#define PEM_FAN_FAN2 2
+#define PEM_FAN_FAN3 3
+
+/* Status register bits */
+#define STS1_OUTPUT_ON (1 << 0)
+#define STS1_LEDS_FLASHING (1 << 1)
+#define STS1_EXT_FAULT (1 << 2)
+#define STS1_SERVICE_LED_ON (1 << 3)
+#define STS1_SHUTDOWN_OCCURRED (1 << 4)
+#define STS1_INT_FAULT (1 << 5)
+#define STS1_ISOLATION_TEST_OK (1 << 6)
+
+#define STS2_ENABLE_PIN_HI (1 << 0)
+#define STS2_DATA_OUT_RANGE (1 << 1)
+#define STS2_RESTARTED_OK (1 << 1)
+#define STS2_ISOLATION_TEST_FAIL (1 << 3)
+#define STS2_HIGH_POWER_CAP (1 << 4)
+#define STS2_INVALID_INSTR (1 << 5)
+#define STS2_WILL_RESTART (1 << 6)
+#define STS2_PEC_ERR (1 << 7)
+
+/* Alarm register bits */
+#define ALRM1_VIN_OUT_LIMIT (1 << 0)
+#define ALRM1_VOUT_OUT_LIMIT (1 << 1)
+#define ALRM1_OV_VOLT_SHUTDOWN (1 << 2)
+#define ALRM1_VIN_OVERCURRENT (1 << 3)
+#define ALRM1_TEMP_WARNING (1 << 4)
+#define ALRM1_TEMP_SHUTDOWN (1 << 5)
+#define ALRM1_PRIMARY_FAULT (1 << 6)
+#define ALRM1_POWER_LIMIT (1 << 7)
+
+#define ALRM2_5V_OUT_LIMIT (1 << 1)
+#define ALRM2_TEMP_FAULT (1 << 2)
+#define ALRM2_OV_LOW (1 << 3)
+#define ALRM2_DCDC_TEMP_HIGH (1 << 4)
+#define ALRM2_PRI_TEMP_HIGH (1 << 5)
+#define ALRM2_NO_PRIMARY (1 << 6)
+#define ALRM2_FAN_FAULT (1 << 7)
+
+#define FIRMWARE_REV_LEN 4
+#define DATA_STRING_LEN 9
+#define INPUT_STRING_LEN 5 /* 4 for most devices */
+#define FAN_SPEED_LEN 5
+
+struct pem_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ bool fans_supported;
+ int input_length;
+ unsigned long last_updated; /* in jiffies */
+
+ u8 firmware_rev[FIRMWARE_REV_LEN];
+ u8 data_string[DATA_STRING_LEN];
+ u8 input_string[INPUT_STRING_LEN];
+ u8 fan_speed[FAN_SPEED_LEN];
+};
+
+static int pem_read_block(struct i2c_client *client, u8 command, u8 *data,
+ int data_len)
+{
+ u8 block_buffer[I2C_SMBUS_BLOCK_MAX];
+ int result;
+
+ result = i2c_smbus_read_block_data(client, command, block_buffer);
+ if (unlikely(result < 0))
+ goto abort;
+ if (unlikely(result == 0xff || result != data_len)) {
+ result = -EIO;
+ goto abort;
+ }
+ memcpy(data, block_buffer, data_len);
+ result = 0;
+abort:
+ return result;
+}
+
+static struct pem_data *pem_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pem_data *data = i2c_get_clientdata(client);
+ struct pem_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ int result;
+
+ /* Read data string */
+ result = pem_read_block(client, PEM_READ_DATA_STRING,
+ data->data_string,
+ sizeof(data->data_string));
+ if (unlikely(result < 0)) {
+ ret = ERR_PTR(result);
+ goto abort;
+ }
+
+ /* Read input string */
+ if (data->input_length) {
+ result = pem_read_block(client, PEM_READ_INPUT_STRING,
+ data->input_string,
+ data->input_length);
+ if (unlikely(result < 0)) {
+ ret = ERR_PTR(result);
+ goto abort;
+ }
+ }
+
+ /* Read fan speeds */
+ if (data->fans_supported) {
+ result = pem_read_block(client, PEM_READ_FAN_SPEED,
+ data->fan_speed,
+ sizeof(data->fan_speed));
+ if (unlikely(result < 0)) {
+ ret = ERR_PTR(result);
+ goto abort;
+ }
+ }
+
+ i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static long pem_get_data(u8 *data, int len, int index)
+{
+ long val;
+
+ switch (index) {
+ case PEM_DATA_VOUT_LSB:
+ val = (data[index] + (data[index+1] << 8)) * 5 / 2;
+ break;
+ case PEM_DATA_CURRENT:
+ val = data[index] * 200;
+ break;
+ case PEM_DATA_TEMP:
+ val = data[index] * 1000;
+ break;
+ case PEM_DATA_TEMP_MAX:
+ val = 97 * 1000; /* 97 degrees C per datasheet */
+ break;
+ case PEM_DATA_TEMP_CRIT:
+ val = 107 * 1000; /* 107 degrees C per datasheet */
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ val = 0;
+ }
+ return val;
+}
+
+static long pem_get_input(u8 *data, int len, int index)
+{
+ long val;
+
+ switch (index) {
+ case PEM_INPUT_VOLTAGE:
+ if (len == INPUT_STRING_LEN)
+ val = (data[index] + (data[index+1] << 8) - 75) * 1000;
+ else
+ val = (data[index] - 75) * 1000;
+ break;
+ case PEM_INPUT_POWER_LSB:
+ if (len == INPUT_STRING_LEN)
+ index++;
+ val = (data[index] + (data[index+1] << 8)) * 1000000L;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ val = 0;
+ }
+ return val;
+}
+
+static long pem_get_fan(u8 *data, int len, int index)
+{
+ long val;
+
+ switch (index) {
+ case PEM_FAN_FAN1:
+ case PEM_FAN_FAN2:
+ case PEM_FAN_FAN3:
+ val = data[index] * 100;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ val = 0;
+ }
+ return val;
+}
+
+/*
+ * Show boolean, either a fault or an alarm.
+ * .nr points to the register, .index is the bit mask to check
+ */
+static ssize_t pem_show_bool(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+ struct pem_data *data = pem_update_device(dev);
+ u8 status;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = data->data_string[attr->nr] & attr->index;
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!status);
+}
+
+static ssize_t pem_show_data(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pem_data *data = pem_update_device(dev);
+ long value;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ value = pem_get_data(data->data_string, sizeof(data->data_string),
+ attr->index);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+static ssize_t pem_show_input(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pem_data *data = pem_update_device(dev);
+ long value;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ value = pem_get_input(data->input_string, sizeof(data->input_string),
+ attr->index);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+static ssize_t pem_show_fan(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pem_data *data = pem_update_device(dev);
+ long value;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ value = pem_get_fan(data->fan_speed, sizeof(data->fan_speed),
+ attr->index);
+
+ return snprintf(buf, PAGE_SIZE, "%ld\n", value);
+}
+
+/* Voltages */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, pem_show_data, NULL,
+ PEM_DATA_VOUT_LSB);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_VOUT_OUT_LIMIT);
+static SENSOR_DEVICE_ATTR_2(in1_crit_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_OV_VOLT_SHUTDOWN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, pem_show_input, NULL,
+ PEM_INPUT_VOLTAGE);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1,
+ ALRM1_VIN_OUT_LIMIT | ALRM1_PRIMARY_FAULT);
+
+/* Currents */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, pem_show_data, NULL,
+ PEM_DATA_CURRENT);
+static SENSOR_DEVICE_ATTR_2(curr1_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_VIN_OVERCURRENT);
+
+/* Power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, pem_show_input, NULL,
+ PEM_INPUT_POWER_LSB);
+static SENSOR_DEVICE_ATTR_2(power1_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_POWER_LIMIT);
+
+/* Fans */
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, pem_show_fan, NULL,
+ PEM_FAN_FAN1);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, pem_show_fan, NULL,
+ PEM_FAN_FAN2);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, pem_show_fan, NULL,
+ PEM_FAN_FAN3);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_2, ALRM2_FAN_FAULT);
+
+/* Temperatures */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, pem_show_data, NULL,
+ PEM_DATA_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, pem_show_data, NULL,
+ PEM_DATA_TEMP_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, pem_show_data, NULL,
+ PEM_DATA_TEMP_CRIT);
+static SENSOR_DEVICE_ATTR_2(temp1_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_TEMP_WARNING);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_1, ALRM1_TEMP_SHUTDOWN);
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, pem_show_bool, NULL,
+ PEM_DATA_ALARM_2, ALRM2_TEMP_FAULT);
+
+static struct attribute *pem_attributes[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_power1_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+
+ NULL,
+};
+
+static const struct attribute_group pem_group = {
+ .attrs = pem_attributes,
+};
+
+static struct attribute *pem_input_attributes[] = {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+};
+
+static const struct attribute_group pem_input_group = {
+ .attrs = pem_input_attributes,
+};
+
+static struct attribute *pem_fan_attributes[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+};
+
+static const struct attribute_group pem_fan_group = {
+ .attrs = pem_fan_attributes,
+};
+
+static int pem_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct pem_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_DATA
+ | I2C_FUNC_SMBUS_WRITE_BYTE))
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /*
+ * We use the next two commands to determine if the device is really
+ * there.
+ */
+ ret = pem_read_block(client, PEM_READ_FIRMWARE_REV,
+ data->firmware_rev, sizeof(data->firmware_rev));
+ if (ret < 0)
+ goto out_kfree;
+
+ ret = i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
+ if (ret < 0)
+ goto out_kfree;
+
+ dev_info(&client->dev, "Firmware revision %d.%d.%d\n",
+ data->firmware_rev[0], data->firmware_rev[1],
+ data->firmware_rev[2]);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &pem_group);
+ if (ret)
+ goto out_kfree;
+
+ /*
+ * Check if input readings are supported.
+ * This is the case if we can read input data,
+ * and if the returned data is not all zeros.
+ * Note that input alarms are always supported.
+ */
+ ret = pem_read_block(client, PEM_READ_INPUT_STRING,
+ data->input_string,
+ sizeof(data->input_string) - 1);
+ if (!ret && (data->input_string[0] || data->input_string[1] ||
+ data->input_string[2]))
+ data->input_length = sizeof(data->input_string) - 1;
+ else if (ret < 0) {
+ /* Input string is one byte longer for some devices */
+ ret = pem_read_block(client, PEM_READ_INPUT_STRING,
+ data->input_string,
+ sizeof(data->input_string));
+ if (!ret && (data->input_string[0] || data->input_string[1] ||
+ data->input_string[2] || data->input_string[3]))
+ data->input_length = sizeof(data->input_string);
+ }
+ ret = 0;
+ if (data->input_length) {
+ ret = sysfs_create_group(&client->dev.kobj, &pem_input_group);
+ if (ret)
+ goto out_remove_groups;
+ }
+
+ /*
+ * Check if fan speed readings are supported.
+ * This is the case if we can read fan speed data,
+ * and if the returned data is not all zeros.
+ * Note that the fan alarm is always supported.
+ */
+ ret = pem_read_block(client, PEM_READ_FAN_SPEED,
+ data->fan_speed,
+ sizeof(data->fan_speed));
+ if (!ret && (data->fan_speed[0] || data->fan_speed[1] ||
+ data->fan_speed[2] || data->fan_speed[3])) {
+ data->fans_supported = true;
+ ret = sysfs_create_group(&client->dev.kobj, &pem_fan_group);
+ if (ret)
+ goto out_remove_groups;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_remove_groups;
+ }
+
+ return 0;
+
+out_remove_groups:
+ sysfs_remove_group(&client->dev.kobj, &pem_input_group);
+ sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pem_group);
+out_kfree:
+ kfree(data);
+ return ret;
+}
+
+static int pem_remove(struct i2c_client *client)
+{
+ struct pem_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+
+ sysfs_remove_group(&client->dev.kobj, &pem_input_group);
+ sysfs_remove_group(&client->dev.kobj, &pem_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pem_group);
+
+ kfree(data);
+ return 0;
+}
+
+static const struct i2c_device_id pem_id[] = {
+ {"lineage_pem", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pem_id);
+
+static struct i2c_driver pem_driver = {
+ .driver = {
+ .name = "lineage_pem",
+ },
+ .probe = pem_probe,
+ .remove = pem_remove,
+ .id_table = pem_id,
+};
+
+static int __init pem_init(void)
+{
+ return i2c_add_driver(&pem_driver);
+}
+
+static void __exit pem_exit(void)
+{
+ i2c_del_driver(&pem_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("Lineage CPL PEM hardware monitoring driver");
+MODULE_LICENSE("GPL");
+
+module_init(pem_init);
+module_exit(pem_exit);
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
index 2549de1de4e2..c1f8a8fbf694 100644
--- a/drivers/hwmon/lis3lv02d_spi.c
+++ b/drivers/hwmon/lis3lv02d_spi.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
+#include <linux/pm.h>
#include "lis3lv02d.h"
@@ -88,9 +89,10 @@ static int __devexit lis302dl_spi_remove(struct spi_device *spi)
return lis3lv02d_remove_fs(&lis3_dev);
}
-#ifdef CONFIG_PM
-static int lis3lv02d_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int lis3lv02d_spi_suspend(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct lis3lv02d *lis3 = spi_get_drvdata(spi);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -99,8 +101,9 @@ static int lis3lv02d_spi_suspend(struct spi_device *spi, pm_message_t mesg)
return 0;
}
-static int lis3lv02d_spi_resume(struct spi_device *spi)
+static int lis3lv02d_spi_resume(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct lis3lv02d *lis3 = spi_get_drvdata(spi);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -108,21 +111,19 @@ static int lis3lv02d_spi_resume(struct spi_device *spi)
return 0;
}
-
-#else
-#define lis3lv02d_spi_suspend NULL
-#define lis3lv02d_spi_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend,
+ lis3lv02d_spi_resume);
+
static struct spi_driver lis302dl_spi_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &lis3lv02d_spi_pm,
},
.probe = lis302dl_spi_probe,
.remove = __devexit_p(lis302dl_spi_remove),
- .suspend = lis3lv02d_spi_suspend,
- .resume = lis3lv02d_spi_resume,
};
static int __init lis302dl_init(void)
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index d2cc28660816..cf47e6e476ed 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
enum chips {
any_chip, lm85b, lm85c,
adm1027, adt7463, adt7468,
- emc6d100, emc6d102, emc6d103
+ emc6d100, emc6d102, emc6d103, emc6d103s
};
/* The LM85 registers */
@@ -283,10 +283,6 @@ struct lm85_zone {
u8 hyst; /* Low limit hysteresis. (0-15) */
u8 range; /* Temp range, encoded */
s8 critical; /* "All fans ON" temp limit */
- u8 off_desired; /* Actual "off" temperature specified. Preserved
- * to prevent "drift" as other autofan control
- * values change.
- */
u8 max_desired; /* Actual "max" temperature specified. Preserved
* to prevent "drift" as other autofan control
* values change.
@@ -306,6 +302,8 @@ struct lm85_data {
const int *freq_map;
enum chips type;
+ bool has_vid5; /* true if VID5 is configured for ADT7463 or ADT7468 */
+
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
unsigned long last_reading; /* In jiffies */
@@ -352,6 +350,7 @@ static const struct i2c_device_id lm85_id[] = {
{ "emc6d101", emc6d100 },
{ "emc6d102", emc6d102 },
{ "emc6d103", emc6d103 },
+ { "emc6d103s", emc6d103s },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm85_id);
@@ -420,8 +419,7 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr,
struct lm85_data *data = lm85_update_device(dev);
int vid;
- if ((data->type == adt7463 || data->type == adt7468) &&
- (data->vid & 0x80)) {
+ if (data->has_vid5) {
/* 6-pin VID (VRM 10) */
vid = vid_from_reg(data->vid & 0x3f, data->vrm);
} else {
@@ -891,7 +889,6 @@ static ssize_t set_temp_auto_temp_off(struct device *dev,
mutex_lock(&data->update_lock);
min = TEMP_FROM_REG(data->zone[nr].limit);
- data->zone[nr].off_desired = TEMP_TO_REG(val);
data->zone[nr].hyst = HYST_TO_REG(min - val);
if (nr == 0 || nr == 1) {
lm85_write_value(client, LM85_REG_AFAN_HYST1,
@@ -934,18 +931,6 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
((data->zone[nr].range & 0x0f) << 4)
| (data->pwm_freq[nr] & 0x07));
-/* Update temp_auto_hyst and temp_auto_off */
- data->zone[nr].hyst = HYST_TO_REG(TEMP_FROM_REG(
- data->zone[nr].limit) - TEMP_FROM_REG(
- data->zone[nr].off_desired));
- if (nr == 0 || nr == 1) {
- lm85_write_value(client, LM85_REG_AFAN_HYST1,
- (data->zone[0].hyst << 4)
- | data->zone[1].hyst);
- } else {
- lm85_write_value(client, LM85_REG_AFAN_HYST2,
- (data->zone[2].hyst << 4));
- }
mutex_unlock(&data->update_lock);
return count;
}
@@ -1084,13 +1069,7 @@ static struct attribute *lm85_attributes[] = {
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
- &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
- &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
- &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
- &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
- &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
- &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
&sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
&sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
&sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
@@ -1111,6 +1090,26 @@ static const struct attribute_group lm85_group = {
.attrs = lm85_attributes,
};
+static struct attribute *lm85_attributes_minctl[] = {
+ &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+};
+
+static const struct attribute_group lm85_group_minctl = {
+ .attrs = lm85_attributes_minctl,
+};
+
+static struct attribute *lm85_attributes_temp_off[] = {
+ &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+};
+
+static const struct attribute_group lm85_group_temp_off = {
+ .attrs = lm85_attributes_temp_off,
+};
+
static struct attribute *lm85_attributes_in4[] = {
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
@@ -1258,16 +1257,9 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
case LM85_VERSTEP_EMC6D103_A1:
type_name = "emc6d103";
break;
- /*
- * Registers apparently missing in EMC6D103S/EMC6D103:A2
- * compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102
- * (according to the data sheets), but used unconditionally
- * in the driver: 62[5:7], 6D[0:7], and 6E[0:7].
- * So skip EMC6D103S for now.
case LM85_VERSTEP_EMC6D103S:
type_name = "emc6d103s";
break;
- */
}
} else {
dev_dbg(&adapter->dev,
@@ -1280,6 +1272,19 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
return 0;
}
+static void lm85_remove_files(struct i2c_client *client, struct lm85_data *data)
+{
+ sysfs_remove_group(&client->dev.kobj, &lm85_group);
+ if (data->type != emc6d103s) {
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_minctl);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_temp_off);
+ }
+ if (!data->has_vid5)
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
+ if (data->type == emc6d100)
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
+}
+
static int lm85_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1302,6 +1307,7 @@ static int lm85_probe(struct i2c_client *client,
case emc6d100:
case emc6d102:
case emc6d103:
+ case emc6d103s:
data->freq_map = adm1027_freq_map;
break;
default:
@@ -1319,11 +1325,26 @@ static int lm85_probe(struct i2c_client *client,
if (err)
goto err_kfree;
+ /* minctl and temp_off exist on all chips except emc6d103s */
+ if (data->type != emc6d103s) {
+ err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl);
+ if (err)
+ goto err_kfree;
+ err = sysfs_create_group(&client->dev.kobj,
+ &lm85_group_temp_off);
+ if (err)
+ goto err_kfree;
+ }
+
/* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
as a sixth digital VID input rather than an analog input. */
- data->vid = lm85_read_value(client, LM85_REG_VID);
- if (!((data->type == adt7463 || data->type == adt7468) &&
- (data->vid & 0x80)))
+ if (data->type == adt7463 || data->type == adt7468) {
+ u8 vid = lm85_read_value(client, LM85_REG_VID);
+ if (vid & 0x80)
+ data->has_vid5 = true;
+ }
+
+ if (!data->has_vid5)
if ((err = sysfs_create_group(&client->dev.kobj,
&lm85_group_in4)))
goto err_remove_files;
@@ -1344,10 +1365,7 @@ static int lm85_probe(struct i2c_client *client,
/* Error out and cleanup code */
err_remove_files:
- sysfs_remove_group(&client->dev.kobj, &lm85_group);
- sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
- if (data->type == emc6d100)
- sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
+ lm85_remove_files(client, data);
err_kfree:
kfree(data);
return err;
@@ -1357,10 +1375,7 @@ static int lm85_remove(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &lm85_group);
- sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
- if (data->type == emc6d100)
- sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
+ lm85_remove_files(client, data);
kfree(data);
return 0;
}
@@ -1457,11 +1472,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
lm85_read_value(client, LM85_REG_FAN(i));
}
- if (!((data->type == adt7463 || data->type == adt7468) &&
- (data->vid & 0x80))) {
- data->in[4] = lm85_read_value(client,
- LM85_REG_IN(4));
- }
+ if (!data->has_vid5)
+ data->in[4] = lm85_read_value(client, LM85_REG_IN(4));
if (data->type == adt7468)
data->cfg5 = lm85_read_value(client, ADT7468_REG_CFG5);
@@ -1487,7 +1499,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
/* More alarm bits */
data->alarms |= lm85_read_value(client,
EMC6D100_REG_ALARM3) << 16;
- } else if (data->type == emc6d102 || data->type == emc6d103) {
+ } else if (data->type == emc6d102 || data->type == emc6d103 ||
+ data->type == emc6d103s) {
/* Have to read LSB bits after the MSB ones because
the reading of the MSB bits has frozen the
LSBs (backward from the ADM1027).
@@ -1528,8 +1541,7 @@ static struct lm85_data *lm85_update_device(struct device *dev)
lm85_read_value(client, LM85_REG_FAN_MIN(i));
}
- if (!((data->type == adt7463 || data->type == adt7468) &&
- (data->vid & 0x80))) {
+ if (!data->has_vid5) {
data->in_min[4] = lm85_read_value(client,
LM85_REG_IN_MIN(4));
data->in_max[4] = lm85_read_value(client,
@@ -1573,17 +1585,19 @@ static struct lm85_data *lm85_update_device(struct device *dev)
}
}
- i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
- data->autofan[0].min_off = (i & 0x20) != 0;
- data->autofan[1].min_off = (i & 0x40) != 0;
- data->autofan[2].min_off = (i & 0x80) != 0;
+ if (data->type != emc6d103s) {
+ i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
+ data->autofan[0].min_off = (i & 0x20) != 0;
+ data->autofan[1].min_off = (i & 0x40) != 0;
+ data->autofan[2].min_off = (i & 0x80) != 0;
- i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
- data->zone[0].hyst = i >> 4;
- data->zone[1].hyst = i & 0x0f;
+ i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
+ data->zone[0].hyst = i >> 4;
+ data->zone[1].hyst = i & 0x0f;
- i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
- data->zone[2].hyst = i >> 4;
+ i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
+ data->zone[2].hyst = i >> 4;
+ }
data->last_config = jiffies;
} /* last_config */
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
new file mode 100644
index 000000000000..4ac06b75aa60
--- /dev/null
+++ b/drivers/hwmon/ltc4151.c
@@ -0,0 +1,256 @@
+/*
+ * Driver for Linear Technology LTC4151 High Voltage I2C Current
+ * and Voltage Monitor
+ *
+ * Copyright (C) 2011 AppearTV AS
+ *
+ * Derived from:
+ *
+ * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot
+ * Swap Controller
+ * Copyright (C) 2010 Ericsson AB.
+ *
+ * Datasheet: http://www.linear.com/docs/Datasheet/4151fc.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/* chip registers */
+#define LTC4151_SENSE_H 0x00
+#define LTC4151_SENSE_L 0x01
+#define LTC4151_VIN_H 0x02
+#define LTC4151_VIN_L 0x03
+#define LTC4151_ADIN_H 0x04
+#define LTC4151_ADIN_L 0x05
+
+struct ltc4151_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ /* Registers */
+ u8 regs[6];
+};
+
+static struct ltc4151_data *ltc4151_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc4151_data *data = i2c_get_clientdata(client);
+ struct ltc4151_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ /*
+ * The chip's A/D updates 6 times per second
+ * (Conversion Rate 6 - 9 Hz)
+ */
+ if (time_after(jiffies, data->last_updated + HZ / 6) || !data->valid) {
+ int i;
+
+ dev_dbg(&client->dev, "Starting ltc4151 update\n");
+
+ /* Read all registers */
+ for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, i);
+ if (unlikely(val < 0)) {
+ dev_dbg(dev,
+ "Failed to read ADC value: error %d\n",
+ val);
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->regs[i] = val;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+/* Return the voltage from the given register in mV */
+static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)
+{
+ u32 val;
+
+ val = (data->regs[reg] << 4) + (data->regs[reg + 1] >> 4);
+
+ switch (reg) {
+ case LTC4151_ADIN_H:
+ /* 500uV resolution. Convert to mV. */
+ val = val * 500 / 1000;
+ break;
+ case LTC4151_SENSE_H:
+ /*
+ * 20uV resolution. Convert to current as measured with
+ * an 1 mOhm sense resistor, in mA.
+ */
+ val = val * 20;
+ break;
+ case LTC4151_VIN_H:
+ /* 25 mV per increment */
+ val = val * 25;
+ break;
+ default:
+ /* If we get here, the developer messed up */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static ssize_t ltc4151_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ltc4151_data *data = ltc4151_update_device(dev);
+ int value;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ value = ltc4151_get_value(data, attr->index);
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/*
+ * Input voltages.
+ */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
+ ltc4151_show_value, NULL, LTC4151_VIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
+ ltc4151_show_value, NULL, LTC4151_ADIN_H);
+
+/* Currents (via sense resistor) */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
+ ltc4151_show_value, NULL, LTC4151_SENSE_H);
+
+/* Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4151_attributes[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+
+ NULL,
+};
+
+static const struct attribute_group ltc4151_group = {
+ .attrs = ltc4151_attributes,
+};
+
+static int ltc4151_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct ltc4151_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out_kzalloc;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &ltc4151_group);
+ if (ret)
+ goto out_sysfs_create_group;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_hwmon_device_register;
+ }
+
+ return 0;
+
+out_hwmon_device_register:
+ sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
+out_sysfs_create_group:
+ kfree(data);
+out_kzalloc:
+ return ret;
+}
+
+static int ltc4151_remove(struct i2c_client *client)
+{
+ struct ltc4151_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
+
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id ltc4151_id[] = {
+ { "ltc4151", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4151_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4151_driver = {
+ .driver = {
+ .name = "ltc4151",
+ },
+ .probe = ltc4151_probe,
+ .remove = ltc4151_remove,
+ .id_table = ltc4151_id,
+};
+
+static int __init ltc4151_init(void)
+{
+ return i2c_add_driver(&ltc4151_driver);
+}
+
+static void __exit ltc4151_exit(void)
+{
+ i2c_del_driver(&ltc4151_driver);
+}
+
+MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
+MODULE_DESCRIPTION("LTC4151 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4151_init);
+module_exit(ltc4151_exit);
diff --git a/drivers/hwmon/max16064.c b/drivers/hwmon/max16064.c
new file mode 100644
index 000000000000..1d6d717060d3
--- /dev/null
+++ b/drivers/hwmon/max16064.c
@@ -0,0 +1,91 @@
+/*
+ * Hardware monitoring driver for Maxim MAX16064
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+static struct pmbus_driver_info max16064_info = {
+ .pages = 4,
+ .direct[PSC_VOLTAGE_IN] = true,
+ .direct[PSC_VOLTAGE_OUT] = true,
+ .direct[PSC_TEMPERATURE] = true,
+ .m[PSC_VOLTAGE_IN] = 19995,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = -1,
+ .m[PSC_VOLTAGE_OUT] = 19995,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -1,
+ .m[PSC_TEMPERATURE] = -7612,
+ .b[PSC_TEMPERATURE] = 335,
+ .R[PSC_TEMPERATURE] = -3,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP,
+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+ .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+};
+
+static int max16064_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &max16064_info);
+}
+
+static int max16064_remove(struct i2c_client *client)
+{
+ return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max16064_id[] = {
+ {"max16064", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max16064_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max16064_driver = {
+ .driver = {
+ .name = "max16064",
+ },
+ .probe = max16064_probe,
+ .remove = max16064_remove,
+ .id_table = max16064_id,
+};
+
+static int __init max16064_init(void)
+{
+ return i2c_add_driver(&max16064_driver);
+}
+
+static void __exit max16064_exit(void)
+{
+ i2c_del_driver(&max16064_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
+MODULE_LICENSE("GPL");
+module_init(max16064_init);
+module_exit(max16064_exit);
diff --git a/drivers/hwmon/max34440.c b/drivers/hwmon/max34440.c
new file mode 100644
index 000000000000..992b701b4c5e
--- /dev/null
+++ b/drivers/hwmon/max34440.c
@@ -0,0 +1,199 @@
+/*
+ * Hardware monitoring driver for Maxim MAX34440/MAX34441
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { max34440, max34441 };
+
+#define MAX34440_STATUS_OC_WARN (1 << 0)
+#define MAX34440_STATUS_OC_FAULT (1 << 1)
+#define MAX34440_STATUS_OT_FAULT (1 << 5)
+#define MAX34440_STATUS_OT_WARN (1 << 6)
+
+static int max34440_get_status(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+ int mfg_status;
+
+ ret = pmbus_set_page(client, page);
+ if (ret < 0)
+ return ret;
+
+ switch (reg) {
+ case PMBUS_STATUS_IOUT:
+ mfg_status = pmbus_read_word_data(client, 0,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfg_status < 0)
+ return mfg_status;
+ if (mfg_status & MAX34440_STATUS_OC_WARN)
+ ret |= PB_IOUT_OC_WARNING;
+ if (mfg_status & MAX34440_STATUS_OC_FAULT)
+ ret |= PB_IOUT_OC_FAULT;
+ break;
+ case PMBUS_STATUS_TEMPERATURE:
+ mfg_status = pmbus_read_word_data(client, 0,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (mfg_status < 0)
+ return mfg_status;
+ if (mfg_status & MAX34440_STATUS_OT_WARN)
+ ret |= PB_TEMP_OT_WARNING;
+ if (mfg_status & MAX34440_STATUS_OT_FAULT)
+ ret |= PB_TEMP_OT_FAULT;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static struct pmbus_driver_info max34440_info[] = {
+ [max34440] = {
+ .pages = 14,
+ .direct[PSC_VOLTAGE_IN] = true,
+ .direct[PSC_VOLTAGE_OUT] = true,
+ .direct[PSC_TEMPERATURE] = true,
+ .direct[PSC_CURRENT_OUT] = true,
+ .m[PSC_VOLTAGE_IN] = 1,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3, /* R = 0 in datasheet reflects mV */
+ .m[PSC_CURRENT_OUT] = 1,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = 3, /* R = 0 in datasheet reflects mA */
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 2,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .get_status = max34440_get_status,
+ },
+ [max34441] = {
+ .pages = 12,
+ .direct[PSC_VOLTAGE_IN] = true,
+ .direct[PSC_VOLTAGE_OUT] = true,
+ .direct[PSC_TEMPERATURE] = true,
+ .direct[PSC_CURRENT_OUT] = true,
+ .direct[PSC_FAN] = true,
+ .m[PSC_VOLTAGE_IN] = 1,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = 3,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_CURRENT_OUT] = 1,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = 3,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 2,
+ .m[PSC_FAN] = 1,
+ .b[PSC_FAN] = 0,
+ .R[PSC_FAN] = 0,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+ .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
+ .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .get_status = max34440_get_status,
+ },
+};
+
+static int max34440_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &max34440_info[id->driver_data]);
+}
+
+static int max34440_remove(struct i2c_client *client)
+{
+ return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max34440_id[] = {
+ {"max34440", max34440},
+ {"max34441", max34441},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max34440_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max34440_driver = {
+ .driver = {
+ .name = "max34440",
+ },
+ .probe = max34440_probe,
+ .remove = max34440_remove,
+ .id_table = max34440_id,
+};
+
+static int __init max34440_init(void)
+{
+ return i2c_add_driver(&max34440_driver);
+}
+
+static void __exit max34440_exit(void)
+{
+ i2c_del_driver(&max34440_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
+MODULE_LICENSE("GPL");
+module_init(max34440_init);
+module_exit(max34440_exit);
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
new file mode 100644
index 000000000000..f20d9978ee78
--- /dev/null
+++ b/drivers/hwmon/max6639.c
@@ -0,0 +1,653 @@
+/*
+ * max6639.c - Support for Maxim MAX6639
+ *
+ * 2-Channel Temperature Monitor with Dual PWM Fan-Speed Controller
+ *
+ * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * based on the initial MAX6639 support from semptian.net
+ * by He Changqing <hechangqing@semptian.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/i2c/max6639.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
+
+/* The MAX6639 registers, valid channel numbers: 0, 1 */
+#define MAX6639_REG_TEMP(ch) (0x00 + (ch))
+#define MAX6639_REG_STATUS 0x02
+#define MAX6639_REG_OUTPUT_MASK 0x03
+#define MAX6639_REG_GCONFIG 0x04
+#define MAX6639_REG_TEMP_EXT(ch) (0x05 + (ch))
+#define MAX6639_REG_ALERT_LIMIT(ch) (0x08 + (ch))
+#define MAX6639_REG_OT_LIMIT(ch) (0x0A + (ch))
+#define MAX6639_REG_THERM_LIMIT(ch) (0x0C + (ch))
+#define MAX6639_REG_FAN_CONFIG1(ch) (0x10 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG2a(ch) (0x11 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG2b(ch) (0x12 + (ch) * 4)
+#define MAX6639_REG_FAN_CONFIG3(ch) (0x13 + (ch) * 4)
+#define MAX6639_REG_FAN_CNT(ch) (0x20 + (ch))
+#define MAX6639_REG_TARGET_CNT(ch) (0x22 + (ch))
+#define MAX6639_REG_FAN_PPR(ch) (0x24 + (ch))
+#define MAX6639_REG_TARGTDUTY(ch) (0x26 + (ch))
+#define MAX6639_REG_FAN_START_TEMP(ch) (0x28 + (ch))
+#define MAX6639_REG_DEVID 0x3D
+#define MAX6639_REG_MANUID 0x3E
+#define MAX6639_REG_DEVREV 0x3F
+
+/* Register bits */
+#define MAX6639_GCONFIG_STANDBY 0x80
+#define MAX6639_GCONFIG_POR 0x40
+#define MAX6639_GCONFIG_DISABLE_TIMEOUT 0x20
+#define MAX6639_GCONFIG_CH2_LOCAL 0x10
+#define MAX6639_GCONFIG_PWM_FREQ_HI 0x08
+
+#define MAX6639_FAN_CONFIG1_PWM 0x80
+
+#define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED 0x40
+
+static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
+
+#define FAN_FROM_REG(val, div, rpm_range) ((val) == 0 ? -1 : \
+ (val) == 255 ? 0 : (rpm_ranges[rpm_range] * 30) / ((div + 1) * (val)))
+#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) / 1000, 0, 255)
+
+/*
+ * Client data (each client gets its own)
+ */
+struct max6639_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values sampled regularly */
+ u16 temp[2]; /* Temperature, in 1/8 C, 0..255 C */
+ bool temp_fault[2]; /* Detected temperature diode failure */
+ u8 fan[2]; /* Register value: TACH count for fans >=30 */
+ u8 status; /* Detected channel alarms and fan failures */
+
+ /* Register values only written to */
+ u8 pwm[2]; /* Register value: Duty cycle 0..120 */
+ u8 temp_therm[2]; /* THERM Temperature, 0..255 C (->_max) */
+ u8 temp_alert[2]; /* ALERT Temperature, 0..255 C (->_crit) */
+ u8 temp_ot[2]; /* OT Temperature, 0..255 C (->_emergency) */
+
+ /* Register values initialized only once */
+ u8 ppr; /* Pulses per rotation 0..3 for 1..4 ppr */
+ u8 rpm_range; /* Index in above rpm_ranges table */
+};
+
+static struct max6639_data *max6639_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct max6639_data *ret = data;
+ int i;
+ int status_reg;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+ int res;
+
+ dev_dbg(&client->dev, "Starting max6639 update\n");
+
+ status_reg = i2c_smbus_read_byte_data(client,
+ MAX6639_REG_STATUS);
+ if (status_reg < 0) {
+ ret = ERR_PTR(status_reg);
+ goto abort;
+ }
+
+ data->status = status_reg;
+
+ for (i = 0; i < 2; i++) {
+ res = i2c_smbus_read_byte_data(client,
+ MAX6639_REG_FAN_CNT(i));
+ if (res < 0) {
+ ret = ERR_PTR(res);
+ goto abort;
+ }
+ data->fan[i] = res;
+
+ res = i2c_smbus_read_byte_data(client,
+ MAX6639_REG_TEMP_EXT(i));
+ if (res < 0) {
+ ret = ERR_PTR(res);
+ goto abort;
+ }
+ data->temp[i] = res >> 5;
+ data->temp_fault[i] = res & 0x01;
+
+ res = i2c_smbus_read_byte_data(client,
+ MAX6639_REG_TEMP(i));
+ if (res < 0) {
+ ret = ERR_PTR(res);
+ goto abort;
+ }
+ data->temp[i] |= res << 3;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static ssize_t show_temp_input(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ long temp;
+ struct max6639_data *data = max6639_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ temp = data->temp[attr->index] * 125;
+ return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct max6639_data *data = max6639_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", data->temp_fault[attr->index]);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *dev_attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ unsigned long val;
+ int res;
+
+ res = strict_strtoul(buf, 10, &val);
+ if (res)
+ return res;
+
+ mutex_lock(&data->update_lock);
+ data->temp_therm[attr->index] = TEMP_LIMIT_TO_REG(val);
+ i2c_smbus_write_byte_data(client,
+ MAX6639_REG_THERM_LIMIT(attr->index),
+ data->temp_therm[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
+}
+
+static ssize_t set_temp_crit(struct device *dev,
+ struct device_attribute *dev_attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ unsigned long val;
+ int res;
+
+ res = strict_strtoul(buf, 10, &val);
+ if (res)
+ return res;
+
+ mutex_lock(&data->update_lock);
+ data->temp_alert[attr->index] = TEMP_LIMIT_TO_REG(val);
+ i2c_smbus_write_byte_data(client,
+ MAX6639_REG_ALERT_LIMIT(attr->index),
+ data->temp_alert[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_temp_emergency(struct device *dev,
+ struct device_attribute *dev_attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
+}
+
+static ssize_t set_temp_emergency(struct device *dev,
+ struct device_attribute *dev_attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ unsigned long val;
+ int res;
+
+ res = strict_strtoul(buf, 10, &val);
+ if (res)
+ return res;
+
+ mutex_lock(&data->update_lock);
+ data->temp_ot[attr->index] = TEMP_LIMIT_TO_REG(val);
+ i2c_smbus_write_byte_data(client,
+ MAX6639_REG_OT_LIMIT(attr->index),
+ data->temp_ot[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
+}
+
+static ssize_t set_pwm(struct device *dev,
+ struct device_attribute *dev_attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+ unsigned long val;
+ int res;
+
+ res = strict_strtoul(buf, 10, &val);
+ if (res)
+ return res;
+
+ val = SENSORS_LIMIT(val, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[attr->index] = (u8)(val * 120 / 255);
+ i2c_smbus_write_byte_data(client,
+ MAX6639_REG_TARGTDUTY(attr->index),
+ data->pwm[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_fan_input(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct max6639_data *data = max6639_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
+ data->ppr, data->rpm_range));
+}
+
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct max6639_data *data = max6639_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", !!(data->status & (1 << attr->index)));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+ set_temp_crit, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
+ set_temp_crit, 1);
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO,
+ show_temp_emergency, set_temp_emergency, 0);
+static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO,
+ show_temp_emergency, set_temp_emergency, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+
+static struct attribute *max6639_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_emergency.dev_attr.attr,
+ &sensor_dev_attr_temp2_emergency.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_fault.dev_attr.attr,
+ &sensor_dev_attr_fan2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max6639_group = {
+ .attrs = max6639_attributes,
+};
+
+/*
+ * returns respective index in rpm_ranges table
+ * 1 by default on invalid range
+ */
+static int rpm_range_to_reg(int range)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rpm_ranges); i++) {
+ if (rpm_ranges[i] == range)
+ return i;
+ }
+
+ return 1; /* default: 4000 RPM */
+}
+
+static int max6639_init_client(struct i2c_client *client)
+{
+ struct max6639_data *data = i2c_get_clientdata(client);
+ struct max6639_platform_data *max6639_info =
+ client->dev.platform_data;
+ int i = 0;
+ int rpm_range = 1; /* default: 4000 RPM */
+ int err = 0;
+
+ /* Reset chip to default values, see below for GCONFIG setup */
+ err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
+ MAX6639_GCONFIG_POR);
+ if (err)
+ goto exit;
+
+ /* Fans pulse per revolution is 2 by default */
+ if (max6639_info && max6639_info->ppr > 0 &&
+ max6639_info->ppr < 5)
+ data->ppr = max6639_info->ppr;
+ else
+ data->ppr = 2;
+ data->ppr -= 1;
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_FAN_PPR(i),
+ data->ppr << 5);
+ if (err)
+ goto exit;
+
+ if (max6639_info)
+ rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
+ data->rpm_range = rpm_range;
+
+ for (i = 0; i < 2; i++) {
+
+ /* Fans config PWM, RPM */
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_FAN_CONFIG1(i),
+ MAX6639_FAN_CONFIG1_PWM | rpm_range);
+ if (err)
+ goto exit;
+
+ /* Fans PWM polarity high by default */
+ if (max6639_info && max6639_info->pwm_polarity == 0)
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_FAN_CONFIG2a(i), 0x00);
+ else
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_FAN_CONFIG2a(i), 0x02);
+ if (err)
+ goto exit;
+
+ /*
+ * /THERM full speed enable,
+ * PWM frequency 25kHz, see also GCONFIG below
+ */
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_FAN_CONFIG3(i),
+ MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
+ if (err)
+ goto exit;
+
+ /* Max. temp. 80C/90C/100C */
+ data->temp_therm[i] = 80;
+ data->temp_alert[i] = 90;
+ data->temp_ot[i] = 100;
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_THERM_LIMIT(i),
+ data->temp_therm[i]);
+ if (err)
+ goto exit;
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_ALERT_LIMIT(i),
+ data->temp_alert[i]);
+ if (err)
+ goto exit;
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_OT_LIMIT(i), data->temp_ot[i]);
+ if (err)
+ goto exit;
+
+ /* PWM 120/120 (i.e. 100%) */
+ data->pwm[i] = 120;
+ err = i2c_smbus_write_byte_data(client,
+ MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
+ if (err)
+ goto exit;
+ }
+ /* Start monitoring */
+ err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
+ MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
+ MAX6639_GCONFIG_PWM_FREQ_HI);
+exit:
+ return err;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6639_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int dev_id, manu_id;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ /* Actual detection via device and manufacturer ID */
+ dev_id = i2c_smbus_read_byte_data(client, MAX6639_REG_DEVID);
+ manu_id = i2c_smbus_read_byte_data(client, MAX6639_REG_MANUID);
+ if (dev_id != 0x58 || manu_id != 0x4D)
+ return -ENODEV;
+
+ strlcpy(info->type, "max6639", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int max6639_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max6639_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct max6639_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the max6639 chip */
+ err = max6639_init_client(client);
+ if (err < 0)
+ goto error_free;
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &max6639_group);
+ if (err)
+ goto error_free;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto error_remove;
+ }
+
+ dev_info(&client->dev, "temperature sensor and fan control found\n");
+
+ return 0;
+
+error_remove:
+ sysfs_remove_group(&client->dev.kobj, &max6639_group);
+error_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max6639_remove(struct i2c_client *client)
+{
+ struct max6639_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &max6639_group);
+
+ kfree(data);
+ return 0;
+}
+
+static int max6639_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+ if (data < 0)
+ return data;
+
+ return i2c_smbus_write_byte_data(client,
+ MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
+}
+
+static int max6639_resume(struct i2c_client *client)
+{
+ int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
+ if (data < 0)
+ return data;
+
+ return i2c_smbus_write_byte_data(client,
+ MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
+}
+
+static const struct i2c_device_id max6639_id[] = {
+ {"max6639", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, max6639_id);
+
+static struct i2c_driver max6639_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "max6639",
+ },
+ .probe = max6639_probe,
+ .remove = max6639_remove,
+ .suspend = max6639_suspend,
+ .resume = max6639_resume,
+ .id_table = max6639_id,
+ .detect = max6639_detect,
+ .address_list = normal_i2c,
+};
+
+static int __init max6639_init(void)
+{
+ return i2c_add_driver(&max6639_driver);
+}
+
+static void __exit max6639_exit(void)
+{
+ i2c_del_driver(&max6639_driver);
+}
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("max6639 driver");
+MODULE_LICENSE("GPL");
+
+module_init(max6639_init);
+module_exit(max6639_exit);
diff --git a/drivers/hwmon/max8688.c b/drivers/hwmon/max8688.c
new file mode 100644
index 000000000000..8ebfef2ecf26
--- /dev/null
+++ b/drivers/hwmon/max8688.c
@@ -0,0 +1,158 @@
+/*
+ * Hardware monitoring driver for Maxim MAX8688
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define MAX8688_MFG_STATUS 0xd8
+
+#define MAX8688_STATUS_OC_FAULT (1 << 4)
+#define MAX8688_STATUS_OV_FAULT (1 << 5)
+#define MAX8688_STATUS_OV_WARNING (1 << 8)
+#define MAX8688_STATUS_UV_FAULT (1 << 9)
+#define MAX8688_STATUS_UV_WARNING (1 << 10)
+#define MAX8688_STATUS_UC_FAULT (1 << 11)
+#define MAX8688_STATUS_OC_WARNING (1 << 12)
+#define MAX8688_STATUS_OT_FAULT (1 << 13)
+#define MAX8688_STATUS_OT_WARNING (1 << 14)
+
+static int max8688_get_status(struct i2c_client *client, int page, int reg)
+{
+ int ret = 0;
+ int mfg_status;
+
+ if (page)
+ return -EINVAL;
+
+ switch (reg) {
+ case PMBUS_STATUS_VOUT:
+ mfg_status = pmbus_read_word_data(client, 0,
+ MAX8688_MFG_STATUS);
+ if (mfg_status < 0)
+ return mfg_status;
+ if (mfg_status & MAX8688_STATUS_UV_WARNING)
+ ret |= PB_VOLTAGE_UV_WARNING;
+ if (mfg_status & MAX8688_STATUS_UV_FAULT)
+ ret |= PB_VOLTAGE_UV_FAULT;
+ if (mfg_status & MAX8688_STATUS_OV_WARNING)
+ ret |= PB_VOLTAGE_OV_WARNING;
+ if (mfg_status & MAX8688_STATUS_OV_FAULT)
+ ret |= PB_VOLTAGE_OV_FAULT;
+ break;
+ case PMBUS_STATUS_IOUT:
+ mfg_status = pmbus_read_word_data(client, 0,
+ MAX8688_MFG_STATUS);
+ if (mfg_status < 0)
+ return mfg_status;
+ if (mfg_status & MAX8688_STATUS_UC_FAULT)
+ ret |= PB_IOUT_UC_FAULT;
+ if (mfg_status & MAX8688_STATUS_OC_WARNING)
+ ret |= PB_IOUT_OC_WARNING;
+ if (mfg_status & MAX8688_STATUS_OC_FAULT)
+ ret |= PB_IOUT_OC_FAULT;
+ break;
+ case PMBUS_STATUS_TEMPERATURE:
+ mfg_status = pmbus_read_word_data(client, 0,
+ MAX8688_MFG_STATUS);
+ if (mfg_status < 0)
+ return mfg_status;
+ if (mfg_status & MAX8688_STATUS_OT_WARNING)
+ ret |= PB_TEMP_OT_WARNING;
+ if (mfg_status & MAX8688_STATUS_OT_FAULT)
+ ret |= PB_TEMP_OT_FAULT;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static struct pmbus_driver_info max8688_info = {
+ .pages = 1,
+ .direct[PSC_VOLTAGE_IN] = true,
+ .direct[PSC_VOLTAGE_OUT] = true,
+ .direct[PSC_TEMPERATURE] = true,
+ .direct[PSC_CURRENT_OUT] = true,
+ .m[PSC_VOLTAGE_IN] = 19995,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = -1,
+ .m[PSC_VOLTAGE_OUT] = 19995,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -1,
+ .m[PSC_CURRENT_OUT] = 23109,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = -2,
+ .m[PSC_TEMPERATURE] = -7612,
+ .b[PSC_TEMPERATURE] = 335,
+ .R[PSC_TEMPERATURE] = -3,
+ .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_STATUS_TEMP,
+ .get_status = max8688_get_status,
+};
+
+static int max8688_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &max8688_info);
+}
+
+static int max8688_remove(struct i2c_client *client)
+{
+ return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max8688_id[] = {
+ {"max8688", 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, max8688_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max8688_driver = {
+ .driver = {
+ .name = "max8688",
+ },
+ .probe = max8688_probe,
+ .remove = max8688_remove,
+ .id_table = max8688_id,
+};
+
+static int __init max8688_init(void)
+{
+ return i2c_add_driver(&max8688_driver);
+}
+
+static void __exit max8688_exit(void)
+{
+ i2c_del_driver(&max8688_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
+MODULE_LICENSE("GPL");
+module_init(max8688_init);
+module_exit(max8688_exit);
diff --git a/drivers/hwmon/pmbus.c b/drivers/hwmon/pmbus.c
new file mode 100644
index 000000000000..98e2e28899e2
--- /dev/null
+++ b/drivers/hwmon/pmbus.c
@@ -0,0 +1,203 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+/*
+ * Find sensor groups and status registers on each page.
+ */
+static void pmbus_find_sensor_groups(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ int page;
+
+ /* Sensors detected on page 0 only */
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN))
+ info->func[0] |= PMBUS_HAVE_VIN;
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_VCAP))
+ info->func[0] |= PMBUS_HAVE_VCAP;
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_IIN))
+ info->func[0] |= PMBUS_HAVE_IIN;
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_PIN))
+ info->func[0] |= PMBUS_HAVE_PIN;
+ if (info->func[0]
+ && pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
+ info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
+ info->func[0] |= PMBUS_HAVE_FAN12;
+ if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
+ info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
+ }
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
+ info->func[0] |= PMBUS_HAVE_FAN34;
+ if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
+ info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
+ }
+ if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) {
+ info->func[0] |= PMBUS_HAVE_TEMP;
+ if (pmbus_check_byte_register(client, 0,
+ PMBUS_STATUS_TEMPERATURE))
+ info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
+ }
+
+ /* Sensors detected on all pages */
+ for (page = 0; page < info->pages; page++) {
+ if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) {
+ info->func[page] |= PMBUS_HAVE_VOUT;
+ if (pmbus_check_byte_register(client, page,
+ PMBUS_STATUS_VOUT))
+ info->func[page] |= PMBUS_HAVE_STATUS_VOUT;
+ }
+ if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) {
+ info->func[page] |= PMBUS_HAVE_IOUT;
+ if (pmbus_check_byte_register(client, 0,
+ PMBUS_STATUS_IOUT))
+ info->func[page] |= PMBUS_HAVE_STATUS_IOUT;
+ }
+ if (pmbus_check_word_register(client, page, PMBUS_READ_POUT))
+ info->func[page] |= PMBUS_HAVE_POUT;
+ }
+}
+
+/*
+ * Identify chip parameters.
+ */
+static int pmbus_identify(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ if (!info->pages) {
+ /*
+ * Check if the PAGE command is supported. If it is,
+ * keep setting the page number until it fails or until the
+ * maximum number of pages has been reached. Assume that
+ * this is the number of pages supported by the chip.
+ */
+ if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
+ int page;
+
+ for (page = 1; page < PMBUS_PAGES; page++) {
+ if (pmbus_set_page(client, page) < 0)
+ break;
+ }
+ pmbus_set_page(client, 0);
+ info->pages = page;
+ } else {
+ info->pages = 1;
+ }
+ }
+
+ /*
+ * We should check if the COEFFICIENTS register is supported.
+ * If it is, and the chip is configured for direct mode, we can read
+ * the coefficients from the chip, one set per group of sensor
+ * registers.
+ *
+ * To do this, we will need access to a chip which actually supports the
+ * COEFFICIENTS command, since the command is too complex to implement
+ * without testing it.
+ */
+
+ /* Try to find sensor groups */
+ pmbus_find_sensor_groups(client, info);
+
+ return 0;
+}
+
+static int pmbus_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pmbus_driver_info *info;
+ int ret;
+
+ info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->pages = id->driver_data;
+ info->identify = pmbus_identify;
+
+ ret = pmbus_do_probe(client, id, info);
+ if (ret < 0)
+ goto out;
+ return 0;
+
+out:
+ kfree(info);
+ return ret;
+}
+
+static int pmbus_remove(struct i2c_client *client)
+{
+ int ret;
+ const struct pmbus_driver_info *info;
+
+ info = pmbus_get_driver_info(client);
+ ret = pmbus_do_remove(client);
+ kfree(info);
+ return ret;
+}
+
+/*
+ * Use driver_data to set the number of pages supported by the chip.
+ */
+static const struct i2c_device_id pmbus_id[] = {
+ {"bmr450", 1},
+ {"bmr451", 1},
+ {"bmr453", 1},
+ {"bmr454", 1},
+ {"ltc2978", 8},
+ {"pmbus", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pmbus_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pmbus_driver = {
+ .driver = {
+ .name = "pmbus",
+ },
+ .probe = pmbus_probe,
+ .remove = pmbus_remove,
+ .id_table = pmbus_id,
+};
+
+static int __init pmbus_init(void)
+{
+ return i2c_add_driver(&pmbus_driver);
+}
+
+static void __exit pmbus_exit(void)
+{
+ i2c_del_driver(&pmbus_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Generic PMBus driver");
+MODULE_LICENSE("GPL");
+module_init(pmbus_init);
+module_exit(pmbus_exit);
diff --git a/drivers/hwmon/pmbus.h b/drivers/hwmon/pmbus.h
new file mode 100644
index 000000000000..a81f7f228762
--- /dev/null
+++ b/drivers/hwmon/pmbus.h
@@ -0,0 +1,313 @@
+/*
+ * pmbus.h - Common defines and structures for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PMBUS_H
+#define PMBUS_H
+
+/*
+ * Registers
+ */
+#define PMBUS_PAGE 0x00
+#define PMBUS_OPERATION 0x01
+#define PMBUS_ON_OFF_CONFIG 0x02
+#define PMBUS_CLEAR_FAULTS 0x03
+#define PMBUS_PHASE 0x04
+
+#define PMBUS_CAPABILITY 0x19
+#define PMBUS_QUERY 0x1A
+
+#define PMBUS_VOUT_MODE 0x20
+#define PMBUS_VOUT_COMMAND 0x21
+#define PMBUS_VOUT_TRIM 0x22
+#define PMBUS_VOUT_CAL_OFFSET 0x23
+#define PMBUS_VOUT_MAX 0x24
+#define PMBUS_VOUT_MARGIN_HIGH 0x25
+#define PMBUS_VOUT_MARGIN_LOW 0x26
+#define PMBUS_VOUT_TRANSITION_RATE 0x27
+#define PMBUS_VOUT_DROOP 0x28
+#define PMBUS_VOUT_SCALE_LOOP 0x29
+#define PMBUS_VOUT_SCALE_MONITOR 0x2A
+
+#define PMBUS_COEFFICIENTS 0x30
+#define PMBUS_POUT_MAX 0x31
+
+#define PMBUS_FAN_CONFIG_12 0x3A
+#define PMBUS_FAN_COMMAND_1 0x3B
+#define PMBUS_FAN_COMMAND_2 0x3C
+#define PMBUS_FAN_CONFIG_34 0x3D
+#define PMBUS_FAN_COMMAND_3 0x3E
+#define PMBUS_FAN_COMMAND_4 0x3F
+
+#define PMBUS_VOUT_OV_FAULT_LIMIT 0x40
+#define PMBUS_VOUT_OV_FAULT_RESPONSE 0x41
+#define PMBUS_VOUT_OV_WARN_LIMIT 0x42
+#define PMBUS_VOUT_UV_WARN_LIMIT 0x43
+#define PMBUS_VOUT_UV_FAULT_LIMIT 0x44
+#define PMBUS_VOUT_UV_FAULT_RESPONSE 0x45
+#define PMBUS_IOUT_OC_FAULT_LIMIT 0x46
+#define PMBUS_IOUT_OC_FAULT_RESPONSE 0x47
+#define PMBUS_IOUT_OC_LV_FAULT_LIMIT 0x48
+#define PMBUS_IOUT_OC_LV_FAULT_RESPONSE 0x49
+#define PMBUS_IOUT_OC_WARN_LIMIT 0x4A
+#define PMBUS_IOUT_UC_FAULT_LIMIT 0x4B
+#define PMBUS_IOUT_UC_FAULT_RESPONSE 0x4C
+
+#define PMBUS_OT_FAULT_LIMIT 0x4F
+#define PMBUS_OT_FAULT_RESPONSE 0x50
+#define PMBUS_OT_WARN_LIMIT 0x51
+#define PMBUS_UT_WARN_LIMIT 0x52
+#define PMBUS_UT_FAULT_LIMIT 0x53
+#define PMBUS_UT_FAULT_RESPONSE 0x54
+#define PMBUS_VIN_OV_FAULT_LIMIT 0x55
+#define PMBUS_VIN_OV_FAULT_RESPONSE 0x56
+#define PMBUS_VIN_OV_WARN_LIMIT 0x57
+#define PMBUS_VIN_UV_WARN_LIMIT 0x58
+#define PMBUS_VIN_UV_FAULT_LIMIT 0x59
+
+#define PMBUS_IIN_OC_FAULT_LIMIT 0x5B
+#define PMBUS_IIN_OC_WARN_LIMIT 0x5D
+
+#define PMBUS_POUT_OP_FAULT_LIMIT 0x68
+#define PMBUS_POUT_OP_WARN_LIMIT 0x6A
+#define PMBUS_PIN_OP_WARN_LIMIT 0x6B
+
+#define PMBUS_STATUS_BYTE 0x78
+#define PMBUS_STATUS_WORD 0x79
+#define PMBUS_STATUS_VOUT 0x7A
+#define PMBUS_STATUS_IOUT 0x7B
+#define PMBUS_STATUS_INPUT 0x7C
+#define PMBUS_STATUS_TEMPERATURE 0x7D
+#define PMBUS_STATUS_CML 0x7E
+#define PMBUS_STATUS_OTHER 0x7F
+#define PMBUS_STATUS_MFR_SPECIFIC 0x80
+#define PMBUS_STATUS_FAN_12 0x81
+#define PMBUS_STATUS_FAN_34 0x82
+
+#define PMBUS_READ_VIN 0x88
+#define PMBUS_READ_IIN 0x89
+#define PMBUS_READ_VCAP 0x8A
+#define PMBUS_READ_VOUT 0x8B
+#define PMBUS_READ_IOUT 0x8C
+#define PMBUS_READ_TEMPERATURE_1 0x8D
+#define PMBUS_READ_TEMPERATURE_2 0x8E
+#define PMBUS_READ_TEMPERATURE_3 0x8F
+#define PMBUS_READ_FAN_SPEED_1 0x90
+#define PMBUS_READ_FAN_SPEED_2 0x91
+#define PMBUS_READ_FAN_SPEED_3 0x92
+#define PMBUS_READ_FAN_SPEED_4 0x93
+#define PMBUS_READ_DUTY_CYCLE 0x94
+#define PMBUS_READ_FREQUENCY 0x95
+#define PMBUS_READ_POUT 0x96
+#define PMBUS_READ_PIN 0x97
+
+#define PMBUS_REVISION 0x98
+#define PMBUS_MFR_ID 0x99
+#define PMBUS_MFR_MODEL 0x9A
+#define PMBUS_MFR_REVISION 0x9B
+#define PMBUS_MFR_LOCATION 0x9C
+#define PMBUS_MFR_DATE 0x9D
+#define PMBUS_MFR_SERIAL 0x9E
+
+/*
+ * CAPABILITY
+ */
+#define PB_CAPABILITY_SMBALERT (1<<4)
+#define PB_CAPABILITY_ERROR_CHECK (1<<7)
+
+/*
+ * VOUT_MODE
+ */
+#define PB_VOUT_MODE_MODE_MASK 0xe0
+#define PB_VOUT_MODE_PARAM_MASK 0x1f
+
+#define PB_VOUT_MODE_LINEAR 0x00
+#define PB_VOUT_MODE_VID 0x20
+#define PB_VOUT_MODE_DIRECT 0x40
+
+/*
+ * Fan configuration
+ */
+#define PB_FAN_2_PULSE_MASK ((1 << 0) | (1 << 1))
+#define PB_FAN_2_RPM (1 << 2)
+#define PB_FAN_2_INSTALLED (1 << 3)
+#define PB_FAN_1_PULSE_MASK ((1 << 4) | (1 << 5))
+#define PB_FAN_1_RPM (1 << 6)
+#define PB_FAN_1_INSTALLED (1 << 7)
+
+/*
+ * STATUS_BYTE, STATUS_WORD (lower)
+ */
+#define PB_STATUS_NONE_ABOVE (1<<0)
+#define PB_STATUS_CML (1<<1)
+#define PB_STATUS_TEMPERATURE (1<<2)
+#define PB_STATUS_VIN_UV (1<<3)
+#define PB_STATUS_IOUT_OC (1<<4)
+#define PB_STATUS_VOUT_OV (1<<5)
+#define PB_STATUS_OFF (1<<6)
+#define PB_STATUS_BUSY (1<<7)
+
+/*
+ * STATUS_WORD (upper)
+ */
+#define PB_STATUS_UNKNOWN (1<<8)
+#define PB_STATUS_OTHER (1<<9)
+#define PB_STATUS_FANS (1<<10)
+#define PB_STATUS_POWER_GOOD_N (1<<11)
+#define PB_STATUS_WORD_MFR (1<<12)
+#define PB_STATUS_INPUT (1<<13)
+#define PB_STATUS_IOUT_POUT (1<<14)
+#define PB_STATUS_VOUT (1<<15)
+
+/*
+ * STATUS_IOUT
+ */
+#define PB_POUT_OP_WARNING (1<<0)
+#define PB_POUT_OP_FAULT (1<<1)
+#define PB_POWER_LIMITING (1<<2)
+#define PB_CURRENT_SHARE_FAULT (1<<3)
+#define PB_IOUT_UC_FAULT (1<<4)
+#define PB_IOUT_OC_WARNING (1<<5)
+#define PB_IOUT_OC_LV_FAULT (1<<6)
+#define PB_IOUT_OC_FAULT (1<<7)
+
+/*
+ * STATUS_VOUT, STATUS_INPUT
+ */
+#define PB_VOLTAGE_UV_FAULT (1<<4)
+#define PB_VOLTAGE_UV_WARNING (1<<5)
+#define PB_VOLTAGE_OV_WARNING (1<<6)
+#define PB_VOLTAGE_OV_FAULT (1<<7)
+
+/*
+ * STATUS_INPUT
+ */
+#define PB_PIN_OP_WARNING (1<<0)
+#define PB_IIN_OC_WARNING (1<<1)
+#define PB_IIN_OC_FAULT (1<<2)
+
+/*
+ * STATUS_TEMPERATURE
+ */
+#define PB_TEMP_UT_FAULT (1<<4)
+#define PB_TEMP_UT_WARNING (1<<5)
+#define PB_TEMP_OT_WARNING (1<<6)
+#define PB_TEMP_OT_FAULT (1<<7)
+
+/*
+ * STATUS_FAN
+ */
+#define PB_FAN_AIRFLOW_WARNING (1<<0)
+#define PB_FAN_AIRFLOW_FAULT (1<<1)
+#define PB_FAN_FAN2_SPEED_OVERRIDE (1<<2)
+#define PB_FAN_FAN1_SPEED_OVERRIDE (1<<3)
+#define PB_FAN_FAN2_WARNING (1<<4)
+#define PB_FAN_FAN1_WARNING (1<<5)
+#define PB_FAN_FAN2_FAULT (1<<6)
+#define PB_FAN_FAN1_FAULT (1<<7)
+
+/*
+ * CML_FAULT_STATUS
+ */
+#define PB_CML_FAULT_OTHER_MEM_LOGIC (1<<0)
+#define PB_CML_FAULT_OTHER_COMM (1<<1)
+#define PB_CML_FAULT_PROCESSOR (1<<3)
+#define PB_CML_FAULT_MEMORY (1<<4)
+#define PB_CML_FAULT_PACKET_ERROR (1<<5)
+#define PB_CML_FAULT_INVALID_DATA (1<<6)
+#define PB_CML_FAULT_INVALID_COMMAND (1<<7)
+
+enum pmbus_sensor_classes {
+ PSC_VOLTAGE_IN = 0,
+ PSC_VOLTAGE_OUT,
+ PSC_CURRENT_IN,
+ PSC_CURRENT_OUT,
+ PSC_POWER,
+ PSC_TEMPERATURE,
+ PSC_FAN,
+ PSC_NUM_CLASSES /* Number of power sensor classes */
+};
+
+#define PMBUS_PAGES 32 /* Per PMBus specification */
+
+/* Functionality bit mask */
+#define PMBUS_HAVE_VIN (1 << 0)
+#define PMBUS_HAVE_VCAP (1 << 1)
+#define PMBUS_HAVE_VOUT (1 << 2)
+#define PMBUS_HAVE_IIN (1 << 3)
+#define PMBUS_HAVE_IOUT (1 << 4)
+#define PMBUS_HAVE_PIN (1 << 5)
+#define PMBUS_HAVE_POUT (1 << 6)
+#define PMBUS_HAVE_FAN12 (1 << 7)
+#define PMBUS_HAVE_FAN34 (1 << 8)
+#define PMBUS_HAVE_TEMP (1 << 9)
+#define PMBUS_HAVE_TEMP2 (1 << 10)
+#define PMBUS_HAVE_TEMP3 (1 << 11)
+#define PMBUS_HAVE_STATUS_VOUT (1 << 12)
+#define PMBUS_HAVE_STATUS_IOUT (1 << 13)
+#define PMBUS_HAVE_STATUS_INPUT (1 << 14)
+#define PMBUS_HAVE_STATUS_TEMP (1 << 15)
+#define PMBUS_HAVE_STATUS_FAN12 (1 << 16)
+#define PMBUS_HAVE_STATUS_FAN34 (1 << 17)
+
+struct pmbus_driver_info {
+ int pages; /* Total number of pages */
+ bool direct[PSC_NUM_CLASSES];
+ /* true if device uses direct data format
+ for the given sensor class */
+ /*
+ * Support one set of coefficients for each sensor type
+ * Used for chips providing data in direct mode.
+ */
+ int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
+ int b[PSC_NUM_CLASSES]; /* offset */
+ int R[PSC_NUM_CLASSES]; /* exponent */
+
+ u32 func[PMBUS_PAGES]; /* Functionality, per page */
+ /*
+ * The get_status function maps manufacturing specific status values
+ * into PMBus standard status values.
+ * This function is optional and only necessary if chip specific status
+ * register values have to be mapped into standard PMBus status register
+ * values.
+ */
+ int (*get_status)(struct i2c_client *client, int page, int reg);
+ /*
+ * The identify function determines supported PMBus functionality.
+ * This function is only necessary if a chip driver supports multiple
+ * chips, and the chip functionality is not pre-determined.
+ */
+ int (*identify)(struct i2c_client *client,
+ struct pmbus_driver_info *info);
+};
+
+/* Function declarations */
+
+int pmbus_set_page(struct i2c_client *client, u8 page);
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+void pmbus_clear_faults(struct i2c_client *client);
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+ struct pmbus_driver_info *info);
+int pmbus_do_remove(struct i2c_client *client);
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
+ *client);
+
+#endif /* PMBUS_H */
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c
new file mode 100644
index 000000000000..6474512f49b0
--- /dev/null
+++ b/drivers/hwmon/pmbus_core.c
@@ -0,0 +1,1658 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/delay.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+/*
+ * Constants needed to determine number of sensors, booleans, and labels.
+ */
+#define PMBUS_MAX_INPUT_SENSORS 11 /* 6*volt, 3*curr, 2*power */
+#define PMBUS_VOUT_SENSORS_PER_PAGE 5 /* input, min, max, lcrit,
+ crit */
+#define PMBUS_IOUT_SENSORS_PER_PAGE 4 /* input, min, max, crit */
+#define PMBUS_POUT_SENSORS_PER_PAGE 4 /* input, cap, max, crit */
+#define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */
+#define PMBUS_MAX_SENSORS_PER_TEMP 5 /* input, min, max, lcrit,
+ crit */
+
+#define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm,
+ lcrit_alarm, crit_alarm;
+ c: alarm, crit_alarm;
+ p: crit_alarm */
+#define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm,
+ lcrit_alarm, crit_alarm */
+#define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm,
+ crit_alarm */
+#define PMBUS_POUT_BOOLEANS_PER_PAGE 2 /* alarm, crit_alarm */
+#define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */
+#define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm,
+ lcrit_alarm, crit_alarm */
+
+#define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */
+
+/*
+ * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
+ * are paged. status_input is unpaged.
+ */
+#define PB_NUM_STATUS_REG (PMBUS_PAGES * 6 + 1)
+
+/*
+ * Index into status register array, per status register group
+ */
+#define PB_STATUS_BASE 0
+#define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES)
+#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_TEMP_BASE (PB_STATUS_INPUT_BASE + 1)
+
+struct pmbus_sensor {
+ char name[I2C_NAME_SIZE]; /* sysfs sensor name */
+ struct sensor_device_attribute attribute;
+ u8 page; /* page number */
+ u8 reg; /* register */
+ enum pmbus_sensor_classes class; /* sensor class */
+ bool update; /* runtime sensor update needed */
+ int data; /* Sensor data.
+ Negative if there was a read error */
+};
+
+struct pmbus_boolean {
+ char name[I2C_NAME_SIZE]; /* sysfs boolean name */
+ struct sensor_device_attribute attribute;
+};
+
+struct pmbus_label {
+ char name[I2C_NAME_SIZE]; /* sysfs label name */
+ struct sensor_device_attribute attribute;
+ char label[I2C_NAME_SIZE]; /* label */
+};
+
+struct pmbus_data {
+ struct device *hwmon_dev;
+
+ u32 flags; /* from platform data */
+
+ int exponent; /* linear mode: exponent for output voltages */
+
+ const struct pmbus_driver_info *info;
+
+ int max_attributes;
+ int num_attributes;
+ struct attribute **attributes;
+ struct attribute_group group;
+
+ /*
+ * Sensors cover both sensor and limit registers.
+ */
+ int max_sensors;
+ int num_sensors;
+ struct pmbus_sensor *sensors;
+ /*
+ * Booleans are used for alarms.
+ * Values are determined from status registers.
+ */
+ int max_booleans;
+ int num_booleans;
+ struct pmbus_boolean *booleans;
+ /*
+ * Labels are used to map generic names (e.g., "in1")
+ * to PMBus specific names (e.g., "vin" or "vout1").
+ */
+ int max_labels;
+ int num_labels;
+ struct pmbus_label *labels;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ /*
+ * A single status register covers multiple attributes,
+ * so we keep them all together.
+ */
+ u8 status_bits;
+ u8 status[PB_NUM_STATUS_REG];
+
+ u8 currpage;
+};
+
+int pmbus_set_page(struct i2c_client *client, u8 page)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ int rv = 0;
+ int newpage;
+
+ if (page != data->currpage) {
+ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+ newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
+ if (newpage != page)
+ rv = -EINVAL;
+ else
+ data->currpage = page;
+ }
+ return rv;
+}
+EXPORT_SYMBOL_GPL(pmbus_set_page);
+
+static int pmbus_write_byte(struct i2c_client *client, u8 page, u8 value)
+{
+ int rv;
+
+ rv = pmbus_set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_write_byte(client, value);
+}
+
+static int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg,
+ u16 word)
+{
+ int rv;
+
+ rv = pmbus_set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_write_word_data(client, reg, word);
+}
+
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
+{
+ int rv;
+
+ rv = pmbus_set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_read_word_data(client, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_read_word_data);
+
+static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg)
+{
+ int rv;
+
+ rv = pmbus_set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static void pmbus_clear_fault_page(struct i2c_client *client, int page)
+{
+ pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+}
+
+void pmbus_clear_faults(struct i2c_client *client)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < data->info->pages; i++)
+ pmbus_clear_fault_page(client, i);
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_faults);
+
+static int pmbus_check_status_cml(struct i2c_client *client, int page)
+{
+ int status, status2;
+
+ status = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
+ if (status < 0 || (status & PB_STATUS_CML)) {
+ status2 = pmbus_read_byte_data(client, page, PMBUS_STATUS_CML);
+ if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
+ return -EINVAL;
+ }
+ return 0;
+}
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+ int rv;
+ struct pmbus_data *data = i2c_get_clientdata(client);
+
+ rv = pmbus_read_byte_data(client, page, reg);
+ if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+ rv = pmbus_check_status_cml(client, page);
+ pmbus_clear_fault_page(client, page);
+ return rv >= 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
+
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
+{
+ int rv;
+ struct pmbus_data *data = i2c_get_clientdata(client);
+
+ rv = pmbus_read_word_data(client, page, reg);
+ if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+ rv = pmbus_check_status_cml(client, page);
+ pmbus_clear_fault_page(client, page);
+ return rv >= 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_check_word_register);
+
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+
+ return data->info;
+}
+EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
+
+static int pmbus_get_status(struct i2c_client *client, int page, int reg)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ const struct pmbus_driver_info *info = data->info;
+ int status;
+
+ if (info->get_status) {
+ status = info->get_status(client, page, reg);
+ if (status != -ENODATA)
+ return status;
+ }
+ return pmbus_read_byte_data(client, page, reg);
+}
+
+static struct pmbus_data *pmbus_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ const struct pmbus_driver_info *info = data->info;
+
+ mutex_lock(&data->update_lock);
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ int i;
+
+ for (i = 0; i < info->pages; i++)
+ data->status[PB_STATUS_BASE + i]
+ = pmbus_read_byte_data(client, i,
+ PMBUS_STATUS_BYTE);
+ for (i = 0; i < info->pages; i++) {
+ if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
+ continue;
+ data->status[PB_STATUS_VOUT_BASE + i]
+ = pmbus_get_status(client, i, PMBUS_STATUS_VOUT);
+ }
+ for (i = 0; i < info->pages; i++) {
+ if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
+ continue;
+ data->status[PB_STATUS_IOUT_BASE + i]
+ = pmbus_get_status(client, i, PMBUS_STATUS_IOUT);
+ }
+ for (i = 0; i < info->pages; i++) {
+ if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
+ continue;
+ data->status[PB_STATUS_TEMP_BASE + i]
+ = pmbus_get_status(client, i,
+ PMBUS_STATUS_TEMPERATURE);
+ }
+ for (i = 0; i < info->pages; i++) {
+ if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
+ continue;
+ data->status[PB_STATUS_FAN_BASE + i]
+ = pmbus_get_status(client, i, PMBUS_STATUS_FAN_12);
+ }
+
+ for (i = 0; i < info->pages; i++) {
+ if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
+ continue;
+ data->status[PB_STATUS_FAN34_BASE + i]
+ = pmbus_get_status(client, i, PMBUS_STATUS_FAN_34);
+ }
+
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
+ data->status[PB_STATUS_INPUT_BASE]
+ = pmbus_get_status(client, 0, PMBUS_STATUS_INPUT);
+
+ for (i = 0; i < data->num_sensors; i++) {
+ struct pmbus_sensor *sensor = &data->sensors[i];
+
+ if (!data->valid || sensor->update)
+ sensor->data
+ = pmbus_read_word_data(client, sensor->page,
+ sensor->reg);
+ }
+ pmbus_clear_faults(client);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/*
+ * Convert linear sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static int pmbus_reg2data_linear(struct pmbus_data *data,
+ struct pmbus_sensor *sensor)
+{
+ s16 exponent;
+ s32 mantissa;
+ long val;
+
+ if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */
+ exponent = data->exponent;
+ mantissa = (u16) sensor->data;
+ } else { /* LINEAR11 */
+ exponent = (sensor->data >> 11) & 0x001f;
+ mantissa = sensor->data & 0x07ff;
+
+ if (exponent > 0x0f)
+ exponent |= 0xffe0; /* sign extend exponent */
+ if (mantissa > 0x03ff)
+ mantissa |= 0xfffff800; /* sign extend mantissa */
+ }
+
+ val = mantissa;
+
+ /* scale result to milli-units for all sensors except fans */
+ if (sensor->class != PSC_FAN)
+ val = val * 1000L;
+
+ /* scale result to micro-units for power sensors */
+ if (sensor->class == PSC_POWER)
+ val = val * 1000L;
+
+ if (exponent >= 0)
+ val <<= exponent;
+ else
+ val >>= -exponent;
+
+ return (int)val;
+}
+
+/*
+ * Convert direct sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static int pmbus_reg2data_direct(struct pmbus_data *data,
+ struct pmbus_sensor *sensor)
+{
+ long val = (s16) sensor->data;
+ long m, b, R;
+
+ m = data->info->m[sensor->class];
+ b = data->info->b[sensor->class];
+ R = data->info->R[sensor->class];
+
+ if (m == 0)
+ return 0;
+
+ /* X = 1/m * (Y * 10^-R - b) */
+ R = -R;
+ /* scale result to milli-units for everything but fans */
+ if (sensor->class != PSC_FAN) {
+ R += 3;
+ b *= 1000;
+ }
+
+ /* scale result to micro-units for power sensors */
+ if (sensor->class == PSC_POWER) {
+ R += 3;
+ b *= 1000;
+ }
+
+ while (R > 0) {
+ val *= 10;
+ R--;
+ }
+ while (R < 0) {
+ val = DIV_ROUND_CLOSEST(val, 10);
+ R++;
+ }
+
+ return (int)((val - b) / m);
+}
+
+static int pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
+{
+ int val;
+
+ if (data->info->direct[sensor->class])
+ val = pmbus_reg2data_direct(data, sensor);
+ else
+ val = pmbus_reg2data_linear(data, sensor);
+
+ return val;
+}
+
+#define MAX_MANTISSA (1023 * 1000)
+#define MIN_MANTISSA (511 * 1000)
+
+static u16 pmbus_data2reg_linear(struct pmbus_data *data,
+ enum pmbus_sensor_classes class, long val)
+{
+ s16 exponent = 0, mantissa;
+ bool negative = false;
+
+ /* simple case */
+ if (val == 0)
+ return 0;
+
+ if (class == PSC_VOLTAGE_OUT) {
+ /* LINEAR16 does not support negative voltages */
+ if (val < 0)
+ return 0;
+
+ /*
+ * For a static exponents, we don't have a choice
+ * but to adjust the value to it.
+ */
+ if (data->exponent < 0)
+ val <<= -data->exponent;
+ else
+ val >>= data->exponent;
+ val = DIV_ROUND_CLOSEST(val, 1000);
+ return val & 0xffff;
+ }
+
+ if (val < 0) {
+ negative = true;
+ val = -val;
+ }
+
+ /* Power is in uW. Convert to mW before converting. */
+ if (class == PSC_POWER)
+ val = DIV_ROUND_CLOSEST(val, 1000L);
+
+ /*
+ * For simplicity, convert fan data to milli-units
+ * before calculating the exponent.
+ */
+ if (class == PSC_FAN)
+ val = val * 1000;
+
+ /* Reduce large mantissa until it fits into 10 bit */
+ while (val >= MAX_MANTISSA && exponent < 15) {
+ exponent++;
+ val >>= 1;
+ }
+ /* Increase small mantissa to improve precision */
+ while (val < MIN_MANTISSA && exponent > -15) {
+ exponent--;
+ val <<= 1;
+ }
+
+ /* Convert mantissa from milli-units to units */
+ mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+ /* Ensure that resulting number is within range */
+ if (mantissa > 0x3ff)
+ mantissa = 0x3ff;
+
+ /* restore sign */
+ if (negative)
+ mantissa = -mantissa;
+
+ /* Convert to 5 bit exponent, 11 bit mantissa */
+ return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
+static u16 pmbus_data2reg_direct(struct pmbus_data *data,
+ enum pmbus_sensor_classes class, long val)
+{
+ long m, b, R;
+
+ m = data->info->m[class];
+ b = data->info->b[class];
+ R = data->info->R[class];
+
+ /* Power is in uW. Adjust R and b. */
+ if (class == PSC_POWER) {
+ R -= 3;
+ b *= 1000;
+ }
+
+ /* Calculate Y = (m * X + b) * 10^R */
+ if (class != PSC_FAN) {
+ R -= 3; /* Adjust R and b for data in milli-units */
+ b *= 1000;
+ }
+ val = val * m + b;
+
+ while (R > 0) {
+ val *= 10;
+ R--;
+ }
+ while (R < 0) {
+ val = DIV_ROUND_CLOSEST(val, 10);
+ R++;
+ }
+
+ return val;
+}
+
+static u16 pmbus_data2reg(struct pmbus_data *data,
+ enum pmbus_sensor_classes class, long val)
+{
+ u16 regval;
+
+ if (data->info->direct[class])
+ regval = pmbus_data2reg_direct(data, class, val);
+ else
+ regval = pmbus_data2reg_linear(data, class, val);
+
+ return regval;
+}
+
+/*
+ * Return boolean calculated from converted data.
+ * <index> defines a status register index and mask, and optionally
+ * two sensor indexes.
+ * The upper half-word references the two sensors,
+ * two sensor indices.
+ * The upper half-word references the two optional sensors,
+ * the lower half word references status register and mask.
+ * The function returns true if (status[reg] & mask) is true and,
+ * if specified, if v1 >= v2.
+ * To determine if an object exceeds upper limits, specify <v, limit>.
+ * To determine if an object exceeds lower limits, specify <limit, v>.
+ *
+ * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
+ * index are set. s1 and s2 (the sensor index values) are zero in this case.
+ * The function returns true if (status[reg] & mask) is true.
+ *
+ * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
+ * a specified limit has to be performed to determine the boolean result.
+ * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
+ * sensor values referenced by sensor indices s1 and s2).
+ *
+ * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
+ * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
+ *
+ * If a negative value is stored in any of the referenced registers, this value
+ * reflects an error code which will be returned.
+ */
+static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val)
+{
+ u8 s1 = (index >> 24) & 0xff;
+ u8 s2 = (index >> 16) & 0xff;
+ u8 reg = (index >> 8) & 0xff;
+ u8 mask = index & 0xff;
+ int status;
+ u8 regval;
+
+ status = data->status[reg];
+ if (status < 0)
+ return status;
+
+ regval = status & mask;
+ if (!s1 && !s2)
+ *val = !!regval;
+ else {
+ int v1, v2;
+ struct pmbus_sensor *sensor1, *sensor2;
+
+ sensor1 = &data->sensors[s1];
+ if (sensor1->data < 0)
+ return sensor1->data;
+ sensor2 = &data->sensors[s2];
+ if (sensor2->data < 0)
+ return sensor2->data;
+
+ v1 = pmbus_reg2data(data, sensor1);
+ v2 = pmbus_reg2data(data, sensor2);
+ *val = !!(regval && v1 >= v2);
+ }
+ return 0;
+}
+
+static ssize_t pmbus_show_boolean(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_data *data = pmbus_update_device(dev);
+ int val;
+ int err;
+
+ err = pmbus_get_boolean(data, attr->index, &val);
+ if (err)
+ return err;
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t pmbus_show_sensor(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct pmbus_data *data = pmbus_update_device(dev);
+ struct pmbus_sensor *sensor;
+
+ sensor = &data->sensors[attr->index];
+ if (sensor->data < 0)
+ return sensor->data;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", pmbus_reg2data(data, sensor));
+}
+
+static ssize_t pmbus_set_sensor(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ struct pmbus_sensor *sensor = &data->sensors[attr->index];
+ ssize_t rv = count;
+ long val = 0;
+ int ret;
+ u16 regval;
+
+ if (strict_strtol(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ regval = pmbus_data2reg(data, sensor->class, val);
+ ret = pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
+ if (ret < 0)
+ rv = ret;
+ else
+ data->sensors[attr->index].data = regval;
+ mutex_unlock(&data->update_lock);
+ return rv;
+}
+
+static ssize_t pmbus_show_label(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ data->labels[attr->index].label);
+}
+
+#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set) \
+do { \
+ struct sensor_device_attribute *a \
+ = &data->_type##s[data->num_##_type##s].attribute; \
+ BUG_ON(data->num_attributes >= data->max_attributes); \
+ a->dev_attr.attr.name = _name; \
+ a->dev_attr.attr.mode = _mode; \
+ a->dev_attr.show = _show; \
+ a->dev_attr.store = _set; \
+ a->index = _idx; \
+ data->attributes[data->num_attributes] = &a->dev_attr.attr; \
+ data->num_attributes++; \
+} while (0)
+
+#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx) \
+ PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type, \
+ pmbus_show_##_type, NULL)
+
+#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx) \
+ PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type, \
+ pmbus_show_##_type, pmbus_set_##_type)
+
+static void pmbus_add_boolean(struct pmbus_data *data,
+ const char *name, const char *type, int seq,
+ int idx)
+{
+ struct pmbus_boolean *boolean;
+
+ BUG_ON(data->num_booleans >= data->max_booleans);
+
+ boolean = &data->booleans[data->num_booleans];
+
+ snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
+ name, seq, type);
+ PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
+ data->num_booleans++;
+}
+
+static void pmbus_add_boolean_reg(struct pmbus_data *data,
+ const char *name, const char *type,
+ int seq, int reg, int bit)
+{
+ pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
+}
+
+static void pmbus_add_boolean_cmp(struct pmbus_data *data,
+ const char *name, const char *type,
+ int seq, int i1, int i2, int reg, int mask)
+{
+ pmbus_add_boolean(data, name, type, seq,
+ (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
+}
+
+static void pmbus_add_sensor(struct pmbus_data *data,
+ const char *name, const char *type, int seq,
+ int page, int reg, enum pmbus_sensor_classes class,
+ bool update)
+{
+ struct pmbus_sensor *sensor;
+
+ BUG_ON(data->num_sensors >= data->max_sensors);
+
+ sensor = &data->sensors[data->num_sensors];
+ snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
+ name, seq, type);
+ sensor->page = page;
+ sensor->reg = reg;
+ sensor->class = class;
+ sensor->update = update;
+ if (update)
+ PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
+ data->num_sensors);
+ else
+ PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
+ data->num_sensors);
+ data->num_sensors++;
+}
+
+static void pmbus_add_label(struct pmbus_data *data,
+ const char *name, int seq,
+ const char *lstring, int index)
+{
+ struct pmbus_label *label;
+
+ BUG_ON(data->num_labels >= data->max_labels);
+
+ label = &data->labels[data->num_labels];
+ snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
+ if (!index)
+ strncpy(label->label, lstring, sizeof(label->label) - 1);
+ else
+ snprintf(label->label, sizeof(label->label), "%s%d", lstring,
+ index);
+
+ PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
+ data->num_labels++;
+}
+
+static const int pmbus_temp_registers[] = {
+ PMBUS_READ_TEMPERATURE_1,
+ PMBUS_READ_TEMPERATURE_2,
+ PMBUS_READ_TEMPERATURE_3
+};
+
+static const int pmbus_temp_flags[] = {
+ PMBUS_HAVE_TEMP,
+ PMBUS_HAVE_TEMP2,
+ PMBUS_HAVE_TEMP3
+};
+
+static const int pmbus_fan_registers[] = {
+ PMBUS_READ_FAN_SPEED_1,
+ PMBUS_READ_FAN_SPEED_2,
+ PMBUS_READ_FAN_SPEED_3,
+ PMBUS_READ_FAN_SPEED_4
+};
+
+static const int pmbus_fan_config_registers[] = {
+ PMBUS_FAN_CONFIG_12,
+ PMBUS_FAN_CONFIG_12,
+ PMBUS_FAN_CONFIG_34,
+ PMBUS_FAN_CONFIG_34
+};
+
+static const int pmbus_fan_status_registers[] = {
+ PMBUS_STATUS_FAN_12,
+ PMBUS_STATUS_FAN_12,
+ PMBUS_STATUS_FAN_34,
+ PMBUS_STATUS_FAN_34
+};
+
+static const u32 pmbus_fan_flags[] = {
+ PMBUS_HAVE_FAN12,
+ PMBUS_HAVE_FAN12,
+ PMBUS_HAVE_FAN34,
+ PMBUS_HAVE_FAN34
+};
+
+static const u32 pmbus_fan_status_flags[] = {
+ PMBUS_HAVE_STATUS_FAN12,
+ PMBUS_HAVE_STATUS_FAN12,
+ PMBUS_HAVE_STATUS_FAN34,
+ PMBUS_HAVE_STATUS_FAN34
+};
+
+/*
+ * Determine maximum number of sensors, booleans, and labels.
+ * To keep things simple, only make a rough high estimate.
+ */
+static void pmbus_find_max_attr(struct i2c_client *client,
+ struct pmbus_data *data)
+{
+ const struct pmbus_driver_info *info = data->info;
+ int page, max_sensors, max_booleans, max_labels;
+
+ max_sensors = PMBUS_MAX_INPUT_SENSORS;
+ max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
+ max_labels = PMBUS_MAX_INPUT_LABELS;
+
+ for (page = 0; page < info->pages; page++) {
+ if (info->func[page] & PMBUS_HAVE_VOUT) {
+ max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
+ max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
+ max_labels++;
+ }
+ if (info->func[page] & PMBUS_HAVE_IOUT) {
+ max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
+ max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
+ max_labels++;
+ }
+ if (info->func[page] & PMBUS_HAVE_POUT) {
+ max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
+ max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
+ max_labels++;
+ }
+ if (info->func[page] & PMBUS_HAVE_FAN12) {
+ max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
+ max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
+ }
+ if (info->func[page] & PMBUS_HAVE_FAN34) {
+ max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
+ max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
+ }
+ if (info->func[page] & PMBUS_HAVE_TEMP) {
+ max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+ max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+ }
+ if (info->func[page] & PMBUS_HAVE_TEMP2) {
+ max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+ max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+ }
+ if (info->func[page] & PMBUS_HAVE_TEMP3) {
+ max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+ max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+ }
+ }
+ data->max_sensors = max_sensors;
+ data->max_booleans = max_booleans;
+ data->max_labels = max_labels;
+ data->max_attributes = max_sensors + max_booleans + max_labels;
+}
+
+/*
+ * Search for attributes. Allocate sensors, booleans, and labels as needed.
+ */
+static void pmbus_find_attributes(struct i2c_client *client,
+ struct pmbus_data *data)
+{
+ const struct pmbus_driver_info *info = data->info;
+ int page, i0, i1, in_index;
+
+ /*
+ * Input voltage sensors
+ */
+ in_index = 1;
+ if (info->func[0] & PMBUS_HAVE_VIN) {
+ bool have_alarm = false;
+
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "in", in_index, "vin", 0);
+ pmbus_add_sensor(data, "in", "input", in_index,
+ 0, PMBUS_READ_VIN, PSC_VOLTAGE_IN, true);
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_VIN_UV_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "min", in_index,
+ 0, PMBUS_VIN_UV_WARN_LIMIT,
+ PSC_VOLTAGE_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
+ pmbus_add_boolean_reg(data, "in", "min_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_VOLTAGE_UV_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_VIN_UV_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "lcrit", in_index,
+ 0, PMBUS_VIN_UV_FAULT_LIMIT,
+ PSC_VOLTAGE_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
+ pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_VOLTAGE_UV_FAULT);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_VIN_OV_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "max", in_index,
+ 0, PMBUS_VIN_OV_WARN_LIMIT,
+ PSC_VOLTAGE_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
+ pmbus_add_boolean_reg(data, "in", "max_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_VOLTAGE_OV_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_VIN_OV_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "crit", in_index,
+ 0, PMBUS_VIN_OV_FAULT_LIMIT,
+ PSC_VOLTAGE_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
+ pmbus_add_boolean_reg(data, "in", "crit_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_VOLTAGE_OV_FAULT);
+ have_alarm = true;
+ }
+ }
+ /*
+ * Add generic alarm attribute only if there are no individual
+ * attributes.
+ */
+ if (!have_alarm)
+ pmbus_add_boolean_reg(data, "in", "alarm",
+ in_index,
+ PB_STATUS_BASE,
+ PB_STATUS_VIN_UV);
+ in_index++;
+ }
+ if (info->func[0] & PMBUS_HAVE_VCAP) {
+ pmbus_add_label(data, "in", in_index, "vcap", 0);
+ pmbus_add_sensor(data, "in", "input", in_index, 0,
+ PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true);
+ in_index++;
+ }
+
+ /*
+ * Output voltage sensors
+ */
+ for (page = 0; page < info->pages; page++) {
+ bool have_alarm = false;
+
+ if (!(info->func[page] & PMBUS_HAVE_VOUT))
+ continue;
+
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "in", in_index, "vout", page + 1);
+ pmbus_add_sensor(data, "in", "input", in_index, page,
+ PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true);
+ if (pmbus_check_word_register(client, page,
+ PMBUS_VOUT_UV_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "min", in_index, page,
+ PMBUS_VOUT_UV_WARN_LIMIT,
+ PSC_VOLTAGE_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
+ pmbus_add_boolean_reg(data, "in", "min_alarm",
+ in_index,
+ PB_STATUS_VOUT_BASE +
+ page,
+ PB_VOLTAGE_UV_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_VOUT_UV_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "lcrit", in_index, page,
+ PMBUS_VOUT_UV_FAULT_LIMIT,
+ PSC_VOLTAGE_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
+ pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
+ in_index,
+ PB_STATUS_VOUT_BASE +
+ page,
+ PB_VOLTAGE_UV_FAULT);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_VOUT_OV_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "max", in_index, page,
+ PMBUS_VOUT_OV_WARN_LIMIT,
+ PSC_VOLTAGE_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
+ pmbus_add_boolean_reg(data, "in", "max_alarm",
+ in_index,
+ PB_STATUS_VOUT_BASE +
+ page,
+ PB_VOLTAGE_OV_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_VOUT_OV_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "in", "crit", in_index, page,
+ PMBUS_VOUT_OV_FAULT_LIMIT,
+ PSC_VOLTAGE_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
+ pmbus_add_boolean_reg(data, "in", "crit_alarm",
+ in_index,
+ PB_STATUS_VOUT_BASE +
+ page,
+ PB_VOLTAGE_OV_FAULT);
+ have_alarm = true;
+ }
+ }
+ /*
+ * Add generic alarm attribute only if there are no individual
+ * attributes.
+ */
+ if (!have_alarm)
+ pmbus_add_boolean_reg(data, "in", "alarm",
+ in_index,
+ PB_STATUS_BASE + page,
+ PB_STATUS_VOUT_OV);
+ in_index++;
+ }
+
+ /*
+ * Current sensors
+ */
+
+ /*
+ * Input current sensors
+ */
+ in_index = 1;
+ if (info->func[0] & PMBUS_HAVE_IIN) {
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "curr", in_index, "iin", 0);
+ pmbus_add_sensor(data, "curr", "input", in_index,
+ 0, PMBUS_READ_IIN, PSC_CURRENT_IN, true);
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_IIN_OC_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "curr", "max", in_index,
+ 0, PMBUS_IIN_OC_WARN_LIMIT,
+ PSC_CURRENT_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
+ pmbus_add_boolean_reg(data, "curr", "max_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_IIN_OC_WARNING);
+ }
+ }
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_IIN_OC_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "curr", "crit", in_index,
+ 0, PMBUS_IIN_OC_FAULT_LIMIT,
+ PSC_CURRENT_IN, false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
+ pmbus_add_boolean_reg(data, "curr",
+ "crit_alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_IIN_OC_FAULT);
+ }
+ in_index++;
+ }
+
+ /*
+ * Output current sensors
+ */
+ for (page = 0; page < info->pages; page++) {
+ bool have_alarm = false;
+
+ if (!(info->func[page] & PMBUS_HAVE_IOUT))
+ continue;
+
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "curr", in_index, "iout", page + 1);
+ pmbus_add_sensor(data, "curr", "input", in_index, page,
+ PMBUS_READ_IOUT, PSC_CURRENT_OUT, true);
+ if (pmbus_check_word_register(client, page,
+ PMBUS_IOUT_OC_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "curr", "max", in_index, page,
+ PMBUS_IOUT_OC_WARN_LIMIT,
+ PSC_CURRENT_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
+ pmbus_add_boolean_reg(data, "curr", "max_alarm",
+ in_index,
+ PB_STATUS_IOUT_BASE +
+ page, PB_IOUT_OC_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_IOUT_UC_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "curr", "lcrit", in_index, page,
+ PMBUS_IOUT_UC_FAULT_LIMIT,
+ PSC_CURRENT_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
+ pmbus_add_boolean_reg(data, "curr",
+ "lcrit_alarm",
+ in_index,
+ PB_STATUS_IOUT_BASE +
+ page, PB_IOUT_UC_FAULT);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_IOUT_OC_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "curr", "crit", in_index, page,
+ PMBUS_IOUT_OC_FAULT_LIMIT,
+ PSC_CURRENT_OUT, false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
+ pmbus_add_boolean_reg(data, "curr",
+ "crit_alarm",
+ in_index,
+ PB_STATUS_IOUT_BASE +
+ page, PB_IOUT_OC_FAULT);
+ have_alarm = true;
+ }
+ }
+ /*
+ * Add generic alarm attribute only if there are no individual
+ * attributes.
+ */
+ if (!have_alarm)
+ pmbus_add_boolean_reg(data, "curr", "alarm",
+ in_index,
+ PB_STATUS_BASE + page,
+ PB_STATUS_IOUT_OC);
+ in_index++;
+ }
+
+ /*
+ * Power sensors
+ */
+ /*
+ * Input Power sensors
+ */
+ in_index = 1;
+ if (info->func[0] & PMBUS_HAVE_PIN) {
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "power", in_index, "pin", 0);
+ pmbus_add_sensor(data, "power", "input", in_index,
+ 0, PMBUS_READ_PIN, PSC_POWER, true);
+ if (pmbus_check_word_register(client, 0,
+ PMBUS_PIN_OP_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "power", "max", in_index,
+ 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER,
+ false);
+ if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
+ pmbus_add_boolean_reg(data, "power",
+ "alarm",
+ in_index,
+ PB_STATUS_INPUT_BASE,
+ PB_PIN_OP_WARNING);
+ }
+ in_index++;
+ }
+
+ /*
+ * Output Power sensors
+ */
+ for (page = 0; page < info->pages; page++) {
+ bool need_alarm = false;
+
+ if (!(info->func[page] & PMBUS_HAVE_POUT))
+ continue;
+
+ i0 = data->num_sensors;
+ pmbus_add_label(data, "power", in_index, "pout", page + 1);
+ pmbus_add_sensor(data, "power", "input", in_index, page,
+ PMBUS_READ_POUT, PSC_POWER, true);
+ /*
+ * Per hwmon sysfs API, power_cap is to be used to limit output
+ * power.
+ * We have two registers related to maximum output power,
+ * PMBUS_POUT_MAX and PMBUS_POUT_OP_WARN_LIMIT.
+ * PMBUS_POUT_MAX matches the powerX_cap attribute definition.
+ * There is no attribute in the API to match
+ * PMBUS_POUT_OP_WARN_LIMIT. We use powerX_max for now.
+ */
+ if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "power", "cap", in_index, page,
+ PMBUS_POUT_MAX, PSC_POWER, false);
+ need_alarm = true;
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_POUT_OP_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "power", "max", in_index, page,
+ PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER,
+ false);
+ need_alarm = true;
+ }
+ if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT))
+ pmbus_add_boolean_reg(data, "power", "alarm",
+ in_index,
+ PB_STATUS_IOUT_BASE + page,
+ PB_POUT_OP_WARNING
+ | PB_POWER_LIMITING);
+
+ if (pmbus_check_word_register(client, page,
+ PMBUS_POUT_OP_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "power", "crit", in_index, page,
+ PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER,
+ false);
+ if (info->func[page] & PMBUS_HAVE_STATUS_IOUT)
+ pmbus_add_boolean_reg(data, "power",
+ "crit_alarm",
+ in_index,
+ PB_STATUS_IOUT_BASE
+ + page,
+ PB_POUT_OP_FAULT);
+ }
+ in_index++;
+ }
+
+ /*
+ * Temperature sensors
+ */
+ in_index = 1;
+ for (page = 0; page < info->pages; page++) {
+ int t;
+
+ for (t = 0; t < ARRAY_SIZE(pmbus_temp_registers); t++) {
+ bool have_alarm = false;
+
+ /*
+ * A PMBus chip may support any combination of
+ * temperature registers on any page. So we can not
+ * abort after a failure to detect a register, but have
+ * to continue checking for all registers on all pages.
+ */
+ if (!(info->func[page] & pmbus_temp_flags[t]))
+ continue;
+
+ if (!pmbus_check_word_register
+ (client, page, pmbus_temp_registers[t]))
+ continue;
+
+ i0 = data->num_sensors;
+ pmbus_add_sensor(data, "temp", "input", in_index, page,
+ pmbus_temp_registers[t],
+ PSC_TEMPERATURE, true);
+
+ /*
+ * PMBus provides only one status register for TEMP1-3.
+ * Thus, we can not use the status register to determine
+ * which of the three sensors actually caused an alarm.
+ * Always compare current temperature against the limit
+ * registers to determine alarm conditions for a
+ * specific sensor.
+ *
+ * Since there is only one set of limit registers for
+ * up to three temperature sensors, we need to update
+ * all limit registers after the limit was changed for
+ * one of the sensors. This ensures that correct limits
+ * are reported for all temperature sensors.
+ */
+ if (pmbus_check_word_register
+ (client, page, PMBUS_UT_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "temp", "min", in_index,
+ page, PMBUS_UT_WARN_LIMIT,
+ PSC_TEMPERATURE, true);
+ if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
+ pmbus_add_boolean_cmp(data, "temp",
+ "min_alarm", in_index, i1, i0,
+ PB_STATUS_TEMP_BASE + page,
+ PB_TEMP_UT_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_UT_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "temp", "lcrit",
+ in_index, page,
+ PMBUS_UT_FAULT_LIMIT,
+ PSC_TEMPERATURE, true);
+ if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
+ pmbus_add_boolean_cmp(data, "temp",
+ "lcrit_alarm", in_index, i1, i0,
+ PB_STATUS_TEMP_BASE + page,
+ PB_TEMP_UT_FAULT);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register
+ (client, page, PMBUS_OT_WARN_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "temp", "max", in_index,
+ page, PMBUS_OT_WARN_LIMIT,
+ PSC_TEMPERATURE, true);
+ if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
+ pmbus_add_boolean_cmp(data, "temp",
+ "max_alarm", in_index, i0, i1,
+ PB_STATUS_TEMP_BASE + page,
+ PB_TEMP_OT_WARNING);
+ have_alarm = true;
+ }
+ }
+ if (pmbus_check_word_register(client, page,
+ PMBUS_OT_FAULT_LIMIT)) {
+ i1 = data->num_sensors;
+ pmbus_add_sensor(data, "temp", "crit", in_index,
+ page, PMBUS_OT_FAULT_LIMIT,
+ PSC_TEMPERATURE, true);
+ if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
+ pmbus_add_boolean_cmp(data, "temp",
+ "crit_alarm", in_index, i0, i1,
+ PB_STATUS_TEMP_BASE + page,
+ PB_TEMP_OT_FAULT);
+ have_alarm = true;
+ }
+ }
+ /*
+ * Last resort - we were not able to create any alarm
+ * registers. Report alarm for all sensors using the
+ * status register temperature alarm bit.
+ */
+ if (!have_alarm)
+ pmbus_add_boolean_reg(data, "temp", "alarm",
+ in_index,
+ PB_STATUS_BASE + page,
+ PB_STATUS_TEMPERATURE);
+ in_index++;
+ }
+ }
+
+ /*
+ * Fans
+ */
+ in_index = 1;
+ for (page = 0; page < info->pages; page++) {
+ int f;
+
+ for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
+ int regval;
+
+ if (!(info->func[page] & pmbus_fan_flags[f]))
+ break;
+
+ if (!pmbus_check_word_register(client, page,
+ pmbus_fan_registers[f])
+ || !pmbus_check_byte_register(client, page,
+ pmbus_fan_config_registers[f]))
+ break;
+
+ /*
+ * Skip fan if not installed.
+ * Each fan configuration register covers multiple fans,
+ * so we have to do some magic.
+ */
+ regval = pmbus_read_byte_data(client, page,
+ pmbus_fan_config_registers[f]);
+ if (regval < 0 ||
+ (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
+ continue;
+
+ i0 = data->num_sensors;
+ pmbus_add_sensor(data, "fan", "input", in_index, page,
+ pmbus_fan_registers[f], PSC_FAN, true);
+
+ /*
+ * Each fan status register covers multiple fans,
+ * so we have to do some magic.
+ */
+ if ((info->func[page] & pmbus_fan_status_flags[f]) &&
+ pmbus_check_byte_register(client,
+ page, pmbus_fan_status_registers[f])) {
+ int base;
+
+ if (f > 1) /* fan 3, 4 */
+ base = PB_STATUS_FAN34_BASE + page;
+ else
+ base = PB_STATUS_FAN_BASE + page;
+ pmbus_add_boolean_reg(data, "fan", "alarm",
+ in_index, base,
+ PB_FAN_FAN1_WARNING >> (f & 1));
+ pmbus_add_boolean_reg(data, "fan", "fault",
+ in_index, base,
+ PB_FAN_FAN1_FAULT >> (f & 1));
+ }
+ in_index++;
+ }
+ }
+}
+
+/*
+ * Identify chip parameters.
+ * This function is called for all chips.
+ */
+static int pmbus_identify_common(struct i2c_client *client,
+ struct pmbus_data *data)
+{
+ int vout_mode = -1, exponent;
+
+ if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE))
+ vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+ if (vout_mode >= 0 && vout_mode != 0xff) {
+ /*
+ * Not all chips support the VOUT_MODE command,
+ * so a failure to read it is not an error.
+ */
+ switch (vout_mode >> 5) {
+ case 0: /* linear mode */
+ if (data->info->direct[PSC_VOLTAGE_OUT])
+ return -ENODEV;
+
+ exponent = vout_mode & 0x1f;
+ /* and sign-extend it */
+ if (exponent & 0x10)
+ exponent |= ~0x1f;
+ data->exponent = exponent;
+ break;
+ case 2: /* direct mode */
+ if (!data->info->direct[PSC_VOLTAGE_OUT])
+ return -ENODEV;
+ break;
+ default:
+ return -ENODEV;
+ }
+ }
+
+ /* Determine maximum number of sensors, booleans, and labels */
+ pmbus_find_max_attr(client, data);
+ pmbus_clear_fault_page(client, 0);
+ return 0;
+}
+
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+ struct pmbus_driver_info *info)
+{
+ const struct pmbus_platform_data *pdata = client->dev.platform_data;
+ struct pmbus_data *data;
+ int ret;
+
+ if (!info) {
+ dev_err(&client->dev, "Missing chip information");
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+ | I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&client->dev, "No memory to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /*
+ * Bail out if status register or PMBus revision register
+ * does not exist.
+ */
+ if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0
+ || i2c_smbus_read_byte_data(client, PMBUS_REVISION) < 0) {
+ dev_err(&client->dev,
+ "Status or revision register not found\n");
+ ret = -ENODEV;
+ goto out_data;
+ }
+
+ if (pdata)
+ data->flags = pdata->flags;
+ data->info = info;
+
+ pmbus_clear_faults(client);
+
+ if (info->identify) {
+ ret = (*info->identify)(client, info);
+ if (ret < 0) {
+ dev_err(&client->dev, "Chip identification failed\n");
+ goto out_data;
+ }
+ }
+
+ if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
+ dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
+ info->pages);
+ ret = -EINVAL;
+ goto out_data;
+ }
+ /*
+ * Bail out if more than one page was configured, but we can not
+ * select the highest page. This is an indication that the wrong
+ * chip type was selected. Better bail out now than keep
+ * returning errors later on.
+ */
+ if (info->pages > 1 && pmbus_set_page(client, info->pages - 1) < 0) {
+ dev_err(&client->dev, "Failed to select page %d\n",
+ info->pages - 1);
+ ret = -EINVAL;
+ goto out_data;
+ }
+
+ ret = pmbus_identify_common(client, data);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to identify chip capabilities\n");
+ goto out_data;
+ }
+
+ ret = -ENOMEM;
+ data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors,
+ GFP_KERNEL);
+ if (!data->sensors) {
+ dev_err(&client->dev, "No memory to allocate sensor data\n");
+ goto out_data;
+ }
+
+ data->booleans = kzalloc(sizeof(struct pmbus_boolean)
+ * data->max_booleans, GFP_KERNEL);
+ if (!data->booleans) {
+ dev_err(&client->dev, "No memory to allocate boolean data\n");
+ goto out_sensors;
+ }
+
+ data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels,
+ GFP_KERNEL);
+ if (!data->labels) {
+ dev_err(&client->dev, "No memory to allocate label data\n");
+ goto out_booleans;
+ }
+
+ data->attributes = kzalloc(sizeof(struct attribute *)
+ * data->max_attributes, GFP_KERNEL);
+ if (!data->attributes) {
+ dev_err(&client->dev, "No memory to allocate attribute data\n");
+ goto out_labels;
+ }
+
+ pmbus_find_attributes(client, data);
+
+ /*
+ * If there are no attributes, something is wrong.
+ * Bail out instead of trying to register nothing.
+ */
+ if (!data->num_attributes) {
+ dev_err(&client->dev, "No attributes found\n");
+ ret = -ENODEV;
+ goto out_attributes;
+ }
+
+ /* Register sysfs hooks */
+ data->group.attrs = data->attributes;
+ ret = sysfs_create_group(&client->dev.kobj, &data->group);
+ if (ret) {
+ dev_err(&client->dev, "Failed to create sysfs entries\n");
+ goto out_attributes;
+ }
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ dev_err(&client->dev, "Failed to register hwmon device\n");
+ goto out_hwmon_device_register;
+ }
+ return 0;
+
+out_hwmon_device_register:
+ sysfs_remove_group(&client->dev.kobj, &data->group);
+out_attributes:
+ kfree(data->attributes);
+out_labels:
+ kfree(data->labels);
+out_booleans:
+ kfree(data->booleans);
+out_sensors:
+ kfree(data->sensors);
+out_data:
+ kfree(data);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_probe);
+
+int pmbus_do_remove(struct i2c_client *client)
+{
+ struct pmbus_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->group);
+ kfree(data->attributes);
+ kfree(data->labels);
+ kfree(data->booleans);
+ kfree(data->sensors);
+ kfree(data);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_remove);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 073eabedc432..f2b377c56a3a 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -1,11 +1,12 @@
/*
w83627ehf - Driver for the hardware monitoring functionality of
- the Winbond W83627EHF Super-I/O chip
+ the Winbond W83627EHF Super-I/O chip
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Copyright (C) 2006 Yuan Mu (Winbond),
- Rudolf Marek <r.marek@assembler.cz>
- David Hubbard <david.c.hubbard@gmail.com>
+ Rudolf Marek <r.marek@assembler.cz>
+ David Hubbard <david.c.hubbard@gmail.com>
Daniel J Blueman <daniel.blueman@gmail.com>
+ Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
Shamelessly ripped from the w83627hf driver
Copyright (C) 2003 Mark Studebaker
@@ -35,11 +36,13 @@
Chip #vin #fan #pwm #temp chip IDs man ID
w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
- 0x8860 0xa1
+ 0x8860 0xa1
w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3
w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3
- w83667hg-b 9 5 3 3 0xb350 0xc1 0x5ca3
+ w83667hg-b 9 5 3 4 0xb350 0xc1 0x5ca3
+ nct6775f 9 4 3 9 0xb470 0xc1 0x5ca3
+ nct6776f 9 5 3 9 0xC330 0xc1 0x5ca3
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -58,21 +61,28 @@
#include <linux/io.h>
#include "lm75.h"
-enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b };
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
+ nct6776 };
/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
-static const char * w83627ehf_device_names[] = {
+static const char * const w83627ehf_device_names[] = {
"w83627ehf",
"w83627dhg",
"w83627dhg",
"w83667hg",
"w83667hg",
+ "nct6775",
+ "nct6776",
};
static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
+static unsigned short fan_debounce;
+module_param(fan_debounce, ushort, 0);
+MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
+
#define DRVNAME "w83627ehf"
/*
@@ -80,7 +90,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
*/
#define W83627EHF_LD_HWM 0x0b
-#define W83667HG_LD_VID 0x0d
+#define W83667HG_LD_VID 0x0d
#define SIO_REG_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
@@ -94,8 +104,10 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
#define SIO_W83627EHG_ID 0x8860
#define SIO_W83627DHG_ID 0xa020
#define SIO_W83627DHG_P_ID 0xb070
-#define SIO_W83667HG_ID 0xa510
+#define SIO_W83667HG_ID 0xa510
#define SIO_W83667HG_B_ID 0xb350
+#define SIO_NCT6775_ID 0xb470
+#define SIO_NCT6776_ID 0xc330
#define SIO_ID_MASK 0xFFF0
static inline void
@@ -138,7 +150,7 @@ superio_exit(int ioreg)
* ISA constants
*/
-#define IOREGION_ALIGNMENT ~7
+#define IOREGION_ALIGNMENT (~7)
#define IOREGION_OFFSET 5
#define IOREGION_LENGTH 2
#define ADDR_REG_OFFSET 0
@@ -164,13 +176,10 @@ static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
#define W83627EHF_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
(0x550 + (nr) - 7))
-#define W83627EHF_REG_TEMP1 0x27
-#define W83627EHF_REG_TEMP1_HYST 0x3a
-#define W83627EHF_REG_TEMP1_OVER 0x39
-static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
-static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
-static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
-static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
+static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
+static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
+static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
+static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
/* Fan clock dividers are spread over the following five registers */
#define W83627EHF_REG_FANDIV1 0x47
@@ -179,6 +188,11 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
#define W83627EHF_REG_DIODE 0x59
#define W83627EHF_REG_SMI_OVT 0x4C
+/* NCT6775F has its own fan divider registers */
+#define NCT6775_REG_FANDIV1 0x506
+#define NCT6775_REG_FANDIV2 0x507
+#define NCT6775_REG_FAN_DEBOUNCE 0xf0
+
#define W83627EHF_REG_ALARM1 0x459
#define W83627EHF_REG_ALARM2 0x45A
#define W83627EHF_REG_ALARM3 0x45B
@@ -199,22 +213,123 @@ static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
/* FAN Duty Cycle, be used to control */
-static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
-static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
/* Advanced Fan control, some values are common for all fans */
-static const u8 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
-static const u8 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
-static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
+static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
+static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
= { 0xff, 0x67, 0xff, 0x69 };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
= { 0xff, 0x68, 0xff, 0x6a };
-static const u8 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
-static const u8 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[] = { 0x68, 0x6a, 0x6c };
+static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
+static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
+ = { 0x68, 0x6a, 0x6c };
+
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
+
+static const u16 NCT6775_REG_TEMP[]
+ = { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
+static const u16 NCT6775_REG_TEMP_CONFIG[]
+ = { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[]
+ = { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[]
+ = { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
+static const u16 NCT6775_REG_TEMP_SOURCE[]
+ = { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
+
+static const char *const w83667hg_b_temp_label[] = {
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN",
+ "AMDTSI",
+ "PECI Agent 1",
+ "PECI Agent 2",
+ "PECI Agent 3",
+ "PECI Agent 4"
+};
+
+static const char *const nct6775_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN",
+ "AMD SB-TSI",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PECI Agent 2",
+ "PECI Agent 3",
+ "PECI Agent 4",
+ "PECI Agent 5",
+ "PECI Agent 6",
+ "PECI Agent 7",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "PCH_DIM0_TEMP",
+ "PCH_DIM1_TEMP",
+ "PCH_DIM2_TEMP",
+ "PCH_DIM3_TEMP"
+};
+
+static const char *const nct6776_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN",
+ "SMBUSMASTER 0",
+ "SMBUSMASTER 1",
+ "SMBUSMASTER 2",
+ "SMBUSMASTER 3",
+ "SMBUSMASTER 4",
+ "SMBUSMASTER 5",
+ "SMBUSMASTER 6",
+ "SMBUSMASTER 7",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "PCH_DIM0_TEMP",
+ "PCH_DIM1_TEMP",
+ "PCH_DIM2_TEMP",
+ "PCH_DIM3_TEMP",
+ "BYTE_TEMP"
+};
+
+#define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP)
+
+static inline int is_word_sized(u16 reg)
+{
+ return ((((reg & 0xff00) == 0x100
+ || (reg & 0xff00) == 0x200)
+ && ((reg & 0x00ff) == 0x50
+ || (reg & 0x00ff) == 0x53
+ || (reg & 0x00ff) == 0x55))
+ || (reg & 0xfff0) == 0x630
+ || reg == 0x640 || reg == 0x642
+ || ((reg & 0xfff0) == 0x650
+ && (reg & 0x000f) >= 0x06)
+ || reg == 0x73 || reg == 0x75 || reg == 0x77
+ );
+}
/*
* Conversions
@@ -232,12 +347,36 @@ static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
(msec + 200) / 400), 1, 255);
}
-static inline unsigned int
-fan_from_reg(u8 reg, unsigned int div)
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
{
if (reg == 0 || reg == 255)
return 0;
- return 1350000U / (reg * div);
+ return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+ if ((reg & 0xff1f) == 0xff1f)
+ return 0;
+
+ reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+ if (reg == 0)
+ return 0;
+
+ return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
+
+ /*
+ * Even though the registers are 16 bit wide, the fan divisor
+ * still applies.
+ */
+ return 1350000U / (reg << divreg);
}
static inline unsigned int
@@ -247,21 +386,19 @@ div_from_reg(u8 reg)
}
static inline int
-temp1_from_reg(s8 reg)
+temp_from_reg(u16 reg, s16 regval)
{
- return reg * 1000;
+ if (is_word_sized(reg))
+ return LM75_TEMP_FROM_REG(regval);
+ return regval * 1000;
}
-static inline s8
-temp1_to_reg(long temp, int min, int max)
+static inline u16
+temp_to_reg(u16 reg, long temp)
{
- if (temp <= min)
- return min / 1000;
- if (temp >= max)
- return max / 1000;
- if (temp < 0)
- return (temp - 500) / 1000;
- return (temp + 500) / 1000;
+ if (is_word_sized(reg))
+ return LM75_TEMP_TO_REG(temp);
+ return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
}
/* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
@@ -275,7 +412,8 @@ static inline long in_from_reg(u8 reg, u8 nr)
static inline u8 in_to_reg(u32 val, u8 nr)
{
- return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0, 255);
+ return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
+ 255);
}
/*
@@ -289,38 +427,57 @@ struct w83627ehf_data {
struct device *hwmon_dev;
struct mutex lock;
- const u8 *REG_FAN_START_OUTPUT;
- const u8 *REG_FAN_STOP_OUTPUT;
- const u8 *REG_FAN_MAX_OUTPUT;
- const u8 *REG_FAN_STEP_OUTPUT;
+ u16 reg_temp[NUM_REG_TEMP];
+ u16 reg_temp_over[NUM_REG_TEMP];
+ u16 reg_temp_hyst[NUM_REG_TEMP];
+ u16 reg_temp_config[NUM_REG_TEMP];
+ u8 temp_src[NUM_REG_TEMP];
+ const char * const *temp_label;
+
+ const u16 *REG_PWM;
+ const u16 *REG_TARGET;
+ const u16 *REG_FAN;
+ const u16 *REG_FAN_MIN;
+ const u16 *REG_FAN_START_OUTPUT;
+ const u16 *REG_FAN_STOP_OUTPUT;
+ const u16 *REG_FAN_STOP_TIME;
+ const u16 *REG_FAN_MAX_OUTPUT;
+ const u16 *REG_FAN_STEP_OUTPUT;
+
+ unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+ unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
/* Register values */
+ u8 bank; /* current register bank */
u8 in_num; /* number of in inputs we have */
u8 in[10]; /* Register value */
u8 in_max[10]; /* Register value */
u8 in_min[10]; /* Register value */
- u8 fan[5];
- u8 fan_min[5];
+ unsigned int rpm[5];
+ u16 fan_min[5];
u8 fan_div[5];
u8 has_fan; /* some fan inputs can be disabled */
+ u8 has_fan_min; /* some fans don't have min register */
+ bool has_fan_div;
u8 temp_type[3];
- s8 temp1;
- s8 temp1_max;
- s8 temp1_max_hyst;
- s16 temp[2];
- s16 temp_max[2];
- s16 temp_max_hyst[2];
+ s16 temp[9];
+ s16 temp_max[9];
+ s16 temp_max_hyst[9];
u32 alarms;
u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
u8 pwm_enable[4]; /* 1->manual
2->thermal cruise mode (also called SmartFan I)
3->fan speed cruise mode
- 4->variable thermal cruise (also called SmartFan III) */
+ 4->variable thermal cruise (also called
+ SmartFan III)
+ 5->enhanced variable thermal cruise (also called
+ SmartFan IV) */
+ u8 pwm_enable_orig[4]; /* original value of pwm_enable */
u8 pwm_num; /* number of pwm */
u8 pwm[4];
u8 target_temp[4];
@@ -335,7 +492,7 @@ struct w83627ehf_data {
u8 vid;
u8 vrm;
- u8 temp3_disable;
+ u16 have_temp;
u8 in6_skip;
};
@@ -344,30 +501,19 @@ struct w83627ehf_sio_data {
enum kinds kind;
};
-static inline int is_word_sized(u16 reg)
-{
- return (((reg & 0xff00) == 0x100
- || (reg & 0xff00) == 0x200)
- && ((reg & 0x00ff) == 0x50
- || (reg & 0x00ff) == 0x53
- || (reg & 0x00ff) == 0x55));
-}
-
-/* Registers 0x50-0x5f are banked */
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
{
- if ((reg & 0x00f0) == 0x50) {
+ u8 bank = reg >> 8;
+ if (data->bank != bank) {
outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
- outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
- }
-}
-
-/* Not strictly necessary, but play it safe for now */
-static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
-{
- if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
- outb_p(0, data->addr + DATA_REG_OFFSET);
+ outb_p(bank, data->addr + DATA_REG_OFFSET);
+ data->bank = bank;
}
}
@@ -385,14 +531,13 @@ static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
data->addr + ADDR_REG_OFFSET);
res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
}
- w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
-
return res;
}
-static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
+ u16 value)
{
int word_sized = is_word_sized(reg);
@@ -406,13 +551,40 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value
data->addr + ADDR_REG_OFFSET);
}
outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
- w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return 0;
}
/* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
+{
+ u8 reg;
+
+ switch (nr) {
+ case 0:
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+ | (data->fan_div[0] & 0x7);
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+ break;
+ case 1:
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+ | ((data->fan_div[1] << 4) & 0x70);
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
+ case 2:
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+ | (data->fan_div[2] & 0x7);
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+ break;
+ case 3:
+ reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+ | ((data->fan_div[3] << 4) & 0x70);
+ w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
+ break;
+ }
+}
+
+/* This function assumes that the caller holds data->update_lock */
static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
{
u8 reg;
@@ -463,6 +635,32 @@ static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
}
}
+static void w83627ehf_write_fan_div_common(struct device *dev,
+ struct w83627ehf_data *data, int nr)
+{
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+ if (sio_data->kind == nct6776)
+ ; /* no dividers, do nothing */
+ else if (sio_data->kind == nct6775)
+ nct6775_write_fan_div(data, nr);
+ else
+ w83627ehf_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct w83627ehf_data *data)
+{
+ u8 i;
+
+ i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+ data->fan_div[0] = i & 0x7;
+ data->fan_div[1] = (i & 0x70) >> 4;
+ i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+ data->fan_div[2] = i & 0x7;
+ if (data->has_fan & (1<<3))
+ data->fan_div[3] = (i & 0x70) >> 4;
+}
+
static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
{
int i;
@@ -488,10 +686,79 @@ static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
}
}
+static void w83627ehf_update_fan_div_common(struct device *dev,
+ struct w83627ehf_data *data)
+{
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+ if (sio_data->kind == nct6776)
+ ; /* no dividers, do nothing */
+ else if (sio_data->kind == nct6775)
+ nct6775_update_fan_div(data);
+ else
+ w83627ehf_update_fan_div(data);
+}
+
+static void nct6775_update_pwm(struct w83627ehf_data *data)
+{
+ int i;
+ int pwmcfg, fanmodecfg;
+
+ for (i = 0; i < data->pwm_num; i++) {
+ pwmcfg = w83627ehf_read_value(data,
+ W83627EHF_REG_PWM_ENABLE[i]);
+ fanmodecfg = w83627ehf_read_value(data,
+ NCT6775_REG_FAN_MODE[i]);
+ data->pwm_mode[i] =
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+ data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
+ data->tolerance[i] = fanmodecfg & 0x0f;
+ data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+ }
+}
+
+static void w83627ehf_update_pwm(struct w83627ehf_data *data)
+{
+ int i;
+ int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+
+ for (i = 0; i < data->pwm_num; i++) {
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
+ /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
+ if (i != 1) {
+ pwmcfg = w83627ehf_read_value(data,
+ W83627EHF_REG_PWM_ENABLE[i]);
+ tolerance = w83627ehf_read_value(data,
+ W83627EHF_REG_TOLERANCE[i]);
+ }
+ data->pwm_mode[i] =
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
+ data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+ & 3) + 1;
+ data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
+
+ data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
+ }
+}
+
+static void w83627ehf_update_pwm_common(struct device *dev,
+ struct w83627ehf_data *data)
+{
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
+ nct6775_update_pwm(data);
+ else
+ w83627ehf_update_pwm(data);
+}
+
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
- int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
int i;
mutex_lock(&data->update_lock);
@@ -499,7 +766,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ/2)
|| !data->valid) {
/* Fan clock dividers */
- w83627ehf_update_fan_div(data);
+ w83627ehf_update_fan_div_common(dev, data);
/* Measured voltages and limits */
for (i = 0; i < data->in_num; i++) {
@@ -513,92 +780,90 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
/* Measured fan speeds and limits */
for (i = 0; i < 5; i++) {
+ u16 reg;
+
if (!(data->has_fan & (1 << i)))
continue;
- data->fan[i] = w83627ehf_read_value(data,
- W83627EHF_REG_FAN[i]);
- data->fan_min[i] = w83627ehf_read_value(data,
- W83627EHF_REG_FAN_MIN[i]);
+ reg = w83627ehf_read_value(data, data->REG_FAN[i]);
+ data->rpm[i] = data->fan_from_reg(reg,
+ data->fan_div[i]);
+
+ if (data->has_fan_min & (1 << i))
+ data->fan_min[i] = w83627ehf_read_value(data,
+ data->REG_FAN_MIN[i]);
/* If we failed to measure the fan speed and clock
divider can be increased, let's try that for next
time */
- if (data->fan[i] == 0xff
- && data->fan_div[i] < 0x07) {
- dev_dbg(dev, "Increasing fan%d "
+ if (data->has_fan_div
+ && (reg >= 0xff || (sio_data->kind == nct6775
+ && reg == 0x00))
+ && data->fan_div[i] < 0x07) {
+ dev_dbg(dev, "Increasing fan%d "
"clock divider from %u to %u\n",
i + 1, div_from_reg(data->fan_div[i]),
div_from_reg(data->fan_div[i] + 1));
data->fan_div[i]++;
- w83627ehf_write_fan_div(data, i);
+ w83627ehf_write_fan_div_common(dev, data, i);
/* Preserve min limit if possible */
- if (data->fan_min[i] >= 2
+ if ((data->has_fan_min & (1 << i))
+ && data->fan_min[i] >= 2
&& data->fan_min[i] != 255)
w83627ehf_write_value(data,
- W83627EHF_REG_FAN_MIN[i],
+ data->REG_FAN_MIN[i],
(data->fan_min[i] /= 2));
}
}
+ w83627ehf_update_pwm_common(dev, data);
+
for (i = 0; i < data->pwm_num; i++) {
if (!(data->has_fan & (1 << i)))
continue;
- /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
- if (i != 1) {
- pwmcfg = w83627ehf_read_value(data,
- W83627EHF_REG_PWM_ENABLE[i]);
- tolerance = w83627ehf_read_value(data,
- W83627EHF_REG_TOLERANCE[i]);
- }
- data->pwm_mode[i] =
- ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
- ? 0 : 1;
- data->pwm_enable[i] =
- ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
- & 3) + 1;
- data->pwm[i] = w83627ehf_read_value(data,
- W83627EHF_REG_PWM[i]);
- data->fan_start_output[i] = w83627ehf_read_value(data,
- W83627EHF_REG_FAN_START_OUTPUT[i]);
- data->fan_stop_output[i] = w83627ehf_read_value(data,
- W83627EHF_REG_FAN_STOP_OUTPUT[i]);
- data->fan_stop_time[i] = w83627ehf_read_value(data,
- W83627EHF_REG_FAN_STOP_TIME[i]);
-
- if (data->REG_FAN_MAX_OUTPUT[i] != 0xff)
+ data->fan_start_output[i] =
+ w83627ehf_read_value(data,
+ data->REG_FAN_START_OUTPUT[i]);
+ data->fan_stop_output[i] =
+ w83627ehf_read_value(data,
+ data->REG_FAN_STOP_OUTPUT[i]);
+ data->fan_stop_time[i] =
+ w83627ehf_read_value(data,
+ data->REG_FAN_STOP_TIME[i]);
+
+ if (data->REG_FAN_MAX_OUTPUT &&
+ data->REG_FAN_MAX_OUTPUT[i] != 0xff)
data->fan_max_output[i] =
w83627ehf_read_value(data,
- data->REG_FAN_MAX_OUTPUT[i]);
+ data->REG_FAN_MAX_OUTPUT[i]);
- if (data->REG_FAN_STEP_OUTPUT[i] != 0xff)
+ if (data->REG_FAN_STEP_OUTPUT &&
+ data->REG_FAN_STEP_OUTPUT[i] != 0xff)
data->fan_step_output[i] =
w83627ehf_read_value(data,
- data->REG_FAN_STEP_OUTPUT[i]);
+ data->REG_FAN_STEP_OUTPUT[i]);
data->target_temp[i] =
w83627ehf_read_value(data,
- W83627EHF_REG_TARGET[i]) &
+ data->REG_TARGET[i]) &
(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
- data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
- & 0x0f;
}
/* Measured temperatures and limits */
- data->temp1 = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP1);
- data->temp1_max = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP1_OVER);
- data->temp1_max_hyst = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP1_HYST);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < NUM_REG_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
data->temp[i] = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP[i]);
- data->temp_max[i] = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP_OVER[i]);
- data->temp_max_hyst[i] = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP_HYST[i]);
+ data->reg_temp[i]);
+ if (data->reg_temp_over[i])
+ data->temp_max[i]
+ = w83627ehf_read_value(data,
+ data->reg_temp_over[i]);
+ if (data->reg_temp_hyst[i])
+ data->temp_max_hyst[i]
+ = w83627ehf_read_value(data,
+ data->reg_temp_hyst[i]);
}
data->alarms = w83627ehf_read_value(data,
@@ -625,7 +890,8 @@ show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
}
@@ -635,14 +901,18 @@ show_in_reg(in_max)
#define store_in_reg(REG, reg) \
static ssize_t \
-store_in_##reg (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
+store_in_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- u32 val = simple_strtoul(buf, NULL, 10); \
- \
+ unsigned long val; \
+ int err; \
+ err = strict_strtoul(buf, 10, &val); \
+ if (err < 0) \
+ return err; \
mutex_lock(&data->update_lock); \
data->in_##reg[nr] = in_to_reg(val, nr); \
w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
@@ -654,7 +924,8 @@ store_in_##reg (struct device *dev, struct device_attribute *attr, \
store_in_reg(MIN, min)
store_in_reg(MAX, max)
-static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct w83627ehf_data *data = w83627ehf_update_device(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
@@ -689,45 +960,50 @@ static struct sensor_device_attribute sda_in_alarm[] = {
};
static struct sensor_device_attribute sda_in_min[] = {
- SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
- SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
- SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
- SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
- SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
- SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
- SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
- SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
- SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
- SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
+ SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
+ SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
+ SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
+ SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
+ SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
+ SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
+ SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
+ SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
+ SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
+ SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
};
static struct sensor_device_attribute sda_in_max[] = {
- SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
- SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
- SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
- SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
- SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
- SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
- SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
- SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
- SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
- SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
+ SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
+ SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
+ SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
+ SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
+ SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
+ SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
+ SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
+ SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
+ SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
};
-#define show_fan_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
- int nr = sensor_attr->index; \
- return sprintf(buf, "%d\n", \
- fan_from_reg(data->reg[nr], \
- div_from_reg(data->fan_div[nr]))); \
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%d\n", data->rpm[nr]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%d\n",
+ data->fan_from_reg_min(data->fan_min[nr],
+ data->fan_div[nr]));
}
-show_fan_reg(fan);
-show_fan_reg(fan_min);
static ssize_t
show_fan_div(struct device *dev, struct device_attribute *attr,
@@ -746,11 +1022,32 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- unsigned int val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+ int err;
unsigned int reg;
u8 new_div;
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
mutex_lock(&data->update_lock);
+ if (!data->has_fan_div) {
+ /*
+ * Only NCT6776F for now, so we know that this is a 13 bit
+ * register
+ */
+ if (!val) {
+ val = 0xff1f;
+ } else {
+ if (val > 1350000U)
+ val = 135000U;
+ val = 1350000U / val;
+ val = (val & 0x1f) | ((val << 3) & 0xff00);
+ }
+ data->fan_min[nr] = val;
+ goto done; /* Leave fan divider alone */
+ }
if (!val) {
/* No min limit, alarm disabled */
data->fan_min[nr] = 255;
@@ -761,15 +1058,17 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
even with the highest divider (128) */
data->fan_min[nr] = 254;
new_div = 7; /* 128 == (1 << 7) */
- dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
- "minimum\n", nr + 1, val, fan_from_reg(254, 128));
+ dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
+ "minimum\n", nr + 1, val,
+ data->fan_from_reg_min(254, 7));
} else if (!reg) {
/* Speed above this value cannot possibly be represented,
even with the lowest divider (1) */
data->fan_min[nr] = 1;
new_div = 0; /* 1 == (1 << 0) */
- dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
- "maximum\n", nr + 1, val, fan_from_reg(1, 1));
+ dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
+ "maximum\n", nr + 1, val,
+ data->fan_from_reg_min(1, 0));
} else {
/* Automatically pick the best divider, i.e. the one such
that the min limit will correspond to a register value
@@ -785,25 +1084,16 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
/* Write both the fan clock divider (if it changed) and the new
fan min (unconditionally) */
if (new_div != data->fan_div[nr]) {
- /* Preserve the fan speed reading */
- if (data->fan[nr] != 0xff) {
- if (new_div > data->fan_div[nr])
- data->fan[nr] >>= new_div - data->fan_div[nr];
- else if (data->fan[nr] & 0x80)
- data->fan[nr] = 0xff;
- else
- data->fan[nr] <<= data->fan_div[nr] - new_div;
- }
-
dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
nr + 1, div_from_reg(data->fan_div[nr]),
div_from_reg(new_div));
data->fan_div[nr] = new_div;
- w83627ehf_write_fan_div(data, nr);
+ w83627ehf_write_fan_div_common(dev, data, nr);
/* Give the chip time to sample a new speed value */
data->last_updated = jiffies;
}
- w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
+done:
+ w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
data->fan_min[nr]);
mutex_unlock(&data->update_lock);
@@ -847,70 +1137,54 @@ static struct sensor_device_attribute sda_fan_div[] = {
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
};
-#define show_temp1_reg(reg) \
-static ssize_t \
-show_##reg(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
-}
-show_temp1_reg(temp1);
-show_temp1_reg(temp1_max);
-show_temp1_reg(temp1_max_hyst);
-
-#define store_temp1_reg(REG, reg) \
-static ssize_t \
-store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct w83627ehf_data *data = dev_get_drvdata(dev); \
- long val = simple_strtol(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
- w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
- data->temp1_##reg); \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
}
-store_temp1_reg(OVER, max);
-store_temp1_reg(HYST, max_hyst);
-#define show_temp_reg(reg) \
+#define show_temp_reg(addr, reg) \
static ssize_t \
show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
return sprintf(buf, "%d\n", \
- LM75_TEMP_FROM_REG(data->reg[nr])); \
+ temp_from_reg(data->addr[nr], data->reg[nr])); \
}
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
+show_temp_reg(reg_temp, temp);
+show_temp_reg(reg_temp_over, temp_max);
+show_temp_reg(reg_temp_hyst, temp_max_hyst);
-#define store_temp_reg(REG, reg) \
+#define store_temp_reg(addr, reg) \
static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- long val = simple_strtol(buf, NULL, 10); \
- \
+ int err; \
+ long val; \
+ err = strict_strtol(buf, 10, &val); \
+ if (err < 0) \
+ return err; \
mutex_lock(&data->update_lock); \
- data->reg[nr] = LM75_TEMP_TO_REG(val); \
- w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
+ data->reg[nr] = temp_to_reg(data->addr[nr], val); \
+ w83627ehf_write_value(data, data->addr[nr], \
data->reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
}
-store_temp_reg(OVER, temp_max);
-store_temp_reg(HYST, temp_max_hyst);
+store_temp_reg(reg_temp_over, temp_max);
+store_temp_reg(reg_temp_hyst, temp_max_hyst);
static ssize_t
show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
@@ -922,27 +1196,69 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
}
static struct sensor_device_attribute sda_temp_input[] = {
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1),
+ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+ SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
+ SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
+ SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
+ SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
+ SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
+ SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+ SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+ SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+ SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+ SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+ SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+ SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+ SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+ SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+ SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
};
static struct sensor_device_attribute sda_temp_max[] = {
- SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max,
- store_temp1_max, 0),
- SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+ SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
store_temp_max, 0),
- SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+ SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
store_temp_max, 1),
+ SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 2),
+ SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 3),
+ SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 4),
+ SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 5),
+ SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 6),
+ SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 7),
+ SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
+ store_temp_max, 8),
};
static struct sensor_device_attribute sda_temp_max_hyst[] = {
- SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst,
- store_temp1_max_hyst, 0),
- SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
store_temp_max_hyst, 0),
- SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
store_temp_max_hyst, 1),
+ SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 2),
+ SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 3),
+ SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 4),
+ SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 5),
+ SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 6),
+ SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 7),
+ SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 8),
};
static struct sensor_device_attribute sda_temp_alarm[] = {
@@ -958,11 +1274,12 @@ static struct sensor_device_attribute sda_temp_type[] = {
};
#define show_pwm_reg(reg) \
-static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
- char *buf) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
return sprintf(buf, "%d\n", data->reg[nr]); \
}
@@ -978,9 +1295,14 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- u32 val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+ int err;
u16 reg;
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
if (val > 1)
return -EINVAL;
mutex_lock(&data->update_lock);
@@ -1001,11 +1323,18 @@ store_pwm(struct device *dev, struct device_attribute *attr,
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+ unsigned long val;
+ int err;
+
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm[nr] = val;
- w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
+ w83627ehf_write_value(data, data->REG_PWM[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1015,19 +1344,38 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- u32 val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+ int err;
u16 reg;
- if (!val || (val > 4))
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
return -EINVAL;
+ /* SmartFan III mode is not supported on NCT6776F */
+ if (sio_data->kind == nct6776 && val == 4)
+ return -EINVAL;
+
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
data->pwm_enable[nr] = val;
- reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
- reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
- w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+ reg = w83627ehf_read_value(data,
+ NCT6775_REG_FAN_MODE[nr]);
+ reg &= 0x0f;
+ reg |= (val - 1) << 4;
+ w83627ehf_write_value(data,
+ NCT6775_REG_FAN_MODE[nr], reg);
+ } else {
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
+ reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+ reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ }
mutex_unlock(&data->update_lock);
return count;
}
@@ -1038,9 +1386,10 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
+ return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
}
show_tol_temp(tolerance)
@@ -1053,11 +1402,18 @@ store_target_temp(struct device *dev, struct device_attribute *attr,
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
+ long val;
+ int err;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
mutex_lock(&data->update_lock);
data->target_temp[nr] = val;
- w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
+ w83627ehf_write_value(data, data->REG_TARGET[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1067,20 +1423,37 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u16 reg;
+ long val;
+ int err;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
/* Limit the temp to 0C - 15C */
- u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
+ val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
- data->tolerance[nr] = val;
- if (nr == 1)
- reg = (reg & 0x0f) | (val << 4);
- else
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+ /* Limit tolerance further for NCT6776F */
+ if (sio_data->kind == nct6776 && val > 7)
+ val = 7;
+ reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
reg = (reg & 0xf0) | val;
- w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+ w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
+ } else {
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
+ if (nr == 1)
+ reg = (reg & 0x0f) | (val << 4);
+ else
+ reg = (reg & 0xf0) | val;
+ w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
+ }
+ data->tolerance[nr] = val;
mutex_unlock(&data->update_lock);
return count;
}
@@ -1143,18 +1516,25 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
return sprintf(buf, "%d\n", data->reg[nr]); \
-}\
+} \
static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
-{\
+{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
+ unsigned long val; \
+ int err; \
+ err = strict_strtoul(buf, 10, &val); \
+ if (err < 0) \
+ return err; \
+ val = SENSORS_LIMIT(val, 1, 255); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
w83627ehf_write_value(data, data->REG_##REG[nr], val); \
@@ -1172,10 +1552,12 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
return sprintf(buf, "%d\n", \
- step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
+ step_time_from_reg(data->reg[nr], \
+ data->pwm_mode[nr])); \
} \
\
static ssize_t \
@@ -1183,10 +1565,15 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ struct sensor_device_attribute *sensor_attr = \
+ to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
- data->pwm_mode[nr]); \
+ unsigned long val; \
+ int err; \
+ err = strict_strtoul(buf, 10, &val); \
+ if (err < 0) \
+ return err; \
+ val = step_time_to_reg(val, data->pwm_mode[nr]); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
@@ -1283,7 +1670,8 @@ static void w83627ehf_device_remove_files(struct device *dev)
for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
struct sensor_device_attribute *attr =
&sda_sf3_max_step_arrays[i];
- if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
+ if (data->REG_FAN_STEP_OUTPUT &&
+ data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
device_remove_file(dev, &attr->dev_attr);
}
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
@@ -1309,12 +1697,15 @@ static void w83627ehf_device_remove_files(struct device *dev)
device_remove_file(dev, &sda_target_temp[i].dev_attr);
device_remove_file(dev, &sda_tolerance[i].dev_attr);
}
- for (i = 0; i < 3; i++) {
- if ((i == 2) && data->temp3_disable)
+ for (i = 0; i < NUM_REG_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
continue;
device_remove_file(dev, &sda_temp_input[i].dev_attr);
+ device_remove_file(dev, &sda_temp_label[i].dev_attr);
device_remove_file(dev, &sda_temp_max[i].dev_attr);
device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+ if (i > 2)
+ continue;
device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
device_remove_file(dev, &sda_temp_type[i].dev_attr);
}
@@ -1335,15 +1726,17 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
tmp | 0x01);
- /* Enable temp2 and temp3 if needed */
- for (i = 0; i < 2; i++) {
- tmp = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP_CONFIG[i]);
- if ((i == 1) && data->temp3_disable)
+ /* Enable temperature sensors if needed */
+ for (i = 0; i < NUM_REG_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ if (!data->reg_temp_config[i])
continue;
+ tmp = w83627ehf_read_value(data,
+ data->reg_temp_config[i]);
if (tmp & 0x01)
w83627ehf_write_value(data,
- W83627EHF_REG_TEMP_CONFIG[i],
+ data->reg_temp_config[i],
tmp & 0xfe);
}
@@ -1362,13 +1755,39 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
}
}
+static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
+ int r1, int r2)
+{
+ u16 tmp;
+
+ tmp = data->temp_src[r1];
+ data->temp_src[r1] = data->temp_src[r2];
+ data->temp_src[r2] = tmp;
+
+ tmp = data->reg_temp[r1];
+ data->reg_temp[r1] = data->reg_temp[r2];
+ data->reg_temp[r2] = tmp;
+
+ tmp = data->reg_temp_over[r1];
+ data->reg_temp_over[r1] = data->reg_temp_over[r2];
+ data->reg_temp_over[r2] = tmp;
+
+ tmp = data->reg_temp_hyst[r1];
+ data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
+ data->reg_temp_hyst[r2] = tmp;
+
+ tmp = data->reg_temp_config[r1];
+ data->reg_temp_config[r1] = data->reg_temp_config[r2];
+ data->reg_temp_config[r2] = tmp;
+}
+
static int __devinit w83627ehf_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct w83627ehf_data *data;
struct resource *res;
- u8 fan4pin, fan5pin, en_vrm10;
+ u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
int i, err = 0;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1380,7 +1799,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
goto exit;
}
- if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
+ data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
+ if (!data) {
err = -ENOMEM;
goto exit_release;
}
@@ -1393,25 +1813,202 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
- /* 667HG has 3 pwms */
+ /* 667HG, NCT6775F, and NCT6776F have 3 pwms */
data->pwm_num = (sio_data->kind == w83667hg
- || sio_data->kind == w83667hg_b) ? 3 : 4;
+ || sio_data->kind == w83667hg_b
+ || sio_data->kind == nct6775
+ || sio_data->kind == nct6776) ? 3 : 4;
+ data->have_temp = 0x07;
/* Check temp3 configuration bit for 667HG */
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
- data->temp3_disable = w83627ehf_read_value(data,
- W83627EHF_REG_TEMP_CONFIG[1]) & 0x01;
- data->in6_skip = !data->temp3_disable;
+ if (sio_data->kind == w83667hg) {
+ u8 reg;
+
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+ if (reg & 0x01)
+ data->have_temp &= ~(1 << 2);
+ else
+ data->in6_skip = 1; /* either temp3 or in6 */
+ }
+
+ /* Deal with temperature register setup first. */
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+ int mask = 0;
+
+ /*
+ * Display temperature sensor output only if it monitors
+ * a source other than one already reported. Always display
+ * first three temperature registers, though.
+ */
+ for (i = 0; i < NUM_REG_TEMP; i++) {
+ u8 src;
+
+ data->reg_temp[i] = NCT6775_REG_TEMP[i];
+ data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
+ data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
+ data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
+
+ src = w83627ehf_read_value(data,
+ NCT6775_REG_TEMP_SOURCE[i]);
+ src &= 0x1f;
+ if (src && !(mask & (1 << src))) {
+ data->have_temp |= 1 << i;
+ mask |= 1 << src;
+ }
+
+ data->temp_src[i] = src;
+
+ /*
+ * Now do some register swapping if index 0..2 don't
+ * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
+ * Idea is to have the first three attributes
+ * report SYSTIN, CPUIN, and AUXIN if possible
+ * without overriding the basic system configuration.
+ */
+ if (i > 0 && data->temp_src[0] != 1
+ && data->temp_src[i] == 1)
+ w82627ehf_swap_tempreg(data, 0, i);
+ if (i > 1 && data->temp_src[1] != 2
+ && data->temp_src[i] == 2)
+ w82627ehf_swap_tempreg(data, 1, i);
+ if (i > 2 && data->temp_src[2] != 3
+ && data->temp_src[i] == 3)
+ w82627ehf_swap_tempreg(data, 2, i);
+ }
+ if (sio_data->kind == nct6776) {
+ /*
+ * On NCT6776, AUXTIN and VIN3 pins are shared.
+ * Only way to detect it is to check if AUXTIN is used
+ * as a temperature source, and if that source is
+ * enabled.
+ *
+ * If that is the case, disable in6, which reports VIN3.
+ * Otherwise disable temp3.
+ */
+ if (data->temp_src[2] == 3) {
+ u8 reg;
+
+ if (data->reg_temp_config[2])
+ reg = w83627ehf_read_value(data,
+ data->reg_temp_config[2]);
+ else
+ reg = 0; /* Assume AUXTIN is used */
+
+ if (reg & 0x01)
+ data->have_temp &= ~(1 << 2);
+ else
+ data->in6_skip = 1;
+ }
+ data->temp_label = nct6776_temp_label;
+ } else {
+ data->temp_label = nct6775_temp_label;
+ }
+ } else if (sio_data->kind == w83667hg_b) {
+ u8 reg;
+
+ /*
+ * Temperature sources are selected with bank 0, registers 0x49
+ * and 0x4a.
+ */
+ for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
+ data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+ data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+ data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+ data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+ }
+ reg = w83627ehf_read_value(data, 0x4a);
+ data->temp_src[0] = reg >> 5;
+ reg = w83627ehf_read_value(data, 0x49);
+ data->temp_src[1] = reg & 0x07;
+ data->temp_src[2] = (reg >> 4) & 0x07;
+
+ /*
+ * W83667HG-B has another temperature register at 0x7e.
+ * The temperature source is selected with register 0x7d.
+ * Support it if the source differs from already reported
+ * sources.
+ */
+ reg = w83627ehf_read_value(data, 0x7d);
+ reg &= 0x07;
+ if (reg != data->temp_src[0] && reg != data->temp_src[1]
+ && reg != data->temp_src[2]) {
+ data->temp_src[3] = reg;
+ data->have_temp |= 1 << 3;
+ }
+
+ /*
+ * Chip supports either AUXTIN or VIN3. Try to find out which
+ * one.
+ */
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
+ if (data->temp_src[2] == 2 && (reg & 0x01))
+ data->have_temp &= ~(1 << 2);
+
+ if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
+ || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
+ data->in6_skip = 1;
+
+ data->temp_label = w83667hg_b_temp_label;
+ } else {
+ /* Temperature sources are fixed */
+ for (i = 0; i < 3; i++) {
+ data->reg_temp[i] = W83627EHF_REG_TEMP[i];
+ data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
+ data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
+ data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
+ }
}
- data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
- data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
- if (sio_data->kind == w83667hg_b) {
+ if (sio_data->kind == nct6775) {
+ data->has_fan_div = true;
+ data->fan_from_reg = fan_from_reg16;
+ data->fan_from_reg_min = fan_from_reg8;
+ data->REG_PWM = NCT6775_REG_PWM;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6775_REG_FAN;
+ data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+ data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
+ data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
+ } else if (sio_data->kind == nct6776) {
+ data->has_fan_div = false;
+ data->fan_from_reg = fan_from_reg13;
+ data->fan_from_reg_min = fan_from_reg13;
+ data->REG_PWM = NCT6775_REG_PWM;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6775_REG_FAN;
+ data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+ data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
+ } else if (sio_data->kind == w83667hg_b) {
+ data->has_fan_div = true;
+ data->fan_from_reg = fan_from_reg8;
+ data->fan_from_reg_min = fan_from_reg8;
+ data->REG_PWM = W83627EHF_REG_PWM;
+ data->REG_TARGET = W83627EHF_REG_TARGET;
+ data->REG_FAN = W83627EHF_REG_FAN;
+ data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+ data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+ data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+ data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
data->REG_FAN_MAX_OUTPUT =
W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
data->REG_FAN_STEP_OUTPUT =
W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
} else {
+ data->has_fan_div = true;
+ data->fan_from_reg = fan_from_reg8;
+ data->fan_from_reg_min = fan_from_reg8;
+ data->REG_PWM = W83627EHF_REG_PWM;
+ data->REG_TARGET = W83627EHF_REG_TARGET;
+ data->REG_FAN = W83627EHF_REG_FAN;
+ data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
+ data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
+ data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
+ data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
data->REG_FAN_MAX_OUTPUT =
W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
data->REG_FAN_STEP_OUTPUT =
@@ -1424,7 +2021,8 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
data->vrm = vid_which_vrm();
superio_enter(sio_data->sioreg);
/* Read VID value */
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+ if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
+ sio_data->kind == nct6775 || sio_data->kind == nct6776) {
/* W83667HG has different pins for VID input and output, so
we can get the VID input values directly at logical device D
0xe3. */
@@ -1475,13 +2073,44 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
}
/* fan4 and fan5 share some pins with the GPIO and serial flash */
- if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
- fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+ if (sio_data->kind == nct6775) {
+ /* On NCT6775, fan4 shares pins with the fdc interface */
+ fan3pin = 1;
+ fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+ fan4min = 0;
+ fan5pin = 0;
+ } else if (sio_data->kind == nct6776) {
+ fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+ fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
+ fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
+ fan4min = fan4pin;
+ } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
+ fan3pin = 1;
fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
+ fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
+ fan4min = fan4pin;
} else {
- fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+ fan3pin = 1;
fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
+ fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
+ fan4min = fan4pin;
}
+
+ if (fan_debounce &&
+ (sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
+ u8 tmp;
+
+ superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+ tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE);
+ if (sio_data->kind == nct6776)
+ superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
+ 0x3e | tmp);
+ else
+ superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
+ 0x1e | tmp);
+ pr_info("Enabled fan debounce for chip %s\n", data->name);
+ }
+
superio_exit(sio_data->sioreg);
/* It looks like fan4 and fan5 pins can be alternatively used
@@ -1490,26 +2119,54 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
connected fan5 as input unless they are emitting log 1, which
is not the default. */
- data->has_fan = 0x07; /* fan1, fan2 and fan3 */
- i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
- if ((i & (1 << 2)) && fan4pin)
- data->has_fan |= (1 << 3);
- if (!(i & (1 << 1)) && fan5pin)
- data->has_fan |= (1 << 4);
+ data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+
+ data->has_fan |= (fan3pin << 2);
+ data->has_fan_min |= (fan3pin << 2);
+
+ /*
+ * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
+ */
+ if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
+ data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+ data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+ } else {
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+ if ((i & (1 << 2)) && fan4pin) {
+ data->has_fan |= (1 << 3);
+ data->has_fan_min |= (1 << 3);
+ }
+ if (!(i & (1 << 1)) && fan5pin) {
+ data->has_fan |= (1 << 4);
+ data->has_fan_min |= (1 << 4);
+ }
+ }
/* Read fan clock dividers immediately */
- w83627ehf_update_fan_div(data);
+ w83627ehf_update_fan_div_common(dev, data);
+
+ /* Read pwm data to save original values */
+ w83627ehf_update_pwm_common(dev, data);
+ for (i = 0; i < data->pwm_num; i++)
+ data->pwm_enable_orig[i] = data->pwm_enable[i];
+
+ /* Read pwm data to save original values */
+ w83627ehf_update_pwm_common(dev, data);
+ for (i = 0; i < data->pwm_num; i++)
+ data->pwm_enable_orig[i] = data->pwm_enable[i];
/* Register sysfs hooks */
- for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
- if ((err = device_create_file(dev,
- &sda_sf3_arrays[i].dev_attr)))
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
+ err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
+ if (err)
goto exit_remove;
+ }
for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
struct sensor_device_attribute *attr =
&sda_sf3_max_step_arrays[i];
- if (data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
+ if (data->REG_FAN_STEP_OUTPUT &&
+ data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
err = device_create_file(dev, &attr->dev_attr);
if (err)
goto exit_remove;
@@ -1518,8 +2175,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
/* if fan4 is enabled create the sf3 files for it */
if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
- if ((err = device_create_file(dev,
- &sda_sf3_arrays_fan4[i].dev_attr)))
+ err = device_create_file(dev,
+ &sda_sf3_arrays_fan4[i].dev_attr);
+ if (err)
goto exit_remove;
}
@@ -1541,12 +2199,20 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
if ((err = device_create_file(dev,
&sda_fan_input[i].dev_attr))
|| (err = device_create_file(dev,
- &sda_fan_alarm[i].dev_attr))
- || (err = device_create_file(dev,
- &sda_fan_div[i].dev_attr))
- || (err = device_create_file(dev,
- &sda_fan_min[i].dev_attr)))
+ &sda_fan_alarm[i].dev_attr)))
goto exit_remove;
+ if (sio_data->kind != nct6776) {
+ err = device_create_file(dev,
+ &sda_fan_div[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->has_fan_min & (1 << i)) {
+ err = device_create_file(dev,
+ &sda_fan_min[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
if (i < data->pwm_num &&
((err = device_create_file(dev,
&sda_pwm[i].dev_attr))
@@ -1562,16 +2228,33 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < 3; i++) {
- if ((i == 2) && data->temp3_disable)
+ for (i = 0; i < NUM_REG_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ if (data->temp_label) {
+ err = device_create_file(dev,
+ &sda_temp_label[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->reg_temp_over[i]) {
+ err = device_create_file(dev,
+ &sda_temp_max[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->reg_temp_hyst[i]) {
+ err = device_create_file(dev,
+ &sda_temp_max_hyst[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (i > 2)
continue;
if ((err = device_create_file(dev,
- &sda_temp_input[i].dev_attr))
- || (err = device_create_file(dev,
- &sda_temp_max[i].dev_attr))
- || (err = device_create_file(dev,
- &sda_temp_max_hyst[i].dev_attr))
- || (err = device_create_file(dev,
&sda_temp_alarm[i].dev_attr))
|| (err = device_create_file(dev,
&sda_temp_type[i].dev_attr)))
@@ -1632,6 +2315,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
static const char __initdata sio_name_W83667HG[] = "W83667HG";
static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
+ static const char __initdata sio_name_NCT6775[] = "NCT6775F";
+ static const char __initdata sio_name_NCT6776[] = "NCT6776F";
u16 val;
const char *sio_name;
@@ -1668,6 +2353,14 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
sio_data->kind = w83667hg_b;
sio_name = sio_name_W83667HG_B;
break;
+ case SIO_NCT6775_ID:
+ sio_data->kind = nct6775;
+ sio_name = sio_name_NCT6775;
+ break;
+ case SIO_NCT6776_ID:
+ sio_data->kind = nct6776;
+ sio_name = sio_name_NCT6776;
+ break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -1689,7 +2382,8 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
/* Activate logical device if needed */
val = superio_inb(sioaddr, SIO_REG_ENABLE);
if (!(val & 0x01)) {
- pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+ pr_warn("Forcibly enabling Super-I/O. "
+ "Sensor is probably unusable.\n");
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
}
@@ -1726,7 +2420,8 @@ static int __init sensors_w83627ehf_init(void)
if (err)
goto exit;
- if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
err = -ENOMEM;
pr_err("Device allocation failed\n");
goto exit_unregister;
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig
new file mode 100644
index 000000000000..eb4af28f8567
--- /dev/null
+++ b/drivers/hwspinlock/Kconfig
@@ -0,0 +1,22 @@
+#
+# Generic HWSPINLOCK framework
+#
+
+config HWSPINLOCK
+ tristate "Generic Hardware Spinlock framework"
+ help
+ Say y here to support the generic hardware spinlock framework.
+ You only need to enable this if you have hardware spinlock module
+ on your system (usually only relevant if your system has remote slave
+ coprocessors).
+
+ If unsure, say N.
+
+config HWSPINLOCK_OMAP
+ tristate "OMAP Hardware Spinlock device"
+ depends on HWSPINLOCK && ARCH_OMAP4
+ help
+ Say y here to support the OMAP Hardware Spinlock device (firstly
+ introduced in OMAP4).
+
+ If unsure, say N.
diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile
new file mode 100644
index 000000000000..5729a3f7ed3d
--- /dev/null
+++ b/drivers/hwspinlock/Makefile
@@ -0,0 +1,6 @@
+#
+# Generic Hardware Spinlock framework
+#
+
+obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
+obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
new file mode 100644
index 000000000000..43a62714b4fb
--- /dev/null
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -0,0 +1,548 @@
+/*
+ * Hardware spinlock framework
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Contact: Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/jiffies.h>
+#include <linux/radix-tree.h>
+#include <linux/hwspinlock.h>
+#include <linux/pm_runtime.h>
+
+#include "hwspinlock_internal.h"
+
+/* radix tree tags */
+#define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused */
+
+/*
+ * A radix tree is used to maintain the available hwspinlock instances.
+ * The tree associates hwspinlock pointers with their integer key id,
+ * and provides easy-to-use API which makes the hwspinlock core code simple
+ * and easy to read.
+ *
+ * Radix trees are quick on lookups, and reasonably efficient in terms of
+ * storage, especially with high density usages such as this framework
+ * requires (a continuous range of integer keys, beginning with zero, is
+ * used as the ID's of the hwspinlock instances).
+ *
+ * The radix tree API supports tagging items in the tree, which this
+ * framework uses to mark unused hwspinlock instances (see the
+ * HWSPINLOCK_UNUSED tag above). As a result, the process of querying the
+ * tree, looking for an unused hwspinlock instance, is now reduced to a
+ * single radix tree API call.
+ */
+static RADIX_TREE(hwspinlock_tree, GFP_KERNEL);
+
+/*
+ * Synchronization of access to the tree is achieved using this spinlock,
+ * as the radix-tree API requires that users provide all synchronisation.
+ */
+static DEFINE_SPINLOCK(hwspinlock_tree_lock);
+
+/**
+ * __hwspin_trylock() - attempt to lock a specific hwspinlock
+ * @hwlock: an hwspinlock which we want to trylock
+ * @mode: controls whether local interrupts are disabled or not
+ * @flags: a pointer where the caller's interrupt state will be saved at (if
+ * requested)
+ *
+ * This function attempts to lock an hwspinlock, and will immediately
+ * fail if the hwspinlock is already taken.
+ *
+ * Upon a successful return from this function, preemption (and possibly
+ * interrupts) is disabled, so the caller must not sleep, and is advised to
+ * release the hwspinlock as soon as possible. This is required in order to
+ * minimize remote cores polling on the hardware interconnect.
+ *
+ * The user decides whether local interrupts are disabled or not, and if yes,
+ * whether he wants their previous state to be saved. It is up to the user
+ * to choose the appropriate @mode of operation, exactly the same way users
+ * should decide between spin_trylock, spin_trylock_irq and
+ * spin_trylock_irqsave.
+ *
+ * Returns 0 if we successfully locked the hwspinlock or -EBUSY if
+ * the hwspinlock was already taken.
+ * This function will never sleep.
+ */
+int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
+{
+ int ret;
+
+ BUG_ON(!hwlock);
+ BUG_ON(!flags && mode == HWLOCK_IRQSTATE);
+
+ /*
+ * This spin_lock{_irq, _irqsave} serves three purposes:
+ *
+ * 1. Disable preemption, in order to minimize the period of time
+ * in which the hwspinlock is taken. This is important in order
+ * to minimize the possible polling on the hardware interconnect
+ * by a remote user of this lock.
+ * 2. Make the hwspinlock SMP-safe (so we can take it from
+ * additional contexts on the local host).
+ * 3. Ensure that in_atomic/might_sleep checks catch potential
+ * problems with hwspinlock usage (e.g. scheduler checks like
+ * 'scheduling while atomic' etc.)
+ */
+ if (mode == HWLOCK_IRQSTATE)
+ ret = spin_trylock_irqsave(&hwlock->lock, *flags);
+ else if (mode == HWLOCK_IRQ)
+ ret = spin_trylock_irq(&hwlock->lock);
+ else
+ ret = spin_trylock(&hwlock->lock);
+
+ /* is lock already taken by another context on the local cpu ? */
+ if (!ret)
+ return -EBUSY;
+
+ /* try to take the hwspinlock device */
+ ret = hwlock->ops->trylock(hwlock);
+
+ /* if hwlock is already taken, undo spin_trylock_* and exit */
+ if (!ret) {
+ if (mode == HWLOCK_IRQSTATE)
+ spin_unlock_irqrestore(&hwlock->lock, *flags);
+ else if (mode == HWLOCK_IRQ)
+ spin_unlock_irq(&hwlock->lock);
+ else
+ spin_unlock(&hwlock->lock);
+
+ return -EBUSY;
+ }
+
+ /*
+ * We can be sure the other core's memory operations
+ * are observable to us only _after_ we successfully take
+ * the hwspinlock, and we must make sure that subsequent memory
+ * operations (both reads and writes) will not be reordered before
+ * we actually took the hwspinlock.
+ *
+ * Note: the implicit memory barrier of the spinlock above is too
+ * early, so we need this additional explicit memory barrier.
+ */
+ mb();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__hwspin_trylock);
+
+/**
+ * __hwspin_lock_timeout() - lock an hwspinlock with timeout limit
+ * @hwlock: the hwspinlock to be locked
+ * @timeout: timeout value in msecs
+ * @mode: mode which controls whether local interrupts are disabled or not
+ * @flags: a pointer to where the caller's interrupt state will be saved at (if
+ * requested)
+ *
+ * This function locks the given @hwlock. If the @hwlock
+ * is already taken, the function will busy loop waiting for it to
+ * be released, but give up after @timeout msecs have elapsed.
+ *
+ * Upon a successful return from this function, preemption is disabled
+ * (and possibly local interrupts, too), so the caller must not sleep,
+ * and is advised to release the hwspinlock as soon as possible.
+ * This is required in order to minimize remote cores polling on the
+ * hardware interconnect.
+ *
+ * The user decides whether local interrupts are disabled or not, and if yes,
+ * whether he wants their previous state to be saved. It is up to the user
+ * to choose the appropriate @mode of operation, exactly the same way users
+ * should decide between spin_lock, spin_lock_irq and spin_lock_irqsave.
+ *
+ * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * error code otherwise (most notably -ETIMEDOUT if the @hwlock is still
+ * busy after @timeout msecs). The function will never sleep.
+ */
+int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
+ int mode, unsigned long *flags)
+{
+ int ret;
+ unsigned long expire;
+
+ expire = msecs_to_jiffies(to) + jiffies;
+
+ for (;;) {
+ /* Try to take the hwspinlock */
+ ret = __hwspin_trylock(hwlock, mode, flags);
+ if (ret != -EBUSY)
+ break;
+
+ /*
+ * The lock is already taken, let's check if the user wants
+ * us to try again
+ */
+ if (time_is_before_eq_jiffies(expire))
+ return -ETIMEDOUT;
+
+ /*
+ * Allow platform-specific relax handlers to prevent
+ * hogging the interconnect (no sleeping, though)
+ */
+ if (hwlock->ops->relax)
+ hwlock->ops->relax(hwlock);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__hwspin_lock_timeout);
+
+/**
+ * __hwspin_unlock() - unlock a specific hwspinlock
+ * @hwlock: a previously-acquired hwspinlock which we want to unlock
+ * @mode: controls whether local interrupts needs to be restored or not
+ * @flags: previous caller's interrupt state to restore (if requested)
+ *
+ * This function will unlock a specific hwspinlock, enable preemption and
+ * (possibly) enable interrupts or restore their previous state.
+ * @hwlock must be already locked before calling this function: it is a bug
+ * to call unlock on a @hwlock that is already unlocked.
+ *
+ * The user decides whether local interrupts should be enabled or not, and
+ * if yes, whether he wants their previous state to be restored. It is up
+ * to the user to choose the appropriate @mode of operation, exactly the
+ * same way users decide between spin_unlock, spin_unlock_irq and
+ * spin_unlock_irqrestore.
+ *
+ * The function will never sleep.
+ */
+void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
+{
+ BUG_ON(!hwlock);
+ BUG_ON(!flags && mode == HWLOCK_IRQSTATE);
+
+ /*
+ * We must make sure that memory operations (both reads and writes),
+ * done before unlocking the hwspinlock, will not be reordered
+ * after the lock is released.
+ *
+ * That's the purpose of this explicit memory barrier.
+ *
+ * Note: the memory barrier induced by the spin_unlock below is too
+ * late; the other core is going to access memory soon after it will
+ * take the hwspinlock, and by then we want to be sure our memory
+ * operations are already observable.
+ */
+ mb();
+
+ hwlock->ops->unlock(hwlock);
+
+ /* Undo the spin_trylock{_irq, _irqsave} called while locking */
+ if (mode == HWLOCK_IRQSTATE)
+ spin_unlock_irqrestore(&hwlock->lock, *flags);
+ else if (mode == HWLOCK_IRQ)
+ spin_unlock_irq(&hwlock->lock);
+ else
+ spin_unlock(&hwlock->lock);
+}
+EXPORT_SYMBOL_GPL(__hwspin_unlock);
+
+/**
+ * hwspin_lock_register() - register a new hw spinlock
+ * @hwlock: hwspinlock to register.
+ *
+ * This function should be called from the underlying platform-specific
+ * implementation, to register a new hwspinlock instance.
+ *
+ * Can be called from an atomic context (will not sleep) but not from
+ * within interrupt context.
+ *
+ * Returns 0 on success, or an appropriate error code on failure
+ */
+int hwspin_lock_register(struct hwspinlock *hwlock)
+{
+ struct hwspinlock *tmp;
+ int ret;
+
+ if (!hwlock || !hwlock->ops ||
+ !hwlock->ops->trylock || !hwlock->ops->unlock) {
+ pr_err("invalid parameters\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&hwlock->lock);
+
+ spin_lock(&hwspinlock_tree_lock);
+
+ ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock);
+ if (ret)
+ goto out;
+
+ /* mark this hwspinlock as available */
+ tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id,
+ HWSPINLOCK_UNUSED);
+
+ /* self-sanity check which should never fail */
+ WARN_ON(tmp != hwlock);
+
+out:
+ spin_unlock(&hwspinlock_tree_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_register);
+
+/**
+ * hwspin_lock_unregister() - unregister an hw spinlock
+ * @id: index of the specific hwspinlock to unregister
+ *
+ * This function should be called from the underlying platform-specific
+ * implementation, to unregister an existing (and unused) hwspinlock.
+ *
+ * Can be called from an atomic context (will not sleep) but not from
+ * within interrupt context.
+ *
+ * Returns the address of hwspinlock @id on success, or NULL on failure
+ */
+struct hwspinlock *hwspin_lock_unregister(unsigned int id)
+{
+ struct hwspinlock *hwlock = NULL;
+ int ret;
+
+ spin_lock(&hwspinlock_tree_lock);
+
+ /* make sure the hwspinlock is not in use (tag is set) */
+ ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
+ if (ret == 0) {
+ pr_err("hwspinlock %d still in use (or not present)\n", id);
+ goto out;
+ }
+
+ hwlock = radix_tree_delete(&hwspinlock_tree, id);
+ if (!hwlock) {
+ pr_err("failed to delete hwspinlock %d\n", id);
+ goto out;
+ }
+
+out:
+ spin_unlock(&hwspinlock_tree_lock);
+ return hwlock;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_unregister);
+
+/**
+ * __hwspin_lock_request() - tag an hwspinlock as used and power it up
+ *
+ * This is an internal function that prepares an hwspinlock instance
+ * before it is given to the user. The function assumes that
+ * hwspinlock_tree_lock is taken.
+ *
+ * Returns 0 or positive to indicate success, and a negative value to
+ * indicate an error (with the appropriate error code)
+ */
+static int __hwspin_lock_request(struct hwspinlock *hwlock)
+{
+ struct hwspinlock *tmp;
+ int ret;
+
+ /* prevent underlying implementation from being removed */
+ if (!try_module_get(hwlock->owner)) {
+ dev_err(hwlock->dev, "%s: can't get owner\n", __func__);
+ return -EINVAL;
+ }
+
+ /* notify PM core that power is now needed */
+ ret = pm_runtime_get_sync(hwlock->dev);
+ if (ret < 0) {
+ dev_err(hwlock->dev, "%s: can't power on device\n", __func__);
+ return ret;
+ }
+
+ /* mark hwspinlock as used, should not fail */
+ tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock->id,
+ HWSPINLOCK_UNUSED);
+
+ /* self-sanity check that should never fail */
+ WARN_ON(tmp != hwlock);
+
+ return ret;
+}
+
+/**
+ * hwspin_lock_get_id() - retrieve id number of a given hwspinlock
+ * @hwlock: a valid hwspinlock instance
+ *
+ * Returns the id number of a given @hwlock, or -EINVAL if @hwlock is invalid.
+ */
+int hwspin_lock_get_id(struct hwspinlock *hwlock)
+{
+ if (!hwlock) {
+ pr_err("invalid hwlock\n");
+ return -EINVAL;
+ }
+
+ return hwlock->id;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
+
+/**
+ * hwspin_lock_request() - request an hwspinlock
+ *
+ * This function should be called by users of the hwspinlock device,
+ * in order to dynamically assign them an unused hwspinlock.
+ * Usually the user of this lock will then have to communicate the lock's id
+ * to the remote core before it can be used for synchronization (to get the
+ * id of a given hwlock, use hwspin_lock_get_id()).
+ *
+ * Can be called from an atomic context (will not sleep) but not from
+ * within interrupt context (simply because there is no use case for
+ * that yet).
+ *
+ * Returns the address of the assigned hwspinlock, or NULL on error
+ */
+struct hwspinlock *hwspin_lock_request(void)
+{
+ struct hwspinlock *hwlock;
+ int ret;
+
+ spin_lock(&hwspinlock_tree_lock);
+
+ /* look for an unused lock */
+ ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock,
+ 0, 1, HWSPINLOCK_UNUSED);
+ if (ret == 0) {
+ pr_warn("a free hwspinlock is not available\n");
+ hwlock = NULL;
+ goto out;
+ }
+
+ /* sanity check that should never fail */
+ WARN_ON(ret > 1);
+
+ /* mark as used and power up */
+ ret = __hwspin_lock_request(hwlock);
+ if (ret < 0)
+ hwlock = NULL;
+
+out:
+ spin_unlock(&hwspinlock_tree_lock);
+ return hwlock;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_request);
+
+/**
+ * hwspin_lock_request_specific() - request for a specific hwspinlock
+ * @id: index of the specific hwspinlock that is requested
+ *
+ * This function should be called by users of the hwspinlock module,
+ * in order to assign them a specific hwspinlock.
+ * Usually early board code will be calling this function in order to
+ * reserve specific hwspinlock ids for predefined purposes.
+ *
+ * Can be called from an atomic context (will not sleep) but not from
+ * within interrupt context (simply because there is no use case for
+ * that yet).
+ *
+ * Returns the address of the assigned hwspinlock, or NULL on error
+ */
+struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
+{
+ struct hwspinlock *hwlock;
+ int ret;
+
+ spin_lock(&hwspinlock_tree_lock);
+
+ /* make sure this hwspinlock exists */
+ hwlock = radix_tree_lookup(&hwspinlock_tree, id);
+ if (!hwlock) {
+ pr_warn("hwspinlock %u does not exist\n", id);
+ goto out;
+ }
+
+ /* sanity check (this shouldn't happen) */
+ WARN_ON(hwlock->id != id);
+
+ /* make sure this hwspinlock is unused */
+ ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
+ if (ret == 0) {
+ pr_warn("hwspinlock %u is already in use\n", id);
+ hwlock = NULL;
+ goto out;
+ }
+
+ /* mark as used and power up */
+ ret = __hwspin_lock_request(hwlock);
+ if (ret < 0)
+ hwlock = NULL;
+
+out:
+ spin_unlock(&hwspinlock_tree_lock);
+ return hwlock;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
+
+/**
+ * hwspin_lock_free() - free a specific hwspinlock
+ * @hwlock: the specific hwspinlock to free
+ *
+ * This function mark @hwlock as free again.
+ * Should only be called with an @hwlock that was retrieved from
+ * an earlier call to omap_hwspin_lock_request{_specific}.
+ *
+ * Can be called from an atomic context (will not sleep) but not from
+ * within interrupt context (simply because there is no use case for
+ * that yet).
+ *
+ * Returns 0 on success, or an appropriate error code on failure
+ */
+int hwspin_lock_free(struct hwspinlock *hwlock)
+{
+ struct hwspinlock *tmp;
+ int ret;
+
+ if (!hwlock) {
+ pr_err("invalid hwlock\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&hwspinlock_tree_lock);
+
+ /* make sure the hwspinlock is used */
+ ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id,
+ HWSPINLOCK_UNUSED);
+ if (ret == 1) {
+ dev_err(hwlock->dev, "%s: hwlock is already free\n", __func__);
+ dump_stack();
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* notify the underlying device that power is not needed */
+ ret = pm_runtime_put(hwlock->dev);
+ if (ret < 0)
+ goto out;
+
+ /* mark this hwspinlock as available */
+ tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock->id,
+ HWSPINLOCK_UNUSED);
+
+ /* sanity check (this shouldn't happen) */
+ WARN_ON(tmp != hwlock);
+
+ module_put(hwlock->owner);
+
+out:
+ spin_unlock(&hwspinlock_tree_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hwspin_lock_free);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hardware spinlock interface");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h
new file mode 100644
index 000000000000..69935e6b93e5
--- /dev/null
+++ b/drivers/hwspinlock/hwspinlock_internal.h
@@ -0,0 +1,61 @@
+/*
+ * Hardware spinlocks internal header
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Contact: Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __HWSPINLOCK_HWSPINLOCK_H
+#define __HWSPINLOCK_HWSPINLOCK_H
+
+#include <linux/spinlock.h>
+#include <linux/device.h>
+
+/**
+ * struct hwspinlock_ops - platform-specific hwspinlock handlers
+ *
+ * @trylock: make a single attempt to take the lock. returns 0 on
+ * failure and true on success. may _not_ sleep.
+ * @unlock: release the lock. always succeed. may _not_ sleep.
+ * @relax: optional, platform-specific relax handler, called by hwspinlock
+ * core while spinning on a lock, between two successive
+ * invocations of @trylock. may _not_ sleep.
+ */
+struct hwspinlock_ops {
+ int (*trylock)(struct hwspinlock *lock);
+ void (*unlock)(struct hwspinlock *lock);
+ void (*relax)(struct hwspinlock *lock);
+};
+
+/**
+ * struct hwspinlock - this struct represents a single hwspinlock instance
+ *
+ * @dev: underlying device, will be used to invoke runtime PM api
+ * @ops: platform-specific hwspinlock handlers
+ * @id: a global, unique, system-wide, index of the lock.
+ * @lock: initialized and used by hwspinlock core
+ * @owner: underlying implementation module, used to maintain module ref count
+ *
+ * Note: currently simplicity was opted for, but later we can squeeze some
+ * memory bytes by grouping the dev, ops and owner members in a single
+ * per-platform struct, and have all hwspinlocks point at it.
+ */
+struct hwspinlock {
+ struct device *dev;
+ const struct hwspinlock_ops *ops;
+ int id;
+ spinlock_t lock;
+ struct module *owner;
+};
+
+#endif /* __HWSPINLOCK_HWSPINLOCK_H */
diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c
new file mode 100644
index 000000000000..a8f02734c026
--- /dev/null
+++ b/drivers/hwspinlock/omap_hwspinlock.c
@@ -0,0 +1,231 @@
+/*
+ * OMAP hardware spinlock driver
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Contact: Simon Que <sque@ti.com>
+ * Hari Kanigeri <h-kanigeri2@ti.com>
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/hwspinlock.h>
+#include <linux/platform_device.h>
+
+#include "hwspinlock_internal.h"
+
+/* Spinlock register offsets */
+#define SYSSTATUS_OFFSET 0x0014
+#define LOCK_BASE_OFFSET 0x0800
+
+#define SPINLOCK_NUMLOCKS_BIT_OFFSET (24)
+
+/* Possible values of SPINLOCK_LOCK_REG */
+#define SPINLOCK_NOTTAKEN (0) /* free */
+#define SPINLOCK_TAKEN (1) /* locked */
+
+#define to_omap_hwspinlock(lock) \
+ container_of(lock, struct omap_hwspinlock, lock)
+
+struct omap_hwspinlock {
+ struct hwspinlock lock;
+ void __iomem *addr;
+};
+
+struct omap_hwspinlock_state {
+ int num_locks; /* Total number of locks in system */
+ void __iomem *io_base; /* Mapped base address */
+};
+
+static int omap_hwspinlock_trylock(struct hwspinlock *lock)
+{
+ struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock);
+
+ /* attempt to acquire the lock by reading its value */
+ return (SPINLOCK_NOTTAKEN == readl(omap_lock->addr));
+}
+
+static void omap_hwspinlock_unlock(struct hwspinlock *lock)
+{
+ struct omap_hwspinlock *omap_lock = to_omap_hwspinlock(lock);
+
+ /* release the lock by writing 0 to it */
+ writel(SPINLOCK_NOTTAKEN, omap_lock->addr);
+}
+
+/*
+ * relax the OMAP interconnect while spinning on it.
+ *
+ * The specs recommended that the retry delay time will be
+ * just over half of the time that a requester would be
+ * expected to hold the lock.
+ *
+ * The number below is taken from an hardware specs example,
+ * obviously it is somewhat arbitrary.
+ */
+static void omap_hwspinlock_relax(struct hwspinlock *lock)
+{
+ ndelay(50);
+}
+
+static const struct hwspinlock_ops omap_hwspinlock_ops = {
+ .trylock = omap_hwspinlock_trylock,
+ .unlock = omap_hwspinlock_unlock,
+ .relax = omap_hwspinlock_relax,
+};
+
+static int __devinit omap_hwspinlock_probe(struct platform_device *pdev)
+{
+ struct omap_hwspinlock *omap_lock;
+ struct omap_hwspinlock_state *state;
+ struct hwspinlock *lock;
+ struct resource *res;
+ void __iomem *io_base;
+ int i, ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ io_base = ioremap(res->start, resource_size(res));
+ if (!io_base) {
+ ret = -ENOMEM;
+ goto free_state;
+ }
+
+ /* Determine number of locks */
+ i = readl(io_base + SYSSTATUS_OFFSET);
+ i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET;
+
+ /* one of the four lsb's must be set, and nothing else */
+ if (hweight_long(i & 0xf) != 1 || i > 8) {
+ ret = -EINVAL;
+ goto iounmap_base;
+ }
+
+ state->num_locks = i * 32;
+ state->io_base = io_base;
+
+ platform_set_drvdata(pdev, state);
+
+ /*
+ * runtime PM will make sure the clock of this module is
+ * enabled iff at least one lock is requested
+ */
+ pm_runtime_enable(&pdev->dev);
+
+ for (i = 0; i < state->num_locks; i++) {
+ omap_lock = kzalloc(sizeof(*omap_lock), GFP_KERNEL);
+ if (!omap_lock) {
+ ret = -ENOMEM;
+ goto free_locks;
+ }
+
+ omap_lock->lock.dev = &pdev->dev;
+ omap_lock->lock.owner = THIS_MODULE;
+ omap_lock->lock.id = i;
+ omap_lock->lock.ops = &omap_hwspinlock_ops;
+ omap_lock->addr = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
+
+ ret = hwspin_lock_register(&omap_lock->lock);
+ if (ret) {
+ kfree(omap_lock);
+ goto free_locks;
+ }
+ }
+
+ return 0;
+
+free_locks:
+ while (--i >= 0) {
+ lock = hwspin_lock_unregister(i);
+ /* this should't happen, but let's give our best effort */
+ if (!lock) {
+ dev_err(&pdev->dev, "%s: cleanups failed\n", __func__);
+ continue;
+ }
+ omap_lock = to_omap_hwspinlock(lock);
+ kfree(omap_lock);
+ }
+ pm_runtime_disable(&pdev->dev);
+iounmap_base:
+ iounmap(io_base);
+free_state:
+ kfree(state);
+ return ret;
+}
+
+static int omap_hwspinlock_remove(struct platform_device *pdev)
+{
+ struct omap_hwspinlock_state *state = platform_get_drvdata(pdev);
+ struct hwspinlock *lock;
+ struct omap_hwspinlock *omap_lock;
+ int i;
+
+ for (i = 0; i < state->num_locks; i++) {
+ lock = hwspin_lock_unregister(i);
+ /* this shouldn't happen at this point. if it does, at least
+ * don't continue with the remove */
+ if (!lock) {
+ dev_err(&pdev->dev, "%s: failed on %d\n", __func__, i);
+ return -EBUSY;
+ }
+
+ omap_lock = to_omap_hwspinlock(lock);
+ kfree(omap_lock);
+ }
+
+ pm_runtime_disable(&pdev->dev);
+ iounmap(state->io_base);
+ kfree(state);
+
+ return 0;
+}
+
+static struct platform_driver omap_hwspinlock_driver = {
+ .probe = omap_hwspinlock_probe,
+ .remove = omap_hwspinlock_remove,
+ .driver = {
+ .name = "omap_hwspinlock",
+ },
+};
+
+static int __init omap_hwspinlock_init(void)
+{
+ return platform_driver_register(&omap_hwspinlock_driver);
+}
+/* board init code might need to reserve hwspinlocks for predefined purposes */
+postcore_initcall(omap_hwspinlock_init);
+
+static void __exit omap_hwspinlock_exit(void)
+{
+ platform_driver_unregister(&omap_hwspinlock_driver);
+}
+module_exit(omap_hwspinlock_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Hardware spinlock driver for OMAP");
+MODULE_AUTHOR("Simon Que <sque@ti.com>");
+MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@ti.com>");
+MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index cbfcf6fb4a61..230601e8853f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -433,7 +433,7 @@ config I2C_IXP2000
config I2C_MPC
tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
- depends on PPC32
+ depends on PPC
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
@@ -452,6 +452,16 @@ config I2C_MV64XXX
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
+config I2C_MXS
+ tristate "Freescale i.MX28 I2C interface"
+ depends on SOC_IMX28
+ help
+ Say Y here if you want to use the I2C bus controller on
+ the Freescale i.MX28 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mxs.
+
config I2C_NOMADIK
tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
depends on PLAT_NOMADIK
@@ -618,6 +628,13 @@ config I2C_STU300
This driver can also be built as a module. If so, the module
will be called i2c-stu300.
+config I2C_TEGRA
+ tristate "NVIDIA Tegra internal I2C controller"
+ depends on ARCH_TEGRA
+ help
+ If you say yes to this option, support will be included for the
+ I2C controller embedded in NVIDIA Tegra SOCs
+
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a83966acc5ab..3878c959d4fa 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
+obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
new file mode 100644
index 000000000000..8022e2390a5a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -0,0 +1,412 @@
+/*
+ * Freescale MXS I2C bus driver
+ *
+ * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
+ *
+ * based on a (non-working) driver which was:
+ *
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * TODO: add dma-support if platform-support for it is available
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+
+#include <mach/common.h>
+
+#define DRIVER_NAME "mxs-i2c"
+
+#define MXS_I2C_CTRL0 (0x00)
+#define MXS_I2C_CTRL0_SET (0x04)
+
+#define MXS_I2C_CTRL0_SFTRST 0x80000000
+#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
+#define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000
+#define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000
+#define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000
+#define MXS_I2C_CTRL0_MASTER_MODE 0x00020000
+#define MXS_I2C_CTRL0_DIRECTION 0x00010000
+#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF)
+
+#define MXS_I2C_CTRL1 (0x40)
+#define MXS_I2C_CTRL1_SET (0x44)
+#define MXS_I2C_CTRL1_CLR (0x48)
+
+#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80
+#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40
+#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20
+#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x10
+#define MXS_I2C_CTRL1_EARLY_TERM_IRQ 0x08
+#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ 0x04
+#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02
+#define MXS_I2C_CTRL1_SLAVE_IRQ 0x01
+
+#define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \
+ MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \
+ MXS_I2C_CTRL1_EARLY_TERM_IRQ | \
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
+ MXS_I2C_CTRL1_SLAVE_IRQ)
+
+#define MXS_I2C_QUEUECTRL (0x60)
+#define MXS_I2C_QUEUECTRL_SET (0x64)
+#define MXS_I2C_QUEUECTRL_CLR (0x68)
+
+#define MXS_I2C_QUEUECTRL_QUEUE_RUN 0x20
+#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE 0x04
+
+#define MXS_I2C_QUEUESTAT (0x70)
+#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000
+
+#define MXS_I2C_QUEUECMD (0x80)
+
+#define MXS_I2C_QUEUEDATA (0x90)
+
+#define MXS_I2C_DATA (0xa0)
+
+
+#define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \
+ MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION | \
+ MXS_I2C_CTRL0_XFER_COUNT(1))
+
+#define MXS_CMD_I2C_WRITE (MXS_I2C_CTRL0_PRE_SEND_START | \
+ MXS_I2C_CTRL0_MASTER_MODE | \
+ MXS_I2C_CTRL0_DIRECTION)
+
+#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
+ MXS_I2C_CTRL0_MASTER_MODE)
+
+/**
+ * struct mxs_i2c_dev - per device, private MXS-I2C data
+ *
+ * @dev: driver model device node
+ * @regs: IO registers pointer
+ * @cmd_complete: completion object for transaction wait
+ * @cmd_err: error code for last transaction
+ * @adapter: i2c subsystem adapter node
+ */
+struct mxs_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+ struct completion cmd_complete;
+ u32 cmd_err;
+ struct i2c_adapter adapter;
+};
+
+/*
+ * TODO: check if calls to here are really needed. If not, we could get rid of
+ * mxs_reset_block and the mach-dependency. Needs an I2C analyzer, probably.
+ */
+static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
+{
+ mxs_reset_block(i2c->regs);
+ writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+}
+
+static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
+ int flags)
+{
+ u32 data;
+
+ writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD);
+
+ data = (addr << 1) | I2C_SMBUS_READ;
+ writel(data, i2c->regs + MXS_I2C_DATA);
+
+ data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags;
+ writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+}
+
+static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c,
+ u8 addr, u8 *buf, int len, int flags)
+{
+ u32 data;
+ int i, shifts_left;
+
+ data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
+ writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+
+ /*
+ * We have to copy the slave address (u8) and buffer (arbitrary number
+ * of u8) into the data register (u32). To achieve that, the u8 are put
+ * into the MSBs of 'data' which is then shifted for the next u8. When
+ * apropriate, 'data' is written to MXS_I2C_DATA. So, the first u32
+ * looks like this:
+ *
+ * 3 2 1 0
+ * 10987654|32109876|54321098|76543210
+ * --------+--------+--------+--------
+ * buffer+2|buffer+1|buffer+0|slave_addr
+ */
+
+ data = ((addr << 1) | I2C_SMBUS_WRITE) << 24;
+
+ for (i = 0; i < len; i++) {
+ data >>= 8;
+ data |= buf[i] << 24;
+ if ((i & 3) == 2)
+ writel(data, i2c->regs + MXS_I2C_DATA);
+ }
+
+ /* Write out the remaining bytes if any */
+ shifts_left = 24 - (i & 3) * 8;
+ if (shifts_left)
+ writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA);
+}
+
+/*
+ * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the
+ * rd_threshold to 1). Couldn't get this to work, though.
+ */
+static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+ while (readl(i2c->regs + MXS_I2C_QUEUESTAT)
+ & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) {
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ cond_resched();
+ }
+
+ return 0;
+}
+
+static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
+{
+ u32 data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if ((i & 3) == 0) {
+ if (mxs_i2c_wait_for_data(i2c))
+ return -ETIMEDOUT;
+ data = readl(i2c->regs + MXS_I2C_QUEUEDATA);
+ }
+ buf[i] = data & 0xff;
+ data >>= 8;
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int stop)
+{
+ struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+ int ret;
+ int flags;
+
+ init_completion(&i2c->cmd_complete);
+
+ dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
+ if (msg->flags & I2C_M_RD)
+ mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
+ else
+ mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
+ flags);
+
+ writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+ i2c->regs + MXS_I2C_QUEUECTRL_SET);
+
+ ret = wait_for_completion_timeout(&i2c->cmd_complete,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ goto timeout;
+
+ if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+ ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
+ if (ret)
+ goto timeout;
+ }
+
+ if (i2c->cmd_err == -ENXIO)
+ mxs_i2c_reset(i2c);
+
+ dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err);
+
+ return i2c->cmd_err;
+
+timeout:
+ dev_dbg(i2c->dev, "Timeout!\n");
+ mxs_i2c_reset(i2c);
+ return -ETIMEDOUT;
+}
+
+static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < num; i++) {
+ err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1));
+ if (err)
+ return err;
+ }
+
+ return num;
+}
+
+static u32 mxs_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
+{
+ struct mxs_i2c_dev *i2c = dev_id;
+ u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
+
+ if (!stat)
+ return IRQ_NONE;
+
+ if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+ i2c->cmd_err = -ENXIO;
+ else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
+ MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
+ MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ))
+ /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
+ i2c->cmd_err = -EIO;
+ else
+ i2c->cmd_err = 0;
+
+ complete(&i2c->cmd_complete);
+
+ writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
+ return IRQ_HANDLED;
+}
+
+static const struct i2c_algorithm mxs_i2c_algo = {
+ .master_xfer = mxs_i2c_xfer,
+ .functionality = mxs_i2c_func,
+};
+
+static int __devinit mxs_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxs_i2c_dev *i2c;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ resource_size_t res_size;
+ int err, irq;
+
+ i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ res_size = resource_size(res);
+ if (!devm_request_mem_region(dev, res->start, res_size, res->name))
+ return -EBUSY;
+
+ i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
+ if (!i2c->regs)
+ return -EBUSY;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
+ if (err)
+ return err;
+
+ i2c->dev = dev;
+ platform_set_drvdata(pdev, i2c);
+
+ /* Do reset to enforce correct startup after pinmuxing */
+ mxs_i2c_reset(i2c);
+ writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+ i2c->regs + MXS_I2C_QUEUECTRL_SET);
+
+ adap = &i2c->adapter;
+ strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &mxs_i2c_algo;
+ adap->dev.parent = dev;
+ adap->nr = pdev->id;
+ i2c_set_adapdata(adap, i2c);
+ err = i2c_add_numbered_adapter(adap);
+ if (err) {
+ dev_err(dev, "Failed to add adapter (%d)\n", err);
+ writel(MXS_I2C_CTRL0_SFTRST,
+ i2c->regs + MXS_I2C_CTRL0_SET);
+ return err;
+ }
+
+ return 0;
+}
+
+static int __devexit mxs_i2c_remove(struct platform_device *pdev)
+{
+ struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = i2c_del_adapter(&i2c->adapter);
+ if (ret)
+ return -EBUSY;
+
+ writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+ i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+ writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mxs_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(mxs_i2c_remove),
+};
+
+static int __init mxs_i2c_init(void)
+{
+ return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
+}
+subsys_initcall(mxs_i2c_init);
+
+static void __exit mxs_i2c_exit(void)
+{
+ platform_driver_unregister(&mxs_i2c_driver);
+}
+module_exit(mxs_i2c_exit);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("MXS I2C Bus Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
new file mode 100644
index 000000000000..3921f664c9c3
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -0,0 +1,700 @@
+/*
+ * drivers/i2c/busses/i2c-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c-tegra.h>
+
+#include <asm/unaligned.h>
+
+#include <mach/clk.h>
+
+#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define BYTES_PER_FIFO_WORD 4
+
+#define I2C_CNFG 0x000
+#define I2C_CNFG_PACKET_MODE_EN (1<<10)
+#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
+#define I2C_SL_CNFG 0x020
+#define I2C_SL_CNFG_NEWSL (1<<2)
+#define I2C_SL_ADDR1 0x02c
+#define I2C_TX_FIFO 0x050
+#define I2C_RX_FIFO 0x054
+#define I2C_PACKET_TRANSFER_STATUS 0x058
+#define I2C_FIFO_CONTROL 0x05c
+#define I2C_FIFO_CONTROL_TX_FLUSH (1<<1)
+#define I2C_FIFO_CONTROL_RX_FLUSH (1<<0)
+#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5
+#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2
+#define I2C_FIFO_STATUS 0x060
+#define I2C_FIFO_STATUS_TX_MASK 0xF0
+#define I2C_FIFO_STATUS_TX_SHIFT 4
+#define I2C_FIFO_STATUS_RX_MASK 0x0F
+#define I2C_FIFO_STATUS_RX_SHIFT 0
+#define I2C_INT_MASK 0x064
+#define I2C_INT_STATUS 0x068
+#define I2C_INT_PACKET_XFER_COMPLETE (1<<7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6)
+#define I2C_INT_TX_FIFO_OVERFLOW (1<<5)
+#define I2C_INT_RX_FIFO_UNDERFLOW (1<<4)
+#define I2C_INT_NO_ACK (1<<3)
+#define I2C_INT_ARBITRATION_LOST (1<<2)
+#define I2C_INT_TX_FIFO_DATA_REQ (1<<1)
+#define I2C_INT_RX_FIFO_DATA_REQ (1<<0)
+#define I2C_CLK_DIVISOR 0x06c
+
+#define DVC_CTRL_REG1 0x000
+#define DVC_CTRL_REG1_INTR_EN (1<<10)
+#define DVC_CTRL_REG2 0x004
+#define DVC_CTRL_REG3 0x008
+#define DVC_CTRL_REG3_SW_PROG (1<<26)
+#define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30)
+#define DVC_STATUS 0x00c
+#define DVC_STATUS_I2C_DONE_INTR (1<<30)
+
+#define I2C_ERR_NONE 0x00
+#define I2C_ERR_NO_ACK 0x01
+#define I2C_ERR_ARBITRATION_LOST 0x02
+
+#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
+#define PACKET_HEADER0_PACKET_ID_SHIFT 16
+#define PACKET_HEADER0_CONT_ID_SHIFT 12
+#define PACKET_HEADER0_PROTOCOL_I2C (1<<4)
+
+#define I2C_HEADER_HIGHSPEED_MODE (1<<22)
+#define I2C_HEADER_CONT_ON_NAK (1<<21)
+#define I2C_HEADER_SEND_START_BYTE (1<<20)
+#define I2C_HEADER_READ (1<<19)
+#define I2C_HEADER_10BIT_ADDR (1<<18)
+#define I2C_HEADER_IE_ENABLE (1<<17)
+#define I2C_HEADER_REPEAT_START (1<<16)
+#define I2C_HEADER_MASTER_ADDR_SHIFT 12
+#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
+
+/**
+ * struct tegra_i2c_dev - per device i2c context
+ * @dev: device reference for power management
+ * @adapter: core i2c layer adapter information
+ * @clk: clock reference for i2c controller
+ * @i2c_clk: clock reference for i2c bus
+ * @iomem: memory resource for registers
+ * @base: ioremapped registers cookie
+ * @cont_id: i2c controller id, used for for packet header
+ * @irq: irq number of transfer complete interrupt
+ * @is_dvc: identifies the DVC i2c controller, has a different register layout
+ * @msg_complete: transfer completion notifier
+ * @msg_err: error code for completed message
+ * @msg_buf: pointer to current message data
+ * @msg_buf_remaining: size of unsent data in the message buffer
+ * @msg_read: identifies read transfers
+ * @bus_clk_rate: current i2c bus clock rate
+ * @is_suspended: prevents i2c controller accesses after suspend is called
+ */
+struct tegra_i2c_dev {
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct clk *clk;
+ struct clk *i2c_clk;
+ struct resource *iomem;
+ void __iomem *base;
+ int cont_id;
+ int irq;
+ int is_dvc;
+ struct completion msg_complete;
+ int msg_err;
+ u8 *msg_buf;
+ size_t msg_buf_remaining;
+ int msg_read;
+ unsigned long bus_clk_rate;
+ bool is_suspended;
+};
+
+static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
+{
+ writel(val, i2c_dev->base + reg);
+}
+
+static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + reg);
+}
+
+/*
+ * i2c_writel and i2c_readl will offset the register if necessary to talk
+ * to the I2C block inside the DVC block
+ */
+static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
+ unsigned long reg)
+{
+ if (i2c_dev->is_dvc)
+ reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
+ return reg;
+}
+
+static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+ unsigned long reg)
+{
+ writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+ return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
+ unsigned long reg, int len)
+{
+ readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+ int_mask &= ~mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+ u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+ int_mask |= mask;
+ i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
+{
+ unsigned long timeout = jiffies + HZ;
+ u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL);
+ val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH;
+ i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+ while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) &
+ (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int rx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
+ I2C_FIFO_STATUS_RX_SHIFT;
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+ if (words_to_transfer > rx_fifo_avail)
+ words_to_transfer = rx_fifo_avail;
+
+ i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ rx_fifo_avail -= words_to_transfer;
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent overwriting past the end of buf
+ */
+ if (rx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ memcpy(buf, &val, buf_remaining);
+ buf_remaining = 0;
+ rx_fifo_avail--;
+ }
+
+ BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf;
+ return 0;
+}
+
+static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int tx_fifo_avail;
+ u8 *buf = i2c_dev->msg_buf;
+ size_t buf_remaining = i2c_dev->msg_buf_remaining;
+ int words_to_transfer;
+
+ val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+ tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
+ I2C_FIFO_STATUS_TX_SHIFT;
+
+ /* Rounds down to not include partial word at the end of buf */
+ words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+
+ /*
+ * If there is a partial word at the end of buf, handle it manually to
+ * prevent reading past the end of buf, which could cross a page
+ * boundary and fault.
+ */
+ if (tx_fifo_avail > 0 && buf_remaining > 0) {
+ BUG_ON(buf_remaining > 3);
+ memcpy(&val, buf, buf_remaining);
+ i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+ buf_remaining = 0;
+ tx_fifo_avail--;
+ }
+
+ BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0);
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf;
+ return 0;
+}
+
+/*
+ * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
+ * block. This block is identical to the rest of the I2C blocks, except that
+ * it only supports master mode, it has registers moved around, and it needs
+ * some extra init to get it into I2C mode. The register moves are handled
+ * by i2c_readl and i2c_writel
+ */
+static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val = 0;
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
+ val |= DVC_CTRL_REG3_SW_PROG;
+ val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
+
+ val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
+ val |= DVC_CTRL_REG1_INTR_EN;
+ dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
+}
+
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
+{
+ u32 val;
+ int err = 0;
+
+ clk_enable(i2c_dev->clk);
+
+ tegra_periph_reset_assert(i2c_dev->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(i2c_dev->clk);
+
+ if (i2c_dev->is_dvc)
+ tegra_dvc_init(i2c_dev);
+
+ val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+ i2c_writel(i2c_dev, val, I2C_CNFG);
+ i2c_writel(i2c_dev, 0, I2C_INT_MASK);
+ clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
+
+ val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
+ 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
+ i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+ if (tegra_i2c_flush_fifos(i2c_dev))
+ err = -ETIMEDOUT;
+
+ clk_disable(i2c_dev->clk);
+ return err;
+}
+
+static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
+{
+ u32 status;
+ const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ struct tegra_i2c_dev *i2c_dev = dev_id;
+
+ status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+
+ if (status == 0) {
+ dev_warn(i2c_dev->dev, "interrupt with no status\n");
+ return IRQ_NONE;
+ }
+
+ if (unlikely(status & status_err)) {
+ if (status & I2C_INT_NO_ACK)
+ i2c_dev->msg_err |= I2C_ERR_NO_ACK;
+ if (status & I2C_INT_ARBITRATION_LOST)
+ i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
+ complete(&i2c_dev->msg_complete);
+ goto err;
+ }
+
+ if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_empty_rx_fifo(i2c_dev);
+ else
+ BUG();
+ }
+
+ if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
+ if (i2c_dev->msg_buf_remaining)
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+ else
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+ }
+
+ if ((status & I2C_INT_PACKET_XFER_COMPLETE) &&
+ !i2c_dev->msg_buf_remaining)
+ complete(&i2c_dev->msg_complete);
+
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+ return IRQ_HANDLED;
+err:
+ /* An error occured, mask all interrupts */
+ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
+ I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
+ I2C_INT_RX_FIFO_DATA_REQ);
+ i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ return IRQ_HANDLED;
+}
+
+static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, int stop)
+{
+ u32 packet_header;
+ u32 int_mask;
+ int ret;
+
+ tegra_i2c_flush_fifos(i2c_dev);
+ i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ i2c_dev->msg_buf = msg->buf;
+ i2c_dev->msg_buf_remaining = msg->len;
+ i2c_dev->msg_err = I2C_ERR_NONE;
+ i2c_dev->msg_read = (msg->flags & I2C_M_RD);
+ INIT_COMPLETION(i2c_dev->msg_complete);
+
+ packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
+ PACKET_HEADER0_PROTOCOL_I2C |
+ (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
+ (1 << PACKET_HEADER0_PACKET_ID_SHIFT);
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = msg->len - 1;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
+ packet_header |= I2C_HEADER_IE_ENABLE;
+ if (msg->flags & I2C_M_TEN)
+ packet_header |= I2C_HEADER_10BIT_ADDR;
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ packet_header |= I2C_HEADER_CONT_ON_NAK;
+ if (msg->flags & I2C_M_NOSTART)
+ packet_header |= I2C_HEADER_REPEAT_START;
+ if (msg->flags & I2C_M_RD)
+ packet_header |= I2C_HEADER_READ;
+ i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+ if (!(msg->flags & I2C_M_RD))
+ tegra_i2c_fill_tx_fifo(i2c_dev);
+
+ int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+ if (msg->flags & I2C_M_RD)
+ int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+ else if (i2c_dev->msg_buf_remaining)
+ int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+ tegra_i2c_unmask_irq(i2c_dev, int_mask);
+ dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
+ i2c_readl(i2c_dev, I2C_INT_MASK));
+
+ ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
+ tegra_i2c_mask_irq(i2c_dev, int_mask);
+
+ if (WARN_ON(ret == 0)) {
+ dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+
+ tegra_i2c_init(i2c_dev);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
+ ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
+
+ if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
+ return 0;
+
+ tegra_i2c_init(i2c_dev);
+ if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ return -EREMOTEIO;
+ }
+
+ return -EIO;
+}
+
+static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ int i;
+ int ret = 0;
+
+ if (i2c_dev->is_suspended)
+ return -EBUSY;
+
+ clk_enable(i2c_dev->clk);
+ for (i = 0; i < num; i++) {
+ int stop = (i == (num - 1)) ? 1 : 0;
+ ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+ if (ret)
+ break;
+ }
+ clk_disable(i2c_dev->clk);
+ return ret ?: i;
+}
+
+static u32 tegra_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm tegra_i2c_algo = {
+ .master_xfer = tegra_i2c_xfer,
+ .functionality = tegra_i2c_func,
+};
+
+static int tegra_i2c_probe(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev;
+ struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct resource *iomem;
+ struct clk *clk;
+ struct clk *i2c_clk;
+ void *base;
+ int irq;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -EINVAL;
+ }
+ iomem = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!iomem) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ base = ioremap(iomem->start, resource_size(iomem));
+ if (!base) {
+ dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no irq resource\n");
+ ret = -EINVAL;
+ goto err_iounmap;
+ }
+ irq = res->start;
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "missing controller clock");
+ ret = PTR_ERR(clk);
+ goto err_release_region;
+ }
+
+ i2c_clk = clk_get(&pdev->dev, "i2c");
+ if (IS_ERR(i2c_clk)) {
+ dev_err(&pdev->dev, "missing bus clock");
+ ret = PTR_ERR(i2c_clk);
+ goto err_clk_put;
+ }
+
+ i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
+ if (!i2c_dev) {
+ ret = -ENOMEM;
+ goto err_i2c_clk_put;
+ }
+
+ i2c_dev->base = base;
+ i2c_dev->clk = clk;
+ i2c_dev->i2c_clk = i2c_clk;
+ i2c_dev->iomem = iomem;
+ i2c_dev->adapter.algo = &tegra_i2c_algo;
+ i2c_dev->irq = irq;
+ i2c_dev->cont_id = pdev->id;
+ i2c_dev->dev = &pdev->dev;
+ i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000;
+
+ if (pdev->id == 3)
+ i2c_dev->is_dvc = 1;
+ init_completion(&i2c_dev->msg_complete);
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ ret = tegra_i2c_init(i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize i2c controller");
+ goto err_free;
+ }
+
+ ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
+ goto err_free;
+ }
+
+ clk_enable(i2c_dev->i2c_clk);
+
+ i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+ i2c_dev->adapter.owner = THIS_MODULE;
+ i2c_dev->adapter.class = I2C_CLASS_HWMON;
+ strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
+ sizeof(i2c_dev->adapter.name));
+ i2c_dev->adapter.algo = &tegra_i2c_algo;
+ i2c_dev->adapter.dev.parent = &pdev->dev;
+ i2c_dev->adapter.nr = pdev->id;
+
+ ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add I2C adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+err_free_irq:
+ free_irq(i2c_dev->irq, i2c_dev);
+err_free:
+ kfree(i2c_dev);
+err_i2c_clk_put:
+ clk_put(i2c_clk);
+err_clk_put:
+ clk_put(clk);
+err_release_region:
+ release_mem_region(iomem->start, resource_size(iomem));
+err_iounmap:
+ iounmap(base);
+ return ret;
+}
+
+static int tegra_i2c_remove(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ i2c_del_adapter(&i2c_dev->adapter);
+ free_irq(i2c_dev->irq, i2c_dev);
+ clk_put(i2c_dev->i2c_clk);
+ clk_put(i2c_dev->clk);
+ release_mem_region(i2c_dev->iomem->start,
+ resource_size(i2c_dev->iomem));
+ iounmap(i2c_dev->base);
+ kfree(i2c_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_lock_adapter(&i2c_dev->adapter);
+ i2c_dev->is_suspended = true;
+ i2c_unlock_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static int tegra_i2c_resume(struct platform_device *pdev)
+{
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ int ret;
+
+ i2c_lock_adapter(&i2c_dev->adapter);
+
+ ret = tegra_i2c_init(i2c_dev);
+
+ if (ret) {
+ i2c_unlock_adapter(&i2c_dev->adapter);
+ return ret;
+ }
+
+ i2c_dev->is_suspended = false;
+
+ i2c_unlock_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver tegra_i2c_driver = {
+ .probe = tegra_i2c_probe,
+ .remove = tegra_i2c_remove,
+#ifdef CONFIG_PM
+ .suspend = tegra_i2c_suspend,
+ .resume = tegra_i2c_resume,
+#endif
+ .driver = {
+ .name = "tegra-i2c",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init tegra_i2c_init_driver(void)
+{
+ return platform_driver_register(&tegra_i2c_driver);
+}
+
+static void __exit tegra_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_i2c_driver);
+}
+
+subsys_initcall(tegra_i2c_init_driver);
+module_exit(tegra_i2c_exit_driver);
+
+MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver");
+MODULE_AUTHOR("Colin Cross");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index bab9f74c0665..cfed5399f074 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -53,8 +53,8 @@ static void __ipath_release_user_pages(struct page **p, size_t num_pages,
}
/* call with current->mm->mmap_sem held */
-static int __get_user_pages(unsigned long start_page, size_t num_pages,
- struct page **p, struct vm_area_struct **vma)
+static int __ipath_get_user_pages(unsigned long start_page, size_t num_pages,
+ struct page **p, struct vm_area_struct **vma)
{
unsigned long lock_limit;
size_t got;
@@ -165,7 +165,7 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
down_write(&current->mm->mmap_sem);
- ret = __get_user_pages(start_page, num_pages, p, NULL);
+ ret = __ipath_get_user_pages(start_page, num_pages, p, NULL);
up_write(&current->mm->mmap_sem);
diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
index d7a26c1d4f37..7689e49c13c9 100644
--- a/drivers/infiniband/hw/qib/qib_user_pages.c
+++ b/drivers/infiniband/hw/qib/qib_user_pages.c
@@ -51,8 +51,8 @@ static void __qib_release_user_pages(struct page **p, size_t num_pages,
/*
* Call with current->mm->mmap_sem held.
*/
-static int __get_user_pages(unsigned long start_page, size_t num_pages,
- struct page **p, struct vm_area_struct **vma)
+static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
+ struct page **p, struct vm_area_struct **vma)
{
unsigned long lock_limit;
size_t got;
@@ -136,7 +136,7 @@ int qib_get_user_pages(unsigned long start_page, size_t num_pages,
down_write(&current->mm->mmap_sem);
- ret = __get_user_pages(start_page, num_pages, p, NULL);
+ ret = __qib_get_user_pages(start_page, num_pages, p, NULL);
up_write(&current->mm->mmap_sem);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 7b2fc98e2f2b..8db008de5392 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -532,6 +532,29 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s
stats->custom[3].value = conn->fmr_unalign_cnt;
}
+static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep,
+ enum iscsi_param param, char *buf)
+{
+ struct iser_conn *ib_conn = ep->dd_data;
+ int len;
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ case ISCSI_PARAM_CONN_ADDRESS:
+ if (!ib_conn || !ib_conn->cma_id)
+ return -ENOTCONN;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &ib_conn->cma_id->route.addr.dst_addr,
+ param, buf);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
static struct iscsi_endpoint *
iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
int non_blocking)
@@ -637,6 +660,8 @@ static struct iscsi_transport iscsi_iser_transport = {
ISCSI_MAX_BURST |
ISCSI_PDU_INORDER_EN |
ISCSI_DATASEQ_INORDER_EN |
+ ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
@@ -659,6 +684,7 @@ static struct iscsi_transport iscsi_iser_transport = {
.destroy_conn = iscsi_iser_conn_destroy,
.set_param = iscsi_iser_set_param,
.get_conn_param = iscsi_conn_get_param,
+ .get_ep_param = iscsi_iser_get_ep_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
.stop_conn = iscsi_iser_conn_stop,
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 92563a681d65..12abc50508e5 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -107,7 +107,8 @@ static void amba_kmi_close(struct serio *io)
clk_disable(kmi->clk);
}
-static int __devinit amba_kmi_probe(struct amba_device *dev, struct amba_id *id)
+static int __devinit amba_kmi_probe(struct amba_device *dev,
+ const struct amba_id *id)
{
struct amba_kmi_port *kmi;
struct serio *io;
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 199f374cf9da..f6e108d0125f 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -206,7 +206,7 @@ recv_Bchannel(struct bchannel *bch, unsigned int id)
hh->id = id;
if (bch->rcount >= 64) {
printk(KERN_WARNING "B-channel %p receive queue overflow, "
- "fushing!\n", bch);
+ "flushing!\n", bch);
skb_queue_purge(&bch->rqueue);
bch->rcount = 0;
return;
@@ -231,7 +231,7 @@ recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb)
{
if (bch->rcount >= 64) {
printk(KERN_WARNING "B-channel %p receive queue overflow, "
- "fushing!\n", bch);
+ "flushing!\n", bch);
skb_queue_purge(&bch->rqueue);
bch->rcount = 0;
}
@@ -279,7 +279,7 @@ confirm_Bsend(struct bchannel *bch)
if (bch->rcount >= 64) {
printk(KERN_WARNING "B-channel %p receive queue overflow, "
- "fushing!\n", bch);
+ "flushing!\n", bch);
skb_queue_purge(&bch->rqueue);
bch->rcount = 0;
}
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 39f660b2a60d..2637c139777b 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -283,7 +283,7 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
}
}
-static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
+static void rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
{
cancel_delayed_work_sync(&rm->cpu[0].sniffer);
cancel_delayed_work_sync(&rm->cpu[1].sniffer);
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index b82d28819e2a..4b0b63c290a6 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1283,24 +1283,22 @@ static int do_end_io(struct multipath *m, struct request *clone,
if (!error && !clone->errors)
return 0; /* I/O complete */
- if (error == -EOPNOTSUPP)
- return error;
-
- if (clone->cmd_flags & REQ_DISCARD)
- /*
- * Pass all discard request failures up.
- * FIXME: only fail_path if the discard failed due to a
- * transport problem. This requires precise understanding
- * of the underlying failure (e.g. the SCSI sense).
- */
+ if (error == -EOPNOTSUPP || error == -EREMOTEIO)
return error;
if (mpio->pgpath)
fail_path(mpio->pgpath);
spin_lock_irqsave(&m->lock, flags);
- if (!m->nr_valid_paths && !m->queue_if_no_path && !__must_push_back(m))
- r = -EIO;
+ if (!m->nr_valid_paths) {
+ if (!m->queue_if_no_path) {
+ if (!__must_push_back(m))
+ r = -EIO;
+ } else {
+ if (error == -EBADE)
+ r = error;
+ }
+ }
spin_unlock_irqrestore(&m->lock, flags);
return r;
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 013c7d881948..22027e7946f7 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -2593,6 +2593,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
#define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE (0x03)
#define MPI_SAS_IOUNIT0_RATE_1_5 (0x08)
#define MPI_SAS_IOUNIT0_RATE_3_0 (0x09)
+#define MPI_SAS_IOUNIT0_RATE_6_0 (0x0A)
/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 8faa4fab7b89..fd6222882a0e 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -841,6 +841,7 @@ typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS
#define MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE (0x03)
#define MPI_EVENT_SAS_PLS_LR_RATE_1_5 (0x08)
#define MPI_EVENT_SAS_PLS_LR_RATE_3_0 (0x09)
+#define MPI_EVENT_SAS_PLS_LR_RATE_6_0 (0x0A)
/* SAS Discovery Event data */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 3358c0af3466..ec8080c98081 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -7418,7 +7418,12 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
snprintf(evStr, EVENT_DESCR_STR_SZ,
"SAS PHY Link Status: Phy=%d:"
- " Rate 3.0 Gpbs",PhyNumber);
+ " Rate 3.0 Gbps", PhyNumber);
+ break;
+ case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS PHY Link Status: Phy=%d:"
+ " Rate 6.0 Gbps", PhyNumber);
break;
default:
snprintf(evStr, EVENT_DESCR_STR_SZ,
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index e8deb8ed0499..878bda0cce70 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1314,8 +1314,10 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
else
karg->adapterType = MPT_IOCTL_INTERFACE_SCSI;
- if (karg->hdr.port > 1)
+ if (karg->hdr.port > 1) {
+ kfree(karg);
return -EINVAL;
+ }
port = karg->hdr.port;
karg->port = port;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 8aefb1829fcd..f5a14afad2cd 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1973,7 +1973,6 @@ static struct scsi_host_template mptsas_driver_template = {
.change_queue_depth = mptscsih_change_queue_depth,
.eh_abort_handler = mptscsih_abort,
.eh_device_reset_handler = mptscsih_dev_reset,
- .eh_bus_reset_handler = mptscsih_bus_reset,
.eh_host_reset_handler = mptscsih_host_reset,
.bios_param = mptscsih_bios_param,
.can_queue = MPT_SAS_CAN_QUEUE,
@@ -3063,6 +3062,9 @@ static int mptsas_probe_one_phy(struct device *dev,
case MPI_SAS_IOUNIT0_RATE_3_0:
phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
break;
+ case MPI_SAS_IOUNIT0_RATE_6_0:
+ phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
+ break;
case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
default:
@@ -3691,7 +3693,8 @@ mptsas_send_link_status_event(struct fw_event_work *fw_event)
}
if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
- link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
+ link_rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
+ link_rate == MPI_SAS_IOUNIT0_RATE_6_0) {
if (!port_info) {
if (ioc->old_sas_discovery_protocal) {
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 7d3cc575c361..098de2b35784 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -1044,8 +1044,7 @@ static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
static int cfg_open(struct inode *inode, struct file *file)
{
- struct i2o_cfg_info *tmp =
- (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info),
+ struct i2o_cfg_info *tmp = kmalloc(sizeof(struct i2o_cfg_info),
GFP_KERNEL);
unsigned long flags;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a6dfa37a674d..fdca643249e1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -81,6 +81,17 @@ config MFD_DM355EVM_MSP
boards. MSP430 firmware manages resets and power sequencing,
inputs from buttons and the IR remote, LEDs, an RTC, and more.
+config MFD_TI_SSP
+ tristate "TI Sequencer Serial Port support"
+ depends on ARCH_DAVINCI_TNETV107X
+ select MFD_CORE
+ ---help---
+ Say Y here if you want support for the Sequencer Serial Port
+ in a Texas Instruments TNETV107X SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti-ssp.
+
config HTC_EGPIO
bool "HTC EGPIO support"
depends on GENERIC_HARDIRQS && GPIOLIB && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 91fe384459ab..f0e25cad762e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
+obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
new file mode 100644
index 000000000000..af9ab0e5ca64
--- /dev/null
+++ b/drivers/mfd/ti-ssp.c
@@ -0,0 +1,476 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ti_ssp.h>
+
+/* Register Offsets */
+#define REG_REV 0x00
+#define REG_IOSEL_1 0x04
+#define REG_IOSEL_2 0x08
+#define REG_PREDIV 0x0c
+#define REG_INTR_ST 0x10
+#define REG_INTR_EN 0x14
+#define REG_TEST_CTRL 0x18
+
+/* Per port registers */
+#define PORT_CFG_2 0x00
+#define PORT_ADDR 0x04
+#define PORT_DATA 0x08
+#define PORT_CFG_1 0x0c
+#define PORT_STATE 0x10
+
+#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT)
+#define SSP_PORT_CLKRATE_MASK 0x0f
+
+#define SSP_SEQRAM_WR_EN BIT(4)
+#define SSP_SEQRAM_RD_EN BIT(5)
+#define SSP_START BIT(15)
+#define SSP_BUSY BIT(10)
+#define SSP_PORT_ASL BIT(7)
+#define SSP_PORT_CFO1 BIT(6)
+
+#define SSP_PORT_SEQRAM_SIZE 32
+
+static const int ssp_port_base[] = {0x040, 0x080};
+static const int ssp_port_seqram[] = {0x100, 0x180};
+
+struct ti_ssp {
+ struct resource *res;
+ struct device *dev;
+ void __iomem *regs;
+ spinlock_t lock;
+ struct clk *clk;
+ int irq;
+ wait_queue_head_t wqh;
+
+ /*
+ * Some of the iosel2 register bits always read-back as 0, we need to
+ * remember these values so that we don't clobber previously set
+ * values.
+ */
+ u32 iosel2;
+};
+
+static inline struct ti_ssp *dev_to_ssp(struct device *dev)
+{
+ return dev_get_drvdata(dev->parent);
+}
+
+static inline int dev_to_port(struct device *dev)
+{
+ return to_platform_device(dev)->id;
+}
+
+/* Register Access Helpers, rmw() functions need to run locked */
+static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
+{
+ return __raw_readl(ssp->regs + reg);
+}
+
+static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
+{
+ __raw_writel(val, ssp->regs + reg);
+}
+
+static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
+{
+ ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
+}
+
+static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
+{
+ return ssp_read(ssp, ssp_port_base[port] + reg);
+}
+
+static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
+ u32 val)
+{
+ ssp_write(ssp, ssp_port_base[port] + reg, val);
+}
+
+static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
+ u32 mask, u32 bits)
+{
+ ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
+}
+
+static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
+ u32 bits)
+{
+ ssp_port_rmw(ssp, port, reg, bits, 0);
+}
+
+static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
+ u32 bits)
+{
+ ssp_port_rmw(ssp, port, reg, 0, bits);
+}
+
+/* Called to setup port clock mode, caller must hold ssp->lock */
+static int __set_mode(struct ti_ssp *ssp, int port, int mode)
+{
+ mode &= SSP_PORT_CONFIG_MASK;
+ ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
+
+ return 0;
+}
+
+int ti_ssp_set_mode(struct device *dev, int mode)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev);
+ int ret;
+
+ spin_lock(&ssp->lock);
+ ret = __set_mode(ssp, port, mode);
+ spin_unlock(&ssp->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(ti_ssp_set_mode);
+
+/* Called to setup iosel2, caller must hold ssp->lock */
+static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
+{
+ ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
+ ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
+}
+
+/* Called to setup port iosel, caller must hold ssp->lock */
+static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
+{
+ unsigned val, shift = port ? 16 : 0;
+
+ /* IOSEL1 gets the least significant 16 bits */
+ val = ssp_read(ssp, REG_IOSEL_1);
+ val &= 0xffff << (port ? 0 : 16);
+ val |= (iosel & 0xffff) << (port ? 16 : 0);
+ ssp_write(ssp, REG_IOSEL_1, val);
+
+ /* IOSEL2 gets the most significant 16 bits */
+ val = (iosel >> 16) & 0x7;
+ __set_iosel2(ssp, 0x7 << shift, val << shift);
+}
+
+int ti_ssp_set_iosel(struct device *dev, u32 iosel)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev);
+
+ spin_lock(&ssp->lock);
+ __set_iosel(ssp, port, iosel);
+ spin_unlock(&ssp->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ti_ssp_set_iosel);
+
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev);
+ int i;
+
+ if (len > SSP_PORT_SEQRAM_SIZE)
+ return -ENOSPC;
+
+ spin_lock(&ssp->lock);
+
+ /* Enable SeqRAM access */
+ ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+ /* Copy code */
+ for (i = 0; i < len; i++) {
+ __raw_writel(prog[i], ssp->regs + offs + 4*i +
+ ssp_port_seqram[port]);
+ }
+
+ /* Disable SeqRAM access */
+ ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
+
+ spin_unlock(&ssp->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ti_ssp_load);
+
+int ti_ssp_raw_read(struct device *dev)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev);
+ int shift = port ? 27 : 11;
+
+ return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
+}
+EXPORT_SYMBOL(ti_ssp_raw_read);
+
+int ti_ssp_raw_write(struct device *dev, u32 val)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev), shift;
+
+ spin_lock(&ssp->lock);
+
+ shift = port ? 22 : 6;
+ val &= 0xf;
+ __set_iosel2(ssp, 0xf << shift, val << shift);
+
+ spin_unlock(&ssp->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ti_ssp_raw_write);
+
+static inline int __xfer_done(struct ti_ssp *ssp, int port)
+{
+ return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
+}
+
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
+{
+ struct ti_ssp *ssp = dev_to_ssp(dev);
+ int port = dev_to_port(dev);
+ int ret;
+
+ if (pc & ~(0x3f))
+ return -EINVAL;
+
+ /* Grab ssp->lock to serialize rmw on ssp registers */
+ spin_lock(&ssp->lock);
+
+ ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
+ ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
+ ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
+
+ /* grab wait queue head lock to avoid race with the isr */
+ spin_lock_irq(&ssp->wqh.lock);
+
+ /* kick off sequence execution in hardware */
+ ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
+
+ /* drop ssp lock; no register writes beyond this */
+ spin_unlock(&ssp->lock);
+
+ ret = wait_event_interruptible_locked_irq(ssp->wqh,
+ __xfer_done(ssp, port));
+ spin_unlock_irq(&ssp->wqh.lock);
+
+ if (ret < 0)
+ return ret;
+
+ if (output) {
+ *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
+ (ssp_port_read(ssp, port, PORT_DATA) & 0xffff);
+ }
+
+ ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
+
+ return ret;
+}
+EXPORT_SYMBOL(ti_ssp_run);
+
+static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
+{
+ struct ti_ssp *ssp = dev_data;
+
+ spin_lock(&ssp->wqh.lock);
+
+ ssp_write(ssp, REG_INTR_ST, 0x3);
+ wake_up_locked(&ssp->wqh);
+
+ spin_unlock(&ssp->wqh.lock);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit ti_ssp_probe(struct platform_device *pdev)
+{
+ static struct ti_ssp *ssp;
+ const struct ti_ssp_data *pdata = pdev->dev.platform_data;
+ int error = 0, prediv = 0xff, id;
+ unsigned long sysclk;
+ struct device *dev = &pdev->dev;
+ struct mfd_cell cells[2];
+
+ ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
+ if (!ssp) {
+ dev_err(dev, "cannot allocate device info\n");
+ return -ENOMEM;
+ }
+
+ ssp->dev = dev;
+ dev_set_drvdata(dev, ssp);
+
+ ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ssp->res) {
+ error = -ENODEV;
+ dev_err(dev, "cannot determine register area\n");
+ goto error_res;
+ }
+
+ if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
+ pdev->name)) {
+ error = -ENOMEM;
+ dev_err(dev, "cannot claim register memory\n");
+ goto error_res;
+ }
+
+ ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
+ if (!ssp->regs) {
+ error = -ENOMEM;
+ dev_err(dev, "cannot map register memory\n");
+ goto error_map;
+ }
+
+ ssp->clk = clk_get(dev, NULL);
+ if (IS_ERR(ssp->clk)) {
+ error = PTR_ERR(ssp->clk);
+ dev_err(dev, "cannot claim device clock\n");
+ goto error_clk;
+ }
+
+ ssp->irq = platform_get_irq(pdev, 0);
+ if (ssp->irq < 0) {
+ error = -ENODEV;
+ dev_err(dev, "unknown irq\n");
+ goto error_irq;
+ }
+
+ error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
+ dev_name(dev), ssp);
+ if (error < 0) {
+ dev_err(dev, "cannot acquire irq\n");
+ goto error_irq;
+ }
+
+ spin_lock_init(&ssp->lock);
+ init_waitqueue_head(&ssp->wqh);
+
+ /* Power on and initialize SSP */
+ error = clk_enable(ssp->clk);
+ if (error) {
+ dev_err(dev, "cannot enable device clock\n");
+ goto error_enable;
+ }
+
+ /* Reset registers to a sensible known state */
+ ssp_write(ssp, REG_IOSEL_1, 0);
+ ssp_write(ssp, REG_IOSEL_2, 0);
+ ssp_write(ssp, REG_INTR_EN, 0x3);
+ ssp_write(ssp, REG_INTR_ST, 0x3);
+ ssp_write(ssp, REG_TEST_CTRL, 0);
+ ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
+ ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
+ ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
+ ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
+
+ sysclk = clk_get_rate(ssp->clk);
+ if (pdata && pdata->out_clock)
+ prediv = (sysclk / pdata->out_clock) - 1;
+ prediv = clamp(prediv, 0, 0xff);
+ ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
+
+ memset(cells, 0, sizeof(cells));
+ for (id = 0; id < 2; id++) {
+ const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
+
+ cells[id].id = id;
+ cells[id].name = data->dev_name;
+ cells[id].platform_data = data->pdata;
+ cells[id].data_size = data->pdata_size;
+ }
+
+ error = mfd_add_devices(dev, 0, cells, 2, NULL, 0);
+ if (error < 0) {
+ dev_err(dev, "cannot add mfd cells\n");
+ goto error_enable;
+ }
+
+ return 0;
+
+error_enable:
+ free_irq(ssp->irq, ssp);
+error_irq:
+ clk_put(ssp->clk);
+error_clk:
+ iounmap(ssp->regs);
+error_map:
+ release_mem_region(ssp->res->start, resource_size(ssp->res));
+error_res:
+ kfree(ssp);
+ return error;
+}
+
+static int __devexit ti_ssp_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ti_ssp *ssp = dev_get_drvdata(dev);
+
+ mfd_remove_devices(dev);
+ clk_disable(ssp->clk);
+ free_irq(ssp->irq, ssp);
+ clk_put(ssp->clk);
+ iounmap(ssp->regs);
+ release_mem_region(ssp->res->start, resource_size(ssp->res));
+ kfree(ssp);
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct platform_driver ti_ssp_driver = {
+ .probe = ti_ssp_probe,
+ .remove = __devexit_p(ti_ssp_remove),
+ .driver = {
+ .name = "ti-ssp",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init ti_ssp_init(void)
+{
+ return platform_driver_register(&ti_ssp_driver);
+}
+module_init(ti_ssp_init);
+
+static void __exit ti_ssp_exit(void)
+{
+ platform_driver_unregister(&ti_ssp_driver);
+}
+module_exit(ti_ssp_exit);
+
+MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp");
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index afe8c6fa166a..54f91321749a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -225,7 +225,7 @@ config MMC_OMAP
config MMC_OMAP_HS
tristate "TI OMAP High Speed Multimedia Card Interface support"
- depends on ARCH_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4
+ depends on SOC_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4
help
This selects the TI OMAP High Speed Multimedia card Interface.
If you have an OMAP2430 or OMAP3 board or OMAP4 board with a
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 2d6de3e03e2d..5bbb87d10251 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -2,7 +2,7 @@
* linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
*
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * Copyright (C) 2010 ST-Ericsson AB.
+ * Copyright (C) 2010 ST-Ericsson SA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -25,8 +25,10 @@
#include <linux/clk.h>
#include <linux/scatterlist.h>
#include <linux/gpio.h>
-#include <linux/amba/mmci.h>
#include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/mmci.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -142,9 +144,6 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
host->mrq = NULL;
host->cmd = NULL;
- if (mrq->data)
- mrq->data->bytes_xfered = host->data_xfered;
-
/*
* Need to drop the host lock here; mmc_request_done may call
* back into the driver...
@@ -189,6 +188,248 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
}
+/*
+ * All the DMA operation mode stuff goes inside this ifdef.
+ * This assumes that you have a generic DMA device interface,
+ * no custom DMA interfaces are supported.
+ */
+#ifdef CONFIG_DMA_ENGINE
+static void __devinit mmci_dma_setup(struct mmci_host *host)
+{
+ struct mmci_platform_data *plat = host->plat;
+ const char *rxname, *txname;
+ dma_cap_mask_t mask;
+
+ if (!plat || !plat->dma_filter) {
+ dev_info(mmc_dev(host->mmc), "no DMA platform data\n");
+ return;
+ }
+
+ /* Try to acquire a generic DMA engine slave channel */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /*
+ * If only an RX channel is specified, the driver will
+ * attempt to use it bidirectionally, however if it is
+ * is specified but cannot be located, DMA will be disabled.
+ */
+ if (plat->dma_rx_param) {
+ host->dma_rx_channel = dma_request_channel(mask,
+ plat->dma_filter,
+ plat->dma_rx_param);
+ /* E.g if no DMA hardware is present */
+ if (!host->dma_rx_channel)
+ dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
+ }
+
+ if (plat->dma_tx_param) {
+ host->dma_tx_channel = dma_request_channel(mask,
+ plat->dma_filter,
+ plat->dma_tx_param);
+ if (!host->dma_tx_channel)
+ dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
+ } else {
+ host->dma_tx_channel = host->dma_rx_channel;
+ }
+
+ if (host->dma_rx_channel)
+ rxname = dma_chan_name(host->dma_rx_channel);
+ else
+ rxname = "none";
+
+ if (host->dma_tx_channel)
+ txname = dma_chan_name(host->dma_tx_channel);
+ else
+ txname = "none";
+
+ dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
+ rxname, txname);
+
+ /*
+ * Limit the maximum segment size in any SG entry according to
+ * the parameters of the DMA engine device.
+ */
+ if (host->dma_tx_channel) {
+ struct device *dev = host->dma_tx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+ if (host->dma_rx_channel) {
+ struct device *dev = host->dma_rx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+}
+
+/*
+ * This is used in __devinit or __devexit so inline it
+ * so it can be discarded.
+ */
+static inline void mmci_dma_release(struct mmci_host *host)
+{
+ struct mmci_platform_data *plat = host->plat;
+
+ if (host->dma_rx_channel)
+ dma_release_channel(host->dma_rx_channel);
+ if (host->dma_tx_channel && plat->dma_tx_param)
+ dma_release_channel(host->dma_tx_channel);
+ host->dma_rx_channel = host->dma_tx_channel = NULL;
+}
+
+static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dma_chan *chan = host->dma_current;
+ enum dma_data_direction dir;
+ u32 status;
+ int i;
+
+ /* Wait up to 1ms for the DMA to complete */
+ for (i = 0; ; i++) {
+ status = readl(host->base + MMCISTATUS);
+ if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
+ break;
+ udelay(10);
+ }
+
+ /*
+ * Check to see whether we still have some data left in the FIFO -
+ * this catches DMA controllers which are unable to monitor the
+ * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
+ * contiguous buffers. On TX, we'll get a FIFO underrun error.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dmaengine_terminate_all(chan);
+ if (!data->error)
+ data->error = -EIO;
+ }
+
+ if (data->flags & MMC_DATA_WRITE) {
+ dir = DMA_TO_DEVICE;
+ } else {
+ dir = DMA_FROM_DEVICE;
+ }
+
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+
+ /*
+ * Use of DMA with scatter-gather is impossible.
+ * Give up with DMA and switch back to PIO mode.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
+ mmci_dma_release(host);
+ }
+}
+
+static void mmci_dma_data_error(struct mmci_host *host)
+{
+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+ dmaengine_terminate_all(host->dma_current);
+}
+
+static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+{
+ struct variant_data *variant = host->variant;
+ struct dma_slave_config conf = {
+ .src_addr = host->phybase + MMCIFIFO,
+ .dst_addr = host->phybase + MMCIFIFO,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ };
+ struct mmc_data *data = host->data;
+ struct dma_chan *chan;
+ struct dma_device *device;
+ struct dma_async_tx_descriptor *desc;
+ int nr_sg;
+
+ host->dma_current = NULL;
+
+ if (data->flags & MMC_DATA_READ) {
+ conf.direction = DMA_FROM_DEVICE;
+ chan = host->dma_rx_channel;
+ } else {
+ conf.direction = DMA_TO_DEVICE;
+ chan = host->dma_tx_channel;
+ }
+
+ /* If there's no DMA channel, fall back to PIO */
+ if (!chan)
+ return -EINVAL;
+
+ /* If less than or equal to the fifo size, don't bother with DMA */
+ if (host->size <= variant->fifosize)
+ return -EINVAL;
+
+ device = chan->device;
+ nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, conf.direction);
+ if (nr_sg == 0)
+ return -EINVAL;
+
+ dmaengine_slave_config(chan, &conf);
+ desc = device->device_prep_slave_sg(chan, data->sg, nr_sg,
+ conf.direction, DMA_CTRL_ACK);
+ if (!desc)
+ goto unmap_exit;
+
+ /* Okay, go for it. */
+ host->dma_current = chan;
+
+ dev_vdbg(mmc_dev(host->mmc),
+ "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
+ data->sg_len, data->blksz, data->blocks, data->flags);
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
+
+ datactrl |= MCI_DPSM_DMAENABLE;
+
+ /* Trigger the DMA transfer */
+ writel(datactrl, host->base + MMCIDATACTRL);
+
+ /*
+ * Let the MMCI say when the data is ended and it's time
+ * to fire next DMA request. When that happens, MMCI will
+ * call mmci_data_end()
+ */
+ writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
+ host->base + MMCIMASK0);
+ return 0;
+
+unmap_exit:
+ dmaengine_terminate_all(chan);
+ dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction);
+ return -ENOMEM;
+}
+#else
+/* Blank functions if the DMA engine is not available */
+static inline void mmci_dma_setup(struct mmci_host *host)
+{
+}
+
+static inline void mmci_dma_release(struct mmci_host *host)
+{
+}
+
+static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
+{
+}
+
+static inline void mmci_dma_data_error(struct mmci_host *host)
+{
+}
+
+static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
+{
+ return -ENOSYS;
+}
+#endif
+
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
struct variant_data *variant = host->variant;
@@ -202,9 +443,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
host->data = data;
host->size = data->blksz * data->blocks;
- host->data_xfered = 0;
-
- mmci_init_sg(host, data);
+ data->bytes_xfered = 0;
clks = (unsigned long long)data->timeout_ns * host->cclk;
do_div(clks, 1000000000UL);
@@ -219,15 +458,29 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
BUG_ON(1 << blksz_bits != data->blksz);
datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
- if (data->flags & MMC_DATA_READ) {
+
+ if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION;
+
+ /*
+ * Attempt to use DMA operation mode, if this
+ * should fail, fall back to PIO mode
+ */
+ if (!mmci_dma_start_data(host, datactrl))
+ return;
+
+ /* IRQ mode, map the SG list for CPU reading/writing */
+ mmci_init_sg(host, data);
+
+ if (data->flags & MMC_DATA_READ) {
irqmask = MCI_RXFIFOHALFFULLMASK;
/*
- * If we have less than a FIFOSIZE of bytes to transfer,
- * trigger a PIO interrupt as soon as any data is available.
+ * If we have less than the fifo 'half-full' threshold to
+ * transfer, trigger a PIO interrupt as soon as any data
+ * is available.
*/
- if (host->size < variant->fifosize)
+ if (host->size < variant->fifohalfsize)
irqmask |= MCI_RXDATAAVLBLMASK;
} else {
/*
@@ -283,49 +536,51 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
u32 remain, success;
- /* Calculate how far we are into the transfer */
+ /* Terminate the DMA transfer */
+ if (dma_inprogress(host))
+ mmci_dma_data_error(host);
+
+ /*
+ * Calculate how far we are into the transfer. Note that
+ * the data counter gives the number of bytes transferred
+ * on the MMC bus, not on the host side. On reads, this
+ * can be as much as a FIFO-worth of data ahead. This
+ * matters for FIFO overruns only.
+ */
remain = readl(host->base + MMCIDATACNT);
success = data->blksz * data->blocks - remain;
- dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
+ dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
+ status, success);
if (status & MCI_DATACRCFAIL) {
/* Last block was not successful */
- host->data_xfered = round_down(success - 1, data->blksz);
+ success -= 1;
data->error = -EILSEQ;
} else if (status & MCI_DATATIMEOUT) {
- host->data_xfered = round_down(success, data->blksz);
data->error = -ETIMEDOUT;
- } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
- host->data_xfered = round_down(success, data->blksz);
+ } else if (status & MCI_TXUNDERRUN) {
+ data->error = -EIO;
+ } else if (status & MCI_RXOVERRUN) {
+ if (success > host->variant->fifosize)
+ success -= host->variant->fifosize;
+ else
+ success = 0;
data->error = -EIO;
}
-
- /*
- * We hit an error condition. Ensure that any data
- * partially written to a page is properly coherent.
- */
- if (data->flags & MMC_DATA_READ) {
- struct sg_mapping_iter *sg_miter = &host->sg_miter;
- unsigned long flags;
-
- local_irq_save(flags);
- if (sg_miter_next(sg_miter)) {
- flush_dcache_page(sg_miter->page);
- sg_miter_stop(sg_miter);
- }
- local_irq_restore(flags);
- }
+ data->bytes_xfered = round_down(success, data->blksz);
}
if (status & MCI_DATABLOCKEND)
dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
if (status & MCI_DATAEND || data->error) {
+ if (dma_inprogress(host))
+ mmci_dma_unmap(host, data);
mmci_stop_data(host);
if (!data->error)
/* The error clause is handled above, success! */
- host->data_xfered += data->blksz * data->blocks;
+ data->bytes_xfered = data->blksz * data->blocks;
if (!data->stop) {
mmci_request_end(host, data->mrq);
@@ -498,9 +753,6 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
if (remain)
break;
- if (status & MCI_RXACTIVE)
- flush_dcache_page(sg_miter->page);
-
status = readl(base + MMCISTATUS);
} while (1);
@@ -509,10 +761,10 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
local_irq_restore(flags);
/*
- * If we're nearing the end of the read, switch to
- * "any data available" mode.
+ * If we have less than the fifo 'half-full' threshold to transfer,
+ * trigger a PIO interrupt as soon as any data is available.
*/
- if (status & MCI_RXACTIVE && host->size < variant->fifosize)
+ if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize)
mmci_set_mask1(host, MCI_RXDATAAVLBLMASK);
/*
@@ -713,7 +965,8 @@ static const struct mmc_host_ops mmci_ops = {
.get_cd = mmci_get_cd,
};
-static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
+static int __devinit mmci_probe(struct amba_device *dev,
+ const struct amba_id *id)
{
struct mmci_platform_data *plat = dev->dev.platform_data;
struct variant_data *variant = id->data;
@@ -776,6 +1029,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
host->mclk);
}
+ host->phybase = dev->res.start;
host->base = ioremap(dev->res.start, resource_size(&dev->res));
if (!host->base) {
ret = -ENOMEM;
@@ -903,9 +1157,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
amba_set_drvdata(dev, mmc);
- dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n",
- mmc_hostname(mmc), amba_part(dev), amba_rev(dev),
- (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
+ dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n",
+ mmc_hostname(mmc), amba_part(dev), amba_manf(dev),
+ amba_rev(dev), (unsigned long long)dev->res.start,
+ dev->irq[0], dev->irq[1]);
+
+ mmci_dma_setup(host);
mmc_add_host(mmc);
@@ -952,6 +1209,7 @@ static int __devexit mmci_remove(struct amba_device *dev)
writel(0, host->base + MMCICOMMAND);
writel(0, host->base + MMCIDATACTRL);
+ mmci_dma_release(host);
free_irq(dev->irq[0], host);
if (!host->singleirq)
free_irq(dev->irq[1], host);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index c1df7b82d36c..ec9a7bc6d0df 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -148,8 +148,10 @@
struct clk;
struct variant_data;
+struct dma_chan;
struct mmci_host {
+ phys_addr_t phybase;
void __iomem *base;
struct mmc_request *mrq;
struct mmc_command *cmd;
@@ -161,8 +163,6 @@ struct mmci_host {
int gpio_cd_irq;
bool singleirq;
- unsigned int data_xfered;
-
spinlock_t lock;
unsigned int mclk;
@@ -181,5 +181,16 @@ struct mmci_host {
struct sg_mapping_iter sg_miter;
unsigned int size;
struct regulator *vcc;
+
+#ifdef CONFIG_DMA_ENGINE
+ /* DMA stuff */
+ struct dma_chan *dma_current;
+ struct dma_chan *dma_rx_channel;
+ struct dma_chan *dma_tx_channel;
+
+#define dma_inprogress(host) ((host)->dma_current)
+#else
+#define dma_inprogress(host) (0)
+#endif
};
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 153ab977a013..97c9b3638d57 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -36,6 +36,7 @@
#include <linux/io.h>
#include <linux/memory.h>
#include <linux/gfp.h>
+#include <linux/gpio.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
@@ -941,6 +942,38 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock_irqrestore(&host->lock, flags);
}
+static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
+{
+ struct msm_mmc_gpio_data *curr;
+ int i, rc = 0;
+
+ if (!host->plat->gpio_data && host->gpio_config_status == enable)
+ return;
+
+ curr = host->plat->gpio_data;
+ for (i = 0; i < curr->size; i++) {
+ if (enable) {
+ rc = gpio_request(curr->gpio[i].no,
+ curr->gpio[i].name);
+ if (rc) {
+ pr_err("%s: gpio_request(%d, %s) failed %d\n",
+ mmc_hostname(host->mmc),
+ curr->gpio[i].no,
+ curr->gpio[i].name, rc);
+ goto free_gpios;
+ }
+ } else {
+ gpio_free(curr->gpio[i].no);
+ }
+ }
+ host->gpio_config_status = enable;
+ return;
+
+free_gpios:
+ for (; i >= 0; i--)
+ gpio_free(curr->gpio[i].no);
+}
+
static void
msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
@@ -953,6 +986,8 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
msmsdcc_enable_clocks(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+
if (ios->clock) {
if (ios->clock != host->clk_rate) {
rc = clk_set_rate(host->clk, ios->clock);
@@ -979,9 +1014,11 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_OFF:
+ msmsdcc_setup_gpio(host, false);
break;
case MMC_POWER_UP:
pwr |= MCI_PWR_UP;
+ msmsdcc_setup_gpio(host, true);
break;
case MMC_POWER_ON:
pwr |= MCI_PWR_ON;
@@ -998,9 +1035,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
msmsdcc_writel(host, pwr, MMCIPOWER);
}
#if BUSCLK_PWRSAVE
+ spin_lock_irqsave(&host->lock, flags);
msmsdcc_disable_clocks(host, 1);
-#endif
spin_unlock_irqrestore(&host->lock, flags);
+#endif
}
static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 939557af266d..42d7bbc977c5 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -243,6 +243,7 @@ struct msmsdcc_host {
unsigned int cmd_datactrl;
struct mmc_command *cmd_cmd;
u32 cmd_c;
+ bool gpio_config_status;
bool prog_scan;
bool prog_enable;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 078fdf11af03..158c0ee53b2c 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -118,7 +118,7 @@
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MASTER_CLOCK 96000000
-#define DRIVER_NAME "mmci-omap-hs"
+#define DRIVER_NAME "omap_hsmmc"
/* Timeouts for entering power saving states on inactivity, msec */
#define OMAP_MMC_DISABLED_TIMEOUT 100
@@ -260,7 +260,7 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
return ret;
}
-static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
int vdd)
{
struct omap_hsmmc_host *host =
@@ -316,6 +316,12 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
return ret;
}
+static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ return 0;
+}
+
static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
int vdd, int cardsleep)
{
@@ -326,7 +332,7 @@ static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
return regulator_set_mode(host->vcc, mode);
}
-static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
+static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
int vdd, int cardsleep)
{
struct omap_hsmmc_host *host =
@@ -365,6 +371,12 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
return regulator_enable(host->vcc_aux);
}
+static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
+ int vdd, int cardsleep)
+{
+ return 0;
+}
+
static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{
struct regulator *reg;
@@ -379,10 +391,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
break;
case OMAP_MMC2_DEVID:
case OMAP_MMC3_DEVID:
+ case OMAP_MMC5_DEVID:
/* Off-chip level shifting, or none */
- mmc_slot(host).set_power = omap_hsmmc_23_set_power;
- mmc_slot(host).set_sleep = omap_hsmmc_23_set_sleep;
+ mmc_slot(host).set_power = omap_hsmmc_235_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
break;
+ case OMAP_MMC4_DEVID:
+ mmc_slot(host).set_power = omap_hsmmc_4_set_power;
+ mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
default:
pr_err("MMC%d configuration not supported!\n", host->id);
return -EINVAL;
@@ -1555,7 +1571,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
- if (host->id == OMAP_MMC1_DEVID) {
+ if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
/* Only MMC1 can interface at 3V without some flavor
* of external transceiver; but they all handle 1.8V.
*/
@@ -1647,7 +1663,7 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
u32 hctl, capa, value;
/* Only MMC1 supports 3.0V */
- if (host->id == OMAP_MMC1_DEVID) {
+ if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
hctl = SDVS30;
capa = VS30 | VS18;
} else {
@@ -2101,14 +2117,14 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
/* we start off in DISABLED state */
host->dpm_state = DISABLED;
- if (mmc_host_enable(host->mmc) != 0) {
+ if (clk_enable(host->iclk) != 0) {
clk_put(host->iclk);
clk_put(host->fclk);
goto err1;
}
- if (clk_enable(host->iclk) != 0) {
- mmc_host_disable(host->mmc);
+ if (mmc_host_enable(host->mmc) != 0) {
+ clk_disable(host->iclk);
clk_put(host->iclk);
clk_put(host->fclk);
goto err1;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index c89592239bc7..4f6c06f16328 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -106,23 +106,6 @@ config MTD_NAND_OMAP2
help
Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
-config MTD_NAND_OMAP_PREFETCH
- bool "GPMC prefetch support for NAND Flash device"
- depends on MTD_NAND_OMAP2
- default y
- help
- The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
- to improve the performance.
-
-config MTD_NAND_OMAP_PREFETCH_DMA
- depends on MTD_NAND_OMAP_PREFETCH
- bool "DMA mode"
- default n
- help
- The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
- or in DMA interrupt mode.
- Say y for DMA mode or MPU mode will be used
-
config MTD_NAND_IDS
tristate
@@ -476,7 +459,7 @@ config MTD_NAND_MPC5121_NFC
config MTD_NAND_MXC
tristate "MXC NAND support"
- depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX51
+ depends on IMX_HAVE_PLATFORM_MXC_NAND
help
This enables the driver for the NAND flash controller on the
MXC processors.
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index ef932ba55a0b..5ae1d9ee2cf1 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -722,9 +722,8 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
/*
* MXC NANDFC can only perform full page+spare or
* spare-only read/write. When the upper layers
- * layers perform a read/write buf operation,
- * we will used the saved column address to index into
- * the full page.
+ * perform a read/write buf operation, the saved column
+ * address is used to index into the full page.
*/
host->send_addr(host, 0, page_addr == -1);
if (mtd->writesize > 512)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 28af71c61834..7b8f1fffc528 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -11,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/mtd/mtd.h>
@@ -24,6 +25,7 @@
#include <plat/nand.h>
#define DRIVER_NAME "omap2-nand"
+#define OMAP_NAND_TIMEOUT_MS 5000
#define NAND_Ecc_P1e (1 << 0)
#define NAND_Ecc_P2e (1 << 1)
@@ -96,26 +98,19 @@
static const char *part_probes[] = { "cmdlinepart", NULL };
#endif
-#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH
-static int use_prefetch = 1;
-
-/* "modprobe ... use_prefetch=0" etc */
-module_param(use_prefetch, bool, 0);
-MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
-
-#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
-static int use_dma = 1;
+/* oob info generated runtime depending on ecc algorithm and layout selected */
+static struct nand_ecclayout omap_oobinfo;
+/* Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks
+ */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr bb_descrip_flashbased = {
+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
-/* "modprobe ... use_dma=0" etc */
-module_param(use_dma, bool, 0);
-MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
-#else
-static const int use_dma;
-#endif
-#else
-const int use_prefetch;
-static const int use_dma;
-#endif
struct omap_nand_info {
struct nand_hw_control controller;
@@ -129,6 +124,13 @@ struct omap_nand_info {
unsigned long phys_base;
struct completion comp;
int dma_ch;
+ int gpmc_irq;
+ enum {
+ OMAP_NAND_IO_READ = 0, /* read */
+ OMAP_NAND_IO_WRITE, /* write */
+ } iomode;
+ u_char *buf;
+ int buf_len;
};
/**
@@ -256,7 +258,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
}
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+ ret = gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@@ -288,9 +291,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
{
struct omap_nand_info *info = container_of(mtd,
struct omap_nand_info, mtd);
- uint32_t pref_count = 0, w_count = 0;
+ uint32_t w_count = 0;
int i = 0, ret = 0;
u16 *p;
+ unsigned long tim, limit;
/* take care of subpage writes */
if (len % 2 != 0) {
@@ -300,7 +304,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
}
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+ ret = gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@@ -316,15 +321,17 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
iowrite16(*p++, info->nand.IO_ADDR_W);
}
/* wait for data to flushed-out before reset the prefetch */
- do {
- pref_count = gpmc_read_status(GPMC_PREFETCH_COUNT);
- } while (pref_count);
+ tim = 0;
+ limit = (loops_per_jiffy *
+ msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+ while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+ cpu_relax();
+
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
}
}
-#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
/*
* omap_nand_dma_cb: callback on the completion of dma transfer
* @lch: logical channel
@@ -348,14 +355,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
{
struct omap_nand_info *info = container_of(mtd,
struct omap_nand_info, mtd);
- uint32_t prefetch_status = 0;
enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
DMA_FROM_DEVICE;
dma_addr_t dma_addr;
int ret;
+ unsigned long tim, limit;
- /* The fifo depth is 64 bytes. We have a sync at each frame and frame
- * length is 64 bytes.
+ /* The fifo depth is 64 bytes max.
+ * But configure the FIFO-threahold to 32 to get a sync at each frame
+ * and frame length is 32 bytes.
*/
int buf_len = len >> 6;
@@ -396,9 +404,10 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
}
/* configure and start prefetch transfer */
- ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
+ ret = gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write);
if (ret)
- /* PFPW engine is busy, use cpu copy methode */
+ /* PFPW engine is busy, use cpu copy method */
goto out_copy;
init_completion(&info->comp);
@@ -407,10 +416,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
/* setup and start DMA using dma_addr */
wait_for_completion(&info->comp);
+ tim = 0;
+ limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+ while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+ cpu_relax();
- do {
- prefetch_status = gpmc_read_status(GPMC_PREFETCH_COUNT);
- } while (prefetch_status);
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
@@ -426,14 +436,6 @@ out_copy:
: omap_write_buf8(mtd, (u_char *) addr, len);
return 0;
}
-#else
-static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {}
-static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
- unsigned int len, int is_write)
-{
- return 0;
-}
-#endif
/**
* omap_read_buf_dma_pref - read data from NAND controller into buffer
@@ -466,6 +468,157 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd,
omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1);
}
+/*
+ * omap_nand_irq - GMPC irq handler
+ * @this_irq: gpmc irq number
+ * @dev: omap_nand_info structure pointer is passed here
+ */
+static irqreturn_t omap_nand_irq(int this_irq, void *dev)
+{
+ struct omap_nand_info *info = (struct omap_nand_info *) dev;
+ u32 bytes;
+ u32 irq_stat;
+
+ irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS);
+ bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
+ bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */
+ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
+ if (irq_stat & 0x2)
+ goto done;
+
+ if (info->buf_len && (info->buf_len < bytes))
+ bytes = info->buf_len;
+ else if (!info->buf_len)
+ bytes = 0;
+ iowrite32_rep(info->nand.IO_ADDR_W,
+ (u32 *)info->buf, bytes >> 2);
+ info->buf = info->buf + bytes;
+ info->buf_len -= bytes;
+
+ } else {
+ ioread32_rep(info->nand.IO_ADDR_R,
+ (u32 *)info->buf, bytes >> 2);
+ info->buf = info->buf + bytes;
+
+ if (irq_stat & 0x2)
+ goto done;
+ }
+ gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
+
+ return IRQ_HANDLED;
+
+done:
+ complete(&info->comp);
+ /* disable irq */
+ gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0);
+
+ /* clear status */
+ gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * omap_read_buf_irq_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ int ret = 0;
+
+ if (len <= mtd->oobsize) {
+ omap_read_buf_pref(mtd, buf, len);
+ return;
+ }
+
+ info->iomode = OMAP_NAND_IO_READ;
+ info->buf = buf;
+ init_completion(&info->comp);
+
+ /* configure and start prefetch transfer */
+ ret = gpmc_prefetch_enable(info->gpmc_cs,
+ PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0);
+ if (ret)
+ /* PFPW engine is busy, use cpu copy method */
+ goto out_copy;
+
+ info->buf_len = len;
+ /* enable irq */
+ gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
+ (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
+
+ /* waiting for read to complete */
+ wait_for_completion(&info->comp);
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset(info->gpmc_cs);
+ return;
+
+out_copy:
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ omap_read_buf16(mtd, buf, len);
+ else
+ omap_read_buf8(mtd, buf, len);
+}
+
+/*
+ * omap_write_buf_irq_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_irq_pref(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct omap_nand_info *info = container_of(mtd,
+ struct omap_nand_info, mtd);
+ int ret = 0;
+ unsigned long tim, limit;
+
+ if (len <= mtd->oobsize) {
+ omap_write_buf_pref(mtd, buf, len);
+ return;
+ }
+
+ info->iomode = OMAP_NAND_IO_WRITE;
+ info->buf = (u_char *) buf;
+ init_completion(&info->comp);
+
+ /* configure and start prefetch transfer : size=24 */
+ ret = gpmc_prefetch_enable(info->gpmc_cs,
+ (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1);
+ if (ret)
+ /* PFPW engine is busy, use cpu copy method */
+ goto out_copy;
+
+ info->buf_len = len;
+ /* enable irq */
+ gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
+ (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
+
+ /* waiting for write to complete */
+ wait_for_completion(&info->comp);
+ /* wait for data to flushed-out before reset the prefetch */
+ tim = 0;
+ limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
+ while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
+ cpu_relax();
+
+ /* disable and stop the PFPW engine */
+ gpmc_prefetch_reset(info->gpmc_cs);
+ return;
+
+out_copy:
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ omap_write_buf16(mtd, buf, len);
+ else
+ omap_write_buf8(mtd, buf, len);
+}
+
/**
* omap_verify_buf - Verify chip data against buffer
* @mtd: MTD device structure
@@ -487,8 +640,6 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
return 0;
}
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
-
/**
* gen_true_ecc - This function will generate true ECC value
* @ecc_buf: buffer to store ecc code
@@ -708,8 +859,6 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size);
}
-#endif
-
/**
* omap_wait - wait until the command is done
* @mtd: MTD device structure
@@ -779,6 +928,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
struct omap_nand_info *info;
struct omap_nand_platform_data *pdata;
int err;
+ int i, offset;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@@ -804,7 +954,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->mtd.name = dev_name(&pdev->dev);
info->mtd.owner = THIS_MODULE;
- info->nand.options |= pdata->devsize ? NAND_BUSWIDTH_16 : 0;
+ info->nand.options = pdata->devsize;
info->nand.options |= NAND_SKIP_BBTSCAN;
/* NAND write protect off */
@@ -842,28 +992,13 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.chip_delay = 50;
}
- if (use_prefetch) {
-
+ switch (pdata->xfer_type) {
+ case NAND_OMAP_PREFETCH_POLLED:
info->nand.read_buf = omap_read_buf_pref;
info->nand.write_buf = omap_write_buf_pref;
- if (use_dma) {
- err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",
- omap_nand_dma_cb, &info->comp, &info->dma_ch);
- if (err < 0) {
- info->dma_ch = -1;
- printk(KERN_WARNING "DMA request failed."
- " Non-dma data transfer mode\n");
- } else {
- omap_set_dma_dest_burst_mode(info->dma_ch,
- OMAP_DMA_DATA_BURST_16);
- omap_set_dma_src_burst_mode(info->dma_ch,
- OMAP_DMA_DATA_BURST_16);
-
- info->nand.read_buf = omap_read_buf_dma_pref;
- info->nand.write_buf = omap_write_buf_dma_pref;
- }
- }
- } else {
+ break;
+
+ case NAND_OMAP_POLLED:
if (info->nand.options & NAND_BUSWIDTH_16) {
info->nand.read_buf = omap_read_buf16;
info->nand.write_buf = omap_write_buf16;
@@ -871,20 +1006,61 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.read_buf = omap_read_buf8;
info->nand.write_buf = omap_write_buf8;
}
+ break;
+
+ case NAND_OMAP_PREFETCH_DMA:
+ err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",
+ omap_nand_dma_cb, &info->comp, &info->dma_ch);
+ if (err < 0) {
+ info->dma_ch = -1;
+ dev_err(&pdev->dev, "DMA request failed!\n");
+ goto out_release_mem_region;
+ } else {
+ omap_set_dma_dest_burst_mode(info->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+ omap_set_dma_src_burst_mode(info->dma_ch,
+ OMAP_DMA_DATA_BURST_16);
+
+ info->nand.read_buf = omap_read_buf_dma_pref;
+ info->nand.write_buf = omap_write_buf_dma_pref;
+ }
+ break;
+
+ case NAND_OMAP_PREFETCH_IRQ:
+ err = request_irq(pdata->gpmc_irq,
+ omap_nand_irq, IRQF_SHARED, "gpmc-nand", info);
+ if (err) {
+ dev_err(&pdev->dev, "requesting irq(%d) error:%d",
+ pdata->gpmc_irq, err);
+ goto out_release_mem_region;
+ } else {
+ info->gpmc_irq = pdata->gpmc_irq;
+ info->nand.read_buf = omap_read_buf_irq_pref;
+ info->nand.write_buf = omap_write_buf_irq_pref;
+ }
+ break;
+
+ default:
+ dev_err(&pdev->dev,
+ "xfer_type(%d) not supported!\n", pdata->xfer_type);
+ err = -EINVAL;
+ goto out_release_mem_region;
}
- info->nand.verify_buf = omap_verify_buf;
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
- info->nand.ecc.bytes = 3;
- info->nand.ecc.size = 512;
- info->nand.ecc.calculate = omap_calculate_ecc;
- info->nand.ecc.hwctl = omap_enable_hwecc;
- info->nand.ecc.correct = omap_correct_data;
- info->nand.ecc.mode = NAND_ECC_HW;
+ info->nand.verify_buf = omap_verify_buf;
-#else
- info->nand.ecc.mode = NAND_ECC_SOFT;
-#endif
+ /* selsect the ecc type */
+ if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
+ info->nand.ecc.mode = NAND_ECC_SOFT;
+ else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
+ (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
+ info->nand.ecc.bytes = 3;
+ info->nand.ecc.size = 512;
+ info->nand.ecc.calculate = omap_calculate_ecc;
+ info->nand.ecc.hwctl = omap_enable_hwecc;
+ info->nand.ecc.correct = omap_correct_data;
+ info->nand.ecc.mode = NAND_ECC_HW;
+ }
/* DIP switches on some boards change between 8 and 16 bit
* bus widths for flash. Try the other width if the first try fails.
@@ -897,6 +1073,26 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
}
}
+ /* rom code layout */
+ if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
+
+ if (info->nand.options & NAND_BUSWIDTH_16)
+ offset = 2;
+ else {
+ offset = 1;
+ info->nand.badblock_pattern = &bb_descrip_flashbased;
+ }
+ omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16);
+ for (i = 0; i < omap_oobinfo.eccbytes; i++)
+ omap_oobinfo.eccpos[i] = i+offset;
+
+ omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
+ omap_oobinfo.oobfree->length = info->mtd.oobsize -
+ (offset + omap_oobinfo.eccbytes);
+
+ info->nand.ecc.layout = &omap_oobinfo;
+ }
+
#ifdef CONFIG_MTD_PARTITIONS
err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
if (err > 0)
@@ -926,9 +1122,12 @@ static int omap_nand_remove(struct platform_device *pdev)
mtd);
platform_set_drvdata(pdev, NULL);
- if (use_dma)
+ if (info->dma_ch != -1)
omap_free_dma(info->dma_ch);
+ if (info->gpmc_irq)
+ free_irq(info->gpmc_irq, info);
+
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);
iounmap(info->nand.IO_ADDR_R);
@@ -947,16 +1146,8 @@ static struct platform_driver omap_nand_driver = {
static int __init omap_nand_init(void)
{
- printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
+ pr_info("%s driver initializing\n", DRIVER_NAME);
- /* This check is required if driver is being
- * loaded run time as a module
- */
- if ((1 == use_dma) && (0 == use_prefetch)) {
- printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 "
- "without use_prefetch'. Prefetch will not be"
- " used in either mode (mpu or dma)\n");
- }
return platform_driver_register(&omap_nand_driver);
}
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 4dbd0f58eebf..4f426195f8db 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -32,7 +32,7 @@ config MTD_ONENAND_OMAP2
config MTD_ONENAND_SAMSUNG
tristate "OneNAND on Samsung SOC controller support"
- depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310
+ depends on ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS4
help
Support for a OneNAND flash device connected to an Samsung SOC.
S3C64XX/S5PC100 use command mapping method.
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index c849cacf4b2f..14a49abe057e 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -63,7 +63,7 @@ struct omap2_onenand {
struct completion dma_done;
int dma_channel;
int freq;
- int (*setup)(void __iomem *base, int freq);
+ int (*setup)(void __iomem *base, int *freq_ptr);
struct regulator *regulator;
};
@@ -148,11 +148,9 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
wait_err("controller error", state, ctrl, intr);
return -EIO;
}
- if ((intr & intr_flags) != intr_flags) {
- wait_err("timeout", state, ctrl, intr);
- return -EIO;
- }
- return 0;
+ if ((intr & intr_flags) == intr_flags)
+ return 0;
+ /* Continue in wait for interrupt branch */
}
if (state != FL_READING) {
@@ -581,7 +579,7 @@ static int __adjust_timing(struct device *dev, void *data)
/* DMA is not in use so this is all that is needed */
/* Revisit for OMAP3! */
- ret = c->setup(c->onenand.base, c->freq);
+ ret = c->setup(c->onenand.base, &c->freq);
return ret;
}
@@ -673,7 +671,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
}
if (pdata->onenand_setup != NULL) {
- r = pdata->onenand_setup(c->onenand.base, c->freq);
+ r = pdata->onenand_setup(c->onenand.base, &c->freq);
if (r < 0) {
dev_err(&pdev->dev, "Onenand platform setup failed: "
"%d\n", r);
@@ -718,8 +716,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual "
- "base %p\n", c->gpmc_cs, c->phys_base,
- c->onenand.base);
+ "base %p, freq %d MHz\n", c->gpmc_cs, c->phys_base,
+ c->onenand.base, c->freq);
c->pdev = pdev;
c->mtd.name = dev_name(&pdev->dev);
@@ -754,24 +752,6 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
if ((r = onenand_scan(&c->mtd, 1)) < 0)
goto err_release_regulator;
- switch ((c->onenand.version_id >> 4) & 0xf) {
- case 0:
- c->freq = 40;
- break;
- case 1:
- c->freq = 54;
- break;
- case 2:
- c->freq = 66;
- break;
- case 3:
- c->freq = 83;
- break;
- case 4:
- c->freq = 104;
- break;
- }
-
#ifdef CONFIG_MTD_PARTITIONS
r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0);
if (r > 0)
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 3cf193fb5e00..6abeb4f13403 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -52,6 +52,12 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy
software.
-source "drivers/mtd/ubi/Kconfig.debug"
+config MTD_UBI_DEBUG
+ bool "UBI debugging"
+ depends on SYSFS
+ select DEBUG_FS
+ select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL
+ help
+ This option enables UBI debugging.
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Kconfig.debug b/drivers/mtd/ubi/Kconfig.debug
deleted file mode 100644
index fad4adc0fe2c..000000000000
--- a/drivers/mtd/ubi/Kconfig.debug
+++ /dev/null
@@ -1,73 +0,0 @@
-comment "UBI debugging options"
-
-config MTD_UBI_DEBUG
- bool "UBI debugging"
- depends on SYSFS
- select DEBUG_FS
- select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL
- help
- This option enables UBI debugging.
-
-if MTD_UBI_DEBUG
-
-config MTD_UBI_DEBUG_MSG
- bool "UBI debugging messages"
- help
- This option enables UBI debugging messages.
-
-config MTD_UBI_DEBUG_PARANOID
- bool "Extra self-checks"
- help
- This option enables extra checks in UBI code. Note this slows UBI down
- significantly.
-
-config MTD_UBI_DEBUG_DISABLE_BGT
- bool "Do not enable the UBI background thread"
- help
- This option switches the background thread off by default. The thread
- may be also be enabled/disabled via UBI sysfs.
-
-config MTD_UBI_DEBUG_EMULATE_BITFLIPS
- bool "Emulate flash bit-flips"
- help
- This option emulates bit-flips with probability 1/50, which in turn
- causes scrubbing. Useful for debugging and stressing UBI.
-
-config MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
- bool "Emulate flash write failures"
- help
- This option emulates write failures with probability 1/100. Useful for
- debugging and testing how UBI handlines errors.
-
-config MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
- bool "Emulate flash erase failures"
- help
- This option emulates erase failures with probability 1/100. Useful for
- debugging and testing how UBI handlines errors.
-
-comment "Additional UBI debugging messages"
-
-config MTD_UBI_DEBUG_MSG_BLD
- bool "Additional UBI initialization and build messages"
- help
- This option enables detailed UBI initialization and device build
- debugging messages.
-
-config MTD_UBI_DEBUG_MSG_EBA
- bool "Eraseblock association unit messages"
- help
- This option enables debugging messages from the UBI eraseblock
- association unit.
-
-config MTD_UBI_DEBUG_MSG_WL
- bool "Wear-leveling unit messages"
- help
- This option enables debugging messages from the UBI wear-leveling
- unit.
-
-config MTD_UBI_DEBUG_MSG_IO
- bool "Input/output unit messages"
- help
- This option enables debugging messages from the UBI input/output unit.
-
-endif # MTD_UBI_DEBUG
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 5ebe280225d6..65626c1c446d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -690,11 +690,25 @@ static int io_init(struct ubi_device *ubi)
ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
+ ubi->max_write_size = ubi->mtd->writebufsize;
+ /*
+ * Maximum write size has to be greater or equivalent to min. I/O
+ * size, and be multiple of min. I/O size.
+ */
+ if (ubi->max_write_size < ubi->min_io_size ||
+ ubi->max_write_size % ubi->min_io_size ||
+ !is_power_of_2(ubi->max_write_size)) {
+ ubi_err("bad write buffer size %d for %d min. I/O unit",
+ ubi->max_write_size, ubi->min_io_size);
+ return -EINVAL;
+ }
+
/* Calculate default aligned sizes of EC and VID headers */
ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
dbg_msg("min_io_size %d", ubi->min_io_size);
+ dbg_msg("max_write_size %d", ubi->max_write_size);
dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize);
dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize);
@@ -711,7 +725,7 @@ static int io_init(struct ubi_device *ubi)
}
/* Similar for the data offset */
- ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
+ ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;
ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset);
@@ -923,6 +937,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
spin_lock_init(&ubi->volumes_lock);
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
+ dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
+ dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
err = io_init(ubi);
if (err)
@@ -937,13 +953,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (!ubi->peb_buf2)
goto out_free;
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
- mutex_init(&ubi->dbg_buf_mutex);
- ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
- if (!ubi->dbg_peb_buf)
- goto out_free;
-#endif
-
err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
@@ -991,8 +1000,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
* checks @ubi->thread_enabled. Otherwise we may fail to wake it up.
*/
spin_lock(&ubi->wl_lock);
- if (!DBG_DISABLE_BGT)
- ubi->thread_enabled = 1;
+ ubi->thread_enabled = 1;
wake_up_process(ubi->bgt_thread);
spin_unlock(&ubi->wl_lock);
@@ -1009,9 +1017,6 @@ out_detach:
out_free:
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
- vfree(ubi->dbg_peb_buf);
-#endif
if (ref)
put_device(&ubi->dev);
else
@@ -1082,9 +1087,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
put_mtd_device(ubi->mtd);
vfree(ubi->peb_buf1);
vfree(ubi->peb_buf2);
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
- vfree(ubi->dbg_peb_buf);
-#endif
ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
put_device(&ubi->dev);
return 0;
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 4876977e52cb..d4d07e5f138f 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -27,6 +27,20 @@
#ifdef CONFIG_MTD_UBI_DEBUG
#include "ubi.h"
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+unsigned int ubi_msg_flags;
+unsigned int ubi_chk_flags;
+unsigned int ubi_tst_flags;
+
+module_param_named(debug_msgs, ubi_msg_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+MODULE_PARM_DESC(debug_chks, "Debug check flags");
+MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
/**
* ubi_dbg_dump_ec_hdr - dump an erase counter header.
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 9eca95074bc2..0b0c2888c656 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -38,6 +38,11 @@
printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
current->pid, __func__, ##__VA_ARGS__)
+#define dbg_do_msg(typ, fmt, ...) do { \
+ if (ubi_msg_flags & typ) \
+ dbg_msg(fmt, ##__VA_ARGS__); \
+} while (0)
+
#define ubi_dbg_dump_stack() dump_stack()
struct ubi_ec_hdr;
@@ -57,62 +62,88 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
+extern unsigned int ubi_msg_flags;
+
+/*
+ * Debugging message type flags (must match msg_type_names in debug.c).
+ *
+ * UBI_MSG_GEN: general messages
+ * UBI_MSG_EBA: journal messages
+ * UBI_MSG_WL: mount messages
+ * UBI_MSG_IO: commit messages
+ * UBI_MSG_BLD: LEB find messages
+ */
+enum {
+ UBI_MSG_GEN = 0x1,
+ UBI_MSG_EBA = 0x2,
+ UBI_MSG_WL = 0x4,
+ UBI_MSG_IO = 0x8,
+ UBI_MSG_BLD = 0x10,
+};
+
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
print_hex_dump(l, ps, pt, r, g, b, len, a)
-#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* General debugging messages */
-#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
-#else
-#define dbg_gen(fmt, ...) ({})
-#endif
+#define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
/* Messages from the eraseblock association sub-system */
-#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
-#else
-#define dbg_eba(fmt, ...) ({})
-#endif
+#define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
/* Messages from the wear-leveling sub-system */
-#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
-#else
-#define dbg_wl(fmt, ...) ({})
-#endif
+#define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
/* Messages from the input/output sub-system */
-#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
-#else
-#define dbg_io(fmt, ...) ({})
-#endif
+#define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
/* Initialization and build messages */
-#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
-#define UBI_IO_DEBUG 1
-#else
-#define dbg_bld(fmt, ...) ({})
-#define UBI_IO_DEBUG 0
-#endif
+#define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
+
+extern unsigned int ubi_chk_flags;
+
+/*
+ * Debugging check flags.
+ *
+ * UBI_CHK_GEN: general checks
+ * UBI_CHK_IO: check writes and erases
+ */
+enum {
+ UBI_CHK_GEN = 0x1,
+ UBI_CHK_IO = 0x2,
+};
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int offset, int len);
-#else
-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
-#endif
-#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
-#define DBG_DISABLE_BGT 1
-#else
-#define DBG_DISABLE_BGT 0
-#endif
+extern unsigned int ubi_tst_flags;
+
+/*
+ * Special testing flags.
+ *
+ * UBIFS_TST_DISABLE_BGT: disable the background thread
+ * UBI_TST_EMULATE_BITFLIPS: emulate bit-flips
+ * UBI_TST_EMULATE_WRITE_FAILURES: emulate write failures
+ * UBI_TST_EMULATE_ERASE_FAILURES: emulate erase failures
+ */
+enum {
+ UBI_TST_DISABLE_BGT = 0x1,
+ UBI_TST_EMULATE_BITFLIPS = 0x2,
+ UBI_TST_EMULATE_WRITE_FAILURES = 0x4,
+ UBI_TST_EMULATE_ERASE_FAILURES = 0x8,
+};
+
+/**
+ * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
+ *
+ * Returns non-zero if the UBI background thread is disabled for testing
+ * purposes.
+ */
+static inline int ubi_dbg_is_bgt_disabled(void)
+{
+ return ubi_tst_flags & UBI_TST_DISABLE_BGT;
+}
-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
/**
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
*
@@ -120,13 +151,11 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
*/
static inline int ubi_dbg_is_bitflip(void)
{
- return !(random32() % 200);
+ if (ubi_tst_flags & UBI_TST_EMULATE_BITFLIPS)
+ return !(random32() % 200);
+ return 0;
}
-#else
-#define ubi_dbg_is_bitflip() 0
-#endif
-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
/**
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
*
@@ -135,13 +164,11 @@ static inline int ubi_dbg_is_bitflip(void)
*/
static inline int ubi_dbg_is_write_failure(void)
{
- return !(random32() % 500);
+ if (ubi_tst_flags & UBI_TST_EMULATE_WRITE_FAILURES)
+ return !(random32() % 500);
+ return 0;
}
-#else
-#define ubi_dbg_is_write_failure() 0
-#endif
-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
/**
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
*
@@ -150,11 +177,10 @@ static inline int ubi_dbg_is_write_failure(void)
*/
static inline int ubi_dbg_is_erase_failure(void)
{
+ if (ubi_tst_flags & UBI_TST_EMULATE_ERASE_FAILURES)
return !(random32() % 400);
+ return 0;
}
-#else
-#define ubi_dbg_is_erase_failure() 0
-#endif
#else
@@ -177,8 +203,7 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({})
-#define UBI_IO_DEBUG 0
-#define DBG_DISABLE_BGT 0
+#define ubi_dbg_is_bgt_disabled() 0
#define ubi_dbg_is_bitflip() 0
#define ubi_dbg_is_write_failure() 0
#define ubi_dbg_is_erase_failure() 0
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 811775aa8ee8..aaa6e1e83b29 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -91,7 +91,7 @@
#include <linux/slab.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
@@ -146,6 +146,28 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
if (err)
return err;
+ /*
+ * Deliberately corrupt the buffer to improve robustness. Indeed, if we
+ * do not do this, the following may happen:
+ * 1. The buffer contains data from previous operation, e.g., read from
+ * another PEB previously. The data looks like expected, e.g., if we
+ * just do not read anything and return - the caller would not
+ * notice this. E.g., if we are reading a VID header, the buffer may
+ * contain a valid VID header from another PEB.
+ * 2. The driver is buggy and returns us success or -EBADMSG or
+ * -EUCLEAN, but it does not actually put any data to the buffer.
+ *
+ * This may confuse UBI or upper layers - they may think the buffer
+ * contains valid data while in fact it is just old data. This is
+ * especially possible because UBI (and UBIFS) relies on CRC, and
+ * treats data as correct even in case of ECC errors if the CRC is
+ * correct.
+ *
+ * Try to prevent this situation by changing the first byte of the
+ * buffer.
+ */
+ *((uint8_t *)buf) ^= 0xFF;
+
addr = (loff_t)pnum * ubi->peb_size + offset;
retry:
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
@@ -166,7 +188,7 @@ retry:
return UBI_IO_BITFLIPS;
}
- if (read != len && retries++ < UBI_IO_RETRIES) {
+ if (retries++ < UBI_IO_RETRIES) {
dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
" read only %zd bytes, retry",
err, errstr, len, pnum, offset, read);
@@ -480,6 +502,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
size_t written;
loff_t addr;
uint32_t data = 0;
+ /*
+ * Note, we cannot generally define VID header buffers on stack,
+ * because of the way we deal with these buffers (see the header
+ * comment in this file). But we know this is a NOR-specific piece of
+ * code, so we can do this. But yes, this is error-prone and we should
+ * (pre-)allocate VID header buffer instead.
+ */
struct ubi_vid_hdr vid_hdr;
/*
@@ -507,11 +536,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* PEB.
*/
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
- if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
+ err1 == UBI_IO_FF) {
struct ubi_ec_hdr ec_hdr;
err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
- if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
+ if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
+ err1 == UBI_IO_FF)
/*
* Both VID and EC headers are corrupted, so we can
* safely erase this PEB and not afraid that it will be
@@ -752,9 +783,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose)
ubi_warn("no EC header found at PEB %d, "
"only 0xFF bytes", pnum);
- else if (UBI_IO_DEBUG)
- dbg_msg("no EC header found at PEB %d, "
- "only 0xFF bytes", pnum);
+ dbg_bld("no EC header found at PEB %d, "
+ "only 0xFF bytes", pnum);
if (!read_err)
return UBI_IO_FF;
else
@@ -769,9 +799,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
ubi_dbg_dump_ec_hdr(ec_hdr);
- } else if (UBI_IO_DEBUG)
- dbg_msg("bad magic number at PEB %d: %08x instead of "
- "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+ }
+ dbg_bld("bad magic number at PEB %d: %08x instead of "
+ "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
return UBI_IO_BAD_HDR;
}
@@ -783,9 +813,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
ubi_warn("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
ubi_dbg_dump_ec_hdr(ec_hdr);
- } else if (UBI_IO_DEBUG)
- dbg_msg("bad EC header CRC at PEB %d, calculated "
- "%#08x, read %#08x", pnum, crc, hdr_crc);
+ }
+ dbg_bld("bad EC header CRC at PEB %d, calculated "
+ "%#08x, read %#08x", pnum, crc, hdr_crc);
if (!read_err)
return UBI_IO_BAD_HDR;
@@ -1008,9 +1038,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose)
ubi_warn("no VID header found at PEB %d, "
"only 0xFF bytes", pnum);
- else if (UBI_IO_DEBUG)
- dbg_msg("no VID header found at PEB %d, "
- "only 0xFF bytes", pnum);
+ dbg_bld("no VID header found at PEB %d, "
+ "only 0xFF bytes", pnum);
if (!read_err)
return UBI_IO_FF;
else
@@ -1021,9 +1050,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
ubi_dbg_dump_vid_hdr(vid_hdr);
- } else if (UBI_IO_DEBUG)
- dbg_msg("bad magic number at PEB %d: %08x instead of "
- "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+ }
+ dbg_bld("bad magic number at PEB %d: %08x instead of "
+ "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
return UBI_IO_BAD_HDR;
}
@@ -1035,9 +1064,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
ubi_warn("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
ubi_dbg_dump_vid_hdr(vid_hdr);
- } else if (UBI_IO_DEBUG)
- dbg_msg("bad CRC at PEB %d, calculated %#08x, "
- "read %#08x", pnum, crc, hdr_crc);
+ }
+ dbg_bld("bad CRC at PEB %d, calculated %#08x, "
+ "read %#08x", pnum, crc, hdr_crc);
if (!read_err)
return UBI_IO_BAD_HDR;
else
@@ -1097,7 +1126,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
@@ -1111,6 +1140,9 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
{
int err;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
err = ubi_io_is_bad(ubi, pnum);
if (!err)
return err;
@@ -1135,6 +1167,9 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x",
@@ -1170,6 +1205,9 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
uint32_t crc, hdr_crc;
struct ubi_ec_hdr *ec_hdr;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -1211,6 +1249,9 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
@@ -1249,6 +1290,9 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
struct ubi_vid_hdr *vid_hdr;
void *p;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -1294,15 +1338,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int offset, int len)
{
int err, i;
+ size_t read;
+ void *buf1;
+ loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- mutex_lock(&ubi->dbg_buf_mutex);
- err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
- if (err)
- goto out_unlock;
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
+ buf1 = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf1) {
+ ubi_err("cannot allocate memory to check writes");
+ return 0;
+ }
+
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
+ if (err && err != -EUCLEAN)
+ goto out_free;
for (i = 0; i < len; i++) {
uint8_t c = ((uint8_t *)buf)[i];
- uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
+ uint8_t c1 = ((uint8_t *)buf1)[i];
int dump_len;
if (c == c1)
@@ -1319,17 +1374,17 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
ubi_msg("hex dump of the read buffer from %d to %d",
i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
- ubi->dbg_peb_buf + i, dump_len, 1);
+ buf1 + i, dump_len, 1);
ubi_dbg_dump_stack();
err = -EINVAL;
- goto out_unlock;
+ goto out_free;
}
- mutex_unlock(&ubi->dbg_buf_mutex);
+ vfree(buf1);
return 0;
-out_unlock:
- mutex_unlock(&ubi->dbg_buf_mutex);
+out_free:
+ vfree(buf1);
return err;
}
@@ -1348,36 +1403,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
size_t read;
int err;
+ void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- mutex_lock(&ubi->dbg_buf_mutex);
- err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
+ if (!(ubi_chk_flags & UBI_CHK_IO))
+ return 0;
+
+ buf = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubi_err("cannot allocate memory to check for 0xFFs");
+ return 0;
+ }
+
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) {
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read);
goto error;
}
- err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len);
+ err = ubi_check_pattern(buf, 0xFF, len);
if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not "
"contain all 0xFF bytes", pnum, offset, len);
goto fail;
}
- mutex_unlock(&ubi->dbg_buf_mutex);
+ vfree(buf);
return 0;
fail:
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_msg("hex dump of the %d-%d region", offset, offset + len);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
- ubi->dbg_peb_buf, len, 1);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL;
error:
ubi_dbg_dump_stack();
- mutex_unlock(&ubi->dbg_buf_mutex);
+ vfree(buf);
return err;
}
-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
+#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 69fa4ef03c53..d39716e5b204 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -40,7 +40,9 @@ void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di)
{
di->ubi_num = ubi->ubi_num;
di->leb_size = ubi->leb_size;
+ di->leb_start = ubi->leb_start;
di->min_io_size = ubi->min_io_size;
+ di->max_write_size = ubi->max_write_size;
di->ro_mode = ubi->ro_mode;
di->cdev = ubi->cdev.dev;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 79ca304fc4db..11eb8ef12485 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -39,32 +39,46 @@
* eraseblocks are put to the @free list and the physical eraseblock to be
* erased are put to the @erase list.
*
+ * About corruptions
+ * ~~~~~~~~~~~~~~~~~
+ *
+ * UBI protects EC and VID headers with CRC-32 checksums, so it can detect
+ * whether the headers are corrupted or not. Sometimes UBI also protects the
+ * data with CRC-32, e.g., when it executes the atomic LEB change operation, or
+ * when it moves the contents of a PEB for wear-leveling purposes.
+ *
* UBI tries to distinguish between 2 types of corruptions.
- * 1. Corruptions caused by power cuts. These are harmless and expected
- * corruptions and UBI tries to handle them gracefully, without printing too
- * many warnings and error messages. The idea is that we do not lose
- * important data in these case - we may lose only the data which was being
- * written to the media just before the power cut happened, and the upper
- * layers (e.g., UBIFS) are supposed to handle these situations. UBI puts
- * these PEBs to the head of the @erase list and they are scheduled for
- * erasure.
+ *
+ * 1. Corruptions caused by power cuts. These are expected corruptions and UBI
+ * tries to handle them gracefully, without printing too many warnings and
+ * error messages. The idea is that we do not lose important data in these case
+ * - we may lose only the data which was being written to the media just before
+ * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
+ * handle such data losses (e.g., by using the FS journal).
+ *
+ * When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
+ * the reason is a power cut, UBI puts this PEB to the @erase list, and all
+ * PEBs in the @erase list are scheduled for erasure later.
*
* 2. Unexpected corruptions which are not caused by power cuts. During
- * scanning, such PEBs are put to the @corr list and UBI preserves them.
- * Obviously, this lessens the amount of available PEBs, and if at some
- * point UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly
- * informs about such PEBs every time the MTD device is attached.
+ * scanning, such PEBs are put to the @corr list and UBI preserves them.
+ * Obviously, this lessens the amount of available PEBs, and if at some point
+ * UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
+ * about such PEBs every time the MTD device is attached.
*
* However, it is difficult to reliably distinguish between these types of
- * corruptions and UBI's strategy is as follows. UBI assumes (2.) if the VID
- * header is corrupted and the data area does not contain all 0xFFs, and there
- * were not bit-flips or integrity errors while reading the data area. Otherwise
- * UBI assumes (1.). The assumptions are:
- * o if the data area contains only 0xFFs, there is no data, and it is safe
- * to just erase this PEB.
- * o if the data area has bit-flips and data integrity errors (ECC errors on
+ * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
+ * if the VID header is corrupted and the data area does not contain all 0xFFs,
+ * and there were no bit-flips or integrity errors while reading the data area.
+ * Otherwise UBI assumes corruption type 1. So the decision criteria are as
+ * follows.
+ * o If the data area contains only 0xFFs, there is no data, and it is safe
+ * to just erase this PEB - this is corruption type 1.
+ * o If the data area has bit-flips or data integrity errors (ECC errors on
* NAND), it is probably a PEB which was being erased when power cut
- * happened.
+ * happened, so this is corruption type 1. However, this is just a guess,
+ * which might be wrong.
+ * o Otherwise this it corruption type 2.
*/
#include <linux/err.h>
@@ -74,7 +88,7 @@
#include <linux/random.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
#else
#define paranoid_check_si(ubi, si) 0
@@ -115,7 +129,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
} else
BUG();
- seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+ seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
if (!seb)
return -ENOMEM;
@@ -144,7 +158,7 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+ seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
if (!seb)
return -ENOMEM;
@@ -553,7 +567,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
if (err)
return err;
- seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
+ seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
if (!seb)
return -ENOMEM;
@@ -1152,9 +1166,15 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
si->volumes = RB_ROOT;
err = -ENOMEM;
+ si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
+ sizeof(struct ubi_scan_leb),
+ 0, 0, NULL);
+ if (!si->scan_leb_slab)
+ goto out_si;
+
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech)
- goto out_si;
+ goto out_slab;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
@@ -1215,6 +1235,8 @@ out_vidh:
ubi_free_vid_hdr(ubi, vidh);
out_ech:
kfree(ech);
+out_slab:
+ kmem_cache_destroy(si->scan_leb_slab);
out_si:
ubi_scan_destroy_si(si);
return ERR_PTR(err);
@@ -1223,11 +1245,12 @@ out_si:
/**
* destroy_sv - free the scanning volume information
* @sv: scanning volume information
+ * @si: scanning information
*
* This function destroys the volume RB-tree (@sv->root) and the scanning
* volume information.
*/
-static void destroy_sv(struct ubi_scan_volume *sv)
+static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
{
struct ubi_scan_leb *seb;
struct rb_node *this = sv->root.rb_node;
@@ -1247,7 +1270,7 @@ static void destroy_sv(struct ubi_scan_volume *sv)
this->rb_right = NULL;
}
- kfree(seb);
+ kmem_cache_free(si->scan_leb_slab, seb);
}
}
kfree(sv);
@@ -1265,19 +1288,19 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
list_del(&seb->u.list);
- kfree(seb);
+ kmem_cache_free(si->scan_leb_slab, seb);
}
list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
list_del(&seb->u.list);
- kfree(seb);
+ kmem_cache_free(si->scan_leb_slab, seb);
}
list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
list_del(&seb->u.list);
- kfree(seb);
+ kmem_cache_free(si->scan_leb_slab, seb);
}
list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
list_del(&seb->u.list);
- kfree(seb);
+ kmem_cache_free(si->scan_leb_slab, seb);
}
/* Destroy the volume RB-tree */
@@ -1298,14 +1321,15 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
rb->rb_right = NULL;
}
- destroy_sv(sv);
+ destroy_sv(si, sv);
}
}
+ kmem_cache_destroy(si->scan_leb_slab);
kfree(si);
}
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_check_si - check the scanning information.
@@ -1323,6 +1347,9 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
struct ubi_scan_leb *seb, *last_seb;
uint8_t *buf;
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return 0;
+
/*
* At first, check that scanning information is OK.
*/
@@ -1575,4 +1602,4 @@ out:
return -EINVAL;
}
-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
+#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index a3264f0bef2b..d48aef15ab5d 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -109,6 +109,7 @@ struct ubi_scan_volume {
* @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
+ * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
*
* This data structure contains the result of scanning and may be used by other
* UBI sub-systems to build final UBI data structures, further error-recovery
@@ -134,6 +135,7 @@ struct ubi_scan_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ struct kmem_cache *scan_leb_slab;
};
struct ubi_device;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 0b0149c41fe3..f1be8b79663c 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -40,6 +40,7 @@
#include <linux/notifier.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/ubi.h>
+#include <asm/pgtable.h>
#include "ubi-media.h"
#include "scan.h"
@@ -381,14 +382,14 @@ struct ubi_wl_entry;
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
* not
* @nor_flash: non-zero if working on top of NOR flash
+ * @max_write_size: maximum amount of bytes the underlying flash can write at a
+ * time (MTD write buffer size)
* @mtd: MTD device descriptor
*
* @peb_buf1: a buffer of PEB size used for different purposes
* @peb_buf2: another buffer of PEB size used for different purposes
* @buf_mutex: protects @peb_buf1 and @peb_buf2
* @ckvol_mutex: serializes static volume checking when opening
- * @dbg_peb_buf: buffer of PEB size used for debugging
- * @dbg_buf_mutex: protects @dbg_peb_buf
*/
struct ubi_device {
struct cdev cdev;
@@ -464,16 +465,13 @@ struct ubi_device {
int vid_hdr_shift;
unsigned int bad_allowed:1;
unsigned int nor_flash:1;
+ int max_write_size;
struct mtd_info *mtd;
void *peb_buf1;
void *peb_buf2;
struct mutex buf_mutex;
struct mutex ckvol_mutex;
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
- void *dbg_peb_buf;
- struct mutex dbg_buf_mutex;
-#endif
};
extern struct kmem_cache *ubi_wl_entry_slab;
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index c47620dfc722..b79e0dea3632 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
static int paranoid_check_volumes(struct ubi_device *ubi);
#else
#define paranoid_check_volumes(ubi) 0
@@ -711,7 +711,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
volume_sysfs_close(vol);
}
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_check_volume - check volume information.
@@ -876,6 +876,9 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
{
int i, err = 0;
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return 0;
+
for (i = 0; i < ubi->vtbl_slots; i++) {
err = paranoid_check_volume(ubi, i);
if (err)
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 0b8141fc5c26..fd3bf770f518 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -62,7 +62,7 @@
#include <asm/div64.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
static void paranoid_vtbl_check(const struct ubi_device *ubi);
#else
#define paranoid_vtbl_check(ubi)
@@ -868,7 +868,7 @@ out_free:
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_vtbl_check - check volume table.
@@ -876,10 +876,13 @@ out_free:
*/
static void paranoid_vtbl_check(const struct ubi_device *ubi)
{
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return;
+
if (vtbl_check(ubi, ubi->vtbl)) {
ubi_err("paranoid check failed");
BUG();
}
}
-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
+#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 655bbbe415d9..b4cf57db2556 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -161,7 +161,7 @@ struct ubi_work {
int torture;
};
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root);
@@ -613,7 +613,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
list_add_tail(&wrk->list, &ubi->works);
ubi_assert(ubi->works_count >= 0);
ubi->works_count += 1;
- if (ubi->thread_enabled)
+ if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled())
wake_up_process(ubi->bgt_thread);
spin_unlock(&ubi->wl_lock);
}
@@ -1364,7 +1364,7 @@ int ubi_thread(void *u)
spin_lock(&ubi->wl_lock);
if (list_empty(&ubi->works) || ubi->ro_mode ||
- !ubi->thread_enabled) {
+ !ubi->thread_enabled || ubi_dbg_is_bgt_disabled()) {
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock(&ubi->wl_lock);
schedule();
@@ -1561,7 +1561,7 @@ void ubi_wl_close(struct ubi_device *ubi)
kfree(ubi->lookuptbl);
}
-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+#ifdef CONFIG_MTD_UBI_DEBUG
/**
* paranoid_check_ec - make sure that the erase counter of a PEB is correct.
@@ -1578,6 +1578,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
long long read_ec;
struct ubi_ec_hdr *ec_hdr;
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return 0;
+
ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -1614,6 +1617,9 @@ out_free:
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root)
{
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return 0;
+
if (in_wl_tree(e, root))
return 0;
@@ -1636,6 +1642,9 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
struct ubi_wl_entry *p;
int i;
+ if (!(ubi_chk_flags & UBI_CHK_GEN))
+ return 0;
+
for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
list_for_each_entry(p, &ubi->pq[i], u.list)
if (p == e)
@@ -1646,4 +1655,5 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
ubi_dbg_dump_stack();
return -EINVAL;
}
-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
+
+#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index 9ab58097fa2e..7cb375e0e29c 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -265,7 +265,7 @@ struct atl1c_recv_ret_status {
__le32 word3;
};
-/* RFD desciptor */
+/* RFD descriptor */
struct atl1c_rx_free_desc {
__le64 buffer_addr;
};
@@ -531,7 +531,7 @@ struct atl1c_rfd_ring {
struct atl1c_buffer *buffer_info;
};
-/* receive return desciptor (rrd) ring */
+/* receive return descriptor (rrd) ring */
struct atl1c_rrd_ring {
void *desc; /* descriptor ring virtual address */
dma_addr_t dma; /* descriptor ring physical address */
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index 9d48659e3b28..32e64cc85d2c 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -145,13 +145,6 @@ static struct {
{ "Broadcom NetXtreme II BCM57712E XGb" }
};
-#ifndef PCI_DEVICE_ID_NX2_57712
-#define PCI_DEVICE_ID_NX2_57712 0x1662
-#endif
-#ifndef PCI_DEVICE_ID_NX2_57712E
-#define PCI_DEVICE_ID_NX2_57712E 0x1663
-#endif
-
static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
{ PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 2d21c60085bc..348b4f1367c9 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -2460,7 +2460,7 @@ map_error:
* The 3032 supports sglists by using the 3 addr/len pairs (ALP)
* in the IOCB plus a chain of outbound address lists (OAL) that
* each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
- * will used to point to an OAL when more ALP entries are required.
+ * will be used to point to an OAL when more ALP entries are required.
* The IOCB is always the top of the chain followed by one or more
* OALs (when necessary).
*/
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index ede017872367..d225077964e2 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -843,7 +843,7 @@ struct gem_txd {
/* GEM requires that RX descriptors are provided four at a time,
* aligned. Also, the RX ring may not wrap around. This means that
- * there will be at least 4 unused desciptor entries in the middle
+ * there will be at least 4 unused descriptor entries in the middle
* of the RX ring at all times.
*
* Similar to HME, GEM assumes that it can write garbage bytes before
diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c
index 7cb301da7474..0825db6d883f 100644
--- a/drivers/net/tile/tilepro.c
+++ b/drivers/net/tile/tilepro.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -44,10 +44,6 @@
#include <linux/tcp.h>
-/* There is no singlethread_cpu, so schedule work on the current cpu. */
-#define singlethread_cpu -1
-
-
/*
* First, "tile_net_init_module()" initializes all four "devices" which
* can be used by linux.
@@ -73,15 +69,16 @@
* return, knowing we will be called again later. Otherwise, we
* reenable the ingress interrupt, and call "napi_complete()".
*
+ * HACK: Since disabling the ingress interrupt is not reliable, we
+ * ignore the interrupt if the global "active" flag is false.
+ *
*
* NOTE: The use of "native_driver" ensures that EPP exists, and that
- * "epp_sendv" is legal, and that "LIPP" is being used.
+ * we are using "LIPP" and "LEPP".
*
* NOTE: Failing to free completions for an arbitrarily long time
* (which is defined to be illegal) does in fact cause bizarre
* problems. The "egress_timer" helps prevent this from happening.
- *
- * NOTE: The egress code can be interrupted by the interrupt handler.
*/
@@ -142,6 +139,7 @@
MODULE_AUTHOR("Tilera");
MODULE_LICENSE("GPL");
+
/*
* Queue of incoming packets for a specific cpu and device.
*
@@ -177,7 +175,7 @@ struct tile_net_cpu {
struct tile_netio_queue queue;
/* Statistics. */
struct tile_net_stats_t stats;
- /* ISSUE: Is this needed? */
+ /* True iff NAPI is enabled. */
bool napi_enabled;
/* True if this tile has succcessfully registered with the IPP. */
bool registered;
@@ -200,20 +198,20 @@ struct tile_net_cpu {
struct tile_net_priv {
/* Our network device. */
struct net_device *dev;
- /* The actual egress queue. */
- lepp_queue_t *epp_queue;
- /* Protects "epp_queue->cmd_tail" and "epp_queue->comp_tail" */
- spinlock_t cmd_lock;
- /* Protects "epp_queue->comp_head". */
- spinlock_t comp_lock;
+ /* Pages making up the egress queue. */
+ struct page *eq_pages;
+ /* Address of the actual egress queue. */
+ lepp_queue_t *eq;
+ /* Protects "eq". */
+ spinlock_t eq_lock;
/* The hypervisor handle for this interface. */
int hv_devhdl;
/* The intr bit mask that IDs this device. */
u32 intr_id;
/* True iff "tile_net_open_aux()" has succeeded. */
- int partly_opened;
- /* True iff "tile_net_open_inner()" has succeeded. */
- int fully_opened;
+ bool partly_opened;
+ /* True iff the device is "active". */
+ bool active;
/* Effective network cpus. */
struct cpumask network_cpus_map;
/* Number of network cpus. */
@@ -228,6 +226,10 @@ struct tile_net_priv {
struct tile_net_cpu *cpu[NR_CPUS];
};
+/* Log2 of the number of small pages needed for the egress queue. */
+#define EQ_ORDER get_order(sizeof(lepp_queue_t))
+/* Size of the egress queue's pages. */
+#define EQ_SIZE (1 << (PAGE_SHIFT + EQ_ORDER))
/*
* The actual devices (xgbe0, xgbe1, gbe0, gbe1).
@@ -284,7 +286,11 @@ static void net_printk(char *fmt, ...)
*/
static void dump_packet(unsigned char *data, unsigned long length, char *s)
{
+ int my_cpu = smp_processor_id();
+
unsigned long i;
+ char buf[128];
+
static unsigned int count;
pr_info("dump_packet(data %p, length 0x%lx s %s count 0x%x)\n",
@@ -294,10 +300,12 @@ static void dump_packet(unsigned char *data, unsigned long length, char *s)
for (i = 0; i < length; i++) {
if ((i & 0xf) == 0)
- sprintf(buf, "%8.8lx:", i);
+ sprintf(buf, "[%02d] %8.8lx:", my_cpu, i);
sprintf(buf + strlen(buf), " %2.2x", data[i]);
- if ((i & 0xf) == 0xf || i == length - 1)
- pr_info("%s\n", buf);
+ if ((i & 0xf) == 0xf || i == length - 1) {
+ strcat(buf, "\n");
+ pr_info("%s", buf);
+ }
}
}
#endif
@@ -351,60 +359,109 @@ static void tile_net_provide_linux_buffer(struct tile_net_cpu *info,
/*
* Provide a linux buffer for LIPP.
+ *
+ * Note that the ACTUAL allocation for each buffer is a "struct sk_buff",
+ * plus a chunk of memory that includes not only the requested bytes, but
+ * also NET_SKB_PAD bytes of initial padding, and a "struct skb_shared_info".
+ *
+ * Note that "struct skb_shared_info" is 88 bytes with 64K pages and
+ * 268 bytes with 4K pages (since the frags[] array needs 18 entries).
+ *
+ * Without jumbo packets, the maximum packet size will be 1536 bytes,
+ * and we use 2 bytes (NET_IP_ALIGN) of padding. ISSUE: If we told
+ * the hardware to clip at 1518 bytes instead of 1536 bytes, then we
+ * could save an entire cache line, but in practice, we don't need it.
+ *
+ * Since CPAs are 38 bits, and we can only encode the high 31 bits in
+ * a "linux_buffer_t", the low 7 bits must be zero, and thus, we must
+ * align the actual "va" mod 128.
+ *
+ * We assume that the underlying "head" will be aligned mod 64. Note
+ * that in practice, we have seen "head" NOT aligned mod 128 even when
+ * using 2048 byte allocations, which is surprising.
+ *
+ * If "head" WAS always aligned mod 128, we could change LIPP to
+ * assume that the low SIX bits are zero, and the 7th bit is one, that
+ * is, align the actual "va" mod 128 plus 64, which would be "free".
+ *
+ * For now, the actual "head" pointer points at NET_SKB_PAD bytes of
+ * padding, plus 28 or 92 bytes of extra padding, plus the sk_buff
+ * pointer, plus the NET_IP_ALIGN padding, plus 126 or 1536 bytes for
+ * the actual packet, plus 62 bytes of empty padding, plus some
+ * padding and the "struct skb_shared_info".
+ *
+ * With 64K pages, a large buffer thus needs 32+92+4+2+1536+62+88
+ * bytes, or 1816 bytes, which fits comfortably into 2048 bytes.
+ *
+ * With 64K pages, a small buffer thus needs 32+92+4+2+126+88
+ * bytes, or 344 bytes, which means we are wasting 64+ bytes, and
+ * could presumably increase the size of small buffers.
+ *
+ * With 4K pages, a large buffer thus needs 32+92+4+2+1536+62+268
+ * bytes, or 1996 bytes, which fits comfortably into 2048 bytes.
+ *
+ * With 4K pages, a small buffer thus needs 32+92+4+2+126+268
+ * bytes, or 524 bytes, which is annoyingly wasteful.
+ *
+ * Maybe we should increase LIPP_SMALL_PACKET_SIZE to 192?
+ *
+ * ISSUE: Maybe we should increase "NET_SKB_PAD" to 64?
*/
static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
bool small)
{
- /* ISSUE: What should we use here? */
+#if TILE_NET_MTU <= 1536
+ /* Without "jumbo", 2 + 1536 should be sufficient. */
+ unsigned int large_size = NET_IP_ALIGN + 1536;
+#else
+ /* ISSUE: This has not been tested. */
unsigned int large_size = NET_IP_ALIGN + TILE_NET_MTU + 100;
+#endif
- /* Round up to ensure to avoid "false sharing" with last cache line. */
- unsigned int buffer_size =
+ /* Avoid "false sharing" with last cache line. */
+ /* ISSUE: This is already done by "dev_alloc_skb()". */
+ unsigned int len =
(((small ? LIPP_SMALL_PACKET_SIZE : large_size) +
CHIP_L2_LINE_SIZE() - 1) & -CHIP_L2_LINE_SIZE());
- /*
- * ISSUE: Since CPAs are 38 bits, and we can only encode the
- * high 31 bits in a "linux_buffer_t", the low 7 bits must be
- * zero, and thus, we must align the actual "va" mod 128.
- */
- const unsigned long align = 128;
+ unsigned int padding = 128 - NET_SKB_PAD;
+ unsigned int align;
struct sk_buff *skb;
void *va;
struct sk_buff **skb_ptr;
- /* Note that "dev_alloc_skb()" adds NET_SKB_PAD more bytes, */
- /* and also "reserves" that many bytes. */
- /* ISSUE: Can we "share" the NET_SKB_PAD bytes with "skb_ptr"? */
- int len = sizeof(*skb_ptr) + align + buffer_size;
-
- while (1) {
-
- /* Allocate (or fail). */
- skb = dev_alloc_skb(len);
- if (skb == NULL)
- return false;
-
- /* Make room for a back-pointer to 'skb'. */
- skb_reserve(skb, sizeof(*skb_ptr));
+ /* Request 96 extra bytes for alignment purposes. */
+ skb = dev_alloc_skb(len + padding);
+ if (skb == NULL)
+ return false;
- /* Make sure we are aligned. */
- skb_reserve(skb, -(long)skb->data & (align - 1));
+ /* Skip 32 or 96 bytes to align "data" mod 128. */
+ align = -(long)skb->data & (128 - 1);
+ BUG_ON(align > padding);
+ skb_reserve(skb, align);
- /* This address is given to IPP. */
- va = skb->data;
+ /* This address is given to IPP. */
+ va = skb->data;
- if (small)
- break;
+ /* Buffers must not span a huge page. */
+ BUG_ON(((((long)va & ~HPAGE_MASK) + len) & HPAGE_MASK) != 0);
- /* ISSUE: This has never been observed! */
- /* Large buffers must not span a huge page. */
- if (((((long)va & ~HPAGE_MASK) + 1535) & HPAGE_MASK) == 0)
- break;
- pr_err("Leaking unaligned linux buffer at %p.\n", va);
+#ifdef TILE_NET_PARANOIA
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default) {
+ HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va);
+ if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
+ panic("Non-HFH ingress buffer! VA=%p Mode=%d PTE=%llx",
+ va, hv_pte_get_mode(pte), hv_pte_val(pte));
}
+#endif
+#endif
+
+ /* Invalidate the packet buffer. */
+ if (!hash_default)
+ __inv_buffer(va, len);
/* Skip two bytes to satisfy LIPP assumptions. */
/* Note that this aligns IP on a 16 byte boundary. */
@@ -415,23 +472,9 @@ static bool tile_net_provide_needed_buffer(struct tile_net_cpu *info,
skb_ptr = va - sizeof(*skb_ptr);
*skb_ptr = skb;
- /* Invalidate the packet buffer. */
- if (!hash_default)
- __inv_buffer(skb->data, buffer_size);
-
/* Make sure "skb_ptr" has been flushed. */
__insn_mf();
-#ifdef TILE_NET_PARANOIA
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (hash_default) {
- HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)va);
- if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
- panic("Non-coherent ingress buffer!");
- }
-#endif
-#endif
-
/* Provide the new buffer. */
tile_net_provide_linux_buffer(info, va, small);
@@ -469,48 +512,64 @@ oops:
* Grab some LEPP completions, and store them in "comps", of size
* "comps_size", and return the number of completions which were
* stored, so the caller can free them.
- *
- * If "pending" is not NULL, it will be set to true if there might
- * still be some pending completions caused by this tile, else false.
*/
-static unsigned int tile_net_lepp_grab_comps(struct net_device *dev,
+static unsigned int tile_net_lepp_grab_comps(lepp_queue_t *eq,
struct sk_buff *comps[],
unsigned int comps_size,
- bool *pending)
+ unsigned int min_size)
{
- struct tile_net_priv *priv = netdev_priv(dev);
-
- lepp_queue_t *eq = priv->epp_queue;
-
unsigned int n = 0;
- unsigned int comp_head;
- unsigned int comp_busy;
- unsigned int comp_tail;
-
- spin_lock(&priv->comp_lock);
-
- comp_head = eq->comp_head;
- comp_busy = eq->comp_busy;
- comp_tail = eq->comp_tail;
+ unsigned int comp_head = eq->comp_head;
+ unsigned int comp_busy = eq->comp_busy;
while (comp_head != comp_busy && n < comps_size) {
comps[n++] = eq->comps[comp_head];
LEPP_QINC(comp_head);
}
- if (pending != NULL)
- *pending = (comp_head != comp_tail);
+ if (n < min_size)
+ return 0;
eq->comp_head = comp_head;
- spin_unlock(&priv->comp_lock);
-
return n;
}
/*
+ * Free some comps, and return true iff there are still some pending.
+ */
+static bool tile_net_lepp_free_comps(struct net_device *dev, bool all)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ lepp_queue_t *eq = priv->eq;
+
+ struct sk_buff *olds[64];
+ unsigned int wanted = 64;
+ unsigned int i, n;
+ bool pending;
+
+ spin_lock(&priv->eq_lock);
+
+ if (all)
+ eq->comp_busy = eq->comp_tail;
+
+ n = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
+
+ pending = (eq->comp_head != eq->comp_tail);
+
+ spin_unlock(&priv->eq_lock);
+
+ for (i = 0; i < n; i++)
+ kfree_skb(olds[i]);
+
+ return pending;
+}
+
+
+/*
* Make sure the egress timer is scheduled.
*
* Note that we use "schedule if not scheduled" logic instead of the more
@@ -544,21 +603,11 @@ static void tile_net_handle_egress_timer(unsigned long arg)
struct tile_net_cpu *info = (struct tile_net_cpu *)arg;
struct net_device *dev = info->napi.dev;
- struct sk_buff *olds[32];
- unsigned int wanted = 32;
- unsigned int i, nolds = 0;
- bool pending;
-
/* The timer is no longer scheduled. */
info->egress_timer_scheduled = false;
- nolds = tile_net_lepp_grab_comps(dev, olds, wanted, &pending);
-
- for (i = 0; i < nolds; i++)
- kfree_skb(olds[i]);
-
- /* Reschedule timer if needed. */
- if (pending)
+ /* Free comps, and reschedule timer if more are pending. */
+ if (tile_net_lepp_free_comps(dev, false))
tile_net_schedule_egress_timer(info);
}
@@ -636,8 +685,39 @@ static bool is_dup_ack(char *s1, char *s2, unsigned int len)
+static void tile_net_discard_aux(struct tile_net_cpu *info, int index)
+{
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_impl_t *qsp = queue->__system_part;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ int index2_aux = index + sizeof(netio_pkt_t);
+ int index2 =
+ ((index2_aux ==
+ qsp->__packet_receive_queue.__last_packet_plus_one) ?
+ 0 : index2_aux);
+
+ netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index);
+
+ /* Extract the "linux_buffer_t". */
+ unsigned int buffer = pkt->__packet.word;
+
+ /* Convert "linux_buffer_t" to "va". */
+ void *va = __va((phys_addr_t)(buffer >> 1) << 7);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ kfree_skb(skb);
+
+ /* Consume this packet. */
+ qup->__packet_receive_read = index2;
+}
+
+
/*
- * Like "tile_net_handle_packets()", but just discard packets.
+ * Like "tile_net_poll()", but just discard packets.
*/
static void tile_net_discard_packets(struct net_device *dev)
{
@@ -650,32 +730,8 @@ static void tile_net_discard_packets(struct net_device *dev)
while (qup->__packet_receive_read !=
qsp->__packet_receive_queue.__packet_write) {
-
int index = qup->__packet_receive_read;
-
- int index2_aux = index + sizeof(netio_pkt_t);
- int index2 =
- ((index2_aux ==
- qsp->__packet_receive_queue.__last_packet_plus_one) ?
- 0 : index2_aux);
-
- netio_pkt_t *pkt = (netio_pkt_t *)
- ((unsigned long) &qsp[1] + index);
-
- /* Extract the "linux_buffer_t". */
- unsigned int buffer = pkt->__packet.word;
-
- /* Convert "linux_buffer_t" to "va". */
- void *va = __va((phys_addr_t)(buffer >> 1) << 7);
-
- /* Acquire the associated "skb". */
- struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
- struct sk_buff *skb = *skb_ptr;
-
- kfree_skb(skb);
-
- /* Consume this packet. */
- qup->__packet_receive_read = index2;
+ tile_net_discard_aux(info, index);
}
}
@@ -704,7 +760,8 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt);
- /* Extract the packet size. */
+ /* Extract the packet size. FIXME: Shouldn't the second line */
+ /* get subtracted? Mostly moot, since it should be "zero". */
unsigned long len =
(NETIO_PKT_CUSTOM_LENGTH(pkt) +
NET_IP_ALIGN - NETIO_PACKET_PADDING);
@@ -722,15 +779,6 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
/* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
unsigned char *buf = va + NET_IP_ALIGN;
-#ifdef IGNORE_DUP_ACKS
-
- static int other;
- static int final;
- static int keep;
- static int skip;
-
-#endif
-
/* Invalidate the packet buffer. */
if (!hash_default)
__inv_buffer(buf, len);
@@ -745,16 +793,8 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
#ifdef TILE_NET_VERIFY_INGRESS
if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) &&
NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) {
- /*
- * FIXME: This complains about UDP packets
- * with a "zero" checksum (bug 6624).
- */
-#ifdef TILE_NET_PANIC_ON_BAD
- dump_packet(buf, len, "rx");
- panic("Bad L4 checksum.");
-#else
+ /* Bug 6624: Includes UDP packets with a "zero" checksum. */
pr_warning("Bad L4 checksum on %d byte packet.\n", len);
-#endif
}
if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) &&
NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) {
@@ -769,90 +809,29 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
}
break;
case NETIO_PKT_STATUS_BAD:
-#ifdef TILE_NET_PANIC_ON_BAD
- dump_packet(buf, len, "rx");
- panic("Unexpected BAD packet.");
-#else
- pr_warning("Unexpected BAD %d byte packet.\n", len);
-#endif
+ pr_warning("Unexpected BAD %ld byte packet.\n", len);
}
#endif
filter = 0;
+ /* ISSUE: Filter TCP packets with "bad" checksums? */
+
if (!(dev->flags & IFF_UP)) {
/* Filter packets received before we're up. */
filter = 1;
+ } else if (NETIO_PKT_STATUS_M(metadata, pkt) == NETIO_PKT_STATUS_BAD) {
+ /* Filter "truncated" packets. */
+ filter = 1;
} else if (!(dev->flags & IFF_PROMISC)) {
- /*
- * FIXME: Implement HW multicast filter.
- */
- if (is_unicast_ether_addr(buf)) {
+ /* FIXME: Implement HW multicast filter. */
+ if (!is_multicast_ether_addr(buf)) {
/* Filter packets not for our address. */
const u8 *mine = dev->dev_addr;
filter = compare_ether_addr(mine, buf);
}
}
-#ifdef IGNORE_DUP_ACKS
-
- if (len != 66) {
- /* FIXME: Must check "is_tcp_ack(buf, len)" somehow. */
-
- other++;
-
- } else if (index2 ==
- qsp->__packet_receive_queue.__packet_write) {
-
- final++;
-
- } else {
-
- netio_pkt_t *pkt2 = (netio_pkt_t *)
- ((unsigned long) &qsp[1] + index2);
-
- netio_pkt_metadata_t *metadata2 =
- NETIO_PKT_METADATA(pkt2);
-
- /* Extract the packet size. */
- unsigned long len2 =
- (NETIO_PKT_CUSTOM_LENGTH(pkt2) +
- NET_IP_ALIGN - NETIO_PACKET_PADDING);
-
- if (len2 == 66 &&
- NETIO_PKT_FLOW_HASH_M(metadata, pkt) ==
- NETIO_PKT_FLOW_HASH_M(metadata2, pkt2)) {
-
- /* Extract the "linux_buffer_t". */
- unsigned int buffer2 = pkt2->__packet.word;
-
- /* Convert "linux_buffer_t" to "va". */
- void *va2 =
- __va((phys_addr_t)(buffer2 >> 1) << 7);
-
- /* Extract the packet data pointer. */
- /* Compare to "NETIO_PKT_CUSTOM_DATA(pkt)". */
- unsigned char *buf2 = va2 + NET_IP_ALIGN;
-
- /* Invalidate the packet buffer. */
- if (!hash_default)
- __inv_buffer(buf2, len2);
-
- if (is_dup_ack(buf, buf2, len)) {
- skip++;
- filter = 1;
- } else {
- keep++;
- }
- }
- }
-
- if (net_ratelimit())
- pr_info("Other %d Final %d Keep %d Skip %d.\n",
- other, final, keep, skip);
-
-#endif
-
if (filter) {
/* ISSUE: Update "drop" statistics? */
@@ -877,10 +856,7 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
/* NOTE: This call also sets "skb->dev = dev". */
skb->protocol = eth_type_trans(skb, dev);
- /* ISSUE: Discard corrupt packets? */
- /* ISSUE: Discard packets with bad checksums? */
-
- /* Avoid recomputing TCP/UDP checksums. */
+ /* Avoid recomputing "good" TCP/UDP checksums. */
if (NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt))
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -912,9 +888,14 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
/*
* Handle some packets for the given device on the current CPU.
*
- * ISSUE: The "rotting packet" race condition occurs if a packet
- * arrives after the queue appears to be empty, and before the
- * hypervisor interrupt is re-enabled.
+ * If "tile_net_stop()" is called on some other tile while this
+ * function is running, we will return, hopefully before that
+ * other tile asks us to call "napi_disable()".
+ *
+ * The "rotting packet" race condition occurs if a packet arrives
+ * during the extremely narrow window between the queue appearing to
+ * be empty, and the ingress interrupt being re-enabled. This happens
+ * a LOT under heavy network load.
*/
static int tile_net_poll(struct napi_struct *napi, int budget)
{
@@ -928,7 +909,7 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
unsigned int work = 0;
- while (1) {
+ while (priv->active) {
int index = qup->__packet_receive_read;
if (index == qsp->__packet_receive_queue.__packet_write)
break;
@@ -941,19 +922,24 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
napi_complete(&info->napi);
- /* Re-enable hypervisor interrupts. */
+ if (!priv->active)
+ goto done;
+
+ /* Re-enable the ingress interrupt. */
enable_percpu_irq(priv->intr_id);
- /* HACK: Avoid the "rotting packet" problem. */
+ /* HACK: Avoid the "rotting packet" problem (see above). */
if (qup->__packet_receive_read !=
- qsp->__packet_receive_queue.__packet_write)
- napi_schedule(&info->napi);
-
- /* ISSUE: Handle completions? */
+ qsp->__packet_receive_queue.__packet_write) {
+ /* ISSUE: Sometimes this returns zero, presumably */
+ /* because an interrupt was handled for this tile. */
+ (void)napi_reschedule(&info->napi);
+ }
done:
- tile_net_provide_needed_buffers(info);
+ if (priv->active)
+ tile_net_provide_needed_buffers(info);
return work;
}
@@ -961,6 +947,12 @@ done:
/*
* Handle an ingress interrupt for the given device on the current cpu.
+ *
+ * ISSUE: Sometimes this gets called after "disable_percpu_irq()" has
+ * been called! This is probably due to "pending hypervisor downcalls".
+ *
+ * ISSUE: Is there any race condition between the "napi_schedule()" here
+ * and the "napi_complete()" call above?
*/
static irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr)
{
@@ -969,9 +961,15 @@ static irqreturn_t tile_net_handle_ingress_interrupt(int irq, void *dev_ptr)
int my_cpu = smp_processor_id();
struct tile_net_cpu *info = priv->cpu[my_cpu];
- /* Disable hypervisor interrupt. */
+ /* Disable the ingress interrupt. */
disable_percpu_irq(priv->intr_id);
+ /* Ignore unwanted interrupts. */
+ if (!priv->active)
+ return IRQ_HANDLED;
+
+ /* ISSUE: Sometimes "info->napi_enabled" is false here. */
+
napi_schedule(&info->napi);
return IRQ_HANDLED;
@@ -1005,8 +1003,7 @@ static int tile_net_open_aux(struct net_device *dev)
*/
{
int epp_home = hv_lotar_to_cpu(epp_lotar);
- struct page *page = virt_to_page(priv->epp_queue);
- homecache_change_page_home(page, 0, epp_home);
+ homecache_change_page_home(priv->eq_pages, EQ_ORDER, epp_home);
}
/*
@@ -1015,9 +1012,9 @@ static int tile_net_open_aux(struct net_device *dev)
{
netio_ipp_address_t ea = {
.va = 0,
- .pa = __pa(priv->epp_queue),
+ .pa = __pa(priv->eq),
.pte = hv_pte(0),
- .size = PAGE_SIZE,
+ .size = EQ_SIZE,
};
ea.pte = hv_pte_set_lotar(ea.pte, epp_lotar);
ea.pte = hv_pte_set_mode(ea.pte, HV_PTE_MODE_CACHE_TILE_L3);
@@ -1043,7 +1040,7 @@ static int tile_net_open_aux(struct net_device *dev)
/*
- * Register with hypervisor on each CPU.
+ * Register with hypervisor on the current CPU.
*
* Strangely, this function does important things even if it "fails",
* which is especially common if the link is not up yet. Hopefully
@@ -1092,7 +1089,8 @@ static void tile_net_register(void *dev_ptr)
priv->cpu[my_cpu] = info;
/*
- * Register ourselves with the IPP.
+ * Register ourselves with LIPP. This does a lot of stuff,
+ * including invoking the LIPP registration code.
*/
ret = hv_dev_pwrite(priv->hv_devhdl, 0,
(HV_VirtAddr)&config,
@@ -1101,8 +1099,11 @@ static void tile_net_register(void *dev_ptr)
PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_REGISTER_OFF) returned %d\n",
ret);
if (ret < 0) {
- printk(KERN_DEBUG "hv_dev_pwrite NETIO_IPP_INPUT_REGISTER_OFF"
- " failure %d\n", ret);
+ if (ret != NETIO_LINK_DOWN) {
+ printk(KERN_DEBUG "hv_dev_pwrite "
+ "NETIO_IPP_INPUT_REGISTER_OFF failure %d\n",
+ ret);
+ }
info->link_down = (ret == NETIO_LINK_DOWN);
return;
}
@@ -1145,15 +1146,47 @@ static void tile_net_register(void *dev_ptr)
NETIO_IPP_GET_FASTIO_OFF);
PDEBUG("hv_dev_pread(NETIO_IPP_GET_FASTIO_OFF) returned %d\n", ret);
- netif_napi_add(dev, &info->napi, tile_net_poll, 64);
-
/* Now we are registered. */
info->registered = true;
}
/*
- * Unregister with hypervisor on each CPU.
+ * Deregister with hypervisor on the current CPU.
+ *
+ * This simply discards all our credits, so no more packets will be
+ * delivered to this tile. There may still be packets in our queue.
+ *
+ * Also, disable the ingress interrupt.
+ */
+static void tile_net_deregister(void *dev_ptr)
+{
+ struct net_device *dev = (struct net_device *)dev_ptr;
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int my_cpu = smp_processor_id();
+ struct tile_net_cpu *info = priv->cpu[my_cpu];
+
+ /* Disable the ingress interrupt. */
+ disable_percpu_irq(priv->intr_id);
+
+ /* Do nothing else if not registered. */
+ if (info == NULL || !info->registered)
+ return;
+
+ {
+ struct tile_netio_queue *queue = &info->queue;
+ netio_queue_user_impl_t *qup = &queue->__user_part;
+
+ /* Discard all our credits. */
+ __netio_fastio_return_credits(qup->__fastio_index, -1);
+ }
+}
+
+
+/*
+ * Unregister with hypervisor on the current CPU.
+ *
+ * Also, disable the ingress interrupt.
*/
static void tile_net_unregister(void *dev_ptr)
{
@@ -1162,35 +1195,23 @@ static void tile_net_unregister(void *dev_ptr)
int my_cpu = smp_processor_id();
struct tile_net_cpu *info = priv->cpu[my_cpu];
- int ret = 0;
+ int ret;
int dummy = 0;
- /* Do nothing if never registered. */
- if (info == NULL)
- return;
+ /* Disable the ingress interrupt. */
+ disable_percpu_irq(priv->intr_id);
- /* Do nothing if already unregistered. */
- if (!info->registered)
+ /* Do nothing else if not registered. */
+ if (info == NULL || !info->registered)
return;
- /*
- * Unregister ourselves with LIPP.
- */
+ /* Unregister ourselves with LIPP/LEPP. */
ret = hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
sizeof(dummy), NETIO_IPP_INPUT_UNREGISTER_OFF);
- PDEBUG("hv_dev_pwrite(NETIO_IPP_INPUT_UNREGISTER_OFF) returned %d\n",
- ret);
- if (ret < 0) {
- /* FIXME: Just panic? */
- pr_err("hv_dev_pwrite NETIO_IPP_INPUT_UNREGISTER_OFF"
- " failure %d\n", ret);
- }
+ if (ret < 0)
+ panic("Failed to unregister with LIPP/LEPP!\n");
- /*
- * Discard all packets still in our NetIO queue. Hopefully,
- * once the unregister call is complete, there will be no
- * packets still in flight on the IDN.
- */
+ /* Discard all packets still in our NetIO queue. */
tile_net_discard_packets(dev);
/* Reset state. */
@@ -1200,11 +1221,6 @@ static void tile_net_unregister(void *dev_ptr)
/* Cancel egress timer. */
del_timer(&info->egress_timer);
info->egress_timer_scheduled = false;
-
- netif_napi_del(&info->napi);
-
- /* Now we are unregistered. */
- info->registered = false;
}
@@ -1212,18 +1228,28 @@ static void tile_net_unregister(void *dev_ptr)
* Helper function for "tile_net_stop()".
*
* Also used to handle registration failure in "tile_net_open_inner()",
- * when "fully_opened" is known to be false, and the various extra
- * steps in "tile_net_stop()" are not necessary. ISSUE: It might be
- * simpler if we could just call "tile_net_stop()" anyway.
+ * when the various extra steps in "tile_net_stop()" are not necessary.
*/
static void tile_net_stop_aux(struct net_device *dev)
{
struct tile_net_priv *priv = netdev_priv(dev);
+ int i;
int dummy = 0;
- /* Unregister all tiles, so LIPP will stop delivering packets. */
+ /*
+ * Unregister all tiles, so LIPP will stop delivering packets.
+ * Also, delete all the "napi" objects (sequentially, to protect
+ * "dev->napi_list").
+ */
on_each_cpu(tile_net_unregister, (void *)dev, 1);
+ for_each_online_cpu(i) {
+ struct tile_net_cpu *info = priv->cpu[i];
+ if (info != NULL && info->registered) {
+ netif_napi_del(&info->napi);
+ info->registered = false;
+ }
+ }
/* Stop LIPP/LEPP. */
if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
@@ -1235,18 +1261,15 @@ static void tile_net_stop_aux(struct net_device *dev)
/*
- * Disable ingress interrupts for the given device on the current cpu.
+ * Disable NAPI for the given device on the current cpu.
*/
-static void tile_net_disable_intr(void *dev_ptr)
+static void tile_net_stop_disable(void *dev_ptr)
{
struct net_device *dev = (struct net_device *)dev_ptr;
struct tile_net_priv *priv = netdev_priv(dev);
int my_cpu = smp_processor_id();
struct tile_net_cpu *info = priv->cpu[my_cpu];
- /* Disable hypervisor interrupt. */
- disable_percpu_irq(priv->intr_id);
-
/* Disable NAPI if needed. */
if (info != NULL && info->napi_enabled) {
napi_disable(&info->napi);
@@ -1256,21 +1279,24 @@ static void tile_net_disable_intr(void *dev_ptr)
/*
- * Enable ingress interrupts for the given device on the current cpu.
+ * Enable NAPI and the ingress interrupt for the given device
+ * on the current cpu.
+ *
+ * ISSUE: Only do this for "network cpus"?
*/
-static void tile_net_enable_intr(void *dev_ptr)
+static void tile_net_open_enable(void *dev_ptr)
{
struct net_device *dev = (struct net_device *)dev_ptr;
struct tile_net_priv *priv = netdev_priv(dev);
int my_cpu = smp_processor_id();
struct tile_net_cpu *info = priv->cpu[my_cpu];
- /* Enable hypervisor interrupt. */
- enable_percpu_irq(priv->intr_id);
-
/* Enable NAPI. */
napi_enable(&info->napi);
info->napi_enabled = true;
+
+ /* Enable the ingress interrupt. */
+ enable_percpu_irq(priv->intr_id);
}
@@ -1288,8 +1314,9 @@ static int tile_net_open_inner(struct net_device *dev)
int my_cpu = smp_processor_id();
struct tile_net_cpu *info;
struct tile_netio_queue *queue;
- unsigned int irq;
+ int result = 0;
int i;
+ int dummy = 0;
/*
* First try to register just on the local CPU, and handle any
@@ -1307,42 +1334,52 @@ static int tile_net_open_inner(struct net_device *dev)
/*
* Now register everywhere else. If any registration fails,
* even for "link down" (which might not be possible), we
- * clean up using "tile_net_stop_aux()".
+ * clean up using "tile_net_stop_aux()". Also, add all the
+ * "napi" objects (sequentially, to protect "dev->napi_list").
+ * ISSUE: Only use "netif_napi_add()" for "network cpus"?
*/
smp_call_function(tile_net_register, (void *)dev, 1);
for_each_online_cpu(i) {
- if (!priv->cpu[i]->registered) {
- tile_net_stop_aux(dev);
- return -EAGAIN;
- }
+ struct tile_net_cpu *info = priv->cpu[i];
+ if (info->registered)
+ netif_napi_add(dev, &info->napi, tile_net_poll, 64);
+ else
+ result = -EAGAIN;
+ }
+ if (result != 0) {
+ tile_net_stop_aux(dev);
+ return result;
}
queue = &info->queue;
- /*
- * Set the device intr bit mask.
- * The tile_net_register above sets per tile __intr_id.
- */
- priv->intr_id = queue->__system_part->__intr_id;
- BUG_ON(!priv->intr_id);
-
- /*
- * Register the device interrupt handler.
- * The __ffs() function returns the index into the interrupt handler
- * table from the interrupt bit mask which should have one bit
- * and one bit only set.
- */
- irq = __ffs(priv->intr_id);
- tile_irq_activate(irq, TILE_IRQ_PERCPU);
- BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt,
- 0, dev->name, (void *)dev) != 0);
+ if (priv->intr_id == 0) {
+ unsigned int irq;
- /* ISSUE: How could "priv->fully_opened" ever be "true" here? */
-
- if (!priv->fully_opened) {
+ /*
+ * Acquire the irq allocated by the hypervisor. Every
+ * queue gets the same irq. The "__intr_id" field is
+ * "1 << irq", so we use "__ffs()" to extract "irq".
+ */
+ priv->intr_id = queue->__system_part->__intr_id;
+ BUG_ON(priv->intr_id == 0);
+ irq = __ffs(priv->intr_id);
- int dummy = 0;
+ /*
+ * Register the ingress interrupt handler for this
+ * device, permanently.
+ *
+ * We used to call "free_irq()" in "tile_net_stop()",
+ * and then re-register the handler here every time,
+ * but that caused DNP errors in "handle_IRQ_event()"
+ * because "desc->action" was NULL. See bug 9143.
+ */
+ tile_irq_activate(irq, TILE_IRQ_PERCPU);
+ BUG_ON(request_irq(irq, tile_net_handle_ingress_interrupt,
+ 0, dev->name, (void *)dev) != 0);
+ }
+ {
/* Allocate initial buffers. */
int max_buffers =
@@ -1359,18 +1396,21 @@ static int tile_net_open_inner(struct net_device *dev)
if (info->num_needed_small_buffers != 0 ||
info->num_needed_large_buffers != 0)
panic("Insufficient memory for buffer stack!");
+ }
- /* Start LIPP/LEPP and activate "ingress" at the shim. */
- if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
- sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0)
- panic("Failed to activate the LIPP Shim!\n");
+ /* We are about to be active. */
+ priv->active = true;
- priv->fully_opened = 1;
- }
+ /* Make sure "active" is visible to all tiles. */
+ mb();
- /* On each tile, enable the hypervisor to trigger interrupts. */
- /* ISSUE: Do this before starting LIPP/LEPP? */
- on_each_cpu(tile_net_enable_intr, (void *)dev, 1);
+ /* On each tile, enable NAPI and the ingress interrupt. */
+ on_each_cpu(tile_net_open_enable, (void *)dev, 1);
+
+ /* Start LIPP/LEPP and activate "ingress" at the shim. */
+ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
+ sizeof(dummy), NETIO_IPP_INPUT_INIT_OFF) < 0)
+ panic("Failed to activate the LIPP Shim!\n");
/* Start our transmit queue. */
netif_start_queue(dev);
@@ -1396,9 +1436,9 @@ static void tile_net_open_retry(struct work_struct *w)
* ourselves to try again later; otherwise, tell Linux we now have
* a working link. ISSUE: What if the return value is negative?
*/
- if (tile_net_open_inner(priv->dev))
- schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
- TILE_NET_RETRY_INTERVAL);
+ if (tile_net_open_inner(priv->dev) != 0)
+ schedule_delayed_work(&priv->retry_work,
+ TILE_NET_RETRY_INTERVAL);
else
netif_carrier_on(priv->dev);
}
@@ -1412,8 +1452,8 @@ static void tile_net_open_retry(struct work_struct *w)
* The open entry point is called when a network interface is made
* active by the system (IFF_UP). At this point all resources needed
* for transmit and receive operations are allocated, the interrupt
- * handler is registered with the OS, the watchdog timer is started,
- * and the stack is notified that the interface is ready.
+ * handler is registered with the OS (if needed), the watchdog timer
+ * is started, and the stack is notified that the interface is ready.
*
* If the actual link is not available yet, then we tell Linux that
* we have no carrier, and we keep checking until the link comes up.
@@ -1468,6 +1508,10 @@ static int tile_net_open(struct net_device *dev)
#endif
priv->partly_opened = 1;
+
+ } else {
+ /* FIXME: Is this possible? */
+ /* printk("Already partly opened.\n"); */
}
/*
@@ -1487,57 +1531,17 @@ static int tile_net_open(struct net_device *dev)
* and then remember to try again later.
*/
netif_carrier_off(dev);
- schedule_delayed_work_on(singlethread_cpu, &priv->retry_work,
- TILE_NET_RETRY_INTERVAL);
+ schedule_delayed_work(&priv->retry_work, TILE_NET_RETRY_INTERVAL);
return 0;
}
-/*
- * Disables a network interface.
- *
- * Returns 0, this is not allowed to fail.
- *
- * The close entry point is called when an interface is de-activated
- * by the OS. The hardware is still under the drivers control, but
- * needs to be disabled. A global MAC reset is issued to stop the
- * hardware, and all transmit and receive resources are freed.
- *
- * ISSUE: Can this can be called while "tile_net_poll()" is running?
- */
-static int tile_net_stop(struct net_device *dev)
+static int tile_net_drain_lipp_buffers(struct tile_net_priv *priv)
{
- struct tile_net_priv *priv = netdev_priv(dev);
-
- bool pending = true;
-
- PDEBUG("tile_net_stop()\n");
-
- /* ISSUE: Only needed if not yet fully open. */
- cancel_delayed_work_sync(&priv->retry_work);
-
- /* Can't transmit any more. */
- netif_stop_queue(dev);
-
- /*
- * Disable hypervisor interrupts on each tile.
- */
- on_each_cpu(tile_net_disable_intr, (void *)dev, 1);
-
- /*
- * Unregister the interrupt handler.
- * The __ffs() function returns the index into the interrupt handler
- * table from the interrupt bit mask which should have one bit
- * and one bit only set.
- */
- if (priv->intr_id)
- free_irq(__ffs(priv->intr_id), dev);
-
- /*
- * Drain all the LIPP buffers.
- */
+ int n = 0;
+ /* Drain all the LIPP buffers. */
while (true) {
int buffer;
@@ -1560,43 +1564,105 @@ static int tile_net_stop(struct net_device *dev)
kfree_skb(skb);
}
+
+ n++;
}
- /* Stop LIPP/LEPP. */
- tile_net_stop_aux(dev);
+ return n;
+}
- priv->fully_opened = 0;
+/*
+ * Disables a network interface.
+ *
+ * Returns 0, this is not allowed to fail.
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ *
+ * ISSUE: How closely does "netif_running(dev)" mirror "priv->active"?
+ *
+ * Before we are called by "__dev_close()", "netif_running()" will
+ * have been cleared, so no NEW calls to "tile_net_poll()" will be
+ * made by "netpoll_poll_dev()".
+ *
+ * Often, this can cause some tiles to still have packets in their
+ * queues, so we must call "tile_net_discard_packets()" later.
+ *
+ * Note that some other tile may still be INSIDE "tile_net_poll()",
+ * and in fact, many will be, if there is heavy network load.
+ *
+ * Calling "on_each_cpu(tile_net_stop_disable, (void *)dev, 1)" when
+ * any tile is still "napi_schedule()"'d will induce a horrible crash
+ * when "msleep()" is called. This includes tiles which are inside
+ * "tile_net_poll()" which have not yet called "napi_complete()".
+ *
+ * So, we must first try to wait long enough for other tiles to finish
+ * with any current "tile_net_poll()" call, and, hopefully, to clear
+ * the "scheduled" flag. ISSUE: It is unclear what happens to tiles
+ * which have called "napi_schedule()" but which had not yet tried to
+ * call "tile_net_poll()", or which exhausted their budget inside
+ * "tile_net_poll()" just before this function was called.
+ */
+static int tile_net_stop(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ PDEBUG("tile_net_stop()\n");
+ /* Start discarding packets. */
+ priv->active = false;
+
+ /* Make sure "active" is visible to all tiles. */
+ mb();
/*
- * XXX: ISSUE: It appears that, in practice anyway, by the
- * time we get here, there are no pending completions.
+ * On each tile, make sure no NEW packets get delivered, and
+ * disable the ingress interrupt.
+ *
+ * Note that the ingress interrupt can fire AFTER this,
+ * presumably due to packets which were recently delivered,
+ * but it will have no effect.
*/
- while (pending) {
+ on_each_cpu(tile_net_deregister, (void *)dev, 1);
- struct sk_buff *olds[32];
- unsigned int wanted = 32;
- unsigned int i, nolds = 0;
+ /* Optimistically drain LIPP buffers. */
+ (void)tile_net_drain_lipp_buffers(priv);
- nolds = tile_net_lepp_grab_comps(dev, olds,
- wanted, &pending);
+ /* ISSUE: Only needed if not yet fully open. */
+ cancel_delayed_work_sync(&priv->retry_work);
- /* ISSUE: We have never actually seen this debug spew. */
- if (nolds != 0)
- pr_info("During tile_net_stop(), grabbed %d comps.\n",
- nolds);
+ /* Can't transmit any more. */
+ netif_stop_queue(dev);
- for (i = 0; i < nolds; i++)
- kfree_skb(olds[i]);
- }
+ /* Disable NAPI on each tile. */
+ on_each_cpu(tile_net_stop_disable, (void *)dev, 1);
+
+ /*
+ * Drain any remaining LIPP buffers. NOTE: This "printk()"
+ * has never been observed, but in theory it could happen.
+ */
+ if (tile_net_drain_lipp_buffers(priv) != 0)
+ printk("Had to drain some extra LIPP buffers!\n");
+ /* Stop LIPP/LEPP. */
+ tile_net_stop_aux(dev);
+
+ /*
+ * ISSUE: It appears that, in practice anyway, by the time we
+ * get here, there are no pending completions, but just in case,
+ * we free (all of) them anyway.
+ */
+ while (tile_net_lepp_free_comps(dev, true))
+ /* loop */;
/* Wipe the EPP queue. */
- memset(priv->epp_queue, 0, sizeof(lepp_queue_t));
+ memset(priv->eq, 0, sizeof(lepp_queue_t));
/* Evict the EPP queue. */
- finv_buffer(priv->epp_queue, PAGE_SIZE);
+ finv_buffer(priv->eq, EQ_SIZE);
return 0;
}
@@ -1620,7 +1686,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
if (b_len != 0) {
if (!hash_default)
- finv_buffer_remote(b_data, b_len);
+ finv_buffer_remote(b_data, b_len, 0);
cpa = __pa(b_data);
frags[n].cpa_lo = cpa;
@@ -1643,7 +1709,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags,
if (!hash_default) {
void *va = pfn_to_kaddr(pfn) + f->page_offset;
BUG_ON(PageHighMem(f->page));
- finv_buffer_remote(va, f->size);
+ finv_buffer_remote(va, f->size, 0);
}
cpa = ((phys_addr_t)pfn << PAGE_SHIFT) + f->page_offset;
@@ -1742,17 +1808,15 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
unsigned long irqflags;
- lepp_queue_t *eq = priv->epp_queue;
+ lepp_queue_t *eq = priv->eq;
- struct sk_buff *olds[4];
- unsigned int wanted = 4;
+ struct sk_buff *olds[8];
+ unsigned int wanted = 8;
unsigned int i, nolds = 0;
unsigned int cmd_head, cmd_tail, cmd_next;
unsigned int comp_tail;
- unsigned int free_slots;
-
/* Paranoia. */
BUG_ON(skb->protocol != htons(ETH_P_IP));
@@ -1780,34 +1844,32 @@ static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
/* Enqueue the command. */
- spin_lock_irqsave(&priv->cmd_lock, irqflags);
+ spin_lock_irqsave(&priv->eq_lock, irqflags);
/*
* Handle completions if needed to make room.
* HACK: Spin until there is sufficient room.
*/
- free_slots = lepp_num_free_comp_slots(eq);
- if (free_slots < 1) {
-spin:
- nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
- wanted - nolds, NULL);
- if (lepp_num_free_comp_slots(eq) < 1)
- goto spin;
+ if (lepp_num_free_comp_slots(eq) == 0) {
+ nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
+ if (nolds == 0) {
+busy:
+ spin_unlock_irqrestore(&priv->eq_lock, irqflags);
+ return NETDEV_TX_BUSY;
+ }
}
cmd_head = eq->cmd_head;
cmd_tail = eq->cmd_tail;
- /* NOTE: The "gotos" below are untested. */
-
/* Prepare to advance, detecting full queue. */
cmd_next = cmd_tail + cmd_size;
if (cmd_tail < cmd_head && cmd_next >= cmd_head)
- goto spin;
+ goto busy;
if (cmd_next > LEPP_CMD_LIMIT) {
cmd_next = 0;
if (cmd_next == cmd_head)
- goto spin;
+ goto busy;
}
/* Copy the command. */
@@ -1823,14 +1885,18 @@ spin:
eq->comp_tail = comp_tail;
/* Flush before allowing LEPP to handle the command. */
+ /* ISSUE: Is this the optimal location for the flush? */
__insn_mf();
eq->cmd_tail = cmd_tail;
- spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
-
+ /* NOTE: Using "4" here is more efficient than "0" or "2", */
+ /* and, strangely, more efficient than pre-checking the number */
+ /* of available completions, and comparing it to 4. */
if (nolds == 0)
- nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+ nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 4);
+
+ spin_unlock_irqrestore(&priv->eq_lock, irqflags);
/* Handle completions. */
for (i = 0; i < nolds; i++)
@@ -1870,10 +1936,10 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
unsigned int num_frags;
- lepp_queue_t *eq = priv->epp_queue;
+ lepp_queue_t *eq = priv->eq;
- struct sk_buff *olds[4];
- unsigned int wanted = 4;
+ struct sk_buff *olds[8];
+ unsigned int wanted = 8;
unsigned int i, nolds = 0;
unsigned int cmd_size = sizeof(lepp_cmd_t);
@@ -1883,8 +1949,6 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
lepp_cmd_t cmds[LEPP_MAX_FRAGS];
- unsigned int free_slots;
-
/*
* This is paranoia, since we think that if the link doesn't come
@@ -1905,7 +1969,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
if (hash_default) {
HV_PTE pte = *virt_to_pte(current->mm, (unsigned long)data);
if (hv_pte_get_mode(pte) != HV_PTE_MODE_CACHE_HASH_L3)
- panic("Non-coherent egress buffer!");
+ panic("Non-HFH egress buffer! VA=%p Mode=%d PTE=%llx",
+ data, hv_pte_get_mode(pte), hv_pte_val(pte));
}
#endif
#endif
@@ -1958,37 +2023,35 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
/* Enqueue the commands. */
- spin_lock_irqsave(&priv->cmd_lock, irqflags);
+ spin_lock_irqsave(&priv->eq_lock, irqflags);
/*
* Handle completions if needed to make room.
* HACK: Spin until there is sufficient room.
*/
- free_slots = lepp_num_free_comp_slots(eq);
- if (free_slots < 1) {
-spin:
- nolds += tile_net_lepp_grab_comps(dev, olds + nolds,
- wanted - nolds, NULL);
- if (lepp_num_free_comp_slots(eq) < 1)
- goto spin;
+ if (lepp_num_free_comp_slots(eq) == 0) {
+ nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 0);
+ if (nolds == 0) {
+busy:
+ spin_unlock_irqrestore(&priv->eq_lock, irqflags);
+ return NETDEV_TX_BUSY;
+ }
}
cmd_head = eq->cmd_head;
cmd_tail = eq->cmd_tail;
- /* NOTE: The "gotos" below are untested. */
-
/* Copy the commands, or fail. */
for (i = 0; i < num_frags; i++) {
/* Prepare to advance, detecting full queue. */
cmd_next = cmd_tail + cmd_size;
if (cmd_tail < cmd_head && cmd_next >= cmd_head)
- goto spin;
+ goto busy;
if (cmd_next > LEPP_CMD_LIMIT) {
cmd_next = 0;
if (cmd_next == cmd_head)
- goto spin;
+ goto busy;
}
/* Copy the command. */
@@ -2005,14 +2068,18 @@ spin:
eq->comp_tail = comp_tail;
/* Flush before allowing LEPP to handle the command. */
+ /* ISSUE: Is this the optimal location for the flush? */
__insn_mf();
eq->cmd_tail = cmd_tail;
- spin_unlock_irqrestore(&priv->cmd_lock, irqflags);
-
+ /* NOTE: Using "4" here is more efficient than "0" or "2", */
+ /* and, strangely, more efficient than pre-checking the number */
+ /* of available completions, and comparing it to 4. */
if (nolds == 0)
- nolds = tile_net_lepp_grab_comps(dev, olds, wanted, NULL);
+ nolds = tile_net_lepp_grab_comps(eq, olds, wanted, 4);
+
+ spin_unlock_irqrestore(&priv->eq_lock, irqflags);
/* Handle completions. */
for (i = 0; i < nolds; i++)
@@ -2261,7 +2328,6 @@ static struct net_device *tile_net_dev_init(const char *name)
int ret;
struct net_device *dev;
struct tile_net_priv *priv;
- struct page *page;
/*
* Allocate the device structure. This allocates "priv", calls
@@ -2285,23 +2351,21 @@ static struct net_device *tile_net_dev_init(const char *name)
INIT_DELAYED_WORK(&priv->retry_work, tile_net_open_retry);
- spin_lock_init(&priv->cmd_lock);
- spin_lock_init(&priv->comp_lock);
+ spin_lock_init(&priv->eq_lock);
- /* Allocate "epp_queue". */
- BUG_ON(get_order(sizeof(lepp_queue_t)) != 0);
- page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
- if (!page) {
+ /* Allocate "eq". */
+ priv->eq_pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, EQ_ORDER);
+ if (!priv->eq_pages) {
free_netdev(dev);
return NULL;
}
- priv->epp_queue = page_address(page);
+ priv->eq = page_address(priv->eq_pages);
/* Register the network device. */
ret = register_netdev(dev);
if (ret) {
pr_err("register_netdev %s failed %d\n", dev->name, ret);
- free_page((unsigned long)priv->epp_queue);
+ __free_pages(priv->eq_pages, EQ_ORDER);
free_netdev(dev);
return NULL;
}
@@ -2310,7 +2374,7 @@ static struct net_device *tile_net_dev_init(const char *name)
ret = tile_net_get_mac(dev);
if (ret < 0) {
unregister_netdev(dev);
- free_page((unsigned long)priv->epp_queue);
+ __free_pages(priv->eq_pages, EQ_ORDER);
free_netdev(dev);
return NULL;
}
@@ -2321,6 +2385,9 @@ static struct net_device *tile_net_dev_init(const char *name)
/*
* Module cleanup.
+ *
+ * FIXME: If compiled as a module, this module cannot be "unloaded",
+ * because the "ingress interrupt handler" is registered permanently.
*/
static void tile_net_cleanup(void)
{
@@ -2331,8 +2398,8 @@ static void tile_net_cleanup(void)
struct net_device *dev = tile_net_devs[i];
struct tile_net_priv *priv = netdev_priv(dev);
unregister_netdev(dev);
- finv_buffer(priv->epp_queue, PAGE_SIZE);
- free_page((unsigned long)priv->epp_queue);
+ finv_buffer(priv->eq, EQ_SIZE);
+ __free_pages(priv->eq_pages, EQ_ORDER);
free_netdev(dev);
}
}
@@ -2355,7 +2422,12 @@ static int tile_net_init_module(void)
}
+module_init(tile_net_init_module);
+module_exit(tile_net_cleanup);
+
+
#ifndef MODULE
+
/*
* The "network_cpus" boot argument specifies the cpus that are dedicated
* to handle ingress packets.
@@ -2391,8 +2463,5 @@ static int __init network_cpus_setup(char *str)
return 0;
}
__setup("network_cpus=", network_cpus_setup);
-#endif
-
-module_init(tile_net_init_module);
-module_exit(tile_net_cleanup);
+#endif
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 59f55441e075..b8ef8ddcc292 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -258,8 +258,10 @@ op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
*/
static int
log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
- unsigned long backtrace, int is_kernel, unsigned long event)
+ unsigned long backtrace, int is_kernel, unsigned long event,
+ struct task_struct *task)
{
+ struct task_struct *tsk = task ? task : current;
cpu_buf->sample_received++;
if (pc == ESCAPE_CODE) {
@@ -267,7 +269,7 @@ log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
return 0;
}
- if (op_add_code(cpu_buf, backtrace, is_kernel, current))
+ if (op_add_code(cpu_buf, backtrace, is_kernel, tsk))
goto fail;
if (op_add_sample(cpu_buf, pc, event))
@@ -292,7 +294,8 @@ static inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf)
static inline void
__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
- unsigned long event, int is_kernel)
+ unsigned long event, int is_kernel,
+ struct task_struct *task)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
unsigned long backtrace = oprofile_backtrace_depth;
@@ -301,7 +304,7 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
* if log_sample() fail we can't backtrace since we lost the
* source of this event
*/
- if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
+ if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event, task))
/* failed */
return;
@@ -313,10 +316,17 @@ __oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
oprofile_end_trace(cpu_buf);
}
+void oprofile_add_ext_hw_sample(unsigned long pc, struct pt_regs * const regs,
+ unsigned long event, int is_kernel,
+ struct task_struct *task)
+{
+ __oprofile_add_ext_sample(pc, regs, event, is_kernel, task);
+}
+
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel)
{
- __oprofile_add_ext_sample(pc, regs, event, is_kernel);
+ __oprofile_add_ext_sample(pc, regs, event, is_kernel, NULL);
}
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
@@ -332,7 +342,7 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
pc = ESCAPE_CODE; /* as this causes an early return. */
}
- __oprofile_add_ext_sample(pc, regs, event, is_kernel);
+ __oprofile_add_ext_sample(pc, regs, event, is_kernel, NULL);
}
/*
@@ -403,7 +413,7 @@ int oprofile_write_commit(struct op_entry *entry)
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
- log_sample(cpu_buf, pc, 0, is_kernel, event);
+ log_sample(cpu_buf, pc, 0, is_kernel, event, NULL);
}
void oprofile_add_trace(unsigned long pc)
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 010725117dbb..3ef44624f510 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -97,7 +97,7 @@ static struct notifier_block __refdata oprofile_cpu_notifier = {
.notifier_call = oprofile_cpu_notify,
};
-int __init oprofile_timer_init(struct oprofile_operations *ops)
+int oprofile_timer_init(struct oprofile_operations *ops)
{
int rc;
@@ -113,7 +113,7 @@ int __init oprofile_timer_init(struct oprofile_operations *ops)
return 0;
}
-void __exit oprofile_timer_exit(void)
+void oprofile_timer_exit(void)
{
unregister_hotcpu_notifier(&oprofile_cpu_notifier);
}
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 38b34a73866a..ad3d099bf5c1 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -39,7 +39,6 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
-#include <linux/dmi.h>
#include <acpi/acpi_drivers.h>
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index d554368c9f57..1d28d4451dae 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -97,7 +97,7 @@ static const struct rtc_class_ops pl030_ops = {
.set_alarm = pl030_set_alarm,
};
-static int pl030_probe(struct amba_device *dev, struct amba_id *id)
+static int pl030_probe(struct amba_device *dev, const struct amba_id *id)
{
struct pl030_rtc *rtc;
int ret;
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index d829ea63c4fb..ff1b84bd9bb5 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -307,7 +307,7 @@ static int pl031_remove(struct amba_device *adev)
return 0;
}
-static int pl031_probe(struct amba_device *adev, struct amba_id *id)
+static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
struct pl031_local *ldata;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 51c666fb67a4..645b0fcbb370 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -122,36 +122,21 @@ static int __init zfcp_module_init(void)
{
int retval = -ENOMEM;
- zfcp_data.gpn_ft_cache = zfcp_cache_hw_align("zfcp_gpn",
- sizeof(struct zfcp_fc_gpn_ft_req));
- if (!zfcp_data.gpn_ft_cache)
- goto out;
-
- zfcp_data.qtcb_cache = zfcp_cache_hw_align("zfcp_qtcb",
- sizeof(struct fsf_qtcb));
- if (!zfcp_data.qtcb_cache)
+ zfcp_fsf_qtcb_cache = zfcp_cache_hw_align("zfcp_fsf_qtcb",
+ sizeof(struct fsf_qtcb));
+ if (!zfcp_fsf_qtcb_cache)
goto out_qtcb_cache;
- zfcp_data.sr_buffer_cache = zfcp_cache_hw_align("zfcp_sr",
- sizeof(struct fsf_status_read_buffer));
- if (!zfcp_data.sr_buffer_cache)
- goto out_sr_cache;
+ zfcp_fc_req_cache = zfcp_cache_hw_align("zfcp_fc_req",
+ sizeof(struct zfcp_fc_req));
+ if (!zfcp_fc_req_cache)
+ goto out_fc_cache;
- zfcp_data.gid_pn_cache = zfcp_cache_hw_align("zfcp_gid",
- sizeof(struct zfcp_fc_gid_pn));
- if (!zfcp_data.gid_pn_cache)
- goto out_gid_cache;
-
- zfcp_data.adisc_cache = zfcp_cache_hw_align("zfcp_adisc",
- sizeof(struct zfcp_fc_els_adisc));
- if (!zfcp_data.adisc_cache)
- goto out_adisc_cache;
-
- zfcp_data.scsi_transport_template =
+ zfcp_scsi_transport_template =
fc_attach_transport(&zfcp_transport_functions);
- if (!zfcp_data.scsi_transport_template)
+ if (!zfcp_scsi_transport_template)
goto out_transport;
- scsi_transport_reserve_device(zfcp_data.scsi_transport_template,
+ scsi_transport_reserve_device(zfcp_scsi_transport_template,
sizeof(struct zfcp_scsi_dev));
@@ -175,18 +160,12 @@ static int __init zfcp_module_init(void)
out_ccw_register:
misc_deregister(&zfcp_cfdc_misc);
out_misc:
- fc_release_transport(zfcp_data.scsi_transport_template);
+ fc_release_transport(zfcp_scsi_transport_template);
out_transport:
- kmem_cache_destroy(zfcp_data.adisc_cache);
-out_adisc_cache:
- kmem_cache_destroy(zfcp_data.gid_pn_cache);
-out_gid_cache:
- kmem_cache_destroy(zfcp_data.sr_buffer_cache);
-out_sr_cache:
- kmem_cache_destroy(zfcp_data.qtcb_cache);
+ kmem_cache_destroy(zfcp_fc_req_cache);
+out_fc_cache:
+ kmem_cache_destroy(zfcp_fsf_qtcb_cache);
out_qtcb_cache:
- kmem_cache_destroy(zfcp_data.gpn_ft_cache);
-out:
return retval;
}
@@ -196,12 +175,9 @@ static void __exit zfcp_module_exit(void)
{
ccw_driver_unregister(&zfcp_ccw_driver);
misc_deregister(&zfcp_cfdc_misc);
- fc_release_transport(zfcp_data.scsi_transport_template);
- kmem_cache_destroy(zfcp_data.adisc_cache);
- kmem_cache_destroy(zfcp_data.gid_pn_cache);
- kmem_cache_destroy(zfcp_data.sr_buffer_cache);
- kmem_cache_destroy(zfcp_data.qtcb_cache);
- kmem_cache_destroy(zfcp_data.gpn_ft_cache);
+ fc_release_transport(zfcp_scsi_transport_template);
+ kmem_cache_destroy(zfcp_fc_req_cache);
+ kmem_cache_destroy(zfcp_fsf_qtcb_cache);
}
module_exit(zfcp_module_exit);
@@ -260,18 +236,18 @@ static int zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
return -ENOMEM;
adapter->pool.qtcb_pool =
- mempool_create_slab_pool(4, zfcp_data.qtcb_cache);
+ mempool_create_slab_pool(4, zfcp_fsf_qtcb_cache);
if (!adapter->pool.qtcb_pool)
return -ENOMEM;
- adapter->pool.status_read_data =
- mempool_create_slab_pool(FSF_STATUS_READS_RECOM,
- zfcp_data.sr_buffer_cache);
- if (!adapter->pool.status_read_data)
+ BUILD_BUG_ON(sizeof(struct fsf_status_read_buffer) > PAGE_SIZE);
+ adapter->pool.sr_data =
+ mempool_create_page_pool(FSF_STATUS_READS_RECOM, 0);
+ if (!adapter->pool.sr_data)
return -ENOMEM;
adapter->pool.gid_pn =
- mempool_create_slab_pool(1, zfcp_data.gid_pn_cache);
+ mempool_create_slab_pool(1, zfcp_fc_req_cache);
if (!adapter->pool.gid_pn)
return -ENOMEM;
@@ -290,8 +266,8 @@ static void zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
mempool_destroy(adapter->pool.qtcb_pool);
if (adapter->pool.status_read_req)
mempool_destroy(adapter->pool.status_read_req);
- if (adapter->pool.status_read_data)
- mempool_destroy(adapter->pool.status_read_data);
+ if (adapter->pool.sr_data)
+ mempool_destroy(adapter->pool.sr_data);
if (adapter->pool.gid_pn)
mempool_destroy(adapter->pool.gid_pn);
}
@@ -386,6 +362,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
+ INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update);
if (zfcp_qdio_setup(adapter))
goto failed;
@@ -437,7 +414,7 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN;
adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
- if (!zfcp_adapter_scsi_register(adapter))
+ if (!zfcp_scsi_adapter_register(adapter))
return adapter;
failed:
@@ -451,10 +428,11 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
cancel_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work);
+ cancel_work_sync(&adapter->ns_up_work);
zfcp_destroy_adapter_work_queue(adapter);
zfcp_fc_wka_ports_force_offline(adapter->gs);
- zfcp_adapter_scsi_unregister(adapter);
+ zfcp_scsi_adapter_unregister(adapter);
sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs);
zfcp_erp_thread_kill(adapter);
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 9ae1d0a6f627..527ba48eea57 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -89,7 +89,6 @@ struct zfcp_reqlist;
#define ZFCP_STATUS_LUN_READONLY 0x00000008
/* FSF request status (this does not have a common part) */
-#define ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT 0x00000002
#define ZFCP_STATUS_FSFREQ_ERROR 0x00000008
#define ZFCP_STATUS_FSFREQ_CLEANUP 0x00000010
#define ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED 0x00000040
@@ -108,7 +107,7 @@ struct zfcp_adapter_mempool {
mempool_t *scsi_req;
mempool_t *scsi_abort;
mempool_t *status_read_req;
- mempool_t *status_read_data;
+ mempool_t *sr_data;
mempool_t *gid_pn;
mempool_t *qtcb_pool;
};
@@ -190,6 +189,7 @@ struct zfcp_adapter {
struct fsf_qtcb_bottom_port *stats_reset_data;
unsigned long stats_reset;
struct work_struct scan_work;
+ struct work_struct ns_up_work;
struct service_level service_level;
struct workqueue_struct *work_queue;
struct device_dma_parameters dma_parms;
@@ -314,15 +314,4 @@ struct zfcp_fsf_req {
void (*handler)(struct zfcp_fsf_req *);
};
-/* driver data */
-struct zfcp_data {
- struct scsi_host_template scsi_host_template;
- struct scsi_transport_template *scsi_transport_template;
- struct kmem_cache *gpn_ft_cache;
- struct kmem_cache *qtcb_cache;
- struct kmem_cache *sr_buffer_cache;
- struct kmem_cache *gid_pn_cache;
- struct kmem_cache *adisc_cache;
-};
-
#endif /* ZFCP_DEF_H */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index e003e306f870..e1b4f800e226 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -732,7 +732,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
return ZFCP_ERP_FAILED;
- if (mempool_resize(act->adapter->pool.status_read_data,
+ if (mempool_resize(act->adapter->pool.sr_data,
act->adapter->stat_read_buf_num, GFP_KERNEL))
return ZFCP_ERP_FAILED;
@@ -1231,8 +1231,10 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
if (result == ZFCP_ERP_SUCCEEDED) {
register_service_level(&adapter->service_level);
queue_work(adapter->work_queue, &adapter->scan_work);
+ queue_work(adapter->work_queue, &adapter->ns_up_work);
} else
unregister_service_level(&adapter->service_level);
+
kref_put(&adapter->ref, zfcp_adapter_release);
break;
}
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 6e325284fbe7..03627cfd81cd 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -80,6 +80,7 @@ extern void zfcp_erp_notify(struct zfcp_erp_action *, unsigned long);
extern void zfcp_erp_timeout_handler(unsigned long);
/* zfcp_fc.c */
+extern struct kmem_cache *zfcp_fc_req_cache;
extern void zfcp_fc_enqueue_event(struct zfcp_adapter *,
enum fc_host_event_code event_code, u32);
extern void zfcp_fc_post_event(struct work_struct *);
@@ -95,8 +96,10 @@ extern int zfcp_fc_gs_setup(struct zfcp_adapter *);
extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *);
+extern void zfcp_fc_sym_name_update(struct work_struct *);
/* zfcp_fsf.c */
+extern struct kmem_cache *zfcp_fsf_qtcb_cache;
extern int zfcp_fsf_open_port(struct zfcp_erp_action *);
extern int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *);
extern int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *);
@@ -139,9 +142,9 @@ extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
struct qdio_buffer *);
/* zfcp_scsi.c */
-extern struct zfcp_data zfcp_data;
-extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
-extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
+extern struct scsi_transport_template *zfcp_scsi_transport_template;
+extern int zfcp_scsi_adapter_register(struct zfcp_adapter *);
+extern void zfcp_scsi_adapter_unregister(struct zfcp_adapter *);
extern struct fc_function_template zfcp_transport_functions;
extern void zfcp_scsi_rport_work(struct work_struct *);
extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 30cf91a787a3..297e6b71ce9c 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -11,11 +11,14 @@
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/utsname.h>
#include <scsi/fc/fc_els.h>
#include <scsi/libfc.h>
#include "zfcp_ext.h"
#include "zfcp_fc.h"
+struct kmem_cache *zfcp_fc_req_cache;
+
static u32 zfcp_fc_rscn_range_mask[] = {
[ELS_ADDR_FMT_PORT] = 0xFFFFFF,
[ELS_ADDR_FMT_AREA] = 0xFFFF00,
@@ -260,24 +263,18 @@ void zfcp_fc_incoming_els(struct zfcp_fsf_req *fsf_req)
zfcp_fc_incoming_rscn(fsf_req);
}
-static void zfcp_fc_ns_gid_pn_eval(void *data)
+static void zfcp_fc_ns_gid_pn_eval(struct zfcp_fc_req *fc_req)
{
- struct zfcp_fc_gid_pn *gid_pn = data;
- struct zfcp_fsf_ct_els *ct = &gid_pn->ct;
- struct zfcp_fc_gid_pn_req *gid_pn_req = sg_virt(ct->req);
- struct zfcp_fc_gid_pn_resp *gid_pn_resp = sg_virt(ct->resp);
- struct zfcp_port *port = gid_pn->port;
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
+ struct zfcp_fc_gid_pn_rsp *gid_pn_rsp = &fc_req->u.gid_pn.rsp;
- if (ct->status)
+ if (ct_els->status)
return;
- if (gid_pn_resp->ct_hdr.ct_cmd != FC_FS_ACC)
+ if (gid_pn_rsp->ct_hdr.ct_cmd != FC_FS_ACC)
return;
- /* paranoia */
- if (gid_pn_req->gid_pn.fn_wwpn != port->wwpn)
- return;
/* looks like a valid d_id */
- port->d_id = ntoh24(gid_pn_resp->gid_pn.fp_fid);
+ ct_els->port->d_id = ntoh24(gid_pn_rsp->gid_pn.fp_fid);
}
static void zfcp_fc_complete(void *data)
@@ -285,69 +282,73 @@ static void zfcp_fc_complete(void *data)
complete(data);
}
+static void zfcp_fc_ct_ns_init(struct fc_ct_hdr *ct_hdr, u16 cmd, u16 mr_size)
+{
+ ct_hdr->ct_rev = FC_CT_REV;
+ ct_hdr->ct_fs_type = FC_FST_DIR;
+ ct_hdr->ct_fs_subtype = FC_NS_SUBTYPE;
+ ct_hdr->ct_cmd = cmd;
+ ct_hdr->ct_mr_size = mr_size / 4;
+}
+
static int zfcp_fc_ns_gid_pn_request(struct zfcp_port *port,
- struct zfcp_fc_gid_pn *gid_pn)
+ struct zfcp_fc_req *fc_req)
{
struct zfcp_adapter *adapter = port->adapter;
DECLARE_COMPLETION_ONSTACK(completion);
+ struct zfcp_fc_gid_pn_req *gid_pn_req = &fc_req->u.gid_pn.req;
+ struct zfcp_fc_gid_pn_rsp *gid_pn_rsp = &fc_req->u.gid_pn.rsp;
int ret;
/* setup parameters for send generic command */
- gid_pn->port = port;
- gid_pn->ct.handler = zfcp_fc_complete;
- gid_pn->ct.handler_data = &completion;
- gid_pn->ct.req = &gid_pn->sg_req;
- gid_pn->ct.resp = &gid_pn->sg_resp;
- sg_init_one(&gid_pn->sg_req, &gid_pn->gid_pn_req,
- sizeof(struct zfcp_fc_gid_pn_req));
- sg_init_one(&gid_pn->sg_resp, &gid_pn->gid_pn_resp,
- sizeof(struct zfcp_fc_gid_pn_resp));
-
- /* setup nameserver request */
- gid_pn->gid_pn_req.ct_hdr.ct_rev = FC_CT_REV;
- gid_pn->gid_pn_req.ct_hdr.ct_fs_type = FC_FST_DIR;
- gid_pn->gid_pn_req.ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE;
- gid_pn->gid_pn_req.ct_hdr.ct_options = 0;
- gid_pn->gid_pn_req.ct_hdr.ct_cmd = FC_NS_GID_PN;
- gid_pn->gid_pn_req.ct_hdr.ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4;
- gid_pn->gid_pn_req.gid_pn.fn_wwpn = port->wwpn;
-
- ret = zfcp_fsf_send_ct(&adapter->gs->ds, &gid_pn->ct,
+ fc_req->ct_els.port = port;
+ fc_req->ct_els.handler = zfcp_fc_complete;
+ fc_req->ct_els.handler_data = &completion;
+ fc_req->ct_els.req = &fc_req->sg_req;
+ fc_req->ct_els.resp = &fc_req->sg_rsp;
+ sg_init_one(&fc_req->sg_req, gid_pn_req, sizeof(*gid_pn_req));
+ sg_init_one(&fc_req->sg_rsp, gid_pn_rsp, sizeof(*gid_pn_rsp));
+
+ zfcp_fc_ct_ns_init(&gid_pn_req->ct_hdr,
+ FC_NS_GID_PN, ZFCP_FC_CT_SIZE_PAGE);
+ gid_pn_req->gid_pn.fn_wwpn = port->wwpn;
+
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, &fc_req->ct_els,
adapter->pool.gid_pn_req,
ZFCP_FC_CTELS_TMO);
if (!ret) {
wait_for_completion(&completion);
- zfcp_fc_ns_gid_pn_eval(gid_pn);
+ zfcp_fc_ns_gid_pn_eval(fc_req);
}
return ret;
}
/**
- * zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
+ * zfcp_fc_ns_gid_pn - initiate GID_PN nameserver request
* @port: port where GID_PN request is needed
* return: -ENOMEM on error, 0 otherwise
*/
static int zfcp_fc_ns_gid_pn(struct zfcp_port *port)
{
int ret;
- struct zfcp_fc_gid_pn *gid_pn;
+ struct zfcp_fc_req *fc_req;
struct zfcp_adapter *adapter = port->adapter;
- gid_pn = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC);
- if (!gid_pn)
+ fc_req = mempool_alloc(adapter->pool.gid_pn, GFP_ATOMIC);
+ if (!fc_req)
return -ENOMEM;
- memset(gid_pn, 0, sizeof(*gid_pn));
+ memset(fc_req, 0, sizeof(*fc_req));
ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
if (ret)
goto out;
- ret = zfcp_fc_ns_gid_pn_request(port, gid_pn);
+ ret = zfcp_fc_ns_gid_pn_request(port, fc_req);
zfcp_fc_wka_port_put(&adapter->gs->ds);
out:
- mempool_free(gid_pn, adapter->pool.gid_pn);
+ mempool_free(fc_req, adapter->pool.gid_pn);
return ret;
}
@@ -419,11 +420,11 @@ void zfcp_fc_plogi_evaluate(struct zfcp_port *port, struct fc_els_flogi *plogi)
static void zfcp_fc_adisc_handler(void *data)
{
- struct zfcp_fc_els_adisc *adisc = data;
- struct zfcp_port *port = adisc->els.port;
- struct fc_els_adisc *adisc_resp = &adisc->adisc_resp;
+ struct zfcp_fc_req *fc_req = data;
+ struct zfcp_port *port = fc_req->ct_els.port;
+ struct fc_els_adisc *adisc_resp = &fc_req->u.adisc.rsp;
- if (adisc->els.status) {
+ if (fc_req->ct_els.status) {
/* request rejected or timed out */
zfcp_erp_port_forced_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED,
"fcadh_1");
@@ -445,42 +446,42 @@ static void zfcp_fc_adisc_handler(void *data)
out:
atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status);
put_device(&port->dev);
- kmem_cache_free(zfcp_data.adisc_cache, adisc);
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
}
static int zfcp_fc_adisc(struct zfcp_port *port)
{
- struct zfcp_fc_els_adisc *adisc;
+ struct zfcp_fc_req *fc_req;
struct zfcp_adapter *adapter = port->adapter;
+ struct Scsi_Host *shost = adapter->scsi_host;
int ret;
- adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC);
- if (!adisc)
+ fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_ATOMIC);
+ if (!fc_req)
return -ENOMEM;
- adisc->els.port = port;
- adisc->els.req = &adisc->req;
- adisc->els.resp = &adisc->resp;
- sg_init_one(adisc->els.req, &adisc->adisc_req,
+ fc_req->ct_els.port = port;
+ fc_req->ct_els.req = &fc_req->sg_req;
+ fc_req->ct_els.resp = &fc_req->sg_rsp;
+ sg_init_one(&fc_req->sg_req, &fc_req->u.adisc.req,
sizeof(struct fc_els_adisc));
- sg_init_one(adisc->els.resp, &adisc->adisc_resp,
+ sg_init_one(&fc_req->sg_rsp, &fc_req->u.adisc.rsp,
sizeof(struct fc_els_adisc));
- adisc->els.handler = zfcp_fc_adisc_handler;
- adisc->els.handler_data = adisc;
+ fc_req->ct_els.handler = zfcp_fc_adisc_handler;
+ fc_req->ct_els.handler_data = fc_req;
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC-AL-2 capability, so we don't set it */
- adisc->adisc_req.adisc_wwpn = fc_host_port_name(adapter->scsi_host);
- adisc->adisc_req.adisc_wwnn = fc_host_node_name(adapter->scsi_host);
- adisc->adisc_req.adisc_cmd = ELS_ADISC;
- hton24(adisc->adisc_req.adisc_port_id,
- fc_host_port_id(adapter->scsi_host));
+ fc_req->u.adisc.req.adisc_wwpn = fc_host_port_name(shost);
+ fc_req->u.adisc.req.adisc_wwnn = fc_host_node_name(shost);
+ fc_req->u.adisc.req.adisc_cmd = ELS_ADISC;
+ hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost));
- ret = zfcp_fsf_send_els(adapter, port->d_id, &adisc->els,
+ ret = zfcp_fsf_send_els(adapter, port->d_id, &fc_req->ct_els,
ZFCP_FC_CTELS_TMO);
if (ret)
- kmem_cache_free(zfcp_data.adisc_cache, adisc);
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
return ret;
}
@@ -528,68 +529,42 @@ void zfcp_fc_test_link(struct zfcp_port *port)
put_device(&port->dev);
}
-static void zfcp_free_sg_env(struct zfcp_fc_gpn_ft *gpn_ft, int buf_num)
+static struct zfcp_fc_req *zfcp_alloc_sg_env(int buf_num)
{
- struct scatterlist *sg = &gpn_ft->sg_req;
-
- kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg));
- zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
-
- kfree(gpn_ft);
-}
+ struct zfcp_fc_req *fc_req;
-static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)
-{
- struct zfcp_fc_gpn_ft *gpn_ft;
- struct zfcp_fc_gpn_ft_req *req;
-
- gpn_ft = kzalloc(sizeof(*gpn_ft), GFP_KERNEL);
- if (!gpn_ft)
+ fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL);
+ if (!fc_req)
return NULL;
- req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
- if (!req) {
- kfree(gpn_ft);
- gpn_ft = NULL;
- goto out;
+ if (zfcp_sg_setup_table(&fc_req->sg_rsp, buf_num)) {
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
+ return NULL;
}
- sg_init_one(&gpn_ft->sg_req, req, sizeof(*req));
- if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) {
- zfcp_free_sg_env(gpn_ft, buf_num);
- gpn_ft = NULL;
- }
-out:
- return gpn_ft;
-}
+ sg_init_one(&fc_req->sg_req, &fc_req->u.gpn_ft.req,
+ sizeof(struct zfcp_fc_gpn_ft_req));
+ return fc_req;
+}
-static int zfcp_fc_send_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
+static int zfcp_fc_send_gpn_ft(struct zfcp_fc_req *fc_req,
struct zfcp_adapter *adapter, int max_bytes)
{
- struct zfcp_fsf_ct_els *ct = &gpn_ft->ct;
- struct zfcp_fc_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
+ struct zfcp_fc_gpn_ft_req *req = &fc_req->u.gpn_ft.req;
DECLARE_COMPLETION_ONSTACK(completion);
int ret;
- /* prepare CT IU for GPN_FT */
- req->ct_hdr.ct_rev = FC_CT_REV;
- req->ct_hdr.ct_fs_type = FC_FST_DIR;
- req->ct_hdr.ct_fs_subtype = FC_NS_SUBTYPE;
- req->ct_hdr.ct_options = 0;
- req->ct_hdr.ct_cmd = FC_NS_GPN_FT;
- req->ct_hdr.ct_mr_size = max_bytes / 4;
- req->gpn_ft.fn_domain_id_scope = 0;
- req->gpn_ft.fn_area_id_scope = 0;
+ zfcp_fc_ct_ns_init(&req->ct_hdr, FC_NS_GPN_FT, max_bytes);
req->gpn_ft.fn_fc4_type = FC_TYPE_FCP;
- /* prepare zfcp_send_ct */
- ct->handler = zfcp_fc_complete;
- ct->handler_data = &completion;
- ct->req = &gpn_ft->sg_req;
- ct->resp = gpn_ft->sg_resp;
+ ct_els->handler = zfcp_fc_complete;
+ ct_els->handler_data = &completion;
+ ct_els->req = &fc_req->sg_req;
+ ct_els->resp = &fc_req->sg_rsp;
- ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct, NULL,
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
ZFCP_FC_CTELS_TMO);
if (!ret)
wait_for_completion(&completion);
@@ -610,11 +585,11 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh)
list_move_tail(&port->list, lh);
}
-static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
+static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_req *fc_req,
struct zfcp_adapter *adapter, int max_entries)
{
- struct zfcp_fsf_ct_els *ct = &gpn_ft->ct;
- struct scatterlist *sg = gpn_ft->sg_resp;
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
+ struct scatterlist *sg = &fc_req->sg_rsp;
struct fc_ct_hdr *hdr = sg_virt(sg);
struct fc_gpn_ft_resp *acc = sg_virt(sg);
struct zfcp_port *port, *tmp;
@@ -623,7 +598,7 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_gpn_ft *gpn_ft,
u32 d_id;
int ret = 0, x, last = 0;
- if (ct->status)
+ if (ct_els->status)
return -EIO;
if (hdr->ct_cmd != FC_FS_ACC) {
@@ -687,7 +662,7 @@ void zfcp_fc_scan_ports(struct work_struct *work)
struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
scan_work);
int ret, i;
- struct zfcp_fc_gpn_ft *gpn_ft;
+ struct zfcp_fc_req *fc_req;
int chain, max_entries, buf_num, max_bytes;
chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS;
@@ -702,25 +677,145 @@ void zfcp_fc_scan_ports(struct work_struct *work)
if (zfcp_fc_wka_port_get(&adapter->gs->ds))
return;
- gpn_ft = zfcp_alloc_sg_env(buf_num);
- if (!gpn_ft)
+ fc_req = zfcp_alloc_sg_env(buf_num);
+ if (!fc_req)
goto out;
for (i = 0; i < 3; i++) {
- ret = zfcp_fc_send_gpn_ft(gpn_ft, adapter, max_bytes);
+ ret = zfcp_fc_send_gpn_ft(fc_req, adapter, max_bytes);
if (!ret) {
- ret = zfcp_fc_eval_gpn_ft(gpn_ft, adapter, max_entries);
+ ret = zfcp_fc_eval_gpn_ft(fc_req, adapter, max_entries);
if (ret == -EAGAIN)
ssleep(1);
else
break;
}
}
- zfcp_free_sg_env(gpn_ft, buf_num);
+ zfcp_sg_free_table(&fc_req->sg_rsp, buf_num);
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
out:
zfcp_fc_wka_port_put(&adapter->gs->ds);
}
+static int zfcp_fc_gspn(struct zfcp_adapter *adapter,
+ struct zfcp_fc_req *fc_req)
+{
+ DECLARE_COMPLETION_ONSTACK(completion);
+ char devno[] = "DEVNO:";
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
+ struct zfcp_fc_gspn_req *gspn_req = &fc_req->u.gspn.req;
+ struct zfcp_fc_gspn_rsp *gspn_rsp = &fc_req->u.gspn.rsp;
+ int ret;
+
+ zfcp_fc_ct_ns_init(&gspn_req->ct_hdr, FC_NS_GSPN_ID,
+ FC_SYMBOLIC_NAME_SIZE);
+ hton24(gspn_req->gspn.fp_fid, fc_host_port_id(adapter->scsi_host));
+
+ sg_init_one(&fc_req->sg_req, gspn_req, sizeof(*gspn_req));
+ sg_init_one(&fc_req->sg_rsp, gspn_rsp, sizeof(*gspn_rsp));
+
+ ct_els->handler = zfcp_fc_complete;
+ ct_els->handler_data = &completion;
+ ct_els->req = &fc_req->sg_req;
+ ct_els->resp = &fc_req->sg_rsp;
+
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
+ ZFCP_FC_CTELS_TMO);
+ if (ret)
+ return ret;
+
+ wait_for_completion(&completion);
+ if (ct_els->status)
+ return ct_els->status;
+
+ if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_NPIV &&
+ !(strstr(gspn_rsp->gspn.fp_name, devno)))
+ snprintf(fc_host_symbolic_name(adapter->scsi_host),
+ FC_SYMBOLIC_NAME_SIZE, "%s%s %s NAME: %s",
+ gspn_rsp->gspn.fp_name, devno,
+ dev_name(&adapter->ccw_device->dev),
+ init_utsname()->nodename);
+ else
+ strlcpy(fc_host_symbolic_name(adapter->scsi_host),
+ gspn_rsp->gspn.fp_name, FC_SYMBOLIC_NAME_SIZE);
+
+ return 0;
+}
+
+static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
+ struct zfcp_fc_req *fc_req)
+{
+ DECLARE_COMPLETION_ONSTACK(completion);
+ struct Scsi_Host *shost = adapter->scsi_host;
+ struct zfcp_fsf_ct_els *ct_els = &fc_req->ct_els;
+ struct zfcp_fc_rspn_req *rspn_req = &fc_req->u.rspn.req;
+ struct fc_ct_hdr *rspn_rsp = &fc_req->u.rspn.rsp;
+ int ret, len;
+
+ zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
+ FC_SYMBOLIC_NAME_SIZE);
+ hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
+ len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
+ FC_SYMBOLIC_NAME_SIZE);
+ rspn_req->rspn.fr_name_len = len;
+
+ sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));
+ sg_init_one(&fc_req->sg_rsp, rspn_rsp, sizeof(*rspn_rsp));
+
+ ct_els->handler = zfcp_fc_complete;
+ ct_els->handler_data = &completion;
+ ct_els->req = &fc_req->sg_req;
+ ct_els->resp = &fc_req->sg_rsp;
+
+ ret = zfcp_fsf_send_ct(&adapter->gs->ds, ct_els, NULL,
+ ZFCP_FC_CTELS_TMO);
+ if (!ret)
+ wait_for_completion(&completion);
+}
+
+/**
+ * zfcp_fc_sym_name_update - Retrieve and update the symbolic port name
+ * @work: ns_up_work of the adapter where to update the symbolic port name
+ *
+ * Retrieve the current symbolic port name that may have been set by
+ * the hardware using the GSPN request and update the fc_host
+ * symbolic_name sysfs attribute. When running in NPIV mode (and hence
+ * the port name is unique for this system), update the symbolic port
+ * name to add Linux specific information and update the FC nameserver
+ * using the RSPN request.
+ */
+void zfcp_fc_sym_name_update(struct work_struct *work)
+{
+ struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
+ ns_up_work);
+ int ret;
+ struct zfcp_fc_req *fc_req;
+
+ if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT &&
+ fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
+ return;
+
+ fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_KERNEL);
+ if (!fc_req)
+ return;
+
+ ret = zfcp_fc_wka_port_get(&adapter->gs->ds);
+ if (ret)
+ goto out_free;
+
+ ret = zfcp_fc_gspn(adapter, fc_req);
+ if (ret || fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPIV)
+ goto out_ds_put;
+
+ memset(fc_req, 0, sizeof(*fc_req));
+ zfcp_fc_rspn(adapter, fc_req);
+
+out_ds_put:
+ zfcp_fc_wka_port_put(&adapter->gs->ds);
+out_free:
+ kmem_cache_free(zfcp_fc_req_cache, fc_req);
+}
+
static void zfcp_fc_ct_els_job_handler(void *data)
{
struct fc_bsg_job *job = data;
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index b464ae01086c..4561f3bf7300 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -64,33 +64,16 @@ struct zfcp_fc_gid_pn_req {
} __packed;
/**
- * struct zfcp_fc_gid_pn_resp - container for ct header plus gid_pn response
+ * struct zfcp_fc_gid_pn_rsp - container for ct header plus gid_pn response
* @ct_hdr: FC GS common transport header
* @gid_pn: GID_PN response
*/
-struct zfcp_fc_gid_pn_resp {
+struct zfcp_fc_gid_pn_rsp {
struct fc_ct_hdr ct_hdr;
struct fc_gid_pn_resp gid_pn;
} __packed;
/**
- * struct zfcp_fc_gid_pn - everything required in zfcp for gid_pn request
- * @ct: data passed to zfcp_fsf for issuing fsf request
- * @sg_req: scatterlist entry for request data
- * @sg_resp: scatterlist entry for response data
- * @gid_pn_req: GID_PN request data
- * @gid_pn_resp: GID_PN response data
- */
-struct zfcp_fc_gid_pn {
- struct zfcp_fsf_ct_els ct;
- struct scatterlist sg_req;
- struct scatterlist sg_resp;
- struct zfcp_fc_gid_pn_req gid_pn_req;
- struct zfcp_fc_gid_pn_resp gid_pn_resp;
- struct zfcp_port *port;
-};
-
-/**
* struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request
* @ct_hdr: FC GS common transport header
* @gpn_ft: GPN_FT request
@@ -101,41 +84,72 @@ struct zfcp_fc_gpn_ft_req {
} __packed;
/**
- * struct zfcp_fc_gpn_ft_resp - container for ct header plus gpn_ft response
+ * struct zfcp_fc_gspn_req - container for ct header plus GSPN_ID request
* @ct_hdr: FC GS common transport header
- * @gpn_ft: Array of gpn_ft response data to fill one memory page
+ * @gspn: GSPN_ID request
*/
-struct zfcp_fc_gpn_ft_resp {
+struct zfcp_fc_gspn_req {
struct fc_ct_hdr ct_hdr;
- struct fc_gpn_ft_resp gpn_ft[ZFCP_FC_GPN_FT_ENT_PAGE];
+ struct fc_gid_pn_resp gspn;
} __packed;
/**
- * struct zfcp_fc_gpn_ft - zfcp data for gpn_ft request
- * @ct: data passed to zfcp_fsf for issuing fsf request
- * @sg_req: scatter list entry for gpn_ft request
- * @sg_resp: scatter list entries for gpn_ft responses (per memory page)
+ * struct zfcp_fc_gspn_rsp - container for ct header plus GSPN_ID response
+ * @ct_hdr: FC GS common transport header
+ * @gspn: GSPN_ID response
+ * @name: The name string of the GSPN_ID response
*/
-struct zfcp_fc_gpn_ft {
- struct zfcp_fsf_ct_els ct;
- struct scatterlist sg_req;
- struct scatterlist sg_resp[ZFCP_FC_GPN_FT_NUM_BUFS];
-};
+struct zfcp_fc_gspn_rsp {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_gspn_resp gspn;
+ char name[FC_SYMBOLIC_NAME_SIZE];
+} __packed;
/**
- * struct zfcp_fc_els_adisc - everything required in zfcp for issuing ELS ADISC
- * @els: data required for issuing els fsf command
- * @req: scatterlist entry for ELS ADISC request
- * @resp: scatterlist entry for ELS ADISC response
- * @adisc_req: ELS ADISC request data
- * @adisc_resp: ELS ADISC response data
+ * struct zfcp_fc_rspn_req - container for ct header plus RSPN_ID request
+ * @ct_hdr: FC GS common transport header
+ * @rspn: RSPN_ID request
+ * @name: The name string of the RSPN_ID request
*/
-struct zfcp_fc_els_adisc {
- struct zfcp_fsf_ct_els els;
- struct scatterlist req;
- struct scatterlist resp;
- struct fc_els_adisc adisc_req;
- struct fc_els_adisc adisc_resp;
+struct zfcp_fc_rspn_req {
+ struct fc_ct_hdr ct_hdr;
+ struct fc_ns_rspn rspn;
+ char name[FC_SYMBOLIC_NAME_SIZE];
+} __packed;
+
+/**
+ * struct zfcp_fc_req - Container for FC ELS and CT requests sent from zfcp
+ * @ct_els: data required for issuing fsf command
+ * @sg_req: scatterlist entry for request data
+ * @sg_rsp: scatterlist entry for response data
+ * @u: request specific data
+ */
+struct zfcp_fc_req {
+ struct zfcp_fsf_ct_els ct_els;
+ struct scatterlist sg_req;
+ struct scatterlist sg_rsp;
+ union {
+ struct {
+ struct fc_els_adisc req;
+ struct fc_els_adisc rsp;
+ } adisc;
+ struct {
+ struct zfcp_fc_gid_pn_req req;
+ struct zfcp_fc_gid_pn_rsp rsp;
+ } gid_pn;
+ struct {
+ struct scatterlist sg_rsp2[ZFCP_FC_GPN_FT_NUM_BUFS - 1];
+ struct zfcp_fc_gpn_ft_req req;
+ } gpn_ft;
+ struct {
+ struct zfcp_fc_gspn_req req;
+ struct zfcp_fc_gspn_rsp rsp;
+ } gspn;
+ struct {
+ struct zfcp_fc_rspn_req req;
+ struct fc_ct_hdr rsp;
+ } rspn;
+ } u;
};
/**
@@ -192,14 +206,21 @@ struct zfcp_fc_wka_ports {
* zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd
* @fcp: fcp_cmnd to setup
* @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB
+ * @tm: task management flags to setup task management command
*/
static inline
-void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
+void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi,
+ u8 tm_flags)
{
char tag[2];
int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
+ if (unlikely(tm_flags)) {
+ fcp->fc_tm_flags = tm_flags;
+ return;
+ }
+
if (scsi_populate_tag_msg(scsi, tag)) {
switch (tag[0]) {
case MSG_ORDERED_TAG:
@@ -226,19 +247,6 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
}
/**
- * zfcp_fc_fcp_tm - setup FCP command as task management command
- * @fcp: fcp_cmnd to setup
- * @dev: scsi_device where to send the task management command
- * @tm: task management flags to setup tm command
- */
-static inline
-void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags)
-{
- int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun);
- fcp->fc_tm_flags |= tm_flags;
-}
-
-/**
* zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly
* @fcp_rsp: FCP RSP IU to evaluate
* @scsi: SCSI command where to update status and sense buffer
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 60ff9d172c79..a0e05ef65924 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -18,6 +18,8 @@
#include "zfcp_qdio.h"
#include "zfcp_reqlist.h"
+struct kmem_cache *zfcp_fsf_qtcb_cache;
+
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
@@ -83,7 +85,7 @@ void zfcp_fsf_req_free(struct zfcp_fsf_req *req)
}
if (likely(req->qtcb))
- kmem_cache_free(zfcp_data.qtcb_cache, req->qtcb);
+ kmem_cache_free(zfcp_fsf_qtcb_cache, req->qtcb);
kfree(req);
}
@@ -212,7 +214,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
if (req->status & ZFCP_STATUS_FSFREQ_DISMISSED) {
zfcp_dbf_hba_fsf_uss("fssrh_1", req);
- mempool_free(sr_buf, adapter->pool.status_read_data);
+ mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
zfcp_fsf_req_free(req);
return;
}
@@ -265,7 +267,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
break;
}
- mempool_free(sr_buf, adapter->pool.status_read_data);
+ mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
zfcp_fsf_req_free(req);
atomic_inc(&adapter->stat_miss);
@@ -628,7 +630,7 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
if (likely(pool))
qtcb = mempool_alloc(pool, GFP_ATOMIC);
else
- qtcb = kmem_cache_alloc(zfcp_data.qtcb_cache, GFP_ATOMIC);
+ qtcb = kmem_cache_alloc(zfcp_fsf_qtcb_cache, GFP_ATOMIC);
if (unlikely(!qtcb))
return NULL;
@@ -723,6 +725,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
struct zfcp_adapter *adapter = qdio->adapter;
struct zfcp_fsf_req *req;
struct fsf_status_read_buffer *sr_buf;
+ struct page *page;
int retval = -EIO;
spin_lock_irq(&qdio->req_q_lock);
@@ -736,11 +739,12 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
goto out;
}
- sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
- if (!sr_buf) {
+ page = mempool_alloc(adapter->pool.sr_data, GFP_ATOMIC);
+ if (!page) {
retval = -ENOMEM;
goto failed_buf;
}
+ sr_buf = page_address(page);
memset(sr_buf, 0, sizeof(*sr_buf));
req->data = sr_buf;
@@ -755,7 +759,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
failed_req_send:
req->data = NULL;
- mempool_free(sr_buf, adapter->pool.status_read_data);
+ mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
failed_buf:
zfcp_dbf_hba_fsf_uss("fssr__1", req);
zfcp_fsf_req_free(req);
@@ -1552,7 +1556,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
SBAL_FLAGS0_TYPE_READ,
qdio->adapter->pool.erp_req);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -1605,7 +1609,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
SBAL_FLAGS0_TYPE_READ,
qdio->adapter->pool.erp_req);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
retval = PTR_ERR(req);
goto out;
}
@@ -2206,7 +2210,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
- zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
+ zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0);
if (scsi_prot_sg_count(scsi_cmnd)) {
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
@@ -2284,7 +2288,6 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,
goto out;
}
- req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT;
req->data = scmnd;
req->handler = zfcp_fsf_fcp_task_mgmt_handler;
req->qtcb->header.lun_handle = zfcp_sdev->lun_handle;
@@ -2296,7 +2299,7 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_cmnd *scmnd,
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
- zfcp_fc_fcp_tm(fcp_cmnd, scmnd->device, tm_flags);
+ zfcp_fc_scsi_to_fcp(fcp_cmnd, scmnd, tm_flags);
zfcp_fsf_start_timer(req, ZFCP_SCSI_ER_TIMEOUT);
if (!zfcp_fsf_req_send(req))
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index ddb5800823a9..2a4991d6d4d5 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -292,7 +292,37 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
return SUCCESS;
}
-int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
+struct scsi_transport_template *zfcp_scsi_transport_template;
+
+static struct scsi_host_template zfcp_scsi_host_template = {
+ .module = THIS_MODULE,
+ .name = "zfcp",
+ .queuecommand = zfcp_scsi_queuecommand,
+ .eh_abort_handler = zfcp_scsi_eh_abort_handler,
+ .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
+ .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler,
+ .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
+ .slave_alloc = zfcp_scsi_slave_alloc,
+ .slave_configure = zfcp_scsi_slave_configure,
+ .slave_destroy = zfcp_scsi_slave_destroy,
+ .change_queue_depth = zfcp_scsi_change_queue_depth,
+ .proc_name = "zfcp",
+ .can_queue = 4096,
+ .this_id = -1,
+ .sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ,
+ .max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
+ .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
+ .cmd_per_lun = 1,
+ .use_clustering = 1,
+ .shost_attrs = zfcp_sysfs_shost_attrs,
+ .sdev_attrs = zfcp_sysfs_sdev_attrs,
+};
+
+/**
+ * zfcp_scsi_adapter_register - Register SCSI and FC host with SCSI midlayer
+ * @adapter: The zfcp adapter to register with the SCSI midlayer
+ */
+int zfcp_scsi_adapter_register(struct zfcp_adapter *adapter)
{
struct ccw_dev_id dev_id;
@@ -301,7 +331,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
ccw_device_get_id(adapter->ccw_device, &dev_id);
/* register adapter as SCSI host with mid layer of SCSI stack */
- adapter->scsi_host = scsi_host_alloc(&zfcp_data.scsi_host_template,
+ adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template,
sizeof (struct zfcp_adapter *));
if (!adapter->scsi_host) {
dev_err(&adapter->ccw_device->dev,
@@ -316,7 +346,7 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
adapter->scsi_host->max_channel = 0;
adapter->scsi_host->unique_id = dev_id.devno;
adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */
- adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
+ adapter->scsi_host->transportt = zfcp_scsi_transport_template;
adapter->scsi_host->hostdata[0] = (unsigned long) adapter;
@@ -328,7 +358,11 @@ int zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
return 0;
}
-void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
+/**
+ * zfcp_scsi_adapter_unregister - Unregister SCSI and FC host from SCSI midlayer
+ * @adapter: The zfcp adapter to unregister.
+ */
+void zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter)
{
struct Scsi_Host *shost;
struct zfcp_port *port;
@@ -346,8 +380,6 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
scsi_remove_host(shost);
scsi_host_put(shost);
adapter->scsi_host = NULL;
-
- return;
}
static struct fc_host_statistics*
@@ -688,33 +720,8 @@ struct fc_function_template zfcp_transport_functions = {
/* no functions registered for following dynamic attributes but
directly set by LLDD */
.show_host_port_type = 1,
+ .show_host_symbolic_name = 1,
.show_host_speed = 1,
.show_host_port_id = 1,
.dd_bsg_size = sizeof(struct zfcp_fsf_ct_els),
};
-
-struct zfcp_data zfcp_data = {
- .scsi_host_template = {
- .name = "zfcp",
- .module = THIS_MODULE,
- .proc_name = "zfcp",
- .change_queue_depth = zfcp_scsi_change_queue_depth,
- .slave_alloc = zfcp_scsi_slave_alloc,
- .slave_configure = zfcp_scsi_slave_configure,
- .slave_destroy = zfcp_scsi_slave_destroy,
- .queuecommand = zfcp_scsi_queuecommand,
- .eh_abort_handler = zfcp_scsi_eh_abort_handler,
- .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
- .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler,
- .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
- .can_queue = 4096,
- .this_id = -1,
- .sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ,
- .cmd_per_lun = 1,
- .use_clustering = 1,
- .sdev_attrs = zfcp_sysfs_sdev_attrs,
- .max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
- .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
- .shost_attrs = zfcp_sysfs_shost_attrs,
- },
-};
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8616496ffc02..4a1f029c4fe9 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -381,6 +381,7 @@ config ISCSI_BOOT_SYSFS
source "drivers/scsi/cxgbi/Kconfig"
source "drivers/scsi/bnx2i/Kconfig"
+source "drivers/scsi/bnx2fc/Kconfig"
source "drivers/scsi/be2iscsi/Kconfig"
config SGIWD93_SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index ef6de669424b..7ad0b8a79ae8 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_LIBFC) += libfc/
obj-$(CONFIG_LIBFCOE) += fcoe/
obj-$(CONFIG_FCOE) += fcoe/
obj-$(CONFIG_FCOE_FNIC) += fnic/
+obj-$(CONFIG_SCSI_BNX2X_FCOE) += libfc/ fcoe/ bnx2fc/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 9a5629f94f95..e7cd2fcbe036 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -936,8 +936,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- cancel_delayed_work(&hostdata->coroutine);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&hostdata->coroutine);
}
/**
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index be5558ab84ea..95ee50385188 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -672,7 +672,7 @@ struct scb_data {
/************************ Target Mode Definitions *****************************/
/*
- * Connection desciptor for select-in requests in target mode.
+ * Connection descriptor for select-in requests in target mode.
*/
struct target_cmd {
uint8_t scsiid; /* Our ID and the initiator's ID */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e4e651cca3e4..17444bc18bca 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -618,7 +618,7 @@ struct scb_data {
/************************ Target Mode Definitions *****************************/
/*
- * Connection desciptor for select-in requests in target mode.
+ * Connection descriptor for select-in requests in target mode.
*/
struct target_cmd {
uint8_t scsiid; /* Our ID and the initiator's ID */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 3f5a542a7793..e021b4812d58 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -4780,7 +4780,7 @@ ahc_init_scbdata(struct ahc_softc *ahc)
SLIST_INIT(&scb_data->sg_maps);
/* Allocate SCB resources */
- scb_data->scbarray = (struct scb *)kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC);
+ scb_data->scbarray = kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC);
if (scb_data->scbarray == NULL)
return (ENOMEM);
memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 984bd527c6c9..da7b9887ec48 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -1020,7 +1020,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- flush_scheduled_work();
+ flush_work_sync(&acb->arcmsr_do_message_isr_bh);
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
arcmsr_stop_adapter_bgrb(acb);
@@ -1066,7 +1066,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
(struct AdapterControlBlock *)host->hostdata;
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
- flush_scheduled_work();
+ flush_work_sync(&acb->arcmsr_do_message_isr_bh);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index eaaa8813067d..868cc5590145 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -210,28 +210,20 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
/**
- * beiscsi_conn_get_param - get the iscsi parameter
- * @cls_conn: pointer to iscsi cls conn
+ * beiscsi_ep_get_param - get the iscsi parameter
+ * @ep: pointer to iscsi ep
* @param: parameter type identifier
* @buf: buffer pointer
*
* returns iscsi parameter
*/
-int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+int beiscsi_ep_get_param(struct iscsi_endpoint *ep,
enum iscsi_param param, char *buf)
{
- struct beiscsi_endpoint *beiscsi_ep;
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
int len = 0;
SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param);
- beiscsi_ep = beiscsi_conn->ep;
- if (!beiscsi_ep) {
- SE_DEBUG(DBG_LVL_1,
- "In beiscsi_conn_get_param , no beiscsi_ep\n");
- return -ENODEV;
- }
switch (param) {
case ISCSI_PARAM_CONN_PORT:
@@ -244,7 +236,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
break;
default:
- return iscsi_conn_get_param(cls_conn, param, buf);
+ return -ENOSYS;
}
return len;
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 8950a702b9f4..9c532797c29e 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -48,8 +48,8 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn,
uint64_t transport_fd, int is_leading);
-int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf);
+int beiscsi_ep_get_param(struct iscsi_endpoint *ep, enum iscsi_param param,
+ char *buf);
int beiscsi_get_host_param(struct Scsi_Host *shost,
enum iscsi_host_param param, char *buf);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 638c72b7f94a..24e20ba9633c 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -4384,7 +4384,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.bind_conn = beiscsi_conn_bind,
.destroy_conn = iscsi_conn_teardown,
.set_param = beiscsi_set_param,
- .get_conn_param = beiscsi_conn_get_param,
+ .get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.get_host_param = beiscsi_get_host_param,
.start_conn = beiscsi_conn_start,
@@ -4395,6 +4395,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.alloc_pdu = beiscsi_alloc_pdu,
.parse_pdu_itt = beiscsi_parse_pdu,
.get_stats = beiscsi_conn_get_stats,
+ .get_ep_param = beiscsi_ep_get_param,
.ep_connect = beiscsi_ep_connect,
.ep_poll = beiscsi_ep_poll,
.ep_disconnect = beiscsi_ep_disconnect,
diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
new file mode 100644
index 000000000000..69d031d98469
--- /dev/null
+++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
@@ -0,0 +1,1080 @@
+#ifndef __57XX_FCOE_HSI_LINUX_LE__
+#define __57XX_FCOE_HSI_LINUX_LE__
+
+/*
+ * common data for all protocols
+ */
+struct b577xx_doorbell_hdr {
+ u8 header;
+#define B577XX_DOORBELL_HDR_RX (0x1<<0)
+#define B577XX_DOORBELL_HDR_RX_SHIFT 0
+#define B577XX_DOORBELL_HDR_DB_TYPE (0x1<<1)
+#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT 1
+#define B577XX_DOORBELL_HDR_DPM_SIZE (0x3<<2)
+#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT 2
+#define B577XX_DOORBELL_HDR_CONN_TYPE (0xF<<4)
+#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT 4
+};
+
+/*
+ * doorbell message sent to the chip
+ */
+struct b577xx_doorbell_set_prod {
+#if defined(__BIG_ENDIAN)
+ u16 prod;
+ u8 zero_fill1;
+ struct b577xx_doorbell_hdr header;
+#elif defined(__LITTLE_ENDIAN)
+ struct b577xx_doorbell_hdr header;
+ u8 zero_fill1;
+ u16 prod;
+#endif
+};
+
+
+struct regpair {
+ __le32 lo;
+ __le32 hi;
+};
+
+
+/*
+ * Fixed size structure in order to plant it in Union structure
+ */
+struct fcoe_abts_rsp_union {
+ u32 r_ctl;
+ u32 abts_rsp_payload[7];
+};
+
+
+/*
+ * 4 regs size
+ */
+struct fcoe_bd_ctx {
+ u32 buf_addr_hi;
+ u32 buf_addr_lo;
+#if defined(__BIG_ENDIAN)
+ u16 rsrv0;
+ u16 buf_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 buf_len;
+ u16 rsrv0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 rsrv1;
+ u16 flags;
+#elif defined(__LITTLE_ENDIAN)
+ u16 flags;
+ u16 rsrv1;
+#endif
+};
+
+
+struct fcoe_cleanup_flow_info {
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u16 task_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 task_id;
+ u16 reserved1;
+#endif
+ u32 reserved2[7];
+};
+
+
+struct fcoe_fcp_cmd_payload {
+ u32 opaque[8];
+};
+
+struct fcoe_fc_hdr {
+#if defined(__BIG_ENDIAN)
+ u8 cs_ctl;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 cs_ctl;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 r_ctl;
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 r_ctl;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 seq_id;
+ u8 df_ctl;
+ u16 seq_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u16 seq_cnt;
+ u8 df_ctl;
+ u8 seq_id;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 type;
+ u8 f_ctl[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 f_ctl[3];
+ u8 type;
+#endif
+ u32 parameters;
+#if defined(__BIG_ENDIAN)
+ u16 ox_id;
+ u16 rx_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_id;
+ u16 ox_id;
+#endif
+};
+
+struct fcoe_fc_frame {
+ struct fcoe_fc_hdr fc_hdr;
+ u32 reserved0[2];
+};
+
+union fcoe_cmd_flow_info {
+ struct fcoe_fcp_cmd_payload fcp_cmd_payload;
+ struct fcoe_fc_frame mp_fc_frame;
+};
+
+
+
+struct fcoe_fcp_rsp_flags {
+ u8 flags;
+#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID (0x1<<0)
+#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID_SHIFT 0
+#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID (0x1<<1)
+#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID_SHIFT 1
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER (0x1<<2)
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER_SHIFT 2
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER (0x1<<3)
+#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER_SHIFT 3
+#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ (0x1<<4)
+#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ_SHIFT 4
+#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS (0x7<<5)
+#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS_SHIFT 5
+};
+
+
+struct fcoe_fcp_rsp_payload {
+ struct regpair reserved0;
+ u32 fcp_resid;
+#if defined(__BIG_ENDIAN)
+ u16 retry_delay_timer;
+ struct fcoe_fcp_rsp_flags fcp_flags;
+ u8 scsi_status_code;
+#elif defined(__LITTLE_ENDIAN)
+ u8 scsi_status_code;
+ struct fcoe_fcp_rsp_flags fcp_flags;
+ u16 retry_delay_timer;
+#endif
+ u32 fcp_rsp_len;
+ u32 fcp_sns_len;
+};
+
+
+/*
+ * Fixed size structure in order to plant it in Union structure
+ */
+struct fcoe_fcp_rsp_union {
+ struct fcoe_fcp_rsp_payload payload;
+ struct regpair reserved0;
+};
+
+
+struct fcoe_fcp_xfr_rdy_payload {
+ u32 burst_len;
+ u32 data_ro;
+};
+
+struct fcoe_read_flow_info {
+ struct fcoe_fc_hdr fc_data_in_hdr;
+ u32 reserved[2];
+};
+
+struct fcoe_write_flow_info {
+ struct fcoe_fc_hdr fc_data_out_hdr;
+ struct fcoe_fcp_xfr_rdy_payload fcp_xfr_payload;
+};
+
+union fcoe_rsp_flow_info {
+ struct fcoe_fcp_rsp_union fcp_rsp;
+ struct fcoe_abts_rsp_union abts_rsp;
+};
+
+/*
+ * 32 bytes used for general purposes
+ */
+union fcoe_general_task_ctx {
+ union fcoe_cmd_flow_info cmd_info;
+ struct fcoe_read_flow_info read_info;
+ struct fcoe_write_flow_info write_info;
+ union fcoe_rsp_flow_info rsp_info;
+ struct fcoe_cleanup_flow_info cleanup_info;
+ u32 comp_info[8];
+};
+
+
+/*
+ * FCoE KCQ CQE parameters
+ */
+union fcoe_kcqe_params {
+ u32 reserved0[4];
+};
+
+/*
+ * FCoE KCQ CQE
+ */
+struct fcoe_kcqe {
+ u32 fcoe_conn_id;
+ u32 completion_status;
+ u32 fcoe_conn_context_id;
+ union fcoe_kcqe_params params;
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KCQE_RESERVED0 (0x7<<0)
+#define FCOE_KCQE_RESERVED0_SHIFT 0
+#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3)
+#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3
+#define FCOE_KCQE_LAYER_CODE (0x7<<4)
+#define FCOE_KCQE_LAYER_CODE_SHIFT 4
+#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7)
+#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7
+ u8 op_code;
+ u16 qe_self_seq;
+#elif defined(__LITTLE_ENDIAN)
+ u16 qe_self_seq;
+ u8 op_code;
+ u8 flags;
+#define FCOE_KCQE_RESERVED0 (0x7<<0)
+#define FCOE_KCQE_RESERVED0_SHIFT 0
+#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3)
+#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3
+#define FCOE_KCQE_LAYER_CODE (0x7<<4)
+#define FCOE_KCQE_LAYER_CODE_SHIFT 4
+#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7)
+#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE KWQE header
+ */
+struct fcoe_kwqe_header {
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0
+#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7
+ u8 op_code;
+#elif defined(__LITTLE_ENDIAN)
+ u8 op_code;
+ u8 flags;
+#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0)
+#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0
+#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4)
+#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4
+#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE firmware init request 1
+ */
+struct fcoe_kwqe_init1 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 num_tasks;
+#elif defined(__LITTLE_ENDIAN)
+ u16 num_tasks;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 task_list_pbl_addr_lo;
+ u32 task_list_pbl_addr_hi;
+ u32 dummy_buffer_addr_lo;
+ u32 dummy_buffer_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 rq_num_wqes;
+ u16 sq_num_wqes;
+#elif defined(__LITTLE_ENDIAN)
+ u16 sq_num_wqes;
+ u16 rq_num_wqes;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 cq_num_wqes;
+ u16 rq_buffer_log_size;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rq_buffer_log_size;
+ u16 cq_num_wqes;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0)
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4)
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4
+#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7
+ u8 num_sessions_log;
+ u16 mtu;
+#elif defined(__LITTLE_ENDIAN)
+ u16 mtu;
+ u8 num_sessions_log;
+ u8 flags;
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0)
+#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4)
+#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4
+#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7)
+#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7
+#endif
+};
+
+/*
+ * FCoE firmware init request 2
+ */
+struct fcoe_kwqe_init2 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 hash_tbl_pbl_addr_lo;
+ u32 hash_tbl_pbl_addr_hi;
+ u32 t2_hash_tbl_addr_lo;
+ u32 t2_hash_tbl_addr_hi;
+ u32 t2_ptr_hash_tbl_addr_lo;
+ u32 t2_ptr_hash_tbl_addr_hi;
+ u32 free_list_count;
+};
+
+/*
+ * FCoE firmware init request 3
+ */
+struct fcoe_kwqe_init3 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 error_bit_map_lo;
+ u32 error_bit_map_hi;
+#if defined(__BIG_ENDIAN)
+ u8 reserved21[3];
+ u8 cached_session_enable;
+#elif defined(__LITTLE_ENDIAN)
+ u8 cached_session_enable;
+ u8 reserved21[3];
+#endif
+ u32 reserved2[4];
+};
+
+/*
+ * FCoE connection offload request 1
+ */
+struct fcoe_kwqe_conn_offload1 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 fcoe_conn_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 fcoe_conn_id;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 sq_addr_lo;
+ u32 sq_addr_hi;
+ u32 rq_pbl_addr_lo;
+ u32 rq_pbl_addr_hi;
+ u32 rq_first_pbe_addr_lo;
+ u32 rq_first_pbe_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u16 rq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rq_prod;
+ u16 reserved0;
+#endif
+};
+
+/*
+ * FCoE connection offload request 2
+ */
+struct fcoe_kwqe_conn_offload2 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 tx_max_fc_pay_len;
+#elif defined(__LITTLE_ENDIAN)
+ u16 tx_max_fc_pay_len;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 cq_addr_lo;
+ u32 cq_addr_hi;
+ u32 xferq_addr_lo;
+ u32 xferq_addr_hi;
+ u32 conn_db_addr_lo;
+ u32 conn_db_addr_hi;
+ u32 reserved1;
+};
+
+/*
+ * FCoE connection offload request 3
+ */
+struct fcoe_kwqe_conn_offload3 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13
+#elif defined(__LITTLE_ENDIAN)
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13
+ struct fcoe_kwqe_header hdr;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 tx_max_conc_seqs_c3;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 tx_max_conc_seqs_c3;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 flags;
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 flags;
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7)
+#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7
+#endif
+ u32 reserved;
+ u32 confq_first_pbe_addr_lo;
+ u32 confq_first_pbe_addr_hi;
+#if defined(__BIG_ENDIAN)
+ u16 rx_max_fc_pay_len;
+ u16 tx_total_conc_seqs;
+#elif defined(__LITTLE_ENDIAN)
+ u16 tx_total_conc_seqs;
+ u16 rx_max_fc_pay_len;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 rx_open_seqs_exch_c3;
+ u8 rx_max_conc_seqs_c3;
+ u16 rx_total_conc_seqs;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_total_conc_seqs;
+ u8 rx_max_conc_seqs_c3;
+ u8 rx_open_seqs_exch_c3;
+#endif
+};
+
+/*
+ * FCoE connection offload request 4
+ */
+struct fcoe_kwqe_conn_offload4 {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u8 reserved2;
+ u8 e_d_tov_timer_val;
+#elif defined(__LITTLE_ENDIAN)
+ u8 e_d_tov_timer_val;
+ u8 reserved2;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u8 src_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u8 dst_mac_addr_hi16[2];
+ u8 src_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 src_mac_addr_hi16[2];
+ u8 dst_mac_addr_hi16[2];
+#endif
+ u8 dst_mac_addr_lo32[4];
+ u32 lcq_addr_lo;
+ u32 lcq_addr_hi;
+ u32 confq_pbl_base_addr_lo;
+ u32 confq_pbl_base_addr_hi;
+};
+
+/*
+ * FCoE connection enable request
+ */
+struct fcoe_kwqe_conn_enable_disable {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u8 src_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13
+ u8 src_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 src_mac_addr_hi16[2];
+ u16 vlan_tag;
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13)
+#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13
+#endif
+ u8 dst_mac_addr_lo32[4];
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 dst_mac_addr_hi16[2];
+#elif defined(__LITTLE_ENDIAN)
+ u8 dst_mac_addr_hi16[2];
+ u16 reserved1;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 vlan_flag;
+ u8 s_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id[3];
+ u8 vlan_flag;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 reserved3;
+ u8 d_id[3];
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id[3];
+ u8 reserved3;
+#endif
+ u32 context_id;
+ u32 conn_id;
+ u32 reserved4;
+};
+
+/*
+ * FCoE connection destroy request
+ */
+struct fcoe_kwqe_conn_destroy {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 context_id;
+ u32 conn_id;
+ u32 reserved1[5];
+};
+
+/*
+ * FCoe destroy request
+ */
+struct fcoe_kwqe_destroy {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 reserved1[7];
+};
+
+/*
+ * FCoe statistics request
+ */
+struct fcoe_kwqe_stat {
+#if defined(__BIG_ENDIAN)
+ struct fcoe_kwqe_header hdr;
+ u16 reserved0;
+#elif defined(__LITTLE_ENDIAN)
+ u16 reserved0;
+ struct fcoe_kwqe_header hdr;
+#endif
+ u32 stat_params_addr_lo;
+ u32 stat_params_addr_hi;
+ u32 reserved1[5];
+};
+
+/*
+ * FCoE KWQ WQE
+ */
+union fcoe_kwqe {
+ struct fcoe_kwqe_init1 init1;
+ struct fcoe_kwqe_init2 init2;
+ struct fcoe_kwqe_init3 init3;
+ struct fcoe_kwqe_conn_offload1 conn_offload1;
+ struct fcoe_kwqe_conn_offload2 conn_offload2;
+ struct fcoe_kwqe_conn_offload3 conn_offload3;
+ struct fcoe_kwqe_conn_offload4 conn_offload4;
+ struct fcoe_kwqe_conn_enable_disable conn_enable_disable;
+ struct fcoe_kwqe_conn_destroy conn_destroy;
+ struct fcoe_kwqe_destroy destroy;
+ struct fcoe_kwqe_stat statistics;
+};
+
+struct fcoe_mul_sges_ctx {
+ struct regpair cur_sge_addr;
+#if defined(__BIG_ENDIAN)
+ u8 sgl_size;
+ u8 cur_sge_idx;
+ u16 cur_sge_off;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cur_sge_off;
+ u8 cur_sge_idx;
+ u8 sgl_size;
+#endif
+};
+
+struct fcoe_s_stat_ctx {
+ u8 flags;
+#define FCOE_S_STAT_CTX_ACTIVE (0x1<<0)
+#define FCOE_S_STAT_CTX_ACTIVE_SHIFT 0
+#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND (0x1<<1)
+#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND_SHIFT 1
+#define FCOE_S_STAT_CTX_ABTS_PERFORMED (0x1<<2)
+#define FCOE_S_STAT_CTX_ABTS_PERFORMED_SHIFT 2
+#define FCOE_S_STAT_CTX_SEQ_TIMEOUT (0x1<<3)
+#define FCOE_S_STAT_CTX_SEQ_TIMEOUT_SHIFT 3
+#define FCOE_S_STAT_CTX_P_RJT (0x1<<4)
+#define FCOE_S_STAT_CTX_P_RJT_SHIFT 4
+#define FCOE_S_STAT_CTX_ACK_EOFT (0x1<<5)
+#define FCOE_S_STAT_CTX_ACK_EOFT_SHIFT 5
+#define FCOE_S_STAT_CTX_RSRV1 (0x3<<6)
+#define FCOE_S_STAT_CTX_RSRV1_SHIFT 6
+};
+
+struct fcoe_seq_ctx {
+#if defined(__BIG_ENDIAN)
+ u16 low_seq_cnt;
+ struct fcoe_s_stat_ctx s_stat;
+ u8 seq_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 seq_id;
+ struct fcoe_s_stat_ctx s_stat;
+ u16 low_seq_cnt;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 err_seq_cnt;
+ u16 high_seq_cnt;
+#elif defined(__LITTLE_ENDIAN)
+ u16 high_seq_cnt;
+ u16 err_seq_cnt;
+#endif
+ u32 low_exp_ro;
+ u32 high_exp_ro;
+};
+
+
+struct fcoe_single_sge_ctx {
+ struct regpair cur_buf_addr;
+#if defined(__BIG_ENDIAN)
+ u16 reserved0;
+ u16 cur_buf_rem;
+#elif defined(__LITTLE_ENDIAN)
+ u16 cur_buf_rem;
+ u16 reserved0;
+#endif
+};
+
+union fcoe_sgl_ctx {
+ struct fcoe_single_sge_ctx single_sge;
+ struct fcoe_mul_sges_ctx mul_sges;
+};
+
+
+
+/*
+ * FCoE SQ element
+ */
+struct fcoe_sqe {
+ u16 wqe;
+#define FCOE_SQE_TASK_ID (0x7FFF<<0)
+#define FCOE_SQE_TASK_ID_SHIFT 0
+#define FCOE_SQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_SQE_TOGGLE_BIT_SHIFT 15
+};
+
+
+
+struct fcoe_task_ctx_entry_tx_only {
+ union fcoe_sgl_ctx sgl_ctx;
+};
+
+struct fcoe_task_ctx_entry_txwr_rxrd {
+#if defined(__BIG_ENDIAN)
+ u16 verify_tx_seq;
+ u8 init_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE (0x7<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE (0x1<<3)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT 3
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE (0x1<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE (0x1<<5)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT 5
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5 (0x3<<6)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5_SHIFT 6
+ u8 tx_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4 (0xF<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4_SHIFT 4
+#elif defined(__LITTLE_ENDIAN)
+ u8 tx_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4 (0xF<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV4_SHIFT 4
+ u8 init_flags;
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE (0x7<<0)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE (0x1<<3)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT 3
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE (0x1<<4)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE (0x1<<5)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT 5
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5 (0x3<<6)
+#define FCOE_TASK_CTX_ENTRY_TXWR_RXRD_RSRV5_SHIFT 6
+ u16 verify_tx_seq;
+#endif
+};
+
+/*
+ * Common section. Both TX and RX processing might write and read from it in
+ * different flows
+ */
+struct fcoe_task_ctx_entry_tx_rx_cmn {
+ u32 data_2_trns;
+ union fcoe_general_task_ctx general;
+#if defined(__BIG_ENDIAN)
+ u16 tx_low_seq_cnt;
+ struct fcoe_s_stat_ctx tx_s_stat;
+ u8 tx_seq_id;
+#elif defined(__LITTLE_ENDIAN)
+ u8 tx_seq_id;
+ struct fcoe_s_stat_ctx tx_s_stat;
+ u16 tx_low_seq_cnt;
+#endif
+ u32 common_flags;
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID (0xFFFFFF<<0)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID (0x1<<24)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT 24
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT (0x1<<25)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT_SHIFT 25
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_XFER (0x1<<26)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_XFER_SHIFT 26
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_CONF (0x1<<27)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_PEND_CONF_SHIFT 27
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME (0x1<<28)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT 28
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_RSRV (0x7<<29)
+#define FCOE_TASK_CTX_ENTRY_TX_RX_CMN_RSRV_SHIFT 29
+};
+
+struct fcoe_task_ctx_entry_rxwr_txrd {
+#if defined(__BIG_ENDIAN)
+ u16 rx_id;
+ u16 rx_flags;
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE (0x7<<4)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ (0x1<<7)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ_SHIFT 7
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME (0x1<<8)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME_SHIFT 8
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0 (0x7F<<9)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0_SHIFT 9
+#elif defined(__LITTLE_ENDIAN)
+ u16 rx_flags;
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE (0xF<<0)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT 0
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE (0x7<<4)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT 4
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ (0x1<<7)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_CONF_REQ_SHIFT 7
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME (0x1<<8)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_MISS_FRAME_SHIFT 8
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0 (0x7F<<9)
+#define FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RESERVED0_SHIFT 9
+ u16 rx_id;
+#endif
+};
+
+struct fcoe_task_ctx_entry_rx_only {
+ struct fcoe_seq_ctx seq_ctx;
+ struct fcoe_seq_ctx ooo_seq_ctx;
+ u32 rsrv3;
+ union fcoe_sgl_ctx sgl_ctx;
+};
+
+struct fcoe_task_ctx_entry {
+ struct fcoe_task_ctx_entry_tx_only tx_wr_only;
+ struct fcoe_task_ctx_entry_txwr_rxrd tx_wr_rx_rd;
+ struct fcoe_task_ctx_entry_tx_rx_cmn cmn;
+ struct fcoe_task_ctx_entry_rxwr_txrd rx_wr_tx_rd;
+ struct fcoe_task_ctx_entry_rx_only rx_wr_only;
+ u32 reserved[4];
+};
+
+
+/*
+ * FCoE XFRQ element
+ */
+struct fcoe_xfrqe {
+ u16 wqe;
+#define FCOE_XFRQE_TASK_ID (0x7FFF<<0)
+#define FCOE_XFRQE_TASK_ID_SHIFT 0
+#define FCOE_XFRQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_XFRQE_TOGGLE_BIT_SHIFT 15
+};
+
+
+/*
+ * FCoE CONFQ element
+ */
+struct fcoe_confqe {
+#if defined(__BIG_ENDIAN)
+ u16 rx_id;
+ u16 ox_id;
+#elif defined(__LITTLE_ENDIAN)
+ u16 ox_id;
+ u16 rx_id;
+#endif
+ u32 param;
+};
+
+
+/*
+ * FCoE conection data base
+ */
+struct fcoe_conn_db {
+#if defined(__BIG_ENDIAN)
+ u16 rsrv0;
+ u16 rq_prod;
+#elif defined(__LITTLE_ENDIAN)
+ u16 rq_prod;
+ u16 rsrv0;
+#endif
+ u32 rsrv1;
+ struct regpair cq_arm;
+};
+
+
+/*
+ * FCoE CQ element
+ */
+struct fcoe_cqe {
+ u16 wqe;
+#define FCOE_CQE_CQE_INFO (0x3FFF<<0)
+#define FCOE_CQE_CQE_INFO_SHIFT 0
+#define FCOE_CQE_CQE_TYPE (0x1<<14)
+#define FCOE_CQE_CQE_TYPE_SHIFT 14
+#define FCOE_CQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_CQE_TOGGLE_BIT_SHIFT 15
+};
+
+
+/*
+ * FCoE error/warning resporting entry
+ */
+struct fcoe_err_report_entry {
+ u32 err_warn_bitmap_lo;
+ u32 err_warn_bitmap_hi;
+ u32 tx_buf_off;
+ u32 rx_buf_off;
+ struct fcoe_fc_hdr fc_hdr;
+};
+
+
+/*
+ * FCoE hash table entry (32 bytes)
+ */
+struct fcoe_hash_table_entry {
+#if defined(__BIG_ENDIAN)
+ u8 d_id_0;
+ u8 s_id_2;
+ u8 s_id_1;
+ u8 s_id_0;
+#elif defined(__LITTLE_ENDIAN)
+ u8 s_id_0;
+ u8 s_id_1;
+ u8 s_id_2;
+ u8 d_id_0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u16 dst_mac_addr_hi;
+ u8 d_id_2;
+ u8 d_id_1;
+#elif defined(__LITTLE_ENDIAN)
+ u8 d_id_1;
+ u8 d_id_2;
+ u16 dst_mac_addr_hi;
+#endif
+ u32 dst_mac_addr_lo;
+#if defined(__BIG_ENDIAN)
+ u16 vlan_id;
+ u16 src_mac_addr_hi;
+#elif defined(__LITTLE_ENDIAN)
+ u16 src_mac_addr_hi;
+ u16 vlan_id;
+#endif
+ u32 src_mac_addr_lo;
+#if defined(__BIG_ENDIAN)
+ u16 reserved1;
+ u8 reserved0;
+ u8 vlan_flag;
+#elif defined(__LITTLE_ENDIAN)
+ u8 vlan_flag;
+ u8 reserved0;
+ u16 reserved1;
+#endif
+ u32 reserved2;
+ u32 field_id;
+#define FCOE_HASH_TABLE_ENTRY_CID (0xFFFFFF<<0)
+#define FCOE_HASH_TABLE_ENTRY_CID_SHIFT 0
+#define FCOE_HASH_TABLE_ENTRY_RESERVED3 (0x7F<<24)
+#define FCOE_HASH_TABLE_ENTRY_RESERVED3_SHIFT 24
+#define FCOE_HASH_TABLE_ENTRY_VALID (0x1<<31)
+#define FCOE_HASH_TABLE_ENTRY_VALID_SHIFT 31
+};
+
+/*
+ * FCoE pending work request CQE
+ */
+struct fcoe_pend_wq_cqe {
+ u16 wqe;
+#define FCOE_PEND_WQ_CQE_TASK_ID (0x3FFF<<0)
+#define FCOE_PEND_WQ_CQE_TASK_ID_SHIFT 0
+#define FCOE_PEND_WQ_CQE_CQE_TYPE (0x1<<14)
+#define FCOE_PEND_WQ_CQE_CQE_TYPE_SHIFT 14
+#define FCOE_PEND_WQ_CQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_PEND_WQ_CQE_TOGGLE_BIT_SHIFT 15
+};
+
+
+/*
+ * FCoE RX statistics parameters section#0
+ */
+struct fcoe_rx_stat_params_section0 {
+ u32 fcoe_ver_cnt;
+ u32 fcoe_rx_pkt_cnt;
+ u32 fcoe_rx_byte_cnt;
+ u32 fcoe_rx_drop_pkt_cnt;
+};
+
+
+/*
+ * FCoE RX statistics parameters section#1
+ */
+struct fcoe_rx_stat_params_section1 {
+ u32 fc_crc_cnt;
+ u32 eofa_del_cnt;
+ u32 miss_frame_cnt;
+ u32 seq_timeout_cnt;
+ u32 drop_seq_cnt;
+ u32 fcoe_rx_drop_pkt_cnt;
+ u32 fcp_rx_pkt_cnt;
+ u32 reserved0;
+};
+
+
+/*
+ * FCoE TX statistics parameters
+ */
+struct fcoe_tx_stat_params {
+ u32 fcoe_tx_pkt_cnt;
+ u32 fcoe_tx_byte_cnt;
+ u32 fcp_tx_pkt_cnt;
+ u32 reserved0;
+};
+
+/*
+ * FCoE statistics parameters
+ */
+struct fcoe_statistics_params {
+ struct fcoe_tx_stat_params tx_stat;
+ struct fcoe_rx_stat_params_section0 rx_stat0;
+ struct fcoe_rx_stat_params_section1 rx_stat1;
+};
+
+
+/*
+ * FCoE t2 hash table entry (64 bytes)
+ */
+struct fcoe_t2_hash_table_entry {
+ struct fcoe_hash_table_entry data;
+ struct regpair next;
+ struct regpair reserved0[3];
+};
+
+/*
+ * FCoE unsolicited CQE
+ */
+struct fcoe_unsolicited_cqe {
+ u16 wqe;
+#define FCOE_UNSOLICITED_CQE_SUBTYPE (0x3<<0)
+#define FCOE_UNSOLICITED_CQE_SUBTYPE_SHIFT 0
+#define FCOE_UNSOLICITED_CQE_PKT_LEN (0xFFF<<2)
+#define FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT 2
+#define FCOE_UNSOLICITED_CQE_CQE_TYPE (0x1<<14)
+#define FCOE_UNSOLICITED_CQE_CQE_TYPE_SHIFT 14
+#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT (0x1<<15)
+#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT_SHIFT 15
+};
+
+
+
+#endif /* __57XX_FCOE_HSI_LINUX_LE__ */
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig
new file mode 100644
index 000000000000..6a38080e35ed
--- /dev/null
+++ b/drivers/scsi/bnx2fc/Kconfig
@@ -0,0 +1,11 @@
+config SCSI_BNX2X_FCOE
+ tristate "Broadcom NetXtreme II FCoE support"
+ depends on PCI
+ select NETDEVICES
+ select NETDEV_1000
+ select LIBFC
+ select LIBFCOE
+ select CNIC
+ ---help---
+ This driver supports FCoE offload for the Broadcom NetXtreme II
+ devices.
diff --git a/drivers/scsi/bnx2fc/Makefile b/drivers/scsi/bnx2fc/Makefile
new file mode 100644
index 000000000000..a92695a25176
--- /dev/null
+++ b/drivers/scsi/bnx2fc/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o
+
+bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
new file mode 100644
index 000000000000..df2fc09ba479
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -0,0 +1,511 @@
+#ifndef _BNX2FC_H_
+#define _BNX2FC_H_
+/* bnx2fc.h: Broadcom NetXtreme II Linux FCoE offload driver.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/kthread.h>
+#include <linux/crc32.h>
+#include <linux/cpu.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/libfc.h>
+#include <scsi/libfcoe.h>
+#include <scsi/fc_encode.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/fc/fc_fip.h>
+#include <scsi/fc/fc_fc2.h>
+#include <scsi/fc_frame.h>
+#include <scsi/fc/fc_fcoe.h>
+#include <scsi/fc/fc_fcp.h>
+
+#include "57xx_hsi_bnx2fc.h"
+#include "bnx2fc_debug.h"
+#include "../../net/cnic_if.h"
+#include "bnx2fc_constants.h"
+
+#define BNX2FC_NAME "bnx2fc"
+#define BNX2FC_VERSION "1.0.0"
+
+#define PFX "bnx2fc: "
+
+#define BNX2X_DOORBELL_PCI_BAR 2
+
+#define BNX2FC_MAX_BD_LEN 0xffff
+#define BNX2FC_BD_SPLIT_SZ 0x8000
+#define BNX2FC_MAX_BDS_PER_CMD 256
+
+#define BNX2FC_SQ_WQES_MAX 256
+
+#define BNX2FC_SCSI_MAX_SQES ((3 * BNX2FC_SQ_WQES_MAX) / 8)
+#define BNX2FC_TM_MAX_SQES ((BNX2FC_SQ_WQES_MAX) / 2)
+#define BNX2FC_ELS_MAX_SQES (BNX2FC_TM_MAX_SQES - 1)
+
+#define BNX2FC_RQ_WQES_MAX 16
+#define BNX2FC_CQ_WQES_MAX (BNX2FC_SQ_WQES_MAX + BNX2FC_RQ_WQES_MAX)
+
+#define BNX2FC_NUM_MAX_SESS 128
+#define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS))
+
+#define BNX2FC_MAX_OUTSTANDING_CMNDS 4096
+#define BNX2FC_MIN_PAYLOAD 256
+#define BNX2FC_MAX_PAYLOAD 2048
+
+#define BNX2FC_RQ_BUF_SZ 256
+#define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ))
+
+#define BNX2FC_SQ_WQE_SIZE (sizeof(struct fcoe_sqe))
+#define BNX2FC_CQ_WQE_SIZE (sizeof(struct fcoe_cqe))
+#define BNX2FC_RQ_WQE_SIZE (BNX2FC_RQ_BUF_SZ)
+#define BNX2FC_XFERQ_WQE_SIZE (sizeof(struct fcoe_xfrqe))
+#define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe))
+#define BNX2FC_5771X_DB_PAGE_SIZE 128
+
+#define BNX2FC_MAX_TASKS BNX2FC_MAX_OUTSTANDING_CMNDS
+#define BNX2FC_TASK_SIZE 128
+#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE)
+#define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE)
+
+#define BNX2FC_MAX_ROWS_IN_HASH_TBL 8
+#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024)
+
+#define BNX2FC_MAX_SEQS 255
+
+#define BNX2FC_READ (1 << 1)
+#define BNX2FC_WRITE (1 << 0)
+
+#define BNX2FC_MIN_XID 0
+#define BNX2FC_MAX_XID (BNX2FC_MAX_OUTSTANDING_CMNDS - 1)
+#define FCOE_MIN_XID (BNX2FC_MAX_OUTSTANDING_CMNDS)
+#define FCOE_MAX_XID \
+ (BNX2FC_MAX_OUTSTANDING_CMNDS + (nr_cpu_ids * 256))
+#define BNX2FC_MAX_LUN 0xFFFF
+#define BNX2FC_MAX_FCP_TGT 256
+#define BNX2FC_MAX_CMD_LEN 16
+
+#define BNX2FC_TM_TIMEOUT 60 /* secs */
+#define BNX2FC_IO_TIMEOUT 20000UL /* msecs */
+
+#define BNX2FC_WAIT_CNT 120
+#define BNX2FC_FW_TIMEOUT (3 * HZ)
+
+#define PORT_MAX 2
+
+#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status)
+
+/* FC FCP Status */
+#define FC_GOOD 0
+
+#define BNX2FC_RNID_HBA 0x7
+
+/* bnx2fc driver uses only one instance of fcoe_percpu_s */
+extern struct fcoe_percpu_s bnx2fc_global;
+
+extern struct workqueue_struct *bnx2fc_wq;
+
+struct bnx2fc_percpu_s {
+ struct task_struct *iothread;
+ struct list_head work_list;
+ spinlock_t fp_work_lock;
+};
+
+
+struct bnx2fc_hba {
+ struct list_head link;
+ struct cnic_dev *cnic;
+ struct pci_dev *pcidev;
+ struct net_device *netdev;
+ struct net_device *phys_dev;
+ unsigned long reg_with_cnic;
+ #define BNX2FC_CNIC_REGISTERED 1
+ struct packet_type fcoe_packet_type;
+ struct packet_type fip_packet_type;
+ struct bnx2fc_cmd_mgr *cmd_mgr;
+ struct workqueue_struct *timer_work_queue;
+ struct kref kref;
+ spinlock_t hba_lock;
+ struct mutex hba_mutex;
+ unsigned long adapter_state;
+ #define ADAPTER_STATE_UP 0
+ #define ADAPTER_STATE_GOING_DOWN 1
+ #define ADAPTER_STATE_LINK_DOWN 2
+ #define ADAPTER_STATE_READY 3
+ u32 flags;
+ unsigned long init_done;
+ #define BNX2FC_FW_INIT_DONE 0
+ #define BNX2FC_CTLR_INIT_DONE 1
+ #define BNX2FC_CREATE_DONE 2
+ struct fcoe_ctlr ctlr;
+ u8 vlan_enabled;
+ int vlan_id;
+ u32 next_conn_id;
+ struct fcoe_task_ctx_entry **task_ctx;
+ dma_addr_t *task_ctx_dma;
+ struct regpair *task_ctx_bd_tbl;
+ dma_addr_t task_ctx_bd_dma;
+
+ int hash_tbl_segment_count;
+ void **hash_tbl_segments;
+ void *hash_tbl_pbl;
+ dma_addr_t hash_tbl_pbl_dma;
+ struct fcoe_t2_hash_table_entry *t2_hash_tbl;
+ dma_addr_t t2_hash_tbl_dma;
+ char *t2_hash_tbl_ptr;
+ dma_addr_t t2_hash_tbl_ptr_dma;
+
+ char *dummy_buffer;
+ dma_addr_t dummy_buf_dma;
+
+ struct fcoe_statistics_params *stats_buffer;
+ dma_addr_t stats_buf_dma;
+
+ /*
+ * PCI related info.
+ */
+ u16 pci_did;
+ u16 pci_vid;
+ u16 pci_sdid;
+ u16 pci_svid;
+ u16 pci_func;
+ u16 pci_devno;
+
+ struct task_struct *l2_thread;
+
+ /* linkdown handling */
+ wait_queue_head_t shutdown_wait;
+ int wait_for_link_down;
+
+ /*destroy handling */
+ struct timer_list destroy_timer;
+ wait_queue_head_t destroy_wait;
+
+ /* Active list of offloaded sessions */
+ struct bnx2fc_rport *tgt_ofld_list[BNX2FC_NUM_MAX_SESS];
+ int num_ofld_sess;
+
+ /* statistics */
+ struct completion stat_req_done;
+};
+
+#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr)
+
+struct bnx2fc_cmd_mgr {
+ struct bnx2fc_hba *hba;
+ u16 next_idx;
+ struct list_head *free_list;
+ spinlock_t *free_list_lock;
+ struct io_bdt **io_bdt_pool;
+ struct bnx2fc_cmd **cmds;
+};
+
+struct bnx2fc_rport {
+ struct fcoe_port *port;
+ struct fc_rport *rport;
+ struct fc_rport_priv *rdata;
+ void __iomem *ctx_base;
+#define DPM_TRIGER_TYPE 0x40
+ u32 fcoe_conn_id;
+ u32 context_id;
+ u32 sid;
+
+ unsigned long flags;
+#define BNX2FC_FLAG_SESSION_READY 0x1
+#define BNX2FC_FLAG_OFFLOADED 0x2
+#define BNX2FC_FLAG_DISABLED 0x3
+#define BNX2FC_FLAG_DESTROYED 0x4
+#define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5
+#define BNX2FC_FLAG_DESTROY_CMPL 0x6
+#define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x7
+#define BNX2FC_FLAG_UPLD_REQ_COMPL 0x8
+#define BNX2FC_FLAG_EXPL_LOGO 0x9
+
+ u32 max_sqes;
+ u32 max_rqes;
+ u32 max_cqes;
+
+ struct fcoe_sqe *sq;
+ dma_addr_t sq_dma;
+ u16 sq_prod_idx;
+ u8 sq_curr_toggle_bit;
+ u32 sq_mem_size;
+
+ struct fcoe_cqe *cq;
+ dma_addr_t cq_dma;
+ u32 cq_cons_idx;
+ u8 cq_curr_toggle_bit;
+ u32 cq_mem_size;
+
+ void *rq;
+ dma_addr_t rq_dma;
+ u32 rq_prod_idx;
+ u32 rq_cons_idx;
+ u32 rq_mem_size;
+
+ void *rq_pbl;
+ dma_addr_t rq_pbl_dma;
+ u32 rq_pbl_size;
+
+ struct fcoe_xfrqe *xferq;
+ dma_addr_t xferq_dma;
+ u32 xferq_mem_size;
+
+ struct fcoe_confqe *confq;
+ dma_addr_t confq_dma;
+ u32 confq_mem_size;
+
+ void *confq_pbl;
+ dma_addr_t confq_pbl_dma;
+ u32 confq_pbl_size;
+
+ struct fcoe_conn_db *conn_db;
+ dma_addr_t conn_db_dma;
+ u32 conn_db_mem_size;
+
+ struct fcoe_sqe *lcq;
+ dma_addr_t lcq_dma;
+ u32 lcq_mem_size;
+
+ void *ofld_req[4];
+ dma_addr_t ofld_req_dma[4];
+ void *enbl_req;
+ dma_addr_t enbl_req_dma;
+
+ spinlock_t tgt_lock;
+ spinlock_t cq_lock;
+ atomic_t num_active_ios;
+ u32 flush_in_prog;
+ unsigned long work_time_slice;
+ unsigned long timestamp;
+ struct list_head free_task_list;
+ struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
+ atomic_t pi;
+ atomic_t ci;
+ struct list_head active_cmd_queue;
+ struct list_head els_queue;
+ struct list_head io_retire_queue;
+ struct list_head active_tm_queue;
+
+ struct timer_list ofld_timer;
+ wait_queue_head_t ofld_wait;
+
+ struct timer_list upld_timer;
+ wait_queue_head_t upld_wait;
+};
+
+struct bnx2fc_mp_req {
+ u8 tm_flags;
+
+ u32 req_len;
+ void *req_buf;
+ dma_addr_t req_buf_dma;
+ struct fcoe_bd_ctx *mp_req_bd;
+ dma_addr_t mp_req_bd_dma;
+ struct fc_frame_header req_fc_hdr;
+
+ u32 resp_len;
+ void *resp_buf;
+ dma_addr_t resp_buf_dma;
+ struct fcoe_bd_ctx *mp_resp_bd;
+ dma_addr_t mp_resp_bd_dma;
+ struct fc_frame_header resp_fc_hdr;
+};
+
+struct bnx2fc_els_cb_arg {
+ struct bnx2fc_cmd *aborted_io_req;
+ struct bnx2fc_cmd *io_req;
+ u16 l2_oxid;
+};
+
+/* bnx2fc command structure */
+struct bnx2fc_cmd {
+ struct list_head link;
+ u8 on_active_queue;
+ u8 on_tmf_queue;
+ u8 cmd_type;
+#define BNX2FC_SCSI_CMD 1
+#define BNX2FC_TASK_MGMT_CMD 2
+#define BNX2FC_ABTS 3
+#define BNX2FC_ELS 4
+#define BNX2FC_CLEANUP 5
+ u8 io_req_flags;
+ struct kref refcount;
+ struct fcoe_port *port;
+ struct bnx2fc_rport *tgt;
+ struct scsi_cmnd *sc_cmd;
+ struct bnx2fc_cmd_mgr *cmd_mgr;
+ struct bnx2fc_mp_req mp_req;
+ void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg);
+ struct bnx2fc_els_cb_arg *cb_arg;
+ struct delayed_work timeout_work; /* timer for ULP timeouts */
+ struct completion tm_done;
+ int wait_for_comp;
+ u16 xid;
+ struct fcoe_task_ctx_entry *task;
+ struct io_bdt *bd_tbl;
+ struct fcp_rsp *rsp;
+ size_t data_xfer_len;
+ unsigned long req_flags;
+#define BNX2FC_FLAG_ISSUE_RRQ 0x1
+#define BNX2FC_FLAG_ISSUE_ABTS 0x2
+#define BNX2FC_FLAG_ABTS_DONE 0x3
+#define BNX2FC_FLAG_TM_COMPL 0x4
+#define BNX2FC_FLAG_TM_TIMEOUT 0x5
+#define BNX2FC_FLAG_IO_CLEANUP 0x6
+#define BNX2FC_FLAG_RETIRE_OXID 0x7
+#define BNX2FC_FLAG_EH_ABORT 0x8
+#define BNX2FC_FLAG_IO_COMPL 0x9
+#define BNX2FC_FLAG_ELS_DONE 0xa
+#define BNX2FC_FLAG_ELS_TIMEOUT 0xb
+ u32 fcp_resid;
+ u32 fcp_rsp_len;
+ u32 fcp_sns_len;
+ u8 cdb_status; /* SCSI IO status */
+ u8 fcp_status; /* FCP IO status */
+ u8 fcp_rsp_code;
+ u8 scsi_comp_flags;
+};
+
+struct io_bdt {
+ struct bnx2fc_cmd *io_req;
+ struct fcoe_bd_ctx *bd_tbl;
+ dma_addr_t bd_tbl_dma;
+ u16 bd_valid;
+};
+
+struct bnx2fc_work {
+ struct list_head list;
+ struct bnx2fc_rport *tgt;
+ u16 wqe;
+};
+struct bnx2fc_unsol_els {
+ struct fc_lport *lport;
+ struct fc_frame *fp;
+ struct work_struct unsol_els_work;
+};
+
+
+
+struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type);
+void bnx2fc_cmd_release(struct kref *ref);
+int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd);
+int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba);
+int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba);
+int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt);
+int bnx2fc_send_session_disable_req(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt);
+int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt);
+int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt);
+void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
+ u32 num_cqe);
+int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba);
+void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba);
+int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba);
+void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba);
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
+ u16 min_xid, u16 max_xid);
+void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr);
+void bnx2fc_get_link_state(struct bnx2fc_hba *hba);
+char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items);
+void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items);
+int bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen);
+int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req);
+int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp);
+int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp);
+int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp);
+int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req);
+int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req);
+void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
+ unsigned int timer_msec);
+int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req);
+void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u16 orig_xid);
+void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task);
+void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task);
+void bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid);
+void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt);
+int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd);
+int bnx2fc_eh_host_reset(struct scsi_cmnd *sc_cmd);
+int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd);
+int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd);
+void bnx2fc_rport_event_handler(struct fc_lport *lport,
+ struct fc_rport_priv *rport,
+ enum fc_rport_event event);
+void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq);
+void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq);
+void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq);
+void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq);
+void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq);
+void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
+ struct fcp_cmnd *fcp_cmnd);
+
+
+
+void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt);
+struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
+ struct fc_frame *fp, unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void *arg, u32 timeout);
+int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt);
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe);
+struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
+ u32 port_id);
+void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
+ unsigned char *buf,
+ u32 frame_len, u16 l2_oxid);
+int bnx2fc_send_stat_req(struct bnx2fc_hba *hba);
+
+#endif
diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h
new file mode 100644
index 000000000000..fe7769173c43
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h
@@ -0,0 +1,206 @@
+#ifndef __BNX2FC_CONSTANTS_H_
+#define __BNX2FC_CONSTANTS_H_
+
+/**
+ * This file defines HSI constants for the FCoE flows
+ */
+
+/* KWQ/KCQ FCoE layer code */
+#define FCOE_KWQE_LAYER_CODE (7)
+
+/* KWQ (kernel work queue) request op codes */
+#define FCOE_KWQE_OPCODE_INIT1 (0)
+#define FCOE_KWQE_OPCODE_INIT2 (1)
+#define FCOE_KWQE_OPCODE_INIT3 (2)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1 (3)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2 (4)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3 (5)
+#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4 (6)
+#define FCOE_KWQE_OPCODE_ENABLE_CONN (7)
+#define FCOE_KWQE_OPCODE_DISABLE_CONN (8)
+#define FCOE_KWQE_OPCODE_DESTROY_CONN (9)
+#define FCOE_KWQE_OPCODE_DESTROY (10)
+#define FCOE_KWQE_OPCODE_STAT (11)
+
+/* KCQ (kernel completion queue) response op codes */
+#define FCOE_KCQE_OPCODE_INIT_FUNC (0x10)
+#define FCOE_KCQE_OPCODE_DESTROY_FUNC (0x11)
+#define FCOE_KCQE_OPCODE_STAT_FUNC (0x12)
+#define FCOE_KCQE_OPCODE_OFFLOAD_CONN (0x15)
+#define FCOE_KCQE_OPCODE_ENABLE_CONN (0x16)
+#define FCOE_KCQE_OPCODE_DISABLE_CONN (0x17)
+#define FCOE_KCQE_OPCODE_DESTROY_CONN (0x18)
+#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20)
+#define FCOE_KCQE_OPCODE_FCOE_ERROR (0x21)
+
+/* KCQ (kernel completion queue) completion status */
+#define FCOE_KCQE_COMPLETION_STATUS_SUCCESS (0x0)
+#define FCOE_KCQE_COMPLETION_STATUS_ERROR (0x1)
+#define FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE (0x2)
+#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3)
+#define FCOE_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x4)
+#define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR (0x5)
+
+/* Unsolicited CQE type */
+#define FCOE_UNSOLICITED_FRAME_CQE_TYPE 0
+#define FCOE_ERROR_DETECTION_CQE_TYPE 1
+#define FCOE_WARNING_DETECTION_CQE_TYPE 2
+
+/* Task context constants */
+/* After driver has initialize the task in case timer services required */
+#define FCOE_TASK_TX_STATE_INIT 0
+/* In case timer services are required then shall be updated by Xstorm after
+ * start processing the task. In case no timer facilities are required then the
+ * driver would initialize the state to this value */
+#define FCOE_TASK_TX_STATE_NORMAL 1
+/* Task is under abort procedure. Updated in order to stop processing of
+ * pending WQEs on this task */
+#define FCOE_TASK_TX_STATE_ABORT 2
+/* For E_D_T_TOV timer expiration in Xstorm (Class 2 only) */
+#define FCOE_TASK_TX_STATE_ERROR 3
+/* For REC_TOV timer expiration indication received from Xstorm */
+#define FCOE_TASK_TX_STATE_WARNING 4
+/* For completed unsolicited task */
+#define FCOE_TASK_TX_STATE_UNSOLICITED_COMPLETED 5
+/* For exchange cleanup request task */
+#define FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP 6
+/* For sequence cleanup request task */
+#define FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP 7
+/* Mark task as aborted and indicate that ABTS was not transmitted */
+#define FCOE_TASK_TX_STATE_BEFORE_ABTS_TX 8
+/* Mark task as aborted and indicate that ABTS was transmitted */
+#define FCOE_TASK_TX_STATE_AFTER_ABTS_TX 9
+/* For completion the ABTS task. */
+#define FCOE_TASK_TX_STATE_ABTS_TX_COMPLETED 10
+/* Mark task as aborted and indicate that Exchange cleanup was not transmitted
+ */
+#define FCOE_TASK_TX_STATE_BEFORE_EXCHANGE_CLEANUP_TX 11
+/* Mark task as aborted and indicate that Exchange cleanup was transmitted */
+#define FCOE_TASK_TX_STATE_AFTER_EXCHANGE_CLEANUP_TX 12
+
+#define FCOE_TASK_RX_STATE_NORMAL 0
+#define FCOE_TASK_RX_STATE_COMPLETED 1
+/* Obsolete: Intermediate completion (middle path with local completion) */
+#define FCOE_TASK_RX_STATE_INTER_COMP 2
+/* For REC_TOV timer expiration indication received from Xstorm */
+#define FCOE_TASK_RX_STATE_WARNING 3
+/* For E_D_T_TOV timer expiration in Ustorm */
+#define FCOE_TASK_RX_STATE_ERROR 4
+/* ABTS ACC arrived wait for local completion to finally complete the task. */
+#define FCOE_TASK_RX_STATE_ABTS_ACC_ARRIVED 5
+/* local completion arrived wait for ABTS ACC to finally complete the task. */
+#define FCOE_TASK_RX_STATE_ABTS_LOCAL_COMP_ARRIVED 6
+/* Special completion indication in case of task was aborted. */
+#define FCOE_TASK_RX_STATE_ABTS_COMPLETED 7
+/* Special completion indication in case of task was cleaned. */
+#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED 8
+/* Special completion indication (in task requested the exchange cleanup) in
+ * case cleaned task is in non-valid. */
+#define FCOE_TASK_RX_STATE_ABORT_CLEANUP_COMPLETED 9
+/* Special completion indication (in task requested the sequence cleanup) in
+ * case cleaned task was already returned to normal. */
+#define FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP 10
+/* Exchange cleanup arrived wait until xfer will be handled to finally
+ * complete the task. */
+#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_ARRIVED 11
+/* Xfer handled, wait for exchange cleanup to finally complete the task. */
+#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_HANDLED_XFER 12
+
+#define FCOE_TASK_TYPE_WRITE 0
+#define FCOE_TASK_TYPE_READ 1
+#define FCOE_TASK_TYPE_MIDPATH 2
+#define FCOE_TASK_TYPE_UNSOLICITED 3
+#define FCOE_TASK_TYPE_ABTS 4
+#define FCOE_TASK_TYPE_EXCHANGE_CLEANUP 5
+#define FCOE_TASK_TYPE_SEQUENCE_CLEANUP 6
+
+#define FCOE_TASK_DEV_TYPE_DISK 0
+#define FCOE_TASK_DEV_TYPE_TAPE 1
+
+#define FCOE_TASK_CLASS_TYPE_3 0
+#define FCOE_TASK_CLASS_TYPE_2 1
+
+/* Everest FCoE connection type */
+#define B577XX_FCOE_CONNECTION_TYPE 4
+
+/* Error codes for Error Reporting in fast path flows */
+/* XFER error codes */
+#define FCOE_ERROR_CODE_XFER_OOO_RO 0
+#define FCOE_ERROR_CODE_XFER_RO_NOT_ALIGNED 1
+#define FCOE_ERROR_CODE_XFER_NULL_BURST_LEN 2
+#define FCOE_ERROR_CODE_XFER_RO_GREATER_THAN_DATA2TRNS 3
+#define FCOE_ERROR_CODE_XFER_INVALID_PAYLOAD_SIZE 4
+#define FCOE_ERROR_CODE_XFER_TASK_TYPE_NOT_WRITE 5
+#define FCOE_ERROR_CODE_XFER_PEND_XFER_SET 6
+#define FCOE_ERROR_CODE_XFER_OPENED_SEQ 7
+#define FCOE_ERROR_CODE_XFER_FCTL 8
+
+/* FCP RSP error codes */
+#define FCOE_ERROR_CODE_FCP_RSP_BIDI_FLAGS_SET 9
+#define FCOE_ERROR_CODE_FCP_RSP_UNDERFLOW 10
+#define FCOE_ERROR_CODE_FCP_RSP_OVERFLOW 11
+#define FCOE_ERROR_CODE_FCP_RSP_INVALID_LENGTH_FIELD 12
+#define FCOE_ERROR_CODE_FCP_RSP_INVALID_SNS_FIELD 13
+#define FCOE_ERROR_CODE_FCP_RSP_INVALID_PAYLOAD_SIZE 14
+#define FCOE_ERROR_CODE_FCP_RSP_PEND_XFER_SET 15
+#define FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ 16
+#define FCOE_ERROR_CODE_FCP_RSP_FCTL 17
+#define FCOE_ERROR_CODE_FCP_RSP_LAST_SEQ_RESET 18
+#define FCOE_ERROR_CODE_FCP_RSP_CONF_REQ_NOT_SUPPORTED_YET 19
+
+/* FCP DATA error codes */
+#define FCOE_ERROR_CODE_DATA_OOO_RO 20
+#define FCOE_ERROR_CODE_DATA_EXCEEDS_DEFINED_MAX_FRAME_SIZE 21
+#define FCOE_ERROR_CODE_DATA_EXCEEDS_DATA2TRNS 22
+#define FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET 23
+#define FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET 24
+#define FCOE_ERROR_CODE_DATA_EOFN_END_SEQ_SET 25
+#define FCOE_ERROR_CODE_DATA_EOFT_END_SEQ_RESET 26
+#define FCOE_ERROR_CODE_DATA_TASK_TYPE_NOT_READ 27
+#define FCOE_ERROR_CODE_DATA_FCTL 28
+
+/* Middle path error codes */
+#define FCOE_ERROR_CODE_MIDPATH_TYPE_NOT_ELS 29
+#define FCOE_ERROR_CODE_MIDPATH_SOFI3_SEQ_ACTIVE_SET 30
+#define FCOE_ERROR_CODE_MIDPATH_SOFN_SEQ_ACTIVE_RESET 31
+#define FCOE_ERROR_CODE_MIDPATH_EOFN_END_SEQ_SET 32
+#define FCOE_ERROR_CODE_MIDPATH_EOFT_END_SEQ_RESET 33
+#define FCOE_ERROR_CODE_MIDPATH_ELS_REPLY_FCTL 34
+#define FCOE_ERROR_CODE_MIDPATH_INVALID_REPLY 35
+#define FCOE_ERROR_CODE_MIDPATH_ELS_REPLY_RCTL 36
+
+/* ABTS error codes */
+#define FCOE_ERROR_CODE_ABTS_REPLY_F_CTL 37
+#define FCOE_ERROR_CODE_ABTS_REPLY_DDF_RCTL_FIELD 38
+#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_BLS_RCTL 39
+#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_RCTL 40
+#define FCOE_ERROR_CODE_ABTS_REPLY_RCTL_GENERAL_MISMATCH 41
+
+/* Common error codes */
+#define FCOE_ERROR_CODE_COMMON_MIDDLE_FRAME_WITH_PAD 42
+#define FCOE_ERROR_CODE_COMMON_SEQ_INIT_IN_TCE 43
+#define FCOE_ERROR_CODE_COMMON_FC_HDR_RX_ID_MISMATCH 44
+#define FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT 45
+#define FCOE_ERROR_CODE_COMMON_DATA_FC_HDR_FCP_TYPE_MISMATCH 46
+#define FCOE_ERROR_CODE_COMMON_DATA_NO_MORE_SGES 47
+#define FCOE_ERROR_CODE_COMMON_OPTIONAL_FC_HDR 48
+#define FCOE_ERROR_CODE_COMMON_READ_TCE_OX_ID_TOO_BIG 49
+#define FCOE_ERROR_CODE_COMMON_DATA_WAS_NOT_TRANSMITTED 50
+
+/* Unsolicited Rx error codes */
+#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_ELS 51
+#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_BLS 52
+#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_ELS 53
+#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_BLS 54
+#define FCOE_ERROR_CODE_UNSOLICITED_R_CTL 55
+
+#define FCOE_ERROR_CODE_RW_TASK_DDF_RCTL_INFO_FIELD 56
+#define FCOE_ERROR_CODE_RW_TASK_INVALID_RCTL 57
+#define FCOE_ERROR_CODE_RW_TASK_RCTL_GENERAL_MISMATCH 58
+
+/* Timer error codes */
+#define FCOE_ERROR_CODE_E_D_TOV_TIMER_EXPIRATION 60
+#define FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION 61
+
+
+#endif /* BNX2FC_CONSTANTS_H_ */
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h
new file mode 100644
index 000000000000..7f6aff68cc53
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h
@@ -0,0 +1,70 @@
+#ifndef __BNX2FC_DEBUG__
+#define __BNX2FC_DEBUG__
+
+/* Log level bit mask */
+#define LOG_IO 0x01 /* scsi cmd error, cleanup */
+#define LOG_TGT 0x02 /* Session setup, cleanup, etc' */
+#define LOG_HBA 0x04 /* lport events, link, mtu, etc' */
+#define LOG_ELS 0x08 /* ELS logs */
+#define LOG_MISC 0x10 /* fcoe L2 frame related logs*/
+#define LOG_ALL 0xff /* LOG all messages */
+
+extern unsigned int bnx2fc_debug_level;
+
+#define BNX2FC_CHK_LOGGING(LEVEL, CMD) \
+ do { \
+ if (unlikely(bnx2fc_debug_level & LEVEL)) \
+ do { \
+ CMD; \
+ } while (0); \
+ } while (0)
+
+#define BNX2FC_ELS_DBG(fmt, arg...) \
+ BNX2FC_CHK_LOGGING(LOG_ELS, \
+ printk(KERN_ALERT PFX fmt, ##arg))
+
+#define BNX2FC_MISC_DBG(fmt, arg...) \
+ BNX2FC_CHK_LOGGING(LOG_MISC, \
+ printk(KERN_ALERT PFX fmt, ##arg))
+
+#define BNX2FC_IO_DBG(io_req, fmt, arg...) \
+ do { \
+ if (!io_req || !io_req->port || !io_req->port->lport || \
+ !io_req->port->lport->host) \
+ BNX2FC_CHK_LOGGING(LOG_IO, \
+ printk(KERN_ALERT PFX "NULL " fmt, ##arg)); \
+ else \
+ BNX2FC_CHK_LOGGING(LOG_IO, \
+ shost_printk(KERN_ALERT, \
+ (io_req)->port->lport->host, \
+ PFX "xid:0x%x " fmt, \
+ (io_req)->xid, ##arg)); \
+ } while (0)
+
+#define BNX2FC_TGT_DBG(tgt, fmt, arg...) \
+ do { \
+ if (!tgt || !tgt->port || !tgt->port->lport || \
+ !tgt->port->lport->host || !tgt->rport) \
+ BNX2FC_CHK_LOGGING(LOG_TGT, \
+ printk(KERN_ALERT PFX "NULL " fmt, ##arg)); \
+ else \
+ BNX2FC_CHK_LOGGING(LOG_TGT, \
+ shost_printk(KERN_ALERT, \
+ (tgt)->port->lport->host, \
+ PFX "port:%x " fmt, \
+ (tgt)->rport->port_id, ##arg)); \
+ } while (0)
+
+
+#define BNX2FC_HBA_DBG(lport, fmt, arg...) \
+ do { \
+ if (!lport || !lport->host) \
+ BNX2FC_CHK_LOGGING(LOG_HBA, \
+ printk(KERN_ALERT PFX "NULL " fmt, ##arg)); \
+ else \
+ BNX2FC_CHK_LOGGING(LOG_HBA, \
+ shost_printk(KERN_ALERT, lport->host, \
+ PFX fmt, ##arg)); \
+ } while (0)
+
+#endif
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
new file mode 100644
index 000000000000..7a11a255157f
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -0,0 +1,515 @@
+/*
+ * bnx2fc_els.c: Broadcom NetXtreme II Linux FCoE offload driver.
+ * This file contains helper routines that handle ELS requests
+ * and responses.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include "bnx2fc.h"
+
+static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
+ void *arg);
+static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
+ void *arg);
+static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
+ void *data, u32 data_len,
+ void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
+ struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec);
+
+static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+ struct bnx2fc_cmd *orig_io_req;
+ struct bnx2fc_cmd *rrq_req;
+ int rc = 0;
+
+ BUG_ON(!cb_arg);
+ rrq_req = cb_arg->io_req;
+ orig_io_req = cb_arg->aborted_io_req;
+ BUG_ON(!orig_io_req);
+ BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n",
+ orig_io_req->xid, rrq_req->xid);
+
+ kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+
+ if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) {
+ /*
+ * els req is timed out. cleanup the IO with FW and
+ * drop the completion. Remove from active_cmd_queue.
+ */
+ BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n",
+ rrq_req->xid);
+
+ if (rrq_req->on_active_queue) {
+ list_del_init(&rrq_req->link);
+ rrq_req->on_active_queue = 0;
+ rc = bnx2fc_initiate_cleanup(rrq_req);
+ BUG_ON(rc);
+ }
+ }
+ kfree(cb_arg);
+}
+int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req)
+{
+
+ struct fc_els_rrq rrq;
+ struct bnx2fc_rport *tgt = aborted_io_req->tgt;
+ struct fc_lport *lport = tgt->rdata->local_port;
+ struct bnx2fc_els_cb_arg *cb_arg = NULL;
+ u32 sid = tgt->sid;
+ u32 r_a_tov = lport->r_a_tov;
+ unsigned long start = jiffies;
+ int rc;
+
+ BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n",
+ aborted_io_req->xid);
+ memset(&rrq, 0, sizeof(rrq));
+
+ cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO);
+ if (!cb_arg) {
+ printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n");
+ rc = -ENOMEM;
+ goto rrq_err;
+ }
+
+ cb_arg->aborted_io_req = aborted_io_req;
+
+ rrq.rrq_cmd = ELS_RRQ;
+ hton24(rrq.rrq_s_id, sid);
+ rrq.rrq_ox_id = htons(aborted_io_req->xid);
+ rrq.rrq_rx_id = htons(aborted_io_req->task->rx_wr_tx_rd.rx_id);
+
+retry_rrq:
+ rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq),
+ bnx2fc_rrq_compl, cb_arg,
+ r_a_tov);
+ if (rc == -ENOMEM) {
+ if (time_after(jiffies, start + (10 * HZ))) {
+ BNX2FC_ELS_DBG("rrq Failed\n");
+ rc = FAILED;
+ goto rrq_err;
+ }
+ msleep(20);
+ goto retry_rrq;
+ }
+rrq_err:
+ if (rc) {
+ BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n",
+ aborted_io_req->xid);
+ kfree(cb_arg);
+ spin_lock_bh(&tgt->tgt_lock);
+ kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ }
+ return rc;
+}
+
+static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+ struct bnx2fc_cmd *els_req;
+ struct bnx2fc_rport *tgt;
+ struct bnx2fc_mp_req *mp_req;
+ struct fc_frame_header *fc_hdr;
+ unsigned char *buf;
+ void *resp_buf;
+ u32 resp_len, hdr_len;
+ u16 l2_oxid;
+ int frame_len;
+ int rc = 0;
+
+ l2_oxid = cb_arg->l2_oxid;
+ BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid);
+
+ els_req = cb_arg->io_req;
+ if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) {
+ /*
+ * els req is timed out. cleanup the IO with FW and
+ * drop the completion. libfc will handle the els timeout
+ */
+ if (els_req->on_active_queue) {
+ list_del_init(&els_req->link);
+ els_req->on_active_queue = 0;
+ rc = bnx2fc_initiate_cleanup(els_req);
+ BUG_ON(rc);
+ }
+ goto free_arg;
+ }
+
+ tgt = els_req->tgt;
+ mp_req = &(els_req->mp_req);
+ fc_hdr = &(mp_req->resp_fc_hdr);
+ resp_len = mp_req->resp_len;
+ resp_buf = mp_req->resp_buf;
+
+ buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+ if (!buf) {
+ printk(KERN_ERR PFX "Unable to alloc mp buf\n");
+ goto free_arg;
+ }
+ hdr_len = sizeof(*fc_hdr);
+ if (hdr_len + resp_len > PAGE_SIZE) {
+ printk(KERN_ERR PFX "l2_els_compl: resp len is "
+ "beyond page size\n");
+ goto free_buf;
+ }
+ memcpy(buf, fc_hdr, hdr_len);
+ memcpy(buf + hdr_len, resp_buf, resp_len);
+ frame_len = hdr_len + resp_len;
+
+ bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid);
+
+free_buf:
+ kfree(buf);
+free_arg:
+ kfree(cb_arg);
+}
+
+int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp)
+{
+ struct fc_els_adisc *adisc;
+ struct fc_frame_header *fh;
+ struct bnx2fc_els_cb_arg *cb_arg;
+ struct fc_lport *lport = tgt->rdata->local_port;
+ u32 r_a_tov = lport->r_a_tov;
+ int rc;
+
+ fh = fc_frame_header_get(fp);
+ cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+ if (!cb_arg) {
+ printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n");
+ return -ENOMEM;
+ }
+
+ cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
+
+ BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
+ adisc = fc_frame_payload_get(fp, sizeof(*adisc));
+ /* adisc is initialized by libfc */
+ rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc),
+ bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
+ if (rc)
+ kfree(cb_arg);
+ return rc;
+}
+
+int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp)
+{
+ struct fc_els_logo *logo;
+ struct fc_frame_header *fh;
+ struct bnx2fc_els_cb_arg *cb_arg;
+ struct fc_lport *lport = tgt->rdata->local_port;
+ u32 r_a_tov = lport->r_a_tov;
+ int rc;
+
+ fh = fc_frame_header_get(fp);
+ cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+ if (!cb_arg) {
+ printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
+ return -ENOMEM;
+ }
+
+ cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
+
+ BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid);
+ logo = fc_frame_payload_get(fp, sizeof(*logo));
+ /* logo is initialized by libfc */
+ rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo),
+ bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
+ if (rc)
+ kfree(cb_arg);
+ return rc;
+}
+
+int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
+{
+ struct fc_els_rls *rls;
+ struct fc_frame_header *fh;
+ struct bnx2fc_els_cb_arg *cb_arg;
+ struct fc_lport *lport = tgt->rdata->local_port;
+ u32 r_a_tov = lport->r_a_tov;
+ int rc;
+
+ fh = fc_frame_header_get(fp);
+ cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+ if (!cb_arg) {
+ printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n");
+ return -ENOMEM;
+ }
+
+ cb_arg->l2_oxid = ntohs(fh->fh_ox_id);
+
+ rls = fc_frame_payload_get(fp, sizeof(*rls));
+ /* rls is initialized by libfc */
+ rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls),
+ bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov);
+ if (rc)
+ kfree(cb_arg);
+ return rc;
+}
+
+static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
+ void *data, u32 data_len,
+ void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
+ struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec)
+{
+ struct fcoe_port *port = tgt->port;
+ struct bnx2fc_hba *hba = port->priv;
+ struct fc_rport *rport = tgt->rport;
+ struct fc_lport *lport = port->lport;
+ struct bnx2fc_cmd *els_req;
+ struct bnx2fc_mp_req *mp_req;
+ struct fc_frame_header *fc_hdr;
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ int rc = 0;
+ int task_idx, index;
+ u32 did, sid;
+ u16 xid;
+
+ rc = fc_remote_port_chkready(rport);
+ if (rc) {
+ printk(KERN_ALERT PFX "els 0x%x: rport not ready\n", op);
+ rc = -EINVAL;
+ goto els_err;
+ }
+ if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
+ printk(KERN_ALERT PFX "els 0x%x: link is not ready\n", op);
+ rc = -EINVAL;
+ goto els_err;
+ }
+ if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) ||
+ (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) {
+ printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op);
+ rc = -EINVAL;
+ goto els_err;
+ }
+ els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS);
+ if (!els_req) {
+ rc = -ENOMEM;
+ goto els_err;
+ }
+
+ els_req->sc_cmd = NULL;
+ els_req->port = port;
+ els_req->tgt = tgt;
+ els_req->cb_func = cb_func;
+ cb_arg->io_req = els_req;
+ els_req->cb_arg = cb_arg;
+
+ mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
+ rc = bnx2fc_init_mp_req(els_req);
+ if (rc == FAILED) {
+ printk(KERN_ALERT PFX "ELS MP request init failed\n");
+ spin_lock_bh(&tgt->tgt_lock);
+ kref_put(&els_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ rc = -ENOMEM;
+ goto els_err;
+ } else {
+ /* rc SUCCESS */
+ rc = 0;
+ }
+
+ /* Set the data_xfer_len to the size of ELS payload */
+ mp_req->req_len = data_len;
+ els_req->data_xfer_len = mp_req->req_len;
+
+ /* Fill ELS Payload */
+ if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) {
+ memcpy(mp_req->req_buf, data, data_len);
+ } else {
+ printk(KERN_ALERT PFX "Invalid ELS op 0x%x\n", op);
+ els_req->cb_func = NULL;
+ els_req->cb_arg = NULL;
+ spin_lock_bh(&tgt->tgt_lock);
+ kref_put(&els_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ rc = -EINVAL;
+ }
+
+ if (rc)
+ goto els_err;
+
+ /* Fill FC header */
+ fc_hdr = &(mp_req->req_fc_hdr);
+
+ did = tgt->rport->port_id;
+ sid = tgt->sid;
+
+ __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
+ FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ |
+ FC_FC_SEQ_INIT, 0);
+
+ /* Obtain exchange id */
+ xid = els_req->xid;
+ task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+
+ /* Initialize task context for this IO request */
+ task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+ bnx2fc_init_mp_task(els_req, task);
+
+ spin_lock_bh(&tgt->tgt_lock);
+
+ if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
+ printk(KERN_ERR PFX "initiate_els.. session not ready\n");
+ els_req->cb_func = NULL;
+ els_req->cb_arg = NULL;
+ kref_put(&els_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return -EINVAL;
+ }
+
+ if (timer_msec)
+ bnx2fc_cmd_timer_set(els_req, timer_msec);
+ bnx2fc_add_2_sq(tgt, xid);
+
+ els_req->on_active_queue = 1;
+ list_add_tail(&els_req->link, &tgt->els_queue);
+
+ /* Ring doorbell */
+ bnx2fc_ring_doorbell(tgt);
+ spin_unlock_bh(&tgt->tgt_lock);
+
+els_err:
+ return rc;
+}
+
+void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
+ struct fcoe_task_ctx_entry *task, u8 num_rq)
+{
+ struct bnx2fc_mp_req *mp_req;
+ struct fc_frame_header *fc_hdr;
+ u64 *hdr;
+ u64 *temp_hdr;
+
+ BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x"
+ "cmd_type = %d\n", els_req->xid, els_req->cmd_type);
+
+ if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE,
+ &els_req->req_flags)) {
+ BNX2FC_ELS_DBG("Timer context finished processing this "
+ "els - 0x%x\n", els_req->xid);
+ /* This IO doesnt receive cleanup completion */
+ kref_put(&els_req->refcount, bnx2fc_cmd_release);
+ return;
+ }
+
+ /* Cancel the timeout_work, as we received the response */
+ if (cancel_delayed_work(&els_req->timeout_work))
+ kref_put(&els_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+
+ if (els_req->on_active_queue) {
+ list_del_init(&els_req->link);
+ els_req->on_active_queue = 0;
+ }
+
+ mp_req = &(els_req->mp_req);
+ fc_hdr = &(mp_req->resp_fc_hdr);
+
+ hdr = (u64 *)fc_hdr;
+ temp_hdr = (u64 *)
+ &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr;
+ hdr[0] = cpu_to_be64(temp_hdr[0]);
+ hdr[1] = cpu_to_be64(temp_hdr[1]);
+ hdr[2] = cpu_to_be64(temp_hdr[2]);
+
+ mp_req->resp_len = task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_off;
+
+ /* Parse ELS response */
+ if ((els_req->cb_func) && (els_req->cb_arg)) {
+ els_req->cb_func(els_req->cb_arg);
+ els_req->cb_arg = NULL;
+ }
+
+ kref_put(&els_req->refcount, bnx2fc_cmd_release);
+}
+
+static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
+ void *arg)
+{
+ struct fcoe_ctlr *fip = arg;
+ struct fc_exch *exch = fc_seq_exch(seq);
+ struct fc_lport *lport = exch->lp;
+ u8 *mac;
+ struct fc_frame_header *fh;
+ u8 op;
+
+ if (IS_ERR(fp))
+ goto done;
+
+ mac = fr_cb(fp)->granted_mac;
+ if (is_zero_ether_addr(mac)) {
+ fh = fc_frame_header_get(fp);
+ if (fh->fh_type != FC_TYPE_ELS) {
+ printk(KERN_ERR PFX "bnx2fc_flogi_resp:"
+ "fh_type != FC_TYPE_ELS\n");
+ fc_frame_free(fp);
+ return;
+ }
+ op = fc_frame_payload_op(fp);
+ if (lport->vport) {
+ if (op == ELS_LS_RJT) {
+ printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n");
+ fc_vport_terminate(lport->vport);
+ fc_frame_free(fp);
+ return;
+ }
+ }
+ if (fcoe_ctlr_recv_flogi(fip, lport, fp)) {
+ fc_frame_free(fp);
+ return;
+ }
+ }
+ fip->update_mac(lport, mac);
+done:
+ fc_lport_flogi_resp(seq, fp, lport);
+}
+
+static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp,
+ void *arg)
+{
+ struct fcoe_ctlr *fip = arg;
+ struct fc_exch *exch = fc_seq_exch(seq);
+ struct fc_lport *lport = exch->lp;
+ static u8 zero_mac[ETH_ALEN] = { 0 };
+
+ if (!IS_ERR(fp))
+ fip->update_mac(lport, zero_mac);
+ fc_lport_logo_resp(seq, fp, lport);
+}
+
+struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
+ struct fc_frame *fp, unsigned int op,
+ void (*resp)(struct fc_seq *,
+ struct fc_frame *,
+ void *),
+ void *arg, u32 timeout)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct fcoe_ctlr *fip = &hba->ctlr;
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
+
+ switch (op) {
+ case ELS_FLOGI:
+ case ELS_FDISC:
+ return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp,
+ fip, timeout);
+ case ELS_LOGO:
+ /* only hook onto fabric logouts, not port logouts */
+ if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI)
+ break;
+ return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp,
+ fip, timeout);
+ }
+ return fc_elsct_send(lport, did, fp, op, resp, arg, timeout);
+}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
new file mode 100644
index 000000000000..e476e8753079
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -0,0 +1,2535 @@
+/* bnx2fc_fcoe.c: Broadcom NetXtreme II Linux FCoE offload driver.
+ * This file contains the code that interacts with libfc, libfcoe,
+ * cnic modules to create FCoE instances, send/receive non-offloaded
+ * FIP/FCoE packets, listen to link events etc.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include "bnx2fc.h"
+
+static struct list_head adapter_list;
+static u32 adapter_count;
+static DEFINE_MUTEX(bnx2fc_dev_lock);
+DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
+
+#define DRV_MODULE_NAME "bnx2fc"
+#define DRV_MODULE_VERSION BNX2FC_VERSION
+#define DRV_MODULE_RELDATE "Jan 25, 2011"
+
+
+static char version[] __devinitdata =
+ "Broadcom NetXtreme II FCoE Driver " DRV_MODULE_NAME \
+ " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+
+MODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 FCoE Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#define BNX2FC_MAX_QUEUE_DEPTH 256
+#define BNX2FC_MIN_QUEUE_DEPTH 32
+#define FCOE_WORD_TO_BYTE 4
+
+static struct scsi_transport_template *bnx2fc_transport_template;
+static struct scsi_transport_template *bnx2fc_vport_xport_template;
+
+struct workqueue_struct *bnx2fc_wq;
+
+/* bnx2fc structure needs only one instance of the fcoe_percpu_s structure.
+ * Here the io threads are per cpu but the l2 thread is just one
+ */
+struct fcoe_percpu_s bnx2fc_global;
+DEFINE_SPINLOCK(bnx2fc_global_lock);
+
+static struct cnic_ulp_ops bnx2fc_cnic_cb;
+static struct libfc_function_template bnx2fc_libfc_fcn_templ;
+static struct scsi_host_template bnx2fc_shost_template;
+static struct fc_function_template bnx2fc_transport_function;
+static struct fc_function_template bnx2fc_vport_xport_function;
+static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode);
+static int bnx2fc_destroy(struct net_device *net_device);
+static int bnx2fc_enable(struct net_device *netdev);
+static int bnx2fc_disable(struct net_device *netdev);
+
+static void bnx2fc_recv_frame(struct sk_buff *skb);
+
+static void bnx2fc_start_disc(struct bnx2fc_hba *hba);
+static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev);
+static int bnx2fc_net_config(struct fc_lport *lp);
+static int bnx2fc_lport_config(struct fc_lport *lport);
+static int bnx2fc_em_config(struct fc_lport *lport);
+static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba);
+static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba);
+static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
+static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba);
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+ struct device *parent, int npiv);
+static void bnx2fc_destroy_work(struct work_struct *work);
+
+static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev);
+static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic);
+
+static int bnx2fc_fw_init(struct bnx2fc_hba *hba);
+static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba);
+
+static void bnx2fc_port_shutdown(struct fc_lport *lport);
+static void bnx2fc_stop(struct bnx2fc_hba *hba);
+static int __init bnx2fc_mod_init(void);
+static void __exit bnx2fc_mod_exit(void);
+
+unsigned int bnx2fc_debug_level;
+module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR);
+
+static int bnx2fc_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu);
+/* notification function for CPU hotplug events */
+static struct notifier_block bnx2fc_cpu_notifier = {
+ .notifier_call = bnx2fc_cpu_callback,
+};
+
+static void bnx2fc_clean_rx_queue(struct fc_lport *lp)
+{
+ struct fcoe_percpu_s *bg;
+ struct fcoe_rcv_info *fr;
+ struct sk_buff_head *list;
+ struct sk_buff *skb, *next;
+ struct sk_buff *head;
+
+ bg = &bnx2fc_global;
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+ list = &bg->fcoe_rx_list;
+ head = list->next;
+ for (skb = head; skb != (struct sk_buff *)list;
+ skb = next) {
+ next = skb->next;
+ fr = fcoe_dev_from_skb(skb);
+ if (fr->fr_dev == lp) {
+ __skb_unlink(skb, list);
+ kfree_skb(skb);
+ }
+ }
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+}
+
+int bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen)
+{
+ int rc;
+ spin_lock(&bnx2fc_global_lock);
+ rc = fcoe_get_paged_crc_eof(skb, tlen, &bnx2fc_global);
+ spin_unlock(&bnx2fc_global_lock);
+
+ return rc;
+}
+
+static void bnx2fc_abort_io(struct fc_lport *lport)
+{
+ /*
+ * This function is no-op for bnx2fc, but we do
+ * not want to leave it as NULL either, as libfc
+ * can call the default function which is
+ * fc_fcp_abort_io.
+ */
+}
+
+static void bnx2fc_cleanup(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_rport *tgt;
+ int i;
+
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ mutex_lock(&hba->hba_mutex);
+ spin_lock_bh(&hba->hba_lock);
+ for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) {
+ tgt = hba->tgt_ofld_list[i];
+ if (tgt) {
+ /* Cleanup IOs belonging to requested vport */
+ if (tgt->port == port) {
+ spin_unlock_bh(&hba->hba_lock);
+ BNX2FC_TGT_DBG(tgt, "flush/cleanup\n");
+ bnx2fc_flush_active_ios(tgt);
+ spin_lock_bh(&hba->hba_lock);
+ }
+ }
+ }
+ spin_unlock_bh(&hba->hba_lock);
+ mutex_unlock(&hba->hba_mutex);
+}
+
+static int bnx2fc_xmit_l2_frame(struct bnx2fc_rport *tgt,
+ struct fc_frame *fp)
+{
+ struct fc_rport_priv *rdata = tgt->rdata;
+ struct fc_frame_header *fh;
+ int rc = 0;
+
+ fh = fc_frame_header_get(fp);
+ BNX2FC_TGT_DBG(tgt, "Xmit L2 frame rport = 0x%x, oxid = 0x%x, "
+ "r_ctl = 0x%x\n", rdata->ids.port_id,
+ ntohs(fh->fh_ox_id), fh->fh_r_ctl);
+ if ((fh->fh_type == FC_TYPE_ELS) &&
+ (fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
+
+ switch (fc_frame_payload_op(fp)) {
+ case ELS_ADISC:
+ rc = bnx2fc_send_adisc(tgt, fp);
+ break;
+ case ELS_LOGO:
+ rc = bnx2fc_send_logo(tgt, fp);
+ break;
+ case ELS_RLS:
+ rc = bnx2fc_send_rls(tgt, fp);
+ break;
+ default:
+ break;
+ }
+ } else if ((fh->fh_type == FC_TYPE_BLS) &&
+ (fh->fh_r_ctl == FC_RCTL_BA_ABTS))
+ BNX2FC_TGT_DBG(tgt, "ABTS frame\n");
+ else {
+ BNX2FC_TGT_DBG(tgt, "Send L2 frame type 0x%x "
+ "rctl 0x%x thru non-offload path\n",
+ fh->fh_type, fh->fh_r_ctl);
+ return -ENODEV;
+ }
+ if (rc)
+ return -ENOMEM;
+ else
+ return 0;
+}
+
+/**
+ * bnx2fc_xmit - bnx2fc's FCoE frame transmit function
+ *
+ * @lport: the associated local port
+ * @fp: the fc_frame to be transmitted
+ */
+static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
+{
+ struct ethhdr *eh;
+ struct fcoe_crc_eof *cp;
+ struct sk_buff *skb;
+ struct fc_frame_header *fh;
+ struct bnx2fc_hba *hba;
+ struct fcoe_port *port;
+ struct fcoe_hdr *hp;
+ struct bnx2fc_rport *tgt;
+ struct fcoe_dev_stats *stats;
+ u8 sof, eof;
+ u32 crc;
+ unsigned int hlen, tlen, elen;
+ int wlen, rc = 0;
+
+ port = (struct fcoe_port *)lport_priv(lport);
+ hba = port->priv;
+
+ fh = fc_frame_header_get(fp);
+
+ skb = fp_skb(fp);
+ if (!lport->link_up) {
+ BNX2FC_HBA_DBG(lport, "bnx2fc_xmit link down\n");
+ kfree_skb(skb);
+ return 0;
+ }
+
+ if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
+ if (!hba->ctlr.sel_fcf) {
+ BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n");
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ if (fcoe_ctlr_els_send(&hba->ctlr, lport, skb))
+ return 0;
+ }
+
+ sof = fr_sof(fp);
+ eof = fr_eof(fp);
+
+ /*
+ * Snoop the frame header to check if the frame is for
+ * an offloaded session
+ */
+ /*
+ * tgt_ofld_list access is synchronized using
+ * both hba mutex and hba lock. Atleast hba mutex or
+ * hba lock needs to be held for read access.
+ */
+
+ spin_lock_bh(&hba->hba_lock);
+ tgt = bnx2fc_tgt_lookup(port, ntoh24(fh->fh_d_id));
+ if (tgt && (test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) {
+ /* This frame is for offloaded session */
+ BNX2FC_HBA_DBG(lport, "xmit: Frame is for offloaded session "
+ "port_id = 0x%x\n", ntoh24(fh->fh_d_id));
+ spin_unlock_bh(&hba->hba_lock);
+ rc = bnx2fc_xmit_l2_frame(tgt, fp);
+ if (rc != -ENODEV) {
+ kfree_skb(skb);
+ return rc;
+ }
+ } else {
+ spin_unlock_bh(&hba->hba_lock);
+ }
+
+ elen = sizeof(struct ethhdr);
+ hlen = sizeof(struct fcoe_hdr);
+ tlen = sizeof(struct fcoe_crc_eof);
+ wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
+
+ skb->ip_summed = CHECKSUM_NONE;
+ crc = fcoe_fc_crc(fp);
+
+ /* copy port crc and eof to the skb buff */
+ if (skb_is_nonlinear(skb)) {
+ skb_frag_t *frag;
+ if (bnx2fc_get_paged_crc_eof(skb, tlen)) {
+ kfree_skb(skb);
+ return -ENOMEM;
+ }
+ frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
+ cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ)
+ + frag->page_offset;
+ } else {
+ cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
+ }
+
+ memset(cp, 0, sizeof(*cp));
+ cp->fcoe_eof = eof;
+ cp->fcoe_crc32 = cpu_to_le32(~crc);
+ if (skb_is_nonlinear(skb)) {
+ kunmap_atomic(cp, KM_SKB_DATA_SOFTIRQ);
+ cp = NULL;
+ }
+
+ /* adjust skb network/transport offsets to match mac/fcoe/port */
+ skb_push(skb, elen + hlen);
+ skb_reset_mac_header(skb);
+ skb_reset_network_header(skb);
+ skb->mac_len = elen;
+ skb->protocol = htons(ETH_P_FCOE);
+ skb->dev = hba->netdev;
+
+ /* fill up mac and fcoe headers */
+ eh = eth_hdr(skb);
+ eh->h_proto = htons(ETH_P_FCOE);
+ if (hba->ctlr.map_dest)
+ fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
+ else
+ /* insert GW address */
+ memcpy(eh->h_dest, hba->ctlr.dest_addr, ETH_ALEN);
+
+ if (unlikely(hba->ctlr.flogi_oxid != FC_XID_UNKNOWN))
+ memcpy(eh->h_source, hba->ctlr.ctl_src_addr, ETH_ALEN);
+ else
+ memcpy(eh->h_source, port->data_src_addr, ETH_ALEN);
+
+ hp = (struct fcoe_hdr *)(eh + 1);
+ memset(hp, 0, sizeof(*hp));
+ if (FC_FCOE_VER)
+ FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
+ hp->fcoe_sof = sof;
+
+ /* fcoe lso, mss is in max_payload which is non-zero for FCP data */
+ if (lport->seq_offload && fr_max_payload(fp)) {
+ skb_shinfo(skb)->gso_type = SKB_GSO_FCOE;
+ skb_shinfo(skb)->gso_size = fr_max_payload(fp);
+ } else {
+ skb_shinfo(skb)->gso_type = 0;
+ skb_shinfo(skb)->gso_size = 0;
+ }
+
+ /*update tx stats */
+ stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+ stats->TxFrames++;
+ stats->TxWords += wlen;
+ put_cpu();
+
+ /* send down to lld */
+ fr_dev(fp) = lport;
+ if (port->fcoe_pending_queue.qlen)
+ fcoe_check_wait_queue(lport, skb);
+ else if (fcoe_start_io(skb))
+ fcoe_check_wait_queue(lport, skb);
+
+ return 0;
+}
+
+/**
+ * bnx2fc_rcv - This is bnx2fc's receive function called by NET_RX_SOFTIRQ
+ *
+ * @skb: the receive socket buffer
+ * @dev: associated net device
+ * @ptype: context
+ * @olddev: last device
+ *
+ * This function receives the packet and builds FC frame and passes it up
+ */
+static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype, struct net_device *olddev)
+{
+ struct fc_lport *lport;
+ struct bnx2fc_hba *hba;
+ struct fc_frame_header *fh;
+ struct fcoe_rcv_info *fr;
+ struct fcoe_percpu_s *bg;
+ unsigned short oxid;
+
+ hba = container_of(ptype, struct bnx2fc_hba, fcoe_packet_type);
+ lport = hba->ctlr.lp;
+
+ if (unlikely(lport == NULL)) {
+ printk(KERN_ALERT PFX "bnx2fc_rcv: lport is NULL\n");
+ goto err;
+ }
+
+ if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
+ printk(KERN_ALERT PFX "bnx2fc_rcv: Wrong FC type frame\n");
+ goto err;
+ }
+
+ /*
+ * Check for minimum frame length, and make sure required FCoE
+ * and FC headers are pulled into the linear data area.
+ */
+ if (unlikely((skb->len < FCOE_MIN_FRAME) ||
+ !pskb_may_pull(skb, FCOE_HEADER_LEN)))
+ goto err;
+
+ skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
+
+ oxid = ntohs(fh->fh_ox_id);
+
+ fr = fcoe_dev_from_skb(skb);
+ fr->fr_dev = lport;
+ fr->ptype = ptype;
+
+ bg = &bnx2fc_global;
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+
+ __skb_queue_tail(&bg->fcoe_rx_list, skb);
+ if (bg->fcoe_rx_list.qlen == 1)
+ wake_up_process(bg->thread);
+
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+
+ return 0;
+err:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int bnx2fc_l2_rcv_thread(void *arg)
+{
+ struct fcoe_percpu_s *bg = arg;
+ struct sk_buff *skb;
+
+ set_user_nice(current, -20);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ schedule();
+ set_current_state(TASK_RUNNING);
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+ while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) {
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+ bnx2fc_recv_frame(skb);
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+ }
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+
+static void bnx2fc_recv_frame(struct sk_buff *skb)
+{
+ u32 fr_len;
+ struct fc_lport *lport;
+ struct fcoe_rcv_info *fr;
+ struct fcoe_dev_stats *stats;
+ struct fc_frame_header *fh;
+ struct fcoe_crc_eof crc_eof;
+ struct fc_frame *fp;
+ struct fc_lport *vn_port;
+ struct fcoe_port *port;
+ u8 *mac = NULL;
+ u8 *dest_mac = NULL;
+ struct fcoe_hdr *hp;
+
+ fr = fcoe_dev_from_skb(skb);
+ lport = fr->fr_dev;
+ if (unlikely(lport == NULL)) {
+ printk(KERN_ALERT PFX "Invalid lport struct\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (skb_is_nonlinear(skb))
+ skb_linearize(skb);
+ mac = eth_hdr(skb)->h_source;
+ dest_mac = eth_hdr(skb)->h_dest;
+
+ /* Pull the header */
+ hp = (struct fcoe_hdr *) skb_network_header(skb);
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
+ skb_pull(skb, sizeof(struct fcoe_hdr));
+ fr_len = skb->len - sizeof(struct fcoe_crc_eof);
+
+ stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+ stats->RxFrames++;
+ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+
+ fp = (struct fc_frame *)skb;
+ fc_frame_init(fp);
+ fr_dev(fp) = lport;
+ fr_sof(fp) = hp->fcoe_sof;
+ if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+ fr_eof(fp) = crc_eof.fcoe_eof;
+ fr_crc(fp) = crc_eof.fcoe_crc32;
+ if (pskb_trim(skb, fr_len)) {
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+
+ fh = fc_frame_header_get(fp);
+
+ vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id));
+ if (vn_port) {
+ port = lport_priv(vn_port);
+ if (compare_ether_addr(port->data_src_addr, dest_mac)
+ != 0) {
+ BNX2FC_HBA_DBG(lport, "fpma mismatch\n");
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+ }
+ if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
+ fh->fh_type == FC_TYPE_FCP) {
+ /* Drop FCP data. We dont this in L2 path */
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+ if (fh->fh_r_ctl == FC_RCTL_ELS_REQ &&
+ fh->fh_type == FC_TYPE_ELS) {
+ switch (fc_frame_payload_op(fp)) {
+ case ELS_LOGO:
+ if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) {
+ /* drop non-FIP LOGO */
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+ break;
+ }
+ }
+ if (le32_to_cpu(fr_crc(fp)) !=
+ ~crc32(~0, skb->data, fr_len)) {
+ if (stats->InvalidCRCCount < 5)
+ printk(KERN_WARNING PFX "dropping frame with "
+ "CRC error\n");
+ stats->InvalidCRCCount++;
+ put_cpu();
+ kfree_skb(skb);
+ return;
+ }
+ put_cpu();
+ fc_exch_recv(lport, fp);
+}
+
+/**
+ * bnx2fc_percpu_io_thread - thread per cpu for ios
+ *
+ * @arg: ptr to bnx2fc_percpu_info structure
+ */
+int bnx2fc_percpu_io_thread(void *arg)
+{
+ struct bnx2fc_percpu_s *p = arg;
+ struct bnx2fc_work *work, *tmp;
+ LIST_HEAD(work_list);
+
+ set_user_nice(current, -20);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ schedule();
+ set_current_state(TASK_RUNNING);
+ spin_lock_bh(&p->fp_work_lock);
+ while (!list_empty(&p->work_list)) {
+ list_splice_init(&p->work_list, &work_list);
+ spin_unlock_bh(&p->fp_work_lock);
+
+ list_for_each_entry_safe(work, tmp, &work_list, list) {
+ list_del_init(&work->list);
+ bnx2fc_process_cq_compl(work->tgt, work->wqe);
+ kfree(work);
+ }
+
+ spin_lock_bh(&p->fp_work_lock);
+ }
+ spin_unlock_bh(&p->fp_work_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost)
+{
+ struct fc_host_statistics *bnx2fc_stats;
+ struct fc_lport *lport = shost_priv(shost);
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct fcoe_statistics_params *fw_stats;
+ int rc = 0;
+
+ fw_stats = (struct fcoe_statistics_params *)hba->stats_buffer;
+ if (!fw_stats)
+ return NULL;
+
+ bnx2fc_stats = fc_get_host_stats(shost);
+
+ init_completion(&hba->stat_req_done);
+ if (bnx2fc_send_stat_req(hba))
+ return bnx2fc_stats;
+ rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ));
+ if (!rc) {
+ BNX2FC_HBA_DBG(lport, "FW stat req timed out\n");
+ return bnx2fc_stats;
+ }
+ bnx2fc_stats->invalid_crc_count += fw_stats->rx_stat1.fc_crc_cnt;
+ bnx2fc_stats->tx_frames += fw_stats->tx_stat.fcoe_tx_pkt_cnt;
+ bnx2fc_stats->tx_words += (fw_stats->tx_stat.fcoe_tx_byte_cnt) / 4;
+ bnx2fc_stats->rx_frames += fw_stats->rx_stat0.fcoe_rx_pkt_cnt;
+ bnx2fc_stats->rx_words += (fw_stats->rx_stat0.fcoe_rx_byte_cnt) / 4;
+
+ bnx2fc_stats->dumped_frames = 0;
+ bnx2fc_stats->lip_count = 0;
+ bnx2fc_stats->nos_count = 0;
+ bnx2fc_stats->loss_of_sync_count = 0;
+ bnx2fc_stats->loss_of_signal_count = 0;
+ bnx2fc_stats->prim_seq_protocol_err_count = 0;
+
+ return bnx2fc_stats;
+}
+
+static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct Scsi_Host *shost = lport->host;
+ int rc = 0;
+
+ shost->max_cmd_len = BNX2FC_MAX_CMD_LEN;
+ shost->max_lun = BNX2FC_MAX_LUN;
+ shost->max_id = BNX2FC_MAX_FCP_TGT;
+ shost->max_channel = 0;
+ if (lport->vport)
+ shost->transportt = bnx2fc_vport_xport_template;
+ else
+ shost->transportt = bnx2fc_transport_template;
+
+ /* Add the new host to SCSI-ml */
+ rc = scsi_add_host(lport->host, dev);
+ if (rc) {
+ printk(KERN_ERR PFX "Error on scsi_add_host\n");
+ return rc;
+ }
+ if (!lport->vport)
+ fc_host_max_npiv_vports(lport->host) = USHRT_MAX;
+ sprintf(fc_host_symbolic_name(lport->host), "%s v%s over %s",
+ BNX2FC_NAME, BNX2FC_VERSION,
+ hba->netdev->name);
+
+ return 0;
+}
+
+static int bnx2fc_mfs_update(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct net_device *netdev = hba->netdev;
+ u32 mfs;
+ u32 max_mfs;
+
+ mfs = netdev->mtu - (sizeof(struct fcoe_hdr) +
+ sizeof(struct fcoe_crc_eof));
+ max_mfs = BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header);
+ BNX2FC_HBA_DBG(lport, "mfs = %d, max_mfs = %d\n", mfs, max_mfs);
+ if (mfs > max_mfs)
+ mfs = max_mfs;
+
+ /* Adjust mfs to be a multiple of 256 bytes */
+ mfs = (((mfs - sizeof(struct fc_frame_header)) / BNX2FC_MIN_PAYLOAD) *
+ BNX2FC_MIN_PAYLOAD);
+ mfs = mfs + sizeof(struct fc_frame_header);
+
+ BNX2FC_HBA_DBG(lport, "Set MFS = %d\n", mfs);
+ if (fc_set_mfs(lport, mfs))
+ return -EINVAL;
+ return 0;
+}
+static void bnx2fc_link_speed_update(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct net_device *netdev = hba->netdev;
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+
+ if (!dev_ethtool_get_settings(netdev, &ecmd)) {
+ lport->link_supported_speeds &=
+ ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
+ if (ecmd.supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full))
+ lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
+ if (ecmd.supported & SUPPORTED_10000baseT_Full)
+ lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
+
+ if (ecmd.speed == SPEED_1000)
+ lport->link_speed = FC_PORTSPEED_1GBIT;
+ if (ecmd.speed == SPEED_10000)
+ lport->link_speed = FC_PORTSPEED_10GBIT;
+ }
+ return;
+}
+static int bnx2fc_link_ok(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct net_device *dev = hba->phys_dev;
+ int rc = 0;
+
+ if ((dev->flags & IFF_UP) && netif_carrier_ok(dev))
+ clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+ else {
+ set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+ rc = -1;
+ }
+ return rc;
+}
+
+/**
+ * bnx2fc_get_link_state - get network link state
+ *
+ * @hba: adapter instance pointer
+ *
+ * updates adapter structure flag based on netdev state
+ */
+void bnx2fc_get_link_state(struct bnx2fc_hba *hba)
+{
+ if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
+ set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+ else
+ clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
+}
+
+static int bnx2fc_net_config(struct fc_lport *lport)
+{
+ struct bnx2fc_hba *hba;
+ struct fcoe_port *port;
+ u64 wwnn, wwpn;
+
+ port = lport_priv(lport);
+ hba = port->priv;
+
+ /* require support for get_pauseparam ethtool op. */
+ if (!hba->phys_dev->ethtool_ops ||
+ !hba->phys_dev->ethtool_ops->get_pauseparam)
+ return -EOPNOTSUPP;
+
+ if (bnx2fc_mfs_update(lport))
+ return -EINVAL;
+
+ skb_queue_head_init(&port->fcoe_pending_queue);
+ port->fcoe_pending_queue_active = 0;
+ setup_timer(&port->timer, fcoe_queue_timer, (unsigned long) lport);
+
+ bnx2fc_link_speed_update(lport);
+
+ if (!lport->vport) {
+ wwnn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 1, 0);
+ BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn);
+ fc_set_wwnn(lport, wwnn);
+
+ wwpn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 2, 0);
+ BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn);
+ fc_set_wwpn(lport, wwpn);
+ }
+
+ return 0;
+}
+
+static void bnx2fc_destroy_timer(unsigned long data)
+{
+ struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data;
+
+ BNX2FC_HBA_DBG(hba->ctlr.lp, "ERROR:bnx2fc_destroy_timer - "
+ "Destroy compl not received!!\n");
+ hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+ wake_up_interruptible(&hba->destroy_wait);
+}
+
+/**
+ * bnx2fc_indicate_netevent - Generic netdev event handler
+ *
+ * @context: adapter structure pointer
+ * @event: event type
+ *
+ * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and
+ * NETDEV_CHANGE_MTU events
+ */
+static void bnx2fc_indicate_netevent(void *context, unsigned long event)
+{
+ struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
+ struct fc_lport *lport = hba->ctlr.lp;
+ struct fc_lport *vport;
+ u32 link_possible = 1;
+
+ if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ BNX2FC_MISC_DBG("driver not ready. event=%s %ld\n",
+ hba->netdev->name, event);
+ return;
+ }
+
+ /*
+ * ASSUMPTION:
+ * indicate_netevent cannot be called from cnic unless bnx2fc
+ * does register_device
+ */
+ BUG_ON(!lport);
+
+ BNX2FC_HBA_DBG(lport, "enter netevent handler - event=%s %ld\n",
+ hba->netdev->name, event);
+
+ switch (event) {
+ case NETDEV_UP:
+ BNX2FC_HBA_DBG(lport, "Port up, adapter_state = %ld\n",
+ hba->adapter_state);
+ if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
+ printk(KERN_ERR "indicate_netevent: "\
+ "adapter is not UP!!\n");
+ /* fall thru to update mfs if MTU has changed */
+ case NETDEV_CHANGEMTU:
+ BNX2FC_HBA_DBG(lport, "NETDEV_CHANGEMTU event\n");
+ bnx2fc_mfs_update(lport);
+ mutex_lock(&lport->lp_mutex);
+ list_for_each_entry(vport, &lport->vports, list)
+ bnx2fc_mfs_update(vport);
+ mutex_unlock(&lport->lp_mutex);
+ break;
+
+ case NETDEV_DOWN:
+ BNX2FC_HBA_DBG(lport, "Port down\n");
+ clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+ clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+ link_possible = 0;
+ break;
+
+ case NETDEV_GOING_DOWN:
+ BNX2FC_HBA_DBG(lport, "Port going down\n");
+ set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+ link_possible = 0;
+ break;
+
+ case NETDEV_CHANGE:
+ BNX2FC_HBA_DBG(lport, "NETDEV_CHANGE\n");
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unkonwn netevent %ld", event);
+ return;
+ }
+
+ bnx2fc_link_speed_update(lport);
+
+ if (link_possible && !bnx2fc_link_ok(lport)) {
+ printk(KERN_ERR "indicate_netevent: call ctlr_link_up\n");
+ fcoe_ctlr_link_up(&hba->ctlr);
+ } else {
+ printk(KERN_ERR "indicate_netevent: call ctlr_link_down\n");
+ if (fcoe_ctlr_link_down(&hba->ctlr)) {
+ clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+ mutex_lock(&lport->lp_mutex);
+ list_for_each_entry(vport, &lport->vports, list)
+ fc_host_port_type(vport->host) =
+ FC_PORTTYPE_UNKNOWN;
+ mutex_unlock(&lport->lp_mutex);
+ fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
+ per_cpu_ptr(lport->dev_stats,
+ get_cpu())->LinkFailureCount++;
+ put_cpu();
+ fcoe_clean_pending_queue(lport);
+
+ init_waitqueue_head(&hba->shutdown_wait);
+ BNX2FC_HBA_DBG(lport, "indicate_netevent "
+ "num_ofld_sess = %d\n",
+ hba->num_ofld_sess);
+ hba->wait_for_link_down = 1;
+ BNX2FC_HBA_DBG(lport, "waiting for uploads to "
+ "compl proc = %s\n",
+ current->comm);
+ wait_event_interruptible(hba->shutdown_wait,
+ (hba->num_ofld_sess == 0));
+ BNX2FC_HBA_DBG(lport, "wakeup - num_ofld_sess = %d\n",
+ hba->num_ofld_sess);
+ hba->wait_for_link_down = 0;
+
+ if (signal_pending(current))
+ flush_signals(current);
+ }
+ }
+}
+
+static int bnx2fc_libfc_config(struct fc_lport *lport)
+{
+
+ /* Set the function pointers set by bnx2fc driver */
+ memcpy(&lport->tt, &bnx2fc_libfc_fcn_templ,
+ sizeof(struct libfc_function_template));
+ fc_elsct_init(lport);
+ fc_exch_init(lport);
+ fc_rport_init(lport);
+ fc_disc_init(lport);
+ return 0;
+}
+
+static int bnx2fc_em_config(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+
+ if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
+ FCOE_MAX_XID, NULL)) {
+ printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
+ BNX2FC_MAX_XID);
+
+ if (!hba->cmd_mgr) {
+ printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
+ fc_exch_mgr_free(lport);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int bnx2fc_lport_config(struct fc_lport *lport)
+{
+ lport->link_up = 0;
+ lport->qfull = 0;
+ lport->max_retry_count = 3;
+ lport->max_rport_retry_count = 3;
+ lport->e_d_tov = 2 * 1000;
+ lport->r_a_tov = 10 * 1000;
+
+ /* REVISIT: enable when supporting tape devices
+ lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
+ FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
+ */
+ lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS);
+ lport->does_npiv = 1;
+
+ memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen));
+ lport->rnid_gen.rnid_atype = BNX2FC_RNID_HBA;
+
+ /* alloc stats structure */
+ if (fc_lport_init_stats(lport))
+ return -ENOMEM;
+
+ /* Finish fc_lport configuration */
+ fc_lport_config(lport);
+
+ return 0;
+}
+
+/**
+ * bnx2fc_fip_recv - handle a received FIP frame.
+ *
+ * @skb: the received skb
+ * @dev: associated &net_device
+ * @ptype: the &packet_type structure which was used to register this handler.
+ * @orig_dev: original receive &net_device, in case @ dev is a bond.
+ *
+ * Returns: 0 for success
+ */
+static int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *ptype,
+ struct net_device *orig_dev)
+{
+ struct bnx2fc_hba *hba;
+ hba = container_of(ptype, struct bnx2fc_hba, fip_packet_type);
+ fcoe_ctlr_recv(&hba->ctlr, skb);
+ return 0;
+}
+
+/**
+ * bnx2fc_update_src_mac - Update Ethernet MAC filters.
+ *
+ * @fip: FCoE controller.
+ * @old: Unicast MAC address to delete if the MAC is non-zero.
+ * @new: Unicast MAC address to add.
+ *
+ * Remove any previously-set unicast MAC filter.
+ * Add secondary FCoE MAC address filter for our OUI.
+ */
+static void bnx2fc_update_src_mac(struct fc_lport *lport, u8 *addr)
+{
+ struct fcoe_port *port = lport_priv(lport);
+
+ memcpy(port->data_src_addr, addr, ETH_ALEN);
+}
+
+/**
+ * bnx2fc_get_src_mac - return the ethernet source address for an lport
+ *
+ * @lport: libfc port
+ */
+static u8 *bnx2fc_get_src_mac(struct fc_lport *lport)
+{
+ struct fcoe_port *port;
+
+ port = (struct fcoe_port *)lport_priv(lport);
+ return port->data_src_addr;
+}
+
+/**
+ * bnx2fc_fip_send - send an Ethernet-encapsulated FIP frame.
+ *
+ * @fip: FCoE controller.
+ * @skb: FIP Packet.
+ */
+static void bnx2fc_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
+{
+ skb->dev = bnx2fc_from_ctlr(fip)->netdev;
+ dev_queue_xmit(skb);
+}
+
+static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+ struct fcoe_port *port = lport_priv(n_port);
+ struct bnx2fc_hba *hba = port->priv;
+ struct net_device *netdev = hba->netdev;
+ struct fc_lport *vn_port;
+
+ if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+ printk(KERN_ERR PFX "vn ports cannot be created on"
+ "this hba\n");
+ return -EIO;
+ }
+ mutex_lock(&bnx2fc_dev_lock);
+ vn_port = bnx2fc_if_create(hba, &vport->dev, 1);
+ mutex_unlock(&bnx2fc_dev_lock);
+
+ if (IS_ERR(vn_port)) {
+ printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n",
+ netdev->name);
+ return -EIO;
+ }
+
+ if (disabled) {
+ fc_vport_set_state(vport, FC_VPORT_DISABLED);
+ } else {
+ vn_port->boot_time = jiffies;
+ fc_lport_init(vn_port);
+ fc_fabric_login(vn_port);
+ fc_vport_setlink(vn_port);
+ }
+ return 0;
+}
+
+static int bnx2fc_vport_destroy(struct fc_vport *vport)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_lport *n_port = shost_priv(shost);
+ struct fc_lport *vn_port = vport->dd_data;
+ struct fcoe_port *port = lport_priv(vn_port);
+
+ mutex_lock(&n_port->lp_mutex);
+ list_del(&vn_port->list);
+ mutex_unlock(&n_port->lp_mutex);
+ queue_work(bnx2fc_wq, &port->destroy_work);
+ return 0;
+}
+
+static int bnx2fc_vport_disable(struct fc_vport *vport, bool disable)
+{
+ struct fc_lport *lport = vport->dd_data;
+
+ if (disable) {
+ fc_vport_set_state(vport, FC_VPORT_DISABLED);
+ fc_fabric_logoff(lport);
+ } else {
+ lport->boot_time = jiffies;
+ fc_fabric_login(lport);
+ fc_vport_setlink(lport);
+ }
+ return 0;
+}
+
+
+static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
+{
+ struct net_device *netdev = hba->netdev;
+ struct net_device *physdev = hba->phys_dev;
+ struct netdev_hw_addr *ha;
+ int sel_san_mac = 0;
+
+ /* Do not support for bonding device */
+ if ((netdev->priv_flags & IFF_MASTER_ALB) ||
+ (netdev->priv_flags & IFF_SLAVE_INACTIVE) ||
+ (netdev->priv_flags & IFF_MASTER_8023AD)) {
+ return -EOPNOTSUPP;
+ }
+
+ /* setup Source MAC Address */
+ rcu_read_lock();
+ for_each_dev_addr(physdev, ha) {
+ BNX2FC_MISC_DBG("net_config: ha->type = %d, fip_mac = ",
+ ha->type);
+ printk(KERN_INFO "%2x:%2x:%2x:%2x:%2x:%2x\n", ha->addr[0],
+ ha->addr[1], ha->addr[2], ha->addr[3],
+ ha->addr[4], ha->addr[5]);
+
+ if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
+ (is_valid_ether_addr(ha->addr))) {
+ memcpy(hba->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
+ sel_san_mac = 1;
+ BNX2FC_MISC_DBG("Found SAN MAC\n");
+ }
+ }
+ rcu_read_unlock();
+
+ if (!sel_san_mac)
+ return -ENODEV;
+
+ hba->fip_packet_type.func = bnx2fc_fip_recv;
+ hba->fip_packet_type.type = htons(ETH_P_FIP);
+ hba->fip_packet_type.dev = netdev;
+ dev_add_pack(&hba->fip_packet_type);
+
+ hba->fcoe_packet_type.func = bnx2fc_rcv;
+ hba->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
+ hba->fcoe_packet_type.dev = netdev;
+ dev_add_pack(&hba->fcoe_packet_type);
+
+ return 0;
+}
+
+static int bnx2fc_attach_transport(void)
+{
+ bnx2fc_transport_template =
+ fc_attach_transport(&bnx2fc_transport_function);
+
+ if (bnx2fc_transport_template == NULL) {
+ printk(KERN_ERR PFX "Failed to attach FC transport\n");
+ return -ENODEV;
+ }
+
+ bnx2fc_vport_xport_template =
+ fc_attach_transport(&bnx2fc_vport_xport_function);
+ if (bnx2fc_vport_xport_template == NULL) {
+ printk(KERN_ERR PFX
+ "Failed to attach FC transport for vport\n");
+ fc_release_transport(bnx2fc_transport_template);
+ bnx2fc_transport_template = NULL;
+ return -ENODEV;
+ }
+ return 0;
+}
+static void bnx2fc_release_transport(void)
+{
+ fc_release_transport(bnx2fc_transport_template);
+ fc_release_transport(bnx2fc_vport_xport_template);
+ bnx2fc_transport_template = NULL;
+ bnx2fc_vport_xport_template = NULL;
+}
+
+static void bnx2fc_interface_release(struct kref *kref)
+{
+ struct bnx2fc_hba *hba;
+ struct net_device *netdev;
+ struct net_device *phys_dev;
+
+ hba = container_of(kref, struct bnx2fc_hba, kref);
+ BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n");
+
+ netdev = hba->netdev;
+ phys_dev = hba->phys_dev;
+
+ /* tear-down FIP controller */
+ if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done))
+ fcoe_ctlr_destroy(&hba->ctlr);
+
+ /* Free the command manager */
+ if (hba->cmd_mgr) {
+ bnx2fc_cmd_mgr_free(hba->cmd_mgr);
+ hba->cmd_mgr = NULL;
+ }
+ dev_put(netdev);
+ module_put(THIS_MODULE);
+}
+
+static inline void bnx2fc_interface_get(struct bnx2fc_hba *hba)
+{
+ kref_get(&hba->kref);
+}
+
+static inline void bnx2fc_interface_put(struct bnx2fc_hba *hba)
+{
+ kref_put(&hba->kref, bnx2fc_interface_release);
+}
+static void bnx2fc_interface_destroy(struct bnx2fc_hba *hba)
+{
+ bnx2fc_unbind_pcidev(hba);
+ kfree(hba);
+}
+
+/**
+ * bnx2fc_interface_create - create a new fcoe instance
+ *
+ * @cnic: pointer to cnic device
+ *
+ * Creates a new FCoE instance on the given device which include allocating
+ * hba structure, scsi_host and lport structures.
+ */
+static struct bnx2fc_hba *bnx2fc_interface_create(struct cnic_dev *cnic)
+{
+ struct bnx2fc_hba *hba;
+ int rc;
+
+ hba = kzalloc(sizeof(*hba), GFP_KERNEL);
+ if (!hba) {
+ printk(KERN_ERR PFX "Unable to allocate hba structure\n");
+ return NULL;
+ }
+ spin_lock_init(&hba->hba_lock);
+ mutex_init(&hba->hba_mutex);
+
+ hba->cnic = cnic;
+ rc = bnx2fc_bind_pcidev(hba);
+ if (rc)
+ goto bind_err;
+ hba->phys_dev = cnic->netdev;
+ /* will get overwritten after we do vlan discovery */
+ hba->netdev = hba->phys_dev;
+
+ init_waitqueue_head(&hba->shutdown_wait);
+ init_waitqueue_head(&hba->destroy_wait);
+
+ return hba;
+bind_err:
+ printk(KERN_ERR PFX "create_interface: bind error\n");
+ kfree(hba);
+ return NULL;
+}
+
+static int bnx2fc_interface_setup(struct bnx2fc_hba *hba,
+ enum fip_state fip_mode)
+{
+ int rc = 0;
+ struct net_device *netdev = hba->netdev;
+ struct fcoe_ctlr *fip = &hba->ctlr;
+
+ dev_hold(netdev);
+ kref_init(&hba->kref);
+
+ hba->flags = 0;
+
+ /* Initialize FIP */
+ memset(fip, 0, sizeof(*fip));
+ fcoe_ctlr_init(fip, fip_mode);
+ hba->ctlr.send = bnx2fc_fip_send;
+ hba->ctlr.update_mac = bnx2fc_update_src_mac;
+ hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
+ set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
+
+ rc = bnx2fc_netdev_setup(hba);
+ if (rc)
+ goto setup_err;
+
+ hba->next_conn_id = 0;
+
+ memset(hba->tgt_ofld_list, 0, sizeof(hba->tgt_ofld_list));
+ hba->num_ofld_sess = 0;
+
+ return 0;
+
+setup_err:
+ fcoe_ctlr_destroy(&hba->ctlr);
+ dev_put(netdev);
+ bnx2fc_interface_put(hba);
+ return rc;
+}
+
+/**
+ * bnx2fc_if_create - Create FCoE instance on a given interface
+ *
+ * @hba: FCoE interface to create a local port on
+ * @parent: Device pointer to be the parent in sysfs for the SCSI host
+ * @npiv: Indicates if the port is vport or not
+ *
+ * Creates a fc_lport instance and a Scsi_Host instance and configure them.
+ *
+ * Returns: Allocated fc_lport or an error pointer
+ */
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+ struct device *parent, int npiv)
+{
+ struct fc_lport *lport = NULL;
+ struct fcoe_port *port;
+ struct Scsi_Host *shost;
+ struct fc_vport *vport = dev_to_vport(parent);
+ int rc = 0;
+
+ /* Allocate Scsi_Host structure */
+ if (!npiv) {
+ lport = libfc_host_alloc(&bnx2fc_shost_template,
+ sizeof(struct fcoe_port));
+ } else {
+ lport = libfc_vport_create(vport,
+ sizeof(struct fcoe_port));
+ }
+
+ if (!lport) {
+ printk(KERN_ERR PFX "could not allocate scsi host structure\n");
+ return NULL;
+ }
+ shost = lport->host;
+ port = lport_priv(lport);
+ port->lport = lport;
+ port->priv = hba;
+ INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
+
+ /* Configure fcoe_port */
+ rc = bnx2fc_lport_config(lport);
+ if (rc)
+ goto lp_config_err;
+
+ if (npiv) {
+ vport = dev_to_vport(parent);
+ printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n",
+ vport->node_name, vport->port_name);
+ fc_set_wwnn(lport, vport->node_name);
+ fc_set_wwpn(lport, vport->port_name);
+ }
+ /* Configure netdev and networking properties of the lport */
+ rc = bnx2fc_net_config(lport);
+ if (rc) {
+ printk(KERN_ERR PFX "Error on bnx2fc_net_config\n");
+ goto lp_config_err;
+ }
+
+ rc = bnx2fc_shost_config(lport, parent);
+ if (rc) {
+ printk(KERN_ERR PFX "Couldnt configure shost for %s\n",
+ hba->netdev->name);
+ goto lp_config_err;
+ }
+
+ /* Initialize the libfc library */
+ rc = bnx2fc_libfc_config(lport);
+ if (rc) {
+ printk(KERN_ERR PFX "Couldnt configure libfc\n");
+ goto shost_err;
+ }
+ fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
+
+ /* Allocate exchange manager */
+ if (!npiv) {
+ rc = bnx2fc_em_config(lport);
+ if (rc) {
+ printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
+ goto shost_err;
+ }
+ }
+
+ bnx2fc_interface_get(hba);
+ return lport;
+
+shost_err:
+ scsi_remove_host(shost);
+lp_config_err:
+ scsi_host_put(lport->host);
+ return NULL;
+}
+
+static void bnx2fc_netdev_cleanup(struct bnx2fc_hba *hba)
+{
+ /* Dont listen for Ethernet packets anymore */
+ __dev_remove_pack(&hba->fcoe_packet_type);
+ __dev_remove_pack(&hba->fip_packet_type);
+ synchronize_net();
+}
+
+static void bnx2fc_if_destroy(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+
+ BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
+ /* Stop the transmit retry timer */
+ del_timer_sync(&port->timer);
+
+ /* Free existing transmit skbs */
+ fcoe_clean_pending_queue(lport);
+
+ bnx2fc_interface_put(hba);
+
+ /* Free queued packets for the receive thread */
+ bnx2fc_clean_rx_queue(lport);
+
+ /* Detach from scsi-ml */
+ fc_remove_host(lport->host);
+ scsi_remove_host(lport->host);
+
+ /*
+ * Note that only the physical lport will have the exchange manager.
+ * for vports, this function is NOP
+ */
+ fc_exch_mgr_free(lport);
+
+ /* Free memory used by statistical counters */
+ fc_lport_free_stats(lport);
+
+ /* Release Scsi_Host */
+ scsi_host_put(lport->host);
+}
+
+/**
+ * bnx2fc_destroy - Destroy a bnx2fc FCoE interface
+ *
+ * @buffer: The name of the Ethernet interface to be destroyed
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int bnx2fc_destroy(struct net_device *netdev)
+{
+ struct bnx2fc_hba *hba = NULL;
+ struct net_device *phys_dev;
+ int rc = 0;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ mutex_lock(&bnx2fc_dev_lock);
+#ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto netdev_err;
+ }
+#endif
+ /* obtain physical netdev */
+ if (netdev->priv_flags & IFF_802_1Q_VLAN)
+ phys_dev = vlan_dev_real_dev(netdev);
+ else {
+ printk(KERN_ERR PFX "Not a vlan device\n");
+ rc = -ENODEV;
+ goto netdev_err;
+ }
+
+ hba = bnx2fc_hba_lookup(phys_dev);
+ if (!hba || !hba->ctlr.lp) {
+ rc = -ENODEV;
+ printk(KERN_ERR PFX "bnx2fc_destroy: hba or lport not found\n");
+ goto netdev_err;
+ }
+
+ if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ printk(KERN_ERR PFX "bnx2fc_destroy: Create not called\n");
+ goto netdev_err;
+ }
+
+ bnx2fc_netdev_cleanup(hba);
+
+ bnx2fc_stop(hba);
+
+ bnx2fc_if_destroy(hba->ctlr.lp);
+
+ destroy_workqueue(hba->timer_work_queue);
+
+ if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
+ bnx2fc_fw_destroy(hba);
+
+ clear_bit(BNX2FC_CREATE_DONE, &hba->init_done);
+netdev_err:
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+ return rc;
+}
+
+static void bnx2fc_destroy_work(struct work_struct *work)
+{
+ struct fcoe_port *port;
+ struct fc_lport *lport;
+
+ port = container_of(work, struct fcoe_port, destroy_work);
+ lport = port->lport;
+
+ BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n");
+
+ bnx2fc_port_shutdown(lport);
+ rtnl_lock();
+ mutex_lock(&bnx2fc_dev_lock);
+ bnx2fc_if_destroy(lport);
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+}
+
+static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba)
+{
+ bnx2fc_free_fw_resc(hba);
+ bnx2fc_free_task_ctx(hba);
+}
+
+/**
+ * bnx2fc_bind_adapter_devices - binds bnx2fc adapter with the associated
+ * pci structure
+ *
+ * @hba: Adapter instance
+ */
+static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba)
+{
+ if (bnx2fc_setup_task_ctx(hba))
+ goto mem_err;
+
+ if (bnx2fc_setup_fw_resc(hba))
+ goto mem_err;
+
+ return 0;
+mem_err:
+ bnx2fc_unbind_adapter_devices(hba);
+ return -ENOMEM;
+}
+
+static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba)
+{
+ struct cnic_dev *cnic;
+
+ if (!hba->cnic) {
+ printk(KERN_ERR PFX "cnic is NULL\n");
+ return -ENODEV;
+ }
+ cnic = hba->cnic;
+ hba->pcidev = cnic->pcidev;
+ if (hba->pcidev)
+ pci_dev_get(hba->pcidev);
+
+ return 0;
+}
+
+static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba)
+{
+ if (hba->pcidev)
+ pci_dev_put(hba->pcidev);
+ hba->pcidev = NULL;
+}
+
+
+
+/**
+ * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance
+ *
+ * @handle: transport handle pointing to adapter struture
+ *
+ * This function maps adapter structure to pcidev structure and initiates
+ * firmware handshake to enable/initialize on-chip FCoE components.
+ * This bnx2fc - cnic interface api callback is used after following
+ * conditions are met -
+ * a) underlying network interface is up (marked by event NETDEV_UP
+ * from netdev
+ * b) bnx2fc adatper structure is registered.
+ */
+static void bnx2fc_ulp_start(void *handle)
+{
+ struct bnx2fc_hba *hba = handle;
+ struct fc_lport *lport = hba->ctlr.lp;
+
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ mutex_lock(&bnx2fc_dev_lock);
+
+ if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
+ goto start_disc;
+
+ if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done))
+ bnx2fc_fw_init(hba);
+
+start_disc:
+ mutex_unlock(&bnx2fc_dev_lock);
+
+ BNX2FC_MISC_DBG("bnx2fc started.\n");
+
+ /* Kick off Fabric discovery*/
+ if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ printk(KERN_ERR PFX "ulp_init: start discovery\n");
+ lport->tt.frame_send = bnx2fc_xmit;
+ bnx2fc_start_disc(hba);
+ }
+}
+
+static void bnx2fc_port_shutdown(struct fc_lport *lport)
+{
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ fc_fabric_logoff(lport);
+ fc_lport_destroy(lport);
+}
+
+static void bnx2fc_stop(struct bnx2fc_hba *hba)
+{
+ struct fc_lport *lport;
+ struct fc_lport *vport;
+
+ BNX2FC_MISC_DBG("ENTERED %s - init_done = %ld\n", __func__,
+ hba->init_done);
+ if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done) &&
+ test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ lport = hba->ctlr.lp;
+ bnx2fc_port_shutdown(lport);
+ BNX2FC_HBA_DBG(lport, "bnx2fc_stop: waiting for %d "
+ "offloaded sessions\n",
+ hba->num_ofld_sess);
+ wait_event_interruptible(hba->shutdown_wait,
+ (hba->num_ofld_sess == 0));
+ mutex_lock(&lport->lp_mutex);
+ list_for_each_entry(vport, &lport->vports, list)
+ fc_host_port_type(vport->host) = FC_PORTTYPE_UNKNOWN;
+ mutex_unlock(&lport->lp_mutex);
+ fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
+ fcoe_ctlr_link_down(&hba->ctlr);
+ fcoe_clean_pending_queue(lport);
+
+ mutex_lock(&hba->hba_mutex);
+ clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+ clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+
+ clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+ mutex_unlock(&hba->hba_mutex);
+ }
+}
+
+static int bnx2fc_fw_init(struct bnx2fc_hba *hba)
+{
+#define BNX2FC_INIT_POLL_TIME (1000 / HZ)
+ int rc = -1;
+ int i = HZ;
+
+ rc = bnx2fc_bind_adapter_devices(hba);
+ if (rc) {
+ printk(KERN_ALERT PFX
+ "bnx2fc_bind_adapter_devices failed - rc = %d\n", rc);
+ goto err_out;
+ }
+
+ rc = bnx2fc_send_fw_fcoe_init_msg(hba);
+ if (rc) {
+ printk(KERN_ALERT PFX
+ "bnx2fc_send_fw_fcoe_init_msg failed - rc = %d\n", rc);
+ goto err_unbind;
+ }
+
+ /*
+ * Wait until the adapter init message is complete, and adapter
+ * state is UP.
+ */
+ while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
+ msleep(BNX2FC_INIT_POLL_TIME);
+
+ if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) {
+ printk(KERN_ERR PFX "bnx2fc_start: %s failed to initialize. "
+ "Ignoring...\n",
+ hba->cnic->netdev->name);
+ rc = -1;
+ goto err_unbind;
+ }
+
+
+ /* Mark HBA to indicate that the FW INIT is done */
+ set_bit(BNX2FC_FW_INIT_DONE, &hba->init_done);
+ return 0;
+
+err_unbind:
+ bnx2fc_unbind_adapter_devices(hba);
+err_out:
+ return rc;
+}
+
+static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
+{
+ if (test_and_clear_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+ if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) {
+ init_timer(&hba->destroy_timer);
+ hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT +
+ jiffies;
+ hba->destroy_timer.function = bnx2fc_destroy_timer;
+ hba->destroy_timer.data = (unsigned long)hba;
+ add_timer(&hba->destroy_timer);
+ wait_event_interruptible(hba->destroy_wait,
+ (hba->flags &
+ BNX2FC_FLAG_DESTROY_CMPL));
+ /* This should never happen */
+ if (signal_pending(current))
+ flush_signals(current);
+
+ del_timer_sync(&hba->destroy_timer);
+ }
+ bnx2fc_unbind_adapter_devices(hba);
+ }
+}
+
+/**
+ * bnx2fc_ulp_stop - cnic callback to shutdown adapter instance
+ *
+ * @handle: transport handle pointing to adapter structure
+ *
+ * Driver checks if adapter is already in shutdown mode, if not start
+ * the shutdown process.
+ */
+static void bnx2fc_ulp_stop(void *handle)
+{
+ struct bnx2fc_hba *hba = (struct bnx2fc_hba *)handle;
+
+ printk(KERN_ERR "ULP_STOP\n");
+
+ mutex_lock(&bnx2fc_dev_lock);
+ bnx2fc_stop(hba);
+ bnx2fc_fw_destroy(hba);
+ mutex_unlock(&bnx2fc_dev_lock);
+}
+
+static void bnx2fc_start_disc(struct bnx2fc_hba *hba)
+{
+ struct fc_lport *lport;
+ int wait_cnt = 0;
+
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ /* Kick off FIP/FLOGI */
+ if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+ printk(KERN_ERR PFX "Init not done yet\n");
+ return;
+ }
+
+ lport = hba->ctlr.lp;
+ BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n");
+
+ if (!bnx2fc_link_ok(lport)) {
+ BNX2FC_HBA_DBG(lport, "ctlr_link_up\n");
+ fcoe_ctlr_link_up(&hba->ctlr);
+ fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;
+ set_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+ }
+
+ /* wait for the FCF to be selected before issuing FLOGI */
+ while (!hba->ctlr.sel_fcf) {
+ msleep(250);
+ /* give up after 3 secs */
+ if (++wait_cnt > 12)
+ break;
+ }
+ fc_lport_init(lport);
+ fc_fabric_login(lport);
+}
+
+
+/**
+ * bnx2fc_ulp_init - Initialize an adapter instance
+ *
+ * @dev : cnic device handle
+ * Called from cnic_register_driver() context to initialize all
+ * enumerated cnic devices. This routine allocates adapter structure
+ * and other device specific resources.
+ */
+static void bnx2fc_ulp_init(struct cnic_dev *dev)
+{
+ struct bnx2fc_hba *hba;
+ int rc = 0;
+
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ /* bnx2fc works only when bnx2x is loaded */
+ if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s,"
+ " flags: %lx\n",
+ dev->netdev->name, dev->flags);
+ return;
+ }
+
+ /* Configure FCoE interface */
+ hba = bnx2fc_interface_create(dev);
+ if (!hba) {
+ printk(KERN_ERR PFX "hba initialization failed\n");
+ return;
+ }
+
+ /* Add HBA to the adapter list */
+ mutex_lock(&bnx2fc_dev_lock);
+ list_add_tail(&hba->link, &adapter_list);
+ adapter_count++;
+ mutex_unlock(&bnx2fc_dev_lock);
+
+ clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic);
+ rc = dev->register_device(dev, CNIC_ULP_FCOE,
+ (void *) hba);
+ if (rc)
+ printk(KERN_ALERT PFX "register_device failed, rc = %d\n", rc);
+ else
+ set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic);
+}
+
+
+static int bnx2fc_disable(struct net_device *netdev)
+{
+ struct bnx2fc_hba *hba;
+ struct net_device *phys_dev;
+ struct ethtool_drvinfo drvinfo;
+ int rc = 0;
+
+ if (!rtnl_trylock()) {
+ printk(KERN_ERR PFX "retrying for rtnl_lock\n");
+ return -EIO;
+ }
+
+ mutex_lock(&bnx2fc_dev_lock);
+
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto nodev;
+ }
+
+ /* obtain physical netdev */
+ if (netdev->priv_flags & IFF_802_1Q_VLAN)
+ phys_dev = vlan_dev_real_dev(netdev);
+ else {
+ printk(KERN_ERR PFX "Not a vlan device\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+
+ /* verify if the physical device is a netxtreme2 device */
+ if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
+ memset(&drvinfo, 0, sizeof(drvinfo));
+ phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
+ if (strcmp(drvinfo.driver, "bnx2x")) {
+ printk(KERN_ERR PFX "Not a netxtreme2 device\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+ } else {
+ printk(KERN_ERR PFX "unable to obtain drv_info\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+
+ printk(KERN_ERR PFX "phys_dev is netxtreme2 device\n");
+
+ /* obtain hba and initialize rest of the structure */
+ hba = bnx2fc_hba_lookup(phys_dev);
+ if (!hba || !hba->ctlr.lp) {
+ rc = -ENODEV;
+ printk(KERN_ERR PFX "bnx2fc_disable: hba or lport not found\n");
+ } else {
+ fcoe_ctlr_link_down(&hba->ctlr);
+ fcoe_clean_pending_queue(hba->ctlr.lp);
+ }
+
+nodev:
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+ return rc;
+}
+
+
+static int bnx2fc_enable(struct net_device *netdev)
+{
+ struct bnx2fc_hba *hba;
+ struct net_device *phys_dev;
+ struct ethtool_drvinfo drvinfo;
+ int rc = 0;
+
+ if (!rtnl_trylock()) {
+ printk(KERN_ERR PFX "retrying for rtnl_lock\n");
+ return -EIO;
+ }
+
+ BNX2FC_MISC_DBG("Entered %s\n", __func__);
+ mutex_lock(&bnx2fc_dev_lock);
+
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto nodev;
+ }
+
+ /* obtain physical netdev */
+ if (netdev->priv_flags & IFF_802_1Q_VLAN)
+ phys_dev = vlan_dev_real_dev(netdev);
+ else {
+ printk(KERN_ERR PFX "Not a vlan device\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+ /* verify if the physical device is a netxtreme2 device */
+ if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
+ memset(&drvinfo, 0, sizeof(drvinfo));
+ phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
+ if (strcmp(drvinfo.driver, "bnx2x")) {
+ printk(KERN_ERR PFX "Not a netxtreme2 device\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+ } else {
+ printk(KERN_ERR PFX "unable to obtain drv_info\n");
+ rc = -ENODEV;
+ goto nodev;
+ }
+
+ /* obtain hba and initialize rest of the structure */
+ hba = bnx2fc_hba_lookup(phys_dev);
+ if (!hba || !hba->ctlr.lp) {
+ rc = -ENODEV;
+ printk(KERN_ERR PFX "bnx2fc_enable: hba or lport not found\n");
+ } else if (!bnx2fc_link_ok(hba->ctlr.lp))
+ fcoe_ctlr_link_up(&hba->ctlr);
+
+nodev:
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+ return rc;
+}
+
+/**
+ * bnx2fc_create - Create bnx2fc FCoE interface
+ *
+ * @buffer: The name of Ethernet interface to create on
+ * @kp: The associated kernel param
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
+{
+ struct bnx2fc_hba *hba;
+ struct net_device *phys_dev;
+ struct fc_lport *lport;
+ struct ethtool_drvinfo drvinfo;
+ int rc = 0;
+ int vlan_id;
+
+ BNX2FC_MISC_DBG("Entered bnx2fc_create\n");
+ if (fip_mode != FIP_MODE_FABRIC) {
+ printk(KERN_ERR "fip mode not FABRIC\n");
+ return -EIO;
+ }
+
+ if (!rtnl_trylock()) {
+ printk(KERN_ERR "trying for rtnl_lock\n");
+ return -EIO;
+ }
+ mutex_lock(&bnx2fc_dev_lock);
+
+#ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE
+ if (THIS_MODULE->state != MODULE_STATE_LIVE) {
+ rc = -ENODEV;
+ goto mod_err;
+ }
+#endif
+
+ if (!try_module_get(THIS_MODULE)) {
+ rc = -EINVAL;
+ goto mod_err;
+ }
+
+ /* obtain physical netdev */
+ if (netdev->priv_flags & IFF_802_1Q_VLAN) {
+ phys_dev = vlan_dev_real_dev(netdev);
+ vlan_id = vlan_dev_vlan_id(netdev);
+ } else {
+ printk(KERN_ERR PFX "Not a vlan device\n");
+ rc = -EINVAL;
+ goto netdev_err;
+ }
+ /* verify if the physical device is a netxtreme2 device */
+ if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
+ memset(&drvinfo, 0, sizeof(drvinfo));
+ phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
+ if (strcmp(drvinfo.driver, "bnx2x")) {
+ printk(KERN_ERR PFX "Not a netxtreme2 device\n");
+ rc = -EINVAL;
+ goto netdev_err;
+ }
+ } else {
+ printk(KERN_ERR PFX "unable to obtain drv_info\n");
+ rc = -EINVAL;
+ goto netdev_err;
+ }
+
+ /* obtain hba and initialize rest of the structure */
+ hba = bnx2fc_hba_lookup(phys_dev);
+ if (!hba) {
+ rc = -ENODEV;
+ printk(KERN_ERR PFX "bnx2fc_create: hba not found\n");
+ goto netdev_err;
+ }
+
+ if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+ rc = bnx2fc_fw_init(hba);
+ if (rc)
+ goto netdev_err;
+ }
+
+ if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ rc = -EEXIST;
+ goto netdev_err;
+ }
+
+ /* update netdev with vlan netdev */
+ hba->netdev = netdev;
+ hba->vlan_id = vlan_id;
+ hba->vlan_enabled = 1;
+
+ rc = bnx2fc_interface_setup(hba, fip_mode);
+ if (rc) {
+ printk(KERN_ERR PFX "bnx2fc_interface_setup failed\n");
+ goto ifput_err;
+ }
+
+ hba->timer_work_queue =
+ create_singlethread_workqueue("bnx2fc_timer_wq");
+ if (!hba->timer_work_queue) {
+ printk(KERN_ERR PFX "ulp_init could not create timer_wq\n");
+ rc = -EINVAL;
+ goto ifput_err;
+ }
+
+ lport = bnx2fc_if_create(hba, &hba->pcidev->dev, 0);
+ if (!lport) {
+ printk(KERN_ERR PFX "Failed to create interface (%s)\n",
+ netdev->name);
+ bnx2fc_netdev_cleanup(hba);
+ rc = -EINVAL;
+ goto if_create_err;
+ }
+
+ lport->boot_time = jiffies;
+
+ /* Make this master N_port */
+ hba->ctlr.lp = lport;
+
+ set_bit(BNX2FC_CREATE_DONE, &hba->init_done);
+ printk(KERN_ERR PFX "create: START DISC\n");
+ bnx2fc_start_disc(hba);
+ /*
+ * Release from kref_init in bnx2fc_interface_setup, on success
+ * lport should be holding a reference taken in bnx2fc_if_create
+ */
+ bnx2fc_interface_put(hba);
+ /* put netdev that was held while calling dev_get_by_name */
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+ return 0;
+
+if_create_err:
+ destroy_workqueue(hba->timer_work_queue);
+ifput_err:
+ bnx2fc_interface_put(hba);
+netdev_err:
+ module_put(THIS_MODULE);
+mod_err:
+ mutex_unlock(&bnx2fc_dev_lock);
+ rtnl_unlock();
+ return rc;
+}
+
+/**
+ * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc adapter instance
+ *
+ * @cnic: Pointer to cnic device instance
+ *
+ **/
+static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic)
+{
+ struct list_head *list;
+ struct list_head *temp;
+ struct bnx2fc_hba *hba;
+
+ /* Called with bnx2fc_dev_lock held */
+ list_for_each_safe(list, temp, &adapter_list) {
+ hba = (struct bnx2fc_hba *)list;
+ if (hba->cnic == cnic)
+ return hba;
+ }
+ return NULL;
+}
+
+static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev)
+{
+ struct list_head *list;
+ struct list_head *temp;
+ struct bnx2fc_hba *hba;
+
+ /* Called with bnx2fc_dev_lock held */
+ list_for_each_safe(list, temp, &adapter_list) {
+ hba = (struct bnx2fc_hba *)list;
+ if (hba->phys_dev == phys_dev)
+ return hba;
+ }
+ printk(KERN_ERR PFX "hba_lookup: hba NULL\n");
+ return NULL;
+}
+
+/**
+ * bnx2fc_ulp_exit - shuts down adapter instance and frees all resources
+ *
+ * @dev cnic device handle
+ */
+static void bnx2fc_ulp_exit(struct cnic_dev *dev)
+{
+ struct bnx2fc_hba *hba;
+
+ BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n");
+
+ if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ printk(KERN_ERR PFX "bnx2fc port check: %s, flags: %lx\n",
+ dev->netdev->name, dev->flags);
+ return;
+ }
+
+ mutex_lock(&bnx2fc_dev_lock);
+ hba = bnx2fc_find_hba_for_cnic(dev);
+ if (!hba) {
+ printk(KERN_ERR PFX "bnx2fc_ulp_exit: hba not found, dev 0%p\n",
+ dev);
+ mutex_unlock(&bnx2fc_dev_lock);
+ return;
+ }
+
+ list_del_init(&hba->link);
+ adapter_count--;
+
+ if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+ /* destroy not called yet, move to quiesced list */
+ bnx2fc_netdev_cleanup(hba);
+ bnx2fc_if_destroy(hba->ctlr.lp);
+ }
+ mutex_unlock(&bnx2fc_dev_lock);
+
+ bnx2fc_ulp_stop(hba);
+ /* unregister cnic device */
+ if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
+ hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
+ bnx2fc_interface_destroy(hba);
+}
+
+/**
+ * bnx2fc_fcoe_reset - Resets the fcoe
+ *
+ * @shost: shost the reset is from
+ *
+ * Returns: always 0
+ */
+static int bnx2fc_fcoe_reset(struct Scsi_Host *shost)
+{
+ struct fc_lport *lport = shost_priv(shost);
+ fc_lport_reset(lport);
+ return 0;
+}
+
+
+static bool bnx2fc_match(struct net_device *netdev)
+{
+ mutex_lock(&bnx2fc_dev_lock);
+ if (netdev->priv_flags & IFF_802_1Q_VLAN) {
+ struct net_device *phys_dev = vlan_dev_real_dev(netdev);
+
+ if (bnx2fc_hba_lookup(phys_dev)) {
+ mutex_unlock(&bnx2fc_dev_lock);
+ return true;
+ }
+ }
+ mutex_unlock(&bnx2fc_dev_lock);
+ return false;
+}
+
+
+static struct fcoe_transport bnx2fc_transport = {
+ .name = {"bnx2fc"},
+ .attached = false,
+ .list = LIST_HEAD_INIT(bnx2fc_transport.list),
+ .match = bnx2fc_match,
+ .create = bnx2fc_create,
+ .destroy = bnx2fc_destroy,
+ .enable = bnx2fc_enable,
+ .disable = bnx2fc_disable,
+};
+
+/**
+ * bnx2fc_percpu_thread_create - Create a receive thread for an
+ * online CPU
+ *
+ * @cpu: cpu index for the online cpu
+ */
+static void bnx2fc_percpu_thread_create(unsigned int cpu)
+{
+ struct bnx2fc_percpu_s *p;
+ struct task_struct *thread;
+
+ p = &per_cpu(bnx2fc_percpu, cpu);
+
+ thread = kthread_create(bnx2fc_percpu_io_thread,
+ (void *)p,
+ "bnx2fc_thread/%d", cpu);
+ /* bind thread to the cpu */
+ if (likely(!IS_ERR(p->iothread))) {
+ kthread_bind(thread, cpu);
+ p->iothread = thread;
+ wake_up_process(thread);
+ }
+}
+
+static void bnx2fc_percpu_thread_destroy(unsigned int cpu)
+{
+ struct bnx2fc_percpu_s *p;
+ struct task_struct *thread;
+ struct bnx2fc_work *work, *tmp;
+ LIST_HEAD(work_list);
+
+ BNX2FC_MISC_DBG("destroying io thread for CPU %d\n", cpu);
+
+ /* Prevent any new work from being queued for this CPU */
+ p = &per_cpu(bnx2fc_percpu, cpu);
+ spin_lock_bh(&p->fp_work_lock);
+ thread = p->iothread;
+ p->iothread = NULL;
+
+
+ /* Free all work in the list */
+ list_for_each_entry_safe(work, tmp, &work_list, list) {
+ list_del_init(&work->list);
+ bnx2fc_process_cq_compl(work->tgt, work->wqe);
+ kfree(work);
+ }
+
+ spin_unlock_bh(&p->fp_work_lock);
+
+ if (thread)
+ kthread_stop(thread);
+}
+
+/**
+ * bnx2fc_cpu_callback - Handler for CPU hotplug events
+ *
+ * @nfb: The callback data block
+ * @action: The event triggering the callback
+ * @hcpu: The index of the CPU that the event is for
+ *
+ * This creates or destroys per-CPU data for fcoe
+ *
+ * Returns NOTIFY_OK always.
+ */
+static int bnx2fc_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ printk(PFX "CPU %x online: Create Rx thread\n", cpu);
+ bnx2fc_percpu_thread_create(cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ printk(PFX "CPU %x offline: Remove Rx thread\n", cpu);
+ bnx2fc_percpu_thread_destroy(cpu);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+/**
+ * bnx2fc_mod_init - module init entry point
+ *
+ * Initialize driver wide global data structures, and register
+ * with cnic module
+ **/
+static int __init bnx2fc_mod_init(void)
+{
+ struct fcoe_percpu_s *bg;
+ struct task_struct *l2_thread;
+ int rc = 0;
+ unsigned int cpu = 0;
+ struct bnx2fc_percpu_s *p;
+
+ printk(KERN_INFO PFX "%s", version);
+
+ /* register as a fcoe transport */
+ rc = fcoe_transport_attach(&bnx2fc_transport);
+ if (rc) {
+ printk(KERN_ERR "failed to register an fcoe transport, check "
+ "if libfcoe is loaded\n");
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&adapter_list);
+ mutex_init(&bnx2fc_dev_lock);
+ adapter_count = 0;
+
+ /* Attach FC transport template */
+ rc = bnx2fc_attach_transport();
+ if (rc)
+ goto detach_ft;
+
+ bnx2fc_wq = alloc_workqueue("bnx2fc", 0, 0);
+ if (!bnx2fc_wq) {
+ rc = -ENOMEM;
+ goto release_bt;
+ }
+
+ bg = &bnx2fc_global;
+ skb_queue_head_init(&bg->fcoe_rx_list);
+ l2_thread = kthread_create(bnx2fc_l2_rcv_thread,
+ (void *)bg,
+ "bnx2fc_l2_thread");
+ if (IS_ERR(l2_thread)) {
+ rc = PTR_ERR(l2_thread);
+ goto free_wq;
+ }
+ wake_up_process(l2_thread);
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+ bg->thread = l2_thread;
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+
+ for_each_possible_cpu(cpu) {
+ p = &per_cpu(bnx2fc_percpu, cpu);
+ INIT_LIST_HEAD(&p->work_list);
+ spin_lock_init(&p->fp_work_lock);
+ }
+
+ for_each_online_cpu(cpu) {
+ bnx2fc_percpu_thread_create(cpu);
+ }
+
+ /* Initialize per CPU interrupt thread */
+ register_hotcpu_notifier(&bnx2fc_cpu_notifier);
+
+ cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb);
+
+ return 0;
+
+free_wq:
+ destroy_workqueue(bnx2fc_wq);
+release_bt:
+ bnx2fc_release_transport();
+detach_ft:
+ fcoe_transport_detach(&bnx2fc_transport);
+out:
+ return rc;
+}
+
+static void __exit bnx2fc_mod_exit(void)
+{
+ LIST_HEAD(to_be_deleted);
+ struct bnx2fc_hba *hba, *next;
+ struct fcoe_percpu_s *bg;
+ struct task_struct *l2_thread;
+ struct sk_buff *skb;
+ unsigned int cpu = 0;
+
+ /*
+ * NOTE: Since cnic calls register_driver routine rtnl_lock,
+ * it will have higher precedence than bnx2fc_dev_lock.
+ * unregister_device() cannot be called with bnx2fc_dev_lock
+ * held.
+ */
+ mutex_lock(&bnx2fc_dev_lock);
+ list_splice(&adapter_list, &to_be_deleted);
+ INIT_LIST_HEAD(&adapter_list);
+ adapter_count = 0;
+ mutex_unlock(&bnx2fc_dev_lock);
+
+ /* Unregister with cnic */
+ list_for_each_entry_safe(hba, next, &to_be_deleted, link) {
+ list_del_init(&hba->link);
+ printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p, kref = %d\n",
+ hba, atomic_read(&hba->kref.refcount));
+ bnx2fc_ulp_stop(hba);
+ /* unregister cnic device */
+ if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED,
+ &hba->reg_with_cnic))
+ hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
+ bnx2fc_interface_destroy(hba);
+ }
+ cnic_unregister_driver(CNIC_ULP_FCOE);
+
+ /* Destroy global thread */
+ bg = &bnx2fc_global;
+ spin_lock_bh(&bg->fcoe_rx_list.lock);
+ l2_thread = bg->thread;
+ bg->thread = NULL;
+ while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL)
+ kfree_skb(skb);
+
+ spin_unlock_bh(&bg->fcoe_rx_list.lock);
+
+ if (l2_thread)
+ kthread_stop(l2_thread);
+
+ unregister_hotcpu_notifier(&bnx2fc_cpu_notifier);
+
+ /* Destroy per cpu threads */
+ for_each_online_cpu(cpu) {
+ bnx2fc_percpu_thread_destroy(cpu);
+ }
+
+ destroy_workqueue(bnx2fc_wq);
+ /*
+ * detach from scsi transport
+ * must happen after all destroys are done
+ */
+ bnx2fc_release_transport();
+
+ /* detach from fcoe transport */
+ fcoe_transport_detach(&bnx2fc_transport);
+}
+
+module_init(bnx2fc_mod_init);
+module_exit(bnx2fc_mod_exit);
+
+static struct fc_function_template bnx2fc_transport_function = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_active_fc4s = 1,
+ .show_host_maxframe_size = 1,
+
+ .show_host_port_id = 1,
+ .show_host_supported_speeds = 1,
+ .get_host_speed = fc_get_host_speed,
+ .show_host_speed = 1,
+ .show_host_port_type = 1,
+ .get_host_port_state = fc_get_host_port_state,
+ .show_host_port_state = 1,
+ .show_host_symbolic_name = 1,
+
+ .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) +
+ sizeof(struct bnx2fc_rport)),
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+ .show_host_fabric_name = 1,
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+ .get_fc_host_stats = bnx2fc_get_host_stats,
+
+ .issue_fc_host_lip = bnx2fc_fcoe_reset,
+
+ .terminate_rport_io = fc_rport_terminate_io,
+
+ .vport_create = bnx2fc_vport_create,
+ .vport_delete = bnx2fc_vport_destroy,
+ .vport_disable = bnx2fc_vport_disable,
+};
+
+static struct fc_function_template bnx2fc_vport_xport_function = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_active_fc4s = 1,
+ .show_host_maxframe_size = 1,
+
+ .show_host_port_id = 1,
+ .show_host_supported_speeds = 1,
+ .get_host_speed = fc_get_host_speed,
+ .show_host_speed = 1,
+ .show_host_port_type = 1,
+ .get_host_port_state = fc_get_host_port_state,
+ .show_host_port_state = 1,
+ .show_host_symbolic_name = 1,
+
+ .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) +
+ sizeof(struct bnx2fc_rport)),
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+ .show_host_fabric_name = 1,
+ .show_starget_node_name = 1,
+ .show_starget_port_name = 1,
+ .show_starget_port_id = 1,
+ .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+ .get_fc_host_stats = fc_get_host_stats,
+ .issue_fc_host_lip = bnx2fc_fcoe_reset,
+ .terminate_rport_io = fc_rport_terminate_io,
+};
+
+/**
+ * scsi_host_template structure used while registering with SCSI-ml
+ */
+static struct scsi_host_template bnx2fc_shost_template = {
+ .module = THIS_MODULE,
+ .name = "Broadcom Offload FCoE Initiator",
+ .queuecommand = bnx2fc_queuecommand,
+ .eh_abort_handler = bnx2fc_eh_abort, /* abts */
+ .eh_device_reset_handler = bnx2fc_eh_device_reset, /* lun reset */
+ .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */
+ .eh_host_reset_handler = fc_eh_host_reset,
+ .slave_alloc = fc_slave_alloc,
+ .change_queue_depth = fc_change_queue_depth,
+ .change_queue_type = fc_change_queue_type,
+ .this_id = -1,
+ .cmd_per_lun = 3,
+ .can_queue = (BNX2FC_MAX_OUTSTANDING_CMNDS/2),
+ .use_clustering = ENABLE_CLUSTERING,
+ .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
+ .max_sectors = 512,
+};
+
+static struct libfc_function_template bnx2fc_libfc_fcn_templ = {
+ .frame_send = bnx2fc_xmit,
+ .elsct_send = bnx2fc_elsct_send,
+ .fcp_abort_io = bnx2fc_abort_io,
+ .fcp_cleanup = bnx2fc_cleanup,
+ .rport_event_callback = bnx2fc_rport_event_handler,
+};
+
+/**
+ * bnx2fc_cnic_cb - global template of bnx2fc - cnic driver interface
+ * structure carrying callback function pointers
+ */
+static struct cnic_ulp_ops bnx2fc_cnic_cb = {
+ .owner = THIS_MODULE,
+ .cnic_init = bnx2fc_ulp_init,
+ .cnic_exit = bnx2fc_ulp_exit,
+ .cnic_start = bnx2fc_ulp_start,
+ .cnic_stop = bnx2fc_ulp_stop,
+ .indicate_kcqes = bnx2fc_indicate_kcqe,
+ .indicate_netevent = bnx2fc_indicate_netevent,
+};
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
new file mode 100644
index 000000000000..4f4096836742
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -0,0 +1,1868 @@
+/* bnx2fc_hwi.c: Broadcom NetXtreme II Linux FCoE offload driver.
+ * This file contains the code that low level functions that interact
+ * with 57712 FCoE firmware.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include "bnx2fc.h"
+
+DECLARE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
+
+static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *new_cqe_kcqe);
+static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *ofld_kcqe);
+static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *ofld_kcqe);
+static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code);
+static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *conn_destroy);
+
+int bnx2fc_send_stat_req(struct bnx2fc_hba *hba)
+{
+ struct fcoe_kwqe_stat stat_req;
+ struct kwqe *kwqe_arr[2];
+ int num_kwqes = 1;
+ int rc = 0;
+
+ memset(&stat_req, 0x00, sizeof(struct fcoe_kwqe_stat));
+ stat_req.hdr.op_code = FCOE_KWQE_OPCODE_STAT;
+ stat_req.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ stat_req.stat_params_addr_lo = (u32) hba->stats_buf_dma;
+ stat_req.stat_params_addr_hi = (u32) ((u64)hba->stats_buf_dma >> 32);
+
+ kwqe_arr[0] = (struct kwqe *) &stat_req;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
+}
+
+/**
+ * bnx2fc_send_fw_fcoe_init_msg - initiates initial handshake with FCoE f/w
+ *
+ * @hba: adapter structure pointer
+ *
+ * Send down FCoE firmware init KWQEs which initiates the initial handshake
+ * with the f/w.
+ *
+ */
+int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
+{
+ struct fcoe_kwqe_init1 fcoe_init1;
+ struct fcoe_kwqe_init2 fcoe_init2;
+ struct fcoe_kwqe_init3 fcoe_init3;
+ struct kwqe *kwqe_arr[3];
+ int num_kwqes = 3;
+ int rc = 0;
+
+ if (!hba->cnic) {
+ printk(KERN_ALERT PFX "hba->cnic NULL during fcoe fw init\n");
+ return -ENODEV;
+ }
+
+ /* fill init1 KWQE */
+ memset(&fcoe_init1, 0x00, sizeof(struct fcoe_kwqe_init1));
+ fcoe_init1.hdr.op_code = FCOE_KWQE_OPCODE_INIT1;
+ fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
+ FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ fcoe_init1.num_tasks = BNX2FC_MAX_TASKS;
+ fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX;
+ fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX;
+ fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ;
+ fcoe_init1.cq_num_wqes = BNX2FC_CQ_WQES_MAX;
+ fcoe_init1.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma;
+ fcoe_init1.dummy_buffer_addr_hi = (u32) ((u64)hba->dummy_buf_dma >> 32);
+ fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma;
+ fcoe_init1.task_list_pbl_addr_hi =
+ (u32) ((u64) hba->task_ctx_bd_dma >> 32);
+ fcoe_init1.mtu = hba->netdev->mtu;
+
+ fcoe_init1.flags = (PAGE_SHIFT <<
+ FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT);
+
+ fcoe_init1.num_sessions_log = BNX2FC_NUM_MAX_SESS_LOG;
+
+ /* fill init2 KWQE */
+ memset(&fcoe_init2, 0x00, sizeof(struct fcoe_kwqe_init2));
+ fcoe_init2.hdr.op_code = FCOE_KWQE_OPCODE_INIT2;
+ fcoe_init2.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
+ FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma;
+ fcoe_init2.hash_tbl_pbl_addr_hi = (u32)
+ ((u64) hba->hash_tbl_pbl_dma >> 32);
+
+ fcoe_init2.t2_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_dma;
+ fcoe_init2.t2_hash_tbl_addr_hi = (u32)
+ ((u64) hba->t2_hash_tbl_dma >> 32);
+
+ fcoe_init2.t2_ptr_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_ptr_dma;
+ fcoe_init2.t2_ptr_hash_tbl_addr_hi = (u32)
+ ((u64) hba->t2_hash_tbl_ptr_dma >> 32);
+
+ fcoe_init2.free_list_count = BNX2FC_NUM_MAX_SESS;
+
+ /* fill init3 KWQE */
+ memset(&fcoe_init3, 0x00, sizeof(struct fcoe_kwqe_init3));
+ fcoe_init3.hdr.op_code = FCOE_KWQE_OPCODE_INIT3;
+ fcoe_init3.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
+ FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+ fcoe_init3.error_bit_map_lo = 0xffffffff;
+ fcoe_init3.error_bit_map_hi = 0xffffffff;
+
+
+ kwqe_arr[0] = (struct kwqe *) &fcoe_init1;
+ kwqe_arr[1] = (struct kwqe *) &fcoe_init2;
+ kwqe_arr[2] = (struct kwqe *) &fcoe_init3;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
+}
+int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba)
+{
+ struct fcoe_kwqe_destroy fcoe_destroy;
+ struct kwqe *kwqe_arr[2];
+ int num_kwqes = 1;
+ int rc = -1;
+
+ /* fill destroy KWQE */
+ memset(&fcoe_destroy, 0x00, sizeof(struct fcoe_kwqe_destroy));
+ fcoe_destroy.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY;
+ fcoe_destroy.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
+ FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+ kwqe_arr[0] = (struct kwqe *) &fcoe_destroy;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ return rc;
+}
+
+/**
+ * bnx2fc_send_session_ofld_req - initiates FCoE Session offload process
+ *
+ * @port: port structure pointer
+ * @tgt: bnx2fc_rport structure pointer
+ */
+int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt)
+{
+ struct fc_lport *lport = port->lport;
+ struct bnx2fc_hba *hba = port->priv;
+ struct kwqe *kwqe_arr[4];
+ struct fcoe_kwqe_conn_offload1 ofld_req1;
+ struct fcoe_kwqe_conn_offload2 ofld_req2;
+ struct fcoe_kwqe_conn_offload3 ofld_req3;
+ struct fcoe_kwqe_conn_offload4 ofld_req4;
+ struct fc_rport_priv *rdata = tgt->rdata;
+ struct fc_rport *rport = tgt->rport;
+ int num_kwqes = 4;
+ u32 port_id;
+ int rc = 0;
+ u16 conn_id;
+
+ /* Initialize offload request 1 structure */
+ memset(&ofld_req1, 0x00, sizeof(struct fcoe_kwqe_conn_offload1));
+
+ ofld_req1.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN1;
+ ofld_req1.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+
+ conn_id = (u16)tgt->fcoe_conn_id;
+ ofld_req1.fcoe_conn_id = conn_id;
+
+
+ ofld_req1.sq_addr_lo = (u32) tgt->sq_dma;
+ ofld_req1.sq_addr_hi = (u32)((u64) tgt->sq_dma >> 32);
+
+ ofld_req1.rq_pbl_addr_lo = (u32) tgt->rq_pbl_dma;
+ ofld_req1.rq_pbl_addr_hi = (u32)((u64) tgt->rq_pbl_dma >> 32);
+
+ ofld_req1.rq_first_pbe_addr_lo = (u32) tgt->rq_dma;
+ ofld_req1.rq_first_pbe_addr_hi =
+ (u32)((u64) tgt->rq_dma >> 32);
+
+ ofld_req1.rq_prod = 0x8000;
+
+ /* Initialize offload request 2 structure */
+ memset(&ofld_req2, 0x00, sizeof(struct fcoe_kwqe_conn_offload2));
+
+ ofld_req2.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN2;
+ ofld_req2.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ ofld_req2.tx_max_fc_pay_len = rdata->maxframe_size;
+
+ ofld_req2.cq_addr_lo = (u32) tgt->cq_dma;
+ ofld_req2.cq_addr_hi = (u32)((u64)tgt->cq_dma >> 32);
+
+ ofld_req2.xferq_addr_lo = (u32) tgt->xferq_dma;
+ ofld_req2.xferq_addr_hi = (u32)((u64)tgt->xferq_dma >> 32);
+
+ ofld_req2.conn_db_addr_lo = (u32)tgt->conn_db_dma;
+ ofld_req2.conn_db_addr_hi = (u32)((u64)tgt->conn_db_dma >> 32);
+
+ /* Initialize offload request 3 structure */
+ memset(&ofld_req3, 0x00, sizeof(struct fcoe_kwqe_conn_offload3));
+
+ ofld_req3.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN3;
+ ofld_req3.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ ofld_req3.vlan_tag = hba->vlan_id <<
+ FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT;
+ ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT;
+
+ port_id = fc_host_port_id(lport->host);
+ if (port_id == 0) {
+ BNX2FC_HBA_DBG(lport, "ofld_req: port_id = 0, link down?\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Store s_id of the initiator for further reference. This will
+ * be used during disable/destroy during linkdown processing as
+ * when the lport is reset, the port_id also is reset to 0
+ */
+ tgt->sid = port_id;
+ ofld_req3.s_id[0] = (port_id & 0x000000FF);
+ ofld_req3.s_id[1] = (port_id & 0x0000FF00) >> 8;
+ ofld_req3.s_id[2] = (port_id & 0x00FF0000) >> 16;
+
+ port_id = rport->port_id;
+ ofld_req3.d_id[0] = (port_id & 0x000000FF);
+ ofld_req3.d_id[1] = (port_id & 0x0000FF00) >> 8;
+ ofld_req3.d_id[2] = (port_id & 0x00FF0000) >> 16;
+
+ ofld_req3.tx_total_conc_seqs = rdata->max_seq;
+
+ ofld_req3.tx_max_conc_seqs_c3 = rdata->max_seq;
+ ofld_req3.rx_max_fc_pay_len = lport->mfs;
+
+ ofld_req3.rx_total_conc_seqs = BNX2FC_MAX_SEQS;
+ ofld_req3.rx_max_conc_seqs_c3 = BNX2FC_MAX_SEQS;
+ ofld_req3.rx_open_seqs_exch_c3 = 1;
+
+ ofld_req3.confq_first_pbe_addr_lo = tgt->confq_dma;
+ ofld_req3.confq_first_pbe_addr_hi = (u32)((u64) tgt->confq_dma >> 32);
+
+ /* set mul_n_port_ids supported flag to 0, until it is supported */
+ ofld_req3.flags = 0;
+ /*
+ ofld_req3.flags |= (((lport->send_sp_features & FC_SP_FT_MNA) ? 1:0) <<
+ FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT);
+ */
+ /* Info from PLOGI response */
+ ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_EDTR) ? 1 : 0) <<
+ FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT);
+
+ ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) <<
+ FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT);
+
+ /* vlan flag */
+ ofld_req3.flags |= (hba->vlan_enabled <<
+ FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT);
+
+ /* C2_VALID and ACK flags are not set as they are not suppported */
+
+
+ /* Initialize offload request 4 structure */
+ memset(&ofld_req4, 0x00, sizeof(struct fcoe_kwqe_conn_offload4));
+ ofld_req4.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN4;
+ ofld_req4.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ ofld_req4.e_d_tov_timer_val = lport->e_d_tov / 20;
+
+
+ ofld_req4.src_mac_addr_lo32[0] = port->data_src_addr[5];
+ /* local mac */
+ ofld_req4.src_mac_addr_lo32[1] = port->data_src_addr[4];
+ ofld_req4.src_mac_addr_lo32[2] = port->data_src_addr[3];
+ ofld_req4.src_mac_addr_lo32[3] = port->data_src_addr[2];
+ ofld_req4.src_mac_addr_hi16[0] = port->data_src_addr[1];
+ ofld_req4.src_mac_addr_hi16[1] = port->data_src_addr[0];
+ ofld_req4.dst_mac_addr_lo32[0] = hba->ctlr.dest_addr[5];/* fcf mac */
+ ofld_req4.dst_mac_addr_lo32[1] = hba->ctlr.dest_addr[4];
+ ofld_req4.dst_mac_addr_lo32[2] = hba->ctlr.dest_addr[3];
+ ofld_req4.dst_mac_addr_lo32[3] = hba->ctlr.dest_addr[2];
+ ofld_req4.dst_mac_addr_hi16[0] = hba->ctlr.dest_addr[1];
+ ofld_req4.dst_mac_addr_hi16[1] = hba->ctlr.dest_addr[0];
+
+ ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma;
+ ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32);
+
+ ofld_req4.confq_pbl_base_addr_lo = (u32) tgt->confq_pbl_dma;
+ ofld_req4.confq_pbl_base_addr_hi =
+ (u32)((u64) tgt->confq_pbl_dma >> 32);
+
+ kwqe_arr[0] = (struct kwqe *) &ofld_req1;
+ kwqe_arr[1] = (struct kwqe *) &ofld_req2;
+ kwqe_arr[2] = (struct kwqe *) &ofld_req3;
+ kwqe_arr[3] = (struct kwqe *) &ofld_req4;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
+}
+
+/**
+ * bnx2fc_send_session_enable_req - initiates FCoE Session enablement
+ *
+ * @port: port structure pointer
+ * @tgt: bnx2fc_rport structure pointer
+ */
+static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt)
+{
+ struct kwqe *kwqe_arr[2];
+ struct bnx2fc_hba *hba = port->priv;
+ struct fcoe_kwqe_conn_enable_disable enbl_req;
+ struct fc_lport *lport = port->lport;
+ struct fc_rport *rport = tgt->rport;
+ int num_kwqes = 1;
+ int rc = 0;
+ u32 port_id;
+
+ memset(&enbl_req, 0x00,
+ sizeof(struct fcoe_kwqe_conn_enable_disable));
+ enbl_req.hdr.op_code = FCOE_KWQE_OPCODE_ENABLE_CONN;
+ enbl_req.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ enbl_req.src_mac_addr_lo32[0] = port->data_src_addr[5];
+ /* local mac */
+ enbl_req.src_mac_addr_lo32[1] = port->data_src_addr[4];
+ enbl_req.src_mac_addr_lo32[2] = port->data_src_addr[3];
+ enbl_req.src_mac_addr_lo32[3] = port->data_src_addr[2];
+ enbl_req.src_mac_addr_hi16[0] = port->data_src_addr[1];
+ enbl_req.src_mac_addr_hi16[1] = port->data_src_addr[0];
+
+ enbl_req.dst_mac_addr_lo32[0] = hba->ctlr.dest_addr[5];/* fcf mac */
+ enbl_req.dst_mac_addr_lo32[1] = hba->ctlr.dest_addr[4];
+ enbl_req.dst_mac_addr_lo32[2] = hba->ctlr.dest_addr[3];
+ enbl_req.dst_mac_addr_lo32[3] = hba->ctlr.dest_addr[2];
+ enbl_req.dst_mac_addr_hi16[0] = hba->ctlr.dest_addr[1];
+ enbl_req.dst_mac_addr_hi16[1] = hba->ctlr.dest_addr[0];
+
+ port_id = fc_host_port_id(lport->host);
+ if (port_id != tgt->sid) {
+ printk(KERN_ERR PFX "WARN: enable_req port_id = 0x%x,"
+ "sid = 0x%x\n", port_id, tgt->sid);
+ port_id = tgt->sid;
+ }
+ enbl_req.s_id[0] = (port_id & 0x000000FF);
+ enbl_req.s_id[1] = (port_id & 0x0000FF00) >> 8;
+ enbl_req.s_id[2] = (port_id & 0x00FF0000) >> 16;
+
+ port_id = rport->port_id;
+ enbl_req.d_id[0] = (port_id & 0x000000FF);
+ enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8;
+ enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
+ enbl_req.vlan_tag = hba->vlan_id <<
+ FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
+ enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
+ enbl_req.vlan_flag = hba->vlan_enabled;
+ enbl_req.context_id = tgt->context_id;
+ enbl_req.conn_id = tgt->fcoe_conn_id;
+
+ kwqe_arr[0] = (struct kwqe *) &enbl_req;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+ return rc;
+}
+
+/**
+ * bnx2fc_send_session_disable_req - initiates FCoE Session disable
+ *
+ * @port: port structure pointer
+ * @tgt: bnx2fc_rport structure pointer
+ */
+int bnx2fc_send_session_disable_req(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt)
+{
+ struct bnx2fc_hba *hba = port->priv;
+ struct fcoe_kwqe_conn_enable_disable disable_req;
+ struct kwqe *kwqe_arr[2];
+ struct fc_rport *rport = tgt->rport;
+ int num_kwqes = 1;
+ int rc = 0;
+ u32 port_id;
+
+ memset(&disable_req, 0x00,
+ sizeof(struct fcoe_kwqe_conn_enable_disable));
+ disable_req.hdr.op_code = FCOE_KWQE_OPCODE_DISABLE_CONN;
+ disable_req.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ disable_req.src_mac_addr_lo32[0] = port->data_src_addr[5];
+ disable_req.src_mac_addr_lo32[2] = port->data_src_addr[3];
+ disable_req.src_mac_addr_lo32[3] = port->data_src_addr[2];
+ disable_req.src_mac_addr_hi16[0] = port->data_src_addr[1];
+ disable_req.src_mac_addr_hi16[1] = port->data_src_addr[0];
+
+ disable_req.dst_mac_addr_lo32[0] = hba->ctlr.dest_addr[5];/* fcf mac */
+ disable_req.dst_mac_addr_lo32[1] = hba->ctlr.dest_addr[4];
+ disable_req.dst_mac_addr_lo32[2] = hba->ctlr.dest_addr[3];
+ disable_req.dst_mac_addr_lo32[3] = hba->ctlr.dest_addr[2];
+ disable_req.dst_mac_addr_hi16[0] = hba->ctlr.dest_addr[1];
+ disable_req.dst_mac_addr_hi16[1] = hba->ctlr.dest_addr[0];
+
+ port_id = tgt->sid;
+ disable_req.s_id[0] = (port_id & 0x000000FF);
+ disable_req.s_id[1] = (port_id & 0x0000FF00) >> 8;
+ disable_req.s_id[2] = (port_id & 0x00FF0000) >> 16;
+
+
+ port_id = rport->port_id;
+ disable_req.d_id[0] = (port_id & 0x000000FF);
+ disable_req.d_id[1] = (port_id & 0x0000FF00) >> 8;
+ disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
+ disable_req.context_id = tgt->context_id;
+ disable_req.conn_id = tgt->fcoe_conn_id;
+ disable_req.vlan_tag = hba->vlan_id <<
+ FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
+ disable_req.vlan_tag |=
+ 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
+ disable_req.vlan_flag = hba->vlan_enabled;
+
+ kwqe_arr[0] = (struct kwqe *) &disable_req;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
+}
+
+/**
+ * bnx2fc_send_session_destroy_req - initiates FCoE Session destroy
+ *
+ * @port: port structure pointer
+ * @tgt: bnx2fc_rport structure pointer
+ */
+int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt)
+{
+ struct fcoe_kwqe_conn_destroy destroy_req;
+ struct kwqe *kwqe_arr[2];
+ int num_kwqes = 1;
+ int rc = 0;
+
+ memset(&destroy_req, 0x00, sizeof(struct fcoe_kwqe_conn_destroy));
+ destroy_req.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY_CONN;
+ destroy_req.hdr.flags =
+ (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
+
+ destroy_req.context_id = tgt->context_id;
+ destroy_req.conn_id = tgt->fcoe_conn_id;
+
+ kwqe_arr[0] = (struct kwqe *) &destroy_req;
+
+ if (hba->cnic && hba->cnic->submit_kwqes)
+ rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes);
+
+ return rc;
+}
+
+static void bnx2fc_unsol_els_work(struct work_struct *work)
+{
+ struct bnx2fc_unsol_els *unsol_els;
+ struct fc_lport *lport;
+ struct fc_frame *fp;
+
+ unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work);
+ lport = unsol_els->lport;
+ fp = unsol_els->fp;
+ fc_exch_recv(lport, fp);
+ kfree(unsol_els);
+}
+
+void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
+ unsigned char *buf,
+ u32 frame_len, u16 l2_oxid)
+{
+ struct fcoe_port *port = tgt->port;
+ struct fc_lport *lport = port->lport;
+ struct bnx2fc_unsol_els *unsol_els;
+ struct fc_frame_header *fh;
+ struct fc_frame *fp;
+ struct sk_buff *skb;
+ u32 payload_len;
+ u32 crc;
+ u8 op;
+
+
+ unsol_els = kzalloc(sizeof(*unsol_els), GFP_ATOMIC);
+ if (!unsol_els) {
+ BNX2FC_TGT_DBG(tgt, "Unable to allocate unsol_work\n");
+ return;
+ }
+
+ BNX2FC_TGT_DBG(tgt, "l2_frame_compl l2_oxid = 0x%x, frame_len = %d\n",
+ l2_oxid, frame_len);
+
+ payload_len = frame_len - sizeof(struct fc_frame_header);
+
+ fp = fc_frame_alloc(lport, payload_len);
+ if (!fp) {
+ printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+ return;
+ }
+
+ fh = (struct fc_frame_header *) fc_frame_header_get(fp);
+ /* Copy FC Frame header and payload into the frame */
+ memcpy(fh, buf, frame_len);
+
+ if (l2_oxid != FC_XID_UNKNOWN)
+ fh->fh_ox_id = htons(l2_oxid);
+
+ skb = fp_skb(fp);
+
+ if ((fh->fh_r_ctl == FC_RCTL_ELS_REQ) ||
+ (fh->fh_r_ctl == FC_RCTL_ELS_REP)) {
+
+ if (fh->fh_type == FC_TYPE_ELS) {
+ op = fc_frame_payload_op(fp);
+ if ((op == ELS_TEST) || (op == ELS_ESTC) ||
+ (op == ELS_FAN) || (op == ELS_CSU)) {
+ /*
+ * No need to reply for these
+ * ELS requests
+ */
+ printk(KERN_ERR PFX "dropping ELS 0x%x\n", op);
+ kfree_skb(skb);
+ return;
+ }
+ }
+ crc = fcoe_fc_crc(fp);
+ fc_frame_init(fp);
+ fr_dev(fp) = lport;
+ fr_sof(fp) = FC_SOF_I3;
+ fr_eof(fp) = FC_EOF_T;
+ fr_crc(fp) = cpu_to_le32(~crc);
+ unsol_els->lport = lport;
+ unsol_els->fp = fp;
+ INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work);
+ queue_work(bnx2fc_wq, &unsol_els->unsol_els_work);
+ } else {
+ BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl);
+ kfree_skb(skb);
+ }
+}
+
+static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
+{
+ u8 num_rq;
+ struct fcoe_err_report_entry *err_entry;
+ unsigned char *rq_data;
+ unsigned char *buf = NULL, *buf1;
+ int i;
+ u16 xid;
+ u32 frame_len, len;
+ struct bnx2fc_cmd *io_req = NULL;
+ struct fcoe_task_ctx_entry *task, *task_page;
+ struct bnx2fc_hba *hba = tgt->port->priv;
+ int task_idx, index;
+ int rc = 0;
+
+
+ BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe);
+ switch (wqe & FCOE_UNSOLICITED_CQE_SUBTYPE) {
+ case FCOE_UNSOLICITED_FRAME_CQE_TYPE:
+ frame_len = (wqe & FCOE_UNSOLICITED_CQE_PKT_LEN) >>
+ FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT;
+
+ num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ;
+
+ rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq);
+ if (rq_data) {
+ buf = rq_data;
+ } else {
+ buf1 = buf = kmalloc((num_rq * BNX2FC_RQ_BUF_SZ),
+ GFP_ATOMIC);
+
+ if (!buf1) {
+ BNX2FC_TGT_DBG(tgt, "Memory alloc failure\n");
+ break;
+ }
+
+ for (i = 0; i < num_rq; i++) {
+ rq_data = (unsigned char *)
+ bnx2fc_get_next_rqe(tgt, 1);
+ len = BNX2FC_RQ_BUF_SZ;
+ memcpy(buf1, rq_data, len);
+ buf1 += len;
+ }
+ }
+ bnx2fc_process_l2_frame_compl(tgt, buf, frame_len,
+ FC_XID_UNKNOWN);
+
+ if (buf != rq_data)
+ kfree(buf);
+ bnx2fc_return_rqe(tgt, num_rq);
+ break;
+
+ case FCOE_ERROR_DETECTION_CQE_TYPE:
+ /*
+ *In case of error reporting CQE a single RQ entry
+ * is consumes.
+ */
+ spin_lock_bh(&tgt->tgt_lock);
+ num_rq = 1;
+ err_entry = (struct fcoe_err_report_entry *)
+ bnx2fc_get_next_rqe(tgt, 1);
+ xid = err_entry->fc_hdr.ox_id;
+ BNX2FC_TGT_DBG(tgt, "Unsol Error Frame OX_ID = 0x%x\n", xid);
+ BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x\n",
+ err_entry->err_warn_bitmap_hi,
+ err_entry->err_warn_bitmap_lo);
+ BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n",
+ err_entry->tx_buf_off, err_entry->rx_buf_off);
+
+ bnx2fc_return_rqe(tgt, 1);
+
+ if (xid > BNX2FC_MAX_XID) {
+ BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
+ xid);
+ spin_unlock_bh(&tgt->tgt_lock);
+ break;
+ }
+
+ task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+ task_page = (struct fcoe_task_ctx_entry *)
+ hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+
+ io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
+ if (!io_req) {
+ spin_unlock_bh(&tgt->tgt_lock);
+ break;
+ }
+
+ if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
+ printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
+ spin_unlock_bh(&tgt->tgt_lock);
+ break;
+ }
+
+ if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
+ &io_req->req_flags)) {
+ BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in "
+ "progress.. ignore unsol err\n");
+ spin_unlock_bh(&tgt->tgt_lock);
+ break;
+ }
+
+ /*
+ * If ABTS is already in progress, and FW error is
+ * received after that, do not cancel the timeout_work
+ * and let the error recovery continue by explicitly
+ * logging out the target, when the ABTS eventually
+ * times out.
+ */
+ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
+ &io_req->req_flags)) {
+ /*
+ * Cancel the timeout_work, as we received IO
+ * completion with FW error.
+ */
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* timer hold */
+
+ rc = bnx2fc_initiate_abts(io_req);
+ if (rc != SUCCESS) {
+ BNX2FC_IO_DBG(io_req, "err_warn: initiate_abts "
+ "failed. issue cleanup\n");
+ rc = bnx2fc_initiate_cleanup(io_req);
+ BUG_ON(rc);
+ }
+ } else
+ printk(KERN_ERR PFX "err_warn: io_req (0x%x) already "
+ "in ABTS processing\n", xid);
+ spin_unlock_bh(&tgt->tgt_lock);
+ break;
+
+ case FCOE_WARNING_DETECTION_CQE_TYPE:
+ /*
+ *In case of warning reporting CQE a single RQ entry
+ * is consumes.
+ */
+ num_rq = 1;
+ err_entry = (struct fcoe_err_report_entry *)
+ bnx2fc_get_next_rqe(tgt, 1);
+ xid = cpu_to_be16(err_entry->fc_hdr.ox_id);
+ BNX2FC_TGT_DBG(tgt, "Unsol Warning Frame OX_ID = 0x%x\n", xid);
+ BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x",
+ err_entry->err_warn_bitmap_hi,
+ err_entry->err_warn_bitmap_lo);
+ BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
+ err_entry->tx_buf_off, err_entry->rx_buf_off);
+
+ bnx2fc_return_rqe(tgt, 1);
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unsol Compl: Invalid CQE Subtype\n");
+ break;
+ }
+}
+
+void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
+{
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ struct fcoe_port *port = tgt->port;
+ struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_cmd *io_req;
+ int task_idx, index;
+ u16 xid;
+ u8 cmd_type;
+ u8 rx_state = 0;
+ u8 num_rq;
+
+ spin_lock_bh(&tgt->tgt_lock);
+ xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
+ if (xid >= BNX2FC_MAX_TASKS) {
+ printk(KERN_ALERT PFX "ERROR:xid out of range\n");
+ spin_unlock_bh(&tgt->tgt_lock);
+ return;
+ }
+ task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+ task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+
+ num_rq = ((task->rx_wr_tx_rd.rx_flags &
+ FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE) >>
+ FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT);
+
+ io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
+
+ if (io_req == NULL) {
+ printk(KERN_ERR PFX "ERROR? cq_compl - io_req is NULL\n");
+ spin_unlock_bh(&tgt->tgt_lock);
+ return;
+ }
+
+ /* Timestamp IO completion time */
+ cmd_type = io_req->cmd_type;
+
+ /* optimized completion path */
+ if (cmd_type == BNX2FC_SCSI_CMD) {
+ rx_state = ((task->rx_wr_tx_rd.rx_flags &
+ FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE) >>
+ FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT);
+
+ if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) {
+ bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return;
+ }
+ }
+
+ /* Process other IO completion types */
+ switch (cmd_type) {
+ case BNX2FC_SCSI_CMD:
+ if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED)
+ bnx2fc_process_abts_compl(io_req, task, num_rq);
+ else if (rx_state ==
+ FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED)
+ bnx2fc_process_cleanup_compl(io_req, task, num_rq);
+ else
+ printk(KERN_ERR PFX "Invalid rx state - %d\n",
+ rx_state);
+ break;
+
+ case BNX2FC_TASK_MGMT_CMD:
+ BNX2FC_IO_DBG(io_req, "Processing TM complete\n");
+ bnx2fc_process_tm_compl(io_req, task, num_rq);
+ break;
+
+ case BNX2FC_ABTS:
+ /*
+ * ABTS request received by firmware. ABTS response
+ * will be delivered to the task belonging to the IO
+ * that was aborted
+ */
+ BNX2FC_IO_DBG(io_req, "cq_compl- ABTS sent out by fw\n");
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ break;
+
+ case BNX2FC_ELS:
+ BNX2FC_IO_DBG(io_req, "cq_compl - call process_els_compl\n");
+ bnx2fc_process_els_compl(io_req, task, num_rq);
+ break;
+
+ case BNX2FC_CLEANUP:
+ BNX2FC_IO_DBG(io_req, "cq_compl- cleanup resp rcvd\n");
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type);
+ break;
+ }
+ spin_unlock_bh(&tgt->tgt_lock);
+}
+
+struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
+{
+ struct bnx2fc_work *work;
+ work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC);
+ if (!work)
+ return NULL;
+
+ INIT_LIST_HEAD(&work->list);
+ work->tgt = tgt;
+ work->wqe = wqe;
+ return work;
+}
+
+int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
+{
+ struct fcoe_cqe *cq;
+ u32 cq_cons;
+ struct fcoe_cqe *cqe;
+ u16 wqe;
+ bool more_cqes_found = false;
+
+ /*
+ * cq_lock is a low contention lock used to protect
+ * the CQ data structure from being freed up during
+ * the upload operation
+ */
+ spin_lock_bh(&tgt->cq_lock);
+
+ if (!tgt->cq) {
+ printk(KERN_ERR PFX "process_new_cqes: cq is NULL\n");
+ spin_unlock_bh(&tgt->cq_lock);
+ return 0;
+ }
+ cq = tgt->cq;
+ cq_cons = tgt->cq_cons_idx;
+ cqe = &cq[cq_cons];
+
+ do {
+ more_cqes_found ^= true;
+
+ while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) ==
+ (tgt->cq_curr_toggle_bit <<
+ FCOE_CQE_TOGGLE_BIT_SHIFT)) {
+
+ /* new entry on the cq */
+ if (wqe & FCOE_CQE_CQE_TYPE) {
+ /* Unsolicited event notification */
+ bnx2fc_process_unsol_compl(tgt, wqe);
+ } else {
+ struct bnx2fc_work *work = NULL;
+ struct bnx2fc_percpu_s *fps = NULL;
+ unsigned int cpu = wqe % num_possible_cpus();
+
+ fps = &per_cpu(bnx2fc_percpu, cpu);
+ spin_lock_bh(&fps->fp_work_lock);
+ if (unlikely(!fps->iothread))
+ goto unlock;
+
+ work = bnx2fc_alloc_work(tgt, wqe);
+ if (work)
+ list_add_tail(&work->list,
+ &fps->work_list);
+unlock:
+ spin_unlock_bh(&fps->fp_work_lock);
+
+ /* Pending work request completion */
+ if (fps->iothread && work)
+ wake_up_process(fps->iothread);
+ else
+ bnx2fc_process_cq_compl(tgt, wqe);
+ }
+ cqe++;
+ tgt->cq_cons_idx++;
+
+ if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) {
+ tgt->cq_cons_idx = 0;
+ cqe = cq;
+ tgt->cq_curr_toggle_bit =
+ 1 - tgt->cq_curr_toggle_bit;
+ }
+ }
+ /* Re-arm CQ */
+ if (more_cqes_found) {
+ tgt->conn_db->cq_arm.lo = -1;
+ wmb();
+ }
+ } while (more_cqes_found);
+
+ /*
+ * Commit tgt->cq_cons_idx change to the memory
+ * spin_lock implies full memory barrier, no need to smp_wmb
+ */
+
+ spin_unlock_bh(&tgt->cq_lock);
+ return 0;
+}
+
+/**
+ * bnx2fc_fastpath_notification - process global event queue (KCQ)
+ *
+ * @hba: adapter structure pointer
+ * @new_cqe_kcqe: pointer to newly DMA'd KCQ entry
+ *
+ * Fast path event notification handler
+ */
+static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *new_cqe_kcqe)
+{
+ u32 conn_id = new_cqe_kcqe->fcoe_conn_id;
+ struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id];
+
+ if (!tgt) {
+ printk(KERN_ALERT PFX "conn_id 0x%x not valid\n", conn_id);
+ return;
+ }
+
+ bnx2fc_process_new_cqes(tgt);
+}
+
+/**
+ * bnx2fc_process_ofld_cmpl - process FCoE session offload completion
+ *
+ * @hba: adapter structure pointer
+ * @ofld_kcqe: connection offload kcqe pointer
+ *
+ * handle session offload completion, enable the session if offload is
+ * successful.
+ */
+static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *ofld_kcqe)
+{
+ struct bnx2fc_rport *tgt;
+ struct fcoe_port *port;
+ u32 conn_id;
+ u32 context_id;
+ int rc;
+
+ conn_id = ofld_kcqe->fcoe_conn_id;
+ context_id = ofld_kcqe->fcoe_conn_context_id;
+ tgt = hba->tgt_ofld_list[conn_id];
+ if (!tgt) {
+ printk(KERN_ALERT PFX "ERROR:ofld_cmpl: No pending ofld req\n");
+ return;
+ }
+ BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n",
+ ofld_kcqe->fcoe_conn_context_id);
+ port = tgt->port;
+ if (hba != tgt->port->priv) {
+ printk(KERN_ALERT PFX "ERROR:ofld_cmpl: HBA mis-match\n");
+ goto ofld_cmpl_err;
+ }
+ /*
+ * cnic has allocated a context_id for this session; use this
+ * while enabling the session.
+ */
+ tgt->context_id = context_id;
+ if (ofld_kcqe->completion_status) {
+ if (ofld_kcqe->completion_status ==
+ FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) {
+ printk(KERN_ERR PFX "unable to allocate FCoE context "
+ "resources\n");
+ set_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, &tgt->flags);
+ }
+ goto ofld_cmpl_err;
+ } else {
+
+ /* now enable the session */
+ rc = bnx2fc_send_session_enable_req(port, tgt);
+ if (rc) {
+ printk(KERN_ALERT PFX "enable session failed\n");
+ goto ofld_cmpl_err;
+ }
+ }
+ return;
+ofld_cmpl_err:
+ set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->ofld_wait);
+}
+
+/**
+ * bnx2fc_process_enable_conn_cmpl - process FCoE session enable completion
+ *
+ * @hba: adapter structure pointer
+ * @ofld_kcqe: connection offload kcqe pointer
+ *
+ * handle session enable completion, mark the rport as ready
+ */
+
+static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *ofld_kcqe)
+{
+ struct bnx2fc_rport *tgt;
+ u32 conn_id;
+ u32 context_id;
+
+ context_id = ofld_kcqe->fcoe_conn_context_id;
+ conn_id = ofld_kcqe->fcoe_conn_id;
+ tgt = hba->tgt_ofld_list[conn_id];
+ if (!tgt) {
+ printk(KERN_ALERT PFX "ERROR:enbl_cmpl: No pending ofld req\n");
+ return;
+ }
+
+ BNX2FC_TGT_DBG(tgt, "Enable compl - context_id = 0x%x\n",
+ ofld_kcqe->fcoe_conn_context_id);
+
+ /*
+ * context_id should be the same for this target during offload
+ * and enable
+ */
+ if (tgt->context_id != context_id) {
+ printk(KERN_ALERT PFX "context id mis-match\n");
+ return;
+ }
+ if (hba != tgt->port->priv) {
+ printk(KERN_ALERT PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
+ goto enbl_cmpl_err;
+ }
+ if (ofld_kcqe->completion_status) {
+ goto enbl_cmpl_err;
+ } else {
+ /* enable successful - rport ready for issuing IOs */
+ set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->ofld_wait);
+ }
+ return;
+
+enbl_cmpl_err:
+ set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->ofld_wait);
+}
+
+static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *disable_kcqe)
+{
+
+ struct bnx2fc_rport *tgt;
+ u32 conn_id;
+
+ conn_id = disable_kcqe->fcoe_conn_id;
+ tgt = hba->tgt_ofld_list[conn_id];
+ if (!tgt) {
+ printk(KERN_ALERT PFX "ERROR: disable_cmpl: No disable req\n");
+ return;
+ }
+
+ BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id);
+
+ if (disable_kcqe->completion_status) {
+ printk(KERN_ALERT PFX "ERROR: Disable failed with cmpl status %d\n",
+ disable_kcqe->completion_status);
+ return;
+ } else {
+ /* disable successful */
+ BNX2FC_TGT_DBG(tgt, "disable successful\n");
+ clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_DISABLED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->upld_wait);
+ }
+}
+
+static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
+ struct fcoe_kcqe *destroy_kcqe)
+{
+ struct bnx2fc_rport *tgt;
+ u32 conn_id;
+
+ conn_id = destroy_kcqe->fcoe_conn_id;
+ tgt = hba->tgt_ofld_list[conn_id];
+ if (!tgt) {
+ printk(KERN_ALERT PFX "destroy_cmpl: No destroy req\n");
+ return;
+ }
+
+ BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id);
+
+ if (destroy_kcqe->completion_status) {
+ printk(KERN_ALERT PFX "Destroy conn failed, cmpl status %d\n",
+ destroy_kcqe->completion_status);
+ return;
+ } else {
+ /* destroy successful */
+ BNX2FC_TGT_DBG(tgt, "upload successful\n");
+ clear_bit(BNX2FC_FLAG_DISABLED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->upld_wait);
+ }
+}
+
+static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code)
+{
+ switch (err_code) {
+ case FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE:
+ printk(KERN_ERR PFX "init_failure due to invalid opcode\n");
+ break;
+
+ case FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE:
+ printk(KERN_ERR PFX "init failed due to ctx alloc failure\n");
+ break;
+
+ case FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR:
+ printk(KERN_ERR PFX "init_failure due to NIC error\n");
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unknown Error code %d\n", err_code);
+ }
+}
+
+/**
+ * bnx2fc_indicae_kcqe - process KCQE
+ *
+ * @hba: adapter structure pointer
+ * @kcqe: kcqe pointer
+ * @num_cqe: Number of completion queue elements
+ *
+ * Generic KCQ event handler
+ */
+void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
+ u32 num_cqe)
+{
+ struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
+ int i = 0;
+ struct fcoe_kcqe *kcqe = NULL;
+
+ while (i < num_cqe) {
+ kcqe = (struct fcoe_kcqe *) kcq[i++];
+
+ switch (kcqe->op_code) {
+ case FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION:
+ bnx2fc_fastpath_notification(hba, kcqe);
+ break;
+
+ case FCOE_KCQE_OPCODE_OFFLOAD_CONN:
+ bnx2fc_process_ofld_cmpl(hba, kcqe);
+ break;
+
+ case FCOE_KCQE_OPCODE_ENABLE_CONN:
+ bnx2fc_process_enable_conn_cmpl(hba, kcqe);
+ break;
+
+ case FCOE_KCQE_OPCODE_INIT_FUNC:
+ if (kcqe->completion_status !=
+ FCOE_KCQE_COMPLETION_STATUS_SUCCESS) {
+ bnx2fc_init_failure(hba,
+ kcqe->completion_status);
+ } else {
+ set_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+ bnx2fc_get_link_state(hba);
+ printk(KERN_INFO PFX "[%.2x]: FCOE_INIT passed\n",
+ (u8)hba->pcidev->bus->number);
+ }
+ break;
+
+ case FCOE_KCQE_OPCODE_DESTROY_FUNC:
+ if (kcqe->completion_status !=
+ FCOE_KCQE_COMPLETION_STATUS_SUCCESS) {
+
+ printk(KERN_ERR PFX "DESTROY failed\n");
+ } else {
+ printk(KERN_ERR PFX "DESTROY success\n");
+ }
+ hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+ wake_up_interruptible(&hba->destroy_wait);
+ break;
+
+ case FCOE_KCQE_OPCODE_DISABLE_CONN:
+ bnx2fc_process_conn_disable_cmpl(hba, kcqe);
+ break;
+
+ case FCOE_KCQE_OPCODE_DESTROY_CONN:
+ bnx2fc_process_conn_destroy_cmpl(hba, kcqe);
+ break;
+
+ case FCOE_KCQE_OPCODE_STAT_FUNC:
+ if (kcqe->completion_status !=
+ FCOE_KCQE_COMPLETION_STATUS_SUCCESS)
+ printk(KERN_ERR PFX "STAT failed\n");
+ complete(&hba->stat_req_done);
+ break;
+
+ case FCOE_KCQE_OPCODE_FCOE_ERROR:
+ /* fall thru */
+ default:
+ printk(KERN_ALERT PFX "unknown opcode 0x%x\n",
+ kcqe->op_code);
+ }
+ }
+}
+
+void bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid)
+{
+ struct fcoe_sqe *sqe;
+
+ sqe = &tgt->sq[tgt->sq_prod_idx];
+
+ /* Fill SQ WQE */
+ sqe->wqe = xid << FCOE_SQE_TASK_ID_SHIFT;
+ sqe->wqe |= tgt->sq_curr_toggle_bit << FCOE_SQE_TOGGLE_BIT_SHIFT;
+
+ /* Advance SQ Prod Idx */
+ if (++tgt->sq_prod_idx == BNX2FC_SQ_WQES_MAX) {
+ tgt->sq_prod_idx = 0;
+ tgt->sq_curr_toggle_bit = 1 - tgt->sq_curr_toggle_bit;
+ }
+}
+
+void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt)
+{
+ struct b577xx_doorbell_set_prod ev_doorbell;
+ u32 msg;
+
+ wmb();
+
+ memset(&ev_doorbell, 0, sizeof(struct b577xx_doorbell_set_prod));
+ ev_doorbell.header.header = B577XX_DOORBELL_HDR_DB_TYPE;
+
+ ev_doorbell.prod = tgt->sq_prod_idx |
+ (tgt->sq_curr_toggle_bit << 15);
+ ev_doorbell.header.header |= B577XX_FCOE_CONNECTION_TYPE <<
+ B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT;
+ msg = *((u32 *)&ev_doorbell);
+ writel(cpu_to_le32(msg), tgt->ctx_base);
+
+ mmiowb();
+
+}
+
+int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt)
+{
+ u32 context_id = tgt->context_id;
+ struct fcoe_port *port = tgt->port;
+ u32 reg_off;
+ resource_size_t reg_base;
+ struct bnx2fc_hba *hba = port->priv;
+
+ reg_base = pci_resource_start(hba->pcidev,
+ BNX2X_DOORBELL_PCI_BAR);
+ reg_off = BNX2FC_5771X_DB_PAGE_SIZE *
+ (context_id & 0x1FFFF) + DPM_TRIGER_TYPE;
+ tgt->ctx_base = ioremap_nocache(reg_base + reg_off, 4);
+ if (!tgt->ctx_base)
+ return -ENOMEM;
+ return 0;
+}
+
+char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items)
+{
+ char *buf = (char *)tgt->rq + (tgt->rq_cons_idx * BNX2FC_RQ_BUF_SZ);
+
+ if (tgt->rq_cons_idx + num_items > BNX2FC_RQ_WQES_MAX)
+ return NULL;
+
+ tgt->rq_cons_idx += num_items;
+
+ if (tgt->rq_cons_idx >= BNX2FC_RQ_WQES_MAX)
+ tgt->rq_cons_idx -= BNX2FC_RQ_WQES_MAX;
+
+ return buf;
+}
+
+void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items)
+{
+ /* return the rq buffer */
+ u32 next_prod_idx = tgt->rq_prod_idx + num_items;
+ if ((next_prod_idx & 0x7fff) == BNX2FC_RQ_WQES_MAX) {
+ /* Wrap around RQ */
+ next_prod_idx += 0x8000 - BNX2FC_RQ_WQES_MAX;
+ }
+ tgt->rq_prod_idx = next_prod_idx;
+ tgt->conn_db->rq_prod = tgt->rq_prod_idx;
+}
+
+void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u16 orig_xid)
+{
+ u8 task_type = FCOE_TASK_TYPE_EXCHANGE_CLEANUP;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ u32 context_id = tgt->context_id;
+
+ memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
+
+ /* Tx Write Rx Read */
+ task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
+ task->tx_wr_rx_rd.init_flags = task_type <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
+ task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
+ /* Common */
+ task->cmn.common_flags = context_id <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
+ task->cmn.general.cleanup_info.task_id = orig_xid;
+
+
+}
+
+void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task)
+{
+ struct bnx2fc_mp_req *mp_req = &(io_req->mp_req);
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct fc_frame_header *fc_hdr;
+ u8 task_type = 0;
+ u64 *hdr;
+ u64 temp_hdr[3];
+ u32 context_id;
+
+
+ /* Obtain task_type */
+ if ((io_req->cmd_type == BNX2FC_TASK_MGMT_CMD) ||
+ (io_req->cmd_type == BNX2FC_ELS)) {
+ task_type = FCOE_TASK_TYPE_MIDPATH;
+ } else if (io_req->cmd_type == BNX2FC_ABTS) {
+ task_type = FCOE_TASK_TYPE_ABTS;
+ }
+
+ memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
+
+ /* Setup the task from io_req for easy reference */
+ io_req->task = task;
+
+ BNX2FC_IO_DBG(io_req, "Init MP task for cmd_type = %d task_type = %d\n",
+ io_req->cmd_type, task_type);
+
+ /* Tx only */
+ if ((task_type == FCOE_TASK_TYPE_MIDPATH) ||
+ (task_type == FCOE_TASK_TYPE_UNSOLICITED)) {
+ task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
+ (u32)mp_req->mp_req_bd_dma;
+ task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
+ (u32)((u64)mp_req->mp_req_bd_dma >> 32);
+ task->tx_wr_only.sgl_ctx.mul_sges.sgl_size = 1;
+ BNX2FC_IO_DBG(io_req, "init_mp_task - bd_dma = 0x%llx\n",
+ (unsigned long long)mp_req->mp_req_bd_dma);
+ }
+
+ /* Tx Write Rx Read */
+ task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_INIT <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
+ task->tx_wr_rx_rd.init_flags = task_type <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
+ task->tx_wr_rx_rd.init_flags |= FCOE_TASK_DEV_TYPE_DISK <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT;
+ task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
+
+ /* Common */
+ task->cmn.data_2_trns = io_req->data_xfer_len;
+ context_id = tgt->context_id;
+ task->cmn.common_flags = context_id <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
+ task->cmn.common_flags |= 1 <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT;
+ task->cmn.common_flags |= 1 <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT;
+
+ /* Rx Write Tx Read */
+ fc_hdr = &(mp_req->req_fc_hdr);
+ if (task_type == FCOE_TASK_TYPE_MIDPATH) {
+ fc_hdr->fh_ox_id = cpu_to_be16(io_req->xid);
+ fc_hdr->fh_rx_id = htons(0xffff);
+ task->rx_wr_tx_rd.rx_id = 0xffff;
+ } else if (task_type == FCOE_TASK_TYPE_UNSOLICITED) {
+ fc_hdr->fh_rx_id = cpu_to_be16(io_req->xid);
+ }
+
+ /* Fill FC Header into middle path buffer */
+ hdr = (u64 *) &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr;
+ memcpy(temp_hdr, fc_hdr, sizeof(temp_hdr));
+ hdr[0] = cpu_to_be64(temp_hdr[0]);
+ hdr[1] = cpu_to_be64(temp_hdr[1]);
+ hdr[2] = cpu_to_be64(temp_hdr[2]);
+
+ /* Rx Only */
+ if (task_type == FCOE_TASK_TYPE_MIDPATH) {
+
+ task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
+ (u32)mp_req->mp_resp_bd_dma;
+ task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
+ (u32)((u64)mp_req->mp_resp_bd_dma >> 32);
+ task->rx_wr_only.sgl_ctx.mul_sges.sgl_size = 1;
+ }
+}
+
+void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task)
+{
+ u8 task_type;
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ struct io_bdt *bd_tbl = io_req->bd_tbl;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ u64 *fcp_cmnd;
+ u64 tmp_fcp_cmnd[4];
+ u32 context_id;
+ int cnt, i;
+ int bd_count;
+
+ memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
+
+ /* Setup the task from io_req for easy reference */
+ io_req->task = task;
+
+ if (sc_cmd->sc_data_direction == DMA_TO_DEVICE)
+ task_type = FCOE_TASK_TYPE_WRITE;
+ else
+ task_type = FCOE_TASK_TYPE_READ;
+
+ /* Tx only */
+ if (task_type == FCOE_TASK_TYPE_WRITE) {
+ task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
+ (u32)bd_tbl->bd_tbl_dma;
+ task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
+ (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+ task->tx_wr_only.sgl_ctx.mul_sges.sgl_size =
+ bd_tbl->bd_valid;
+ }
+
+ /*Tx Write Rx Read */
+ /* Init state to NORMAL */
+ task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_NORMAL <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
+ task->tx_wr_rx_rd.init_flags = task_type <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
+ task->tx_wr_rx_rd.init_flags |= FCOE_TASK_DEV_TYPE_DISK <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT;
+ task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
+
+ /* Common */
+ task->cmn.data_2_trns = io_req->data_xfer_len;
+ context_id = tgt->context_id;
+ task->cmn.common_flags = context_id <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
+ task->cmn.common_flags |= 1 <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT;
+ task->cmn.common_flags |= 1 <<
+ FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT;
+
+ /* Set initiative ownership */
+ task->cmn.common_flags |= FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT;
+
+ /* Set initial seq counter */
+ task->cmn.tx_low_seq_cnt = 1;
+
+ /* Set state to "waiting for the first packet" */
+ task->cmn.common_flags |= FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME;
+
+ /* Fill FCP_CMND IU */
+ fcp_cmnd = (u64 *)
+ task->cmn.general.cmd_info.fcp_cmd_payload.opaque;
+ bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd);
+
+ /* swap fcp_cmnd */
+ cnt = sizeof(struct fcp_cmnd) / sizeof(u64);
+
+ for (i = 0; i < cnt; i++) {
+ *fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]);
+ fcp_cmnd++;
+ }
+
+ /* Rx Write Tx Read */
+ task->rx_wr_tx_rd.rx_id = 0xffff;
+
+ /* Rx Only */
+ if (task_type == FCOE_TASK_TYPE_READ) {
+
+ bd_count = bd_tbl->bd_valid;
+ if (bd_count == 1) {
+
+ struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
+
+ task->rx_wr_only.sgl_ctx.single_sge.cur_buf_addr.lo =
+ fcoe_bd_tbl->buf_addr_lo;
+ task->rx_wr_only.sgl_ctx.single_sge.cur_buf_addr.hi =
+ fcoe_bd_tbl->buf_addr_hi;
+ task->rx_wr_only.sgl_ctx.single_sge.cur_buf_rem =
+ fcoe_bd_tbl->buf_len;
+ task->tx_wr_rx_rd.init_flags |= 1 <<
+ FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT;
+ } else {
+
+ task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
+ (u32)bd_tbl->bd_tbl_dma;
+ task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
+ (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+ task->rx_wr_only.sgl_ctx.mul_sges.sgl_size =
+ bd_tbl->bd_valid;
+ }
+ }
+}
+
+/**
+ * bnx2fc_setup_task_ctx - allocate and map task context
+ *
+ * @hba: pointer to adapter structure
+ *
+ * allocate memory for task context, and associated BD table to be used
+ * by firmware
+ *
+ */
+int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
+{
+ int rc = 0;
+ struct regpair *task_ctx_bdt;
+ dma_addr_t addr;
+ int i;
+
+ /*
+ * Allocate task context bd table. A page size of bd table
+ * can map 256 buffers. Each buffer contains 32 task context
+ * entries. Hence the limit with one page is 8192 task context
+ * entries.
+ */
+ hba->task_ctx_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
+ PAGE_SIZE,
+ &hba->task_ctx_bd_dma,
+ GFP_KERNEL);
+ if (!hba->task_ctx_bd_tbl) {
+ printk(KERN_ERR PFX "unable to allocate task context BDT\n");
+ rc = -1;
+ goto out;
+ }
+ memset(hba->task_ctx_bd_tbl, 0, PAGE_SIZE);
+
+ /*
+ * Allocate task_ctx which is an array of pointers pointing to
+ * a page containing 32 task contexts
+ */
+ hba->task_ctx = kzalloc((BNX2FC_TASK_CTX_ARR_SZ * sizeof(void *)),
+ GFP_KERNEL);
+ if (!hba->task_ctx) {
+ printk(KERN_ERR PFX "unable to allocate task context array\n");
+ rc = -1;
+ goto out1;
+ }
+
+ /*
+ * Allocate task_ctx_dma which is an array of dma addresses
+ */
+ hba->task_ctx_dma = kmalloc((BNX2FC_TASK_CTX_ARR_SZ *
+ sizeof(dma_addr_t)), GFP_KERNEL);
+ if (!hba->task_ctx_dma) {
+ printk(KERN_ERR PFX "unable to alloc context mapping array\n");
+ rc = -1;
+ goto out2;
+ }
+
+ task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl;
+ for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+
+ hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev,
+ PAGE_SIZE,
+ &hba->task_ctx_dma[i],
+ GFP_KERNEL);
+ if (!hba->task_ctx[i]) {
+ printk(KERN_ERR PFX "unable to alloc task context\n");
+ rc = -1;
+ goto out3;
+ }
+ memset(hba->task_ctx[i], 0, PAGE_SIZE);
+ addr = (u64)hba->task_ctx_dma[i];
+ task_ctx_bdt->hi = cpu_to_le32((u64)addr >> 32);
+ task_ctx_bdt->lo = cpu_to_le32((u32)addr);
+ task_ctx_bdt++;
+ }
+ return 0;
+
+out3:
+ for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ if (hba->task_ctx[i]) {
+
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->task_ctx[i], hba->task_ctx_dma[i]);
+ hba->task_ctx[i] = NULL;
+ }
+ }
+
+ kfree(hba->task_ctx_dma);
+ hba->task_ctx_dma = NULL;
+out2:
+ kfree(hba->task_ctx);
+ hba->task_ctx = NULL;
+out1:
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->task_ctx_bd_tbl, hba->task_ctx_bd_dma);
+ hba->task_ctx_bd_tbl = NULL;
+out:
+ return rc;
+}
+
+void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba)
+{
+ int i;
+
+ if (hba->task_ctx_bd_tbl) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->task_ctx_bd_tbl,
+ hba->task_ctx_bd_dma);
+ hba->task_ctx_bd_tbl = NULL;
+ }
+
+ if (hba->task_ctx) {
+ for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ if (hba->task_ctx[i]) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->task_ctx[i],
+ hba->task_ctx_dma[i]);
+ hba->task_ctx[i] = NULL;
+ }
+ }
+ kfree(hba->task_ctx);
+ hba->task_ctx = NULL;
+ }
+
+ kfree(hba->task_ctx_dma);
+ hba->task_ctx_dma = NULL;
+}
+
+static void bnx2fc_free_hash_table(struct bnx2fc_hba *hba)
+{
+ int i;
+ int segment_count;
+ int hash_table_size;
+ u32 *pbl;
+
+ segment_count = hba->hash_tbl_segment_count;
+ hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL *
+ sizeof(struct fcoe_hash_table_entry);
+
+ pbl = hba->hash_tbl_pbl;
+ for (i = 0; i < segment_count; ++i) {
+ dma_addr_t dma_address;
+
+ dma_address = le32_to_cpu(*pbl);
+ ++pbl;
+ dma_address += ((u64)le32_to_cpu(*pbl)) << 32;
+ ++pbl;
+ dma_free_coherent(&hba->pcidev->dev,
+ BNX2FC_HASH_TBL_CHUNK_SIZE,
+ hba->hash_tbl_segments[i],
+ dma_address);
+
+ }
+
+ if (hba->hash_tbl_pbl) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->hash_tbl_pbl,
+ hba->hash_tbl_pbl_dma);
+ hba->hash_tbl_pbl = NULL;
+ }
+}
+
+static int bnx2fc_allocate_hash_table(struct bnx2fc_hba *hba)
+{
+ int i;
+ int hash_table_size;
+ int segment_count;
+ int segment_array_size;
+ int dma_segment_array_size;
+ dma_addr_t *dma_segment_array;
+ u32 *pbl;
+
+ hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL *
+ sizeof(struct fcoe_hash_table_entry);
+
+ segment_count = hash_table_size + BNX2FC_HASH_TBL_CHUNK_SIZE - 1;
+ segment_count /= BNX2FC_HASH_TBL_CHUNK_SIZE;
+ hba->hash_tbl_segment_count = segment_count;
+
+ segment_array_size = segment_count * sizeof(*hba->hash_tbl_segments);
+ hba->hash_tbl_segments = kzalloc(segment_array_size, GFP_KERNEL);
+ if (!hba->hash_tbl_segments) {
+ printk(KERN_ERR PFX "hash table pointers alloc failed\n");
+ return -ENOMEM;
+ }
+ dma_segment_array_size = segment_count * sizeof(*dma_segment_array);
+ dma_segment_array = kzalloc(dma_segment_array_size, GFP_KERNEL);
+ if (!dma_segment_array) {
+ printk(KERN_ERR PFX "hash table pointers (dma) alloc failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < segment_count; ++i) {
+ hba->hash_tbl_segments[i] =
+ dma_alloc_coherent(&hba->pcidev->dev,
+ BNX2FC_HASH_TBL_CHUNK_SIZE,
+ &dma_segment_array[i],
+ GFP_KERNEL);
+ if (!hba->hash_tbl_segments[i]) {
+ printk(KERN_ERR PFX "hash segment alloc failed\n");
+ while (--i >= 0) {
+ dma_free_coherent(&hba->pcidev->dev,
+ BNX2FC_HASH_TBL_CHUNK_SIZE,
+ hba->hash_tbl_segments[i],
+ dma_segment_array[i]);
+ hba->hash_tbl_segments[i] = NULL;
+ }
+ kfree(dma_segment_array);
+ return -ENOMEM;
+ }
+ memset(hba->hash_tbl_segments[i], 0,
+ BNX2FC_HASH_TBL_CHUNK_SIZE);
+ }
+
+ hba->hash_tbl_pbl = dma_alloc_coherent(&hba->pcidev->dev,
+ PAGE_SIZE,
+ &hba->hash_tbl_pbl_dma,
+ GFP_KERNEL);
+ if (!hba->hash_tbl_pbl) {
+ printk(KERN_ERR PFX "hash table pbl alloc failed\n");
+ kfree(dma_segment_array);
+ return -ENOMEM;
+ }
+ memset(hba->hash_tbl_pbl, 0, PAGE_SIZE);
+
+ pbl = hba->hash_tbl_pbl;
+ for (i = 0; i < segment_count; ++i) {
+ u64 paddr = dma_segment_array[i];
+ *pbl = cpu_to_le32((u32) paddr);
+ ++pbl;
+ *pbl = cpu_to_le32((u32) (paddr >> 32));
+ ++pbl;
+ }
+ pbl = hba->hash_tbl_pbl;
+ i = 0;
+ while (*pbl && *(pbl + 1)) {
+ u32 lo;
+ u32 hi;
+ lo = *pbl;
+ ++pbl;
+ hi = *pbl;
+ ++pbl;
+ ++i;
+ }
+ kfree(dma_segment_array);
+ return 0;
+}
+
+/**
+ * bnx2fc_setup_fw_resc - Allocate and map hash table and dummy buffer
+ *
+ * @hba: Pointer to adapter structure
+ *
+ */
+int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba)
+{
+ u64 addr;
+ u32 mem_size;
+ int i;
+
+ if (bnx2fc_allocate_hash_table(hba))
+ return -ENOMEM;
+
+ mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair);
+ hba->t2_hash_tbl_ptr = dma_alloc_coherent(&hba->pcidev->dev, mem_size,
+ &hba->t2_hash_tbl_ptr_dma,
+ GFP_KERNEL);
+ if (!hba->t2_hash_tbl_ptr) {
+ printk(KERN_ERR PFX "unable to allocate t2 hash table ptr\n");
+ bnx2fc_free_fw_resc(hba);
+ return -ENOMEM;
+ }
+ memset(hba->t2_hash_tbl_ptr, 0x00, mem_size);
+
+ mem_size = BNX2FC_NUM_MAX_SESS *
+ sizeof(struct fcoe_t2_hash_table_entry);
+ hba->t2_hash_tbl = dma_alloc_coherent(&hba->pcidev->dev, mem_size,
+ &hba->t2_hash_tbl_dma,
+ GFP_KERNEL);
+ if (!hba->t2_hash_tbl) {
+ printk(KERN_ERR PFX "unable to allocate t2 hash table\n");
+ bnx2fc_free_fw_resc(hba);
+ return -ENOMEM;
+ }
+ memset(hba->t2_hash_tbl, 0x00, mem_size);
+ for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) {
+ addr = (unsigned long) hba->t2_hash_tbl_dma +
+ ((i+1) * sizeof(struct fcoe_t2_hash_table_entry));
+ hba->t2_hash_tbl[i].next.lo = addr & 0xffffffff;
+ hba->t2_hash_tbl[i].next.hi = addr >> 32;
+ }
+
+ hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+ PAGE_SIZE, &hba->dummy_buf_dma,
+ GFP_KERNEL);
+ if (!hba->dummy_buffer) {
+ printk(KERN_ERR PFX "unable to alloc MP Dummy Buffer\n");
+ bnx2fc_free_fw_resc(hba);
+ return -ENOMEM;
+ }
+
+ hba->stats_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+ PAGE_SIZE,
+ &hba->stats_buf_dma,
+ GFP_KERNEL);
+ if (!hba->stats_buffer) {
+ printk(KERN_ERR PFX "unable to alloc Stats Buffer\n");
+ bnx2fc_free_fw_resc(hba);
+ return -ENOMEM;
+ }
+ memset(hba->stats_buffer, 0x00, PAGE_SIZE);
+
+ return 0;
+}
+
+void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba)
+{
+ u32 mem_size;
+
+ if (hba->stats_buffer) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->stats_buffer, hba->stats_buf_dma);
+ hba->stats_buffer = NULL;
+ }
+
+ if (hba->dummy_buffer) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ hba->dummy_buffer, hba->dummy_buf_dma);
+ hba->dummy_buffer = NULL;
+ }
+
+ if (hba->t2_hash_tbl_ptr) {
+ mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair);
+ dma_free_coherent(&hba->pcidev->dev, mem_size,
+ hba->t2_hash_tbl_ptr,
+ hba->t2_hash_tbl_ptr_dma);
+ hba->t2_hash_tbl_ptr = NULL;
+ }
+
+ if (hba->t2_hash_tbl) {
+ mem_size = BNX2FC_NUM_MAX_SESS *
+ sizeof(struct fcoe_t2_hash_table_entry);
+ dma_free_coherent(&hba->pcidev->dev, mem_size,
+ hba->t2_hash_tbl, hba->t2_hash_tbl_dma);
+ hba->t2_hash_tbl = NULL;
+ }
+ bnx2fc_free_hash_table(hba);
+}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
new file mode 100644
index 000000000000..0f1dd23730db
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -0,0 +1,1833 @@
+/* bnx2fc_io.c: Broadcom NetXtreme II Linux FCoE offload driver.
+ * IO manager and SCSI IO processing.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include "bnx2fc.h"
+static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len,
+ int bd_index);
+static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req);
+static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req);
+static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
+ struct bnx2fc_cmd *io_req);
+static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req);
+static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req);
+static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
+ struct fcoe_fcp_rsp_payload *fcp_rsp,
+ u8 num_rq);
+
+void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
+ unsigned int timer_msec)
+{
+ struct bnx2fc_hba *hba = io_req->port->priv;
+
+ if (queue_delayed_work(hba->timer_work_queue, &io_req->timeout_work,
+ msecs_to_jiffies(timer_msec)))
+ kref_get(&io_req->refcount);
+}
+
+static void bnx2fc_cmd_timeout(struct work_struct *work)
+{
+ struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd,
+ timeout_work.work);
+ struct fc_lport *lport;
+ struct fc_rport_priv *rdata;
+ u8 cmd_type = io_req->cmd_type;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ int logo_issued;
+ int rc;
+
+ BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d,"
+ "req_flags = %lx\n", cmd_type, io_req->req_flags);
+
+ spin_lock_bh(&tgt->tgt_lock);
+ if (test_and_clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags)) {
+ clear_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags);
+ /*
+ * ideally we should hold the io_req until RRQ complets,
+ * and release io_req from timeout hold.
+ */
+ spin_unlock_bh(&tgt->tgt_lock);
+ bnx2fc_send_rrq(io_req);
+ return;
+ }
+ if (test_and_clear_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags)) {
+ BNX2FC_IO_DBG(io_req, "IO ready for reuse now\n");
+ goto done;
+ }
+
+ switch (cmd_type) {
+ case BNX2FC_SCSI_CMD:
+ if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
+ &io_req->req_flags)) {
+ /* Handle eh_abort timeout */
+ BNX2FC_IO_DBG(io_req, "eh_abort timed out\n");
+ complete(&io_req->tm_done);
+ } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS,
+ &io_req->req_flags)) {
+ /* Handle internally generated ABTS timeout */
+ BNX2FC_IO_DBG(io_req, "ABTS timed out refcnt = %d\n",
+ io_req->refcount.refcount.counter);
+ if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
+ &io_req->req_flags))) {
+
+ lport = io_req->port->lport;
+ rdata = io_req->tgt->rdata;
+ logo_issued = test_and_set_bit(
+ BNX2FC_FLAG_EXPL_LOGO,
+ &tgt->flags);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ /* Explicitly logo the target */
+ if (!logo_issued) {
+ BNX2FC_IO_DBG(io_req, "Explicit "
+ "logo - tgt flags = 0x%lx\n",
+ tgt->flags);
+
+ mutex_lock(&lport->disc.disc_mutex);
+ lport->tt.rport_logoff(rdata);
+ mutex_unlock(&lport->disc.disc_mutex);
+ }
+ return;
+ }
+ } else {
+ /* Hanlde IO timeout */
+ BNX2FC_IO_DBG(io_req, "IO timed out. issue ABTS\n");
+ if (test_and_set_bit(BNX2FC_FLAG_IO_COMPL,
+ &io_req->req_flags)) {
+ BNX2FC_IO_DBG(io_req, "IO completed before "
+ " timer expiry\n");
+ goto done;
+ }
+
+ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
+ &io_req->req_flags)) {
+ rc = bnx2fc_initiate_abts(io_req);
+ if (rc == SUCCESS)
+ goto done;
+ /*
+ * Explicitly logo the target if
+ * abts initiation fails
+ */
+ lport = io_req->port->lport;
+ rdata = io_req->tgt->rdata;
+ logo_issued = test_and_set_bit(
+ BNX2FC_FLAG_EXPL_LOGO,
+ &tgt->flags);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ if (!logo_issued) {
+ BNX2FC_IO_DBG(io_req, "Explicit "
+ "logo - tgt flags = 0x%lx\n",
+ tgt->flags);
+
+
+ mutex_lock(&lport->disc.disc_mutex);
+ lport->tt.rport_logoff(rdata);
+ mutex_unlock(&lport->disc.disc_mutex);
+ }
+ return;
+ } else {
+ BNX2FC_IO_DBG(io_req, "IO already in "
+ "ABTS processing\n");
+ }
+ }
+ break;
+ case BNX2FC_ELS:
+
+ if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
+ BNX2FC_IO_DBG(io_req, "ABTS for ELS timed out\n");
+
+ if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
+ &io_req->req_flags)) {
+ lport = io_req->port->lport;
+ rdata = io_req->tgt->rdata;
+ logo_issued = test_and_set_bit(
+ BNX2FC_FLAG_EXPL_LOGO,
+ &tgt->flags);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ /* Explicitly logo the target */
+ if (!logo_issued) {
+ BNX2FC_IO_DBG(io_req, "Explicitly logo"
+ "(els)\n");
+ mutex_lock(&lport->disc.disc_mutex);
+ lport->tt.rport_logoff(rdata);
+ mutex_unlock(&lport->disc.disc_mutex);
+ }
+ return;
+ }
+ } else {
+ /*
+ * Handle ELS timeout.
+ * tgt_lock is used to sync compl path and timeout
+ * path. If els compl path is processing this IO, we
+ * have nothing to do here, just release the timer hold
+ */
+ BNX2FC_IO_DBG(io_req, "ELS timed out\n");
+ if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE,
+ &io_req->req_flags))
+ goto done;
+
+ /* Indicate the cb_func that this ELS is timed out */
+ set_bit(BNX2FC_FLAG_ELS_TIMEOUT, &io_req->req_flags);
+
+ if ((io_req->cb_func) && (io_req->cb_arg)) {
+ io_req->cb_func(io_req->cb_arg);
+ io_req->cb_arg = NULL;
+ }
+ }
+ break;
+ default:
+ printk(KERN_ERR PFX "cmd_timeout: invalid cmd_type %d\n",
+ cmd_type);
+ break;
+ }
+
+done:
+ /* release the cmd that was held when timer was set */
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+}
+
+static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code)
+{
+ /* Called with host lock held */
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+
+ /*
+ * active_cmd_queue may have other command types as well,
+ * and during flush operation, we want to error back only
+ * scsi commands.
+ */
+ if (io_req->cmd_type != BNX2FC_SCSI_CMD)
+ return;
+
+ BNX2FC_IO_DBG(io_req, "scsi_done. err_code = 0x%x\n", err_code);
+ bnx2fc_unmap_sg_list(io_req);
+ io_req->sc_cmd = NULL;
+ if (!sc_cmd) {
+ printk(KERN_ERR PFX "scsi_done - sc_cmd NULL. "
+ "IO(0x%x) already cleaned up\n",
+ io_req->xid);
+ return;
+ }
+ sc_cmd->result = err_code << 16;
+
+ BNX2FC_IO_DBG(io_req, "sc=%p, result=0x%x, retries=%d, allowed=%d\n",
+ sc_cmd, host_byte(sc_cmd->result), sc_cmd->retries,
+ sc_cmd->allowed);
+ scsi_set_resid(sc_cmd, scsi_bufflen(sc_cmd));
+ sc_cmd->SCp.ptr = NULL;
+ sc_cmd->scsi_done(sc_cmd);
+}
+
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
+ u16 min_xid, u16 max_xid)
+{
+ struct bnx2fc_cmd_mgr *cmgr;
+ struct io_bdt *bdt_info;
+ struct bnx2fc_cmd *io_req;
+ size_t len;
+ u32 mem_size;
+ u16 xid;
+ int i;
+ int num_ios;
+ size_t bd_tbl_sz;
+
+ if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) {
+ printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \
+ and max_xid 0x%x\n", min_xid, max_xid);
+ return NULL;
+ }
+ BNX2FC_MISC_DBG("min xid 0x%x, max xid 0x%x\n", min_xid, max_xid);
+
+ num_ios = max_xid - min_xid + 1;
+ len = (num_ios * (sizeof(struct bnx2fc_cmd *)));
+ len += sizeof(struct bnx2fc_cmd_mgr);
+
+ cmgr = kzalloc(len, GFP_KERNEL);
+ if (!cmgr) {
+ printk(KERN_ERR PFX "failed to alloc cmgr\n");
+ return NULL;
+ }
+
+ cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) *
+ num_possible_cpus(), GFP_KERNEL);
+ if (!cmgr->free_list) {
+ printk(KERN_ERR PFX "failed to alloc free_list\n");
+ goto mem_err;
+ }
+
+ cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) *
+ num_possible_cpus(), GFP_KERNEL);
+ if (!cmgr->free_list_lock) {
+ printk(KERN_ERR PFX "failed to alloc free_list_lock\n");
+ goto mem_err;
+ }
+
+ cmgr->hba = hba;
+ cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1);
+
+ for (i = 0; i < num_possible_cpus(); i++) {
+ INIT_LIST_HEAD(&cmgr->free_list[i]);
+ spin_lock_init(&cmgr->free_list_lock[i]);
+ }
+
+ /* Pre-allocated pool of bnx2fc_cmds */
+ xid = BNX2FC_MIN_XID;
+ for (i = 0; i < num_ios; i++) {
+ io_req = kzalloc(sizeof(*io_req), GFP_KERNEL);
+
+ if (!io_req) {
+ printk(KERN_ERR PFX "failed to alloc io_req\n");
+ goto mem_err;
+ }
+
+ INIT_LIST_HEAD(&io_req->link);
+ INIT_DELAYED_WORK(&io_req->timeout_work, bnx2fc_cmd_timeout);
+
+ io_req->xid = xid++;
+ if (io_req->xid >= BNX2FC_MAX_OUTSTANDING_CMNDS)
+ printk(KERN_ERR PFX "ERROR allocating xids - 0x%x\n",
+ io_req->xid);
+ list_add_tail(&io_req->link,
+ &cmgr->free_list[io_req->xid % num_possible_cpus()]);
+ io_req++;
+ }
+
+ /* Allocate pool of io_bdts - one for each bnx2fc_cmd */
+ mem_size = num_ios * sizeof(struct io_bdt *);
+ cmgr->io_bdt_pool = kmalloc(mem_size, GFP_KERNEL);
+ if (!cmgr->io_bdt_pool) {
+ printk(KERN_ERR PFX "failed to alloc io_bdt_pool\n");
+ goto mem_err;
+ }
+
+ mem_size = sizeof(struct io_bdt);
+ for (i = 0; i < num_ios; i++) {
+ cmgr->io_bdt_pool[i] = kmalloc(mem_size, GFP_KERNEL);
+ if (!cmgr->io_bdt_pool[i]) {
+ printk(KERN_ERR PFX "failed to alloc "
+ "io_bdt_pool[%d]\n", i);
+ goto mem_err;
+ }
+ }
+
+ /* Allocate an map fcoe_bdt_ctx structures */
+ bd_tbl_sz = BNX2FC_MAX_BDS_PER_CMD * sizeof(struct fcoe_bd_ctx);
+ for (i = 0; i < num_ios; i++) {
+ bdt_info = cmgr->io_bdt_pool[i];
+ bdt_info->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev,
+ bd_tbl_sz,
+ &bdt_info->bd_tbl_dma,
+ GFP_KERNEL);
+ if (!bdt_info->bd_tbl) {
+ printk(KERN_ERR PFX "failed to alloc "
+ "bdt_tbl[%d]\n", i);
+ goto mem_err;
+ }
+ }
+
+ return cmgr;
+
+mem_err:
+ bnx2fc_cmd_mgr_free(cmgr);
+ return NULL;
+}
+
+void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr)
+{
+ struct io_bdt *bdt_info;
+ struct bnx2fc_hba *hba = cmgr->hba;
+ size_t bd_tbl_sz;
+ u16 min_xid = BNX2FC_MIN_XID;
+ u16 max_xid = BNX2FC_MAX_XID;
+ int num_ios;
+ int i;
+
+ num_ios = max_xid - min_xid + 1;
+
+ /* Free fcoe_bdt_ctx structures */
+ if (!cmgr->io_bdt_pool)
+ goto free_cmd_pool;
+
+ bd_tbl_sz = BNX2FC_MAX_BDS_PER_CMD * sizeof(struct fcoe_bd_ctx);
+ for (i = 0; i < num_ios; i++) {
+ bdt_info = cmgr->io_bdt_pool[i];
+ if (bdt_info->bd_tbl) {
+ dma_free_coherent(&hba->pcidev->dev, bd_tbl_sz,
+ bdt_info->bd_tbl,
+ bdt_info->bd_tbl_dma);
+ bdt_info->bd_tbl = NULL;
+ }
+ }
+
+ /* Destroy io_bdt pool */
+ for (i = 0; i < num_ios; i++) {
+ kfree(cmgr->io_bdt_pool[i]);
+ cmgr->io_bdt_pool[i] = NULL;
+ }
+
+ kfree(cmgr->io_bdt_pool);
+ cmgr->io_bdt_pool = NULL;
+
+free_cmd_pool:
+ kfree(cmgr->free_list_lock);
+
+ /* Destroy cmd pool */
+ if (!cmgr->free_list)
+ goto free_cmgr;
+
+ for (i = 0; i < num_possible_cpus(); i++) {
+ struct list_head *list;
+ struct list_head *tmp;
+
+ list_for_each_safe(list, tmp, &cmgr->free_list[i]) {
+ struct bnx2fc_cmd *io_req = (struct bnx2fc_cmd *)list;
+ list_del(&io_req->link);
+ kfree(io_req);
+ }
+ }
+ kfree(cmgr->free_list);
+free_cmgr:
+ /* Free command manager itself */
+ kfree(cmgr);
+}
+
+struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type)
+{
+ struct fcoe_port *port = tgt->port;
+ struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+ struct bnx2fc_cmd *io_req;
+ struct list_head *listp;
+ struct io_bdt *bd_tbl;
+ u32 max_sqes;
+ u16 xid;
+
+ max_sqes = tgt->max_sqes;
+ switch (type) {
+ case BNX2FC_TASK_MGMT_CMD:
+ max_sqes = BNX2FC_TM_MAX_SQES;
+ break;
+ case BNX2FC_ELS:
+ max_sqes = BNX2FC_ELS_MAX_SQES;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * NOTE: Free list insertions and deletions are protected with
+ * cmgr lock
+ */
+ spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+ if ((list_empty(&(cmd_mgr->free_list[smp_processor_id()]))) ||
+ (tgt->num_active_ios.counter >= max_sqes)) {
+ BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available "
+ "ios(%d):sqes(%d)\n",
+ tgt->num_active_ios.counter, tgt->max_sqes);
+ if (list_empty(&(cmd_mgr->free_list[smp_processor_id()])))
+ printk(KERN_ERR PFX "elstm_alloc: list_empty\n");
+ spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+ return NULL;
+ }
+
+ listp = (struct list_head *)
+ cmd_mgr->free_list[smp_processor_id()].next;
+ list_del_init(listp);
+ io_req = (struct bnx2fc_cmd *) listp;
+ xid = io_req->xid;
+ cmd_mgr->cmds[xid] = io_req;
+ atomic_inc(&tgt->num_active_ios);
+ spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+
+ INIT_LIST_HEAD(&io_req->link);
+
+ io_req->port = port;
+ io_req->cmd_mgr = cmd_mgr;
+ io_req->req_flags = 0;
+ io_req->cmd_type = type;
+
+ /* Bind io_bdt for this io_req */
+ /* Have a static link between io_req and io_bdt_pool */
+ bd_tbl = io_req->bd_tbl = cmd_mgr->io_bdt_pool[xid];
+ bd_tbl->io_req = io_req;
+
+ /* Hold the io_req against deletion */
+ kref_init(&io_req->refcount);
+ return io_req;
+}
+static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
+{
+ struct fcoe_port *port = tgt->port;
+ struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+ struct bnx2fc_cmd *io_req;
+ struct list_head *listp;
+ struct io_bdt *bd_tbl;
+ u32 max_sqes;
+ u16 xid;
+
+ max_sqes = BNX2FC_SCSI_MAX_SQES;
+ /*
+ * NOTE: Free list insertions and deletions are protected with
+ * cmgr lock
+ */
+ spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+ if ((list_empty(&cmd_mgr->free_list[smp_processor_id()])) ||
+ (tgt->num_active_ios.counter >= max_sqes)) {
+ spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+ return NULL;
+ }
+
+ listp = (struct list_head *)
+ cmd_mgr->free_list[smp_processor_id()].next;
+ list_del_init(listp);
+ io_req = (struct bnx2fc_cmd *) listp;
+ xid = io_req->xid;
+ cmd_mgr->cmds[xid] = io_req;
+ atomic_inc(&tgt->num_active_ios);
+ spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+
+ INIT_LIST_HEAD(&io_req->link);
+
+ io_req->port = port;
+ io_req->cmd_mgr = cmd_mgr;
+ io_req->req_flags = 0;
+
+ /* Bind io_bdt for this io_req */
+ /* Have a static link between io_req and io_bdt_pool */
+ bd_tbl = io_req->bd_tbl = cmd_mgr->io_bdt_pool[xid];
+ bd_tbl->io_req = io_req;
+
+ /* Hold the io_req against deletion */
+ kref_init(&io_req->refcount);
+ return io_req;
+}
+
+void bnx2fc_cmd_release(struct kref *ref)
+{
+ struct bnx2fc_cmd *io_req = container_of(ref,
+ struct bnx2fc_cmd, refcount);
+ struct bnx2fc_cmd_mgr *cmd_mgr = io_req->cmd_mgr;
+
+ spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+ if (io_req->cmd_type != BNX2FC_SCSI_CMD)
+ bnx2fc_free_mp_resc(io_req);
+ cmd_mgr->cmds[io_req->xid] = NULL;
+ /* Delete IO from retire queue */
+ list_del_init(&io_req->link);
+ /* Add it to the free list */
+ list_add(&io_req->link,
+ &cmd_mgr->free_list[smp_processor_id()]);
+ atomic_dec(&io_req->tgt->num_active_ios);
+ spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]);
+}
+
+static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
+{
+ struct bnx2fc_mp_req *mp_req = &(io_req->mp_req);
+ struct bnx2fc_hba *hba = io_req->port->priv;
+ size_t sz = sizeof(struct fcoe_bd_ctx);
+
+ /* clear tm flags */
+ mp_req->tm_flags = 0;
+ if (mp_req->mp_req_bd) {
+ dma_free_coherent(&hba->pcidev->dev, sz,
+ mp_req->mp_req_bd,
+ mp_req->mp_req_bd_dma);
+ mp_req->mp_req_bd = NULL;
+ }
+ if (mp_req->mp_resp_bd) {
+ dma_free_coherent(&hba->pcidev->dev, sz,
+ mp_req->mp_resp_bd,
+ mp_req->mp_resp_bd_dma);
+ mp_req->mp_resp_bd = NULL;
+ }
+ if (mp_req->req_buf) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->req_buf,
+ mp_req->req_buf_dma);
+ mp_req->req_buf = NULL;
+ }
+ if (mp_req->resp_buf) {
+ dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ mp_req->resp_buf,
+ mp_req->resp_buf_dma);
+ mp_req->resp_buf = NULL;
+ }
+}
+
+int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
+{
+ struct bnx2fc_mp_req *mp_req;
+ struct fcoe_bd_ctx *mp_req_bd;
+ struct fcoe_bd_ctx *mp_resp_bd;
+ struct bnx2fc_hba *hba = io_req->port->priv;
+ dma_addr_t addr;
+ size_t sz;
+
+ mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req);
+ memset(mp_req, 0, sizeof(struct bnx2fc_mp_req));
+
+ mp_req->req_len = sizeof(struct fcp_cmnd);
+ io_req->data_xfer_len = mp_req->req_len;
+ mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ &mp_req->req_buf_dma,
+ GFP_ATOMIC);
+ if (!mp_req->req_buf) {
+ printk(KERN_ERR PFX "unable to alloc MP req buffer\n");
+ bnx2fc_free_mp_resc(io_req);
+ return FAILED;
+ }
+
+ mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+ &mp_req->resp_buf_dma,
+ GFP_ATOMIC);
+ if (!mp_req->resp_buf) {
+ printk(KERN_ERR PFX "unable to alloc TM resp buffer\n");
+ bnx2fc_free_mp_resc(io_req);
+ return FAILED;
+ }
+ memset(mp_req->req_buf, 0, PAGE_SIZE);
+ memset(mp_req->resp_buf, 0, PAGE_SIZE);
+
+ /* Allocate and map mp_req_bd and mp_resp_bd */
+ sz = sizeof(struct fcoe_bd_ctx);
+ mp_req->mp_req_bd = dma_alloc_coherent(&hba->pcidev->dev, sz,
+ &mp_req->mp_req_bd_dma,
+ GFP_ATOMIC);
+ if (!mp_req->mp_req_bd) {
+ printk(KERN_ERR PFX "unable to alloc MP req bd\n");
+ bnx2fc_free_mp_resc(io_req);
+ return FAILED;
+ }
+ mp_req->mp_resp_bd = dma_alloc_coherent(&hba->pcidev->dev, sz,
+ &mp_req->mp_resp_bd_dma,
+ GFP_ATOMIC);
+ if (!mp_req->mp_req_bd) {
+ printk(KERN_ERR PFX "unable to alloc MP resp bd\n");
+ bnx2fc_free_mp_resc(io_req);
+ return FAILED;
+ }
+ /* Fill bd table */
+ addr = mp_req->req_buf_dma;
+ mp_req_bd = mp_req->mp_req_bd;
+ mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff;
+ mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32);
+ mp_req_bd->buf_len = PAGE_SIZE;
+ mp_req_bd->flags = 0;
+
+ /*
+ * MP buffer is either a task mgmt command or an ELS.
+ * So the assumption is that it consumes a single bd
+ * entry in the bd table
+ */
+ mp_resp_bd = mp_req->mp_resp_bd;
+ addr = mp_req->resp_buf_dma;
+ mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff;
+ mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32);
+ mp_resp_bd->buf_len = PAGE_SIZE;
+ mp_resp_bd->flags = 0;
+
+ return SUCCESS;
+}
+
+static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
+{
+ struct fc_lport *lport;
+ struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
+ struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fcoe_port *port;
+ struct bnx2fc_hba *hba;
+ struct bnx2fc_rport *tgt;
+ struct bnx2fc_cmd *io_req;
+ struct bnx2fc_mp_req *tm_req;
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ struct Scsi_Host *host = sc_cmd->device->host;
+ struct fc_frame_header *fc_hdr;
+ struct fcp_cmnd *fcp_cmnd;
+ int task_idx, index;
+ int rc = SUCCESS;
+ u16 xid;
+ u32 sid, did;
+ unsigned long start = jiffies;
+
+ lport = shost_priv(host);
+ port = lport_priv(lport);
+ hba = port->priv;
+
+ if (rport == NULL) {
+ printk(KERN_ALERT PFX "device_reset: rport is NULL\n");
+ rc = FAILED;
+ goto tmf_err;
+ }
+
+ rc = fc_block_scsi_eh(sc_cmd);
+ if (rc)
+ return rc;
+
+ if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
+ printk(KERN_ERR PFX "device_reset: link is not ready\n");
+ rc = FAILED;
+ goto tmf_err;
+ }
+ /* rport and tgt are allocated together, so tgt should be non-NULL */
+ tgt = (struct bnx2fc_rport *)&rp[1];
+
+ if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) {
+ printk(KERN_ERR PFX "device_reset: tgt not offloaded\n");
+ rc = FAILED;
+ goto tmf_err;
+ }
+retry_tmf:
+ io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_TASK_MGMT_CMD);
+ if (!io_req) {
+ if (time_after(jiffies, start + HZ)) {
+ printk(KERN_ERR PFX "tmf: Failed TMF");
+ rc = FAILED;
+ goto tmf_err;
+ }
+ msleep(20);
+ goto retry_tmf;
+ }
+ /* Initialize rest of io_req fields */
+ io_req->sc_cmd = sc_cmd;
+ io_req->port = port;
+ io_req->tgt = tgt;
+
+ tm_req = (struct bnx2fc_mp_req *)&(io_req->mp_req);
+
+ rc = bnx2fc_init_mp_req(io_req);
+ if (rc == FAILED) {
+ printk(KERN_ERR PFX "Task mgmt MP request init failed\n");
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ goto tmf_err;
+ }
+
+ /* Set TM flags */
+ io_req->io_req_flags = 0;
+ tm_req->tm_flags = tm_flags;
+
+ /* Fill FCP_CMND */
+ bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)tm_req->req_buf);
+ fcp_cmnd = (struct fcp_cmnd *)tm_req->req_buf;
+ memset(fcp_cmnd->fc_cdb, 0, sc_cmd->cmd_len);
+ fcp_cmnd->fc_dl = 0;
+
+ /* Fill FC header */
+ fc_hdr = &(tm_req->req_fc_hdr);
+ sid = tgt->sid;
+ did = rport->port_id;
+ __fc_fill_fc_hdr(fc_hdr, FC_RCTL_DD_UNSOL_CMD, did, sid,
+ FC_TYPE_FCP, FC_FC_FIRST_SEQ | FC_FC_END_SEQ |
+ FC_FC_SEQ_INIT, 0);
+ /* Obtain exchange id */
+ xid = io_req->xid;
+
+ BNX2FC_TGT_DBG(tgt, "Initiate TMF - xid = 0x%x\n", xid);
+ task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+
+ /* Initialize task context for this IO request */
+ task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+ bnx2fc_init_mp_task(io_req, task);
+
+ sc_cmd->SCp.ptr = (char *)io_req;
+
+ /* Obtain free SQ entry */
+ spin_lock_bh(&tgt->tgt_lock);
+ bnx2fc_add_2_sq(tgt, xid);
+
+ /* Enqueue the io_req to active_tm_queue */
+ io_req->on_tmf_queue = 1;
+ list_add_tail(&io_req->link, &tgt->active_tm_queue);
+
+ init_completion(&io_req->tm_done);
+ io_req->wait_for_comp = 1;
+
+ /* Ring doorbell */
+ bnx2fc_ring_doorbell(tgt);
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ rc = wait_for_completion_timeout(&io_req->tm_done,
+ BNX2FC_TM_TIMEOUT * HZ);
+ spin_lock_bh(&tgt->tgt_lock);
+
+ io_req->wait_for_comp = 0;
+ if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags)))
+ set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags);
+
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ if (!rc) {
+ printk(KERN_ERR PFX "task mgmt command failed...\n");
+ rc = FAILED;
+ } else {
+ printk(KERN_ERR PFX "task mgmt command success...\n");
+ rc = SUCCESS;
+ }
+tmf_err:
+ return rc;
+}
+
+int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
+{
+ struct fc_lport *lport;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct fc_rport *rport = tgt->rport;
+ struct fc_rport_priv *rdata = tgt->rdata;
+ struct bnx2fc_hba *hba;
+ struct fcoe_port *port;
+ struct bnx2fc_cmd *abts_io_req;
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ struct fc_frame_header *fc_hdr;
+ struct bnx2fc_mp_req *abts_req;
+ int task_idx, index;
+ u32 sid, did;
+ u16 xid;
+ int rc = SUCCESS;
+ u32 r_a_tov = rdata->r_a_tov;
+
+ /* called with tgt_lock held */
+ BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_abts\n");
+
+ port = io_req->port;
+ hba = port->priv;
+ lport = port->lport;
+
+ if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
+ printk(KERN_ERR PFX "initiate_abts: tgt not offloaded\n");
+ rc = FAILED;
+ goto abts_err;
+ }
+
+ if (rport == NULL) {
+ printk(KERN_ALERT PFX "initiate_abts: rport is NULL\n");
+ rc = FAILED;
+ goto abts_err;
+ }
+
+ if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
+ printk(KERN_ERR PFX "initiate_abts: link is not ready\n");
+ rc = FAILED;
+ goto abts_err;
+ }
+
+ abts_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ABTS);
+ if (!abts_io_req) {
+ printk(KERN_ERR PFX "abts: couldnt allocate cmd\n");
+ rc = FAILED;
+ goto abts_err;
+ }
+
+ /* Initialize rest of io_req fields */
+ abts_io_req->sc_cmd = NULL;
+ abts_io_req->port = port;
+ abts_io_req->tgt = tgt;
+ abts_io_req->data_xfer_len = 0; /* No data transfer for ABTS */
+
+ abts_req = (struct bnx2fc_mp_req *)&(abts_io_req->mp_req);
+ memset(abts_req, 0, sizeof(struct bnx2fc_mp_req));
+
+ /* Fill FC header */
+ fc_hdr = &(abts_req->req_fc_hdr);
+
+ /* Obtain oxid and rxid for the original exchange to be aborted */
+ fc_hdr->fh_ox_id = htons(io_req->xid);
+ fc_hdr->fh_rx_id = htons(io_req->task->rx_wr_tx_rd.rx_id);
+
+ sid = tgt->sid;
+ did = rport->port_id;
+
+ __fc_fill_fc_hdr(fc_hdr, FC_RCTL_BA_ABTS, did, sid,
+ FC_TYPE_BLS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ |
+ FC_FC_SEQ_INIT, 0);
+
+ xid = abts_io_req->xid;
+ BNX2FC_IO_DBG(abts_io_req, "ABTS io_req\n");
+ task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+
+ /* Initialize task context for this IO request */
+ task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+ bnx2fc_init_mp_task(abts_io_req, task);
+
+ /*
+ * ABTS task is a temporary task that will be cleaned up
+ * irrespective of ABTS response. We need to start the timer
+ * for the original exchange, as the CQE is posted for the original
+ * IO request.
+ *
+ * Timer for ABTS is started only when it is originated by a
+ * TM request. For the ABTS issued as part of ULP timeout,
+ * scsi-ml maintains the timers.
+ */
+
+ /* if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags))*/
+ bnx2fc_cmd_timer_set(io_req, 2 * r_a_tov);
+
+ /* Obtain free SQ entry */
+ bnx2fc_add_2_sq(tgt, xid);
+
+ /* Ring doorbell */
+ bnx2fc_ring_doorbell(tgt);
+
+abts_err:
+ return rc;
+}
+
+int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
+{
+ struct fc_lport *lport;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct bnx2fc_hba *hba;
+ struct fcoe_port *port;
+ struct bnx2fc_cmd *cleanup_io_req;
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ int task_idx, index;
+ u16 xid, orig_xid;
+ int rc = 0;
+
+ /* ASSUMPTION: called with tgt_lock held */
+ BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_cleanup\n");
+
+ port = io_req->port;
+ hba = port->priv;
+ lport = port->lport;
+
+ cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP);
+ if (!cleanup_io_req) {
+ printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n");
+ rc = -1;
+ goto cleanup_err;
+ }
+
+ /* Initialize rest of io_req fields */
+ cleanup_io_req->sc_cmd = NULL;
+ cleanup_io_req->port = port;
+ cleanup_io_req->tgt = tgt;
+ cleanup_io_req->data_xfer_len = 0; /* No data transfer for cleanup */
+
+ xid = cleanup_io_req->xid;
+
+ task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+
+ /* Initialize task context for this IO request */
+ task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+ orig_xid = io_req->xid;
+
+ BNX2FC_IO_DBG(io_req, "CLEANUP io_req xid = 0x%x\n", xid);
+
+ bnx2fc_init_cleanup_task(cleanup_io_req, task, orig_xid);
+
+ /* Obtain free SQ entry */
+ bnx2fc_add_2_sq(tgt, xid);
+
+ /* Ring doorbell */
+ bnx2fc_ring_doorbell(tgt);
+
+cleanup_err:
+ return rc;
+}
+
+/**
+ * bnx2fc_eh_target_reset: Reset a target
+ *
+ * @sc_cmd: SCSI command
+ *
+ * Set from SCSI host template to send task mgmt command to the target
+ * and wait for the response
+ */
+int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd)
+{
+ return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET);
+}
+
+/**
+ * bnx2fc_eh_device_reset - Reset a single LUN
+ *
+ * @sc_cmd: SCSI command
+ *
+ * Set from SCSI host template to send task mgmt command to the target
+ * and wait for the response
+ */
+int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
+{
+ return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
+}
+
+/**
+ * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding
+ * SCSI command
+ *
+ * @sc_cmd: SCSI_ML command pointer
+ *
+ * SCSI abort request handler
+ */
+int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
+{
+ struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
+ struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct bnx2fc_cmd *io_req;
+ struct fc_lport *lport;
+ struct bnx2fc_rport *tgt;
+ int rc = FAILED;
+
+
+ rc = fc_block_scsi_eh(sc_cmd);
+ if (rc)
+ return rc;
+
+ lport = shost_priv(sc_cmd->device->host);
+ if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
+ printk(KERN_ALERT PFX "eh_abort: link not ready\n");
+ return rc;
+ }
+
+ tgt = (struct bnx2fc_rport *)&rp[1];
+
+ BNX2FC_TGT_DBG(tgt, "Entered bnx2fc_eh_abort\n");
+
+ spin_lock_bh(&tgt->tgt_lock);
+ io_req = (struct bnx2fc_cmd *)sc_cmd->SCp.ptr;
+ if (!io_req) {
+ /* Command might have just completed */
+ printk(KERN_ERR PFX "eh_abort: io_req is NULL\n");
+ spin_unlock_bh(&tgt->tgt_lock);
+ return SUCCESS;
+ }
+ BNX2FC_IO_DBG(io_req, "eh_abort - refcnt = %d\n",
+ io_req->refcount.refcount.counter);
+
+ /* Hold IO request across abort processing */
+ kref_get(&io_req->refcount);
+
+ BUG_ON(tgt != io_req->tgt);
+
+ /* Remove the io_req from the active_q. */
+ /*
+ * Task Mgmt functions (LUN RESET & TGT RESET) will not
+ * issue an ABTS on this particular IO req, as the
+ * io_req is no longer in the active_q.
+ */
+ if (tgt->flush_in_prog) {
+ printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+ "flush in progress\n", io_req->xid);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return SUCCESS;
+ }
+
+ if (io_req->on_active_queue == 0) {
+ printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+ "not on active_q\n", io_req->xid);
+ /*
+ * This condition can happen only due to the FW bug,
+ * where we do not receive cleanup response from
+ * the FW. Handle this case gracefully by erroring
+ * back the IO request to SCSI-ml
+ */
+ bnx2fc_scsi_done(io_req, DID_ABORT);
+
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return SUCCESS;
+ }
+
+ /*
+ * Only eh_abort processing will remove the IO from
+ * active_cmd_q before processing the request. this is
+ * done to avoid race conditions between IOs aborted
+ * as part of task management completion and eh_abort
+ * processing
+ */
+ list_del_init(&io_req->link);
+ io_req->on_active_queue = 0;
+ /* Move IO req to retire queue */
+ list_add_tail(&io_req->link, &tgt->io_retire_queue);
+
+ init_completion(&io_req->tm_done);
+ io_req->wait_for_comp = 1;
+
+ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
+ /* Cancel the current timer running on this io_req */
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+ set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
+ rc = bnx2fc_initiate_abts(io_req);
+ } else {
+ printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+ "already in abts processing\n", io_req->xid);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return SUCCESS;
+ }
+ if (rc == FAILED) {
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return rc;
+ }
+ spin_unlock_bh(&tgt->tgt_lock);
+
+ wait_for_completion(&io_req->tm_done);
+
+ spin_lock_bh(&tgt->tgt_lock);
+ io_req->wait_for_comp = 0;
+ if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
+ &io_req->req_flags))) {
+ /* Let the scsi-ml try to recover this command */
+ printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
+ io_req->xid);
+ rc = FAILED;
+ } else {
+ /*
+ * We come here even when there was a race condition
+ * between timeout and abts completion, and abts
+ * completion happens just in time.
+ */
+ BNX2FC_IO_DBG(io_req, "abort succeeded\n");
+ rc = SUCCESS;
+ bnx2fc_scsi_done(io_req, DID_ABORT);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ }
+
+ /* release the reference taken in eh_abort */
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return rc;
+}
+
+void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq)
+{
+ BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl "
+ "refcnt = %d, cmd_type = %d\n",
+ io_req->refcount.refcount.counter, io_req->cmd_type);
+ bnx2fc_scsi_done(io_req, DID_ERROR);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+}
+
+void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq)
+{
+ u32 r_ctl;
+ u32 r_a_tov = FC_DEF_R_A_TOV;
+ u8 issue_rrq = 0;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+
+ BNX2FC_IO_DBG(io_req, "Entered process_abts_compl xid = 0x%x"
+ "refcnt = %d, cmd_type = %d\n",
+ io_req->xid,
+ io_req->refcount.refcount.counter, io_req->cmd_type);
+
+ if (test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
+ &io_req->req_flags)) {
+ BNX2FC_IO_DBG(io_req, "Timer context finished processing"
+ " this io\n");
+ return;
+ }
+
+ /* Do not issue RRQ as this IO is already cleanedup */
+ if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP,
+ &io_req->req_flags))
+ goto io_compl;
+
+ /*
+ * For ABTS issued due to SCSI eh_abort_handler, timeout
+ * values are maintained by scsi-ml itself. Cancel timeout
+ * in case ABTS issued as part of task management function
+ * or due to FW error.
+ */
+ if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags))
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+
+ r_ctl = task->cmn.general.rsp_info.abts_rsp.r_ctl;
+
+ switch (r_ctl) {
+ case FC_RCTL_BA_ACC:
+ /*
+ * Dont release this cmd yet. It will be relesed
+ * after we get RRQ response
+ */
+ BNX2FC_IO_DBG(io_req, "ABTS response - ACC Send RRQ\n");
+ issue_rrq = 1;
+ break;
+
+ case FC_RCTL_BA_RJT:
+ BNX2FC_IO_DBG(io_req, "ABTS response - RJT\n");
+ break;
+ default:
+ printk(KERN_ERR PFX "Unknown ABTS response\n");
+ break;
+ }
+
+ if (issue_rrq) {
+ BNX2FC_IO_DBG(io_req, "Issue RRQ after R_A_TOV\n");
+ set_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
+ }
+ set_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags);
+ bnx2fc_cmd_timer_set(io_req, r_a_tov);
+
+io_compl:
+ if (io_req->wait_for_comp) {
+ if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
+ &io_req->req_flags))
+ complete(&io_req->tm_done);
+ } else {
+ /*
+ * We end up here when ABTS is issued as
+ * in asynchronous context, i.e., as part
+ * of task management completion, or
+ * when FW error is received or when the
+ * ABTS is issued when the IO is timed
+ * out.
+ */
+
+ if (io_req->on_active_queue) {
+ list_del_init(&io_req->link);
+ io_req->on_active_queue = 0;
+ /* Move IO req to retire queue */
+ list_add_tail(&io_req->link, &tgt->io_retire_queue);
+ }
+ bnx2fc_scsi_done(io_req, DID_ERROR);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ }
+}
+
+static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req)
+{
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct list_head *list;
+ struct list_head *tmp;
+ struct bnx2fc_cmd *cmd;
+ int tm_lun = sc_cmd->device->lun;
+ int rc = 0;
+ int lun;
+
+ /* called with tgt_lock held */
+ BNX2FC_IO_DBG(io_req, "Entered bnx2fc_lun_reset_cmpl\n");
+ /*
+ * Walk thru the active_ios queue and ABORT the IO
+ * that matches with the LUN that was reset
+ */
+ list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+ BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n");
+ cmd = (struct bnx2fc_cmd *)list;
+ lun = cmd->sc_cmd->device->lun;
+ if (lun == tm_lun) {
+ /* Initiate ABTS on this cmd */
+ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
+ &cmd->req_flags)) {
+ /* cancel the IO timeout */
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release);
+ /* timer hold */
+ rc = bnx2fc_initiate_abts(cmd);
+ /* abts shouldnt fail in this context */
+ WARN_ON(rc != SUCCESS);
+ } else
+ printk(KERN_ERR PFX "lun_rst: abts already in"
+ " progress for this IO 0x%x\n",
+ cmd->xid);
+ }
+ }
+}
+
+static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req)
+{
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct list_head *list;
+ struct list_head *tmp;
+ struct bnx2fc_cmd *cmd;
+ int rc = 0;
+
+ /* called with tgt_lock held */
+ BNX2FC_IO_DBG(io_req, "Entered bnx2fc_tgt_reset_cmpl\n");
+ /*
+ * Walk thru the active_ios queue and ABORT the IO
+ * that matches with the LUN that was reset
+ */
+ list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+ BNX2FC_TGT_DBG(tgt, "TGT RST cmpl: scan for pending IOs\n");
+ cmd = (struct bnx2fc_cmd *)list;
+ /* Initiate ABTS */
+ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
+ &cmd->req_flags)) {
+ /* cancel the IO timeout */
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* timer hold */
+ rc = bnx2fc_initiate_abts(cmd);
+ /* abts shouldnt fail in this context */
+ WARN_ON(rc != SUCCESS);
+
+ } else
+ printk(KERN_ERR PFX "tgt_rst: abts already in progress"
+ " for this IO 0x%x\n", cmd->xid);
+ }
+}
+
+void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task, u8 num_rq)
+{
+ struct bnx2fc_mp_req *tm_req;
+ struct fc_frame_header *fc_hdr;
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ u64 *hdr;
+ u64 *temp_hdr;
+ void *rsp_buf;
+
+ /* Called with tgt_lock held */
+ BNX2FC_IO_DBG(io_req, "Entered process_tm_compl\n");
+
+ if (!(test_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags)))
+ set_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags);
+ else {
+ /* TM has already timed out and we got
+ * delayed completion. Ignore completion
+ * processing.
+ */
+ return;
+ }
+
+ tm_req = &(io_req->mp_req);
+ fc_hdr = &(tm_req->resp_fc_hdr);
+ hdr = (u64 *)fc_hdr;
+ temp_hdr = (u64 *)
+ &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr;
+ hdr[0] = cpu_to_be64(temp_hdr[0]);
+ hdr[1] = cpu_to_be64(temp_hdr[1]);
+ hdr[2] = cpu_to_be64(temp_hdr[2]);
+
+ tm_req->resp_len = task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_off;
+
+ rsp_buf = tm_req->resp_buf;
+
+ if (fc_hdr->fh_r_ctl == FC_RCTL_DD_CMD_STATUS) {
+ bnx2fc_parse_fcp_rsp(io_req,
+ (struct fcoe_fcp_rsp_payload *)
+ rsp_buf, num_rq);
+ if (io_req->fcp_rsp_code == 0) {
+ /* TM successful */
+ if (tm_req->tm_flags & FCP_TMF_LUN_RESET)
+ bnx2fc_lun_reset_cmpl(io_req);
+ else if (tm_req->tm_flags & FCP_TMF_TGT_RESET)
+ bnx2fc_tgt_reset_cmpl(io_req);
+ }
+ } else {
+ printk(KERN_ERR PFX "tmf's fc_hdr r_ctl = 0x%x\n",
+ fc_hdr->fh_r_ctl);
+ }
+ if (!sc_cmd->SCp.ptr) {
+ printk(KERN_ALERT PFX "tm_compl: SCp.ptr is NULL\n");
+ return;
+ }
+ switch (io_req->fcp_status) {
+ case FC_GOOD:
+ if (io_req->cdb_status == 0) {
+ /* Good IO completion */
+ sc_cmd->result = DID_OK << 16;
+ } else {
+ /* Transport status is good, SCSI status not good */
+ sc_cmd->result = (DID_OK << 16) | io_req->cdb_status;
+ }
+ if (io_req->fcp_resid)
+ scsi_set_resid(sc_cmd, io_req->fcp_resid);
+ break;
+
+ default:
+ BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n",
+ io_req->fcp_status);
+ break;
+ }
+
+ sc_cmd = io_req->sc_cmd;
+ io_req->sc_cmd = NULL;
+
+ /* check if the io_req exists in tgt's tmf_q */
+ if (io_req->on_tmf_queue) {
+
+ list_del_init(&io_req->link);
+ io_req->on_tmf_queue = 0;
+ } else {
+
+ printk(KERN_ALERT PFX "Command not on active_cmd_queue!\n");
+ return;
+ }
+
+ sc_cmd->SCp.ptr = NULL;
+ sc_cmd->scsi_done(sc_cmd);
+
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ if (io_req->wait_for_comp) {
+ BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n");
+ complete(&io_req->tm_done);
+ }
+}
+
+static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len,
+ int bd_index)
+{
+ struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl;
+ int frag_size, sg_frags;
+
+ sg_frags = 0;
+ while (sg_len) {
+ if (sg_len >= BNX2FC_BD_SPLIT_SZ)
+ frag_size = BNX2FC_BD_SPLIT_SZ;
+ else
+ frag_size = sg_len;
+ bd[bd_index + sg_frags].buf_addr_lo = addr & 0xffffffff;
+ bd[bd_index + sg_frags].buf_addr_hi = addr >> 32;
+ bd[bd_index + sg_frags].buf_len = (u16)frag_size;
+ bd[bd_index + sg_frags].flags = 0;
+
+ addr += (u64) frag_size;
+ sg_frags++;
+ sg_len -= frag_size;
+ }
+ return sg_frags;
+
+}
+
+static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req)
+{
+ struct scsi_cmnd *sc = io_req->sc_cmd;
+ struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl;
+ struct scatterlist *sg;
+ int byte_count = 0;
+ int sg_count = 0;
+ int bd_count = 0;
+ int sg_frags;
+ unsigned int sg_len;
+ u64 addr;
+ int i;
+
+ sg_count = scsi_dma_map(sc);
+ scsi_for_each_sg(sc, sg, sg_count, i) {
+ sg_len = sg_dma_len(sg);
+ addr = sg_dma_address(sg);
+ if (sg_len > BNX2FC_MAX_BD_LEN) {
+ sg_frags = bnx2fc_split_bd(io_req, addr, sg_len,
+ bd_count);
+ } else {
+
+ sg_frags = 1;
+ bd[bd_count].buf_addr_lo = addr & 0xffffffff;
+ bd[bd_count].buf_addr_hi = addr >> 32;
+ bd[bd_count].buf_len = (u16)sg_len;
+ bd[bd_count].flags = 0;
+ }
+ bd_count += sg_frags;
+ byte_count += sg_len;
+ }
+ if (byte_count != scsi_bufflen(sc))
+ printk(KERN_ERR PFX "byte_count = %d != scsi_bufflen = %d, "
+ "task_id = 0x%x\n", byte_count, scsi_bufflen(sc),
+ io_req->xid);
+ return bd_count;
+}
+
+static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req)
+{
+ struct scsi_cmnd *sc = io_req->sc_cmd;
+ struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl;
+ int bd_count;
+
+ if (scsi_sg_count(sc))
+ bd_count = bnx2fc_map_sg(io_req);
+ else {
+ bd_count = 0;
+ bd[0].buf_addr_lo = bd[0].buf_addr_hi = 0;
+ bd[0].buf_len = bd[0].flags = 0;
+ }
+ io_req->bd_tbl->bd_valid = bd_count;
+}
+
+static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req)
+{
+ struct scsi_cmnd *sc = io_req->sc_cmd;
+
+ if (io_req->bd_tbl->bd_valid && sc) {
+ scsi_dma_unmap(sc);
+ io_req->bd_tbl->bd_valid = 0;
+ }
+}
+
+void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
+ struct fcp_cmnd *fcp_cmnd)
+{
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ char tag[2];
+
+ memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd));
+
+ int_to_scsilun(sc_cmd->device->lun,
+ (struct scsi_lun *) fcp_cmnd->fc_lun);
+
+
+ fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len);
+ memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len);
+
+ fcp_cmnd->fc_cmdref = 0;
+ fcp_cmnd->fc_pri_ta = 0;
+ fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags;
+ fcp_cmnd->fc_flags = io_req->io_req_flags;
+
+ if (scsi_populate_tag_msg(sc_cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ fcp_cmnd->fc_pri_ta = FCP_PTA_HEADQ;
+ break;
+ case ORDERED_QUEUE_TAG:
+ fcp_cmnd->fc_pri_ta = FCP_PTA_ORDERED;
+ break;
+ default:
+ fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
+ break;
+ }
+ } else {
+ fcp_cmnd->fc_pri_ta = 0;
+ }
+}
+
+static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
+ struct fcoe_fcp_rsp_payload *fcp_rsp,
+ u8 num_rq)
+{
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ u8 rsp_flags = fcp_rsp->fcp_flags.flags;
+ u32 rq_buff_len = 0;
+ int i;
+ unsigned char *rq_data;
+ unsigned char *dummy;
+ int fcp_sns_len = 0;
+ int fcp_rsp_len = 0;
+
+ io_req->fcp_status = FC_GOOD;
+ io_req->fcp_resid = fcp_rsp->fcp_resid;
+
+ io_req->scsi_comp_flags = rsp_flags;
+ CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status =
+ fcp_rsp->scsi_status_code;
+
+ /* Fetch fcp_rsp_info and fcp_sns_info if available */
+ if (num_rq) {
+
+ /*
+ * We do not anticipate num_rq >1, as the linux defined
+ * SCSI_SENSE_BUFFERSIZE is 96 bytes + 8 bytes of FCP_RSP_INFO
+ * 256 bytes of single rq buffer is good enough to hold this.
+ */
+
+ if (rsp_flags &
+ FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID) {
+ fcp_rsp_len = rq_buff_len
+ = fcp_rsp->fcp_rsp_len;
+ }
+
+ if (rsp_flags &
+ FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID) {
+ fcp_sns_len = fcp_rsp->fcp_sns_len;
+ rq_buff_len += fcp_rsp->fcp_sns_len;
+ }
+
+ io_req->fcp_rsp_len = fcp_rsp_len;
+ io_req->fcp_sns_len = fcp_sns_len;
+
+ if (rq_buff_len > num_rq * BNX2FC_RQ_BUF_SZ) {
+ /* Invalid sense sense length. */
+ printk(KERN_ALERT PFX "invalid sns length %d\n",
+ rq_buff_len);
+ /* reset rq_buff_len */
+ rq_buff_len = num_rq * BNX2FC_RQ_BUF_SZ;
+ }
+
+ rq_data = bnx2fc_get_next_rqe(tgt, 1);
+
+ if (num_rq > 1) {
+ /* We do not need extra sense data */
+ for (i = 1; i < num_rq; i++)
+ dummy = bnx2fc_get_next_rqe(tgt, 1);
+ }
+
+ /* fetch fcp_rsp_code */
+ if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) {
+ /* Only for task management function */
+ io_req->fcp_rsp_code = rq_data[3];
+ printk(KERN_ERR PFX "fcp_rsp_code = %d\n",
+ io_req->fcp_rsp_code);
+ }
+
+ /* fetch sense data */
+ rq_data += fcp_rsp_len;
+
+ if (fcp_sns_len > SCSI_SENSE_BUFFERSIZE) {
+ printk(KERN_ERR PFX "Truncating sense buffer\n");
+ fcp_sns_len = SCSI_SENSE_BUFFERSIZE;
+ }
+
+ memset(sc_cmd->sense_buffer, 0, sizeof(sc_cmd->sense_buffer));
+ if (fcp_sns_len)
+ memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len);
+
+ /* return RQ entries */
+ for (i = 0; i < num_rq; i++)
+ bnx2fc_return_rqe(tgt, 1);
+ }
+}
+
+/**
+ * bnx2fc_queuecommand - Queuecommand function of the scsi template
+ *
+ * @host: The Scsi_Host the command was issued to
+ * @sc_cmd: struct scsi_cmnd to be executed
+ *
+ * This is the IO strategy routine, called by SCSI-ML
+ **/
+int bnx2fc_queuecommand(struct Scsi_Host *host,
+ struct scsi_cmnd *sc_cmd)
+{
+ struct fc_lport *lport = shost_priv(host);
+ struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
+ struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct bnx2fc_rport *tgt;
+ struct bnx2fc_cmd *io_req;
+ int rc = 0;
+ int rval;
+
+ rval = fc_remote_port_chkready(rport);
+ if (rval) {
+ sc_cmd->result = rval;
+ sc_cmd->scsi_done(sc_cmd);
+ return 0;
+ }
+
+ if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit_qcmd;
+ }
+
+ /* rport and tgt are allocated together, so tgt should be non-NULL */
+ tgt = (struct bnx2fc_rport *)&rp[1];
+
+ if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
+ /*
+ * Session is not offloaded yet. Let SCSI-ml retry
+ * the command.
+ */
+ rc = SCSI_MLQUEUE_TARGET_BUSY;
+ goto exit_qcmd;
+ }
+
+ io_req = bnx2fc_cmd_alloc(tgt);
+ if (!io_req) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit_qcmd;
+ }
+ io_req->sc_cmd = sc_cmd;
+
+ if (bnx2fc_post_io_req(tgt, io_req)) {
+ printk(KERN_ERR PFX "Unable to post io_req\n");
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit_qcmd;
+ }
+exit_qcmd:
+ return rc;
+}
+
+void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
+ struct fcoe_task_ctx_entry *task,
+ u8 num_rq)
+{
+ struct fcoe_fcp_rsp_payload *fcp_rsp;
+ struct bnx2fc_rport *tgt = io_req->tgt;
+ struct scsi_cmnd *sc_cmd;
+ struct Scsi_Host *host;
+
+
+ /* scsi_cmd_cmpl is called with tgt lock held */
+
+ if (test_and_set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) {
+ /* we will not receive ABTS response for this IO */
+ BNX2FC_IO_DBG(io_req, "Timer context finished processing "
+ "this scsi cmd\n");
+ }
+
+ /* Cancel the timeout_work, as we received IO completion */
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+
+ sc_cmd = io_req->sc_cmd;
+ if (sc_cmd == NULL) {
+ printk(KERN_ERR PFX "scsi_cmd_compl - sc_cmd is NULL\n");
+ return;
+ }
+
+ /* Fetch fcp_rsp from task context and perform cmd completion */
+ fcp_rsp = (struct fcoe_fcp_rsp_payload *)
+ &(task->cmn.general.rsp_info.fcp_rsp.payload);
+
+ /* parse fcp_rsp and obtain sense data from RQ if available */
+ bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq);
+
+ host = sc_cmd->device->host;
+ if (!sc_cmd->SCp.ptr) {
+ printk(KERN_ERR PFX "SCp.ptr is NULL\n");
+ return;
+ }
+ io_req->sc_cmd = NULL;
+
+ if (io_req->on_active_queue) {
+ list_del_init(&io_req->link);
+ io_req->on_active_queue = 0;
+ /* Move IO req to retire queue */
+ list_add_tail(&io_req->link, &tgt->io_retire_queue);
+ } else {
+ /* This should not happen, but could have been pulled
+ * by bnx2fc_flush_active_ios(), or during a race
+ * between command abort and (late) completion.
+ */
+ BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n");
+ if (io_req->wait_for_comp)
+ if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
+ &io_req->req_flags))
+ complete(&io_req->tm_done);
+ }
+
+ bnx2fc_unmap_sg_list(io_req);
+
+ switch (io_req->fcp_status) {
+ case FC_GOOD:
+ if (io_req->cdb_status == 0) {
+ /* Good IO completion */
+ sc_cmd->result = DID_OK << 16;
+ } else {
+ /* Transport status is good, SCSI status not good */
+ BNX2FC_IO_DBG(io_req, "scsi_cmpl: cdb_status = %d"
+ " fcp_resid = 0x%x\n",
+ io_req->cdb_status, io_req->fcp_resid);
+ sc_cmd->result = (DID_OK << 16) | io_req->cdb_status;
+ }
+ if (io_req->fcp_resid)
+ scsi_set_resid(sc_cmd, io_req->fcp_resid);
+ break;
+ default:
+ printk(KERN_ALERT PFX "scsi_cmd_compl: fcp_status = %d\n",
+ io_req->fcp_status);
+ break;
+ }
+ sc_cmd->SCp.ptr = NULL;
+ sc_cmd->scsi_done(sc_cmd);
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+}
+
+static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
+ struct bnx2fc_cmd *io_req)
+{
+ struct fcoe_task_ctx_entry *task;
+ struct fcoe_task_ctx_entry *task_page;
+ struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
+ struct fcoe_port *port = tgt->port;
+ struct bnx2fc_hba *hba = port->priv;
+ struct fc_lport *lport = port->lport;
+ struct fcoe_dev_stats *stats;
+ int task_idx, index;
+ u16 xid;
+
+ /* Initialize rest of io_req fields */
+ io_req->cmd_type = BNX2FC_SCSI_CMD;
+ io_req->port = port;
+ io_req->tgt = tgt;
+ io_req->data_xfer_len = scsi_bufflen(sc_cmd);
+ sc_cmd->SCp.ptr = (char *)io_req;
+
+ stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+ if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ io_req->io_req_flags = BNX2FC_READ;
+ stats->InputRequests++;
+ stats->InputBytes += io_req->data_xfer_len;
+ } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
+ io_req->io_req_flags = BNX2FC_WRITE;
+ stats->OutputRequests++;
+ stats->OutputBytes += io_req->data_xfer_len;
+ } else {
+ io_req->io_req_flags = 0;
+ stats->ControlRequests++;
+ }
+ put_cpu();
+
+ xid = io_req->xid;
+
+ /* Build buffer descriptor list for firmware from sg list */
+ bnx2fc_build_bd_list_from_sg(io_req);
+
+ task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+ index = xid % BNX2FC_TASKS_PER_PAGE;
+
+ /* Initialize task context for this IO request */
+ task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+ task = &(task_page[index]);
+ bnx2fc_init_task(io_req, task);
+
+ spin_lock_bh(&tgt->tgt_lock);
+
+ if (tgt->flush_in_prog) {
+ printk(KERN_ERR PFX "Flush in progress..Host Busy\n");
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return -EAGAIN;
+ }
+
+ if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
+ printk(KERN_ERR PFX "Session not ready...post_io\n");
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return -EAGAIN;
+ }
+
+ /* Time IO req */
+ bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT);
+ /* Obtain free SQ entry */
+ bnx2fc_add_2_sq(tgt, xid);
+
+ /* Enqueue the io_req to active_cmd_queue */
+
+ io_req->on_active_queue = 1;
+ /* move io_req from pending_queue to active_queue */
+ list_add_tail(&io_req->link, &tgt->active_cmd_queue);
+
+ /* Ring doorbell */
+ bnx2fc_ring_doorbell(tgt);
+ spin_unlock_bh(&tgt->tgt_lock);
+ return 0;
+}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
new file mode 100644
index 000000000000..7ea93af60260
--- /dev/null
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -0,0 +1,844 @@
+/* bnx2fc_tgt.c: Broadcom NetXtreme II Linux FCoE offload driver.
+ * Handles operations such as session offload/upload etc, and manages
+ * session resources such as connection id and qp resources.
+ *
+ * Copyright (c) 2008 - 2010 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com)
+ */
+
+#include "bnx2fc.h"
+static void bnx2fc_upld_timer(unsigned long data);
+static void bnx2fc_ofld_timer(unsigned long data);
+static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
+ struct fcoe_port *port,
+ struct fc_rport_priv *rdata);
+static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt);
+static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt);
+static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt);
+static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id);
+
+static void bnx2fc_upld_timer(unsigned long data)
+{
+
+ struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data;
+
+ BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n");
+ /* fake upload completion */
+ clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->upld_wait);
+}
+
+static void bnx2fc_ofld_timer(unsigned long data)
+{
+
+ struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data;
+
+ BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n");
+ /* NOTE: This function should never be called, as
+ * offload should never timeout
+ */
+ /*
+ * If the timer has expired, this session is dead
+ * Clear offloaded flag and logout of this device.
+ * Since OFFLOADED flag is cleared, this case
+ * will be considered as offload error and the
+ * port will be logged off, and conn_id, session
+ * resources are freed up in bnx2fc_offload_session
+ */
+ clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
+ set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
+ wake_up_interruptible(&tgt->ofld_wait);
+}
+
+static void bnx2fc_offload_session(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt,
+ struct fc_rport_priv *rdata)
+{
+ struct fc_lport *lport = rdata->local_port;
+ struct fc_rport *rport = rdata->rport;
+ struct bnx2fc_hba *hba = port->priv;
+ int rval;
+ int i = 0;
+
+ /* Initialize bnx2fc_rport */
+ /* NOTE: tgt is already bzero'd */
+ rval = bnx2fc_init_tgt(tgt, port, rdata);
+ if (rval) {
+ printk(KERN_ERR PFX "Failed to allocate conn id for "
+ "port_id (%6x)\n", rport->port_id);
+ goto ofld_err;
+ }
+
+ /* Allocate session resources */
+ rval = bnx2fc_alloc_session_resc(hba, tgt);
+ if (rval) {
+ printk(KERN_ERR PFX "Failed to allocate resources\n");
+ goto ofld_err;
+ }
+
+ /*
+ * Initialize FCoE session offload process.
+ * Upon completion of offload process add
+ * rport to list of rports
+ */
+retry_ofld:
+ clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
+ rval = bnx2fc_send_session_ofld_req(port, tgt);
+ if (rval) {
+ printk(KERN_ERR PFX "ofld_req failed\n");
+ goto ofld_err;
+ }
+
+ /*
+ * wait for the session is offloaded and enabled. 3 Secs
+ * should be ample time for this process to complete.
+ */
+ setup_timer(&tgt->ofld_timer, bnx2fc_ofld_timer, (unsigned long)tgt);
+ mod_timer(&tgt->ofld_timer, jiffies + BNX2FC_FW_TIMEOUT);
+
+ wait_event_interruptible(tgt->ofld_wait,
+ (test_bit(
+ BNX2FC_FLAG_OFLD_REQ_CMPL,
+ &tgt->flags)));
+ if (signal_pending(current))
+ flush_signals(current);
+
+ del_timer_sync(&tgt->ofld_timer);
+
+ if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) {
+ if (test_and_clear_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE,
+ &tgt->flags)) {
+ BNX2FC_TGT_DBG(tgt, "ctx_alloc_failure, "
+ "retry ofld..%d\n", i++);
+ msleep_interruptible(1000);
+ if (i > 3) {
+ i = 0;
+ goto ofld_err;
+ }
+ goto retry_ofld;
+ }
+ goto ofld_err;
+ }
+ if (bnx2fc_map_doorbell(tgt)) {
+ printk(KERN_ERR PFX "map doorbell failed - no mem\n");
+ /* upload will take care of cleaning up sess resc */
+ lport->tt.rport_logoff(rdata);
+ }
+ return;
+
+ofld_err:
+ /* couldn't offload the session. log off from this rport */
+ BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n");
+ lport->tt.rport_logoff(rdata);
+ /* Free session resources */
+ bnx2fc_free_session_resc(hba, tgt);
+ if (tgt->fcoe_conn_id != -1)
+ bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
+}
+
+void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
+{
+ struct bnx2fc_cmd *io_req;
+ struct list_head *list;
+ struct list_head *tmp;
+ int rc;
+ int i = 0;
+ BNX2FC_TGT_DBG(tgt, "Entered flush_active_ios - %d\n",
+ tgt->num_active_ios.counter);
+
+ spin_lock_bh(&tgt->tgt_lock);
+ tgt->flush_in_prog = 1;
+
+ list_for_each_safe(list, tmp, &tgt->active_cmd_queue) {
+ i++;
+ io_req = (struct bnx2fc_cmd *)list;
+ list_del_init(&io_req->link);
+ io_req->on_active_queue = 0;
+ BNX2FC_IO_DBG(io_req, "cmd_queue cleanup\n");
+
+ if (cancel_delayed_work(&io_req->timeout_work)) {
+ if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
+ &io_req->req_flags)) {
+ /* Handle eh_abort timeout */
+ BNX2FC_IO_DBG(io_req, "eh_abort for IO "
+ "cleaned up\n");
+ complete(&io_req->tm_done);
+ }
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+ }
+
+ set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags);
+ set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags);
+ rc = bnx2fc_initiate_cleanup(io_req);
+ BUG_ON(rc);
+ }
+
+ list_for_each_safe(list, tmp, &tgt->els_queue) {
+ i++;
+ io_req = (struct bnx2fc_cmd *)list;
+ list_del_init(&io_req->link);
+ io_req->on_active_queue = 0;
+
+ BNX2FC_IO_DBG(io_req, "els_queue cleanup\n");
+
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount,
+ bnx2fc_cmd_release); /* drop timer hold */
+
+ if ((io_req->cb_func) && (io_req->cb_arg)) {
+ io_req->cb_func(io_req->cb_arg);
+ io_req->cb_arg = NULL;
+ }
+
+ rc = bnx2fc_initiate_cleanup(io_req);
+ BUG_ON(rc);
+ }
+
+ list_for_each_safe(list, tmp, &tgt->io_retire_queue) {
+ i++;
+ io_req = (struct bnx2fc_cmd *)list;
+ list_del_init(&io_req->link);
+
+ BNX2FC_IO_DBG(io_req, "retire_queue flush\n");
+
+ if (cancel_delayed_work(&io_req->timeout_work))
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+
+ clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
+ }
+
+ BNX2FC_TGT_DBG(tgt, "IOs flushed = %d\n", i);
+ i = 0;
+ spin_unlock_bh(&tgt->tgt_lock);
+ /* wait for active_ios to go to 0 */
+ while ((tgt->num_active_ios.counter != 0) && (i++ < BNX2FC_WAIT_CNT))
+ msleep(25);
+ if (tgt->num_active_ios.counter != 0)
+ printk(KERN_ERR PFX "CLEANUP on port 0x%x:"
+ " active_ios = %d\n",
+ tgt->rdata->ids.port_id, tgt->num_active_ios.counter);
+ spin_lock_bh(&tgt->tgt_lock);
+ tgt->flush_in_prog = 0;
+ spin_unlock_bh(&tgt->tgt_lock);
+}
+
+static void bnx2fc_upload_session(struct fcoe_port *port,
+ struct bnx2fc_rport *tgt)
+{
+ struct bnx2fc_hba *hba = port->priv;
+
+ BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n",
+ tgt->num_active_ios.counter);
+
+ /*
+ * Called with hba->hba_mutex held.
+ * This is a blocking call
+ */
+ clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+ bnx2fc_send_session_disable_req(port, tgt);
+
+ /*
+ * wait for upload to complete. 3 Secs
+ * should be sufficient time for this process to complete.
+ */
+ setup_timer(&tgt->upld_timer, bnx2fc_upld_timer, (unsigned long)tgt);
+ mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT);
+
+ BNX2FC_TGT_DBG(tgt, "waiting for disable compl\n");
+ wait_event_interruptible(tgt->upld_wait,
+ (test_bit(
+ BNX2FC_FLAG_UPLD_REQ_COMPL,
+ &tgt->flags)));
+
+ if (signal_pending(current))
+ flush_signals(current);
+
+ del_timer_sync(&tgt->upld_timer);
+
+ /*
+ * traverse thru the active_q and tmf_q and cleanup
+ * IOs in these lists
+ */
+ BNX2FC_TGT_DBG(tgt, "flush/upload - disable wait flags = 0x%lx\n",
+ tgt->flags);
+ bnx2fc_flush_active_ios(tgt);
+
+ /* Issue destroy KWQE */
+ if (test_bit(BNX2FC_FLAG_DISABLED, &tgt->flags)) {
+ BNX2FC_TGT_DBG(tgt, "send destroy req\n");
+ clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags);
+ bnx2fc_send_session_destroy_req(hba, tgt);
+
+ /* wait for destroy to complete */
+ setup_timer(&tgt->upld_timer,
+ bnx2fc_upld_timer, (unsigned long)tgt);
+ mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT);
+
+ wait_event_interruptible(tgt->upld_wait,
+ (test_bit(
+ BNX2FC_FLAG_UPLD_REQ_COMPL,
+ &tgt->flags)));
+
+ if (!(test_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags)))
+ printk(KERN_ERR PFX "ERROR!! destroy timed out\n");
+
+ BNX2FC_TGT_DBG(tgt, "destroy wait complete flags = 0x%lx\n",
+ tgt->flags);
+ if (signal_pending(current))
+ flush_signals(current);
+
+ del_timer_sync(&tgt->upld_timer);
+
+ } else
+ printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy"
+ " not sent to FW\n");
+
+ /* Free session resources */
+ spin_lock_bh(&tgt->cq_lock);
+ bnx2fc_free_session_resc(hba, tgt);
+ bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
+ spin_unlock_bh(&tgt->cq_lock);
+}
+
+static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
+ struct fcoe_port *port,
+ struct fc_rport_priv *rdata)
+{
+
+ struct fc_rport *rport = rdata->rport;
+ struct bnx2fc_hba *hba = port->priv;
+
+ tgt->rport = rport;
+ tgt->rdata = rdata;
+ tgt->port = port;
+
+ if (hba->num_ofld_sess >= BNX2FC_NUM_MAX_SESS) {
+ BNX2FC_TGT_DBG(tgt, "exceeded max sessions. logoff this tgt\n");
+ tgt->fcoe_conn_id = -1;
+ return -1;
+ }
+
+ tgt->fcoe_conn_id = bnx2fc_alloc_conn_id(hba, tgt);
+ if (tgt->fcoe_conn_id == -1)
+ return -1;
+
+ BNX2FC_TGT_DBG(tgt, "init_tgt - conn_id = 0x%x\n", tgt->fcoe_conn_id);
+
+ tgt->max_sqes = BNX2FC_SQ_WQES_MAX;
+ tgt->max_rqes = BNX2FC_RQ_WQES_MAX;
+ tgt->max_cqes = BNX2FC_CQ_WQES_MAX;
+
+ /* Initialize the toggle bit */
+ tgt->sq_curr_toggle_bit = 1;
+ tgt->cq_curr_toggle_bit = 1;
+ tgt->sq_prod_idx = 0;
+ tgt->cq_cons_idx = 0;
+ tgt->rq_prod_idx = 0x8000;
+ tgt->rq_cons_idx = 0;
+ atomic_set(&tgt->num_active_ios, 0);
+
+ tgt->work_time_slice = 2;
+
+ spin_lock_init(&tgt->tgt_lock);
+ spin_lock_init(&tgt->cq_lock);
+
+ /* Initialize active_cmd_queue list */
+ INIT_LIST_HEAD(&tgt->active_cmd_queue);
+
+ /* Initialize IO retire queue */
+ INIT_LIST_HEAD(&tgt->io_retire_queue);
+
+ INIT_LIST_HEAD(&tgt->els_queue);
+
+ /* Initialize active_tm_queue list */
+ INIT_LIST_HEAD(&tgt->active_tm_queue);
+
+ init_waitqueue_head(&tgt->ofld_wait);
+ init_waitqueue_head(&tgt->upld_wait);
+
+ return 0;
+}
+
+/**
+ * This event_callback is called after successful completion of libfc
+ * initiated target login. bnx2fc can proceed with initiating the session
+ * establishment.
+ */
+void bnx2fc_rport_event_handler(struct fc_lport *lport,
+ struct fc_rport_priv *rdata,
+ enum fc_rport_event event)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct bnx2fc_hba *hba = port->priv;
+ struct fc_rport *rport = rdata->rport;
+ struct fc_rport_libfc_priv *rp;
+ struct bnx2fc_rport *tgt;
+ u32 port_id;
+
+ BNX2FC_HBA_DBG(lport, "rport_event_hdlr: event = %d, port_id = 0x%x\n",
+ event, rdata->ids.port_id);
+ switch (event) {
+ case RPORT_EV_READY:
+ if (!rport) {
+ printk(KERN_ALERT PFX "rport is NULL: ERROR!\n");
+ break;
+ }
+
+ rp = rport->dd_data;
+ if (rport->port_id == FC_FID_DIR_SERV) {
+ /*
+ * bnx2fc_rport structure doesnt exist for
+ * directory server.
+ * We should not come here, as lport will
+ * take care of fabric login
+ */
+ printk(KERN_ALERT PFX "%x - rport_event_handler ERROR\n",
+ rdata->ids.port_id);
+ break;
+ }
+
+ if (rdata->spp_type != FC_TYPE_FCP) {
+ BNX2FC_HBA_DBG(lport, "not FCP type target."
+ " not offloading\n");
+ break;
+ }
+ if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) {
+ BNX2FC_HBA_DBG(lport, "not FCP_TARGET"
+ " not offloading\n");
+ break;
+ }
+
+ /*
+ * Offlaod process is protected with hba mutex.
+ * Use the same mutex_lock for upload process too
+ */
+ mutex_lock(&hba->hba_mutex);
+ tgt = (struct bnx2fc_rport *)&rp[1];
+
+ /* This can happen when ADISC finds the same target */
+ if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) {
+ BNX2FC_TGT_DBG(tgt, "already offloaded\n");
+ mutex_unlock(&hba->hba_mutex);
+ return;
+ }
+
+ /*
+ * Offload the session. This is a blocking call, and will
+ * wait until the session is offloaded.
+ */
+ bnx2fc_offload_session(port, tgt, rdata);
+
+ BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n",
+ hba->num_ofld_sess);
+
+ if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) {
+ /*
+ * Session is offloaded and enabled. Map
+ * doorbell register for this target
+ */
+ BNX2FC_TGT_DBG(tgt, "sess offloaded\n");
+ /* This counter is protected with hba mutex */
+ hba->num_ofld_sess++;
+
+ set_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
+ } else {
+ /*
+ * Offload or enable would have failed.
+ * In offload/enable completion path, the
+ * rport would have already been removed
+ */
+ BNX2FC_TGT_DBG(tgt, "Port is being logged off as "
+ "offloaded flag not set\n");
+ }
+ mutex_unlock(&hba->hba_mutex);
+ break;
+ case RPORT_EV_LOGO:
+ case RPORT_EV_FAILED:
+ case RPORT_EV_STOP:
+ port_id = rdata->ids.port_id;
+ if (port_id == FC_FID_DIR_SERV)
+ break;
+
+ if (!rport) {
+ printk(KERN_ALERT PFX "%x - rport not created Yet!!\n",
+ port_id);
+ break;
+ }
+ rp = rport->dd_data;
+ mutex_lock(&hba->hba_mutex);
+ /*
+ * Perform session upload. Note that rdata->peers is already
+ * removed from disc->rports list before we get this event.
+ */
+ tgt = (struct bnx2fc_rport *)&rp[1];
+
+ if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) {
+ mutex_unlock(&hba->hba_mutex);
+ break;
+ }
+ clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
+
+ bnx2fc_upload_session(port, tgt);
+ hba->num_ofld_sess--;
+ BNX2FC_TGT_DBG(tgt, "UPLOAD num_ofld_sess = %d\n",
+ hba->num_ofld_sess);
+ /*
+ * Try to wake up the linkdown wait thread. If num_ofld_sess
+ * is 0, the waiting therad wakes up
+ */
+ if ((hba->wait_for_link_down) &&
+ (hba->num_ofld_sess == 0)) {
+ wake_up_interruptible(&hba->shutdown_wait);
+ }
+ if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) {
+ printk(KERN_ERR PFX "Relogin to the tgt\n");
+ mutex_lock(&lport->disc.disc_mutex);
+ lport->tt.rport_login(rdata);
+ mutex_unlock(&lport->disc.disc_mutex);
+ }
+ mutex_unlock(&hba->hba_mutex);
+
+ break;
+
+ case RPORT_EV_NONE:
+ break;
+ }
+}
+
+/**
+ * bnx2fc_tgt_lookup() - Lookup a bnx2fc_rport by port_id
+ *
+ * @port: fcoe_port struct to lookup the target port on
+ * @port_id: The remote port ID to look up
+ */
+struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
+ u32 port_id)
+{
+ struct bnx2fc_hba *hba = port->priv;
+ struct bnx2fc_rport *tgt;
+ struct fc_rport_priv *rdata;
+ int i;
+
+ for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) {
+ tgt = hba->tgt_ofld_list[i];
+ if ((tgt) && (tgt->port == port)) {
+ rdata = tgt->rdata;
+ if (rdata->ids.port_id == port_id) {
+ if (rdata->rp_state != RPORT_ST_DELETE) {
+ BNX2FC_TGT_DBG(tgt, "rport "
+ "obtained\n");
+ return tgt;
+ } else {
+ printk(KERN_ERR PFX "rport 0x%x "
+ "is in DELETED state\n",
+ rdata->ids.port_id);
+ return NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * bnx2fc_alloc_conn_id - allocates FCOE Connection id
+ *
+ * @hba: pointer to adapter structure
+ * @tgt: pointer to bnx2fc_rport structure
+ */
+static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt)
+{
+ u32 conn_id, next;
+
+ /* called with hba mutex held */
+
+ /*
+ * tgt_ofld_list access is synchronized using
+ * both hba mutex and hba lock. Atleast hba mutex or
+ * hba lock needs to be held for read access.
+ */
+
+ spin_lock_bh(&hba->hba_lock);
+ next = hba->next_conn_id;
+ conn_id = hba->next_conn_id++;
+ if (hba->next_conn_id == BNX2FC_NUM_MAX_SESS)
+ hba->next_conn_id = 0;
+
+ while (hba->tgt_ofld_list[conn_id] != NULL) {
+ conn_id++;
+ if (conn_id == BNX2FC_NUM_MAX_SESS)
+ conn_id = 0;
+
+ if (conn_id == next) {
+ /* No free conn_ids are available */
+ spin_unlock_bh(&hba->hba_lock);
+ return -1;
+ }
+ }
+ hba->tgt_ofld_list[conn_id] = tgt;
+ tgt->fcoe_conn_id = conn_id;
+ spin_unlock_bh(&hba->hba_lock);
+ return conn_id;
+}
+
+static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id)
+{
+ /* called with hba mutex held */
+ spin_lock_bh(&hba->hba_lock);
+ hba->tgt_ofld_list[conn_id] = NULL;
+ hba->next_conn_id = conn_id;
+ spin_unlock_bh(&hba->hba_lock);
+}
+
+/**
+ *bnx2fc_alloc_session_resc - Allocate qp resources for the session
+ *
+ */
+static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt)
+{
+ dma_addr_t page;
+ int num_pages;
+ u32 *pbl;
+
+ /* Allocate and map SQ */
+ tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
+ tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
+ &tgt->sq_dma, GFP_KERNEL);
+ if (!tgt->sq) {
+ printk(KERN_ALERT PFX "unable to allocate SQ memory %d\n",
+ tgt->sq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->sq, 0, tgt->sq_mem_size);
+
+ /* Allocate and map CQ */
+ tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
+ tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
+ &tgt->cq_dma, GFP_KERNEL);
+ if (!tgt->cq) {
+ printk(KERN_ALERT PFX "unable to allocate CQ memory %d\n",
+ tgt->cq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->cq, 0, tgt->cq_mem_size);
+
+ /* Allocate and map RQ and RQ PBL */
+ tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
+ tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
+ &tgt->rq_dma, GFP_KERNEL);
+ if (!tgt->rq) {
+ printk(KERN_ALERT PFX "unable to allocate RQ memory %d\n",
+ tgt->rq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->rq, 0, tgt->rq_mem_size);
+
+ tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
+ tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
+ &tgt->rq_pbl_dma, GFP_KERNEL);
+ if (!tgt->rq_pbl) {
+ printk(KERN_ALERT PFX "unable to allocate RQ PBL %d\n",
+ tgt->rq_pbl_size);
+ goto mem_alloc_failure;
+ }
+
+ memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
+ num_pages = tgt->rq_mem_size / PAGE_SIZE;
+ page = tgt->rq_dma;
+ pbl = (u32 *)tgt->rq_pbl;
+
+ while (num_pages--) {
+ *pbl = (u32)page;
+ pbl++;
+ *pbl = (u32)((u64)page >> 32);
+ pbl++;
+ page += PAGE_SIZE;
+ }
+
+ /* Allocate and map XFERQ */
+ tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
+ tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
+ PAGE_MASK;
+
+ tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
+ &tgt->xferq_dma, GFP_KERNEL);
+ if (!tgt->xferq) {
+ printk(KERN_ALERT PFX "unable to allocate XFERQ %d\n",
+ tgt->xferq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->xferq, 0, tgt->xferq_mem_size);
+
+ /* Allocate and map CONFQ & CONFQ PBL */
+ tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
+ tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
+ PAGE_MASK;
+
+ tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
+ &tgt->confq_dma, GFP_KERNEL);
+ if (!tgt->confq) {
+ printk(KERN_ALERT PFX "unable to allocate CONFQ %d\n",
+ tgt->confq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->confq, 0, tgt->confq_mem_size);
+
+ tgt->confq_pbl_size =
+ (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
+ tgt->confq_pbl_size =
+ (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+
+ tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
+ tgt->confq_pbl_size,
+ &tgt->confq_pbl_dma, GFP_KERNEL);
+ if (!tgt->confq_pbl) {
+ printk(KERN_ALERT PFX "unable to allocate CONFQ PBL %d\n",
+ tgt->confq_pbl_size);
+ goto mem_alloc_failure;
+ }
+
+ memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
+ num_pages = tgt->confq_mem_size / PAGE_SIZE;
+ page = tgt->confq_dma;
+ pbl = (u32 *)tgt->confq_pbl;
+
+ while (num_pages--) {
+ *pbl = (u32)page;
+ pbl++;
+ *pbl = (u32)((u64)page >> 32);
+ pbl++;
+ page += PAGE_SIZE;
+ }
+
+ /* Allocate and map ConnDB */
+ tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db);
+
+ tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev,
+ tgt->conn_db_mem_size,
+ &tgt->conn_db_dma, GFP_KERNEL);
+ if (!tgt->conn_db) {
+ printk(KERN_ALERT PFX "unable to allocate conn_db %d\n",
+ tgt->conn_db_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->conn_db, 0, tgt->conn_db_mem_size);
+
+
+ /* Allocate and map LCQ */
+ tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
+ tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
+ PAGE_MASK;
+
+ tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
+ &tgt->lcq_dma, GFP_KERNEL);
+
+ if (!tgt->lcq) {
+ printk(KERN_ALERT PFX "unable to allocate lcq %d\n",
+ tgt->lcq_mem_size);
+ goto mem_alloc_failure;
+ }
+ memset(tgt->lcq, 0, tgt->lcq_mem_size);
+
+ /* Arm CQ */
+ tgt->conn_db->cq_arm.lo = -1;
+ tgt->conn_db->rq_prod = 0x8000;
+
+ return 0;
+
+mem_alloc_failure:
+ bnx2fc_free_session_resc(hba, tgt);
+ bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
+ return -ENOMEM;
+}
+
+/**
+ * bnx2i_free_session_resc - free qp resources for the session
+ *
+ * @hba: adapter structure pointer
+ * @tgt: bnx2fc_rport structure pointer
+ *
+ * Free QP resources - SQ/RQ/CQ/XFERQ memory and PBL
+ */
+static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
+ struct bnx2fc_rport *tgt)
+{
+ BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n");
+
+ if (tgt->ctx_base) {
+ iounmap(tgt->ctx_base);
+ tgt->ctx_base = NULL;
+ }
+ /* Free LCQ */
+ if (tgt->lcq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
+ tgt->lcq, tgt->lcq_dma);
+ tgt->lcq = NULL;
+ }
+ /* Free connDB */
+ if (tgt->conn_db) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->conn_db_mem_size,
+ tgt->conn_db, tgt->conn_db_dma);
+ tgt->conn_db = NULL;
+ }
+ /* Free confq and confq pbl */
+ if (tgt->confq_pbl) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->confq_pbl_size,
+ tgt->confq_pbl, tgt->confq_pbl_dma);
+ tgt->confq_pbl = NULL;
+ }
+ if (tgt->confq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
+ tgt->confq, tgt->confq_dma);
+ tgt->confq = NULL;
+ }
+ /* Free XFERQ */
+ if (tgt->xferq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
+ tgt->xferq, tgt->xferq_dma);
+ tgt->xferq = NULL;
+ }
+ /* Free RQ PBL and RQ */
+ if (tgt->rq_pbl) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
+ tgt->rq_pbl, tgt->rq_pbl_dma);
+ tgt->rq_pbl = NULL;
+ }
+ if (tgt->rq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
+ tgt->rq, tgt->rq_dma);
+ tgt->rq = NULL;
+ }
+ /* Free CQ */
+ if (tgt->cq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
+ tgt->cq, tgt->cq_dma);
+ tgt->cq = NULL;
+ }
+ /* Free SQ */
+ if (tgt->sq) {
+ dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
+ tgt->sq, tgt->sq_dma);
+ tgt->sq = NULL;
+ }
+}
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index e1ca5fe7e6bb..cfd59023227b 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -360,7 +360,7 @@ struct bnx2i_hba {
#define ADAPTER_STATE_LINK_DOWN 2
#define ADAPTER_STATE_INIT_FAILED 31
unsigned int mtu_supported;
- #define BNX2I_MAX_MTU_SUPPORTED 1500
+ #define BNX2I_MAX_MTU_SUPPORTED 9000
struct Scsi_Host *shost;
@@ -751,6 +751,8 @@ extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn,
struct iscsi_task *mtask);
+extern int bnx2i_send_iscsi_text(struct bnx2i_conn *conn,
+ struct iscsi_task *mtask);
extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn,
struct bnx2i_cmd *cmnd);
extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn,
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 96505e3ab986..1da34c019b8a 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -445,6 +445,56 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
}
/**
+ * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware
+ * @conn: iscsi connection
+ * @mtask: driver command structure which is requesting
+ * a WQE to sent to chip for further processing
+ *
+ * prepare and post an iSCSI Text request WQE to CNIC firmware
+ */
+int bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn,
+ struct iscsi_task *mtask)
+{
+ struct bnx2i_cmd *bnx2i_cmd;
+ struct bnx2i_text_request *text_wqe;
+ struct iscsi_text *text_hdr;
+ u32 dword;
+
+ bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data;
+ text_hdr = (struct iscsi_text *)mtask->hdr;
+ text_wqe = (struct bnx2i_text_request *) bnx2i_conn->ep->qp.sq_prod_qe;
+
+ memset(text_wqe, 0, sizeof(struct bnx2i_text_request));
+
+ text_wqe->op_code = text_hdr->opcode;
+ text_wqe->op_attr = text_hdr->flags;
+ text_wqe->data_length = ntoh24(text_hdr->dlength);
+ text_wqe->itt = mtask->itt |
+ (ISCSI_TASK_TYPE_MPATH << ISCSI_TEXT_REQUEST_TYPE_SHIFT);
+ text_wqe->ttt = be32_to_cpu(text_hdr->ttt);
+
+ text_wqe->cmd_sn = be32_to_cpu(text_hdr->cmdsn);
+
+ text_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
+ text_wqe->resp_bd_list_addr_hi =
+ (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32);
+
+ dword = ((1 << ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT) |
+ (bnx2i_conn->gen_pdu.resp_buf_size <<
+ ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
+ text_wqe->resp_buffer = dword;
+ text_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
+ text_wqe->bd_list_addr_hi =
+ (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
+ text_wqe->num_bds = 1;
+ text_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
+
+ bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
+ return 0;
+}
+
+
+/**
* bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware
* @conn: iscsi connection
* @cmd: driver command structure which is requesting
@@ -490,15 +540,18 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn,
bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
nopout_hdr = (struct iscsi_nopout *)task->hdr;
nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe;
+
+ memset(nopout_wqe, 0x00, sizeof(struct bnx2i_nop_out_request));
+
nopout_wqe->op_code = nopout_hdr->opcode;
nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
memcpy(nopout_wqe->lun, nopout_hdr->lun, 8);
if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
- u32 tmp = nopout_hdr->lun[0];
+ u32 tmp = nopout_wqe->lun[0];
/* 57710 requires LUN field to be swapped */
- nopout_hdr->lun[0] = nopout_hdr->lun[1];
- nopout_hdr->lun[1] = tmp;
+ nopout_wqe->lun[0] = nopout_wqe->lun[1];
+ nopout_wqe->lun[1] = tmp;
}
nopout_wqe->itt = ((u16)task->itt |
@@ -1425,6 +1478,68 @@ done:
return 0;
}
+
+/**
+ * bnx2i_process_text_resp - this function handles iscsi text response
+ * @session: iscsi session pointer
+ * @bnx2i_conn: iscsi connection pointer
+ * @cqe: pointer to newly DMA'ed CQE entry for processing
+ *
+ * process iSCSI Text Response CQE& complete it to open-iscsi user daemon
+ */
+static int bnx2i_process_text_resp(struct iscsi_session *session,
+ struct bnx2i_conn *bnx2i_conn,
+ struct cqe *cqe)
+{
+ struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
+ struct iscsi_task *task;
+ struct bnx2i_text_response *text;
+ struct iscsi_text_rsp *resp_hdr;
+ int pld_len;
+ int pad_len;
+
+ text = (struct bnx2i_text_response *) cqe;
+ spin_lock(&session->lock);
+ task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
+ if (!task)
+ goto done;
+
+ resp_hdr = (struct iscsi_text_rsp *)&bnx2i_conn->gen_pdu.resp_hdr;
+ memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
+ resp_hdr->opcode = text->op_code;
+ resp_hdr->flags = text->response_flags;
+ resp_hdr->hlength = 0;
+
+ hton24(resp_hdr->dlength, text->data_length);
+ resp_hdr->itt = task->hdr->itt;
+ resp_hdr->ttt = cpu_to_be32(text->ttt);
+ resp_hdr->statsn = task->hdr->exp_statsn;
+ resp_hdr->exp_cmdsn = cpu_to_be32(text->exp_cmd_sn);
+ resp_hdr->max_cmdsn = cpu_to_be32(text->max_cmd_sn);
+ pld_len = text->data_length;
+ bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf +
+ pld_len;
+ pad_len = 0;
+ if (pld_len & 0x3)
+ pad_len = 4 - (pld_len % 4);
+
+ if (pad_len) {
+ int i = 0;
+ for (i = 0; i < pad_len; i++) {
+ bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0;
+ bnx2i_conn->gen_pdu.resp_wr_ptr++;
+ }
+ }
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+ bnx2i_conn->gen_pdu.resp_buf,
+ bnx2i_conn->gen_pdu.resp_wr_ptr -
+ bnx2i_conn->gen_pdu.resp_buf);
+done:
+ spin_unlock(&session->lock);
+ return 0;
+}
+
+
/**
* bnx2i_process_tmf_resp - this function handles iscsi TMF response
* @session: iscsi session pointer
@@ -1766,6 +1881,10 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
bnx2i_process_tmf_resp(session, bnx2i_conn,
qp->cq_cons_qe);
break;
+ case ISCSI_OP_TEXT_RSP:
+ bnx2i_process_text_resp(session, bnx2i_conn,
+ qp->cq_cons_qe);
+ break;
case ISCSI_OP_LOGOUT_RSP:
bnx2i_process_logout_resp(session, bnx2i_conn,
qp->cq_cons_qe);
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 72a7b2d4a439..1d24a2819736 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
#define DRV_MODULE_NAME "bnx2i"
-#define DRV_MODULE_VERSION "2.6.2.2"
-#define DRV_MODULE_RELDATE "Nov 23, 2010"
+#define DRV_MODULE_VERSION "2.6.2.3"
+#define DRV_MODULE_RELDATE "Dec 31, 2010"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -29,7 +29,7 @@ static char version[] __devinitdata =
MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com> and "
"Eddie Wai <eddie.wai@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711/57712"
" iSCSI Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
@@ -88,9 +88,11 @@ void bnx2i_identify_device(struct bnx2i_hba *hba)
(hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
- } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
- hba->pci_did == PCI_DEVICE_ID_NX2_57711 ||
- hba->pci_did == PCI_DEVICE_ID_NX2_57711E)
+ } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_57711 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_57711E ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_57712 ||
+ hba->pci_did == PCI_DEVICE_ID_NX2_57712E)
set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
else
printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
@@ -161,6 +163,21 @@ void bnx2i_start(void *handle)
struct bnx2i_hba *hba = handle;
int i = HZ;
+ if (!hba->cnic->max_iscsi_conn) {
+ printk(KERN_ALERT "bnx2i: dev %s does not support "
+ "iSCSI\n", hba->netdev->name);
+
+ if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
+ mutex_lock(&bnx2i_dev_lock);
+ list_del_init(&hba->link);
+ adapter_count--;
+ hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
+ clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
+ mutex_unlock(&bnx2i_dev_lock);
+ bnx2i_free_hba(hba);
+ }
+ return;
+ }
bnx2i_send_fw_iscsi_init_msg(hba);
while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
msleep(BNX2I_INIT_POLL_TIME);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index f0dce26593eb..1809f9ccc4ce 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1092,6 +1092,9 @@ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task)
case ISCSI_OP_SCSI_TMFUNC:
rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task);
break;
+ case ISCSI_OP_TEXT:
+ rc = bnx2i_send_iscsi_text(bnx2i_conn, task);
+ break;
default:
iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data,
"send_gen: unsupported op 0x%x\n",
@@ -1455,42 +1458,40 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn)
/**
- * bnx2i_conn_get_param - return iscsi connection parameter to caller
- * @cls_conn: pointer to iscsi cls conn
+ * bnx2i_ep_get_param - return iscsi ep parameter to caller
+ * @ep: pointer to iscsi endpoint
* @param: parameter type identifier
* @buf: buffer pointer
*
- * returns iSCSI connection parameters
+ * returns iSCSI ep parameters
*/
-static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
+static int bnx2i_ep_get_param(struct iscsi_endpoint *ep,
+ enum iscsi_param param, char *buf)
{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct bnx2i_conn *bnx2i_conn = conn->dd_data;
- int len = 0;
+ struct bnx2i_endpoint *bnx2i_ep = ep->dd_data;
+ struct bnx2i_hba *hba = bnx2i_ep->hba;
+ int len = -ENOTCONN;
- if (!(bnx2i_conn && bnx2i_conn->ep && bnx2i_conn->ep->hba))
- goto out;
+ if (!hba)
+ return -ENOTCONN;
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
- if (bnx2i_conn->ep->cm_sk)
- len = sprintf(buf, "%hu\n",
- bnx2i_conn->ep->cm_sk->dst_port);
- mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_ep->cm_sk)
+ len = sprintf(buf, "%hu\n", bnx2i_ep->cm_sk->dst_port);
+ mutex_unlock(&hba->net_dev_lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock);
- if (bnx2i_conn->ep->cm_sk)
- len = sprintf(buf, "%pI4\n",
- &bnx2i_conn->ep->cm_sk->dst_ip);
- mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock);
+ mutex_lock(&hba->net_dev_lock);
+ if (bnx2i_ep->cm_sk)
+ len = sprintf(buf, "%pI4\n", &bnx2i_ep->cm_sk->dst_ip);
+ mutex_unlock(&hba->net_dev_lock);
break;
default:
- return iscsi_conn_get_param(cls_conn, param, buf);
+ return -ENOSYS;
}
-out:
+
return len;
}
@@ -1935,13 +1936,13 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
cnic_dev_10g = 1;
switch (bnx2i_ep->state) {
- case EP_STATE_CONNECT_FAILED:
case EP_STATE_CLEANUP_FAILED:
case EP_STATE_OFLD_FAILED:
case EP_STATE_DISCONN_TIMEDOUT:
ret = 0;
break;
case EP_STATE_CONNECT_START:
+ case EP_STATE_CONNECT_FAILED:
case EP_STATE_CONNECT_COMPL:
case EP_STATE_ULP_UPDATE_START:
case EP_STATE_ULP_UPDATE_COMPL:
@@ -2167,7 +2168,8 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.name = "bnx2i",
.caps = CAP_RECOVERY_L0 | CAP_HDRDGST |
CAP_MULTI_R2T | CAP_DATADGST |
- CAP_DATA_PATH_OFFLOAD,
+ CAP_DATA_PATH_OFFLOAD |
+ CAP_TEXT_NEGO,
.param_mask = ISCSI_MAX_RECV_DLENGTH |
ISCSI_MAX_XMIT_DLENGTH |
ISCSI_HDRDGST_EN |
@@ -2200,7 +2202,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.bind_conn = bnx2i_conn_bind,
.destroy_conn = bnx2i_conn_destroy,
.set_param = iscsi_set_param,
- .get_conn_param = bnx2i_conn_get_param,
+ .get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.get_host_param = bnx2i_host_get_param,
.start_conn = bnx2i_conn_start,
@@ -2209,6 +2211,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
.xmit_task = bnx2i_task_xmit,
.get_stats = bnx2i_conn_get_stats,
/* TCP connect - disconnect - option-2 interface calls */
+ .get_ep_param = bnx2i_ep_get_param,
.ep_connect = bnx2i_ep_connect,
.ep_poll = bnx2i_ep_poll,
.ep_disconnect = bnx2i_ep_disconnect,
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index a129a170b47b..fc2cdb62f53b 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -105,7 +105,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
/* owner and name should be set already */
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST
| CAP_DATADGST | CAP_DIGEST_OFFLOAD |
- CAP_PADDING_OFFLOAD,
+ CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO,
.param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH |
ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN |
ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T |
@@ -137,7 +137,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
.destroy_conn = iscsi_tcp_conn_teardown,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_conn_stop,
- .get_conn_param = cxgbi_get_conn_param,
+ .get_conn_param = iscsi_conn_get_param,
.set_param = cxgbi_set_conn_param,
.get_stats = cxgbi_get_conn_stats,
/* pdu xmit req from user space */
@@ -152,6 +152,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
.xmit_pdu = cxgbi_conn_xmit_pdu,
.parse_pdu_itt = cxgbi_parse_pdu_itt,
/* TCP connect/disconnect */
+ .get_ep_param = cxgbi_get_ep_param,
.ep_connect = cxgbi_ep_connect,
.ep_poll = cxgbi_ep_poll,
.ep_disconnect = cxgbi_ep_disconnect,
@@ -1108,10 +1109,11 @@ static int ddp_set_map(struct cxgbi_sock *csk, struct cxgbi_pagepod_hdr *hdr,
csk, idx, npods, gl);
for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {
- struct sk_buff *skb = ddp->gl_skb[idx];
+ struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) +
+ PPOD_SIZE, 0, GFP_ATOMIC);
- /* hold on to the skb until we clear the ddp mapping */
- skb_get(skb);
+ if (!skb)
+ return -ENOMEM;
ulp_mem_io_set_hdr(skb, pm_addr);
cxgbi_ddp_ppod_set((struct cxgbi_pagepod *)(skb->head +
@@ -1136,56 +1138,20 @@ static void ddp_clear_map(struct cxgbi_hba *chba, unsigned int tag,
cdev, idx, npods, tag);
for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {
- struct sk_buff *skb = ddp->gl_skb[idx];
+ struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) +
+ PPOD_SIZE, 0, GFP_ATOMIC);
if (!skb) {
- pr_err("tag 0x%x, 0x%x, %d/%u, skb NULL.\n",
+ pr_err("tag 0x%x, 0x%x, %d/%u, skb OOM.\n",
tag, idx, i, npods);
continue;
}
- ddp->gl_skb[idx] = NULL;
- memset(skb->head + sizeof(struct ulp_mem_io), 0, PPOD_SIZE);
ulp_mem_io_set_hdr(skb, pm_addr);
skb->priority = CPL_PRIORITY_CONTROL;
cxgb3_ofld_send(cdev->lldev, skb);
}
}
-static void ddp_free_gl_skb(struct cxgbi_ddp_info *ddp, int idx, int cnt)
-{
- int i;
-
- log_debug(1 << CXGBI_DBG_DDP,
- "ddp 0x%p, idx %d, cnt %d.\n", ddp, idx, cnt);
-
- for (i = 0; i < cnt; i++, idx++)
- if (ddp->gl_skb[idx]) {
- kfree_skb(ddp->gl_skb[idx]);
- ddp->gl_skb[idx] = NULL;
- }
-}
-
-static int ddp_alloc_gl_skb(struct cxgbi_ddp_info *ddp, int idx,
- int cnt, gfp_t gfp)
-{
- int i;
-
- log_debug(1 << CXGBI_DBG_DDP,
- "ddp 0x%p, idx %d, cnt %d.\n", ddp, idx, cnt);
-
- for (i = 0; i < cnt; i++) {
- struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) +
- PPOD_SIZE, 0, gfp);
- if (skb)
- ddp->gl_skb[idx + i] = skb;
- else {
- ddp_free_gl_skb(ddp, idx, i);
- return -ENOMEM;
- }
- }
- return 0;
-}
-
static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk,
unsigned int tid, int pg_idx, bool reply)
{
@@ -1316,8 +1282,6 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev)
}
tdev->ulp_iscsi = ddp;
- cdev->csk_ddp_free_gl_skb = ddp_free_gl_skb;
- cdev->csk_ddp_alloc_gl_skb = ddp_alloc_gl_skb;
cdev->csk_ddp_setup_digest = ddp_setup_conn_digest;
cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx;
cdev->csk_ddp_set = ddp_set_map;
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h
index 5f5e3394b594..20593fd69d8f 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h
@@ -24,10 +24,21 @@
extern cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS];
-#define cxgb3i_get_private_ipv4addr(ndev) \
- (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr)
-#define cxgb3i_set_private_ipv4addr(ndev, addr) \
- (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) = addr
+static inline unsigned int cxgb3i_get_private_ipv4addr(struct net_device *ndev)
+{
+ return ((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr;
+}
+
+static inline void cxgb3i_set_private_ipv4addr(struct net_device *ndev,
+ unsigned int addr)
+{
+ struct port_info *pi = (struct port_info *)netdev_priv(ndev);
+
+ pi->iscsic.flags = addr ? 1 : 0;
+ pi->iscsi_ipv4addr = addr;
+ if (addr)
+ memcpy(pi->iscsic.mac_addr, ndev->dev_addr, ETH_ALEN);
+}
struct cpl_iscsi_hdr_norss {
union opcode_tid ot;
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 8c04fada710b..f3a4cd7cf782 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -106,7 +106,7 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
.name = DRV_MODULE_NAME,
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST |
CAP_DATADGST | CAP_DIGEST_OFFLOAD |
- CAP_PADDING_OFFLOAD,
+ CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO,
.param_mask = ISCSI_MAX_RECV_DLENGTH | ISCSI_MAX_XMIT_DLENGTH |
ISCSI_HDRDGST_EN | ISCSI_DATADGST_EN |
ISCSI_INITIAL_R2T_EN | ISCSI_MAX_R2T |
@@ -138,7 +138,7 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
.destroy_conn = iscsi_tcp_conn_teardown,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_conn_stop,
- .get_conn_param = cxgbi_get_conn_param,
+ .get_conn_param = iscsi_conn_get_param,
.set_param = cxgbi_set_conn_param,
.get_stats = cxgbi_get_conn_stats,
/* pdu xmit req from user space */
@@ -153,6 +153,7 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
.xmit_pdu = cxgbi_conn_xmit_pdu,
.parse_pdu_itt = cxgbi_parse_pdu_itt,
/* TCP connect/disconnect */
+ .get_ep_param = cxgbi_get_ep_param,
.ep_connect = cxgbi_ep_connect,
.ep_poll = cxgbi_ep_poll,
.ep_disconnect = cxgbi_ep_disconnect,
@@ -1425,8 +1426,6 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
cxgbi_ddp_page_size_factor(pgsz_factor);
cxgb4_iscsi_init(lldi->ports[0], tagmask, pgsz_factor);
- cdev->csk_ddp_free_gl_skb = NULL;
- cdev->csk_ddp_alloc_gl_skb = NULL;
cdev->csk_ddp_setup_digest = ddp_setup_conn_digest;
cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx;
cdev->csk_ddp_set = ddp_set_map;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index a24dff9f9163..de764ea7419d 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -530,6 +530,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
csk->dst = dst;
csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr;
csk->daddr.sin_port = daddr->sin_port;
+ csk->daddr.sin_family = daddr->sin_family;
csk->saddr.sin_addr.s_addr = rt->rt_src;
return csk;
@@ -1264,12 +1265,6 @@ static int ddp_tag_reserve(struct cxgbi_sock *csk, unsigned int tid,
return idx;
}
- if (cdev->csk_ddp_alloc_gl_skb) {
- err = cdev->csk_ddp_alloc_gl_skb(ddp, idx, npods, gfp);
- if (err < 0)
- goto unmark_entries;
- }
-
tag = cxgbi_ddp_tag_base(tformat, sw_tag);
tag |= idx << PPOD_IDX_SHIFT;
@@ -1280,11 +1275,8 @@ static int ddp_tag_reserve(struct cxgbi_sock *csk, unsigned int tid,
hdr.page_offset = htonl(gl->offset);
err = cdev->csk_ddp_set(csk, &hdr, idx, npods, gl);
- if (err < 0) {
- if (cdev->csk_ddp_free_gl_skb)
- cdev->csk_ddp_free_gl_skb(ddp, idx, npods);
+ if (err < 0)
goto unmark_entries;
- }
ddp->idx_last = idx;
log_debug(1 << CXGBI_DBG_DDP,
@@ -1350,8 +1342,6 @@ static void ddp_destroy(struct kref *kref)
>> PPOD_PAGES_SHIFT;
pr_info("cdev 0x%p, ddp %d + %d.\n", cdev, i, npods);
kfree(gl);
- if (cdev->csk_ddp_free_gl_skb)
- cdev->csk_ddp_free_gl_skb(ddp, i, npods);
i += npods;
} else
i++;
@@ -1394,8 +1384,6 @@ int cxgbi_ddp_init(struct cxgbi_device *cdev,
return -ENOMEM;
}
ddp->gl_map = (struct cxgbi_gather_list **)(ddp + 1);
- ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) +
- ppmax * sizeof(struct cxgbi_gather_list *));
cdev->ddp = ddp;
spin_lock_init(&ddp->map_lock);
@@ -1895,13 +1883,16 @@ EXPORT_SYMBOL_GPL(cxgbi_conn_alloc_pdu);
static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc)
{
- u8 submode = 0;
+ if (hcrc || dcrc) {
+ u8 submode = 0;
- if (hcrc)
- submode |= 1;
- if (dcrc)
- submode |= 2;
- cxgbi_skcb_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode;
+ if (hcrc)
+ submode |= 1;
+ if (dcrc)
+ submode |= 2;
+ cxgbi_skcb_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode;
+ } else
+ cxgbi_skcb_ulp_mode(skb) = 0;
}
int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
@@ -2197,32 +2188,34 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
}
EXPORT_SYMBOL_GPL(cxgbi_set_conn_param);
-int cxgbi_get_conn_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
+int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param,
+ char *buf)
{
- struct iscsi_conn *iconn = cls_conn->dd_data;
+ struct cxgbi_endpoint *cep = ep->dd_data;
+ struct cxgbi_sock *csk;
int len;
log_debug(1 << CXGBI_DBG_ISCSI,
- "cls_conn 0x%p, param %d.\n", cls_conn, param);
+ "cls_conn 0x%p, param %d.\n", ep, param);
switch (param) {
case ISCSI_PARAM_CONN_PORT:
- spin_lock_bh(&iconn->session->lock);
- len = sprintf(buf, "%hu\n", iconn->portal_port);
- spin_unlock_bh(&iconn->session->lock);
- break;
case ISCSI_PARAM_CONN_ADDRESS:
- spin_lock_bh(&iconn->session->lock);
- len = sprintf(buf, "%s\n", iconn->portal_address);
- spin_unlock_bh(&iconn->session->lock);
- break;
+ if (!cep)
+ return -ENOTCONN;
+
+ csk = cep->csk;
+ if (!csk)
+ return -ENOTCONN;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &csk->daddr, param, buf);
default:
- return iscsi_conn_get_param(cls_conn, param, buf);
+ return -ENOSYS;
}
return len;
}
-EXPORT_SYMBOL_GPL(cxgbi_get_conn_param);
+EXPORT_SYMBOL_GPL(cxgbi_get_ep_param);
struct iscsi_cls_conn *
cxgbi_create_conn(struct iscsi_cls_session *cls_session, u32 cid)
@@ -2289,11 +2282,6 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session,
cxgbi_conn_max_xmit_dlength(conn);
cxgbi_conn_max_recv_dlength(conn);
- spin_lock_bh(&conn->session->lock);
- sprintf(conn->portal_address, "%pI4", &csk->daddr.sin_addr.s_addr);
- conn->portal_port = ntohs(csk->daddr.sin_port);
- spin_unlock_bh(&conn->session->lock);
-
log_debug(1 << CXGBI_DBG_ISCSI,
"cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n",
cls_session, cls_conn, ep, cconn, csk);
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index c57d59db000c..0a20fd5f7102 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -131,7 +131,6 @@ struct cxgbi_ddp_info {
unsigned int rsvd_tag_mask;
spinlock_t map_lock;
struct cxgbi_gather_list **gl_map;
- struct sk_buff **gl_skb;
};
#define DDP_PGIDX_MAX 4
@@ -536,8 +535,6 @@ struct cxgbi_device {
struct cxgbi_ddp_info *ddp;
void (*dev_ddp_cleanup)(struct cxgbi_device *);
- void (*csk_ddp_free_gl_skb)(struct cxgbi_ddp_info *, int, int);
- int (*csk_ddp_alloc_gl_skb)(struct cxgbi_ddp_info *, int, int, gfp_t);
int (*csk_ddp_set)(struct cxgbi_sock *, struct cxgbi_pagepod_hdr *,
unsigned int, unsigned int,
struct cxgbi_gather_list *);
@@ -715,7 +712,7 @@ void cxgbi_cleanup_task(struct iscsi_task *task);
void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *);
int cxgbi_set_conn_param(struct iscsi_cls_conn *,
enum iscsi_param, char *, int);
-int cxgbi_get_conn_param(struct iscsi_cls_conn *, enum iscsi_param, char *);
+int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param, char *);
struct iscsi_cls_conn *cxgbi_create_conn(struct iscsi_cls_session *, u32);
int cxgbi_bind_conn(struct iscsi_cls_session *,
struct iscsi_cls_conn *, u64, int);
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index b837c5b3c8f9..564e6ecd17c2 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -25,16 +25,9 @@
#include <scsi/scsi_dh.h>
#include "../scsi_priv.h"
-struct scsi_dh_devinfo_list {
- struct list_head node;
- char vendor[9];
- char model[17];
- struct scsi_device_handler *handler;
-};
-
static DEFINE_SPINLOCK(list_lock);
static LIST_HEAD(scsi_dh_list);
-static LIST_HEAD(scsi_dh_dev_list);
+static int scsi_dh_list_idx = 1;
static struct scsi_device_handler *get_device_handler(const char *name)
{
@@ -51,40 +44,18 @@ static struct scsi_device_handler *get_device_handler(const char *name)
return found;
}
-
-static struct scsi_device_handler *
-scsi_dh_cache_lookup(struct scsi_device *sdev)
+static struct scsi_device_handler *get_device_handler_by_idx(int idx)
{
- struct scsi_dh_devinfo_list *tmp;
- struct scsi_device_handler *found_dh = NULL;
+ struct scsi_device_handler *tmp, *found = NULL;
spin_lock(&list_lock);
- list_for_each_entry(tmp, &scsi_dh_dev_list, node) {
- if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) &&
- !strncmp(sdev->model, tmp->model, strlen(tmp->model))) {
- found_dh = tmp->handler;
+ list_for_each_entry(tmp, &scsi_dh_list, list) {
+ if (tmp->idx == idx) {
+ found = tmp;
break;
}
}
spin_unlock(&list_lock);
-
- return found_dh;
-}
-
-static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh,
- struct scsi_device *sdev)
-{
- int i, found = 0;
-
- for(i = 0; scsi_dh->devlist[i].vendor; i++) {
- if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
- strlen(scsi_dh->devlist[i].vendor)) &&
- !strncmp(sdev->model, scsi_dh->devlist[i].model,
- strlen(scsi_dh->devlist[i].model))) {
- found = 1;
- break;
- }
- }
return found;
}
@@ -102,41 +73,14 @@ device_handler_match(struct scsi_device_handler *scsi_dh,
struct scsi_device *sdev)
{
struct scsi_device_handler *found_dh = NULL;
- struct scsi_dh_devinfo_list *tmp;
+ int idx;
- found_dh = scsi_dh_cache_lookup(sdev);
- if (found_dh)
- return found_dh;
+ idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model,
+ SCSI_DEVINFO_DH);
+ found_dh = get_device_handler_by_idx(idx);
- if (scsi_dh) {
- if (scsi_dh_handler_lookup(scsi_dh, sdev))
- found_dh = scsi_dh;
- } else {
- struct scsi_device_handler *tmp_dh;
-
- spin_lock(&list_lock);
- list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
- if (scsi_dh_handler_lookup(tmp_dh, sdev))
- found_dh = tmp_dh;
- }
- spin_unlock(&list_lock);
- }
-
- if (found_dh) { /* If device is found, add it to the cache */
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (tmp) {
- strncpy(tmp->vendor, sdev->vendor, 8);
- strncpy(tmp->model, sdev->model, 16);
- tmp->vendor[8] = '\0';
- tmp->model[16] = '\0';
- tmp->handler = found_dh;
- spin_lock(&list_lock);
- list_add(&tmp->node, &scsi_dh_dev_list);
- spin_unlock(&list_lock);
- } else {
- found_dh = NULL;
- }
- }
+ if (scsi_dh && found_dh != scsi_dh)
+ found_dh = NULL;
return found_dh;
}
@@ -373,12 +317,25 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
*/
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
{
+ int i;
+
if (get_device_handler(scsi_dh->name))
return -EBUSY;
spin_lock(&list_lock);
+ scsi_dh->idx = scsi_dh_list_idx++;
list_add(&scsi_dh->list, &scsi_dh_list);
spin_unlock(&list_lock);
+
+ for (i = 0; scsi_dh->devlist[i].vendor; i++) {
+ scsi_dev_info_list_add_keyed(0,
+ scsi_dh->devlist[i].vendor,
+ scsi_dh->devlist[i].model,
+ NULL,
+ scsi_dh->idx,
+ SCSI_DEVINFO_DH);
+ }
+
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
@@ -395,7 +352,7 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler);
*/
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
{
- struct scsi_dh_devinfo_list *tmp, *pos;
+ int i;
if (!get_device_handler(scsi_dh->name))
return -ENODEV;
@@ -403,14 +360,14 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
scsi_dh_notifier_remove);
+ for (i = 0; scsi_dh->devlist[i].vendor; i++) {
+ scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor,
+ scsi_dh->devlist[i].model,
+ SCSI_DEVINFO_DH);
+ }
+
spin_lock(&list_lock);
list_del(&scsi_dh->list);
- list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) {
- if (pos->handler == scsi_dh) {
- list_del(&pos->node);
- kfree(pos);
- }
- }
spin_unlock(&list_lock);
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
@@ -576,6 +533,10 @@ static int __init scsi_dh_init(void)
{
int r;
+ r = scsi_dev_info_add_list(SCSI_DEVINFO_DH, "SCSI Device Handler");
+ if (r)
+ return r;
+
r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
if (!r)
@@ -590,6 +551,7 @@ static void __exit scsi_dh_exit(void)
bus_for_each_dev(&scsi_bus_type, NULL, NULL,
scsi_dh_sysfs_attr_remove);
bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
+ scsi_dev_info_remove_list(SCSI_DEVINFO_DH);
}
module_init(scsi_dh_init);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6b729324b8d3..7cae0bc85390 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -253,13 +253,15 @@ static void stpg_endio(struct request *req, int error)
{
struct alua_dh_data *h = req->end_io_data;
struct scsi_sense_hdr sense_hdr;
- unsigned err = SCSI_DH_IO;
+ unsigned err = SCSI_DH_OK;
if (error || host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE)
+ msg_byte(req->errors) != COMMAND_COMPLETE) {
+ err = SCSI_DH_IO;
goto done;
+ }
- if (err == SCSI_DH_IO && h->senselen > 0) {
+ if (h->senselen > 0) {
err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr);
if (!err) {
@@ -285,7 +287,8 @@ static void stpg_endio(struct request *req, int error)
print_alua_state(h->state));
}
done:
- blk_put_request(req);
+ req->end_io_data = NULL;
+ __blk_put_request(req->q, req);
if (h->callback_fn) {
h->callback_fn(h->callback_data, err);
h->callback_fn = h->callback_data = NULL;
@@ -303,7 +306,6 @@ done:
static unsigned submit_stpg(struct alua_dh_data *h)
{
struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
int stpg_len = 8;
struct scsi_device *sdev = h->sdev;
@@ -332,7 +334,7 @@ static unsigned submit_stpg(struct alua_dh_data *h)
rq->end_io_data = h;
blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
- return err;
+ return SCSI_DH_OK;
}
/*
@@ -730,7 +732,9 @@ static const struct scsi_dh_devlist alua_dev_list[] = {
{"Pillar", "Axiom" },
{"Intel", "Multi-Flex"},
{"NETAPP", "LUN"},
+ {"NETAPP", "LUN C-Mode"},
{"AIX", "NVDISK"},
+ {"Promise", "VTrak"},
{NULL, NULL}
};
@@ -759,7 +763,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
unsigned long flags;
int err = SCSI_DH_OK;
- scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
+ sizeof(*h) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 6faf472f7537..48441f6908a4 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -650,7 +650,7 @@ static int clariion_bus_attach(struct scsi_device *sdev)
unsigned long flags;
int err;
- scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
+ sizeof(*h) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index e3916641e627..b479f1eef968 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -225,7 +225,8 @@ static void start_stop_endio(struct request *req, int error)
}
}
done:
- blk_put_request(req);
+ req->end_io_data = NULL;
+ __blk_put_request(req->q, req);
if (h->callback_fn) {
h->callback_fn(h->callback_data, err);
h->callback_fn = h->callback_data = NULL;
@@ -338,8 +339,8 @@ static int hp_sw_bus_attach(struct scsi_device *sdev)
unsigned long flags;
int ret;
- scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
- + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
+ scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
+ + sizeof(*h) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
HP_SW_NAME);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 5be3ae15cb71..293c183dfe6d 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -281,11 +281,13 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
}
static struct request *rdac_failover_get(struct scsi_device *sdev,
- struct rdac_dh_data *h)
+ struct rdac_dh_data *h, struct list_head *list)
{
struct request *rq;
struct rdac_mode_common *common;
unsigned data_size;
+ struct rdac_queue_data *qdata;
+ u8 *lun_table;
if (h->ctlr->use_ms10) {
struct rdac_pg_expanded *rdac_pg;
@@ -298,6 +300,7 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
rdac_pg->subpage_code = 0x1;
rdac_pg->page_len[0] = 0x01;
rdac_pg->page_len[1] = 0x28;
+ lun_table = rdac_pg->lun_table;
} else {
struct rdac_pg_legacy *rdac_pg;
@@ -307,11 +310,16 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
common = &rdac_pg->common;
rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
rdac_pg->page_len = 0x68;
+ lun_table = rdac_pg->lun_table;
}
common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
common->rdac_options = RDAC_FORCED_QUIESENCE;
+ list_for_each_entry(qdata, list, entry) {
+ lun_table[qdata->h->lun] = 0x81;
+ }
+
/* get request for block layer packet command */
rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE);
if (!rq)
@@ -565,7 +573,6 @@ static void send_mode_select(struct work_struct *work)
int err, retry_cnt = RDAC_RETRY_COUNT;
struct rdac_queue_data *tmp, *qdata;
LIST_HEAD(list);
- u8 *lun_table;
spin_lock(&ctlr->ms_lock);
list_splice_init(&ctlr->ms_head, &list);
@@ -573,21 +580,12 @@ static void send_mode_select(struct work_struct *work)
ctlr->ms_sdev = NULL;
spin_unlock(&ctlr->ms_lock);
- if (ctlr->use_ms10)
- lun_table = ctlr->mode_select.expanded.lun_table;
- else
- lun_table = ctlr->mode_select.legacy.lun_table;
-
retry:
err = SCSI_DH_RES_TEMP_UNAVAIL;
- rq = rdac_failover_get(sdev, h);
+ rq = rdac_failover_get(sdev, h, &list);
if (!rq)
goto done;
- list_for_each_entry(qdata, &list, entry) {
- lun_table[qdata->h->lun] = 0x81;
- }
-
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
"%s MODE_SELECT command",
(char *) h->ctlr->array_name, h->ctlr->index,
@@ -769,6 +767,7 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"DELL", "MD32xx"},
{"DELL", "MD32xxi"},
{"DELL", "MD36xxi"},
+ {"DELL", "MD36xxf"},
{"LSI", "INF-01-00"},
{"ENGENIO", "INF-01-00"},
{"STK", "FLEXLINE 380"},
@@ -800,7 +799,7 @@ static int rdac_bus_attach(struct scsi_device *sdev)
int err;
char array_name[ARRAY_LABEL_LEN];
- scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
+ sizeof(*h) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
@@ -906,4 +905,5 @@ module_exit(rdac_exit);
MODULE_DESCRIPTION("Multipath LSI/Engenio RDAC driver");
MODULE_AUTHOR("Mike Christie, Chandra Seetharaman");
+MODULE_VERSION("01.00.0000.0000");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile
index 950f27615c76..f6d37d0271f7 100644
--- a/drivers/scsi/fcoe/Makefile
+++ b/drivers/scsi/fcoe/Makefile
@@ -1,2 +1,4 @@
obj-$(CONFIG_FCOE) += fcoe.o
obj-$(CONFIG_LIBFCOE) += libfcoe.o
+
+libfcoe-objs := fcoe_ctlr.o fcoe_transport.o
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 3becc6a20a4f..bde6ee5333eb 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -31,6 +31,7 @@
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
+#include <linux/workqueue.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_transport.h>
@@ -58,6 +59,8 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \
DEFINE_MUTEX(fcoe_config_mutex);
+static struct workqueue_struct *fcoe_wq;
+
/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */
static DECLARE_COMPLETION(fcoe_flush_completion);
@@ -72,7 +75,6 @@ static int fcoe_xmit(struct fc_lport *, struct fc_frame *);
static int fcoe_rcv(struct sk_buff *, struct net_device *,
struct packet_type *, struct net_device *);
static int fcoe_percpu_receive_thread(void *);
-static void fcoe_clean_pending_queue(struct fc_lport *);
static void fcoe_percpu_clean(struct fc_lport *);
static int fcoe_link_speed_update(struct fc_lport *);
static int fcoe_link_ok(struct fc_lport *);
@@ -80,7 +82,6 @@ static int fcoe_link_ok(struct fc_lport *);
static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
static int fcoe_hostlist_add(const struct fc_lport *);
-static void fcoe_check_wait_queue(struct fc_lport *, struct sk_buff *);
static int fcoe_device_notification(struct notifier_block *, ulong, void *);
static void fcoe_dev_setup(void);
static void fcoe_dev_cleanup(void);
@@ -101,10 +102,11 @@ static int fcoe_ddp_done(struct fc_lport *, u16);
static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *);
-static int fcoe_create(const char *, struct kernel_param *);
-static int fcoe_destroy(const char *, struct kernel_param *);
-static int fcoe_enable(const char *, struct kernel_param *);
-static int fcoe_disable(const char *, struct kernel_param *);
+static bool fcoe_match(struct net_device *netdev);
+static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode);
+static int fcoe_destroy(struct net_device *netdev);
+static int fcoe_enable(struct net_device *netdev);
+static int fcoe_disable(struct net_device *netdev);
static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
u32 did, struct fc_frame *,
@@ -117,24 +119,6 @@ static void fcoe_recv_frame(struct sk_buff *skb);
static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
-module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_FABRIC, S_IWUSR);
-__MODULE_PARM_TYPE(create, "string");
-MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
-module_param_call(create_vn2vn, fcoe_create, NULL,
- (void *)FIP_MODE_VN2VN, S_IWUSR);
-__MODULE_PARM_TYPE(create_vn2vn, "string");
-MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
- "on an Ethernet interface");
-module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
-__MODULE_PARM_TYPE(destroy, "string");
-MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
-module_param_call(enable, fcoe_enable, NULL, NULL, S_IWUSR);
-__MODULE_PARM_TYPE(enable, "string");
-MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
-module_param_call(disable, fcoe_disable, NULL, NULL, S_IWUSR);
-__MODULE_PARM_TYPE(disable, "string");
-MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
-
/* notification function for packets from net device */
static struct notifier_block fcoe_notifier = {
.notifier_call = fcoe_device_notification,
@@ -145,8 +129,8 @@ static struct notifier_block fcoe_cpu_notifier = {
.notifier_call = fcoe_cpu_callback,
};
-static struct scsi_transport_template *fcoe_transport_template;
-static struct scsi_transport_template *fcoe_vport_transport_template;
+static struct scsi_transport_template *fcoe_nport_scsi_transport;
+static struct scsi_transport_template *fcoe_vport_scsi_transport;
static int fcoe_vport_destroy(struct fc_vport *);
static int fcoe_vport_create(struct fc_vport *, bool disabled);
@@ -163,7 +147,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
.lport_set_port_id = fcoe_set_port_id,
};
-struct fc_function_template fcoe_transport_function = {
+struct fc_function_template fcoe_nport_fc_functions = {
.show_host_node_name = 1,
.show_host_port_name = 1,
.show_host_supported_classes = 1,
@@ -203,7 +187,7 @@ struct fc_function_template fcoe_transport_function = {
.bsg_request = fc_lport_bsg_request,
};
-struct fc_function_template fcoe_vport_transport_function = {
+struct fc_function_template fcoe_vport_fc_functions = {
.show_host_node_name = 1,
.show_host_port_name = 1,
.show_host_supported_classes = 1,
@@ -354,10 +338,18 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
struct fcoe_interface *fcoe;
int err;
+ if (!try_module_get(THIS_MODULE)) {
+ FCOE_NETDEV_DBG(netdev,
+ "Could not get a reference to the module\n");
+ fcoe = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL);
if (!fcoe) {
FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n");
- return NULL;
+ fcoe = ERR_PTR(-ENOMEM);
+ goto out_nomod;
}
dev_hold(netdev);
@@ -376,9 +368,15 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
fcoe_ctlr_destroy(&fcoe->ctlr);
kfree(fcoe);
dev_put(netdev);
- return NULL;
+ fcoe = ERR_PTR(err);
+ goto out_nomod;
}
+ goto out;
+
+out_nomod:
+ module_put(THIS_MODULE);
+out:
return fcoe;
}
@@ -440,6 +438,7 @@ static void fcoe_interface_release(struct kref *kref)
fcoe_ctlr_destroy(&fcoe->ctlr);
kfree(fcoe);
dev_put(netdev);
+ module_put(THIS_MODULE);
}
/**
@@ -503,7 +502,7 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr)
{
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
rtnl_lock();
if (!is_zero_ether_addr(port->data_src_addr))
@@ -559,17 +558,6 @@ static int fcoe_lport_config(struct fc_lport *lport)
}
/**
- * fcoe_queue_timer() - The fcoe queue timer
- * @lport: The local port
- *
- * Calls fcoe_check_wait_queue on timeout
- */
-static void fcoe_queue_timer(ulong lport)
-{
- fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
-}
-
-/**
* fcoe_get_wwn() - Get the world wide name from LLD if it supports it
* @netdev: the associated net device
* @wwn: the output WWN
@@ -648,7 +636,7 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
/* Setup lport private data to point to fcoe softc */
port = lport_priv(lport);
- fcoe = port->fcoe;
+ fcoe = port->priv;
/*
* Determine max frame size based on underlying device and optional
@@ -706,9 +694,9 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
lport->host->max_cmd_len = FCOE_MAX_CMD_LEN;
if (lport->vport)
- lport->host->transportt = fcoe_vport_transport_template;
+ lport->host->transportt = fcoe_vport_scsi_transport;
else
- lport->host->transportt = fcoe_transport_template;
+ lport->host->transportt = fcoe_nport_scsi_transport;
/* add the new host to the SCSI-ml */
rc = scsi_add_host(lport->host, dev);
@@ -758,7 +746,7 @@ bool fcoe_oem_match(struct fc_frame *fp)
static inline int fcoe_em_config(struct fc_lport *lport)
{
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
struct fcoe_interface *oldfcoe = NULL;
struct net_device *old_real_dev, *cur_real_dev;
u16 min_xid = FCOE_MIN_XID;
@@ -842,7 +830,7 @@ skip_oem:
static void fcoe_if_destroy(struct fc_lport *lport)
{
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
struct net_device *netdev = fcoe->netdev;
FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
@@ -884,7 +872,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
/* Release the Scsi_Host */
scsi_host_put(lport->host);
- module_put(THIS_MODULE);
}
/**
@@ -939,8 +926,9 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
struct device *parent, int npiv)
{
struct net_device *netdev = fcoe->netdev;
- struct fc_lport *lport = NULL;
+ struct fc_lport *lport, *n_port;
struct fcoe_port *port;
+ struct Scsi_Host *shost;
int rc;
/*
* parent is only a vport if npiv is 1,
@@ -950,13 +938,11 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
FCOE_NETDEV_DBG(netdev, "Create Interface\n");
- if (!npiv) {
- lport = libfc_host_alloc(&fcoe_shost_template,
- sizeof(struct fcoe_port));
- } else {
- lport = libfc_vport_create(vport,
- sizeof(struct fcoe_port));
- }
+ if (!npiv)
+ lport = libfc_host_alloc(&fcoe_shost_template, sizeof(*port));
+ else
+ lport = libfc_vport_create(vport, sizeof(*port));
+
if (!lport) {
FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n");
rc = -ENOMEM;
@@ -964,7 +950,9 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
}
port = lport_priv(lport);
port->lport = lport;
- port->fcoe = fcoe;
+ port->priv = fcoe;
+ port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH;
+ port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH;
INIT_WORK(&port->destroy_work, fcoe_destroy_work);
/* configure a fc_lport including the exchange manager */
@@ -1007,24 +995,27 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
goto out_lp_destroy;
}
- if (!npiv) {
- /*
- * fcoe_em_alloc() and fcoe_hostlist_add() both
- * need to be atomic with respect to other changes to the
- * hostlist since fcoe_em_alloc() looks for an existing EM
- * instance on host list updated by fcoe_hostlist_add().
- *
- * This is currently handled through the fcoe_config_mutex
- * begin held.
- */
-
+ /*
+ * fcoe_em_alloc() and fcoe_hostlist_add() both
+ * need to be atomic with respect to other changes to the
+ * hostlist since fcoe_em_alloc() looks for an existing EM
+ * instance on host list updated by fcoe_hostlist_add().
+ *
+ * This is currently handled through the fcoe_config_mutex
+ * begin held.
+ */
+ if (!npiv)
/* lport exch manager allocation */
rc = fcoe_em_config(lport);
- if (rc) {
- FCOE_NETDEV_DBG(netdev, "Could not configure the EM "
- "for the interface\n");
- goto out_lp_destroy;
- }
+ else {
+ shost = vport_to_shost(vport);
+ n_port = shost_priv(shost);
+ rc = fc_exch_mgr_list_clone(n_port, lport);
+ }
+
+ if (rc) {
+ FCOE_NETDEV_DBG(netdev, "Could not configure the EM\n");
+ goto out_lp_destroy;
}
fcoe_interface_get(fcoe);
@@ -1048,11 +1039,12 @@ out:
static int __init fcoe_if_init(void)
{
/* attach to scsi transport */
- fcoe_transport_template = fc_attach_transport(&fcoe_transport_function);
- fcoe_vport_transport_template =
- fc_attach_transport(&fcoe_vport_transport_function);
+ fcoe_nport_scsi_transport =
+ fc_attach_transport(&fcoe_nport_fc_functions);
+ fcoe_vport_scsi_transport =
+ fc_attach_transport(&fcoe_vport_fc_functions);
- if (!fcoe_transport_template) {
+ if (!fcoe_nport_scsi_transport) {
printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n");
return -ENODEV;
}
@@ -1069,10 +1061,10 @@ static int __init fcoe_if_init(void)
*/
int __exit fcoe_if_exit(void)
{
- fc_release_transport(fcoe_transport_template);
- fc_release_transport(fcoe_vport_transport_template);
- fcoe_transport_template = NULL;
- fcoe_vport_transport_template = NULL;
+ fc_release_transport(fcoe_nport_scsi_transport);
+ fc_release_transport(fcoe_vport_scsi_transport);
+ fcoe_nport_scsi_transport = NULL;
+ fcoe_vport_scsi_transport = NULL;
return 0;
}
@@ -1359,108 +1351,22 @@ err2:
}
/**
- * fcoe_start_io() - Start FCoE I/O
- * @skb: The packet to be transmitted
- *
- * This routine is called from the net device to start transmitting
- * FCoE packets.
- *
- * Returns: 0 for success
- */
-static inline int fcoe_start_io(struct sk_buff *skb)
-{
- struct sk_buff *nskb;
- int rc;
-
- nskb = skb_clone(skb, GFP_ATOMIC);
- rc = dev_queue_xmit(nskb);
- if (rc != 0)
- return rc;
- kfree_skb(skb);
- return 0;
-}
-
-/**
- * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC
+ * fcoe_alloc_paged_crc_eof() - Allocate a page to be used for the trailer CRC
* @skb: The packet to be transmitted
* @tlen: The total length of the trailer
*
- * This routine allocates a page for frame trailers. The page is re-used if
- * there is enough room left on it for the current trailer. If there isn't
- * enough buffer left a new page is allocated for the trailer. Reference to
- * the page from this function as well as the skbs using the page fragments
- * ensure that the page is freed at the appropriate time.
- *
* Returns: 0 for success
*/
-static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen)
+static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen)
{
struct fcoe_percpu_s *fps;
- struct page *page;
+ int rc;
fps = &get_cpu_var(fcoe_percpu);
- page = fps->crc_eof_page;
- if (!page) {
- page = alloc_page(GFP_ATOMIC);
- if (!page) {
- put_cpu_var(fcoe_percpu);
- return -ENOMEM;
- }
- fps->crc_eof_page = page;
- fps->crc_eof_offset = 0;
- }
-
- get_page(page);
- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
- fps->crc_eof_offset, tlen);
- skb->len += tlen;
- skb->data_len += tlen;
- skb->truesize += tlen;
- fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
-
- if (fps->crc_eof_offset >= PAGE_SIZE) {
- fps->crc_eof_page = NULL;
- fps->crc_eof_offset = 0;
- put_page(page);
- }
+ rc = fcoe_get_paged_crc_eof(skb, tlen, fps);
put_cpu_var(fcoe_percpu);
- return 0;
-}
-/**
- * fcoe_fc_crc() - Calculates the CRC for a given frame
- * @fp: The frame to be checksumed
- *
- * This uses crc32() routine to calculate the CRC for a frame
- *
- * Return: The 32 bit CRC value
- */
-u32 fcoe_fc_crc(struct fc_frame *fp)
-{
- struct sk_buff *skb = fp_skb(fp);
- struct skb_frag_struct *frag;
- unsigned char *data;
- unsigned long off, len, clen;
- u32 crc;
- unsigned i;
-
- crc = crc32(~0, skb->data, skb_headlen(skb));
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- off = frag->page_offset;
- len = frag->size;
- while (len > 0) {
- clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
- data = kmap_atomic(frag->page + (off >> PAGE_SHIFT),
- KM_SKB_DATA_SOFTIRQ);
- crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
- kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
- off += clen;
- len -= clen;
- }
- }
- return crc;
+ return rc;
}
/**
@@ -1483,7 +1389,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
unsigned int tlen; /* trailer length */
unsigned int elen; /* eth header, may include vlan */
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
u8 sof, eof;
struct fcoe_hdr *hp;
@@ -1524,7 +1430,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
/* copy port crc and eof to the skb buff */
if (skb_is_nonlinear(skb)) {
skb_frag_t *frag;
- if (fcoe_get_paged_crc_eof(skb, tlen)) {
+ if (fcoe_alloc_paged_crc_eof(skb, tlen)) {
kfree_skb(skb);
return -ENOMEM;
}
@@ -1604,6 +1510,56 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb)
}
/**
+ * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC
+ * @lport: The local port the frame was received on
+ * @fp: The received frame
+ *
+ * Return: 0 on passing filtering checks
+ */
+static inline int fcoe_filter_frames(struct fc_lport *lport,
+ struct fc_frame *fp)
+{
+ struct fcoe_interface *fcoe;
+ struct fc_frame_header *fh;
+ struct sk_buff *skb = (struct sk_buff *)fp;
+ struct fcoe_dev_stats *stats;
+
+ /*
+ * We only check CRC if no offload is available and if it is
+ * it's solicited data, in which case, the FCP layer would
+ * check it during the copy.
+ */
+ if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY)
+ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
+ else
+ fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
+
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
+ fh = fc_frame_header_get(fp);
+ if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP)
+ return 0;
+
+ fcoe = ((struct fcoe_port *)lport_priv(lport))->priv;
+ if (is_fip_mode(&fcoe->ctlr) && fc_frame_payload_op(fp) == ELS_LOGO &&
+ ntoh24(fh->fh_s_id) == FC_FID_FLOGI) {
+ FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n");
+ return -EINVAL;
+ }
+
+ if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED) ||
+ le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) {
+ fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
+ return 0;
+ }
+
+ stats = per_cpu_ptr(lport->dev_stats, get_cpu());
+ stats->InvalidCRCCount++;
+ if (stats->InvalidCRCCount < 5)
+ printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
+ return -EINVAL;
+}
+
+/**
* fcoe_recv_frame() - process a single received frame
* @skb: frame to process
*/
@@ -1613,7 +1569,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
struct fc_lport *lport;
struct fcoe_rcv_info *fr;
struct fcoe_dev_stats *stats;
- struct fc_frame_header *fh;
struct fcoe_crc_eof crc_eof;
struct fc_frame *fp;
struct fcoe_port *port;
@@ -1644,7 +1599,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
* was done in fcoe_rcv already.
*/
hp = (struct fcoe_hdr *) skb_network_header(skb);
- fh = (struct fc_frame_header *) skb_transport_header(skb);
stats = per_cpu_ptr(lport->dev_stats, get_cpu());
if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
@@ -1677,35 +1631,11 @@ static void fcoe_recv_frame(struct sk_buff *skb)
if (pskb_trim(skb, fr_len))
goto drop;
- /*
- * We only check CRC if no offload is available and if it is
- * it's solicited data, in which case, the FCP layer would
- * check it during the copy.
- */
- if (lport->crc_offload &&
- skb->ip_summed == CHECKSUM_UNNECESSARY)
- fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
- else
- fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
-
- fh = fc_frame_header_get(fp);
- if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
- fh->fh_type != FC_TYPE_FCP) &&
- (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
- if (le32_to_cpu(fr_crc(fp)) !=
- ~crc32(~0, skb->data, fr_len)) {
- if (stats->InvalidCRCCount < 5)
- printk(KERN_WARNING "fcoe: dropping "
- "frame with CRC error\n");
- stats->InvalidCRCCount++;
- goto drop;
- }
- fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
+ if (!fcoe_filter_frames(lport, fp)) {
+ put_cpu();
+ fc_exch_recv(lport, fp);
+ return;
}
- put_cpu();
- fc_exch_recv(lport, fp);
- return;
-
drop:
stats->ErrorFrames++;
put_cpu();
@@ -1744,64 +1674,6 @@ int fcoe_percpu_receive_thread(void *arg)
}
/**
- * fcoe_check_wait_queue() - Attempt to clear the transmit backlog
- * @lport: The local port whose backlog is to be cleared
- *
- * This empties the wait_queue, dequeues the head of the wait_queue queue
- * and calls fcoe_start_io() for each packet. If all skb have been
- * transmitted it returns the qlen. If an error occurs it restores
- * wait_queue (to try again later) and returns -1.
- *
- * The wait_queue is used when the skb transmit fails. The failed skb
- * will go in the wait_queue which will be emptied by the timer function or
- * by the next skb transmit.
- */
-static void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
-{
- struct fcoe_port *port = lport_priv(lport);
- int rc;
-
- spin_lock_bh(&port->fcoe_pending_queue.lock);
-
- if (skb)
- __skb_queue_tail(&port->fcoe_pending_queue, skb);
-
- if (port->fcoe_pending_queue_active)
- goto out;
- port->fcoe_pending_queue_active = 1;
-
- while (port->fcoe_pending_queue.qlen) {
- /* keep qlen > 0 until fcoe_start_io succeeds */
- port->fcoe_pending_queue.qlen++;
- skb = __skb_dequeue(&port->fcoe_pending_queue);
-
- spin_unlock_bh(&port->fcoe_pending_queue.lock);
- rc = fcoe_start_io(skb);
- spin_lock_bh(&port->fcoe_pending_queue.lock);
-
- if (rc) {
- __skb_queue_head(&port->fcoe_pending_queue, skb);
- /* undo temporary increment above */
- port->fcoe_pending_queue.qlen--;
- break;
- }
- /* undo temporary increment above */
- port->fcoe_pending_queue.qlen--;
- }
-
- if (port->fcoe_pending_queue.qlen < FCOE_LOW_QUEUE_DEPTH)
- lport->qfull = 0;
- if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer))
- mod_timer(&port->timer, jiffies + 2);
- port->fcoe_pending_queue_active = 0;
-out:
- if (port->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
- lport->qfull = 1;
- spin_unlock_bh(&port->fcoe_pending_queue.lock);
- return;
-}
-
-/**
* fcoe_dev_setup() - Setup the link change notification interface
*/
static void fcoe_dev_setup(void)
@@ -1872,7 +1744,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
list_del(&fcoe->list);
port = lport_priv(fcoe->ctlr.lp);
fcoe_interface_cleanup(fcoe);
- schedule_work(&port->destroy_work);
+ queue_work(fcoe_wq, &port->destroy_work);
goto out;
break;
case NETDEV_FEAT_CHANGE:
@@ -1898,39 +1770,16 @@ out:
}
/**
- * fcoe_if_to_netdev() - Parse a name buffer to get a net device
- * @buffer: The name of the net device
- *
- * Returns: NULL or a ptr to net_device
- */
-static struct net_device *fcoe_if_to_netdev(const char *buffer)
-{
- char *cp;
- char ifname[IFNAMSIZ + 2];
-
- if (buffer) {
- strlcpy(ifname, buffer, IFNAMSIZ);
- cp = ifname + strlen(ifname);
- while (--cp >= ifname && *cp == '\n')
- *cp = '\0';
- return dev_get_by_name(&init_net, ifname);
- }
- return NULL;
-}
-
-/**
* fcoe_disable() - Disables a FCoE interface
- * @buffer: The name of the Ethernet interface to be disabled
- * @kp: The associated kernel parameter
+ * @netdev : The net_device object the Ethernet interface to create on
*
- * Called from sysfs.
+ * Called from fcoe transport.
*
* Returns: 0 for success
*/
-static int fcoe_disable(const char *buffer, struct kernel_param *kp)
+static int fcoe_disable(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
- struct net_device *netdev;
int rc = 0;
mutex_lock(&fcoe_config_mutex);
@@ -1946,16 +1795,9 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
}
#endif
- netdev = fcoe_if_to_netdev(buffer);
- if (!netdev) {
- rc = -ENODEV;
- goto out_nodev;
- }
-
if (!rtnl_trylock()) {
- dev_put(netdev);
mutex_unlock(&fcoe_config_mutex);
- return restart_syscall();
+ return -ERESTARTSYS;
}
fcoe = fcoe_hostlist_lookup_port(netdev);
@@ -1967,7 +1809,6 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
} else
rc = -ENODEV;
- dev_put(netdev);
out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
@@ -1975,17 +1816,15 @@ out_nodev:
/**
* fcoe_enable() - Enables a FCoE interface
- * @buffer: The name of the Ethernet interface to be enabled
- * @kp: The associated kernel parameter
+ * @netdev : The net_device object the Ethernet interface to create on
*
- * Called from sysfs.
+ * Called from fcoe transport.
*
* Returns: 0 for success
*/
-static int fcoe_enable(const char *buffer, struct kernel_param *kp)
+static int fcoe_enable(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
- struct net_device *netdev;
int rc = 0;
mutex_lock(&fcoe_config_mutex);
@@ -2000,17 +1839,9 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
goto out_nodev;
}
#endif
-
- netdev = fcoe_if_to_netdev(buffer);
- if (!netdev) {
- rc = -ENODEV;
- goto out_nodev;
- }
-
if (!rtnl_trylock()) {
- dev_put(netdev);
mutex_unlock(&fcoe_config_mutex);
- return restart_syscall();
+ return -ERESTARTSYS;
}
fcoe = fcoe_hostlist_lookup_port(netdev);
@@ -2021,7 +1852,6 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
else if (!fcoe_link_ok(fcoe->ctlr.lp))
fcoe_ctlr_link_up(&fcoe->ctlr);
- dev_put(netdev);
out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
@@ -2029,17 +1859,15 @@ out_nodev:
/**
* fcoe_destroy() - Destroy a FCoE interface
- * @buffer: The name of the Ethernet interface to be destroyed
- * @kp: The associated kernel parameter
+ * @netdev : The net_device object the Ethernet interface to create on
*
- * Called from sysfs.
+ * Called from fcoe transport
*
* Returns: 0 for success
*/
-static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
+static int fcoe_destroy(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
- struct net_device *netdev;
int rc = 0;
mutex_lock(&fcoe_config_mutex);
@@ -2054,32 +1882,21 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
goto out_nodev;
}
#endif
-
- netdev = fcoe_if_to_netdev(buffer);
- if (!netdev) {
- rc = -ENODEV;
- goto out_nodev;
- }
-
if (!rtnl_trylock()) {
- dev_put(netdev);
mutex_unlock(&fcoe_config_mutex);
- return restart_syscall();
+ return -ERESTARTSYS;
}
fcoe = fcoe_hostlist_lookup_port(netdev);
if (!fcoe) {
rtnl_unlock();
rc = -ENODEV;
- goto out_putdev;
+ goto out_nodev;
}
fcoe_interface_cleanup(fcoe);
list_del(&fcoe->list);
/* RTNL mutex is dropped by fcoe_if_destroy */
fcoe_if_destroy(fcoe->ctlr.lp);
-
-out_putdev:
- dev_put(netdev);
out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
@@ -2102,27 +1919,39 @@ static void fcoe_destroy_work(struct work_struct *work)
}
/**
+ * fcoe_match() - Check if the FCoE is supported on the given netdevice
+ * @netdev : The net_device object the Ethernet interface to create on
+ *
+ * Called from fcoe transport.
+ *
+ * Returns: always returns true as this is the default FCoE transport,
+ * i.e., support all netdevs.
+ */
+static bool fcoe_match(struct net_device *netdev)
+{
+ return true;
+}
+
+/**
* fcoe_create() - Create a fcoe interface
- * @buffer: The name of the Ethernet interface to create on
- * @kp: The associated kernel param
+ * @netdev : The net_device object the Ethernet interface to create on
+ * @fip_mode: The FIP mode for this creation
*
- * Called from sysfs.
+ * Called from fcoe transport
*
* Returns: 0 for success
*/
-static int fcoe_create(const char *buffer, struct kernel_param *kp)
+static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
{
- enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
int rc;
struct fcoe_interface *fcoe;
struct fc_lport *lport;
- struct net_device *netdev;
mutex_lock(&fcoe_config_mutex);
if (!rtnl_trylock()) {
mutex_unlock(&fcoe_config_mutex);
- return restart_syscall();
+ return -ERESTARTSYS;
}
#ifdef CONFIG_FCOE_MODULE
@@ -2133,31 +1962,20 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
*/
if (THIS_MODULE->state != MODULE_STATE_LIVE) {
rc = -ENODEV;
- goto out_nomod;
- }
-#endif
-
- if (!try_module_get(THIS_MODULE)) {
- rc = -EINVAL;
- goto out_nomod;
- }
-
- netdev = fcoe_if_to_netdev(buffer);
- if (!netdev) {
- rc = -ENODEV;
goto out_nodev;
}
+#endif
/* look for existing lport */
if (fcoe_hostlist_lookup(netdev)) {
rc = -EEXIST;
- goto out_putdev;
+ goto out_nodev;
}
fcoe = fcoe_interface_create(netdev, fip_mode);
- if (!fcoe) {
- rc = -ENOMEM;
- goto out_putdev;
+ if (IS_ERR(fcoe)) {
+ rc = PTR_ERR(fcoe);
+ goto out_nodev;
}
lport = fcoe_if_create(fcoe, &netdev->dev, 0);
@@ -2186,18 +2004,13 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
* should be holding a reference taken in fcoe_if_create().
*/
fcoe_interface_put(fcoe);
- dev_put(netdev);
rtnl_unlock();
mutex_unlock(&fcoe_config_mutex);
return 0;
out_free:
fcoe_interface_put(fcoe);
-out_putdev:
- dev_put(netdev);
out_nodev:
- module_put(THIS_MODULE);
-out_nomod:
rtnl_unlock();
mutex_unlock(&fcoe_config_mutex);
return rc;
@@ -2212,8 +2025,7 @@ out_nomod:
*/
int fcoe_link_speed_update(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lport);
- struct net_device *netdev = port->fcoe->netdev;
+ struct net_device *netdev = fcoe_netdev(lport);
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
if (!dev_ethtool_get_settings(netdev, &ecmd)) {
@@ -2244,8 +2056,7 @@ int fcoe_link_speed_update(struct fc_lport *lport)
*/
int fcoe_link_ok(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lport);
- struct net_device *netdev = port->fcoe->netdev;
+ struct net_device *netdev = fcoe_netdev(lport);
if (netif_oper_up(netdev))
return 0;
@@ -2309,24 +2120,6 @@ void fcoe_percpu_clean(struct fc_lport *lport)
}
/**
- * fcoe_clean_pending_queue() - Dequeue a skb and free it
- * @lport: The local port to dequeue a skb on
- */
-void fcoe_clean_pending_queue(struct fc_lport *lport)
-{
- struct fcoe_port *port = lport_priv(lport);
- struct sk_buff *skb;
-
- spin_lock_bh(&port->fcoe_pending_queue.lock);
- while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) {
- spin_unlock_bh(&port->fcoe_pending_queue.lock);
- kfree_skb(skb);
- spin_lock_bh(&port->fcoe_pending_queue.lock);
- }
- spin_unlock_bh(&port->fcoe_pending_queue.lock);
-}
-
-/**
* fcoe_reset() - Reset a local port
* @shost: The SCSI host associated with the local port to be reset
*
@@ -2335,7 +2128,13 @@ void fcoe_clean_pending_queue(struct fc_lport *lport)
int fcoe_reset(struct Scsi_Host *shost)
{
struct fc_lport *lport = shost_priv(shost);
- fc_lport_reset(lport);
+ struct fcoe_port *port = lport_priv(lport);
+ struct fcoe_interface *fcoe = port->priv;
+
+ fcoe_ctlr_link_down(&fcoe->ctlr);
+ fcoe_clean_pending_queue(fcoe->ctlr.lp);
+ if (!fcoe_link_ok(fcoe->ctlr.lp))
+ fcoe_ctlr_link_up(&fcoe->ctlr);
return 0;
}
@@ -2393,12 +2192,24 @@ static int fcoe_hostlist_add(const struct fc_lport *lport)
fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport));
if (!fcoe) {
port = lport_priv(lport);
- fcoe = port->fcoe;
+ fcoe = port->priv;
list_add_tail(&fcoe->list, &fcoe_hostlist);
}
return 0;
}
+
+static struct fcoe_transport fcoe_sw_transport = {
+ .name = {FCOE_TRANSPORT_DEFAULT},
+ .attached = false,
+ .list = LIST_HEAD_INIT(fcoe_sw_transport.list),
+ .match = fcoe_match,
+ .create = fcoe_create,
+ .destroy = fcoe_destroy,
+ .enable = fcoe_enable,
+ .disable = fcoe_disable,
+};
+
/**
* fcoe_init() - Initialize fcoe.ko
*
@@ -2410,6 +2221,18 @@ static int __init fcoe_init(void)
unsigned int cpu;
int rc = 0;
+ fcoe_wq = alloc_workqueue("fcoe", 0, 0);
+ if (!fcoe_wq)
+ return -ENOMEM;
+
+ /* register as a fcoe transport */
+ rc = fcoe_transport_attach(&fcoe_sw_transport);
+ if (rc) {
+ printk(KERN_ERR "failed to register an fcoe transport, check "
+ "if libfcoe is loaded\n");
+ return rc;
+ }
+
mutex_lock(&fcoe_config_mutex);
for_each_possible_cpu(cpu) {
@@ -2440,6 +2263,7 @@ out_free:
fcoe_percpu_thread_destroy(cpu);
}
mutex_unlock(&fcoe_config_mutex);
+ destroy_workqueue(fcoe_wq);
return rc;
}
module_init(fcoe_init);
@@ -2465,7 +2289,7 @@ static void __exit fcoe_exit(void)
list_del(&fcoe->list);
port = lport_priv(fcoe->ctlr.lp);
fcoe_interface_cleanup(fcoe);
- schedule_work(&port->destroy_work);
+ queue_work(fcoe_wq, &port->destroy_work);
}
rtnl_unlock();
@@ -2476,16 +2300,21 @@ static void __exit fcoe_exit(void)
mutex_unlock(&fcoe_config_mutex);
- /* flush any asyncronous interface destroys,
- * this should happen after the netdev notifier is unregistered */
- flush_scheduled_work();
- /* That will flush out all the N_Ports on the hostlist, but now we
- * may have NPIV VN_Ports scheduled for destruction */
- flush_scheduled_work();
+ /*
+ * destroy_work's may be chained but destroy_workqueue()
+ * can take care of them. Just kill the fcoe_wq.
+ */
+ destroy_workqueue(fcoe_wq);
- /* detach from scsi transport
- * must happen after all destroys are done, therefor after the flush */
+ /*
+ * Detaching from the scsi transport must happen after all
+ * destroys are done on the fcoe_wq. destroy_workqueue will
+ * enusre the fcoe_wq is flushed.
+ */
fcoe_if_exit();
+
+ /* detach from fcoe transport */
+ fcoe_transport_detach(&fcoe_sw_transport);
}
module_exit(fcoe_exit);
@@ -2557,7 +2386,7 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did,
void *arg, u32 timeout)
{
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
struct fcoe_ctlr *fip = &fcoe->ctlr;
struct fc_frame_header *fh = fc_frame_header_get(fp);
@@ -2590,7 +2419,7 @@ static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
struct Scsi_Host *shost = vport_to_shost(vport);
struct fc_lport *n_port = shost_priv(shost);
struct fcoe_port *port = lport_priv(n_port);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
struct net_device *netdev = fcoe->netdev;
struct fc_lport *vn_port;
@@ -2630,7 +2459,7 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
mutex_lock(&n_port->lp_mutex);
list_del(&vn_port->list);
mutex_unlock(&n_port->lp_mutex);
- schedule_work(&port->destroy_work);
+ queue_work(fcoe_wq, &port->destroy_work);
return 0;
}
@@ -2734,7 +2563,7 @@ static void fcoe_set_port_id(struct fc_lport *lport,
u32 port_id, struct fc_frame *fp)
{
struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->fcoe;
+ struct fcoe_interface *fcoe = port->priv;
if (fp && fc_frame_payload_op(fp) == ELS_FLOGI)
fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp);
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index c69b2c56c2d1..408a6fd78fb4 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -24,7 +24,7 @@
#include <linux/kthread.h>
#define FCOE_MAX_QUEUE_DEPTH 256
-#define FCOE_LOW_QUEUE_DEPTH 32
+#define FCOE_MIN_QUEUE_DEPTH 32
#define FCOE_WORD_TO_BYTE 4
@@ -40,12 +40,6 @@
#define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */
#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */
-/*
- * Max MTU for FCoE: 14 (FCoE header) + 24 (FC header) + 2112 (max FC payload)
- * + 4 (FC CRC) + 4 (FCoE trailer) = 2158 bytes
- */
-#define FCOE_MTU 2158
-
unsigned int fcoe_debug_logging;
module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
@@ -71,21 +65,6 @@ do { \
netdev->name, ##args);)
/**
- * struct fcoe_percpu_s - The per-CPU context for FCoE receive threads
- * @thread: The thread context
- * @fcoe_rx_list: The queue of pending packets to process
- * @page: The memory page for calculating frame trailer CRCs
- * @crc_eof_offset: The offset into the CRC page pointing to available
- * memory for a new trailer
- */
-struct fcoe_percpu_s {
- struct task_struct *thread;
- struct sk_buff_head fcoe_rx_list;
- struct page *crc_eof_page;
- int crc_eof_offset;
-};
-
-/**
* struct fcoe_interface - A FCoE interface
* @list: Handle for a list of FCoE interfaces
* @netdev: The associated net device
@@ -108,30 +87,6 @@ struct fcoe_interface {
struct kref kref;
};
-/**
- * struct fcoe_port - The FCoE private structure
- * @fcoe: The associated fcoe interface
- * @lport: The associated local port
- * @fcoe_pending_queue: The pending Rx queue of skbs
- * @fcoe_pending_queue_active: Indicates if the pending queue is active
- * @timer: The queue timer
- * @destroy_work: Handle for work context
- * (to prevent RTNL deadlocks)
- * @data_srt_addr: Source address for data
- *
- * An instance of this structure is to be allocated along with the
- * Scsi_Host and libfc fc_lport structures.
- */
-struct fcoe_port {
- struct fcoe_interface *fcoe;
- struct fc_lport *lport;
- struct sk_buff_head fcoe_pending_queue;
- u8 fcoe_pending_queue_active;
- struct timer_list timer;
- struct work_struct destroy_work;
- u8 data_src_addr[ETH_ALEN];
-};
-
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
/**
@@ -140,7 +95,8 @@ struct fcoe_port {
*/
static inline struct net_device *fcoe_netdev(const struct fc_lport *lport)
{
- return ((struct fcoe_port *)lport_priv(lport))->fcoe->netdev;
+ return ((struct fcoe_interface *)
+ ((struct fcoe_port *)lport_priv(lport))->priv)->netdev;
}
#endif /* _FCOE_H_ */
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 625c6be25396..c93f007e702f 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -44,9 +44,7 @@
#include <scsi/libfc.h>
#include <scsi/libfcoe.h>
-MODULE_AUTHOR("Open-FCoE.org");
-MODULE_DESCRIPTION("FIP discovery protocol support for FCoE HBAs");
-MODULE_LICENSE("GPL v2");
+#include "libfcoe.h"
#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */
#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */
@@ -66,31 +64,7 @@ static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS;
static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS;
-unsigned int libfcoe_debug_logging;
-module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
-
-#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
-#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
-
-#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
-do { \
- if (unlikely(libfcoe_debug_logging & LEVEL)) \
- do { \
- CMD; \
- } while (0); \
-} while (0)
-
-#define LIBFCOE_DBG(fmt, args...) \
- LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
- printk(KERN_INFO "libfcoe: " fmt, ##args);)
-
-#define LIBFCOE_FIP_DBG(fip, fmt, args...) \
- LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
- printk(KERN_INFO "host%d: fip: " fmt, \
- (fip)->lp->host->host_no, ##args);)
-
-static const char *fcoe_ctlr_states[] = {
+static const char * const fcoe_ctlr_states[] = {
[FIP_ST_DISABLED] = "DISABLED",
[FIP_ST_LINK_WAIT] = "LINK_WAIT",
[FIP_ST_AUTO] = "AUTO",
@@ -308,8 +282,8 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
struct fip_mac_desc mac;
struct fip_wwn_desc wwnn;
struct fip_size_desc size;
- } __attribute__((packed)) desc;
- } __attribute__((packed)) *sol;
+ } __packed desc;
+ } __packed * sol;
u32 fcoe_size;
skb = dev_alloc_skb(sizeof(*sol));
@@ -456,7 +430,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
struct ethhdr eth;
struct fip_header fip;
struct fip_mac_desc mac;
- } __attribute__((packed)) *kal;
+ } __packed * kal;
struct fip_vn_desc *vn;
u32 len;
struct fc_lport *lp;
@@ -527,7 +501,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
struct ethhdr eth;
struct fip_header fip;
struct fip_encaps encaps;
- } __attribute__((packed)) *cap;
+ } __packed * cap;
struct fc_frame_header *fh;
struct fip_mac_desc *mac;
struct fcoe_fcf *fcf;
@@ -1819,7 +1793,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip,
struct fip_mac_desc mac;
struct fip_wwn_desc wwnn;
struct fip_vn_desc vn;
- } __attribute__((packed)) *frame;
+ } __packed * frame;
struct fip_fc4_feat *ff;
struct fip_size_desc *size;
u32 fcp_feat;
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
new file mode 100644
index 000000000000..258684101bfd
--- /dev/null
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Maintained at www.Open-FCoE.org
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/errno.h>
+#include <linux/crc32.h>
+#include <scsi/libfcoe.h>
+
+#include "libfcoe.h"
+
+MODULE_AUTHOR("Open-FCoE.org");
+MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs");
+MODULE_LICENSE("GPL v2");
+
+static int fcoe_transport_create(const char *, struct kernel_param *);
+static int fcoe_transport_destroy(const char *, struct kernel_param *);
+static int fcoe_transport_show(char *buffer, const struct kernel_param *kp);
+static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device);
+static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device);
+static int fcoe_transport_enable(const char *, struct kernel_param *);
+static int fcoe_transport_disable(const char *, struct kernel_param *);
+static int libfcoe_device_notification(struct notifier_block *notifier,
+ ulong event, void *ptr);
+
+static LIST_HEAD(fcoe_transports);
+static DEFINE_MUTEX(ft_mutex);
+static LIST_HEAD(fcoe_netdevs);
+static DEFINE_MUTEX(fn_mutex);
+
+unsigned int libfcoe_debug_logging;
+module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+
+module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR);
+__MODULE_PARM_TYPE(show, "string");
+MODULE_PARM_DESC(show, " Show attached FCoE transports");
+
+module_param_call(create, fcoe_transport_create, NULL,
+ (void *)FIP_MODE_FABRIC, S_IWUSR);
+__MODULE_PARM_TYPE(create, "string");
+MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
+
+module_param_call(create_vn2vn, fcoe_transport_create, NULL,
+ (void *)FIP_MODE_VN2VN, S_IWUSR);
+__MODULE_PARM_TYPE(create_vn2vn, "string");
+MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
+ "on an Ethernet interface");
+
+module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(destroy, "string");
+MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
+
+module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(enable, "string");
+MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface.");
+
+module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
+__MODULE_PARM_TYPE(disable, "string");
+MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface.");
+
+/* notification function for packets from net device */
+static struct notifier_block libfcoe_notifier = {
+ .notifier_call = libfcoe_device_notification,
+};
+
+/**
+ * fcoe_fc_crc() - Calculates the CRC for a given frame
+ * @fp: The frame to be checksumed
+ *
+ * This uses crc32() routine to calculate the CRC for a frame
+ *
+ * Return: The 32 bit CRC value
+ */
+u32 fcoe_fc_crc(struct fc_frame *fp)
+{
+ struct sk_buff *skb = fp_skb(fp);
+ struct skb_frag_struct *frag;
+ unsigned char *data;
+ unsigned long off, len, clen;
+ u32 crc;
+ unsigned i;
+
+ crc = crc32(~0, skb->data, skb_headlen(skb));
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ off = frag->page_offset;
+ len = frag->size;
+ while (len > 0) {
+ clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
+ data = kmap_atomic(frag->page + (off >> PAGE_SHIFT),
+ KM_SKB_DATA_SOFTIRQ);
+ crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
+ kunmap_atomic(data, KM_SKB_DATA_SOFTIRQ);
+ off += clen;
+ len -= clen;
+ }
+ }
+ return crc;
+}
+EXPORT_SYMBOL_GPL(fcoe_fc_crc);
+
+/**
+ * fcoe_start_io() - Start FCoE I/O
+ * @skb: The packet to be transmitted
+ *
+ * This routine is called from the net device to start transmitting
+ * FCoE packets.
+ *
+ * Returns: 0 for success
+ */
+int fcoe_start_io(struct sk_buff *skb)
+{
+ struct sk_buff *nskb;
+ int rc;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (!nskb)
+ return -ENOMEM;
+ rc = dev_queue_xmit(nskb);
+ if (rc != 0)
+ return rc;
+ kfree_skb(skb);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fcoe_start_io);
+
+
+/**
+ * fcoe_clean_pending_queue() - Dequeue a skb and free it
+ * @lport: The local port to dequeue a skb on
+ */
+void fcoe_clean_pending_queue(struct fc_lport *lport)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ struct sk_buff *skb;
+
+ spin_lock_bh(&port->fcoe_pending_queue.lock);
+ while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) {
+ spin_unlock_bh(&port->fcoe_pending_queue.lock);
+ kfree_skb(skb);
+ spin_lock_bh(&port->fcoe_pending_queue.lock);
+ }
+ spin_unlock_bh(&port->fcoe_pending_queue.lock);
+}
+EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue);
+
+/**
+ * fcoe_check_wait_queue() - Attempt to clear the transmit backlog
+ * @lport: The local port whose backlog is to be cleared
+ *
+ * This empties the wait_queue, dequeues the head of the wait_queue queue
+ * and calls fcoe_start_io() for each packet. If all skb have been
+ * transmitted it returns the qlen. If an error occurs it restores
+ * wait_queue (to try again later) and returns -1.
+ *
+ * The wait_queue is used when the skb transmit fails. The failed skb
+ * will go in the wait_queue which will be emptied by the timer function or
+ * by the next skb transmit.
+ */
+void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
+{
+ struct fcoe_port *port = lport_priv(lport);
+ int rc;
+
+ spin_lock_bh(&port->fcoe_pending_queue.lock);
+
+ if (skb)
+ __skb_queue_tail(&port->fcoe_pending_queue, skb);
+
+ if (port->fcoe_pending_queue_active)
+ goto out;
+ port->fcoe_pending_queue_active = 1;
+
+ while (port->fcoe_pending_queue.qlen) {
+ /* keep qlen > 0 until fcoe_start_io succeeds */
+ port->fcoe_pending_queue.qlen++;
+ skb = __skb_dequeue(&port->fcoe_pending_queue);
+
+ spin_unlock_bh(&port->fcoe_pending_queue.lock);
+ rc = fcoe_start_io(skb);
+ spin_lock_bh(&port->fcoe_pending_queue.lock);
+
+ if (rc) {
+ __skb_queue_head(&port->fcoe_pending_queue, skb);
+ /* undo temporary increment above */
+ port->fcoe_pending_queue.qlen--;
+ break;
+ }
+ /* undo temporary increment above */
+ port->fcoe_pending_queue.qlen--;
+ }
+
+ if (port->fcoe_pending_queue.qlen < port->min_queue_depth)
+ lport->qfull = 0;
+ if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer))
+ mod_timer(&port->timer, jiffies + 2);
+ port->fcoe_pending_queue_active = 0;
+out:
+ if (port->fcoe_pending_queue.qlen > port->max_queue_depth)
+ lport->qfull = 1;
+ spin_unlock_bh(&port->fcoe_pending_queue.lock);
+}
+EXPORT_SYMBOL_GPL(fcoe_check_wait_queue);
+
+/**
+ * fcoe_queue_timer() - The fcoe queue timer
+ * @lport: The local port
+ *
+ * Calls fcoe_check_wait_queue on timeout
+ */
+void fcoe_queue_timer(ulong lport)
+{
+ fcoe_check_wait_queue((struct fc_lport *)lport, NULL);
+}
+EXPORT_SYMBOL_GPL(fcoe_queue_timer);
+
+/**
+ * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC
+ * @skb: The packet to be transmitted
+ * @tlen: The total length of the trailer
+ * @fps: The fcoe context
+ *
+ * This routine allocates a page for frame trailers. The page is re-used if
+ * there is enough room left on it for the current trailer. If there isn't
+ * enough buffer left a new page is allocated for the trailer. Reference to
+ * the page from this function as well as the skbs using the page fragments
+ * ensure that the page is freed at the appropriate time.
+ *
+ * Returns: 0 for success
+ */
+int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
+ struct fcoe_percpu_s *fps)
+{
+ struct page *page;
+
+ page = fps->crc_eof_page;
+ if (!page) {
+ page = alloc_page(GFP_ATOMIC);
+ if (!page)
+ return -ENOMEM;
+
+ fps->crc_eof_page = page;
+ fps->crc_eof_offset = 0;
+ }
+
+ get_page(page);
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page,
+ fps->crc_eof_offset, tlen);
+ skb->len += tlen;
+ skb->data_len += tlen;
+ skb->truesize += tlen;
+ fps->crc_eof_offset += sizeof(struct fcoe_crc_eof);
+
+ if (fps->crc_eof_offset >= PAGE_SIZE) {
+ fps->crc_eof_page = NULL;
+ fps->crc_eof_offset = 0;
+ put_page(page);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof);
+
+/**
+ * fcoe_transport_lookup - find an fcoe transport that matches a netdev
+ * @netdev: The netdev to look for from all attached transports
+ *
+ * Returns : ptr to the fcoe transport that supports this netdev or NULL
+ * if not found.
+ *
+ * The ft_mutex should be held when this is called
+ */
+static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
+{
+ struct fcoe_transport *ft = NULL;
+
+ list_for_each_entry(ft, &fcoe_transports, list)
+ if (ft->match && ft->match(netdev))
+ return ft;
+ return NULL;
+}
+
+/**
+ * fcoe_transport_attach - Attaches an FCoE transport
+ * @ft: The fcoe transport to be attached
+ *
+ * Returns : 0 for success
+ */
+int fcoe_transport_attach(struct fcoe_transport *ft)
+{
+ int rc = 0;
+
+ mutex_lock(&ft_mutex);
+ if (ft->attached) {
+ LIBFCOE_TRANSPORT_DBG("transport %s already attached\n",
+ ft->name);
+ rc = -EEXIST;
+ goto out_attach;
+ }
+
+ /* Add default transport to the tail */
+ if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
+ list_add(&ft->list, &fcoe_transports);
+ else
+ list_add_tail(&ft->list, &fcoe_transports);
+
+ ft->attached = true;
+ LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
+
+out_attach:
+ mutex_unlock(&ft_mutex);
+ return rc;
+}
+EXPORT_SYMBOL(fcoe_transport_attach);
+
+/**
+ * fcoe_transport_attach - Detaches an FCoE transport
+ * @ft: The fcoe transport to be attached
+ *
+ * Returns : 0 for success
+ */
+int fcoe_transport_detach(struct fcoe_transport *ft)
+{
+ int rc = 0;
+
+ mutex_lock(&ft_mutex);
+ if (!ft->attached) {
+ LIBFCOE_TRANSPORT_DBG("transport %s already detached\n",
+ ft->name);
+ rc = -ENODEV;
+ goto out_attach;
+ }
+
+ list_del(&ft->list);
+ ft->attached = false;
+ LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
+
+out_attach:
+ mutex_unlock(&ft_mutex);
+ return rc;
+
+}
+EXPORT_SYMBOL(fcoe_transport_detach);
+
+static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
+{
+ int i, j;
+ struct fcoe_transport *ft = NULL;
+
+ i = j = sprintf(buffer, "Attached FCoE transports:");
+ mutex_lock(&ft_mutex);
+ list_for_each_entry(ft, &fcoe_transports, list) {
+ i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
+ if (i >= PAGE_SIZE)
+ break;
+ }
+ mutex_unlock(&ft_mutex);
+ if (i == j)
+ i += snprintf(&buffer[i], IFNAMSIZ, "none");
+ return i;
+}
+
+static int __init fcoe_transport_init(void)
+{
+ register_netdevice_notifier(&libfcoe_notifier);
+ return 0;
+}
+
+static int __exit fcoe_transport_exit(void)
+{
+ struct fcoe_transport *ft;
+
+ unregister_netdevice_notifier(&libfcoe_notifier);
+ mutex_lock(&ft_mutex);
+ list_for_each_entry(ft, &fcoe_transports, list)
+ printk(KERN_ERR "FCoE transport %s is still attached!\n",
+ ft->name);
+ mutex_unlock(&ft_mutex);
+ return 0;
+}
+
+
+static int fcoe_add_netdev_mapping(struct net_device *netdev,
+ struct fcoe_transport *ft)
+{
+ struct fcoe_netdev_mapping *nm;
+
+ nm = kmalloc(sizeof(*nm), GFP_KERNEL);
+ if (!nm) {
+ printk(KERN_ERR "Unable to allocate netdev_mapping");
+ return -ENOMEM;
+ }
+
+ nm->netdev = netdev;
+ nm->ft = ft;
+
+ mutex_lock(&fn_mutex);
+ list_add(&nm->list, &fcoe_netdevs);
+ mutex_unlock(&fn_mutex);
+ return 0;
+}
+
+
+static void fcoe_del_netdev_mapping(struct net_device *netdev)
+{
+ struct fcoe_netdev_mapping *nm = NULL, *tmp;
+
+ mutex_lock(&fn_mutex);
+ list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
+ if (nm->netdev == netdev) {
+ list_del(&nm->list);
+ kfree(nm);
+ mutex_unlock(&fn_mutex);
+ return;
+ }
+ }
+ mutex_unlock(&fn_mutex);
+}
+
+
+/**
+ * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which
+ * it was created
+ *
+ * Returns : ptr to the fcoe transport that supports this netdev or NULL
+ * if not found.
+ *
+ * The ft_mutex should be held when this is called
+ */
+static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
+{
+ struct fcoe_transport *ft = NULL;
+ struct fcoe_netdev_mapping *nm;
+
+ mutex_lock(&fn_mutex);
+ list_for_each_entry(nm, &fcoe_netdevs, list) {
+ if (netdev == nm->netdev) {
+ ft = nm->ft;
+ mutex_unlock(&fn_mutex);
+ return ft;
+ }
+ }
+
+ mutex_unlock(&fn_mutex);
+ return NULL;
+}
+
+/**
+ * fcoe_if_to_netdev() - Parse a name buffer to get a net device
+ * @buffer: The name of the net device
+ *
+ * Returns: NULL or a ptr to net_device
+ */
+static struct net_device *fcoe_if_to_netdev(const char *buffer)
+{
+ char *cp;
+ char ifname[IFNAMSIZ + 2];
+
+ if (buffer) {
+ strlcpy(ifname, buffer, IFNAMSIZ);
+ cp = ifname + strlen(ifname);
+ while (--cp >= ifname && *cp == '\n')
+ *cp = '\0';
+ return dev_get_by_name(&init_net, ifname);
+ }
+ return NULL;
+}
+
+/**
+ * libfcoe_device_notification() - Handler for net device events
+ * @notifier: The context of the notification
+ * @event: The type of event
+ * @ptr: The net device that the event was on
+ *
+ * This function is called by the Ethernet driver in case of link change event.
+ *
+ * Returns: 0 for success
+ */
+static int libfcoe_device_notification(struct notifier_block *notifier,
+ ulong event, void *ptr)
+{
+ struct net_device *netdev = ptr;
+
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
+ netdev->name);
+ fcoe_del_netdev_mapping(netdev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+
+/**
+ * fcoe_transport_create() - Create a fcoe interface
+ * @buffer: The name of the Ethernet interface to create on
+ * @kp: The associated kernel param
+ *
+ * Called from sysfs. This holds the ft_mutex while calling the
+ * registered fcoe transport's create function.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
+{
+ int rc = -ENODEV;
+ struct net_device *netdev = NULL;
+ struct fcoe_transport *ft = NULL;
+ enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
+
+ if (!mutex_trylock(&ft_mutex))
+ return restart_syscall();
+
+#ifdef CONFIG_LIBFCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module parameter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE)
+ goto out_nodev;
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev) {
+ LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
+ goto out_nodev;
+ }
+
+ ft = fcoe_netdev_map_lookup(netdev);
+ if (ft) {
+ LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
+ "FCoE instance on %s.\n",
+ ft->name, netdev->name);
+ rc = -EEXIST;
+ goto out_putdev;
+ }
+
+ ft = fcoe_transport_lookup(netdev);
+ if (!ft) {
+ LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
+ netdev->name);
+ goto out_putdev;
+ }
+
+ rc = fcoe_add_netdev_mapping(netdev, ft);
+ if (rc) {
+ LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
+ "for FCoE transport %s for %s.\n",
+ ft->name, netdev->name);
+ goto out_putdev;
+ }
+
+ /* pass to transport create */
+ rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV;
+ if (rc)
+ fcoe_del_netdev_mapping(netdev);
+
+ LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
+ ft->name, (rc) ? "failed" : "succeeded",
+ netdev->name);
+
+out_putdev:
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&ft_mutex);
+ if (rc == -ERESTARTSYS)
+ return restart_syscall();
+ else
+ return rc;
+}
+
+/**
+ * fcoe_transport_destroy() - Destroy a FCoE interface
+ * @buffer: The name of the Ethernet interface to be destroyed
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs. This holds the ft_mutex while calling the
+ * registered fcoe transport's destroy function.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
+{
+ int rc = -ENODEV;
+ struct net_device *netdev = NULL;
+ struct fcoe_transport *ft = NULL;
+
+ if (!mutex_trylock(&ft_mutex))
+ return restart_syscall();
+
+#ifdef CONFIG_LIBFCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module parameter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE)
+ goto out_nodev;
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev) {
+ LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
+ goto out_nodev;
+ }
+
+ ft = fcoe_netdev_map_lookup(netdev);
+ if (!ft) {
+ LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
+ netdev->name);
+ goto out_putdev;
+ }
+
+ /* pass to transport destroy */
+ rc = ft->destroy ? ft->destroy(netdev) : -ENODEV;
+ fcoe_del_netdev_mapping(netdev);
+ LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
+ ft->name, (rc) ? "failed" : "succeeded",
+ netdev->name);
+
+out_putdev:
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&ft_mutex);
+
+ if (rc == -ERESTARTSYS)
+ return restart_syscall();
+ else
+ return rc;
+}
+
+/**
+ * fcoe_transport_disable() - Disables a FCoE interface
+ * @buffer: The name of the Ethernet interface to be disabled
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
+{
+ int rc = -ENODEV;
+ struct net_device *netdev = NULL;
+ struct fcoe_transport *ft = NULL;
+
+ if (!mutex_trylock(&ft_mutex))
+ return restart_syscall();
+
+#ifdef CONFIG_LIBFCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module parameter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE)
+ goto out_nodev;
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev)
+ goto out_nodev;
+
+ ft = fcoe_netdev_map_lookup(netdev);
+ if (!ft)
+ goto out_putdev;
+
+ rc = ft->disable ? ft->disable(netdev) : -ENODEV;
+
+out_putdev:
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&ft_mutex);
+
+ if (rc == -ERESTARTSYS)
+ return restart_syscall();
+ else
+ return rc;
+}
+
+/**
+ * fcoe_transport_enable() - Enables a FCoE interface
+ * @buffer: The name of the Ethernet interface to be enabled
+ * @kp: The associated kernel parameter
+ *
+ * Called from sysfs.
+ *
+ * Returns: 0 for success
+ */
+static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
+{
+ int rc = -ENODEV;
+ struct net_device *netdev = NULL;
+ struct fcoe_transport *ft = NULL;
+
+ if (!mutex_trylock(&ft_mutex))
+ return restart_syscall();
+
+#ifdef CONFIG_LIBFCOE_MODULE
+ /*
+ * Make sure the module has been initialized, and is not about to be
+ * removed. Module parameter sysfs files are writable before the
+ * module_init function is called and after module_exit.
+ */
+ if (THIS_MODULE->state != MODULE_STATE_LIVE)
+ goto out_nodev;
+#endif
+
+ netdev = fcoe_if_to_netdev(buffer);
+ if (!netdev)
+ goto out_nodev;
+
+ ft = fcoe_netdev_map_lookup(netdev);
+ if (!ft)
+ goto out_putdev;
+
+ rc = ft->enable ? ft->enable(netdev) : -ENODEV;
+
+out_putdev:
+ dev_put(netdev);
+out_nodev:
+ mutex_unlock(&ft_mutex);
+ if (rc == -ERESTARTSYS)
+ return restart_syscall();
+ else
+ return rc;
+}
+
+/**
+ * libfcoe_init() - Initialization routine for libfcoe.ko
+ */
+static int __init libfcoe_init(void)
+{
+ fcoe_transport_init();
+
+ return 0;
+}
+module_init(libfcoe_init);
+
+/**
+ * libfcoe_exit() - Tear down libfcoe.ko
+ */
+static void __exit libfcoe_exit(void)
+{
+ fcoe_transport_exit();
+}
+module_exit(libfcoe_exit);
diff --git a/drivers/scsi/fcoe/libfcoe.h b/drivers/scsi/fcoe/libfcoe.h
new file mode 100644
index 000000000000..6af5fc3a17d8
--- /dev/null
+++ b/drivers/scsi/fcoe/libfcoe.h
@@ -0,0 +1,31 @@
+#ifndef _FCOE_LIBFCOE_H_
+#define _FCOE_LIBFCOE_H_
+
+extern unsigned int libfcoe_debug_logging;
+#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
+#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
+#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */
+
+#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
+do { \
+ if (unlikely(libfcoe_debug_logging & LEVEL)) \
+ do { \
+ CMD; \
+ } while (0); \
+} while (0)
+
+#define LIBFCOE_DBG(fmt, args...) \
+ LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
+ printk(KERN_INFO "libfcoe: " fmt, ##args);)
+
+#define LIBFCOE_FIP_DBG(fip, fmt, args...) \
+ LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
+ printk(KERN_INFO "host%d: fip: " fmt, \
+ (fip)->lp->host->host_no, ##args);)
+
+#define LIBFCOE_TRANSPORT_DBG(fmt, args...) \
+ LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \
+ printk(KERN_INFO "%s: " fmt, \
+ __func__, ##args);)
+
+#endif /* _FCOE_LIBFCOE_H_ */
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index 92f185081e62..671cde9d4060 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -37,7 +37,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.4.0.145"
+#define DRV_VERSION "1.5.0.1"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c
index db710148d156..b576be734e2e 100644
--- a/drivers/scsi/fnic/vnic_dev.c
+++ b/drivers/scsi/fnic/vnic_dev.c
@@ -654,7 +654,7 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
vdev->linkstatus_pa);
if (vdev->stats)
pci_free_consistent(vdev->pdev,
- sizeof(struct vnic_dev),
+ sizeof(struct vnic_stats),
vdev->stats, vdev->stats_pa);
if (vdev->fw_info)
pci_free_consistent(vdev->pdev,
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 12deffccb8da..415ad4fb50d4 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -74,6 +74,10 @@ static int hpsa_allow_any;
module_param(hpsa_allow_any, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(hpsa_allow_any,
"Allow hpsa driver to access unknown HP Smart Array hardware");
+static int hpsa_simple_mode;
+module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hpsa_simple_mode,
+ "Use 'simple mode' rather than 'performant mode'");
/* define the PCI info for the cards we can control */
static const struct pci_device_id hpsa_pci_device_id[] = {
@@ -85,11 +89,13 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3356},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -109,11 +115,13 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324a103C, "Smart Array P712m", &SA5_access},
{0x324b103C, "Smart Array P711m", &SA5_access},
- {0x3250103C, "Smart Array", &SA5_access},
- {0x3250113C, "Smart Array", &SA5_access},
- {0x3250123C, "Smart Array", &SA5_access},
- {0x3250133C, "Smart Array", &SA5_access},
- {0x3250143C, "Smart Array", &SA5_access},
+ {0x3350103C, "Smart Array", &SA5_access},
+ {0x3351103C, "Smart Array", &SA5_access},
+ {0x3352103C, "Smart Array", &SA5_access},
+ {0x3353103C, "Smart Array", &SA5_access},
+ {0x3354103C, "Smart Array", &SA5_access},
+ {0x3355103C, "Smart Array", &SA5_access},
+ {0x3356103C, "Smart Array", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
@@ -147,17 +155,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
static int hpsa_slave_alloc(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
-static ssize_t raid_level_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t lunid_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t unique_id_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-static ssize_t host_show_firmware_revision(struct device *dev,
- struct device_attribute *attr, char *buf);
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
-static ssize_t host_store_rescan(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
static int check_for_unit_attention(struct ctlr_info *h,
struct CommandList *c);
static void check_ioctl_unit_attention(struct ctlr_info *h,
@@ -173,47 +171,10 @@ static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar);
static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
-
-static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
-static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
-static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
-static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
-static DEVICE_ATTR(firmware_revision, S_IRUGO,
- host_show_firmware_revision, NULL);
-
-static struct device_attribute *hpsa_sdev_attrs[] = {
- &dev_attr_raid_level,
- &dev_attr_lunid,
- &dev_attr_unique_id,
- NULL,
-};
-
-static struct device_attribute *hpsa_shost_attrs[] = {
- &dev_attr_rescan,
- &dev_attr_firmware_revision,
- NULL,
-};
-
-static struct scsi_host_template hpsa_driver_template = {
- .module = THIS_MODULE,
- .name = "hpsa",
- .proc_name = "hpsa",
- .queuecommand = hpsa_scsi_queue_command,
- .scan_start = hpsa_scan_start,
- .scan_finished = hpsa_scan_finished,
- .change_queue_depth = hpsa_change_queue_depth,
- .this_id = -1,
- .use_clustering = ENABLE_CLUSTERING,
- .eh_device_reset_handler = hpsa_eh_device_reset_handler,
- .ioctl = hpsa_ioctl,
- .slave_alloc = hpsa_slave_alloc,
- .slave_destroy = hpsa_slave_destroy,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = hpsa_compat_ioctl,
-#endif
- .sdev_attrs = hpsa_sdev_attrs,
- .shost_attrs = hpsa_shost_attrs,
-};
+static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
+ void __iomem *vaddr, int wait_for_ready);
+#define BOARD_NOT_READY 0
+#define BOARD_READY 1
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -291,67 +252,63 @@ static ssize_t host_show_firmware_revision(struct device *dev,
fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
}
-/* Enqueuing and dequeuing functions for cmdlists. */
-static inline void addQ(struct hlist_head *list, struct CommandList *c)
+static ssize_t host_show_commands_outstanding(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- hlist_add_head(&c->list, list);
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ctlr_info *h = shost_to_hba(shost);
+
+ return snprintf(buf, 20, "%d\n", h->commands_outstanding);
}
-static inline u32 next_command(struct ctlr_info *h)
+static ssize_t host_show_transport_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- u32 a;
-
- if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
- return h->access.command_completed(h);
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
- if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
- a = *(h->reply_pool_head); /* Next cmd in ring buffer */
- (h->reply_pool_head)++;
- h->commands_outstanding--;
- } else {
- a = FIFO_EMPTY;
- }
- /* Check for wraparound */
- if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
- h->reply_pool_head = h->reply_pool;
- h->reply_pool_wraparound ^= 1;
- }
- return a;
+ h = shost_to_hba(shost);
+ return snprintf(buf, 20, "%s\n",
+ h->transMethod & CFGTBL_Trans_Performant ?
+ "performant" : "simple");
}
-/* set_performant_mode: Modify the tag for cciss performant
- * set bit 0 for pull model, bits 3-1 for block fetch
- * register number
- */
-static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
-{
- if (likely(h->transMethod == CFGTBL_Trans_Performant))
- c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
-}
+/* List of controllers which cannot be reset on kexec with reset_devices */
+static u32 unresettable_controller[] = {
+ 0x324a103C, /* Smart Array P712m */
+ 0x324b103C, /* SmartArray P711m */
+ 0x3223103C, /* Smart Array P800 */
+ 0x3234103C, /* Smart Array P400 */
+ 0x3235103C, /* Smart Array P400i */
+ 0x3211103C, /* Smart Array E200i */
+ 0x3212103C, /* Smart Array E200 */
+ 0x3213103C, /* Smart Array E200i */
+ 0x3214103C, /* Smart Array E200i */
+ 0x3215103C, /* Smart Array E200i */
+ 0x3237103C, /* Smart Array E500 */
+ 0x323D103C, /* Smart Array P700m */
+ 0x409C0E11, /* Smart Array 6400 */
+ 0x409D0E11, /* Smart Array 6400 EM */
+};
-static void enqueue_cmd_and_start_io(struct ctlr_info *h,
- struct CommandList *c)
+static int ctlr_is_resettable(struct ctlr_info *h)
{
- unsigned long flags;
+ int i;
- set_performant_mode(h, c);
- spin_lock_irqsave(&h->lock, flags);
- addQ(&h->reqQ, c);
- h->Qdepth++;
- start_io(h);
- spin_unlock_irqrestore(&h->lock, flags);
+ for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
+ if (unresettable_controller[i] == h->board_id)
+ return 0;
+ return 1;
}
-static inline void removeQ(struct CommandList *c)
+static ssize_t host_show_resettable(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- if (WARN_ON(hlist_unhashed(&c->list)))
- return;
- hlist_del_init(&c->list);
-}
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
-static inline int is_hba_lunid(unsigned char scsi3addr[])
-{
- return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0;
+ h = shost_to_hba(shost);
+ return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h));
}
static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
@@ -359,15 +316,6 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
return (scsi3addr[3] & 0xC0) == 0x40;
}
-static inline int is_scsi_rev_5(struct ctlr_info *h)
-{
- if (!h->hba_inquiry_data)
- return 0;
- if ((h->hba_inquiry_data[2] & 0x07) == 5)
- return 1;
- return 0;
-}
-
static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
"UNKNOWN"
};
@@ -459,6 +407,129 @@ static ssize_t unique_id_show(struct device *dev,
sn[12], sn[13], sn[14], sn[15]);
}
+static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
+static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
+static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(firmware_revision, S_IRUGO,
+ host_show_firmware_revision, NULL);
+static DEVICE_ATTR(commands_outstanding, S_IRUGO,
+ host_show_commands_outstanding, NULL);
+static DEVICE_ATTR(transport_mode, S_IRUGO,
+ host_show_transport_mode, NULL);
+static DEVICE_ATTR(resettable, S_IRUGO,
+ host_show_resettable, NULL);
+
+static struct device_attribute *hpsa_sdev_attrs[] = {
+ &dev_attr_raid_level,
+ &dev_attr_lunid,
+ &dev_attr_unique_id,
+ NULL,
+};
+
+static struct device_attribute *hpsa_shost_attrs[] = {
+ &dev_attr_rescan,
+ &dev_attr_firmware_revision,
+ &dev_attr_commands_outstanding,
+ &dev_attr_transport_mode,
+ &dev_attr_resettable,
+ NULL,
+};
+
+static struct scsi_host_template hpsa_driver_template = {
+ .module = THIS_MODULE,
+ .name = "hpsa",
+ .proc_name = "hpsa",
+ .queuecommand = hpsa_scsi_queue_command,
+ .scan_start = hpsa_scan_start,
+ .scan_finished = hpsa_scan_finished,
+ .change_queue_depth = hpsa_change_queue_depth,
+ .this_id = -1,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = hpsa_eh_device_reset_handler,
+ .ioctl = hpsa_ioctl,
+ .slave_alloc = hpsa_slave_alloc,
+ .slave_destroy = hpsa_slave_destroy,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hpsa_compat_ioctl,
+#endif
+ .sdev_attrs = hpsa_sdev_attrs,
+ .shost_attrs = hpsa_shost_attrs,
+};
+
+
+/* Enqueuing and dequeuing functions for cmdlists. */
+static inline void addQ(struct list_head *list, struct CommandList *c)
+{
+ list_add_tail(&c->list, list);
+}
+
+static inline u32 next_command(struct ctlr_info *h)
+{
+ u32 a;
+
+ if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
+ return h->access.command_completed(h);
+
+ if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
+ a = *(h->reply_pool_head); /* Next cmd in ring buffer */
+ (h->reply_pool_head)++;
+ h->commands_outstanding--;
+ } else {
+ a = FIFO_EMPTY;
+ }
+ /* Check for wraparound */
+ if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
+ h->reply_pool_head = h->reply_pool;
+ h->reply_pool_wraparound ^= 1;
+ }
+ return a;
+}
+
+/* set_performant_mode: Modify the tag for cciss performant
+ * set bit 0 for pull model, bits 3-1 for block fetch
+ * register number
+ */
+static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
+{
+ if (likely(h->transMethod & CFGTBL_Trans_Performant))
+ c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+}
+
+static void enqueue_cmd_and_start_io(struct ctlr_info *h,
+ struct CommandList *c)
+{
+ unsigned long flags;
+
+ set_performant_mode(h, c);
+ spin_lock_irqsave(&h->lock, flags);
+ addQ(&h->reqQ, c);
+ h->Qdepth++;
+ start_io(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static inline void removeQ(struct CommandList *c)
+{
+ if (WARN_ON(list_empty(&c->list)))
+ return;
+ list_del_init(&c->list);
+}
+
+static inline int is_hba_lunid(unsigned char scsi3addr[])
+{
+ return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0;
+}
+
+static inline int is_scsi_rev_5(struct ctlr_info *h)
+{
+ if (!h->hba_inquiry_data)
+ return 0;
+ if ((h->hba_inquiry_data[2] & 0x07) == 5)
+ return 1;
+ return 0;
+}
+
static int hpsa_find_target_lun(struct ctlr_info *h,
unsigned char scsi3addr[], int bus, int *target, int *lun)
{
@@ -1130,6 +1201,10 @@ static void complete_scsi_command(struct CommandList *cp,
cmd->result = DID_TIME_OUT << 16;
dev_warn(&h->pdev->dev, "cp %p timedout\n", cp);
break;
+ case CMD_UNABORTABLE:
+ cmd->result = DID_ERROR << 16;
+ dev_warn(&h->pdev->dev, "Command unabortable\n");
+ break;
default:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
@@ -1160,7 +1235,7 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
- sh->irq = h->intr[PERF_MODE_INT];
+ sh->irq = h->intr[h->intr_mode];
sh->unique_id = sh->irq;
error = scsi_add_host(sh, &h->pdev->dev);
if (error)
@@ -1295,6 +1370,9 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
case CMD_TIMEOUT:
dev_warn(d, "cp %p timed out\n", cp);
break;
+ case CMD_UNABORTABLE:
+ dev_warn(d, "Command unabortable\n");
+ break;
default:
dev_warn(d, "cp %p returned unknown status %x\n", cp,
ei->CommandStatus);
@@ -1595,6 +1673,8 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
if (lun == 0) /* if lun is 0, then obviously we have a lun 0. */
return 0;
+ memset(scsi3addr, 0, 8);
+ scsi3addr[3] = target;
if (is_hba_lunid(scsi3addr))
return 0; /* Don't add the RAID controller here. */
@@ -1609,8 +1689,6 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
return 0;
}
- memset(scsi3addr, 0, 8);
- scsi3addr[3] = target;
if (hpsa_update_device_info(h, scsi3addr, this_device))
return 0;
(*nmsa2xxx_enclosures)++;
@@ -2199,7 +2277,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
c->cmdindex = i;
- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2237,7 +2315,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
}
memset(c->err_info, 0, sizeof(*c->err_info));
- INIT_HLIST_NODE(&c->list);
+ INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2267,7 +2345,7 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
pci_free_consistent(h->pdev, sizeof(*c->err_info),
c->err_info, (dma_addr_t) temp64.val);
pci_free_consistent(h->pdev, sizeof(*c),
- c, (dma_addr_t) c->busaddr);
+ c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK));
}
#ifdef CONFIG_COMPAT
@@ -2281,6 +2359,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
int err;
u32 cp;
+ memset(&arg64, 0, sizeof(arg64));
err = 0;
err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
sizeof(arg64.LUN_info));
@@ -2317,6 +2396,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
int err;
u32 cp;
+ memset(&arg64, 0, sizeof(arg64));
err = 0;
err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
sizeof(arg64.LUN_info));
@@ -2433,15 +2513,17 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
if (buff == NULL)
return -EFAULT;
- }
- if (iocommand.Request.Type.Direction == XFER_WRITE) {
- /* Copy the data into the buffer we created */
- if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
- kfree(buff);
- return -EFAULT;
+ if (iocommand.Request.Type.Direction == XFER_WRITE) {
+ /* Copy the data into the buffer we created */
+ if (copy_from_user(buff, iocommand.buf,
+ iocommand.buf_size)) {
+ kfree(buff);
+ return -EFAULT;
+ }
+ } else {
+ memset(buff, 0, iocommand.buf_size);
}
- } else
- memset(buff, 0, iocommand.buf_size);
+ }
c = cmd_special_alloc(h);
if (c == NULL) {
kfree(buff);
@@ -2487,8 +2569,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
cmd_special_free(h, c);
return -EFAULT;
}
-
- if (iocommand.Request.Type.Direction == XFER_READ) {
+ if (iocommand.Request.Type.Direction == XFER_READ &&
+ iocommand.buf_size > 0) {
/* Copy the data out of the buffer we created */
if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
kfree(buff);
@@ -2581,14 +2663,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
}
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
-
- if (ioc->buf_size > 0) {
- c->Header.SGList = sg_used;
- c->Header.SGTotal = sg_used;
- } else {
- c->Header.SGList = 0;
- c->Header.SGTotal = 0;
- }
+ c->Header.SGList = c->Header.SGTotal = sg_used;
memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
c->Header.Tag.lower = c->busaddr;
memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
@@ -2605,7 +2680,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
}
}
hpsa_scsi_do_simple_cmd_core(h, c);
- hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
+ if (sg_used)
+ hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c);
/* Copy the error information out */
memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
@@ -2614,7 +2690,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
status = -EFAULT;
goto cleanup1;
}
- if (ioc->Request.Type.Direction == XFER_READ) {
+ if (ioc->Request.Type.Direction == XFER_READ && ioc->buf_size > 0) {
/* Copy the data out of the buffer we created */
BYTE __user *ptr = ioc->buf;
for (i = 0; i < sg_used; i++) {
@@ -2810,8 +2886,8 @@ static void start_io(struct ctlr_info *h)
{
struct CommandList *c;
- while (!hlist_empty(&h->reqQ)) {
- c = hlist_entry(h->reqQ.first, struct CommandList, list);
+ while (!list_empty(&h->reqQ)) {
+ c = list_entry(h->reqQ.next, struct CommandList, list);
/* can't do anything if fifo is full */
if ((h->access.fifo_full(h))) {
dev_warn(&h->pdev->dev, "fifo full\n");
@@ -2867,20 +2943,22 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
static inline u32 hpsa_tag_contains_index(u32 tag)
{
-#define DIRECT_LOOKUP_BIT 0x10
return tag & DIRECT_LOOKUP_BIT;
}
static inline u32 hpsa_tag_to_index(u32 tag)
{
-#define DIRECT_LOOKUP_SHIFT 5
return tag >> DIRECT_LOOKUP_SHIFT;
}
-static inline u32 hpsa_tag_discard_error_bits(u32 tag)
+
+static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
{
-#define HPSA_ERROR_BITS 0x03
- return tag & ~HPSA_ERROR_BITS;
+#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
+#define HPSA_SIMPLE_ERROR_BITS 0x03
+ if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
+ return tag & ~HPSA_SIMPLE_ERROR_BITS;
+ return tag & ~HPSA_PERF_ERROR_BITS;
}
/* process completion of an indexed ("direct lookup") command */
@@ -2904,10 +2982,9 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
{
u32 tag;
struct CommandList *c = NULL;
- struct hlist_node *tmp;
- tag = hpsa_tag_discard_error_bits(raw_tag);
- hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+ tag = hpsa_tag_discard_error_bits(h, raw_tag);
+ list_for_each_entry(c, &h->cmpQ, list) {
if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
finish_cmd(c, raw_tag);
return next_command(h);
@@ -2957,7 +3034,10 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/* Send a message CDB to the firmware. */
+/* Send a message CDB to the firmware. Careful, this only works
+ * in simple mode, not performant mode due to the tag lookup.
+ * We only ever use this immediately after a controller reset.
+ */
static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
unsigned char type)
{
@@ -3023,7 +3103,7 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
- if (hpsa_tag_discard_error_bits(tag) == paddr32)
+ if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32)
break;
msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
}
@@ -3055,38 +3135,6 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
#define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0)
#define hpsa_noop(p) hpsa_message(p, 3, 0)
-static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
-{
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-
- int pos;
- u16 control = 0;
-
- pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
- if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos), &control);
- if (control & PCI_MSI_FLAGS_ENABLE) {
- dev_info(&pdev->dev, "resetting MSI\n");
- pci_write_config_word(pdev, msi_control_reg(pos),
- control & ~PCI_MSI_FLAGS_ENABLE);
- }
- }
-
- pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
- if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos), &control);
- if (control & PCI_MSIX_FLAGS_ENABLE) {
- dev_info(&pdev->dev, "resetting MSI-X\n");
- pci_write_config_word(pdev, msi_control_reg(pos),
- control & ~PCI_MSIX_FLAGS_ENABLE);
- }
- }
-
- return 0;
-}
-
static int hpsa_controller_hard_reset(struct pci_dev *pdev,
void * __iomem vaddr, bool use_doorbell)
{
@@ -3142,17 +3190,17 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
*/
static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
{
- u16 saved_config_space[32];
u64 cfg_offset;
u32 cfg_base_addr;
u64 cfg_base_addr_index;
void __iomem *vaddr;
unsigned long paddr;
u32 misc_fw_support, active_transport;
- int rc, i;
+ int rc;
struct CfgTable __iomem *cfgtable;
bool use_doorbell;
u32 board_id;
+ u16 command_register;
/* For controllers as old as the P600, this is very nearly
* the same thing as
@@ -3162,14 +3210,6 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
* pci_set_power_state(pci_dev, PCI_D0);
* pci_restore_state(pci_dev);
*
- * but we can't use these nice canned kernel routines on
- * kexec, because they also check the MSI/MSI-X state in PCI
- * configuration space and do the wrong thing when it is
- * set/cleared. Also, the pci_save/restore_state functions
- * violate the ordering requirements for restoring the
- * configuration space from the CCISS document (see the
- * comment below). So we roll our own ....
- *
* For controllers newer than the P600, the pci power state
* method of resetting doesn't work so we have another way
* using the doorbell register.
@@ -3182,13 +3222,21 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
* likely not be happy. Just forbid resetting this conjoined mess.
* The 640x isn't really supported by hpsa anyway.
*/
- hpsa_lookup_board_id(pdev, &board_id);
+ rc = hpsa_lookup_board_id(pdev, &board_id);
+ if (rc < 0) {
+ dev_warn(&pdev->dev, "Not resetting device.\n");
+ return -ENODEV;
+ }
if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
return -ENOTSUPP;
- for (i = 0; i < 32; i++)
- pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
-
+ /* Save the PCI command register */
+ pci_read_config_word(pdev, 4, &command_register);
+ /* Turn the board off. This is so that later pci_restore_state()
+ * won't turn the board on before the rest of config space is ready.
+ */
+ pci_disable_device(pdev);
+ pci_save_state(pdev);
/* find the first memory BAR, so we can find the cfg table */
rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
@@ -3214,46 +3262,47 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
misc_fw_support = readl(&cfgtable->misc_fw_support);
use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
- /* The doorbell reset seems to cause lockups on some Smart
- * Arrays (e.g. P410, P410i, maybe others). Until this is
- * fixed or at least isolated, avoid the doorbell reset.
- */
- use_doorbell = 0;
-
rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
if (rc)
goto unmap_cfgtable;
- /* Restore the PCI configuration space. The Open CISS
- * Specification says, "Restore the PCI Configuration
- * Registers, offsets 00h through 60h. It is important to
- * restore the command register, 16-bits at offset 04h,
- * last. Do not restore the configuration status register,
- * 16-bits at offset 06h." Note that the offset is 2*i.
- */
- for (i = 0; i < 32; i++) {
- if (i == 2 || i == 3)
- continue;
- pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+ pci_restore_state(pdev);
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_warn(&pdev->dev, "failed to enable device.\n");
+ goto unmap_cfgtable;
}
- wmb();
- pci_write_config_word(pdev, 4, saved_config_space[2]);
+ pci_write_config_word(pdev, 4, command_register);
/* Some devices (notably the HP Smart Array 5i Controller)
need a little pause here */
msleep(HPSA_POST_RESET_PAUSE_MSECS);
+ /* Wait for board to become not ready, then ready. */
+ dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+ rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+ if (rc)
+ dev_warn(&pdev->dev,
+ "failed waiting for board to become not ready\n");
+ rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
+ if (rc) {
+ dev_warn(&pdev->dev,
+ "failed waiting for board to become ready\n");
+ goto unmap_cfgtable;
+ }
+ dev_info(&pdev->dev, "board ready.\n");
+
/* Controller should be in simple mode at this point. If it's not,
* It means we're on one of those controllers which doesn't support
* the doorbell reset method and on which the PCI power management reset
* method doesn't work (P800, for example.)
- * In those cases, pretend the reset worked and hope for the best.
+ * In those cases, don't try to proceed, as it generally doesn't work.
*/
active_transport = readl(&cfgtable->TransportActive);
if (active_transport & PERFORMANT_MODE) {
dev_warn(&pdev->dev, "Unable to successfully reset controller,"
- " proceeding anyway.\n");
- rc = -ENOTSUPP;
+ " Ignoring controller.\n");
+ rc = -ENODEV;
}
unmap_cfgtable:
@@ -3386,7 +3435,7 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
default_int_mode:
#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- h->intr[PERF_MODE_INT] = h->pdev->irq;
+ h->intr[h->intr_mode] = h->pdev->irq;
}
static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
@@ -3438,18 +3487,28 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
return -ENODEV;
}
-static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
+static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
+ void __iomem *vaddr, int wait_for_ready)
{
- int i;
+ int i, iterations;
u32 scratchpad;
+ if (wait_for_ready)
+ iterations = HPSA_BOARD_READY_ITERATIONS;
+ else
+ iterations = HPSA_BOARD_NOT_READY_ITERATIONS;
- for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
- scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
- if (scratchpad == HPSA_FIRMWARE_READY)
- return 0;
+ for (i = 0; i < iterations; i++) {
+ scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+ if (wait_for_ready) {
+ if (scratchpad == HPSA_FIRMWARE_READY)
+ return 0;
+ } else {
+ if (scratchpad != HPSA_FIRMWARE_READY)
+ return 0;
+ }
msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
}
- dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+ dev_warn(&pdev->dev, "board not ready, timed out.\n");
return -ENODEV;
}
@@ -3497,6 +3556,11 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
{
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+ /* Limit commands in memory limited kdump scenario. */
+ if (reset_devices && h->max_commands > 32)
+ h->max_commands = 32;
+
if (h->max_commands < 16) {
dev_warn(&h->pdev->dev, "Controller reports "
"max supported commands of %d, an obvious lie. "
@@ -3571,16 +3635,21 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
{
int i;
+ u32 doorbell_value;
+ unsigned long flags;
/* under certain very rare conditions, this can take awhile.
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
* as we enter this code.)
*/
for (i = 0; i < MAX_CONFIG_WAIT; i++) {
- if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+ spin_lock_irqsave(&h->lock, flags);
+ doorbell_value = readl(h->vaddr + SA5_DOORBELL);
+ spin_unlock_irqrestore(&h->lock, flags);
+ if (!(doorbell_value & CFGTBL_ChangeReq))
break;
/* delay and try again */
- msleep(10);
+ usleep_range(10000, 20000);
}
}
@@ -3603,6 +3672,7 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
"unable to get board into simple mode\n");
return -ENODEV;
}
+ h->transMethod = CFGTBL_Trans_Simple;
return 0;
}
@@ -3641,7 +3711,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
err = -ENOMEM;
goto err_out_free_res;
}
- err = hpsa_wait_for_board_ready(h);
+ err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
if (err)
goto err_out_free_res;
err = hpsa_find_cfgtables(h);
@@ -3710,8 +3780,6 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
return 0; /* just try to do the kdump anyhow. */
if (rc)
return -ENODEV;
- if (hpsa_reset_msi(pdev))
- return -ENODEV;
/* Now try to get the controller to respond to a no-op */
for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
@@ -3749,8 +3817,11 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
h->pdev = pdev;
h->busy_initializing = 1;
- INIT_HLIST_HEAD(&h->cmpQ);
- INIT_HLIST_HEAD(&h->reqQ);
+ h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
+ INIT_LIST_HEAD(&h->cmpQ);
+ INIT_LIST_HEAD(&h->reqQ);
+ spin_lock_init(&h->lock);
+ spin_lock_init(&h->scan_lock);
rc = hpsa_pci_init(h);
if (rc != 0)
goto clean1;
@@ -3777,20 +3848,20 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
h->access.set_intr_mask(h, HPSA_INTR_OFF);
if (h->msix_vector || h->msi_vector)
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+ rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi,
IRQF_DISABLED, h->devname, h);
else
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+ rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_intx,
IRQF_DISABLED, h->devname, h);
if (rc) {
dev_err(&pdev->dev, "unable to get irq %d for %s\n",
- h->intr[PERF_MODE_INT], h->devname);
+ h->intr[h->intr_mode], h->devname);
goto clean2;
}
dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
h->devname, pdev->device,
- h->intr[PERF_MODE_INT], dac ? "" : " not");
+ h->intr[h->intr_mode], dac ? "" : " not");
h->cmd_pool_bits =
kmalloc(((h->nr_cmds + BITS_PER_LONG -
@@ -3810,8 +3881,6 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
}
if (hpsa_allocate_sg_chain_blocks(h))
goto clean4;
- spin_lock_init(&h->lock);
- spin_lock_init(&h->scan_lock);
init_waitqueue_head(&h->scan_wait_queue);
h->scan_finished = 1; /* no scan currently in progress */
@@ -3843,7 +3912,7 @@ clean4:
h->nr_cmds * sizeof(struct ErrorInfo),
h->errinfo_pool,
h->errinfo_pool_dhandle);
- free_irq(h->intr[PERF_MODE_INT], h);
+ free_irq(h->intr[h->intr_mode], h);
clean2:
clean1:
h->busy_initializing = 0;
@@ -3887,7 +3956,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
*/
hpsa_flush_cache(h);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- free_irq(h->intr[PERF_MODE_INT], h);
+ free_irq(h->intr[h->intr_mode], h);
#ifdef CONFIG_PCI_MSI
if (h->msix_vector)
pci_disable_msix(h->pdev);
@@ -3989,7 +4058,8 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
+ u32 use_short_tags)
{
int i;
unsigned long register_value;
@@ -4037,7 +4107,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
writel(0, &h->transtable->RepQCtrAddrHigh32);
writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
writel(0, &h->transtable->RepQAddr0High32);
- writel(CFGTBL_Trans_Performant,
+ writel(CFGTBL_Trans_Performant | use_short_tags,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_mode_change_ack(h);
@@ -4047,12 +4117,18 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
" performant mode\n");
return;
}
+ /* Change the access methods to the performant access methods */
+ h->access = SA5_performant_access;
+ h->transMethod = CFGTBL_Trans_Performant;
}
static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support;
+ if (hpsa_simple_mode)
+ return;
+
trans_support = readl(&(h->cfgtable->TransportSupport));
if (!(trans_support & PERFORMANT_MODE))
return;
@@ -4072,11 +4148,8 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|| (h->blockFetchTable == NULL))
goto clean_up;
- hpsa_enter_performant_mode(h);
-
- /* Change the access methods to the performant access methods */
- h->access = SA5_performant_access;
- h->transMethod = CFGTBL_Trans_Performant;
+ hpsa_enter_performant_mode(h,
+ trans_support & CFGTBL_Trans_use_short_tags);
return;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 19586e189f0f..621a1530054a 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -72,11 +72,12 @@ struct ctlr_info {
unsigned int intr[4];
unsigned int msix_vector;
unsigned int msi_vector;
+ int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */
struct access_method access;
/* queue and queue Info */
- struct hlist_head reqQ;
- struct hlist_head cmpQ;
+ struct list_head reqQ;
+ struct list_head cmpQ;
unsigned int Qdepth;
unsigned int maxQsinceinit;
unsigned int maxSG;
@@ -154,12 +155,16 @@ struct ctlr_info {
* HPSA_BOARD_READY_ITERATIONS are derived from those.
*/
#define HPSA_BOARD_READY_WAIT_SECS (120)
+#define HPSA_BOARD_NOT_READY_WAIT_SECS (10)
#define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100)
#define HPSA_BOARD_READY_POLL_INTERVAL \
((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000)
#define HPSA_BOARD_READY_ITERATIONS \
((HPSA_BOARD_READY_WAIT_SECS * 1000) / \
HPSA_BOARD_READY_POLL_INTERVAL_MSECS)
+#define HPSA_BOARD_NOT_READY_ITERATIONS \
+ ((HPSA_BOARD_NOT_READY_WAIT_SECS * 1000) / \
+ HPSA_BOARD_READY_POLL_INTERVAL_MSECS)
#define HPSA_POST_RESET_PAUSE_MSECS (3000)
#define HPSA_POST_RESET_NOOP_RETRIES (12)
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index f5c4c3cc0530..18464900e761 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -104,6 +104,7 @@
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
+#define CFGTBL_Trans_use_short_tags 0x20000000l
#define CFGTBL_BusType_Ultra2 0x00000001l
#define CFGTBL_BusType_Ultra3 0x00000002l
@@ -265,6 +266,7 @@ struct ErrorInfo {
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
+#define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1))
#define HPSA_ERROR_BIT 0x02
struct ctlr_info; /* defined in hpsa.h */
@@ -291,7 +293,7 @@ struct CommandList {
struct ctlr_info *h;
int cmd_type;
long cmdindex;
- struct hlist_node list;
+ struct list_head list;
struct request *rq;
struct completion *waiting;
void *scsi_cmd;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index d841e98a8bd5..0621238fac4a 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -1301,7 +1301,7 @@ static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,
ipr_clear_res_target(res);
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
}
- } else if (!res->sdev) {
+ } else if (!res->sdev || res->del_from_ml) {
res->add_to_ml = 1;
if (ioa_cfg->allow_ml_add_del)
schedule_work(&ioa_cfg->work_q);
@@ -3104,7 +3104,10 @@ restart:
did_work = 1;
sdev = res->sdev;
if (!scsi_device_get(sdev)) {
- list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+ if (!res->add_to_ml)
+ list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+ else
+ res->del_from_ml = 0;
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
scsi_remove_device(sdev);
scsi_device_put(sdev);
@@ -8864,7 +8867,7 @@ static void __ipr_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
- flush_scheduled_work();
+ flush_work_sync(&ioa_cfg->work_q);
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
spin_lock(&ipr_driver_lock);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index fec47de72535..a860452a8f71 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -608,54 +608,12 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
iscsi_sw_tcp_release_conn(conn);
}
-static int iscsi_sw_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
- char *buf, int *port,
- int (*getname)(struct socket *,
- struct sockaddr *,
- int *addrlen))
-{
- struct sockaddr_storage *addr;
- struct sockaddr_in6 *sin6;
- struct sockaddr_in *sin;
- int rc = 0, len;
-
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr)
- return -ENOMEM;
-
- if (getname(sock, (struct sockaddr *) addr, &len)) {
- rc = -ENODEV;
- goto free_addr;
- }
-
- switch (addr->ss_family) {
- case AF_INET:
- sin = (struct sockaddr_in *)addr;
- spin_lock_bh(&conn->session->lock);
- sprintf(buf, "%pI4", &sin->sin_addr.s_addr);
- *port = be16_to_cpu(sin->sin_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)addr;
- spin_lock_bh(&conn->session->lock);
- sprintf(buf, "%pI6", &sin6->sin6_addr);
- *port = be16_to_cpu(sin6->sin6_port);
- spin_unlock_bh(&conn->session->lock);
- break;
- }
-free_addr:
- kfree(addr);
- return rc;
-}
-
static int
iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
int is_leading)
{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_host *ihost = shost_priv(shost);
+ struct iscsi_session *session = cls_session->dd_data;
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
@@ -670,27 +628,15 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
"sockfd_lookup failed %d\n", err);
return -EEXIST;
}
- /*
- * copy these values now because if we drop the session
- * userspace may still want to query the values since we will
- * be using them for the reconnect
- */
- err = iscsi_sw_tcp_get_addr(conn, sock, conn->portal_address,
- &conn->portal_port, kernel_getpeername);
- if (err)
- goto free_socket;
-
- err = iscsi_sw_tcp_get_addr(conn, sock, ihost->local_address,
- &ihost->local_port, kernel_getsockname);
- if (err)
- goto free_socket;
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
if (err)
goto free_socket;
+ spin_lock_bh(&session->lock);
/* bind iSCSI connection and socket */
tcp_sw_conn->sock = sock;
+ spin_unlock_bh(&session->lock);
/* setup Socket parameters */
sk = sock->sk;
@@ -752,24 +698,74 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- int len;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
+ struct sockaddr_in6 addr;
+ int rc, len;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
- spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%hu\n", conn->portal_port);
- spin_unlock_bh(&conn->session->lock);
- break;
case ISCSI_PARAM_CONN_ADDRESS:
spin_lock_bh(&conn->session->lock);
- len = sprintf(buf, "%s\n", conn->portal_address);
+ if (!tcp_sw_conn || !tcp_sw_conn->sock) {
+ spin_unlock_bh(&conn->session->lock);
+ return -ENOTCONN;
+ }
+ rc = kernel_getpeername(tcp_sw_conn->sock,
+ (struct sockaddr *)&addr, &len);
spin_unlock_bh(&conn->session->lock);
- break;
+ if (rc)
+ return rc;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &addr, param, buf);
default:
return iscsi_conn_get_param(cls_conn, param, buf);
}
- return len;
+ return 0;
+}
+
+static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf)
+{
+ struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost);
+ struct iscsi_session *session = tcp_sw_host->session;
+ struct iscsi_conn *conn;
+ struct iscsi_tcp_conn *tcp_conn;
+ struct iscsi_sw_tcp_conn *tcp_sw_conn;
+ struct sockaddr_in6 addr;
+ int rc, len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ spin_lock_bh(&session->lock);
+ conn = session->leadconn;
+ if (!conn) {
+ spin_unlock_bh(&session->lock);
+ return -ENOTCONN;
+ }
+ tcp_conn = conn->dd_data;
+
+ tcp_sw_conn = tcp_conn->dd_data;
+ if (!tcp_sw_conn->sock) {
+ spin_unlock_bh(&session->lock);
+ return -ENOTCONN;
+ }
+
+ rc = kernel_getsockname(tcp_sw_conn->sock,
+ (struct sockaddr *)&addr, &len);
+ spin_unlock_bh(&session->lock);
+ if (rc)
+ return rc;
+
+ return iscsi_conn_get_addr_param((struct sockaddr_storage *)
+ &addr, param, buf);
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+
+ return 0;
}
static void
@@ -797,6 +793,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
+ struct iscsi_sw_tcp_host *tcp_sw_host;
struct Scsi_Host *shost;
if (ep) {
@@ -804,7 +801,8 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
return NULL;
}
- shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, 0, 1);
+ shost = iscsi_host_alloc(&iscsi_sw_tcp_sht,
+ sizeof(struct iscsi_sw_tcp_host), 1);
if (!shost)
return NULL;
shost->transportt = iscsi_sw_tcp_scsi_transport;
@@ -825,6 +823,8 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
if (!cls_session)
goto remove_host;
session = cls_session->dd_data;
+ tcp_sw_host = iscsi_host_priv(shost);
+ tcp_sw_host->session = session;
shost->can_queue = session->scsi_cmds_max;
if (iscsi_tcp_r2tpool_alloc(session))
@@ -929,7 +929,7 @@ static struct iscsi_transport iscsi_sw_tcp_transport = {
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_sw_tcp_conn_stop,
/* iscsi host params */
- .get_host_param = iscsi_host_get_param,
+ .get_host_param = iscsi_sw_tcp_host_get_param,
.set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 94644bad0ed7..666fe09378fa 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -55,6 +55,10 @@ struct iscsi_sw_tcp_conn {
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
};
+struct iscsi_sw_tcp_host {
+ struct iscsi_session *session;
+};
+
struct iscsi_sw_tcp_hdrbuf {
struct iscsi_hdr hdrbuf;
char hdrextbuf[ISCSI_MAX_AHS_SIZE +
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index d21367d3305f..28231badd9e6 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -38,7 +38,7 @@ u16 fc_cpu_mask; /* cpu mask for possible cpus */
EXPORT_SYMBOL(fc_cpu_mask);
static u16 fc_cpu_order; /* 2's power to represent total possible cpus */
static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
-struct workqueue_struct *fc_exch_workqueue;
+static struct workqueue_struct *fc_exch_workqueue;
/*
* Structure and function definitions for managing Fibre Channel Exchanges
@@ -558,6 +558,22 @@ static struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
return sp;
}
+/*
+ * Set the response handler for the exchange associated with a sequence.
+ */
+static void fc_seq_set_resp(struct fc_seq *sp,
+ void (*resp)(struct fc_seq *, struct fc_frame *,
+ void *),
+ void *arg)
+{
+ struct fc_exch *ep = fc_seq_exch(sp);
+
+ spin_lock_bh(&ep->ex_lock);
+ ep->resp = resp;
+ ep->arg = arg;
+ spin_unlock_bh(&ep->ex_lock);
+}
+
/**
* fc_seq_exch_abort() - Abort an exchange and sequence
* @req_sp: The sequence to be aborted
@@ -650,13 +666,10 @@ static void fc_exch_timeout(struct work_struct *work)
if (e_stat & ESB_ST_ABNORMAL)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
+ if (!rc)
+ fc_exch_delete(ep);
if (resp)
resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg);
- if (!rc) {
- /* delete the exchange if it's already being aborted */
- fc_exch_delete(ep);
- return;
- }
fc_seq_exch_abort(sp, 2 * ep->r_a_tov);
goto done;
}
@@ -1266,6 +1279,8 @@ free:
* @fp: The request frame
*
* On success, the sequence pointer will be returned and also in fr_seq(@fp).
+ * A reference will be held on the exchange/sequence for the caller, which
+ * must call fc_seq_release().
*/
static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
{
@@ -1283,6 +1298,15 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
}
/**
+ * fc_seq_release() - Release the hold
+ * @sp: The sequence.
+ */
+static void fc_seq_release(struct fc_seq *sp)
+{
+ fc_exch_release(fc_seq_exch(sp));
+}
+
+/**
* fc_exch_recv_req() - Handler for an incoming request
* @lport: The local port that received the request
* @mp: The EM that the exchange is on
@@ -2151,6 +2175,7 @@ err:
fc_exch_mgr_del(ema);
return -ENOMEM;
}
+EXPORT_SYMBOL(fc_exch_mgr_list_clone);
/**
* fc_exch_mgr_alloc() - Allocate an exchange manager
@@ -2254,16 +2279,45 @@ void fc_exch_mgr_free(struct fc_lport *lport)
EXPORT_SYMBOL(fc_exch_mgr_free);
/**
+ * fc_find_ema() - Lookup and return appropriate Exchange Manager Anchor depending
+ * upon 'xid'.
+ * @f_ctl: f_ctl
+ * @lport: The local port the frame was received on
+ * @fh: The received frame header
+ */
+static struct fc_exch_mgr_anchor *fc_find_ema(u32 f_ctl,
+ struct fc_lport *lport,
+ struct fc_frame_header *fh)
+{
+ struct fc_exch_mgr_anchor *ema;
+ u16 xid;
+
+ if (f_ctl & FC_FC_EX_CTX)
+ xid = ntohs(fh->fh_ox_id);
+ else {
+ xid = ntohs(fh->fh_rx_id);
+ if (xid == FC_XID_UNKNOWN)
+ return list_entry(lport->ema_list.prev,
+ typeof(*ema), ema_list);
+ }
+
+ list_for_each_entry(ema, &lport->ema_list, ema_list) {
+ if ((xid >= ema->mp->min_xid) &&
+ (xid <= ema->mp->max_xid))
+ return ema;
+ }
+ return NULL;
+}
+/**
* fc_exch_recv() - Handler for received frames
* @lport: The local port the frame was received on
- * @fp: The received frame
+ * @fp: The received frame
*/
void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
struct fc_exch_mgr_anchor *ema;
- u32 f_ctl, found = 0;
- u16 oxid;
+ u32 f_ctl;
/* lport lock ? */
if (!lport || lport->state == LPORT_ST_DISABLED) {
@@ -2274,24 +2328,17 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
}
f_ctl = ntoh24(fh->fh_f_ctl);
- oxid = ntohs(fh->fh_ox_id);
- if (f_ctl & FC_FC_EX_CTX) {
- list_for_each_entry(ema, &lport->ema_list, ema_list) {
- if ((oxid >= ema->mp->min_xid) &&
- (oxid <= ema->mp->max_xid)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- FC_LPORT_DBG(lport, "Received response for out "
- "of range oxid:%hx\n", oxid);
- fc_frame_free(fp);
- return;
- }
- } else
- ema = list_entry(lport->ema_list.prev, typeof(*ema), ema_list);
+ ema = fc_find_ema(f_ctl, lport, fh);
+ if (!ema) {
+ FC_LPORT_DBG(lport, "Unable to find Exchange Manager Anchor,"
+ "fc_ctl <0x%x>, xid <0x%x>\n",
+ f_ctl,
+ (f_ctl & FC_FC_EX_CTX) ?
+ ntohs(fh->fh_ox_id) :
+ ntohs(fh->fh_rx_id));
+ fc_frame_free(fp);
+ return;
+ }
/*
* If frame is marked invalid, just drop it.
@@ -2329,6 +2376,9 @@ int fc_exch_init(struct fc_lport *lport)
if (!lport->tt.seq_start_next)
lport->tt.seq_start_next = fc_seq_start_next;
+ if (!lport->tt.seq_set_resp)
+ lport->tt.seq_set_resp = fc_seq_set_resp;
+
if (!lport->tt.exch_seq_send)
lport->tt.exch_seq_send = fc_exch_seq_send;
@@ -2350,6 +2400,9 @@ int fc_exch_init(struct fc_lport *lport)
if (!lport->tt.seq_assign)
lport->tt.seq_assign = fc_seq_assign;
+ if (!lport->tt.seq_release)
+ lport->tt.seq_release = fc_seq_release;
+
return 0;
}
EXPORT_SYMBOL(fc_exch_init);
@@ -2357,7 +2410,7 @@ EXPORT_SYMBOL(fc_exch_init);
/**
* fc_setup_exch_mgr() - Setup an exchange manager
*/
-int fc_setup_exch_mgr()
+int fc_setup_exch_mgr(void)
{
fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch),
0, SLAB_HWCACHE_ALIGN, NULL);
@@ -2395,7 +2448,7 @@ int fc_setup_exch_mgr()
/**
* fc_destroy_exch_mgr() - Destroy an exchange manager
*/
-void fc_destroy_exch_mgr()
+void fc_destroy_exch_mgr(void)
{
destroy_workqueue(fc_exch_workqueue);
kmem_cache_destroy(fc_em_cachep);
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 5962d1a5a674..b1b03af158bf 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -42,7 +42,7 @@
#include "fc_libfc.h"
-struct kmem_cache *scsi_pkt_cachep;
+static struct kmem_cache *scsi_pkt_cachep;
/* SRB state definitions */
#define FC_SRB_FREE 0 /* cmd is free */
@@ -155,6 +155,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
if (fsp) {
memset(fsp, 0, sizeof(*fsp));
fsp->lp = lport;
+ fsp->xfer_ddp = FC_XID_UNKNOWN;
atomic_set(&fsp->ref_cnt, 1);
init_timer(&fsp->timer);
INIT_LIST_HEAD(&fsp->list);
@@ -1201,6 +1202,7 @@ unlock:
static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp)
{
int rc = FAILED;
+ unsigned long ticks_left;
if (fc_fcp_send_abort(fsp))
return FAILED;
@@ -1209,13 +1211,13 @@ static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp)
fsp->wait_for_comp = 1;
spin_unlock_bh(&fsp->scsi_pkt_lock);
- rc = wait_for_completion_timeout(&fsp->tm_done, FC_SCSI_TM_TOV);
+ ticks_left = wait_for_completion_timeout(&fsp->tm_done,
+ FC_SCSI_TM_TOV);
spin_lock_bh(&fsp->scsi_pkt_lock);
fsp->wait_for_comp = 0;
- if (!rc) {
+ if (!ticks_left) {
FC_FCP_DBG(fsp, "target abort cmd failed\n");
- rc = FAILED;
} else if (fsp->state & FC_SRB_ABORTED) {
FC_FCP_DBG(fsp, "target abort cmd passed\n");
rc = SUCCESS;
@@ -1321,7 +1323,7 @@ static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg)
*
* scsi-eh will escalate for when either happens.
*/
- goto out;
+ return;
}
if (fc_fcp_lock_pkt(fsp))
@@ -1787,15 +1789,14 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport)
/**
* fc_queuecommand() - The queuecommand function of the SCSI template
+ * @shost: The Scsi_Host that the command was issued to
* @cmd: The scsi_cmnd to be executed
- * @done: The callback function to be called when the scsi_cmnd is complete
*
- * This is the i/o strategy routine, called by the SCSI layer. This routine
- * is called with the host_lock held.
+ * This is the i/o strategy routine, called by the SCSI layer.
*/
-static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
+int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
{
- struct fc_lport *lport;
+ struct fc_lport *lport = shost_priv(shost);
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
struct fc_fcp_pkt *fsp;
struct fc_rport_libfc_priv *rpriv;
@@ -1803,15 +1804,12 @@ static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scs
int rc = 0;
struct fcoe_dev_stats *stats;
- lport = shost_priv(sc_cmd->device->host);
-
rval = fc_remote_port_chkready(rport);
if (rval) {
sc_cmd->result = rval;
- done(sc_cmd);
+ sc_cmd->scsi_done(sc_cmd);
return 0;
}
- spin_unlock_irq(lport->host->host_lock);
if (!*(struct fc_remote_port **)rport->dd_data) {
/*
@@ -1819,7 +1817,7 @@ static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scs
* online
*/
sc_cmd->result = DID_IMM_RETRY << 16;
- done(sc_cmd);
+ sc_cmd->scsi_done(sc_cmd);
goto out;
}
@@ -1842,10 +1840,7 @@ static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scs
* build the libfc request pkt
*/
fsp->cmd = sc_cmd; /* save the cmd */
- fsp->lp = lport; /* save the softc ptr */
fsp->rport = rport; /* set the remote port ptr */
- fsp->xfer_ddp = FC_XID_UNKNOWN;
- sc_cmd->scsi_done = done;
/*
* set up the transfer length
@@ -1886,11 +1881,8 @@ static int fc_queuecommand_lck(struct scsi_cmnd *sc_cmd, void (*done)(struct scs
rc = SCSI_MLQUEUE_HOST_BUSY;
}
out:
- spin_lock_irq(lport->host->host_lock);
return rc;
}
-
-DEF_SCSI_QCMD(fc_queuecommand)
EXPORT_SYMBOL(fc_queuecommand);
/**
@@ -2112,7 +2104,6 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
* the sc passed in is not setup for execution like when sent
* through the queuecommand callout.
*/
- fsp->lp = lport; /* save the softc ptr */
fsp->rport = rport; /* set the remote port ptr */
/*
@@ -2245,7 +2236,7 @@ void fc_fcp_destroy(struct fc_lport *lport)
}
EXPORT_SYMBOL(fc_fcp_destroy);
-int fc_setup_fcp()
+int fc_setup_fcp(void)
{
int rc = 0;
@@ -2261,7 +2252,7 @@ int fc_setup_fcp()
return rc;
}
-void fc_destroy_fcp()
+void fc_destroy_fcp(void)
{
if (scsi_pkt_cachep)
kmem_cache_destroy(scsi_pkt_cachep);
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index 6a48c28e4420..b7735129f1f3 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -35,6 +35,27 @@ unsigned int fc_debug_logging;
module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
+DEFINE_MUTEX(fc_prov_mutex);
+static LIST_HEAD(fc_local_ports);
+struct blocking_notifier_head fc_lport_notifier_head =
+ BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
+EXPORT_SYMBOL(fc_lport_notifier_head);
+
+/*
+ * Providers which primarily send requests and PRLIs.
+ */
+struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
+ [0] = &fc_rport_t0_prov,
+ [FC_TYPE_FCP] = &fc_rport_fcp_init,
+};
+
+/*
+ * Providers which receive requests.
+ */
+struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
+ [FC_TYPE_ELS] = &fc_lport_els_prov,
+};
+
/**
* libfc_init() - Initialize libfc.ko
*/
@@ -210,3 +231,102 @@ void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
}
EXPORT_SYMBOL(fc_fill_reply_hdr);
+
+/**
+ * fc_fc4_conf_lport_params() - Modify "service_params" of specified lport
+ * if there is service provider (target provider) registered with libfc
+ * for specified "fc_ft_type"
+ * @lport: Local port which service_params needs to be modified
+ * @type: FC-4 type, such as FC_TYPE_FCP
+ */
+void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type)
+{
+ struct fc4_prov *prov_entry;
+ BUG_ON(type >= FC_FC4_PROV_SIZE);
+ BUG_ON(!lport);
+ prov_entry = fc_passive_prov[type];
+ if (type == FC_TYPE_FCP) {
+ if (prov_entry && prov_entry->recv)
+ lport->service_params |= FCP_SPPF_TARG_FCN;
+ }
+}
+
+void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
+{
+ struct fc_lport *lport;
+
+ mutex_lock(&fc_prov_mutex);
+ list_for_each_entry(lport, &fc_local_ports, lport_list)
+ notify(lport, arg);
+ mutex_unlock(&fc_prov_mutex);
+}
+EXPORT_SYMBOL(fc_lport_iterate);
+
+/**
+ * fc_fc4_register_provider() - register FC-4 upper-level provider.
+ * @type: FC-4 type, such as FC_TYPE_FCP
+ * @prov: structure describing provider including ops vector.
+ *
+ * Returns 0 on success, negative error otherwise.
+ */
+int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
+{
+ struct fc4_prov **prov_entry;
+ int ret = 0;
+
+ if (type >= FC_FC4_PROV_SIZE)
+ return -EINVAL;
+ mutex_lock(&fc_prov_mutex);
+ prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
+ if (*prov_entry)
+ ret = -EBUSY;
+ else
+ *prov_entry = prov;
+ mutex_unlock(&fc_prov_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(fc_fc4_register_provider);
+
+/**
+ * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
+ * @type: FC-4 type, such as FC_TYPE_FCP
+ * @prov: structure describing provider including ops vector.
+ */
+void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
+{
+ BUG_ON(type >= FC_FC4_PROV_SIZE);
+ mutex_lock(&fc_prov_mutex);
+ if (prov->recv)
+ rcu_assign_pointer(fc_passive_prov[type], NULL);
+ else
+ rcu_assign_pointer(fc_active_prov[type], NULL);
+ mutex_unlock(&fc_prov_mutex);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL(fc_fc4_deregister_provider);
+
+/**
+ * fc_fc4_add_lport() - add new local port to list and run notifiers.
+ * @lport: The new local port.
+ */
+void fc_fc4_add_lport(struct fc_lport *lport)
+{
+ mutex_lock(&fc_prov_mutex);
+ list_add_tail(&lport->lport_list, &fc_local_ports);
+ blocking_notifier_call_chain(&fc_lport_notifier_head,
+ FC_LPORT_EV_ADD, lport);
+ mutex_unlock(&fc_prov_mutex);
+}
+
+/**
+ * fc_fc4_del_lport() - remove local port from list and run notifiers.
+ * @lport: The new local port.
+ */
+void fc_fc4_del_lport(struct fc_lport *lport)
+{
+ mutex_lock(&fc_prov_mutex);
+ list_del(&lport->lport_list);
+ blocking_notifier_call_chain(&fc_lport_notifier_head,
+ FC_LPORT_EV_DEL, lport);
+ mutex_unlock(&fc_prov_mutex);
+}
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index eea0c3541b71..fedc819d70c0 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -94,6 +94,17 @@ extern unsigned int fc_debug_logging;
(lport)->host->host_no, ##args))
/*
+ * FC-4 Providers.
+ */
+extern struct fc4_prov *fc_active_prov[]; /* providers without recv */
+extern struct fc4_prov *fc_passive_prov[]; /* providers with recv */
+extern struct mutex fc_prov_mutex; /* lock over table changes */
+
+extern struct fc4_prov fc_rport_t0_prov; /* type 0 provider */
+extern struct fc4_prov fc_lport_els_prov; /* ELS provider */
+extern struct fc4_prov fc_rport_fcp_init; /* FCP initiator provider */
+
+/*
* Set up direct-data placement for this I/O request
*/
void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
@@ -112,6 +123,9 @@ void fc_destroy_fcp(void);
* Internal libfc functions
*/
const char *fc_els_resp_type(struct fc_frame *);
+extern void fc_fc4_add_lport(struct fc_lport *);
+extern void fc_fc4_del_lport(struct fc_lport *);
+extern void fc_fc4_conf_lport_params(struct fc_lport *, enum fc_fh_type);
/*
* Copies a buffer into an sg list
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index c5a10f94f845..8c08b210001d 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -633,6 +633,7 @@ int fc_lport_destroy(struct fc_lport *lport)
lport->tt.fcp_abort_io(lport);
lport->tt.disc_stop_final(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
+ fc_fc4_del_lport(lport);
return 0;
}
EXPORT_SYMBOL(fc_lport_destroy);
@@ -849,7 +850,7 @@ out:
}
/**
- * fc_lport_recv_req() - The generic lport request handler
+ * fc_lport_recv_els_req() - The generic lport ELS request handler
* @lport: The local port that received the request
* @fp: The request frame
*
@@ -859,9 +860,9 @@ out:
* Locking Note: This function should not be called with the lport
* lock held becuase it will grab the lock.
*/
-static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
+static void fc_lport_recv_els_req(struct fc_lport *lport,
+ struct fc_frame *fp)
{
- struct fc_frame_header *fh = fc_frame_header_get(fp);
void (*recv)(struct fc_lport *, struct fc_frame *);
mutex_lock(&lport->lp_mutex);
@@ -873,8 +874,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
*/
if (!lport->link_up)
fc_frame_free(fp);
- else if (fh->fh_type == FC_TYPE_ELS &&
- fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
+ else {
/*
* Check opcode.
*/
@@ -903,14 +903,62 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
}
recv(lport, fp);
- } else {
- FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
- fr_eof(fp));
- fc_frame_free(fp);
}
mutex_unlock(&lport->lp_mutex);
}
+static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len,
+ const struct fc_els_spp *spp_in,
+ struct fc_els_spp *spp_out)
+{
+ return FC_SPP_RESP_INVL;
+}
+
+struct fc4_prov fc_lport_els_prov = {
+ .prli = fc_lport_els_prli,
+ .recv = fc_lport_recv_els_req,
+};
+
+/**
+ * fc_lport_recv_req() - The generic lport request handler
+ * @lport: The lport that received the request
+ * @fp: The frame the request is in
+ *
+ * Locking Note: This function should not be called with the lport
+ * lock held becuase it may grab the lock.
+ */
+static void fc_lport_recv_req(struct fc_lport *lport,
+ struct fc_frame *fp)
+{
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
+ struct fc_seq *sp = fr_seq(fp);
+ struct fc4_prov *prov;
+
+ /*
+ * Use RCU read lock and module_lock to be sure module doesn't
+ * deregister and get unloaded while we're calling it.
+ * try_module_get() is inlined and accepts a NULL parameter.
+ * Only ELSes and FCP target ops should come through here.
+ * The locking is unfortunate, and a better scheme is being sought.
+ */
+
+ rcu_read_lock();
+ if (fh->fh_type >= FC_FC4_PROV_SIZE)
+ goto drop;
+ prov = rcu_dereference(fc_passive_prov[fh->fh_type]);
+ if (!prov || !try_module_get(prov->module))
+ goto drop;
+ rcu_read_unlock();
+ prov->recv(lport, fp);
+ module_put(prov->module);
+ return;
+drop:
+ rcu_read_unlock();
+ FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type);
+ fc_frame_free(fp);
+ lport->tt.exch_done(sp);
+}
+
/**
* fc_lport_reset() - Reset a local port
* @lport: The local port which should be reset
@@ -1542,6 +1590,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
*/
int fc_lport_config(struct fc_lport *lport)
{
+ INIT_LIST_HEAD(&lport->ema_list);
INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
mutex_init(&lport->lp_mutex);
@@ -1549,6 +1598,7 @@ int fc_lport_config(struct fc_lport *lport)
fc_lport_add_fc4_type(lport, FC_TYPE_FCP);
fc_lport_add_fc4_type(lport, FC_TYPE_CT);
+ fc_fc4_conf_lport_params(lport, FC_TYPE_FCP);
return 0;
}
@@ -1586,6 +1636,7 @@ int fc_lport_init(struct fc_lport *lport)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT;
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
+ fc_fc4_add_lport(lport);
return 0;
}
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
index dd2b43bb1c70..f33b897e4784 100644
--- a/drivers/scsi/libfc/fc_npiv.c
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -37,9 +37,7 @@ struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize)
vn_port = libfc_host_alloc(shost->hostt, privsize);
if (!vn_port)
- goto err_out;
- if (fc_exch_mgr_list_clone(n_port, vn_port))
- goto err_put;
+ return vn_port;
vn_port->vport = vport;
vport->dd_data = vn_port;
@@ -49,11 +47,6 @@ struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize)
mutex_unlock(&n_port->lp_mutex);
return vn_port;
-
-err_put:
- scsi_host_put(vn_port->host);
-err_out:
- return NULL;
}
EXPORT_SYMBOL(libfc_vport_create);
@@ -86,6 +79,7 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
return lport;
}
+EXPORT_SYMBOL(fc_vport_id_lookup);
/*
* When setting the link state of vports during an lport state change, it's
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index a7175adab32d..49e1ccca09d5 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -58,7 +58,7 @@
#include "fc_libfc.h"
-struct workqueue_struct *rport_event_queue;
+static struct workqueue_struct *rport_event_queue;
static void fc_rport_enter_flogi(struct fc_rport_priv *);
static void fc_rport_enter_plogi(struct fc_rport_priv *);
@@ -145,8 +145,10 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
INIT_WORK(&rdata->event_work, fc_rport_work);
- if (port_id != FC_FID_DIR_SERV)
+ if (port_id != FC_FID_DIR_SERV) {
+ rdata->lld_event_callback = lport->tt.rport_event_callback;
list_add_rcu(&rdata->peers, &lport->disc.rports);
+ }
return rdata;
}
@@ -257,6 +259,8 @@ static void fc_rport_work(struct work_struct *work)
struct fc_rport_operations *rport_ops;
struct fc_rport_identifiers ids;
struct fc_rport *rport;
+ struct fc4_prov *prov;
+ u8 type;
mutex_lock(&rdata->rp_mutex);
event = rdata->event;
@@ -300,12 +304,25 @@ static void fc_rport_work(struct work_struct *work)
FC_RPORT_DBG(rdata, "callback ev %d\n", event);
rport_ops->event_callback(lport, rdata, event);
}
+ if (rdata->lld_event_callback) {
+ FC_RPORT_DBG(rdata, "lld callback ev %d\n", event);
+ rdata->lld_event_callback(lport, rdata, event);
+ }
kref_put(&rdata->kref, lport->tt.rport_destroy);
break;
case RPORT_EV_FAILED:
case RPORT_EV_LOGO:
case RPORT_EV_STOP:
+ if (rdata->prli_count) {
+ mutex_lock(&fc_prov_mutex);
+ for (type = 1; type < FC_FC4_PROV_SIZE; type++) {
+ prov = fc_passive_prov[type];
+ if (prov && prov->prlo)
+ prov->prlo(rdata);
+ }
+ mutex_unlock(&fc_prov_mutex);
+ }
port_id = rdata->ids.port_id;
mutex_unlock(&rdata->rp_mutex);
@@ -313,6 +330,10 @@ static void fc_rport_work(struct work_struct *work)
FC_RPORT_DBG(rdata, "callback ev %d\n", event);
rport_ops->event_callback(lport, rdata, event);
}
+ if (rdata->lld_event_callback) {
+ FC_RPORT_DBG(rdata, "lld callback ev %d\n", event);
+ rdata->lld_event_callback(lport, rdata, event);
+ }
cancel_delayed_work_sync(&rdata->retry_work);
/*
@@ -336,6 +357,7 @@ static void fc_rport_work(struct work_struct *work)
if (port_id == FC_FID_DIR_SERV) {
rdata->event = RPORT_EV_NONE;
mutex_unlock(&rdata->rp_mutex);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
} else if ((rdata->flags & FC_RP_STARTED) &&
rdata->major_retries <
lport->max_rport_retry_count) {
@@ -575,7 +597,7 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata,
/* make sure this isn't an FC_EX_CLOSED error, never retry those */
if (PTR_ERR(fp) == -FC_EX_CLOSED)
- return fc_rport_error(rdata, fp);
+ goto out;
if (rdata->retries < rdata->local_port->max_rport_retry_count) {
FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
@@ -588,7 +610,8 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata,
return;
}
- return fc_rport_error(rdata, fp);
+out:
+ fc_rport_error(rdata, fp);
}
/**
@@ -878,6 +901,9 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
+ /* save plogi response sp_features for further reference */
+ rdata->sp_features = ntohs(plp->fl_csp.sp_features);
+
if (lport->point_to_multipoint)
fc_rport_login_complete(rdata, fp);
csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
@@ -949,6 +975,8 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_els_prli prli;
struct fc_els_spp spp;
} *pp;
+ struct fc_els_spp temp_spp;
+ struct fc4_prov *prov;
u32 roles = FC_RPORT_ROLE_UNKNOWN;
u32 fcp_parm = 0;
u8 op;
@@ -983,6 +1011,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
pp->spp.spp_flags);
+ rdata->spp_type = pp->spp.spp_type;
if (resp_code != FC_SPP_RESP_ACK) {
if (resp_code == FC_SPP_RESP_CONF)
fc_rport_error(rdata, fp);
@@ -996,6 +1025,15 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
fcp_parm = ntohl(pp->spp.spp_params);
if (fcp_parm & FCP_SPPF_RETRY)
rdata->flags |= FC_RP_FLAGS_RETRY;
+ if (fcp_parm & FCP_SPPF_CONF_COMPL)
+ rdata->flags |= FC_RP_FLAGS_CONF_REQ;
+
+ prov = fc_passive_prov[FC_TYPE_FCP];
+ if (prov) {
+ memset(&temp_spp, 0, sizeof(temp_spp));
+ prov->prli(rdata, pp->prli.prli_spp_len,
+ &pp->spp, &temp_spp);
+ }
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
@@ -1033,6 +1071,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
struct fc_els_spp spp;
} *pp;
struct fc_frame *fp;
+ struct fc4_prov *prov;
/*
* If the rport is one of the well known addresses
@@ -1054,9 +1093,20 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
return;
}
- if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
- fc_rport_prli_resp, rdata,
- 2 * lport->r_a_tov))
+ fc_prli_fill(lport, fp);
+
+ prov = fc_passive_prov[FC_TYPE_FCP];
+ if (prov) {
+ pp = fc_frame_payload_get(fp, sizeof(*pp));
+ prov->prli(rdata, sizeof(pp->spp), NULL, &pp->spp);
+ }
+
+ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rdata->ids.port_id,
+ fc_host_port_id(lport->host), FC_TYPE_ELS,
+ FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+
+ if (!lport->tt.exch_seq_send(lport, fp, fc_rport_prli_resp,
+ NULL, rdata, 2 * lport->r_a_tov))
fc_rport_error_retry(rdata, NULL);
else
kref_get(&rdata->kref);
@@ -1642,9 +1692,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
unsigned int len;
unsigned int plen;
enum fc_els_spp_resp resp;
+ enum fc_els_spp_resp passive;
struct fc_seq_els_data rjt_data;
- u32 fcp_parm;
- u32 roles = FC_RPORT_ROLE_UNKNOWN;
+ struct fc4_prov *prov;
FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
fc_rport_state(rdata));
@@ -1678,46 +1728,42 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
pp->prli.prli_len = htons(len);
len -= sizeof(struct fc_els_prli);
- /* reinitialize remote port roles */
- rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
-
/*
* Go through all the service parameter pages and build
* response. If plen indicates longer SPP than standard,
* use that. The entire response has been pre-cleared above.
*/
spp = &pp->spp;
+ mutex_lock(&fc_prov_mutex);
while (len >= plen) {
+ rdata->spp_type = rspp->spp_type;
spp->spp_type = rspp->spp_type;
spp->spp_type_ext = rspp->spp_type_ext;
- spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
- resp = FC_SPP_RESP_ACK;
-
- switch (rspp->spp_type) {
- case 0: /* common to all FC-4 types */
- break;
- case FC_TYPE_FCP:
- fcp_parm = ntohl(rspp->spp_params);
- if (fcp_parm & FCP_SPPF_RETRY)
- rdata->flags |= FC_RP_FLAGS_RETRY;
- rdata->supported_classes = FC_COS_CLASS3;
- if (fcp_parm & FCP_SPPF_INIT_FCN)
- roles |= FC_RPORT_ROLE_FCP_INITIATOR;
- if (fcp_parm & FCP_SPPF_TARG_FCN)
- roles |= FC_RPORT_ROLE_FCP_TARGET;
- rdata->ids.roles = roles;
-
- spp->spp_params = htonl(lport->service_params);
- break;
- default:
- resp = FC_SPP_RESP_INVL;
- break;
+ resp = 0;
+
+ if (rspp->spp_type < FC_FC4_PROV_SIZE) {
+ prov = fc_active_prov[rspp->spp_type];
+ if (prov)
+ resp = prov->prli(rdata, plen, rspp, spp);
+ prov = fc_passive_prov[rspp->spp_type];
+ if (prov) {
+ passive = prov->prli(rdata, plen, rspp, spp);
+ if (!resp || passive == FC_SPP_RESP_ACK)
+ resp = passive;
+ }
+ }
+ if (!resp) {
+ if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
+ resp |= FC_SPP_RESP_CONF;
+ else
+ resp |= FC_SPP_RESP_INVL;
}
spp->spp_flags |= resp;
len -= plen;
rspp = (struct fc_els_spp *)((char *)rspp + plen);
spp = (struct fc_els_spp *)((char *)spp + plen);
}
+ mutex_unlock(&fc_prov_mutex);
/*
* Send LS_ACC. If this fails, the originator should retry.
@@ -1887,9 +1933,82 @@ int fc_rport_init(struct fc_lport *lport)
EXPORT_SYMBOL(fc_rport_init);
/**
+ * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
+ * @rdata: remote port private
+ * @spp_len: service parameter page length
+ * @rspp: received service parameter page
+ * @spp: response service parameter page
+ *
+ * Returns the value for the response code to be placed in spp_flags;
+ * Returns 0 if not an initiator.
+ */
+static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
+ const struct fc_els_spp *rspp,
+ struct fc_els_spp *spp)
+{
+ struct fc_lport *lport = rdata->local_port;
+ u32 fcp_parm;
+
+ fcp_parm = ntohl(rspp->spp_params);
+ rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
+ if (fcp_parm & FCP_SPPF_INIT_FCN)
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+ if (fcp_parm & FCP_SPPF_TARG_FCN)
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+ if (fcp_parm & FCP_SPPF_RETRY)
+ rdata->flags |= FC_RP_FLAGS_RETRY;
+ rdata->supported_classes = FC_COS_CLASS3;
+
+ if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR))
+ return 0;
+
+ spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
+
+ /*
+ * OR in our service parameters with other providers (target), if any.
+ */
+ fcp_parm = ntohl(spp->spp_params);
+ spp->spp_params = htonl(fcp_parm | lport->service_params);
+ return FC_SPP_RESP_ACK;
+}
+
+/*
+ * FC-4 provider ops for FCP initiator.
+ */
+struct fc4_prov fc_rport_fcp_init = {
+ .prli = fc_rport_fcp_prli,
+};
+
+/**
+ * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
+ * @rdata: remote port private
+ * @spp_len: service parameter page length
+ * @rspp: received service parameter page
+ * @spp: response service parameter page
+ */
+static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
+ const struct fc_els_spp *rspp,
+ struct fc_els_spp *spp)
+{
+ if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR)
+ return FC_SPP_RESP_INVL;
+ return FC_SPP_RESP_ACK;
+}
+
+/*
+ * FC-4 provider ops for type 0 service parameters.
+ *
+ * This handles the special case of type 0 which is always successful
+ * but doesn't do anything otherwise.
+ */
+struct fc4_prov fc_rport_t0_prov = {
+ .prli = fc_rport_t0_prli,
+};
+
+/**
* fc_setup_rport() - Initialize the rport_event_queue
*/
-int fc_setup_rport()
+int fc_setup_rport(void)
{
rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
if (!rport_event_queue)
@@ -1900,7 +2019,7 @@ int fc_setup_rport()
/**
* fc_destroy_rport() - Destroy the rport_event_queue
*/
-void fc_destroy_rport()
+void fc_destroy_rport(void)
{
destroy_workqueue(rport_event_queue);
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index da8b61543ee4..0c550d5b9133 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -3352,6 +3352,47 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_session_get_param);
+int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,
+ enum iscsi_param param, char *buf)
+{
+ struct sockaddr_in6 *sin6 = NULL;
+ struct sockaddr_in *sin = NULL;
+ int len;
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_ADDRESS:
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ if (sin)
+ len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr);
+ else
+ len = sprintf(buf, "%pI6\n", &sin6->sin6_addr);
+ break;
+ case ISCSI_PARAM_CONN_PORT:
+ if (sin)
+ len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port));
+ else
+ len = sprintf(buf, "%hu\n",
+ be16_to_cpu(sin6->sin6_port));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_get_addr_param);
+
int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
@@ -3416,9 +3457,6 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
case ISCSI_HOST_PARAM_INITIATOR_NAME:
len = sprintf(buf, "%s\n", ihost->initiatorname);
break;
- case ISCSI_HOST_PARAM_IPADDRESS:
- len = sprintf(buf, "%s\n", ihost->local_address);
- break;
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index 18f33cd54411..9dafe64e7c7a 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -46,11 +46,3 @@ config SCSI_SAS_HOST_SMP
Allows sas hosts to receive SMP frames. Selecting this
option builds an SMP interpreter into libsas. Say
N here if you want to save the few kb this consumes.
-
-config SCSI_SAS_LIBSAS_DEBUG
- bool "Compile the SAS Domain Transport Attributes in debug mode"
- default y
- depends on SCSI_SAS_LIBSAS
- help
- Compiles the SAS Layer in debug mode. In debug mode, the
- SAS Layer prints diagnostic and debug messages.
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index 1ad1323c60fa..566a10024598 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -21,10 +21,6 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
-ifeq ($(CONFIG_SCSI_SAS_LIBSAS_DEBUG),y)
- EXTRA_CFLAGS += -DSAS_DEBUG
-endif
-
obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o
libsas-y += sas_init.o \
sas_phy.o \
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 4d3b704ede1c..31fc21f4d831 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -71,13 +71,13 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
case SAS_SG_ERR:
return AC_ERR_INVALID;
- case SAM_STAT_CHECK_CONDITION:
case SAS_OPEN_TO:
case SAS_OPEN_REJECT:
SAS_DPRINTK("%s: Saw error %d. What to do?\n",
__func__, ts->stat);
return AC_ERR_OTHER;
+ case SAM_STAT_CHECK_CONDITION:
case SAS_ABORTED_TASK:
return AC_ERR_DEV;
@@ -107,13 +107,15 @@ static void sas_ata_task_done(struct sas_task *task)
sas_ha = dev->port->ha;
spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
- if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD) {
+ if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
+ ((stat->stat == SAM_STAT_CHECK_CONDITION &&
+ dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
dev->sata_dev.sstatus = resp->sstatus;
dev->sata_dev.serror = resp->serror;
dev->sata_dev.scontrol = resp->scontrol;
- } else if (stat->stat != SAM_STAT_GOOD) {
+ } else {
ac = sas_to_ata_err(stat);
if (ac) {
SAS_DPRINTK("%s: SAS error %x\n", __func__,
@@ -305,55 +307,6 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
}
}
-static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in,
- u32 val)
-{
- struct domain_device *dev = link->ap->private_data;
-
- SAS_DPRINTK("STUB %s\n", __func__);
- switch (sc_reg_in) {
- case SCR_STATUS:
- dev->sata_dev.sstatus = val;
- break;
- case SCR_CONTROL:
- dev->sata_dev.scontrol = val;
- break;
- case SCR_ERROR:
- dev->sata_dev.serror = val;
- break;
- case SCR_ACTIVE:
- dev->sata_dev.ap->link.sactive = val;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in,
- u32 *val)
-{
- struct domain_device *dev = link->ap->private_data;
-
- SAS_DPRINTK("STUB %s\n", __func__);
- switch (sc_reg_in) {
- case SCR_STATUS:
- *val = dev->sata_dev.sstatus;
- return 0;
- case SCR_CONTROL:
- *val = dev->sata_dev.scontrol;
- return 0;
- case SCR_ERROR:
- *val = dev->sata_dev.serror;
- return 0;
- case SCR_ACTIVE:
- *val = dev->sata_dev.ap->link.sactive;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
static struct ata_port_operations sas_sata_ops = {
.prereset = ata_std_prereset,
.softreset = NULL,
@@ -367,8 +320,6 @@ static struct ata_port_operations sas_sata_ops = {
.qc_fill_rtf = sas_ata_qc_fill_rtf,
.port_start = ata_sas_port_start,
.port_stop = ata_sas_port_stop,
- .scr_read = sas_ata_scr_read,
- .scr_write = sas_ata_scr_write
};
static struct ata_port_info sata_port_info = {
@@ -801,7 +752,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
if (!dev_is_sata(ddev))
continue;
-
+
ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler");
ata_scsi_port_error_handler(shost, ap);
}
@@ -834,13 +785,13 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
LIST_HEAD(sata_q);
ap = NULL;
-
+
list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
struct domain_device *ddev = cmd_to_domain_dev(cmd);
if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd))
continue;
- if(ap && ap != ddev->sata_dev.ap)
+ if (ap && ap != ddev->sata_dev.ap)
continue;
ap = ddev->sata_dev.ap;
rtn = 1;
@@ -848,8 +799,21 @@ int sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
}
if (!list_empty(&sata_q)) {
- ata_port_printk(ap, KERN_DEBUG,"sas eh calling libata cmd error handler\n");
+ ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata cmd error handler\n");
ata_scsi_cmd_error_handler(shost, ap, &sata_q);
+ /*
+ * ata's error handler may leave the cmd on the list
+ * so make sure they don't remain on a stack list
+ * about to go out of scope.
+ *
+ * This looks strange, since the commands are
+ * now part of no list, but the next error
+ * action will be ata_port_error_handler()
+ * which takes no list and sweeps them up
+ * anyway from the ata tag array.
+ */
+ while (!list_empty(&sata_q))
+ list_del_init(sata_q.next);
}
} while (ap);
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index c17c25030f1c..fc460933575c 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -24,8 +24,6 @@
#include "sas_dump.h"
-#ifdef SAS_DEBUG
-
static const char *sas_hae_str[] = {
[0] = "HAE_RESET",
};
@@ -72,5 +70,3 @@ void sas_dump_port(struct asd_sas_port *port)
SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode);
SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys);
}
-
-#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_dump.h b/drivers/scsi/libsas/sas_dump.h
index 47b45d4f5258..800e4c69093f 100644
--- a/drivers/scsi/libsas/sas_dump.h
+++ b/drivers/scsi/libsas/sas_dump.h
@@ -24,19 +24,7 @@
#include "sas_internal.h"
-#ifdef SAS_DEBUG
-
void sas_dprint_porte(int phyid, enum port_event pe);
void sas_dprint_phye(int phyid, enum phy_event pe);
void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he);
void sas_dump_port(struct asd_sas_port *port);
-
-#else /* SAS_DEBUG */
-
-static inline void sas_dprint_porte(int phyid, enum port_event pe) { }
-static inline void sas_dprint_phye(int phyid, enum phy_event pe) { }
-static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha,
- enum ha_event he) { }
-static inline void sas_dump_port(struct asd_sas_port *port) { }
-
-#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 505ffe358293..f3f693b772ac 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -244,6 +244,11 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
* dev to host FIS as described in section G.5 of
* sas-2 r 04b */
dr = &((struct smp_resp *)disc_resp)->disc;
+ if (memcmp(dev->sas_addr, dr->attached_sas_addr,
+ SAS_ADDR_SIZE) == 0) {
+ sas_printk("Found loopback topology, just ignore it!\n");
+ return 0;
+ }
if (!(dr->attached_dev_type == 0 &&
dr->attached_sata_dev))
break;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 0001374bd6b2..8b538bd1ff2b 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -33,11 +33,7 @@
#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
-#ifdef SAS_DEBUG
-#define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
-#else
-#define SAS_DPRINTK(fmt, ...)
-#endif
+#define SAS_DPRINTK(fmt, ...) printk(KERN_DEBUG "sas: " fmt, ## __VA_ARGS__)
#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 67758ea8eb7f..f6e189f40917 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -681,11 +681,10 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
{
struct sas_task *task = TO_SAS_TASK(cmd);
unsigned long flags;
- enum blk_eh_timer_return rtn;
+ enum blk_eh_timer_return rtn;
if (sas_ata_timed_out(cmd, task, &rtn))
return rtn;
-
if (!task) {
cmd->request->timeout /= 2;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 746dd3d7a092..b64c6da870d3 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2010 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -325,6 +325,7 @@ struct lpfc_vport {
#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */
#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */
#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */
+#define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */
uint32_t ct_flags;
#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
@@ -348,6 +349,8 @@ struct lpfc_vport {
uint32_t fc_myDID; /* fibre channel S_ID */
uint32_t fc_prevDID; /* previous fibre channel S_ID */
+ struct lpfc_name fabric_portname;
+ struct lpfc_name fabric_nodename;
int32_t stopped; /* HBA has not been restarted since last ERATT */
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
@@ -372,6 +375,7 @@ struct lpfc_vport {
#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
+#define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
@@ -382,6 +386,7 @@ struct lpfc_vport {
struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
+ struct timer_list delayed_disc_tmo;
int unreg_vpi_cmpl;
@@ -548,6 +553,8 @@ struct lpfc_hba {
#define LPFC_SLI3_CRP_ENABLED 0x08
#define LPFC_SLI3_BG_ENABLED 0x20
#define LPFC_SLI3_DSS_ENABLED 0x40
+#define LPFC_SLI4_PERFH_ENABLED 0x80
+#define LPFC_SLI4_PHWQ_ENABLED 0x100
uint32_t iocb_cmd_size;
uint32_t iocb_rsp_size;
@@ -655,7 +662,7 @@ struct lpfc_hba {
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
-
+ uint32_t cfg_enable_dss;
lpfc_vpd_t vpd; /* vital product data */
struct pci_dev *pcidev;
@@ -792,6 +799,10 @@ struct lpfc_hba {
struct dentry *debug_slow_ring_trc;
struct lpfc_debugfs_trc *slow_ring_trc;
atomic_t slow_ring_trc_cnt;
+ /* iDiag debugfs sub-directory */
+ struct dentry *idiag_root;
+ struct dentry *idiag_pci_cfg;
+ struct dentry *idiag_que_info;
#endif
/* Used for deferred freeing of ELS data buffers */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 3512abb8a587..e7c020df12fa 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -623,10 +623,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
int status = 0;
int cnt = 0;
int i;
+ int rc;
init_completion(&online_compl);
- lpfc_workq_post_event(phba, &status, &online_compl,
+ rc = lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_OFFLINE_PREP);
+ if (rc == 0)
+ return -ENOMEM;
+
wait_for_completion(&online_compl);
if (status != 0)
@@ -652,7 +656,10 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
}
init_completion(&online_compl);
- lpfc_workq_post_event(phba, &status, &online_compl, type);
+ rc = lpfc_workq_post_event(phba, &status, &online_compl, type);
+ if (rc == 0)
+ return -ENOMEM;
+
wait_for_completion(&online_compl);
if (status != 0)
@@ -671,6 +678,7 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
*
* Notes:
* Assumes any error from lpfc_do_offline() will be negative.
+ * Do not make this function static.
*
* Returns:
* lpfc_do_offline() return code if not zero
@@ -682,6 +690,7 @@ lpfc_selective_reset(struct lpfc_hba *phba)
{
struct completion online_compl;
int status = 0;
+ int rc;
if (!phba->cfg_enable_hba_reset)
return -EIO;
@@ -692,8 +701,11 @@ lpfc_selective_reset(struct lpfc_hba *phba)
return status;
init_completion(&online_compl);
- lpfc_workq_post_event(phba, &status, &online_compl,
+ rc = lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_ONLINE);
+ if (rc == 0)
+ return -ENOMEM;
+
wait_for_completion(&online_compl);
if (status != 0)
@@ -812,14 +824,17 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
int status=0;
+ int rc;
if (!phba->cfg_enable_hba_reset)
return -EACCES;
init_completion(&online_compl);
if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
- lpfc_workq_post_event(phba, &status, &online_compl,
+ rc = lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_ONLINE);
+ if (rc == 0)
+ return -ENOMEM;
wait_for_completion(&online_compl);
} else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
@@ -1279,6 +1294,28 @@ lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr,
}
/**
+ * lpfc_dss_show - Return the current state of dss and the configured state
+ * @dev: class converted to a Scsi_host structure.
+ * @attr: device attribute, not used.
+ * @buf: on return contains the formatted text.
+ *
+ * Returns: size of formatted string.
+ **/
+static ssize_t
+lpfc_dss_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%s - %sOperational\n",
+ (phba->cfg_enable_dss) ? "Enabled" : "Disabled",
+ (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ?
+ "" : "Not ");
+}
+
+/**
* lpfc_param_show - Return a cfg attribute value in decimal
*
* Description:
@@ -1597,13 +1634,13 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
#define LPFC_ATTR(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_init(name, defval, minval, maxval)
#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1611,7 +1648,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1622,7 +1659,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_hex_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1630,7 +1667,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_param_hex_show(name)\
lpfc_param_init(name, defval, minval, maxval)\
@@ -1641,13 +1678,13 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_init(name, defval, minval, maxval)
#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1655,7 +1692,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1666,7 +1703,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_hex_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1674,7 +1711,7 @@ static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
static uint lpfc_##name = defval;\
-module_param(lpfc_##name, uint, 0);\
+module_param(lpfc_##name, uint, S_IRUGO);\
MODULE_PARM_DESC(lpfc_##name, desc);\
lpfc_vport_param_hex_show(name)\
lpfc_vport_param_init(name, defval, minval, maxval)\
@@ -1718,7 +1755,7 @@ static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL);
static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL);
static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL);
-
+static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL);
static char *lpfc_soft_wwn_key = "C99G71SL8032A";
@@ -1813,6 +1850,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
int stat1=0, stat2=0;
unsigned int i, j, cnt=count;
u8 wwpn[8];
+ int rc;
if (!phba->cfg_enable_hba_reset)
return -EACCES;
@@ -1863,7 +1901,11 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
"0463 lpfc_soft_wwpn attribute set failed to "
"reinit adapter - %d\n", stat1);
init_completion(&online_compl);
- lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
+ rc = lpfc_workq_post_event(phba, &stat2, &online_compl,
+ LPFC_EVT_ONLINE);
+ if (rc == 0)
+ return -ENOMEM;
+
wait_for_completion(&online_compl);
if (stat2)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -1954,7 +1996,7 @@ static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\
static int lpfc_poll = 0;
-module_param(lpfc_poll, int, 0);
+module_param(lpfc_poll, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:"
" 0 - none,"
" 1 - poll with interrupts enabled"
@@ -1964,21 +2006,21 @@ static DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
int lpfc_sli_mode = 0;
-module_param(lpfc_sli_mode, int, 0);
+module_param(lpfc_sli_mode, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
" 0 - auto (SLI-3 if supported),"
" 2 - select SLI-2 even on SLI-3 capable HBAs,"
" 3 - select SLI-3");
int lpfc_enable_npiv = 1;
-module_param(lpfc_enable_npiv, int, 0);
+module_param(lpfc_enable_npiv, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
lpfc_param_show(enable_npiv);
lpfc_param_init(enable_npiv, 1, 0, 1);
static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
int lpfc_enable_rrq;
-module_param(lpfc_enable_rrq, int, 0);
+module_param(lpfc_enable_rrq, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
lpfc_param_show(enable_rrq);
lpfc_param_init(enable_rrq, 0, 0, 1);
@@ -2040,7 +2082,7 @@ static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
lpfc_txcmplq_hw_show, NULL);
int lpfc_iocb_cnt = 2;
-module_param(lpfc_iocb_cnt, int, 1);
+module_param(lpfc_iocb_cnt, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_iocb_cnt,
"Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
lpfc_param_show(iocb_cnt);
@@ -2192,7 +2234,7 @@ static DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
# disappear until the timer expires. Value range is [0,255]. Default
# value is 30.
*/
-module_param(lpfc_devloss_tmo, int, 0);
+module_param(lpfc_devloss_tmo, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_devloss_tmo,
"Seconds driver will hold I/O waiting "
"for a device to come back");
@@ -2302,7 +2344,7 @@ LPFC_VPORT_ATTR_R(peer_port_login, 0, 0, 1,
# Default value of this parameter is 1.
*/
static int lpfc_restrict_login = 1;
-module_param(lpfc_restrict_login, int, 0);
+module_param(lpfc_restrict_login, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_restrict_login,
"Restrict virtual ports login to remote initiators.");
lpfc_vport_param_show(restrict_login);
@@ -2473,7 +2515,7 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
static int lpfc_topology = 0;
-module_param(lpfc_topology, int, 0);
+module_param(lpfc_topology, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
lpfc_param_show(topology)
lpfc_param_init(topology, 0, 0, 6)
@@ -2915,7 +2957,7 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
}
static int lpfc_link_speed = 0;
-module_param(lpfc_link_speed, int, 0);
+module_param(lpfc_link_speed, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
lpfc_param_show(link_speed)
@@ -3043,7 +3085,7 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
}
static int lpfc_aer_support = 1;
-module_param(lpfc_aer_support, int, 1);
+module_param(lpfc_aer_support, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support");
lpfc_param_show(aer_support)
@@ -3155,7 +3197,7 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
# The value is set in milliseconds.
*/
static int lpfc_max_scsicmpl_time;
-module_param(lpfc_max_scsicmpl_time, int, 0);
+module_param(lpfc_max_scsicmpl_time, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_max_scsicmpl_time,
"Use command completion time to control queue depth");
lpfc_vport_param_show(max_scsicmpl_time);
@@ -3331,7 +3373,7 @@ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
*/
unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION;
-module_param(lpfc_prot_mask, uint, 0);
+module_param(lpfc_prot_mask, uint, S_IRUGO);
MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
/*
@@ -3343,9 +3385,28 @@ MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
#
*/
unsigned char lpfc_prot_guard = SHOST_DIX_GUARD_IP;
-module_param(lpfc_prot_guard, byte, 0);
+module_param(lpfc_prot_guard, byte, S_IRUGO);
MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type");
+/*
+ * Delay initial NPort discovery when Clean Address bit is cleared in
+ * FLOGI/FDISC accept and FCID/Fabric name/Fabric portname is changed.
+ * This parameter can have value 0 or 1.
+ * When this parameter is set to 0, no delay is added to the initial
+ * discovery.
+ * When this parameter is set to non-zero value, initial Nport discovery is
+ * delayed by ra_tov seconds when Clean Address bit is cleared in FLOGI/FDISC
+ * accept and FCID/Fabric name/Fabric portname is changed.
+ * Driver always delay Nport discovery for subsequent FLOGI/FDISC completion
+ * when Clean Address bit is cleared in FLOGI/FDISC
+ * accept and FCID/Fabric name/Fabric portname is changed.
+ * Default value is 0.
+ */
+int lpfc_delay_discovery;
+module_param(lpfc_delay_discovery, int, S_IRUGO);
+MODULE_PARM_DESC(lpfc_delay_discovery,
+ "Delay NPort discovery when Clean Address bit is cleared. "
+ "Allowed values: 0,1.");
/*
* lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count
@@ -3437,6 +3498,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_txcmplq_hw,
&dev_attr_lpfc_fips_level,
&dev_attr_lpfc_fips_rev,
+ &dev_attr_lpfc_dss,
NULL,
};
@@ -4639,6 +4701,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_aer_support_init(phba, lpfc_aer_support);
lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
+ phba->cfg_enable_dss = 1;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 17fde522c84a..3d40023f4804 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -53,9 +53,9 @@ void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_supported_pages(struct lpfcMboxq *);
-void lpfc_sli4_params(struct lpfcMboxq *);
+void lpfc_pc_sli4_params(struct lpfcMboxq *);
int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
-
+int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
@@ -167,6 +167,8 @@ int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+void lpfc_delayed_disc_tmo(unsigned long);
+void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
int lpfc_config_port_prep(struct lpfc_hba *);
int lpfc_config_port_post(struct lpfc_hba *);
@@ -341,6 +343,7 @@ extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode;
extern int lpfc_enable_npiv;
+extern int lpfc_delay_discovery;
int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t);
@@ -423,6 +426,6 @@ int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
uint16_t, uint16_t, uint16_t);
void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
-void lpfc_cleanup_vports_rrqs(struct lpfc_vport *);
+void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
uint32_t);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index c004fa9a681e..d9edfd90d7ff 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1738,6 +1738,55 @@ fdmi_cmd_exit:
return 1;
}
+/**
+ * lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer.
+ * @ptr - Context object of the timer.
+ *
+ * This function set the WORKER_DELAYED_DISC_TMO flag and wake up
+ * the worker thread.
+ **/
+void
+lpfc_delayed_disc_tmo(unsigned long ptr)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t tmo_posted;
+ unsigned long iflag;
+
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ tmo_posted = vport->work_port_events & WORKER_DELAYED_DISC_TMO;
+ if (!tmo_posted)
+ vport->work_port_events |= WORKER_DELAYED_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ if (!tmo_posted)
+ lpfc_worker_wake_up(phba);
+ return;
+}
+
+/**
+ * lpfc_delayed_disc_timeout_handler - Function called by worker thread to
+ * handle delayed discovery.
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * This function start nport discovery of the vport.
+ **/
+void
+lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
+ if (!(vport->fc_flag & FC_DISC_DELAYED)) {
+ spin_unlock_irq(shost->host_lock);
+ return;
+ }
+ vport->fc_flag &= ~FC_DISC_DELAYED;
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_do_scr_ns_plogi(vport->phba, vport);
+}
+
void
lpfc_fdmi_tmo(unsigned long ptr)
{
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index a80d938fafc9..a753581509d6 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2007-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2007-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -57,8 +57,8 @@
* # mount -t debugfs none /sys/kernel/debug
*
* The lpfc debugfs directory hierarchy is:
- * lpfc/lpfcX/vportY
- * where X is the lpfc hba unique_id
+ * /sys/kernel/debug/lpfc/fnX/vportY
+ * where X is the lpfc hba function unique_id
* where Y is the vport VPI on that hba
*
* Debugging services available per vport:
@@ -82,52 +82,34 @@
* the HBA. X MUST also be a power of 2.
*/
static int lpfc_debugfs_enable = 1;
-module_param(lpfc_debugfs_enable, int, 0);
+module_param(lpfc_debugfs_enable, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
/* This MUST be a power of 2 */
static int lpfc_debugfs_max_disc_trc;
-module_param(lpfc_debugfs_max_disc_trc, int, 0);
+module_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
"Set debugfs discovery trace depth");
/* This MUST be a power of 2 */
static int lpfc_debugfs_max_slow_ring_trc;
-module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
+module_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
"Set debugfs slow ring trace depth");
static int lpfc_debugfs_mask_disc_trc;
-module_param(lpfc_debugfs_mask_disc_trc, int, 0);
+module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
"Set debugfs discovery trace mask");
#include <linux/debugfs.h>
-/* size of output line, for discovery_trace and slow_ring_trace */
-#define LPFC_DEBUG_TRC_ENTRY_SIZE 100
-
-/* nodelist output buffer size */
-#define LPFC_NODELIST_SIZE 8192
-#define LPFC_NODELIST_ENTRY_SIZE 120
-
-/* dumpHBASlim output buffer size */
-#define LPFC_DUMPHBASLIM_SIZE 4096
-
-/* dumpHostSlim output buffer size */
-#define LPFC_DUMPHOSTSLIM_SIZE 4096
-
-/* hbqinfo output buffer size */
-#define LPFC_HBQINFO_SIZE 8192
-
-struct lpfc_debug {
- char *buffer;
- int len;
-};
-
static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
static unsigned long lpfc_debugfs_start_time = 0L;
+/* iDiag */
+static struct lpfc_idiag idiag;
+
/**
* lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer
* @vport: The vport to gather the log info from.
@@ -996,8 +978,6 @@ lpfc_debugfs_dumpDataDif_write(struct file *file, const char __user *buf,
return nbytes;
}
-
-
/**
* lpfc_debugfs_nodelist_open - Open the nodelist debugfs file
* @inode: The inode pointer that contains a vport pointer.
@@ -1099,6 +1079,7 @@ lpfc_debugfs_read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
struct lpfc_debug *debug = file->private_data;
+
return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
debug->len);
}
@@ -1137,6 +1118,776 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file)
return 0;
}
+/*
+ * iDiag debugfs file access methods
+ */
+
+/*
+ * iDiag PCI config space register access methods:
+ *
+ * The PCI config space register accessees of read, write, read-modify-write
+ * for set bits, and read-modify-write for clear bits to SLI4 PCI functions
+ * are provided. In the proper SLI4 PCI function's debugfs iDiag directory,
+ *
+ * /sys/kernel/debug/lpfc/fn<#>/iDiag
+ *
+ * the access is through the debugfs entry pciCfg:
+ *
+ * 1. For PCI config space register read access, there are two read methods:
+ * A) read a single PCI config space register in the size of a byte
+ * (8 bits), a word (16 bits), or a dword (32 bits); or B) browse through
+ * the 4K extended PCI config space.
+ *
+ * A) Read a single PCI config space register consists of two steps:
+ *
+ * Step-1: Set up PCI config space register read command, the command
+ * syntax is,
+ *
+ * echo 1 <where> <count> > pciCfg
+ *
+ * where, 1 is the iDiag command for PCI config space read, <where> is the
+ * offset from the beginning of the device's PCI config space to read from,
+ * and <count> is the size of PCI config space register data to read back,
+ * it will be 1 for reading a byte (8 bits), 2 for reading a word (16 bits
+ * or 2 bytes), or 4 for reading a dword (32 bits or 4 bytes).
+ *
+ * Setp-2: Perform the debugfs read operation to execute the idiag command
+ * set up in Step-1,
+ *
+ * cat pciCfg
+ *
+ * Examples:
+ * To read PCI device's vendor-id and device-id from PCI config space,
+ *
+ * echo 1 0 4 > pciCfg
+ * cat pciCfg
+ *
+ * To read PCI device's currnt command from config space,
+ *
+ * echo 1 4 2 > pciCfg
+ * cat pciCfg
+ *
+ * B) Browse through the entire 4K extended PCI config space also consists
+ * of two steps:
+ *
+ * Step-1: Set up PCI config space register browsing command, the command
+ * syntax is,
+ *
+ * echo 1 0 4096 > pciCfg
+ *
+ * where, 1 is the iDiag command for PCI config space read, 0 must be used
+ * as the offset for PCI config space register browse, and 4096 must be
+ * used as the count for PCI config space register browse.
+ *
+ * Step-2: Repeately issue the debugfs read operation to browse through
+ * the entire PCI config space registers:
+ *
+ * cat pciCfg
+ * cat pciCfg
+ * cat pciCfg
+ * ...
+ *
+ * When browsing to the end of the 4K PCI config space, the browse method
+ * shall wrap around to start reading from beginning again, and again...
+ *
+ * 2. For PCI config space register write access, it supports a single PCI
+ * config space register write in the size of a byte (8 bits), a word
+ * (16 bits), or a dword (32 bits). The command syntax is,
+ *
+ * echo 2 <where> <count> <value> > pciCfg
+ *
+ * where, 2 is the iDiag command for PCI config space write, <where> is
+ * the offset from the beginning of the device's PCI config space to write
+ * into, <count> is the size of data to write into the PCI config space,
+ * it will be 1 for writing a byte (8 bits), 2 for writing a word (16 bits
+ * or 2 bytes), or 4 for writing a dword (32 bits or 4 bytes), and <value>
+ * is the data to be written into the PCI config space register at the
+ * offset.
+ *
+ * Examples:
+ * To disable PCI device's interrupt assertion,
+ *
+ * 1) Read in device's PCI config space register command field <cmd>:
+ *
+ * echo 1 4 2 > pciCfg
+ * cat pciCfg
+ *
+ * 2) Set bit 10 (Interrupt Disable bit) in the <cmd>:
+ *
+ * <cmd> = <cmd> | (1 < 10)
+ *
+ * 3) Write the modified command back:
+ *
+ * echo 2 4 2 <cmd> > pciCfg
+ *
+ * 3. For PCI config space register set bits access, it supports a single PCI
+ * config space register set bits in the size of a byte (8 bits), a word
+ * (16 bits), or a dword (32 bits). The command syntax is,
+ *
+ * echo 3 <where> <count> <bitmask> > pciCfg
+ *
+ * where, 3 is the iDiag command for PCI config space set bits, <where> is
+ * the offset from the beginning of the device's PCI config space to set
+ * bits into, <count> is the size of the bitmask to set into the PCI config
+ * space, it will be 1 for setting a byte (8 bits), 2 for setting a word
+ * (16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 bytes), and
+ * <bitmask> is the bitmask, indicating the bits to be set into the PCI
+ * config space register at the offset. The logic performed to the content
+ * of the PCI config space register, regval, is,
+ *
+ * regval |= <bitmask>
+ *
+ * 4. For PCI config space register clear bits access, it supports a single
+ * PCI config space register clear bits in the size of a byte (8 bits),
+ * a word (16 bits), or a dword (32 bits). The command syntax is,
+ *
+ * echo 4 <where> <count> <bitmask> > pciCfg
+ *
+ * where, 4 is the iDiag command for PCI config space clear bits, <where>
+ * is the offset from the beginning of the device's PCI config space to
+ * clear bits from, <count> is the size of the bitmask to set into the PCI
+ * config space, it will be 1 for setting a byte (8 bits), 2 for setting
+ * a word(16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4
+ * bytes), and <bitmask> is the bitmask, indicating the bits to be cleared
+ * from the PCI config space register at the offset. the logic performed
+ * to the content of the PCI config space register, regval, is,
+ *
+ * regval &= ~<bitmask>
+ *
+ * Note, for all single register read, write, set bits, or clear bits access,
+ * the offset (<where>) must be aligned with the size of the data:
+ *
+ * For data size of byte (8 bits), the offset must be aligned to the byte
+ * boundary; for data size of word (16 bits), the offset must be aligned
+ * to the word boundary; while for data size of dword (32 bits), the offset
+ * must be aligned to the dword boundary. Otherwise, the interface will
+ * return the error:
+ *
+ * "-bash: echo: write error: Invalid argument".
+ *
+ * For example:
+ *
+ * echo 1 2 4 > pciCfg
+ * -bash: echo: write error: Invalid argument
+ *
+ * Note also, all of the numbers in the command fields for all read, write,
+ * set bits, and clear bits PCI config space register command fields can be
+ * either decimal or hex.
+ *
+ * For example,
+ * echo 1 0 4096 > pciCfg
+ *
+ * will be the same as
+ * echo 1 0 0x1000 > pciCfg
+ *
+ * And,
+ * echo 2 155 1 10 > pciCfg
+ *
+ * will be
+ * echo 2 0x9b 1 0xa > pciCfg
+ */
+
+/**
+ * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space
+ * @buf: The pointer to the user space buffer.
+ * @nbytes: The number of bytes in the user space buffer.
+ * @idiag_cmd: pointer to the idiag command struct.
+ *
+ * This routine reads data from debugfs user space buffer and parses the
+ * buffer for getting the idiag command and arguments. The while space in
+ * between the set of data is used as the parsing separator.
+ *
+ * This routine returns 0 when successful, it returns proper error code
+ * back to the user space in error conditions.
+ */
+static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes,
+ struct lpfc_idiag_cmd *idiag_cmd)
+{
+ char mybuf[64];
+ char *pbuf, *step_str;
+ int bsize, i;
+
+ /* Protect copy from user */
+ if (!access_ok(VERIFY_READ, buf, nbytes))
+ return -EFAULT;
+
+ memset(mybuf, 0, sizeof(mybuf));
+ memset(idiag_cmd, 0, sizeof(*idiag_cmd));
+ bsize = min(nbytes, (sizeof(mybuf)-1));
+
+ if (copy_from_user(mybuf, buf, bsize))
+ return -EFAULT;
+ pbuf = &mybuf[0];
+ step_str = strsep(&pbuf, "\t ");
+
+ /* The opcode must present */
+ if (!step_str)
+ return -EINVAL;
+
+ idiag_cmd->opcode = simple_strtol(step_str, NULL, 0);
+ if (idiag_cmd->opcode == 0)
+ return -EINVAL;
+
+ for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) {
+ step_str = strsep(&pbuf, "\t ");
+ if (!step_str)
+ return 0;
+ idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0);
+ }
+ return 0;
+}
+
+/**
+ * lpfc_idiag_open - idiag open debugfs
+ * @inode: The inode pointer that contains a pointer to phba.
+ * @file: The file pointer to attach the file operation.
+ *
+ * Description:
+ * This routine is the entry point for the debugfs open file operation. It
+ * gets the reference to phba from the i_private field in @inode, it then
+ * allocates buffer for the file operation, performs the necessary PCI config
+ * space read into the allocated buffer according to the idiag user command
+ * setup, and then returns a pointer to buffer in the private_data field in
+ * @file.
+ *
+ * Returns:
+ * This function returns zero if successful. On error it will return an
+ * negative error value.
+ **/
+static int
+lpfc_idiag_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_debug *debug;
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ return -ENOMEM;
+
+ debug->i_private = inode->i_private;
+ debug->buffer = NULL;
+ file->private_data = debug;
+
+ return 0;
+}
+
+/**
+ * lpfc_idiag_release - Release idiag access file operation
+ * @inode: The inode pointer that contains a vport pointer. (unused)
+ * @file: The file pointer that contains the buffer to release.
+ *
+ * Description:
+ * This routine is the generic release routine for the idiag access file
+ * operation, it frees the buffer that was allocated when the debugfs file
+ * was opened.
+ *
+ * Returns:
+ * This function returns zero.
+ **/
+static int
+lpfc_idiag_release(struct inode *inode, struct file *file)
+{
+ struct lpfc_debug *debug = file->private_data;
+
+ /* Free the buffers to the file operation */
+ kfree(debug->buffer);
+ kfree(debug);
+
+ return 0;
+}
+
+/**
+ * lpfc_idiag_cmd_release - Release idiag cmd access file operation
+ * @inode: The inode pointer that contains a vport pointer. (unused)
+ * @file: The file pointer that contains the buffer to release.
+ *
+ * Description:
+ * This routine frees the buffer that was allocated when the debugfs file
+ * was opened. It also reset the fields in the idiag command struct in the
+ * case the command is not continuous browsing of the data structure.
+ *
+ * Returns:
+ * This function returns zero.
+ **/
+static int
+lpfc_idiag_cmd_release(struct inode *inode, struct file *file)
+{
+ struct lpfc_debug *debug = file->private_data;
+
+ /* Read PCI config register, if not read all, clear command fields */
+ if ((debug->op == LPFC_IDIAG_OP_RD) &&
+ (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD))
+ if ((idiag.cmd.data[1] == sizeof(uint8_t)) ||
+ (idiag.cmd.data[1] == sizeof(uint16_t)) ||
+ (idiag.cmd.data[1] == sizeof(uint32_t)))
+ memset(&idiag, 0, sizeof(idiag));
+
+ /* Write PCI config register, clear command fields */
+ if ((debug->op == LPFC_IDIAG_OP_WR) &&
+ (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR))
+ memset(&idiag, 0, sizeof(idiag));
+
+ /* Free the buffers to the file operation */
+ kfree(debug->buffer);
+ kfree(debug);
+
+ return 0;
+}
+
+/**
+ * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba pci config space according to the
+ * idiag command, and copies to user @buf. Depending on the PCI config space
+ * read command setup, it does either a single register read of a byte
+ * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all
+ * registers from the 4K extended PCI config space.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ struct lpfc_debug *debug = file->private_data;
+ struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+ int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE;
+ int where, count;
+ char *pbuffer;
+ struct pci_dev *pdev;
+ uint32_t u32val;
+ uint16_t u16val;
+ uint8_t u8val;
+
+ pdev = phba->pcidev;
+ if (!pdev)
+ return 0;
+
+ /* This is a user read operation */
+ debug->op = LPFC_IDIAG_OP_RD;
+
+ if (!debug->buffer)
+ debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL);
+ if (!debug->buffer)
+ return 0;
+ pbuffer = debug->buffer;
+
+ if (*ppos)
+ return 0;
+
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
+ where = idiag.cmd.data[0];
+ count = idiag.cmd.data[1];
+ } else
+ return 0;
+
+ /* Read single PCI config space register */
+ switch (count) {
+ case SIZE_U8: /* byte (8 bits) */
+ pci_read_config_byte(pdev, where, &u8val);
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "%03x: %02x\n", where, u8val);
+ break;
+ case SIZE_U16: /* word (16 bits) */
+ pci_read_config_word(pdev, where, &u16val);
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "%03x: %04x\n", where, u16val);
+ break;
+ case SIZE_U32: /* double word (32 bits) */
+ pci_read_config_dword(pdev, where, &u32val);
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "%03x: %08x\n", where, u32val);
+ break;
+ case LPFC_PCI_CFG_SIZE: /* browse all */
+ goto pcicfg_browse;
+ break;
+ default:
+ /* illegal count */
+ len = 0;
+ break;
+ }
+ return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+
+pcicfg_browse:
+
+ /* Browse all PCI config space registers */
+ offset_label = idiag.offset.last_rd;
+ offset = offset_label;
+
+ /* Read PCI config space */
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "%03x: ", offset_label);
+ while (index > 0) {
+ pci_read_config_dword(pdev, offset, &u32val);
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "%08x ", u32val);
+ offset += sizeof(uint32_t);
+ index -= sizeof(uint32_t);
+ if (!index)
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "\n");
+ else if (!(index % (8 * sizeof(uint32_t)))) {
+ offset_label += (8 * sizeof(uint32_t));
+ len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ "\n%03x: ", offset_label);
+ }
+ }
+
+ /* Set up the offset for next portion of pci cfg read */
+ idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
+ if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
+ idiag.offset.last_rd = 0;
+
+ return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and
+ * then perform the syntax check for PCI config space read or write command
+ * accordingly. In the case of PCI config space read command, it sets up
+ * the command in the idiag command struct for the debugfs read operation.
+ * In the case of PCI config space write operation, it executes the write
+ * operation into the PCI config space accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ */
+static ssize_t
+lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct lpfc_debug *debug = file->private_data;
+ struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+ uint32_t where, value, count;
+ uint32_t u32val;
+ uint16_t u16val;
+ uint8_t u8val;
+ struct pci_dev *pdev;
+ int rc;
+
+ pdev = phba->pcidev;
+ if (!pdev)
+ return -EFAULT;
+
+ /* This is a user write operation */
+ debug->op = LPFC_IDIAG_OP_WR;
+
+ rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+ if (rc)
+ return rc;
+
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
+ /* Read command from PCI config space, set up command fields */
+ where = idiag.cmd.data[0];
+ count = idiag.cmd.data[1];
+ if (count == LPFC_PCI_CFG_SIZE) {
+ if (where != 0)
+ goto error_out;
+ } else if ((count != sizeof(uint8_t)) &&
+ (count != sizeof(uint16_t)) &&
+ (count != sizeof(uint32_t)))
+ goto error_out;
+ if (count == sizeof(uint8_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
+ goto error_out;
+ if (where % sizeof(uint8_t))
+ goto error_out;
+ }
+ if (count == sizeof(uint16_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
+ goto error_out;
+ if (where % sizeof(uint16_t))
+ goto error_out;
+ }
+ if (count == sizeof(uint32_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
+ goto error_out;
+ if (where % sizeof(uint32_t))
+ goto error_out;
+ }
+ } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR ||
+ idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST ||
+ idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
+ /* Write command to PCI config space, read-modify-write */
+ where = idiag.cmd.data[0];
+ count = idiag.cmd.data[1];
+ value = idiag.cmd.data[2];
+ /* Sanity checks */
+ if ((count != sizeof(uint8_t)) &&
+ (count != sizeof(uint16_t)) &&
+ (count != sizeof(uint32_t)))
+ goto error_out;
+ if (count == sizeof(uint8_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t))
+ goto error_out;
+ if (where % sizeof(uint8_t))
+ goto error_out;
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
+ pci_write_config_byte(pdev, where,
+ (uint8_t)value);
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
+ rc = pci_read_config_byte(pdev, where, &u8val);
+ if (!rc) {
+ u8val |= (uint8_t)value;
+ pci_write_config_byte(pdev, where,
+ u8val);
+ }
+ }
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
+ rc = pci_read_config_byte(pdev, where, &u8val);
+ if (!rc) {
+ u8val &= (uint8_t)(~value);
+ pci_write_config_byte(pdev, where,
+ u8val);
+ }
+ }
+ }
+ if (count == sizeof(uint16_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t))
+ goto error_out;
+ if (where % sizeof(uint16_t))
+ goto error_out;
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
+ pci_write_config_word(pdev, where,
+ (uint16_t)value);
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
+ rc = pci_read_config_word(pdev, where, &u16val);
+ if (!rc) {
+ u16val |= (uint16_t)value;
+ pci_write_config_word(pdev, where,
+ u16val);
+ }
+ }
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
+ rc = pci_read_config_word(pdev, where, &u16val);
+ if (!rc) {
+ u16val &= (uint16_t)(~value);
+ pci_write_config_word(pdev, where,
+ u16val);
+ }
+ }
+ }
+ if (count == sizeof(uint32_t)) {
+ if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t))
+ goto error_out;
+ if (where % sizeof(uint32_t))
+ goto error_out;
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)
+ pci_write_config_dword(pdev, where, value);
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) {
+ rc = pci_read_config_dword(pdev, where,
+ &u32val);
+ if (!rc) {
+ u32val |= value;
+ pci_write_config_dword(pdev, where,
+ u32val);
+ }
+ }
+ if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) {
+ rc = pci_read_config_dword(pdev, where,
+ &u32val);
+ if (!rc) {
+ u32val &= ~value;
+ pci_write_config_dword(pdev, where,
+ u32val);
+ }
+ }
+ }
+ } else
+ /* All other opecodes are illegal for now */
+ goto error_out;
+
+ return nbytes;
+error_out:
+ memset(&idiag, 0, sizeof(idiag));
+ return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_queinfo_read - idiag debugfs read queue information
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba SLI4 PCI function queue information,
+ * and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ struct lpfc_debug *debug = file->private_data;
+ struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+ int len = 0, fcp_qidx;
+ char *pbuffer;
+
+ if (!debug->buffer)
+ debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL);
+ if (!debug->buffer)
+ return 0;
+ pbuffer = debug->buffer;
+
+ if (*ppos)
+ return 0;
+
+ /* Get slow-path event queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Slow-path EQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], EQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n",
+ phba->sli4_hba.sp_eq->queue_id,
+ phba->sli4_hba.sp_eq->entry_count,
+ phba->sli4_hba.sp_eq->host_index,
+ phba->sli4_hba.sp_eq->hba_index);
+
+ /* Get fast-path event queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Fast-path EQ information:\n");
+ for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) {
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], EQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n",
+ phba->sli4_hba.fp_eq[fcp_qidx]->queue_id,
+ phba->sli4_hba.fp_eq[fcp_qidx]->entry_count,
+ phba->sli4_hba.fp_eq[fcp_qidx]->host_index,
+ phba->sli4_hba.fp_eq[fcp_qidx]->hba_index);
+ }
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+
+ /* Get mailbox complete queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Mailbox CQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated EQ-ID [%02d]:\n",
+ phba->sli4_hba.mbx_cq->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], CQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n",
+ phba->sli4_hba.mbx_cq->queue_id,
+ phba->sli4_hba.mbx_cq->entry_count,
+ phba->sli4_hba.mbx_cq->host_index,
+ phba->sli4_hba.mbx_cq->hba_index);
+
+ /* Get slow-path complete queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Slow-path CQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated EQ-ID [%02d]:\n",
+ phba->sli4_hba.els_cq->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], CQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n",
+ phba->sli4_hba.els_cq->queue_id,
+ phba->sli4_hba.els_cq->entry_count,
+ phba->sli4_hba.els_cq->host_index,
+ phba->sli4_hba.els_cq->hba_index);
+
+ /* Get fast-path complete queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Fast-path CQ information:\n");
+ for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) {
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated EQ-ID [%02d]:\n",
+ phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], EQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n",
+ phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id,
+ phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count,
+ phba->sli4_hba.fcp_cq[fcp_qidx]->host_index,
+ phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index);
+ }
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+
+ /* Get mailbox queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Mailbox MQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated CQ-ID [%02d]:\n",
+ phba->sli4_hba.mbx_wq->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], MQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n",
+ phba->sli4_hba.mbx_wq->queue_id,
+ phba->sli4_hba.mbx_wq->entry_count,
+ phba->sli4_hba.mbx_wq->host_index,
+ phba->sli4_hba.mbx_wq->hba_index);
+
+ /* Get slow-path work queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Slow-path WQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated CQ-ID [%02d]:\n",
+ phba->sli4_hba.els_wq->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], WQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n",
+ phba->sli4_hba.els_wq->queue_id,
+ phba->sli4_hba.els_wq->entry_count,
+ phba->sli4_hba.els_wq->host_index,
+ phba->sli4_hba.els_wq->hba_index);
+
+ /* Get fast-path work queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Fast-path WQ information:\n");
+ for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) {
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated CQ-ID [%02d]:\n",
+ phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], WQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n",
+ phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id,
+ phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count,
+ phba->sli4_hba.fcp_wq[fcp_qidx]->host_index,
+ phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index);
+ }
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n");
+
+ /* Get receive queue information */
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "Slow-path RQ information:\n");
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\t\tAssociated CQ-ID [%02d]:\n",
+ phba->sli4_hba.hdr_rq->assoc_qid);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], RHQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n",
+ phba->sli4_hba.hdr_rq->queue_id,
+ phba->sli4_hba.hdr_rq->entry_count,
+ phba->sli4_hba.hdr_rq->host_index,
+ phba->sli4_hba.hdr_rq->hba_index);
+ len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len,
+ "\tID [%02d], RDQE-COUNT [%04d], "
+ "HOST-INDEX [%04x], PORT-INDEX [%04x]\n",
+ phba->sli4_hba.dat_rq->queue_id,
+ phba->sli4_hba.dat_rq->entry_count,
+ phba->sli4_hba.dat_rq->host_index,
+ phba->sli4_hba.dat_rq->hba_index);
+
+ return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
#undef lpfc_debugfs_op_disc_trc
static const struct file_operations lpfc_debugfs_op_disc_trc = {
.owner = THIS_MODULE,
@@ -1213,6 +1964,28 @@ static const struct file_operations lpfc_debugfs_op_slow_ring_trc = {
static struct dentry *lpfc_debugfs_root = NULL;
static atomic_t lpfc_debugfs_hba_count;
+
+/*
+ * File operations for the iDiag debugfs
+ */
+#undef lpfc_idiag_op_pciCfg
+static const struct file_operations lpfc_idiag_op_pciCfg = {
+ .owner = THIS_MODULE,
+ .open = lpfc_idiag_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_idiag_pcicfg_read,
+ .write = lpfc_idiag_pcicfg_write,
+ .release = lpfc_idiag_cmd_release,
+};
+
+#undef lpfc_idiag_op_queInfo
+static const struct file_operations lpfc_idiag_op_queInfo = {
+ .owner = THIS_MODULE,
+ .open = lpfc_idiag_open,
+ .read = lpfc_idiag_queinfo_read,
+ .release = lpfc_idiag_release,
+};
+
#endif
/**
@@ -1249,8 +2022,8 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
if (!lpfc_debugfs_start_time)
lpfc_debugfs_start_time = jiffies;
- /* Setup lpfcX directory for specific HBA */
- snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
+ /* Setup funcX directory for specific HBA PCI function */
+ snprintf(name, sizeof(name), "fn%d", phba->brd_no);
if (!phba->hba_debugfs_root) {
phba->hba_debugfs_root =
debugfs_create_dir(name, lpfc_debugfs_root);
@@ -1275,28 +2048,38 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
/* Setup dumpHBASlim */
- snprintf(name, sizeof(name), "dumpHBASlim");
- phba->debug_dumpHBASlim =
- debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
- phba->hba_debugfs_root,
- phba, &lpfc_debugfs_op_dumpHBASlim);
- if (!phba->debug_dumpHBASlim) {
- lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0413 Cannot create debugfs dumpHBASlim\n");
- goto debug_failed;
- }
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ snprintf(name, sizeof(name), "dumpHBASlim");
+ phba->debug_dumpHBASlim =
+ debugfs_create_file(name,
+ S_IFREG|S_IRUGO|S_IWUSR,
+ phba->hba_debugfs_root,
+ phba, &lpfc_debugfs_op_dumpHBASlim);
+ if (!phba->debug_dumpHBASlim) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0413 Cannot create debugfs "
+ "dumpHBASlim\n");
+ goto debug_failed;
+ }
+ } else
+ phba->debug_dumpHBASlim = NULL;
/* Setup dumpHostSlim */
- snprintf(name, sizeof(name), "dumpHostSlim");
- phba->debug_dumpHostSlim =
- debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
- phba->hba_debugfs_root,
- phba, &lpfc_debugfs_op_dumpHostSlim);
- if (!phba->debug_dumpHostSlim) {
- lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0414 Cannot create debugfs dumpHostSlim\n");
- goto debug_failed;
- }
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ snprintf(name, sizeof(name), "dumpHostSlim");
+ phba->debug_dumpHostSlim =
+ debugfs_create_file(name,
+ S_IFREG|S_IRUGO|S_IWUSR,
+ phba->hba_debugfs_root,
+ phba, &lpfc_debugfs_op_dumpHostSlim);
+ if (!phba->debug_dumpHostSlim) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "0414 Cannot create debugfs "
+ "dumpHostSlim\n");
+ goto debug_failed;
+ }
+ } else
+ phba->debug_dumpHBASlim = NULL;
/* Setup dumpData */
snprintf(name, sizeof(name), "dumpData");
@@ -1322,8 +2105,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
goto debug_failed;
}
-
-
/* Setup slow ring trace */
if (lpfc_debugfs_max_slow_ring_trc) {
num = lpfc_debugfs_max_slow_ring_trc - 1;
@@ -1342,7 +2123,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
}
-
snprintf(name, sizeof(name), "slow_ring_trace");
phba->debug_slow_ring_trc =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
@@ -1434,6 +2214,53 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
"0409 Cant create debugfs nodelist\n");
goto debug_failed;
}
+
+ /*
+ * iDiag debugfs root entry points for SLI4 device only
+ */
+ if (phba->sli_rev < LPFC_SLI_REV4)
+ goto debug_failed;
+
+ snprintf(name, sizeof(name), "iDiag");
+ if (!phba->idiag_root) {
+ phba->idiag_root =
+ debugfs_create_dir(name, phba->hba_debugfs_root);
+ if (!phba->idiag_root) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "2922 Can't create idiag debugfs\n");
+ goto debug_failed;
+ }
+ /* Initialize iDiag data structure */
+ memset(&idiag, 0, sizeof(idiag));
+ }
+
+ /* iDiag read PCI config space */
+ snprintf(name, sizeof(name), "pciCfg");
+ if (!phba->idiag_pci_cfg) {
+ phba->idiag_pci_cfg =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ phba->idiag_root, phba, &lpfc_idiag_op_pciCfg);
+ if (!phba->idiag_pci_cfg) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "2923 Can't create idiag debugfs\n");
+ goto debug_failed;
+ }
+ idiag.offset.last_rd = 0;
+ }
+
+ /* iDiag get PCI function queue information */
+ snprintf(name, sizeof(name), "queInfo");
+ if (!phba->idiag_que_info) {
+ phba->idiag_que_info =
+ debugfs_create_file(name, S_IFREG|S_IRUGO,
+ phba->idiag_root, phba, &lpfc_idiag_op_queInfo);
+ if (!phba->idiag_que_info) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+ "2924 Can't create idiag debugfs\n");
+ goto debug_failed;
+ }
+ }
+
debug_failed:
return;
#endif
@@ -1508,8 +2335,31 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
phba->debug_slow_ring_trc = NULL;
}
+ /*
+ * iDiag release
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ if (phba->idiag_que_info) {
+ /* iDiag queInfo */
+ debugfs_remove(phba->idiag_que_info);
+ phba->idiag_que_info = NULL;
+ }
+ if (phba->idiag_pci_cfg) {
+ /* iDiag pciCfg */
+ debugfs_remove(phba->idiag_pci_cfg);
+ phba->idiag_pci_cfg = NULL;
+ }
+
+ /* Finally remove the iDiag debugfs root */
+ if (phba->idiag_root) {
+ /* iDiag root */
+ debugfs_remove(phba->idiag_root);
+ phba->idiag_root = NULL;
+ }
+ }
+
if (phba->hba_debugfs_root) {
- debugfs_remove(phba->hba_debugfs_root); /* lpfcX */
+ debugfs_remove(phba->hba_debugfs_root); /* fnX */
phba->hba_debugfs_root = NULL;
atomic_dec(&lpfc_debugfs_hba_count);
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index 03c7313a1012..91b9a9427cda 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2007 Emulex. All rights reserved. *
+ * Copyright (C) 2007-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -22,6 +22,44 @@
#define _H_LPFC_DEBUG_FS
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+
+/* size of output line, for discovery_trace and slow_ring_trace */
+#define LPFC_DEBUG_TRC_ENTRY_SIZE 100
+
+/* nodelist output buffer size */
+#define LPFC_NODELIST_SIZE 8192
+#define LPFC_NODELIST_ENTRY_SIZE 120
+
+/* dumpHBASlim output buffer size */
+#define LPFC_DUMPHBASLIM_SIZE 4096
+
+/* dumpHostSlim output buffer size */
+#define LPFC_DUMPHOSTSLIM_SIZE 4096
+
+/* hbqinfo output buffer size */
+#define LPFC_HBQINFO_SIZE 8192
+
+/* rdPciConf output buffer size */
+#define LPFC_PCI_CFG_SIZE 4096
+#define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2)
+#define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4)
+
+/* queue info output buffer size */
+#define LPFC_QUE_INFO_GET_BUF_SIZE 2048
+
+#define SIZE_U8 sizeof(uint8_t)
+#define SIZE_U16 sizeof(uint16_t)
+#define SIZE_U32 sizeof(uint32_t)
+
+struct lpfc_debug {
+ char *i_private;
+ char op;
+#define LPFC_IDIAG_OP_RD 1
+#define LPFC_IDIAG_OP_WR 2
+ char *buffer;
+ int len;
+};
+
struct lpfc_debugfs_trc {
char *fmt;
uint32_t data1;
@@ -30,6 +68,26 @@ struct lpfc_debugfs_trc {
uint32_t seq_cnt;
unsigned long jif;
};
+
+struct lpfc_idiag_offset {
+ uint32_t last_rd;
+};
+
+#define LPFC_IDIAG_CMD_DATA_SIZE 4
+struct lpfc_idiag_cmd {
+ uint32_t opcode;
+#define LPFC_IDIAG_CMD_PCICFG_RD 0x00000001
+#define LPFC_IDIAG_CMD_PCICFG_WR 0x00000002
+#define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003
+#define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004
+ uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE];
+};
+
+struct lpfc_idiag {
+ uint32_t active;
+ struct lpfc_idiag_cmd cmd;
+ struct lpfc_idiag_offset offset;
+};
#endif
/* Mask for discovery_trace */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c62d567cc845..8e28edf9801e 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2009 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -485,6 +485,59 @@ fail:
}
/**
+ * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean.
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @sp: pointer to service parameter data structure.
+ *
+ * This routine is called from FLOGI/FDISC completion handler functions.
+ * lpfc_check_clean_addr_bit return 1 when FCID/Fabric portname/ Fabric
+ * node nodename is changed in the completion service parameter else return
+ * 0. This function also set flag in the vport data structure to delay
+ * NP_Port discovery after the FLOGI/FDISC completion if Clean address bit
+ * in FLOGI/FDISC response is cleared and FCID/Fabric portname/ Fabric
+ * node nodename is changed in the completion service parameter.
+ *
+ * Return code
+ * 0 - FCID and Fabric Nodename and Fabric portname is not changed.
+ * 1 - FCID or Fabric Nodename or Fabric portname is changed.
+ *
+ **/
+static uint8_t
+lpfc_check_clean_addr_bit(struct lpfc_vport *vport,
+ struct serv_parm *sp)
+{
+ uint8_t fabric_param_changed = 0;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if ((vport->fc_prevDID != vport->fc_myDID) ||
+ memcmp(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name)) ||
+ memcmp(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name)))
+ fabric_param_changed = 1;
+
+ /*
+ * Word 1 Bit 31 in common service parameter is overloaded.
+ * Word 1 Bit 31 in FLOGI request is multiple NPort request
+ * Word 1 Bit 31 in FLOGI response is clean address bit
+ *
+ * If fabric parameter is changed and clean address bit is
+ * cleared delay nport discovery if
+ * - vport->fc_prevDID != 0 (not initial discovery) OR
+ * - lpfc_delay_discovery module parameter is set.
+ */
+ if (fabric_param_changed && !sp->cmn.clean_address_bit &&
+ (vport->fc_prevDID || lpfc_delay_discovery)) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_DISC_DELAYED;
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ return fabric_param_changed;
+}
+
+
+/**
* lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port
* @vport: pointer to a host virtual N_Port data structure.
* @ndlp: pointer to a node-list data structure.
@@ -512,6 +565,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *np;
struct lpfc_nodelist *next_np;
+ uint8_t fabric_param_changed;
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_FABRIC;
@@ -544,6 +598,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
sp->cmn.bbRcvSizeLsb;
+
+ fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ memcpy(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name));
+ memcpy(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name));
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
@@ -565,7 +625,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
}
- if ((vport->fc_prevDID != vport->fc_myDID) &&
+ if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/* If our NportID changed, we need to ensure all
@@ -2203,6 +2263,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
+ struct lpfcMboxq *mbox;
psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
@@ -2260,6 +2321,21 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
NLP_EVT_CMPL_LOGO);
out:
lpfc_els_free_iocb(phba, cmdiocb);
+ /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */
+ if ((vport->fc_flag & FC_PT2PT) &&
+ !(vport->fc_flag & FC_PT2PT_PLOGI)) {
+ phba->pport->fc_myDID = 0;
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) ==
+ MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+ }
return;
}
@@ -2745,7 +2821,8 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
}
break;
case ELS_CMD_FDISC:
- lpfc_issue_els_fdisc(vport, ndlp, retry);
+ if (!(vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI))
+ lpfc_issue_els_fdisc(vport, ndlp, retry);
break;
}
return;
@@ -2815,9 +2892,17 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
switch (irsp->ulpStatus) {
case IOSTAT_FCP_RSP_ERROR:
+ break;
case IOSTAT_REMOTE_STOP:
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ /* This IO was aborted by the target, we don't
+ * know the rxid and because we did not send the
+ * ABTS we cannot generate and RRQ.
+ */
+ lpfc_set_rrq_active(phba, ndlp,
+ cmdiocb->sli4_xritag, 0, 0);
+ }
break;
-
case IOSTAT_LOCAL_REJECT:
switch ((irsp->un.ulpWord[4] & 0xff)) {
case IOERR_LOOP_OPEN_FAILURE:
@@ -4013,28 +4098,34 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport,
uint8_t *pcmd;
struct RRQ *rrq;
uint16_t rxid;
+ uint16_t xri;
struct lpfc_node_rrq *prrq;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt);
pcmd += sizeof(uint32_t);
rrq = (struct RRQ *)pcmd;
- rxid = bf_get(rrq_oxid, rrq);
+ rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg);
+ rxid = be16_to_cpu(bf_get(rrq_rxid, rrq));
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x"
" x%x x%x\n",
- bf_get(rrq_did, rrq),
- bf_get(rrq_oxid, rrq),
+ be32_to_cpu(bf_get(rrq_did, rrq)),
+ be16_to_cpu(bf_get(rrq_oxid, rrq)),
rxid,
iocb->iotag, iocb->iocb.ulpContext);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
"Clear RRQ: did:x%x flg:x%x exchg:x%.08x",
ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg);
- prrq = lpfc_get_active_rrq(vport, rxid, ndlp->nlp_DID);
+ if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq)))
+ xri = be16_to_cpu(bf_get(rrq_oxid, rrq));
+ else
+ xri = rxid;
+ prrq = lpfc_get_active_rrq(vport, xri, ndlp->nlp_DID);
if (prrq)
- lpfc_clr_rrq_active(phba, rxid, prrq);
+ lpfc_clr_rrq_active(phba, xri, prrq);
return;
}
@@ -6166,6 +6257,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (vport->load_flag & FC_UNLOADING)
goto dropit;
+ /* If NPort discovery is delayed drop incoming ELS */
+ if ((vport->fc_flag & FC_DISC_DELAYED) &&
+ (cmd != ELS_CMD_PLOGI))
+ goto dropit;
+
ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
@@ -6218,6 +6314,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
lpfc_send_els_event(vport, ndlp, payload);
+
+ /* If Nport discovery is delayed, reject PLOGIs */
+ if (vport->fc_flag & FC_DISC_DELAYED) {
+ rjt_err = LSRJT_UNABLE_TPC;
+ break;
+ }
if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -6596,6 +6698,21 @@ void
lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /*
+ * If lpfc_delay_discovery parameter is set and the clean address
+ * bit is cleared and fc fabric parameters chenged, delay FC NPort
+ * discovery.
+ */
+ spin_lock_irq(shost->host_lock);
+ if (vport->fc_flag & FC_DISC_DELAYED) {
+ spin_unlock_irq(shost->host_lock);
+ mod_timer(&vport->delayed_disc_tmo,
+ jiffies + HZ * phba->fc_ratov);
+ return;
+ }
+ spin_unlock_irq(shost->host_lock);
ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (!ndlp) {
@@ -6938,6 +7055,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *next_np;
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_iocbq *piocb;
+ struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
+ struct serv_parm *sp;
+ uint8_t fabric_param_changed;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0123 FDISC completes. x%x/x%x prevDID: x%x\n",
@@ -6981,7 +7101,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
- if ((vport->fc_prevDID != vport->fc_myDID) &&
+ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
+ sp = prsp->virt + sizeof(uint32_t);
+ fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ memcpy(&vport->fabric_portname, &sp->portName,
+ sizeof(struct lpfc_name));
+ memcpy(&vport->fabric_nodename, &sp->nodeName,
+ sizeof(struct lpfc_name));
+ if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
/* If our NportID changed, we need to ensure all
* remaining NPORTs get unreg_login'ed so we can
@@ -7582,6 +7709,32 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_vport_delete_els_xri_aborted -Remove all ndlp references for vport
+ * @vport: pointer to lpfc vport data structure.
+ *
+ * This routine is invoked by the vport cleanup for deletions and the cleanup
+ * for an ndlp on removal.
+ **/
+void
+lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
+ unsigned long iflag = 0;
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
+ list_for_each_entry_safe(sglq_entry, sglq_next,
+ &phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
+ if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport)
+ sglq_entry->ndlp = NULL;
+ }
+ spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
+}
+
+/**
* lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort
* @phba: pointer to lpfc hba data structure.
* @axri: pointer to the els xri abort wcqe structure.
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bb015960dbc9..154c715fb3af 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -658,6 +658,8 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_ramp_down_queue_handler(phba);
if (work_port_events & WORKER_RAMP_UP_QUEUE)
lpfc_ramp_up_queue_handler(phba);
+ if (work_port_events & WORKER_DELAYED_DISC_TMO)
+ lpfc_delayed_disc_timeout_handler(vport);
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -838,6 +840,11 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
lpfc_port_link_failure(vport);
+ /* Stop delayed Nport discovery */
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_DISC_DELAYED;
+ spin_unlock_irq(shost->host_lock);
+ del_timer_sync(&vport->delayed_disc_tmo);
}
int
@@ -3160,7 +3167,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_unlock_irq(shost->host_lock);
vport->unreg_vpi_cmpl = VPORT_OK;
mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_cleanup_vports_rrqs(vport);
+ lpfc_cleanup_vports_rrqs(vport, NULL);
/*
* This shost reference might have been taken at the beginning of
* lpfc_vport_delete()
@@ -3900,6 +3907,8 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
return;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ if (vport->phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_cleanup_vports_rrqs(vport, ndlp);
lpfc_nlp_put(ndlp);
return;
}
@@ -4289,7 +4298,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
list_del_init(&ndlp->els_retry_evt.evt_listp);
list_del_init(&ndlp->dev_loss_evt.evt_listp);
-
+ lpfc_cleanup_vports_rrqs(vport, ndlp);
lpfc_unreg_rpi(vport, ndlp);
return 0;
@@ -4426,10 +4435,11 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
+ unsigned long iflags;
- spin_lock_irq(shost->host_lock);
+ spin_lock_irqsave(shost->host_lock, iflags);
ndlp = __lpfc_findnode_did(vport, did);
- spin_unlock_irq(shost->host_lock);
+ spin_unlock_irqrestore(shost->host_lock, iflags);
return ndlp;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 96ed3ba6ba95..94ae37c5111a 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -341,6 +341,12 @@ struct csp {
uint8_t bbCreditMsb;
uint8_t bbCreditlsb; /* FC Word 0, byte 3 */
+/*
+ * Word 1 Bit 31 in common service parameter is overloaded.
+ * Word 1 Bit 31 in FLOGI request is multiple NPort request
+ * Word 1 Bit 31 in FLOGI response is clean address bit
+ */
+#define clean_address_bit request_multiple_Nport /* Word 1, bit 31 */
#ifdef __BIG_ENDIAN_BITFIELD
uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */
uint16_t randomOffset:1; /* FC Word 1, bit 30 */
@@ -3198,7 +3204,10 @@ typedef struct {
#define IOERR_SLER_RRQ_RJT_ERR 0x4C
#define IOERR_SLER_RRQ_RETRY_ERR 0x4D
#define IOERR_SLER_ABTS_ERR 0x4E
-
+#define IOERR_ELXSEC_KEY_UNWRAP_ERROR 0xF0
+#define IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR 0xF1
+#define IOERR_ELXSEC_CRYPTO_ERROR 0xF2
+#define IOERR_ELXSEC_CRYPTO_COMPARE_ERROR 0xF3
#define IOERR_DRVR_MASK 0x100
#define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */
#define IOERR_SLI_BRESET 0x102
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 94c1aa1136de..c7178d60c7bf 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -778,6 +778,7 @@ struct mbox_header {
#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A
#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D
#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A
+#define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5
/* FCoE Opcodes */
#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01
@@ -1852,6 +1853,9 @@ struct lpfc_mbx_request_features {
#define lpfc_mbx_rq_ftr_rq_ifip_SHIFT 7
#define lpfc_mbx_rq_ftr_rq_ifip_MASK 0x00000001
#define lpfc_mbx_rq_ftr_rq_ifip_WORD word2
+#define lpfc_mbx_rq_ftr_rq_perfh_SHIFT 11
+#define lpfc_mbx_rq_ftr_rq_perfh_MASK 0x00000001
+#define lpfc_mbx_rq_ftr_rq_perfh_WORD word2
uint32_t word3;
#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT 0
#define lpfc_mbx_rq_ftr_rsp_iaab_MASK 0x00000001
@@ -1877,6 +1881,9 @@ struct lpfc_mbx_request_features {
#define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT 7
#define lpfc_mbx_rq_ftr_rsp_ifip_MASK 0x00000001
#define lpfc_mbx_rq_ftr_rsp_ifip_WORD word3
+#define lpfc_mbx_rq_ftr_rsp_perfh_SHIFT 11
+#define lpfc_mbx_rq_ftr_rsp_perfh_MASK 0x00000001
+#define lpfc_mbx_rq_ftr_rsp_perfh_WORD word3
};
struct lpfc_mbx_supp_pages {
@@ -1935,7 +1942,7 @@ struct lpfc_mbx_supp_pages {
#define LPFC_SLI4_PARAMETERS 2
};
-struct lpfc_mbx_sli4_params {
+struct lpfc_mbx_pc_sli4_params {
uint32_t word1;
#define qs_SHIFT 0
#define qs_MASK 0x00000001
@@ -2051,6 +2058,88 @@ struct lpfc_mbx_sli4_params {
uint32_t rsvd_13_63[51];
};
+struct lpfc_sli4_parameters {
+ uint32_t word0;
+#define cfg_prot_type_SHIFT 0
+#define cfg_prot_type_MASK 0x000000FF
+#define cfg_prot_type_WORD word0
+ uint32_t word1;
+#define cfg_ft_SHIFT 0
+#define cfg_ft_MASK 0x00000001
+#define cfg_ft_WORD word1
+#define cfg_sli_rev_SHIFT 4
+#define cfg_sli_rev_MASK 0x0000000f
+#define cfg_sli_rev_WORD word1
+#define cfg_sli_family_SHIFT 8
+#define cfg_sli_family_MASK 0x0000000f
+#define cfg_sli_family_WORD word1
+#define cfg_if_type_SHIFT 12
+#define cfg_if_type_MASK 0x0000000f
+#define cfg_if_type_WORD word1
+#define cfg_sli_hint_1_SHIFT 16
+#define cfg_sli_hint_1_MASK 0x000000ff
+#define cfg_sli_hint_1_WORD word1
+#define cfg_sli_hint_2_SHIFT 24
+#define cfg_sli_hint_2_MASK 0x0000001f
+#define cfg_sli_hint_2_WORD word1
+ uint32_t word2;
+ uint32_t word3;
+ uint32_t word4;
+#define cfg_cqv_SHIFT 14
+#define cfg_cqv_MASK 0x00000003
+#define cfg_cqv_WORD word4
+ uint32_t word5;
+ uint32_t word6;
+#define cfg_mqv_SHIFT 14
+#define cfg_mqv_MASK 0x00000003
+#define cfg_mqv_WORD word6
+ uint32_t word7;
+ uint32_t word8;
+#define cfg_wqv_SHIFT 14
+#define cfg_wqv_MASK 0x00000003
+#define cfg_wqv_WORD word8
+ uint32_t word9;
+ uint32_t word10;
+#define cfg_rqv_SHIFT 14
+#define cfg_rqv_MASK 0x00000003
+#define cfg_rqv_WORD word10
+ uint32_t word11;
+#define cfg_rq_db_window_SHIFT 28
+#define cfg_rq_db_window_MASK 0x0000000f
+#define cfg_rq_db_window_WORD word11
+ uint32_t word12;
+#define cfg_fcoe_SHIFT 0
+#define cfg_fcoe_MASK 0x00000001
+#define cfg_fcoe_WORD word12
+#define cfg_phwq_SHIFT 15
+#define cfg_phwq_MASK 0x00000001
+#define cfg_phwq_WORD word12
+#define cfg_loopbk_scope_SHIFT 28
+#define cfg_loopbk_scope_MASK 0x0000000f
+#define cfg_loopbk_scope_WORD word12
+ uint32_t sge_supp_len;
+ uint32_t word14;
+#define cfg_sgl_page_cnt_SHIFT 0
+#define cfg_sgl_page_cnt_MASK 0x0000000f
+#define cfg_sgl_page_cnt_WORD word14
+#define cfg_sgl_page_size_SHIFT 8
+#define cfg_sgl_page_size_MASK 0x000000ff
+#define cfg_sgl_page_size_WORD word14
+#define cfg_sgl_pp_align_SHIFT 16
+#define cfg_sgl_pp_align_MASK 0x000000ff
+#define cfg_sgl_pp_align_WORD word14
+ uint32_t word15;
+ uint32_t word16;
+ uint32_t word17;
+ uint32_t word18;
+ uint32_t word19;
+};
+
+struct lpfc_mbx_get_sli4_parameters {
+ struct mbox_header header;
+ struct lpfc_sli4_parameters sli4_parameters;
+};
+
/* Mailbox Completion Queue Error Messages */
#define MB_CQE_STATUS_SUCCESS 0x0
#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1
@@ -2103,7 +2192,8 @@ struct lpfc_mqe {
struct lpfc_mbx_post_hdr_tmpl hdr_tmpl;
struct lpfc_mbx_query_fw_cfg query_fw_cfg;
struct lpfc_mbx_supp_pages supp_pages;
- struct lpfc_mbx_sli4_params sli4_params;
+ struct lpfc_mbx_pc_sli4_params sli4_params;
+ struct lpfc_mbx_get_sli4_parameters get_sli4_parameters;
struct lpfc_mbx_nop nop;
} un;
};
@@ -2381,6 +2471,10 @@ struct wqe_common {
#define wqe_wqes_SHIFT 15
#define wqe_wqes_MASK 0x00000001
#define wqe_wqes_WORD word10
+/* Note that this field overlaps above fields */
+#define wqe_wqid_SHIFT 1
+#define wqe_wqid_MASK 0x0000007f
+#define wqe_wqid_WORD word10
#define wqe_pri_SHIFT 16
#define wqe_pri_MASK 0x00000007
#define wqe_pri_WORD word10
@@ -2599,7 +2693,8 @@ struct fcp_iwrite64_wqe {
uint32_t total_xfer_len;
uint32_t initial_xfer_len;
struct wqe_common wqe_com; /* words 6-11 */
- uint32_t rsvd_12_15[4]; /* word 12-15 */
+ uint32_t rsrvd12;
+ struct ulp_bde64 ph_bde; /* words 13-15 */
};
struct fcp_iread64_wqe {
@@ -2608,7 +2703,8 @@ struct fcp_iread64_wqe {
uint32_t total_xfer_len; /* word 4 */
uint32_t rsrvd5; /* word 5 */
struct wqe_common wqe_com; /* words 6-11 */
- uint32_t rsvd_12_15[4]; /* word 12-15 */
+ uint32_t rsrvd12;
+ struct ulp_bde64 ph_bde; /* words 13-15 */
};
struct fcp_icmnd64_wqe {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 6d0b36aa3389..35665cfb5689 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -460,7 +460,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
|| ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G)
&& !(phba->lmt & LMT_16Gb))) {
/* Reset link speed to auto */
- lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
phba->cfg_link_speed);
@@ -945,17 +945,13 @@ static void
lpfc_rrq_timeout(unsigned long ptr)
{
struct lpfc_hba *phba;
- uint32_t tmo_posted;
unsigned long iflag;
phba = (struct lpfc_hba *)ptr;
spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
- tmo_posted = phba->hba_flag & HBA_RRQ_ACTIVE;
- if (!tmo_posted)
- phba->hba_flag |= HBA_RRQ_ACTIVE;
+ phba->hba_flag |= HBA_RRQ_ACTIVE;
spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
- if (!tmo_posted)
- lpfc_worker_wake_up(phba);
+ lpfc_worker_wake_up(phba);
}
/**
@@ -2280,6 +2276,7 @@ lpfc_cleanup(struct lpfc_vport *vport)
/* Wait for any activity on ndlps to settle */
msleep(10);
}
+ lpfc_cleanup_vports_rrqs(vport, NULL);
}
/**
@@ -2295,6 +2292,7 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
del_timer_sync(&vport->els_tmofunc);
del_timer_sync(&vport->fc_fdmitmo);
+ del_timer_sync(&vport->delayed_disc_tmo);
lpfc_can_disctmo(vport);
return;
}
@@ -2355,6 +2353,10 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
del_timer_sync(&phba->fabric_block_timer);
del_timer_sync(&phba->eratt_poll);
del_timer_sync(&phba->hb_tmofunc);
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ del_timer_sync(&phba->rrq_tmr);
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ }
phba->hb_outstanding = 0;
switch (phba->pci_dev_grp) {
@@ -2732,6 +2734,11 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
init_timer(&vport->els_tmofunc);
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
+
+ init_timer(&vport->delayed_disc_tmo);
+ vport->delayed_disc_tmo.function = lpfc_delayed_disc_tmo;
+ vport->delayed_disc_tmo.data = (unsigned long)vport;
+
error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
if (error)
goto out_put_shost;
@@ -4283,36 +4290,37 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
goto out_free_bsmbx;
}
- /* Get the Supported Pages. It is always available. */
+ /* Get the Supported Pages if PORT_CAPABILITIES is supported by port. */
lpfc_supported_pages(mboxq);
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
- if (unlikely(rc)) {
- rc = -EIO;
- mempool_free(mboxq, phba->mbox_mem_pool);
- goto out_free_bsmbx;
- }
-
- mqe = &mboxq->u.mqe;
- memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
- LPFC_MAX_SUPPORTED_PAGES);
- for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
- switch (pn_page[i]) {
- case LPFC_SLI4_PARAMETERS:
- phba->sli4_hba.pc_sli4_params.supported = 1;
- break;
- default:
- break;
+ if (!rc) {
+ mqe = &mboxq->u.mqe;
+ memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
+ LPFC_MAX_SUPPORTED_PAGES);
+ for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
+ switch (pn_page[i]) {
+ case LPFC_SLI4_PARAMETERS:
+ phba->sli4_hba.pc_sli4_params.supported = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ /* Read the port's SLI4 Parameters capabilities if supported. */
+ if (phba->sli4_hba.pc_sli4_params.supported)
+ rc = lpfc_pc_sli4_params_get(phba, mboxq);
+ if (rc) {
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ rc = -EIO;
+ goto out_free_bsmbx;
}
}
-
- /* Read the port's SLI4 Parameters capabilities if supported. */
- if (phba->sli4_hba.pc_sli4_params.supported)
- rc = lpfc_pc_sli4_params_get(phba, mboxq);
+ /*
+ * Get sli4 parameters that override parameters from Port capabilities.
+ * If this call fails it is not a critical error so continue loading.
+ */
+ lpfc_get_sli4_parameters(phba, mboxq);
mempool_free(mboxq, phba->mbox_mem_pool);
- if (rc) {
- rc = -EIO;
- goto out_free_bsmbx;
- }
/* Create all the SLI4 queues */
rc = lpfc_sli4_queue_create(phba);
if (rc)
@@ -7810,7 +7818,7 @@ lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
mqe = &mboxq->u.mqe;
/* Read the port's SLI4 Parameters port capabilities */
- lpfc_sli4_params(mboxq);
+ lpfc_pc_sli4_params(mboxq);
if (!phba->sli4_hba.intr_enable)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
else {
@@ -7854,6 +7862,66 @@ lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
}
/**
+ * lpfc_get_sli4_parameters - Get the SLI4 Config PARAMETERS.
+ * @phba: Pointer to HBA context object.
+ * @mboxq: Pointer to the mailboxq memory for the mailbox command response.
+ *
+ * This function is called in the SLI4 code path to read the port's
+ * sli4 capabilities.
+ *
+ * This function may be be called from any context that can block-wait
+ * for the completion. The expectation is that this routine is called
+ * typically from probe_one or from the online routine.
+ **/
+int
+lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+ int rc;
+ struct lpfc_mqe *mqe = &mboxq->u.mqe;
+ struct lpfc_pc_sli4_params *sli4_params;
+ int length;
+ struct lpfc_sli4_parameters *mbx_sli4_parameters;
+
+ /* Read the port's SLI4 Config Parameters */
+ length = (sizeof(struct lpfc_mbx_get_sli4_parameters) -
+ sizeof(struct lpfc_sli4_cfg_mhdr));
+ lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
+ LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS,
+ length, LPFC_SLI4_MBX_EMBED);
+ if (!phba->sli4_hba.intr_enable)
+ rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
+ lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
+ if (unlikely(rc))
+ return rc;
+ sli4_params = &phba->sli4_hba.pc_sli4_params;
+ mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters;
+ sli4_params->if_type = bf_get(cfg_if_type, mbx_sli4_parameters);
+ sli4_params->sli_rev = bf_get(cfg_sli_rev, mbx_sli4_parameters);
+ sli4_params->sli_family = bf_get(cfg_sli_family, mbx_sli4_parameters);
+ sli4_params->featurelevel_1 = bf_get(cfg_sli_hint_1,
+ mbx_sli4_parameters);
+ sli4_params->featurelevel_2 = bf_get(cfg_sli_hint_2,
+ mbx_sli4_parameters);
+ if (bf_get(cfg_phwq, mbx_sli4_parameters))
+ phba->sli3_options |= LPFC_SLI4_PHWQ_ENABLED;
+ else
+ phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED;
+ sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len;
+ sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters);
+ sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters);
+ sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
+ sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
+ sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
+ sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
+ mbx_sli4_parameters);
+ sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
+ mbx_sli4_parameters);
+ return 0;
+}
+
+/**
* lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem.
* @pdev: pointer to PCI device
* @pid: pointer to PCI device identifier
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 23403c650207..dba32dfdb59b 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1263,7 +1263,8 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) {
if (phba->cfg_enable_bg)
mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */
- mb->un.varCfgPort.cdss = 1; /* Configure Security */
+ if (phba->cfg_enable_dss)
+ mb->un.varCfgPort.cdss = 1; /* Configure Security */
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
@@ -1692,7 +1693,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
* @mbox: pointer to lpfc mbox command.
* @subsystem: The sli4 config sub mailbox subsystem.
* @opcode: The sli4 config sub mailbox command opcode.
- * @length: Length of the sli4 config mailbox command.
+ * @length: Length of the sli4 config mailbox command (including sub-header).
*
* This routine sets up the header fields of SLI4 specific mailbox command
* for sending IOCTL command.
@@ -1723,14 +1724,14 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
if (emb) {
/* Set up main header fields */
bf_set(lpfc_mbox_hdr_emb, &sli4_config->header.cfg_mhdr, 1);
- sli4_config->header.cfg_mhdr.payload_length =
- LPFC_MBX_CMD_HDR_LENGTH + length;
+ sli4_config->header.cfg_mhdr.payload_length = length;
/* Set up sub-header fields following main header */
bf_set(lpfc_mbox_hdr_opcode,
&sli4_config->header.cfg_shdr.request, opcode);
bf_set(lpfc_mbox_hdr_subsystem,
&sli4_config->header.cfg_shdr.request, subsystem);
- sli4_config->header.cfg_shdr.request.request_length = length;
+ sli4_config->header.cfg_shdr.request.request_length =
+ length - LPFC_MBX_CMD_HDR_LENGTH;
return length;
}
@@ -1902,6 +1903,7 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq)
/* Set up host requested features. */
bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1);
+ bf_set(lpfc_mbx_rq_ftr_rq_perfh, &mboxq->u.mqe.un.req_ftrs, 1);
/* Enable DIF (block guard) only if configured to do so. */
if (phba->cfg_enable_bg)
@@ -2159,17 +2161,16 @@ lpfc_supported_pages(struct lpfcMboxq *mbox)
}
/**
- * lpfc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params
- * mailbox command.
+ * lpfc_pc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params mbox cmd.
* @mbox: pointer to lpfc mbox command to initialize.
*
* The PORT_CAPABILITIES SLI4 parameters mailbox command is issued to
* retrieve the particular SLI4 features supported by the port.
**/
void
-lpfc_sli4_params(struct lpfcMboxq *mbox)
+lpfc_pc_sli4_params(struct lpfcMboxq *mbox)
{
- struct lpfc_mbx_sli4_params *sli4_params;
+ struct lpfc_mbx_pc_sli4_params *sli4_params;
memset(mbox, 0, sizeof(*mbox));
sli4_params = &mbox->u.mqe.un.sli4_params;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index d85a7423a694..52b35159fc35 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -350,7 +350,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
- /* no need to reg_login if we are already in one of these states */
+ /*
+ * Need to unreg_login if we are already in one of these states and
+ * change to NPR state. This will block the port until after the ACC
+ * completes and the reg_login is issued and completed.
+ */
switch (ndlp->nlp_state) {
case NLP_STE_NPR_NODE:
if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
@@ -359,8 +363,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
case NLP_STE_PRLI_ISSUE:
case NLP_STE_UNMAPPED_NODE:
case NLP_STE_MAPPED_NODE:
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
- return 1;
+ lpfc_unreg_rpi(vport, ndlp);
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
if ((vport->fc_flag & FC_PT2PT) &&
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c97751c95d77..bf34178b80bf 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -609,6 +609,32 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)
}
/**
+ * lpfc_sli4_vport_delete_fcp_xri_aborted -Remove all ndlp references for vport
+ * @vport: pointer to lpfc vport data structure.
+ *
+ * This routine is invoked by the vport cleanup for deletions and the cleanup
+ * for an ndlp on removal.
+ **/
+void
+lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_scsi_buf *psb, *next_psb;
+ unsigned long iflag = 0;
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+ list_for_each_entry_safe(psb, next_psb,
+ &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
+ if (psb->rdata && psb->rdata->pnode
+ && psb->rdata->pnode->vport == vport)
+ psb->rdata = NULL;
+ }
+ spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+}
+
+/**
* lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort
* @phba: pointer to lpfc hba data structure.
* @axri: pointer to the fcp xri abort wcqe structure.
@@ -640,7 +666,11 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb->status = IOSTAT_SUCCESS;
spin_unlock(
&phba->sli4_hba.abts_scsi_buf_list_lock);
- ndlp = psb->rdata->pnode;
+ if (psb->rdata && psb->rdata->pnode)
+ ndlp = psb->rdata->pnode;
+ else
+ ndlp = NULL;
+
rrq_empty = list_empty(&phba->active_rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflag);
if (ndlp)
@@ -964,36 +994,29 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
static struct lpfc_scsi_buf*
lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
- struct lpfc_scsi_buf *lpfc_cmd = NULL;
- struct lpfc_scsi_buf *start_lpfc_cmd = NULL;
- struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
+ struct lpfc_scsi_buf *lpfc_cmd ;
unsigned long iflag = 0;
int found = 0;
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
- list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
- spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
- while (!found && lpfc_cmd) {
+ list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list,
+ list) {
if (lpfc_test_rrq_active(phba, ndlp,
- lpfc_cmd->cur_iocbq.sli4_xritag)) {
- lpfc_release_scsi_buf_s4(phba, lpfc_cmd);
- spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
- list_remove_head(scsi_buf_list, lpfc_cmd,
- struct lpfc_scsi_buf, list);
- spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
- iflag);
- if (lpfc_cmd == start_lpfc_cmd) {
- lpfc_cmd = NULL;
- break;
- } else
- continue;
- }
+ lpfc_cmd->cur_iocbq.sli4_xritag))
+ continue;
+ list_del(&lpfc_cmd->list);
found = 1;
lpfc_cmd->seg_cnt = 0;
lpfc_cmd->nonsg_phys = 0;
lpfc_cmd->prot_seg_cnt = 0;
+ break;
}
- return lpfc_cmd;
+ spin_unlock_irqrestore(&phba->scsi_buf_list_lock,
+ iflag);
+ if (!found)
+ return NULL;
+ else
+ return lpfc_cmd;
}
/**
* lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA
@@ -1981,12 +2004,14 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
struct scatterlist *sgel = NULL;
struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
+ struct sli4_sge *first_data_sgl;
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
dma_addr_t physaddr;
uint32_t num_bde = 0;
uint32_t dma_len;
uint32_t dma_offset = 0;
int nseg;
+ struct ulp_bde64 *bde;
/*
* There are three possibilities here - use scatter-gather segment, use
@@ -2011,7 +2036,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
bf_set(lpfc_sli4_sge_last, sgl, 0);
sgl->word2 = cpu_to_le32(sgl->word2);
sgl += 1;
-
+ first_data_sgl = sgl;
lpfc_cmd->seg_cnt = nseg;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:"
@@ -2047,6 +2072,17 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
dma_offset += dma_len;
sgl++;
}
+ /* setup the performance hint (first data BDE) if enabled */
+ if (phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) {
+ bde = (struct ulp_bde64 *)
+ &(iocb_cmd->unsli3.sli3Words[5]);
+ bde->addrLow = first_data_sgl->addr_lo;
+ bde->addrHigh = first_data_sgl->addr_hi;
+ bde->tus.f.bdeSize =
+ le32_to_cpu(first_data_sgl->sge_len);
+ bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ bde->tus.w = cpu_to_le32(bde->tus.w);
+ }
} else {
sgl += 1;
/* clear the last flag in the fcp_rsp map entry */
@@ -2471,6 +2507,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_worker_wake_up(phba);
break;
case IOSTAT_LOCAL_REJECT:
+ case IOSTAT_REMOTE_STOP:
+ if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR ||
+ lpfc_cmd->result ==
+ IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR ||
+ lpfc_cmd->result == IOERR_ELXSEC_CRYPTO_ERROR ||
+ lpfc_cmd->result ==
+ IOERR_ELXSEC_CRYPTO_COMPARE_ERROR) {
+ cmd->result = ScsiResult(DID_NO_CONNECT, 0);
+ break;
+ }
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
@@ -2478,7 +2524,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
cmd->result = ScsiResult(DID_REQUEUE, 0);
break;
}
-
if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
lpfc_cmd->result == IOERR_TX_DMA_FAILED) &&
pIocbOut->iocb.unsli3.sli3_bg.bgstat) {
@@ -2497,7 +2542,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
"on unprotected cmd\n");
}
}
-
+ if ((lpfc_cmd->status == IOSTAT_REMOTE_STOP)
+ && (phba->sli_rev == LPFC_SLI_REV4)
+ && (pnode && NLP_CHK_NODE_ACT(pnode))) {
+ /* This IO was aborted by the target, we don't
+ * know the rxid and because we did not send the
+ * ABTS we cannot generate and RRQ.
+ */
+ lpfc_set_rrq_active(phba, pnode,
+ lpfc_cmd->cur_iocbq.sli4_xritag,
+ 0, 0);
+ }
/* else: fall through */
default:
cmd->result = ScsiResult(DID_ERROR, 0);
@@ -2508,9 +2563,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
|| (pnode->nlp_state != NLP_STE_MAPPED_NODE))
cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED,
SAM_STAT_BUSY);
- } else {
+ } else
cmd->result = ScsiResult(DID_OK, 0);
- }
if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) {
uint32_t *lp = (uint32_t *)cmd->sense_buffer;
@@ -3004,11 +3058,11 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
* transport is still transitioning.
*/
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
- cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
+ cmnd->result = ScsiResult(DID_IMM_RETRY, 0);
goto out_fail_command;
}
if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
- goto out_host_busy;
+ goto out_tgt_busy;
lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
if (lpfc_cmd == NULL) {
@@ -3125,6 +3179,9 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
+ out_tgt_busy:
+ return SCSI_MLQUEUE_TARGET_BUSY;
+
out_fail_command:
done(cmnd);
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a359d2b873ce..2ee0374a9908 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -96,7 +96,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
/* set consumption flag every once in a while */
if (!((q->host_index + 1) % LPFC_RELEASE_NOTIFICATION_INTERVAL))
bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
-
+ if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
+ bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
/* Update the host index before invoking device */
@@ -534,15 +535,35 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
uint16_t adj_xri;
struct lpfc_node_rrq *rrq;
int empty;
+ uint32_t did = 0;
+
+
+ if (!ndlp)
+ return -EINVAL;
+
+ if (!phba->cfg_enable_rrq)
+ return -EINVAL;
+
+ if (phba->pport->load_flag & FC_UNLOADING) {
+ phba->hba_flag &= ~HBA_RRQ_ACTIVE;
+ goto out;
+ }
+ did = ndlp->nlp_DID;
/*
* set the active bit even if there is no mem available.
*/
adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
- if (!ndlp)
- return -EINVAL;
+
+ if (NLP_CHK_FREE_REQ(ndlp))
+ goto out;
+
+ if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
+ goto out;
+
if (test_and_set_bit(adj_xri, ndlp->active_rrqs.xri_bitmap))
- return -EINVAL;
+ goto out;
+
rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
if (rrq) {
rrq->send_rrq = send_rrq;
@@ -553,14 +574,7 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
rrq->vport = ndlp->vport;
rrq->rxid = rxid;
empty = list_empty(&phba->active_rrq_list);
- if (phba->cfg_enable_rrq && send_rrq)
- /*
- * We need the xri before we can add this to the
- * phba active rrq list.
- */
- rrq->send_rrq = send_rrq;
- else
- rrq->send_rrq = 0;
+ rrq->send_rrq = send_rrq;
list_add_tail(&rrq->list, &phba->active_rrq_list);
if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) {
phba->hba_flag |= HBA_RRQ_ACTIVE;
@@ -569,40 +583,49 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
}
return 0;
}
- return -ENOMEM;
+out:
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2921 Can't set rrq active xri:0x%x rxid:0x%x"
+ " DID:0x%x Send:%d\n",
+ xritag, rxid, did, send_rrq);
+ return -EINVAL;
}
/**
- * __lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
+ * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
* @phba: Pointer to HBA context object.
* @xritag: xri used in this exchange.
* @rrq: The RRQ to be cleared.
*
- * This function is called with hbalock held. This function
**/
-static void
-__lpfc_clr_rrq_active(struct lpfc_hba *phba,
- uint16_t xritag,
- struct lpfc_node_rrq *rrq)
+void
+lpfc_clr_rrq_active(struct lpfc_hba *phba,
+ uint16_t xritag,
+ struct lpfc_node_rrq *rrq)
{
uint16_t adj_xri;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_nodelist *ndlp = NULL;
- ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID);
+ if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp))
+ ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID);
/* The target DID could have been swapped (cable swap)
* we should use the ndlp from the findnode if it is
* available.
*/
- if (!ndlp)
+ if ((!ndlp) && rrq->ndlp)
ndlp = rrq->ndlp;
+ if (!ndlp)
+ goto out;
+
adj_xri = xritag - phba->sli4_hba.max_cfg_param.xri_base;
if (test_and_clear_bit(adj_xri, ndlp->active_rrqs.xri_bitmap)) {
rrq->send_rrq = 0;
rrq->xritag = 0;
rrq->rrq_stop_time = 0;
}
+out:
mempool_free(rrq, phba->rrq_pool);
}
@@ -627,34 +650,34 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba)
struct lpfc_node_rrq *nextrrq;
unsigned long next_time;
unsigned long iflags;
+ LIST_HEAD(send_rrq);
spin_lock_irqsave(&phba->hbalock, iflags);
phba->hba_flag &= ~HBA_RRQ_ACTIVE;
next_time = jiffies + HZ * (phba->fc_ratov + 1);
list_for_each_entry_safe(rrq, nextrrq,
- &phba->active_rrq_list, list) {
- if (time_after(jiffies, rrq->rrq_stop_time)) {
- list_del(&rrq->list);
- if (!rrq->send_rrq)
- /* this call will free the rrq */
- __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
- else {
- /* if we send the rrq then the completion handler
- * will clear the bit in the xribitmap.
- */
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- if (lpfc_send_rrq(phba, rrq)) {
- lpfc_clr_rrq_active(phba, rrq->xritag,
- rrq);
- }
- spin_lock_irqsave(&phba->hbalock, iflags);
- }
- } else if (time_before(rrq->rrq_stop_time, next_time))
+ &phba->active_rrq_list, list) {
+ if (time_after(jiffies, rrq->rrq_stop_time))
+ list_move(&rrq->list, &send_rrq);
+ else if (time_before(rrq->rrq_stop_time, next_time))
next_time = rrq->rrq_stop_time;
}
spin_unlock_irqrestore(&phba->hbalock, iflags);
if (!list_empty(&phba->active_rrq_list))
mod_timer(&phba->rrq_tmr, next_time);
+ list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) {
+ list_del(&rrq->list);
+ if (!rrq->send_rrq)
+ /* this call will free the rrq */
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ else if (lpfc_send_rrq(phba, rrq)) {
+ /* if we send the rrq then the completion handler
+ * will clear the bit in the xribitmap.
+ */
+ lpfc_clr_rrq_active(phba, rrq->xritag,
+ rrq);
+ }
+ }
}
/**
@@ -692,29 +715,37 @@ lpfc_get_active_rrq(struct lpfc_vport *vport, uint16_t xri, uint32_t did)
/**
* lpfc_cleanup_vports_rrqs - Remove and clear the active RRQ for this vport.
* @vport: Pointer to vport context object.
- *
- * Remove all active RRQs for this vport from the phba->active_rrq_list and
- * clear the rrq.
+ * @ndlp: Pointer to the lpfc_node_list structure.
+ * If ndlp is NULL Remove all active RRQs for this vport from the
+ * phba->active_rrq_list and clear the rrq.
+ * If ndlp is not NULL then only remove rrqs for this vport & this ndlp.
**/
void
-lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport)
+lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_node_rrq *rrq;
struct lpfc_node_rrq *nextrrq;
unsigned long iflags;
+ LIST_HEAD(rrq_list);
if (phba->sli_rev != LPFC_SLI_REV4)
return;
- spin_lock_irqsave(&phba->hbalock, iflags);
- list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
- if (rrq->vport == vport) {
- list_del(&rrq->list);
- __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
- }
+ if (!ndlp) {
+ lpfc_sli4_vport_delete_els_xri_aborted(vport);
+ lpfc_sli4_vport_delete_fcp_xri_aborted(vport);
}
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list)
+ if ((rrq->vport == vport) && (!ndlp || rrq->ndlp == ndlp))
+ list_move(&rrq->list, &rrq_list);
spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) {
+ list_del(&rrq->list);
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ }
}
/**
@@ -732,24 +763,27 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
struct lpfc_node_rrq *nextrrq;
unsigned long next_time;
unsigned long iflags;
+ LIST_HEAD(rrq_list);
if (phba->sli_rev != LPFC_SLI_REV4)
return;
spin_lock_irqsave(&phba->hbalock, iflags);
phba->hba_flag &= ~HBA_RRQ_ACTIVE;
next_time = jiffies + HZ * (phba->fc_ratov * 2);
- list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) {
+ list_splice_init(&phba->active_rrq_list, &rrq_list);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) {
list_del(&rrq->list);
- __lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
}
- spin_unlock_irqrestore(&phba->hbalock, iflags);
if (!list_empty(&phba->active_rrq_list))
mod_timer(&phba->rrq_tmr, next_time);
}
/**
- * __lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
+ * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
* @phba: Pointer to HBA context object.
* @ndlp: Targets nodelist pointer for this exchange.
* @xritag the xri in the bitmap to test.
@@ -758,8 +792,8 @@ lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba)
* returns 0 = rrq not active for this xri
* 1 = rrq is valid for this xri.
**/
-static int
-__lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+int
+lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
uint16_t xritag)
{
uint16_t adj_xri;
@@ -802,52 +836,6 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
}
/**
- * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
- * @phba: Pointer to HBA context object.
- * @xritag: xri used in this exchange.
- * @rrq: The RRQ to be cleared.
- *
- * This function is takes the hbalock.
- **/
-void
-lpfc_clr_rrq_active(struct lpfc_hba *phba,
- uint16_t xritag,
- struct lpfc_node_rrq *rrq)
-{
- unsigned long iflags;
-
- spin_lock_irqsave(&phba->hbalock, iflags);
- __lpfc_clr_rrq_active(phba, xritag, rrq);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- return;
-}
-
-
-
-/**
- * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap.
- * @phba: Pointer to HBA context object.
- * @ndlp: Targets nodelist pointer for this exchange.
- * @xritag the xri in the bitmap to test.
- *
- * This function takes the hbalock.
- * returns 0 = rrq not active for this xri
- * 1 = rrq is valid for this xri.
- **/
-int
-lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
- uint16_t xritag)
-{
- int ret;
- unsigned long iflags;
-
- spin_lock_irqsave(&phba->hbalock, iflags);
- ret = __lpfc_test_rrq_active(phba, ndlp, xritag);
- spin_unlock_irqrestore(&phba->hbalock, iflags);
- return ret;
-}
-
-/**
* __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool
* @phba: Pointer to HBA context object.
* @piocb: Pointer to the iocbq.
@@ -884,7 +872,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
return NULL;
adj_xri = sglq->sli4_xritag -
phba->sli4_hba.max_cfg_param.xri_base;
- if (__lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
+ if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) {
/* This xri has an rrq outstanding for this DID.
* put it back in the list and get another xri.
*/
@@ -969,7 +957,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
} else {
sglq->state = SGL_FREED;
sglq->ndlp = NULL;
- list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+ list_add_tail(&sglq->list,
+ &phba->sli4_hba.lpfc_sgl_list);
/* Check if TXQ queue needs to be serviced */
if (pring->txq_cnt)
@@ -4817,7 +4806,10 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"0378 No support for fcpi mode.\n");
ftr_rsp++;
}
-
+ if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
+ phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
+ else
+ phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
/*
* If the port cannot support the host's requested features
* then turn off the global config parameters to disable the
@@ -5004,7 +4996,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
phba->link_state = LPFC_LINK_DOWN;
spin_unlock_irq(&phba->hbalock);
- rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
+ if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK)
+ rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
out_unset_queue:
/* Unset all the queues set up in this routine when error out */
if (rc)
@@ -10478,6 +10471,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
cq->type = type;
cq->subtype = subtype;
cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
+ cq->assoc_qid = eq->queue_id;
cq->host_index = 0;
cq->hba_index = 0;
@@ -10672,6 +10666,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
goto out;
}
mq->type = LPFC_MQ;
+ mq->assoc_qid = cq->queue_id;
mq->subtype = subtype;
mq->host_index = 0;
mq->hba_index = 0;
@@ -10759,6 +10754,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
goto out;
}
wq->type = LPFC_WQ;
+ wq->assoc_qid = cq->queue_id;
wq->subtype = subtype;
wq->host_index = 0;
wq->hba_index = 0;
@@ -10876,6 +10872,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
goto out;
}
hrq->type = LPFC_HRQ;
+ hrq->assoc_qid = cq->queue_id;
hrq->subtype = subtype;
hrq->host_index = 0;
hrq->hba_index = 0;
@@ -10936,6 +10933,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
goto out;
}
drq->type = LPFC_DRQ;
+ drq->assoc_qid = cq->queue_id;
drq->subtype = subtype;
drq->host_index = 0;
drq->hba_index = 0;
@@ -11189,7 +11187,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
if (!mbox)
return -ENOMEM;
length = (sizeof(struct lpfc_mbx_rq_destroy) -
- sizeof(struct mbox_header));
+ sizeof(struct lpfc_sli4_cfg_mhdr));
lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY,
length, LPFC_SLI4_MBX_EMBED);
@@ -11279,7 +11277,7 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES,
sizeof(struct lpfc_mbx_post_sgl_pages) -
- sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+ sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED);
post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *)
&mbox->u.mqe.un.post_sgl_pages;
@@ -12402,7 +12400,8 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE,
LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE,
sizeof(struct lpfc_mbx_post_hdr_tmpl) -
- sizeof(struct mbox_header), LPFC_SLI4_MBX_EMBED);
+ sizeof(struct lpfc_sli4_cfg_mhdr),
+ LPFC_SLI4_MBX_EMBED);
bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt,
hdr_tmpl, rpi_page->page_count);
bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl,
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index c7217d579e0f..595056b89608 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -125,9 +125,9 @@ struct lpfc_queue {
uint32_t entry_count; /* Number of entries to support on the queue */
uint32_t entry_size; /* Size of each queue entry. */
uint32_t queue_id; /* Queue ID assigned by the hardware */
+ uint32_t assoc_qid; /* Queue ID associated with, for CQ/WQ/MQ */
struct list_head page_list;
uint32_t page_count; /* Number of pages allocated for this queue */
-
uint32_t host_index; /* The host's index for putting or getting */
uint32_t hba_index; /* The last known hba index for get or put */
union sli4_qe qe[1]; /* array to index entries (must be last) */
@@ -359,6 +359,10 @@ struct lpfc_pc_sli4_params {
uint32_t hdr_pp_align;
uint32_t sgl_pages_max;
uint32_t sgl_pp_align;
+ uint8_t cqv;
+ uint8_t mqv;
+ uint8_t wqv;
+ uint8_t rqv;
};
/* SLI4 HBA data structure entries */
@@ -562,6 +566,8 @@ void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *,
struct sli4_wcqe_xri_aborted *);
void lpfc_sli4_els_xri_aborted(struct lpfc_hba *,
struct sli4_wcqe_xri_aborted *);
+void lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *);
+void lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *);
int lpfc_sli4_brdreset(struct lpfc_hba *);
int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *);
void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 386cf92de492..0a4d376dbca5 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2010 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2011 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.20"
+#define LPFC_DRIVER_VERSION "8.3.21"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 6b8d2952e32f..30ba5440c67a 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -464,6 +464,7 @@ disable_vport(struct fc_vport *fc_vport)
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
long timeout;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (ndlp && NLP_CHK_NODE_ACT(ndlp)
@@ -498,6 +499,9 @@ disable_vport(struct fc_vport *fc_vport)
* scsi_host_put() to release the vport.
*/
lpfc_mbx_unreg_vpi(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+ spin_unlock_irq(shost->host_lock);
lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 9aa048525eb2..c212694a9714 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1412,7 +1412,7 @@ megaraid_isr_memmapped(int irq, void *devp)
* @nstatus - number of completed commands
* @status - status of the last command completed
*
- * Complete the comamnds and call the scsi mid-layer callback hooks.
+ * Complete the commands and call the scsi mid-layer callback hooks.
*/
static void
mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
@@ -4296,7 +4296,7 @@ mega_support_cluster(adapter_t *adapter)
* @adapter - pointer to our soft state
* @dma_handle - DMA address of the buffer
*
- * Issue internal comamnds while interrupts are available.
+ * Issue internal commands while interrupts are available.
* We only issue direct mailbox commands from within the driver. ioctl()
* interface using these routines can issue passthru commands.
*/
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 1b5e375732c0..635b228c3ead 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -33,9 +33,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.05.29-rc1"
-#define MEGASAS_RELDATE "Dec. 7, 2010"
-#define MEGASAS_EXT_VERSION "Tue. Dec. 7 17:00:00 PDT 2010"
+#define MEGASAS_VERSION "00.00.05.34-rc1"
+#define MEGASAS_RELDATE "Feb. 24, 2011"
+#define MEGASAS_EXT_VERSION "Thu. Feb. 24 17:00:00 PDT 2011"
/*
* Device IDs
@@ -723,6 +723,7 @@ struct megasas_ctrl_info {
MEGASAS_MAX_DEV_PER_CHANNEL)
#define MEGASAS_MAX_SECTORS (2*1024)
+#define MEGASAS_MAX_SECTORS_IEEE (2*128)
#define MEGASAS_DBG_LVL 1
#define MEGASAS_FW_BUSY 1
@@ -1477,4 +1478,7 @@ struct megasas_mgmt_info {
int max_index;
};
+#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
+#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
+
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 5d6d07bd1cd0..bbd10c81fd9c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -18,12 +18,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* FILE: megaraid_sas_base.c
- * Version : v00.00.05.29-rc1
+ * Version : v00.00.05.34-rc1
*
* Authors: LSI Corporation
* Sreenivas Bagalkote
* Sumant Patro
* Bo Yang
+ * Adam Radford <linuxraid@lsi.com>
*
* Send feedback to: <megaraidlinux@lsi.com>
*
@@ -134,7 +135,11 @@ spinlock_t poll_aen_lock;
void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
-
+static u32
+megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs);
+static int
+megasas_adp_reset_gen2(struct megasas_instance *instance,
+ struct megasas_register_set __iomem *reg_set);
static irqreturn_t megasas_isr(int irq, void *devp);
static u32
megasas_init_adapter_mfi(struct megasas_instance *instance);
@@ -554,6 +559,8 @@ static int
megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
{
u32 status;
+ u32 mfiStatus = 0;
+
/*
* Check if it is our interrupt
*/
@@ -564,6 +571,15 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
}
/*
+ * Check if it is our interrupt
+ */
+ if ((megasas_read_fw_status_reg_gen2(regs) & MFI_STATE_MASK) ==
+ MFI_STATE_FAULT) {
+ mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
+ } else
+ mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+
+ /*
* Clear the interrupt by writing back the same value
*/
writel(status, &regs->outbound_intr_status);
@@ -573,7 +589,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
*/
readl(&regs->outbound_intr_status);
- return 1;
+ return mfiStatus;
}
/**
@@ -597,17 +613,6 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
}
/**
- * megasas_adp_reset_skinny - For controller reset
- * @regs: MFI register set
- */
-static int
-megasas_adp_reset_skinny(struct megasas_instance *instance,
- struct megasas_register_set __iomem *regs)
-{
- return 0;
-}
-
-/**
* megasas_check_reset_skinny - For controller reset check
* @regs: MFI register set
*/
@@ -625,7 +630,7 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
.disable_intr = megasas_disable_intr_skinny,
.clear_intr = megasas_clear_intr_skinny,
.read_fw_status_reg = megasas_read_fw_status_reg_skinny,
- .adp_reset = megasas_adp_reset_skinny,
+ .adp_reset = megasas_adp_reset_gen2,
.check_reset = megasas_check_reset_skinny,
.service_isr = megasas_isr,
.tasklet = megasas_complete_cmd_dpc,
@@ -740,20 +745,28 @@ megasas_adp_reset_gen2(struct megasas_instance *instance,
{
u32 retry = 0 ;
u32 HostDiag;
+ u32 *seq_offset = &reg_set->seq_offset;
+ u32 *hostdiag_offset = &reg_set->host_diag;
+
+ if (instance->instancet == &megasas_instance_template_skinny) {
+ seq_offset = &reg_set->fusion_seq_offset;
+ hostdiag_offset = &reg_set->fusion_host_diag;
+ }
+
+ writel(0, seq_offset);
+ writel(4, seq_offset);
+ writel(0xb, seq_offset);
+ writel(2, seq_offset);
+ writel(7, seq_offset);
+ writel(0xd, seq_offset);
- writel(0, &reg_set->seq_offset);
- writel(4, &reg_set->seq_offset);
- writel(0xb, &reg_set->seq_offset);
- writel(2, &reg_set->seq_offset);
- writel(7, &reg_set->seq_offset);
- writel(0xd, &reg_set->seq_offset);
msleep(1000);
- HostDiag = (u32)readl(&reg_set->host_diag);
+ HostDiag = (u32)readl(hostdiag_offset);
while ( !( HostDiag & DIAG_WRITE_ENABLE) ) {
msleep(100);
- HostDiag = (u32)readl(&reg_set->host_diag);
+ HostDiag = (u32)readl(hostdiag_offset);
printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n",
retry, HostDiag);
@@ -764,14 +777,14 @@ megasas_adp_reset_gen2(struct megasas_instance *instance,
printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
- writel((HostDiag | DIAG_RESET_ADAPTER), &reg_set->host_diag);
+ writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset);
ssleep(10);
- HostDiag = (u32)readl(&reg_set->host_diag);
+ HostDiag = (u32)readl(hostdiag_offset);
while ( ( HostDiag & DIAG_RESET_ADAPTER) ) {
msleep(100);
- HostDiag = (u32)readl(&reg_set->host_diag);
+ HostDiag = (u32)readl(hostdiag_offset);
printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n",
retry, HostDiag);
@@ -877,7 +890,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
* @instance: Adapter soft state
* @cmd_to_abort: Previously issued cmd to be aborted
*
- * MFI firmware can abort previously issued AEN comamnd (automatic event
+ * MFI firmware can abort previously issued AEN command (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
* cmd and waits for return status.
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
@@ -2503,7 +2516,9 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
if ((mfiStatus = instance->instancet->clear_intr(
instance->reg_set)
) == 0) {
- return IRQ_NONE;
+ /* Hardware may not set outbound_intr_status in MSI-X mode */
+ if (!instance->msi_flag)
+ return IRQ_NONE;
}
instance->mfiStatus = mfiStatus;
@@ -2611,7 +2626,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
case MFI_STATE_FAULT:
printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
- return -ENODEV;
+ max_wait = MEGASAS_RESET_WAIT_TIME;
+ cur_state = MFI_STATE_FAULT;
+ break;
case MFI_STATE_WAIT_HANDSHAKE:
/*
@@ -3424,7 +3441,6 @@ fail_reply_queue:
megasas_free_cmds(instance);
fail_alloc_cmds:
- iounmap(instance->reg_set);
return 1;
}
@@ -3494,7 +3510,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
/* Get operational params, sge flags, send init cmd to controller */
if (instance->instancet->init_adapter(instance))
- return -ENODEV;
+ goto fail_init_adapter;
printk(KERN_ERR "megasas: INIT adapter done\n");
@@ -3543,7 +3559,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
* Setup tasklet for cmd completion
*/
- tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
/* Initialize the cmd completion timer */
@@ -3553,6 +3569,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
MEGASAS_COMPLETION_TIMER_INTERVAL);
return 0;
+fail_init_adapter:
fail_ready_state:
iounmap(instance->reg_set);
@@ -3820,6 +3837,10 @@ static int megasas_io_attach(struct megasas_instance *instance)
instance->max_fw_cmds - MEGASAS_INT_CMDS;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
+
+ if (instance->fw_support_ieee)
+ instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE;
+
/*
* Check if the module parameter value for max_sectors can be used
*/
@@ -3899,9 +3920,26 @@ fail_set_dma_mask:
static int __devinit
megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- int rval;
+ int rval, pos;
struct Scsi_Host *host;
struct megasas_instance *instance;
+ u16 control = 0;
+
+ /* Reset MSI-X in the kdump kernel */
+ if (reset_devices) {
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(pdev, msi_control_reg(pos),
+ &control);
+ if (control & PCI_MSIX_FLAGS_ENABLE) {
+ dev_info(&pdev->dev, "resetting MSI-X\n");
+ pci_write_config_word(pdev,
+ msi_control_reg(pos),
+ control &
+ ~PCI_MSIX_FLAGS_ENABLE);
+ }
+ }
+ }
/*
* Announce PCI information
@@ -4039,12 +4077,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
else
INIT_WORK(&instance->work_init, process_fw_state_change_wq);
- /*
- * Initialize MFI Firmware
- */
- if (megasas_init_fw(instance))
- goto fail_init_mfi;
-
/* Try to enable MSI-X */
if ((instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078R) &&
(instance->pdev->device != PCI_DEVICE_ID_LSI_SAS1078DE) &&
@@ -4054,6 +4086,12 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->msi_flag = 1;
/*
+ * Initialize MFI Firmware
+ */
+ if (megasas_init_fw(instance))
+ goto fail_init_mfi;
+
+ /*
* Register IRQ
*/
if (request_irq(instance->msi_flag ? instance->msixentry.vector :
@@ -4105,24 +4143,23 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->msi_flag ? instance->msixentry.vector :
instance->pdev->irq, instance);
+fail_irq:
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION)
+ megasas_release_fusion(instance);
+ else
+ megasas_release_mfi(instance);
+ fail_init_mfi:
if (instance->msi_flag)
pci_disable_msix(instance->pdev);
-
- fail_irq:
- fail_init_mfi:
fail_alloc_dma_buf:
if (instance->evt_detail)
pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
instance->evt_detail,
instance->evt_detail_h);
- if (instance->producer) {
+ if (instance->producer)
pci_free_consistent(pdev, sizeof(u32), instance->producer,
instance->producer_h);
- megasas_release_mfi(instance);
- } else {
- megasas_release_fusion(instance);
- }
if (instance->consumer)
pci_free_consistent(pdev, sizeof(u32), instance->consumer,
instance->consumer_h);
@@ -4242,9 +4279,8 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
/* cancel the delayed work if this work still in queue */
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work(
+ cancel_delayed_work_sync(
(struct delayed_work *)&ev->hotplug_work);
- flush_scheduled_work();
instance->ev = NULL;
}
@@ -4297,6 +4333,10 @@ megasas_resume(struct pci_dev *pdev)
if (megasas_set_dma_mask(pdev))
goto fail_set_dma_mask;
+ /* Now re-enable MSI-X */
+ if (instance->msi_flag)
+ pci_enable_msix(instance->pdev, &instance->msixentry, 1);
+
/*
* Initialize MFI Firmware
*/
@@ -4333,10 +4373,6 @@ megasas_resume(struct pci_dev *pdev)
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance);
- /* Now re-enable MSI-X */
- if (instance->msi_flag)
- pci_enable_msix(instance->pdev, &instance->msixentry, 1);
-
/*
* Register IRQ
*/
@@ -4417,9 +4453,8 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
/* cancel the delayed work if this work still in queue*/
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work(
+ cancel_delayed_work_sync(
(struct delayed_work *)&ev->hotplug_work);
- flush_scheduled_work();
instance->ev = NULL;
}
@@ -4611,6 +4646,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* For each user buffer, create a mirror buffer and copy in
*/
for (i = 0; i < ioc->sge_count; i++) {
+ if (!ioc->sgl[i].iov_len)
+ continue;
+
kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
ioc->sgl[i].iov_len,
&buf_handle, GFP_KERNEL);
@@ -5177,6 +5215,7 @@ megasas_aen_polling(struct work_struct *work)
break;
case MR_EVT_LD_OFFLINE:
+ case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
megasas_get_ld_list(instance);
for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index d6e2a663b165..145a8cffb1fa 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -81,6 +81,10 @@ u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+
+void
+megasas_check_and_restore_queue_depth(struct megasas_instance *instance);
+
u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map,
struct LD_LOAD_BALANCE_INFO *lbInfo);
u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
@@ -983,13 +987,15 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
return 0;
-fail_alloc_cmds:
-fail_alloc_mfi_cmds:
fail_map_info:
if (i == 1)
dma_free_coherent(&instance->pdev->dev, fusion->map_sz,
fusion->ld_map[0], fusion->ld_map_phys[0]);
fail_ioc_init:
+ megasas_free_cmds_fusion(instance);
+fail_alloc_cmds:
+ megasas_free_cmds(instance);
+fail_alloc_mfi_cmds:
return 1;
}
@@ -1431,8 +1437,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
/* Check if this is a system PD I/O */
- if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
- (instance->pd_list[pd_index].driveType == TYPE_DISK)) {
+ if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
io_request->Function = 0;
io_request->DevHandle =
local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
@@ -1455,7 +1460,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
}
io_request->RaidContext.VirtualDiskTgtId = device_id;
- io_request->LUN[0] = scmd->device->lun;
+ io_request->LUN[1] = scmd->device->lun;
io_request->DataLength = scsi_bufflen(scmd);
}
@@ -1479,7 +1484,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
device_id = MEGASAS_DEV_INDEX(instance, scp);
/* Zero out some fields so they don't get reused */
- io_request->LUN[0] = 0;
+ io_request->LUN[1] = 0;
io_request->CDB.EEDP32.PrimaryReferenceTag = 0;
io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0;
io_request->EEDPFlags = 0;
@@ -1743,7 +1748,7 @@ complete_cmd_fusion(struct megasas_instance *instance)
wmb();
writel(fusion->last_reply_idx,
&instance->reg_set->reply_post_host_index);
-
+ megasas_check_and_restore_queue_depth(instance);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 8be75e65f763..a3e60385787f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.16
+ * mpi2.h Version: 02.00.17
*
* Version History
* ---------------
@@ -63,6 +63,7 @@
* function codes, 0xF0 to 0xFF.
* 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
* Added alternative defines for the SGE Direction bit.
+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -88,7 +89,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x10)
+#define MPI2_HEADER_VERSION_UNIT (0x11)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index d76a65847603..f5b9c766e28f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.15
+ * mpi2_cnfg.h Version: 02.00.16
*
* Version History
* ---------------
@@ -125,6 +125,8 @@
* define.
* Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
* Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
+ * defines.
* --------------------------------------------------------------------------
*/
@@ -745,8 +747,6 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040)
#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004)
-#define MPI2_IOUNITPAGE1_MULTI_PATHING (0x00000002)
-#define MPI2_IOUNITPAGE1_SINGLE_PATHING (0x00000000)
/* IO Unit Page 3 */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
deleted file mode 100644
index b1e88f26b748..000000000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
+++ /dev/null
@@ -1,384 +0,0 @@
- ==============================
- Fusion-MPT MPI 2.0 Header File Change History
- ==============================
-
- Copyright (c) 2000-2010 LSI Corporation.
-
- ---------------------------------------
- Header Set Release Version: 02.00.14
- Header Set Release Date: 10-28-09
- ---------------------------------------
-
- Filename Current version Prior version
- ---------- --------------- -------------
- mpi2.h 02.00.14 02.00.13
- mpi2_cnfg.h 02.00.13 02.00.12
- mpi2_init.h 02.00.08 02.00.07
- mpi2_ioc.h 02.00.13 02.00.12
- mpi2_raid.h 02.00.04 02.00.04
- mpi2_sas.h 02.00.03 02.00.02
- mpi2_targ.h 02.00.03 02.00.03
- mpi2_tool.h 02.00.04 02.00.04
- mpi2_type.h 02.00.00 02.00.00
- mpi2_ra.h 02.00.00 02.00.00
- mpi2_hbd.h 02.00.00
- mpi2_history.txt 02.00.14 02.00.13
-
-
- * Date Version Description
- * -------- -------- ------------------------------------------------------
-
-mpi2.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT.
- * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT.
- * Moved ReplyPostHostIndex register to offset 0x6C of the
- * MPI2_SYSTEM_INTERFACE_REGS and modified the define for
- * MPI2_REPLY_POST_HOST_INDEX_OFFSET.
- * Added union of request descriptors.
- * Added union of reply descriptors.
- * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added define for MPI2_VERSION_02_00.
- * Fixed the size of the FunctionDependent5 field in the
- * MPI2_DEFAULT_REPLY structure.
- * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT.
- * Removed the MPI-defined Fault Codes and extended the
- * product specific codes up to 0xEFFF.
- * Added a sixth key value for the WriteSequence register
- * and changed the flush value to 0x0.
- * Added message function codes for Diagnostic Buffer Post
- * and Diagnsotic Release.
- * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
- * Moved MPI2_VERSION_UNION from mpi2_ioc.h.
- * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT.
- * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added #defines for marking a reply descriptor as unused.
- * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT.
- * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
- * Moved LUN field defines from mpi2_init.h.
- * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
- * In all request and reply descriptors, replaced VF_ID
- * field with MSIxIndex field.
- * Removed DevHandle field from
- * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
- * bytes reserved.
- * Added RAID Accelerator functionality.
- * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
- * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MSI-x index mask and shift for Reply Post Host
- * Index register.
- * Added function code for Host Based Discovery Action.
- * --------------------------------------------------------------------------
-
-mpi2_cnfg.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags.
- * Added Manufacturing Page 11.
- * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
- * define.
- * 06-26-07 02.00.02 Adding generic structure for product-specific
- * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
- * Rework of BIOS Page 2 configuration page.
- * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
- * forms.
- * Added configuration pages IOC Page 8 and Driver
- * Persistent Mapping Page 0.
- * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated
- * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
- * RAID Physical Disk Pages 0 and 1, RAID Configuration
- * Page 0).
- * Added new value for AccessStatus field of SAS Device
- * Page 0 (_SATA_NEEDS_INITIALIZATION).
- * 10-31-07 02.00.04 Added missing SEPDevHandle field to
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for
- * NVDATA.
- * Modified IOC Page 7 to use masks and added field for
- * SASBroadcastPrimitiveMasks.
- * Added MPI2_CONFIG_PAGE_BIOS_4.
- * Added MPI2_CONFIG_PAGE_LOG_0.
- * 02-29-08 02.00.06 Modified various names to make them 32-character unique.
- * Added SAS Device IDs.
- * Updated Integrated RAID configuration pages including
- * Manufacturing Page 4, IOC Page 6, and RAID Configuration
- * Page 0.
- * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
- * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
- * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
- * Added missing MaxNumRoutedSasAddresses field to
- * MPI2_CONFIG_PAGE_EXPANDER_0.
- * Added SAS Port Page 0.
- * Modified structure layout for
- * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
- * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
- * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
- * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
- * to 0x000000FF.
- * Added two new values for the Physical Disk Coercion Size
- * bits in the Flags field of Manufacturing Page 4.
- * Added product-specific Manufacturing pages 16 to 31.
- * Modified Flags bits for controlling write cache on SATA
- * drives in IO Unit Page 1.
- * Added new bit to AdditionalControlFlags of SAS IO Unit
- * Page 1 to control Invalid Topology Correction.
- * Added SupportedPhysDisks field to RAID Volume Page 1 and
- * added related defines.
- * Added additional defines for RAID Volume Page 0
- * VolumeStatusFlags field.
- * Modified meaning of RAID Volume Page 0 VolumeSettings
- * define for auto-configure of hot-swap drives.
- * Added PhysDiskAttributes field (and related defines) to
- * RAID Physical Disk Page 0.
- * Added MPI2_SAS_PHYINFO_PHY_VACANT define.
- * Added three new DiscoveryStatus bits for SAS IO Unit
- * Page 0 and SAS Expander Page 0.
- * Removed multiplexing information from SAS IO Unit pages.
- * Added BootDeviceWaitTime field to SAS IO Unit Page 4.
- * Removed Zone Address Resolved bit from PhyInfo and from
- * Expander Page 0 Flags field.
- * Added two new AccessStatus values to SAS Device Page 0
- * for indicating routing problems. Added 3 reserved words
- * to this page.
- * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3.
- * Inserted missing reserved field into structure for IOC
- * Page 6.
- * Added more pending task bits to RAID Volume Page 0
- * VolumeStatusFlags defines.
- * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
- * Added a new DiscoveryStatus bit for SAS IO Unit Page 0
- * and SAS Expander Page 0 to flag a downstream initiator
- * when in simplified routing mode.
- * Removed SATA Init Failure defines for DiscoveryStatus
- * fields of SAS IO Unit Page 0 and SAS Expander Page 0.
- * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
- * Added PortGroups, DmaGroup, and ControlGroup fields to
- * SAS Device Page 0.
- * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
- * Unit Page 6.
- * Added expander reduced functionality data to SAS
- * Expander Page 0.
- * Added SAS PHY Page 2 and SAS PHY Page 3.
- * 07-30-09 02.00.12 Added IO Unit Page 7.
- * Added new device ids.
- * Added SAS IO Unit Page 5.
- * Added partial and slumber power management capable flags
- * to SAS Device Page 0 Flags field.
- * Added PhyInfo defines for power condition.
- * Added Ethernet configuration pages.
- * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
- * Added SAS PHY Page 4 structure and defines.
- * --------------------------------------------------------------------------
-
-mpi2_init.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t.
- * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines.
- * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention.
- * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
- * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
- * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
- * Control field Task Attribute flags.
- * Moved LUN field defines to mpi2.h becasue they are
- * common to many structures.
- * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
- * Query Asynchronous Event.
- * Defined two new bits in the SlotStatus field of the SCSI
- * Enclosure Processor Request and Reply.
- * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
- * both SCSI IO Error Reply and SCSI Task Management Reply.
- * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
- * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
- * --------------------------------------------------------------------------
-
-mpi2_ioc.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to
- * MaxTargets.
- * Added TotalImageSize field to FWDownload Request.
- * Added reserved words to FWUpload Request.
- * 06-26-07 02.00.02 Added IR Configuration Change List Event.
- * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit
- * request and replaced it with
- * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
- * Replaced the MinReplyQueueDepth field of the IOCFacts
- * reply with MaxReplyDescriptorPostQueueDepth.
- * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
- * depth for the Reply Descriptor Post Queue.
- * Added SASAddress field to Initiator Device Table
- * Overflow Event data.
- * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
- * for SAS Initiator Device Status Change Event data.
- * Modified Reason Code defines for SAS Topology Change
- * List Event data, including adding a bit for PHY Vacant
- * status, and adding a mask for the Reason Code.
- * Added define for
- * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
- * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
- * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of
- * the IOCFacts Reply.
- * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
- * Moved MPI2_VERSION_UNION to mpi2.h.
- * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
- * instead of enables, and added SASBroadcastPrimitiveMasks
- * field.
- * Added Log Entry Added Event and related structure.
- * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
- * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
- * Added MaxVolumes and MaxPersistentEntries fields to
- * IOCFacts reply.
- * Added ProtocalFlags and IOCCapabilities fields to
- * MPI2_FW_IMAGE_HEADER.
- * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
- * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
- * a U16 (from a U32).
- * Removed extra 's' from EventMasks name.
- * 06-27-08 02.00.08 Fixed an offset in a comment.
- * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
- * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
- * renamed MinReplyFrameSize to ReplyFrameSize.
- * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
- * Added two new RAIDOperation values for Integrated RAID
- * Operations Status Event data.
- * Added four new IR Configuration Change List Event data
- * ReasonCode values.
- * Added two new ReasonCode defines for SAS Device Status
- * Change Event data.
- * Added three new DiscoveryStatus bits for the SAS
- * Discovery event data.
- * Added Multiplexing Status Change bit to the PhyStatus
- * field of the SAS Topology Change List event data.
- * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
- * BootFlags are now product-specific.
- * Added defines for the indivdual signature bytes
- * for MPI2_INIT_IMAGE_FOOTER.
- * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
- * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
- * define.
- * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
- * define.
- * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
- * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
- * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
- * Added two new reason codes for SAS Device Status Change
- * Event.
- * Added new event: SAS PHY Counter.
- * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
- * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
- * Added new product id family for 2208.
- * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
- * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
- * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
- * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
- * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
- * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
- * Added Host Based Discovery Phy Event data.
- * Added defines for ProductID Product field
- * (MPI2_FW_HEADER_PID_).
- * Modified values for SAS ProductID Family
- * (MPI2_FW_HEADER_PID_FAMILY_).
- * --------------------------------------------------------------------------
-
-mpi2_raid.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 08-31-07 02.00.01 Modifications to RAID Action request and reply,
- * including the Actions and ActionData.
- * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
- * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
- * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
- * can be sized by the build environment.
- * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
- * VolumeCreationFlags and marked the old one as obsolete.
- * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
- * --------------------------------------------------------------------------
-
-mpi2_sas.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit
- * Control Request.
- * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
- * Request.
- * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
- * to MPI2_SGE_IO_UNION since it supports chained SGLs.
- * 05-12-10 02.00.04 Modified some comments.
- * --------------------------------------------------------------------------
-
-mpi2_targ.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to
- * BufferPostFlags field of CommandBufferPostBase Request.
- * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
- * 10-02-08 02.00.03 Removed NextCmdBufferOffset from
- * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
- * Target Status Send Request only takes a single SGE for
- * response data.
- * --------------------------------------------------------------------------
-
-mpi2_tool.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
- * structures and defines.
- * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
- * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
- * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
- * and reply messages.
- * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
- * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
- * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
- * --------------------------------------------------------------------------
-
-mpi2_type.h
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * --------------------------------------------------------------------------
-
-mpi2_ra.h
- * 05-06-09 02.00.00 Initial version.
- * --------------------------------------------------------------------------
-
-mpi2_hbd.h
- * 10-28-09 02.00.00 Initial version.
- * --------------------------------------------------------------------------
-
-
-mpi2_history.txt Parts list history
-
-Filename 02.00.14 02.00.13 02.00.12
----------- -------- -------- --------
-mpi2.h 02.00.14 02.00.13 02.00.12
-mpi2_cnfg.h 02.00.13 02.00.12 02.00.11
-mpi2_init.h 02.00.08 02.00.07 02.00.07
-mpi2_ioc.h 02.00.13 02.00.12 02.00.11
-mpi2_raid.h 02.00.04 02.00.04 02.00.03
-mpi2_sas.h 02.00.03 02.00.02 02.00.02
-mpi2_targ.h 02.00.03 02.00.03 02.00.03
-mpi2_tool.h 02.00.04 02.00.04 02.00.03
-mpi2_type.h 02.00.00 02.00.00 02.00.00
-mpi2_ra.h 02.00.00 02.00.00 02.00.00
-mpi2_hbd.h 02.00.00
-
-Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
----------- -------- -------- -------- -------- -------- --------
-mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
-mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06
-mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03
-mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06
-mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02
-mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01
-mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02
-mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02
-mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
-
-Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
----------- -------- -------- -------- -------- -------- --------
-mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
-mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
-mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00
-mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
-mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
-mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00
-mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
-mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
-mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
index 608f6d6e6fca..fdffde1ebc0f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
@@ -6,7 +6,7 @@
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2_sas.h Version: 02.00.04
+ * mpi2_sas.h Version: 02.00.05
*
* Version History
* ---------------
@@ -21,6 +21,7 @@
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
* 05-12-10 02.00.04 Modified some comments.
+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
* --------------------------------------------------------------------------
*/
@@ -163,7 +164,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
U32 Reserved4; /* 0x14 */
U32 DataLength; /* 0x18 */
U8 CommandFIS[20]; /* 0x1C */
- MPI2_SGE_IO_UNION SGL; /* 0x20 */
+ MPI2_SGE_IO_UNION SGL; /* 0x30 */
} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
@@ -246,6 +247,8 @@ typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
+#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14)
+#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15)
#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
/* values for the PrimFlags field */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 5c6e3a67bb94..2a4bceda364b 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -6,7 +6,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.05
+ * mpi2_tool.h Version: 02.00.06
*
* Version History
* ---------------
@@ -23,6 +23,8 @@
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
* 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
+ * Post Request.
* --------------------------------------------------------------------------
*/
@@ -354,6 +356,10 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
/* count of the number of buffer types */
#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
+/* values for the Flags field */
+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002)
+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001)
+
/****************************************************************************
* Diagnostic Buffer Post reply
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 9ead0399808a..e8a6f1cf1e4b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -752,20 +752,19 @@ static u8
_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
int i;
- u8 cb_idx = 0xFF;
-
- if (smid >= ioc->hi_priority_smid) {
- if (smid < ioc->internal_smid) {
- i = smid - ioc->hi_priority_smid;
- cb_idx = ioc->hpr_lookup[i].cb_idx;
- } else if (smid <= ioc->hba_queue_depth) {
- i = smid - ioc->internal_smid;
- cb_idx = ioc->internal_lookup[i].cb_idx;
- }
- } else {
+ u8 cb_idx;
+
+ if (smid < ioc->hi_priority_smid) {
i = smid - 1;
cb_idx = ioc->scsi_lookup[i].cb_idx;
- }
+ } else if (smid < ioc->internal_smid) {
+ i = smid - ioc->hi_priority_smid;
+ cb_idx = ioc->hpr_lookup[i].cb_idx;
+ } else if (smid <= ioc->hba_queue_depth) {
+ i = smid - ioc->internal_smid;
+ cb_idx = ioc->internal_lookup[i].cb_idx;
+ } else
+ cb_idx = 0xFF;
return cb_idx;
}
@@ -1430,7 +1429,7 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
struct scsi_cmnd *scmd)
{
unsigned long flags;
- struct request_tracker *request;
+ struct scsiio_tracker *request;
u16 smid;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
@@ -1442,7 +1441,7 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
}
request = list_entry(ioc->free_list.next,
- struct request_tracker, tracker_list);
+ struct scsiio_tracker, tracker_list);
request->scmd = scmd;
request->cb_idx = cb_idx;
smid = request->smid;
@@ -1496,48 +1495,47 @@ mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
struct chain_tracker *chain_req, *next;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (smid >= ioc->hi_priority_smid) {
- if (smid < ioc->internal_smid) {
- /* hi-priority */
- i = smid - ioc->hi_priority_smid;
- ioc->hpr_lookup[i].cb_idx = 0xFF;
- list_add_tail(&ioc->hpr_lookup[i].tracker_list,
- &ioc->hpr_free_list);
- } else {
- /* internal queue */
- i = smid - ioc->internal_smid;
- ioc->internal_lookup[i].cb_idx = 0xFF;
- list_add_tail(&ioc->internal_lookup[i].tracker_list,
- &ioc->internal_free_list);
+ if (smid < ioc->hi_priority_smid) {
+ /* scsiio queue */
+ i = smid - 1;
+ if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
+ list_for_each_entry_safe(chain_req, next,
+ &ioc->scsi_lookup[i].chain_list, tracker_list) {
+ list_del_init(&chain_req->tracker_list);
+ list_add_tail(&chain_req->tracker_list,
+ &ioc->free_chain_list);
+ }
}
+ ioc->scsi_lookup[i].cb_idx = 0xFF;
+ ioc->scsi_lookup[i].scmd = NULL;
+ list_add_tail(&ioc->scsi_lookup[i].tracker_list,
+ &ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return;
- }
- /* scsiio queue */
- i = smid - 1;
- if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
- list_for_each_entry_safe(chain_req, next,
- &ioc->scsi_lookup[i].chain_list, tracker_list) {
- list_del_init(&chain_req->tracker_list);
- list_add_tail(&chain_req->tracker_list,
- &ioc->free_chain_list);
+ /*
+ * See _wait_for_commands_to_complete() call with regards
+ * to this code.
+ */
+ if (ioc->shost_recovery && ioc->pending_io_count) {
+ if (ioc->pending_io_count == 1)
+ wake_up(&ioc->reset_wq);
+ ioc->pending_io_count--;
}
+ return;
+ } else if (smid < ioc->internal_smid) {
+ /* hi-priority */
+ i = smid - ioc->hi_priority_smid;
+ ioc->hpr_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->hpr_lookup[i].tracker_list,
+ &ioc->hpr_free_list);
+ } else if (smid <= ioc->hba_queue_depth) {
+ /* internal queue */
+ i = smid - ioc->internal_smid;
+ ioc->internal_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->internal_lookup[i].tracker_list,
+ &ioc->internal_free_list);
}
- ioc->scsi_lookup[i].cb_idx = 0xFF;
- ioc->scsi_lookup[i].scmd = NULL;
- list_add_tail(&ioc->scsi_lookup[i].tracker_list,
- &ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- /*
- * See _wait_for_commands_to_complete() call with regards to this code.
- */
- if (ioc->shost_recovery && ioc->pending_io_count) {
- if (ioc->pending_io_count == 1)
- wake_up(&ioc->reset_wq);
- ioc->pending_io_count--;
- }
}
/**
@@ -1725,6 +1723,31 @@ _base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc)
}
/**
+ * _base_display_intel_branding - Display branding string
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc)
+{
+ if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_INTEL &&
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008) {
+
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RMS2LL080_SSDID:
+ printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS2LL040_SSDID:
+ printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL040_BRANDING);
+ break;
+ }
+ }
+}
+
+/**
* _base_display_ioc_capabilities - Disply IOC's capabilities.
* @ioc: per adapter object
*
@@ -1754,6 +1777,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
ioc->bios_pg3.BiosVersion & 0x000000FF);
_base_display_dell_branding(ioc);
+ _base_display_intel_branding(ioc);
printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
@@ -2252,9 +2276,9 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->name, (unsigned long long) ioc->request_dma));
total_sz += sz;
- sz = ioc->scsiio_depth * sizeof(struct request_tracker);
+ sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker);
ioc->scsi_lookup_pages = get_order(sz);
- ioc->scsi_lookup = (struct request_tracker *)__get_free_pages(
+ ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages(
GFP_KERNEL, ioc->scsi_lookup_pages);
if (!ioc->scsi_lookup) {
printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 283568c6fb04..a3f8aa9baea4 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,8 +69,8 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "07.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 07
+#define MPT2SAS_DRIVER_VERSION "08.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 08
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -101,7 +101,8 @@
#define MPT_NAME_LENGTH 32 /* generic length of strings */
#define MPT_STRING_LENGTH 64
-#define MPT_MAX_CALLBACKS 16
+#define MPT_MAX_CALLBACKS 16
+
#define CAN_SLEEP 1
#define NO_SLEEP 0
@@ -154,6 +155,20 @@
#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22
/*
+ * Intel HBA branding
+ */
+#define MPT2SAS_INTEL_RMS2LL080_BRANDING \
+ "Intel Integrated RAID Module RMS2LL080"
+#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
+ "Intel Integrated RAID Module RMS2LL040"
+
+/*
+ * Intel HBA SSDIDs
+ */
+#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
+#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
+
+/*
* per target private data
*/
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
@@ -431,14 +446,14 @@ struct chain_tracker {
};
/**
- * struct request_tracker - firmware request tracker
+ * struct scsiio_tracker - scsi mf request tracker
* @smid: system message id
* @scmd: scsi request pointer
* @cb_idx: callback index
* @chain_list: list of chains associated to this IO
* @tracker_list: list of free request (ioc->free_list)
*/
-struct request_tracker {
+struct scsiio_tracker {
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
@@ -447,6 +462,19 @@ struct request_tracker {
};
/**
+ * struct request_tracker - misc mf request tracker
+ * @smid: system message id
+ * @scmd: scsi request pointer
+ * @cb_idx: callback index
+ * @tracker_list: list of free request (ioc->free_list)
+ */
+struct request_tracker {
+ u16 smid;
+ u8 cb_idx;
+ struct list_head tracker_list;
+};
+
+/**
* struct _tr_list - target reset list
* @handle: device handle
* @state: state machine
@@ -709,7 +737,7 @@ struct MPT2SAS_ADAPTER {
u8 *request;
dma_addr_t request_dma;
u32 request_dma_sz;
- struct request_tracker *scsi_lookup;
+ struct scsiio_tracker *scsi_lookup;
ulong scsi_lookup_pages;
spinlock_t scsi_lookup_lock;
struct list_head free_list;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 5ded3db6e316..6ceb7759bfe5 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -6975,7 +6975,6 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
u32 device_state;
mpt2sas_base_stop_watchdog(ioc);
- flush_scheduled_work();
scsi_block_requests(shost);
device_state = pci_choose_state(pdev, state);
printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index b37c8a3c1bb0..86afb13f1e79 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1005,11 +1005,23 @@ int osd_req_read_sg(struct osd_request *or,
const struct osd_sg_entry *sglist, unsigned numentries)
{
u64 len;
- int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len);
+ u64 off;
+ int ret;
- if (ret)
- return ret;
- osd_req_read(or, obj, 0, bio, len);
+ if (numentries > 1) {
+ off = 0;
+ ret = _add_sg_continuation_descriptor(or, sglist, numentries,
+ &len);
+ if (ret)
+ return ret;
+ } else {
+ /* Optimize the case of single segment, read_sg is a
+ * bidi operation.
+ */
+ len = sglist->len;
+ off = sglist->offset;
+ }
+ osd_req_read(or, obj, off, bio, len);
return 0;
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 54de1d1af1a7..521e2182d45b 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -1484,7 +1484,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst
int dbg = debugging;
#endif
- if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
+ if ((buffer = vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
return (-EIO);
printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
@@ -2296,7 +2296,7 @@ static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRp
if (STp->raw) return 0;
if (STp->header_cache == NULL) {
- if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+ if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
return (-ENOMEM);
}
@@ -2484,7 +2484,7 @@ static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request **
name, ppos, update_frame_cntr);
#endif
if (STp->header_cache == NULL) {
- if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+ if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
return 0;
}
@@ -5851,9 +5851,7 @@ static int osst_probe(struct device *dev)
/* if this is the first attach, build the infrastructure */
write_lock(&os_scsi_tapes_lock);
if (os_scsi_tapes == NULL) {
- os_scsi_tapes =
- (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
- GFP_ATOMIC);
+ os_scsi_tapes = kmalloc(osst_max_dev * sizeof(struct osst_tape *), GFP_ATOMIC);
if (os_scsi_tapes == NULL) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index d8db0137c0c7..18b6c55cd08c 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -1382,53 +1382,50 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
return MPI_IO_STATUS_BUSY;
}
-static void pm8001_work_queue(struct work_struct *work)
+static void pm8001_work_fn(struct work_struct *work)
{
- struct delayed_work *dw = container_of(work, struct delayed_work, work);
- struct pm8001_wq *wq = container_of(dw, struct pm8001_wq, work_q);
+ struct pm8001_work *pw = container_of(work, struct pm8001_work, work);
struct pm8001_device *pm8001_dev;
- struct domain_device *dev;
+ struct domain_device *dev;
- switch (wq->handler) {
+ switch (pw->handler) {
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
- pm8001_dev = wq->data;
+ pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
- pm8001_dev = wq->data;
+ pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_DS_IN_ERROR:
- pm8001_dev = wq->data;
+ pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
case IO_DS_NON_OPERATIONAL:
- pm8001_dev = wq->data;
+ pm8001_dev = pw->data;
dev = pm8001_dev->sas_device;
pm8001_I_T_nexus_reset(dev);
break;
}
- list_del(&wq->entry);
- kfree(wq);
+ kfree(pw);
}
static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
int handler)
{
- struct pm8001_wq *wq;
+ struct pm8001_work *pw;
int ret = 0;
- wq = kmalloc(sizeof(struct pm8001_wq), GFP_ATOMIC);
- if (wq) {
- wq->pm8001_ha = pm8001_ha;
- wq->data = data;
- wq->handler = handler;
- INIT_DELAYED_WORK(&wq->work_q, pm8001_work_queue);
- list_add_tail(&wq->entry, &pm8001_ha->wq_list);
- schedule_delayed_work(&wq->work_q, 0);
+ pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC);
+ if (pw) {
+ pw->pm8001_ha = pm8001_ha;
+ pw->data = data;
+ pw->handler = handler;
+ INIT_WORK(&pw->work, pm8001_work_fn);
+ queue_work(pm8001_wq, &pw->work);
} else
ret = -ENOMEM;
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index b95285f3383f..002360da01e3 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -51,6 +51,8 @@ static int pm8001_id;
LIST_HEAD(hba_list);
+struct workqueue_struct *pm8001_wq;
+
/**
* The main structure which LLDD must register for scsi core.
*/
@@ -134,7 +136,6 @@ static void __devinit pm8001_phy_init(struct pm8001_hba_info *pm8001_ha,
static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
{
int i;
- struct pm8001_wq *wq;
if (!pm8001_ha)
return;
@@ -150,8 +151,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha)
PM8001_CHIP_DISP->chip_iounmap(pm8001_ha);
if (pm8001_ha->shost)
scsi_host_put(pm8001_ha->shost);
- list_for_each_entry(wq, &pm8001_ha->wq_list, entry)
- cancel_delayed_work(&wq->work_q);
+ flush_workqueue(pm8001_wq);
kfree(pm8001_ha->tags);
kfree(pm8001_ha);
}
@@ -381,7 +381,6 @@ pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id, struct Scsi_Host *shost)
pm8001_ha->sas = sha;
pm8001_ha->shost = shost;
pm8001_ha->id = pm8001_id++;
- INIT_LIST_HEAD(&pm8001_ha->wq_list);
pm8001_ha->logging_level = 0x01;
sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id);
#ifdef PM8001_USE_TASKLET
@@ -758,7 +757,7 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
int i , pos;
u32 device_state;
pm8001_ha = sha->lldd_ha;
- flush_scheduled_work();
+ flush_workqueue(pm8001_wq);
scsi_block_requests(pm8001_ha->shost);
pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (pos == 0) {
@@ -870,17 +869,26 @@ static struct pci_driver pm8001_pci_driver = {
*/
static int __init pm8001_init(void)
{
- int rc;
+ int rc = -ENOMEM;
+
+ pm8001_wq = alloc_workqueue("pm8001", 0, 0);
+ if (!pm8001_wq)
+ goto err;
+
pm8001_id = 0;
pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops);
if (!pm8001_stt)
- return -ENOMEM;
+ goto err_wq;
rc = pci_register_driver(&pm8001_pci_driver);
if (rc)
- goto err_out;
+ goto err_tp;
return 0;
-err_out:
+
+err_tp:
sas_release_transport(pm8001_stt);
+err_wq:
+ destroy_workqueue(pm8001_wq);
+err:
return rc;
}
@@ -888,6 +896,7 @@ static void __exit pm8001_exit(void)
{
pci_unregister_driver(&pm8001_pci_driver);
sas_release_transport(pm8001_stt);
+ destroy_workqueue(pm8001_wq);
}
module_init(pm8001_init);
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 7f064f9ca828..bdb6b27dedd6 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -50,6 +50,7 @@
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <scsi/libsas.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
@@ -379,18 +380,16 @@ struct pm8001_hba_info {
#ifdef PM8001_USE_TASKLET
struct tasklet_struct tasklet;
#endif
- struct list_head wq_list;
u32 logging_level;
u32 fw_status;
const struct firmware *fw_image;
};
-struct pm8001_wq {
- struct delayed_work work_q;
+struct pm8001_work {
+ struct work_struct work;
struct pm8001_hba_info *pm8001_ha;
void *data;
int handler;
- struct list_head entry;
};
struct pm8001_fw_image_header {
@@ -460,6 +459,9 @@ struct fw_control_ex {
void *param3;
};
+/* pm8001 workqueue */
+extern struct workqueue_struct *pm8001_wq;
+
/******************** function prototype *********************/
int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out);
void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha);
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 321cf3ae8630..bcf858e88c64 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -5454,7 +5454,7 @@ static void __devexit pmcraid_remove(struct pci_dev *pdev)
pmcraid_shutdown(pdev);
pmcraid_disable_interrupts(pinstance, ~0);
- flush_scheduled_work();
+ flush_work_sync(&pinstance->worker_q);
pmcraid_kill_tasklets(pinstance);
pmcraid_unregister_interrupt_handler(pinstance);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index ccfc8e78be21..6c51c0a35b9e 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2402,13 +2402,13 @@ struct qla_hw_data {
volatile struct {
uint32_t mbox_int :1;
uint32_t mbox_busy :1;
-
uint32_t disable_risc_code_load :1;
uint32_t enable_64bit_addressing :1;
uint32_t enable_lip_reset :1;
uint32_t enable_target_reset :1;
uint32_t enable_lip_full_login :1;
uint32_t enable_led_scheme :1;
+
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
@@ -2417,6 +2417,7 @@ struct qla_hw_data {
uint32_t pci_channel_io_perm_failure :1;
uint32_t fce_enabled :1;
uint32_t fac_supported :1;
+
uint32_t chip_reset_done :1;
uint32_t port0 :1;
uint32_t running_gold_fw :1;
@@ -2424,9 +2425,11 @@ struct qla_hw_data {
uint32_t cpu_affinity_enabled :1;
uint32_t disable_msix_handshake :1;
uint32_t fcp_prio_enabled :1;
- uint32_t fw_hung :1;
- uint32_t quiesce_owner:1;
+ uint32_t isp82xx_fw_hung:1;
+
+ uint32_t quiesce_owner:1;
uint32_t thermal_supported:1;
+ uint32_t isp82xx_reset_hdlr_active:1;
/* 26 bits */
} flags;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 89e900adb679..d48326ee3f61 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -565,6 +565,7 @@ extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(srb_t *);
extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
+extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *);
/* BSG related functions */
extern int qla24xx_bsg_request(struct fc_bsg_job *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 4c083928c2fb..74a91b6dfc68 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -121,8 +121,11 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
rval = QLA_FUNCTION_FAILED;
if (ms_pkt->entry_status != 0) {
- DEBUG2_3(printk("scsi(%ld): %s failed, error status (%x).\n",
- vha->host_no, routine, ms_pkt->entry_status));
+ DEBUG2_3(printk(KERN_WARNING "scsi(%ld): %s failed, error status "
+ "(%x) on port_id: %02x%02x%02x.\n",
+ vha->host_no, routine, ms_pkt->entry_status,
+ vha->d_id.b.domain, vha->d_id.b.area,
+ vha->d_id.b.al_pa));
} else {
if (IS_FWI2_CAPABLE(ha))
comp_status = le16_to_cpu(
@@ -136,8 +139,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
if (ct_rsp->header.response !=
__constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
DEBUG2_3(printk("scsi(%ld): %s failed, "
- "rejected request:\n", vha->host_no,
- routine));
+ "rejected request on port_id: %02x%02x%02x\n",
+ vha->host_no, routine,
+ vha->d_id.b.domain, vha->d_id.b.area,
+ vha->d_id.b.al_pa));
DEBUG2_3(qla2x00_dump_buffer(
(uint8_t *)&ct_rsp->header,
sizeof(struct ct_rsp_hdr)));
@@ -147,8 +152,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
break;
default:
DEBUG2_3(printk("scsi(%ld): %s failed, completion "
- "status (%x).\n", vha->host_no, routine,
- comp_status));
+ "status (%x) on port_id: %02x%02x%02x.\n",
+ vha->host_no, routine, comp_status,
+ vha->d_id.b.domain, vha->d_id.b.area,
+ vha->d_id.b.al_pa));
break;
}
}
@@ -1965,7 +1972,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
"scsi(%ld): GFF_ID issue IOCB failed "
"(%d).\n", vha->host_no, rval));
} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
- "GPN_ID") != QLA_SUCCESS) {
+ "GFF_ID") != QLA_SUCCESS) {
DEBUG2_3(printk(KERN_INFO
"scsi(%ld): GFF_ID IOCB status had a "
"failure status code\n", vha->host_no));
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index d9479c3fe5f8..8575808dbae0 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1967,7 +1967,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
} else {
/* Mailbox cmd failed. Timeout on min_wait. */
if (time_after_eq(jiffies, mtime) ||
- (IS_QLA82XX(ha) && ha->flags.fw_hung))
+ ha->flags.isp82xx_fw_hung)
break;
}
@@ -3945,8 +3945,13 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *vp;
unsigned long flags;
+ fc_port_t *fcport;
- vha->flags.online = 0;
+ /* For ISP82XX, driver waits for completion of the commands.
+ * online flag should be set.
+ */
+ if (!IS_QLA82XX(ha))
+ vha->flags.online = 0;
ha->flags.chip_reset_done = 0;
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
ha->qla_stats.total_isp_aborts++;
@@ -3954,7 +3959,10 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
qla_printk(KERN_INFO, ha,
"Performing ISP error recovery - ha= %p.\n", ha);
- /* Chip reset does not apply to 82XX */
+ /* For ISP82XX, reset_chip is just disabling interrupts.
+ * Driver waits for the completion of the commands.
+ * the interrupts need to be enabled.
+ */
if (!IS_QLA82XX(ha))
ha->isp_ops->reset_chip(vha);
@@ -3980,14 +3988,31 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
LOOP_DOWN_TIME);
}
+ /* Clear all async request states across all VPs. */
+ list_for_each_entry(fcport, &vha->vp_fcports, list)
+ fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ list_for_each_entry(vp, &ha->vp_list, list) {
+ atomic_inc(&vp->vref_count);
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+ list_for_each_entry(fcport, &vp->vp_fcports, list)
+ fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ atomic_dec(&vp->vref_count);
+ }
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+
if (!ha->flags.eeh_busy) {
/* Make sure for ISP 82XX IO DMA is complete */
if (IS_QLA82XX(ha)) {
- if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
- WAIT_HOST) == QLA_SUCCESS) {
- DEBUG2(qla_printk(KERN_INFO, ha,
- "Done wait for pending commands\n"));
- }
+ qla82xx_chip_reset_cleanup(vha);
+
+ /* Done waiting for pending commands.
+ * Reset the online flag.
+ */
+ vha->flags.online = 0;
}
/* Requeue all commands in outstanding command list. */
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 4c1ba6263eb3..d78d5896fc33 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -328,6 +328,7 @@ qla2x00_start_scsi(srb_t *sp)
struct qla_hw_data *ha;
struct req_que *req;
struct rsp_que *rsp;
+ char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -406,7 +407,22 @@ qla2x00_start_scsi(srb_t *sp)
cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);
/* Update tagged queuing modifier */
- cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ cmd_pkt->control_flags =
+ __constant_cpu_to_le16(CF_HEAD_TAG);
+ break;
+ case ORDERED_QUEUE_TAG:
+ cmd_pkt->control_flags =
+ __constant_cpu_to_le16(CF_ORDERED_TAG);
+ break;
+ default:
+ cmd_pkt->control_flags =
+ __constant_cpu_to_le16(CF_SIMPLE_TAG);
+ break;
+ }
+ }
/* Load SCSI command packet. */
memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
@@ -971,6 +987,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
uint16_t fcp_cmnd_len;
struct fcp_cmnd *fcp_cmnd;
dma_addr_t crc_ctx_dma;
+ char tag[2];
cmd = sp->cmd;
@@ -1068,9 +1085,27 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32(
MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
- fcp_cmnd->task_attribute = 0;
fcp_cmnd->task_management = 0;
+ /*
+ * Update tagged queuing modifier if using command tag queuing
+ */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ fcp_cmnd->task_attribute = TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ fcp_cmnd->task_attribute = TSK_ORDERED;
+ break;
+ default:
+ fcp_cmnd->task_attribute = 0;
+ break;
+ }
+ } else {
+ fcp_cmnd->task_attribute = 0;
+ }
+
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data"
@@ -1177,6 +1212,7 @@ qla24xx_start_scsi(srb_t *sp)
struct scsi_cmnd *cmd = sp->cmd;
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
+ char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -1260,6 +1296,18 @@ qla24xx_start_scsi(srb_t *sp)
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+ /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ cmd_pkt->task = TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ cmd_pkt->task = TSK_ORDERED;
+ break;
+ }
+ }
+
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index e473e9fb363c..7a7c0ecfe7dd 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -71,6 +71,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}
+ if (ha->flags.isp82xx_fw_hung) {
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
/*
* Wait for active mailbox commands to finish by waiting at most tov
* seconds. This is to serialize actual issuing of mailbox cmds during
@@ -83,13 +90,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}
- if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
- /* Setting Link-Down error */
- mcp->mb[0] = MBS_LINK_DOWN_ERROR;
- rval = QLA_FUNCTION_FAILED;
- goto premature_exit;
- }
-
ha->flags.mbox_busy = 1;
/* Save mailbox command for debug */
ha->mcp = mcp;
@@ -223,7 +223,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
ha->flags.mbox_int = 0;
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+ if (ha->flags.isp82xx_fw_hung) {
ha->flags.mbox_busy = 0;
/* Setting Link-Down error */
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
@@ -2462,22 +2462,19 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
"-- completion status (%x).\n", __func__,
vha->host_no, le16_to_cpu(sts->comp_status)));
rval = QLA_FUNCTION_FAILED;
- } else if (!(le16_to_cpu(sts->scsi_status) &
- SS_RESPONSE_INFO_LEN_VALID)) {
- DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
- "-- no response info (%x).\n", __func__, vha->host_no,
- le16_to_cpu(sts->scsi_status)));
- rval = QLA_FUNCTION_FAILED;
- } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
- DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
- "-- not enough response info (%d).\n", __func__,
- vha->host_no, le32_to_cpu(sts->rsp_data_len)));
- rval = QLA_FUNCTION_FAILED;
- } else if (sts->data[3]) {
- DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
- "-- response (%x).\n", __func__,
- vha->host_no, sts->data[3]));
- rval = QLA_FUNCTION_FAILED;
+ } else if (le16_to_cpu(sts->scsi_status) &
+ SS_RESPONSE_INFO_LEN_VALID) {
+ if (le32_to_cpu(sts->rsp_data_len) < 4) {
+ DEBUG2_3_11(printk("%s(%ld): ignoring inconsistent "
+ "data length -- not enough response info (%d).\n",
+ __func__, vha->host_no,
+ le32_to_cpu(sts->rsp_data_len)));
+ } else if (sts->data[3]) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- response (%x).\n", __func__,
+ vha->host_no, sts->data[3]));
+ rval = QLA_FUNCTION_FAILED;
+ }
}
/* Issue marker IOCB. */
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index fdb96a3584a5..76ec876e6b21 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -7,6 +7,7 @@
#include "qla_def.h"
#include <linux/delay.h>
#include <linux/pci.h>
+#include <scsi/scsi_tcq.h>
#define MASK(n) ((1ULL<<(n))-1)
#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
@@ -2547,7 +2548,7 @@ qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
*dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *dsd_seg++ = dsd_list_len;
+ cmd_pkt->fcp_data_dseg_len = dsd_list_len;
} else {
*cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
*cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
@@ -2620,6 +2621,7 @@ qla82xx_start_scsi(srb_t *sp)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
+ char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -2770,6 +2772,22 @@ sufficient_dsds:
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+ /*
+ * Update tagged queuing modifier -- default is TSK_SIMPLE (0).
+ */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ ctx->fcp_cmnd->task_attribute =
+ TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ ctx->fcp_cmnd->task_attribute =
+ TSK_ORDERED;
+ break;
+ }
+ }
+
/* build FCP_CMND IU */
memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
@@ -2835,6 +2853,20 @@ sufficient_dsds:
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
sizeof(cmd_pkt->lun));
+ /*
+ * Update tagged queuing modifier -- default is TSK_SIMPLE (0).
+ */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ cmd_pkt->task = TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ cmd_pkt->task = TSK_ORDERED;
+ break;
+ }
+ }
+
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
@@ -3457,46 +3489,28 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
}
}
-static void
+int
qla82xx_check_fw_alive(scsi_qla_host_t *vha)
{
- uint32_t fw_heartbeat_counter, halt_status;
- struct qla_hw_data *ha = vha->hw;
+ uint32_t fw_heartbeat_counter;
+ int status = 0;
- fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+ fw_heartbeat_counter = qla82xx_rd_32(vha->hw,
+ QLA82XX_PEG_ALIVE_COUNTER);
/* all 0xff, assume AER/EEH in progress, ignore */
if (fw_heartbeat_counter == 0xffffffff)
- return;
+ return status;
if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
vha->seconds_since_last_heartbeat++;
/* FW not alive after 2 seconds */
if (vha->seconds_since_last_heartbeat == 2) {
vha->seconds_since_last_heartbeat = 0;
- halt_status = qla82xx_rd_32(ha,
- QLA82XX_PEG_HALT_STATUS1);
- if (halt_status & HALT_STATUS_UNRECOVERABLE) {
- set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
- } else {
- qla_printk(KERN_INFO, ha,
- "scsi(%ld): %s - detect abort needed\n",
- vha->host_no, __func__);
- set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
- }
- qla2xxx_wake_dpc(vha);
- ha->flags.fw_hung = 1;
- if (ha->flags.mbox_busy) {
- ha->flags.mbox_int = 1;
- DEBUG2(qla_printk(KERN_ERR, ha,
- "Due to fw hung, doing premature "
- "completion of mbx command\n"));
- if (test_bit(MBX_INTR_WAIT,
- &ha->mbx_cmd_flags))
- complete(&ha->mbx_intr_comp);
- }
+ status = 1;
}
} else
vha->seconds_since_last_heartbeat = 0;
vha->fw_heartbeat_counter = fw_heartbeat_counter;
+ return status;
}
/*
@@ -3557,6 +3571,8 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
break;
case QLA82XX_DEV_NEED_RESET:
qla82xx_need_reset_handler(vha);
+ dev_init_timeout = jiffies +
+ (ha->nx_dev_init_timeout * HZ);
break;
case QLA82XX_DEV_NEED_QUIESCENT:
qla82xx_need_qsnt_handler(vha);
@@ -3596,30 +3612,18 @@ exit:
void qla82xx_watchdog(scsi_qla_host_t *vha)
{
- uint32_t dev_state;
+ uint32_t dev_state, halt_status;
struct qla_hw_data *ha = vha->hw;
- dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-
/* don't poll if reset is going on */
- if (!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
- test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))) {
- if (dev_state == QLA82XX_DEV_NEED_RESET) {
+ if (!ha->flags.isp82xx_reset_hdlr_active) {
+ dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+ if (dev_state == QLA82XX_DEV_NEED_RESET &&
+ !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
qla_printk(KERN_WARNING, ha,
- "%s(): Adapter reset needed!\n", __func__);
+ "%s(): Adapter reset needed!\n", __func__);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
- ha->flags.fw_hung = 1;
- if (ha->flags.mbox_busy) {
- ha->flags.mbox_int = 1;
- DEBUG2(qla_printk(KERN_ERR, ha,
- "Need reset, doing premature "
- "completion of mbx command\n"));
- if (test_bit(MBX_INTR_WAIT,
- &ha->mbx_cmd_flags))
- complete(&ha->mbx_intr_comp);
- }
} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
!test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
DEBUG(qla_printk(KERN_INFO, ha,
@@ -3629,6 +3633,31 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
qla2xxx_wake_dpc(vha);
} else {
qla82xx_check_fw_alive(vha);
+ if (qla82xx_check_fw_alive(vha)) {
+ halt_status = qla82xx_rd_32(ha,
+ QLA82XX_PEG_HALT_STATUS1);
+ if (halt_status & HALT_STATUS_UNRECOVERABLE) {
+ set_bit(ISP_UNRECOVERABLE,
+ &vha->dpc_flags);
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "scsi(%ld): %s - detect abort needed\n",
+ vha->host_no, __func__);
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ }
+ qla2xxx_wake_dpc(vha);
+ ha->flags.isp82xx_fw_hung = 1;
+ if (ha->flags.mbox_busy) {
+ ha->flags.mbox_int = 1;
+ DEBUG2(qla_printk(KERN_ERR, ha,
+ "Due to fw hung, doing premature "
+ "completion of mbx command\n"));
+ if (test_bit(MBX_INTR_WAIT,
+ &ha->mbx_cmd_flags))
+ complete(&ha->mbx_intr_comp);
+ }
+ }
}
}
}
@@ -3663,6 +3692,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
"Exiting.\n", __func__, vha->host_no);
return QLA_SUCCESS;
}
+ ha->flags.isp82xx_reset_hdlr_active = 1;
qla82xx_idc_lock(ha);
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
@@ -3683,7 +3713,8 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
qla82xx_idc_unlock(ha);
if (rval == QLA_SUCCESS) {
- ha->flags.fw_hung = 0;
+ ha->flags.isp82xx_fw_hung = 0;
+ ha->flags.isp82xx_reset_hdlr_active = 0;
qla82xx_restart_isp(vha);
}
@@ -3791,3 +3822,71 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
return status;
}
+
+void
+qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
+{
+ int i;
+ unsigned long flags;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Check if 82XX firmware is alive or not
+ * We may have arrived here from NEED_RESET
+ * detection only
+ */
+ if (!ha->flags.isp82xx_fw_hung) {
+ for (i = 0; i < 2; i++) {
+ msleep(1000);
+ if (qla82xx_check_fw_alive(vha)) {
+ ha->flags.isp82xx_fw_hung = 1;
+ if (ha->flags.mbox_busy) {
+ ha->flags.mbox_int = 1;
+ complete(&ha->mbx_intr_comp);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Abort all commands gracefully if fw NOT hung */
+ if (!ha->flags.isp82xx_fw_hung) {
+ int cnt, que;
+ srb_t *sp;
+ struct req_que *req;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (que = 0; que < ha->max_req_queues; que++) {
+ req = ha->req_q_map[que];
+ if (!req)
+ continue;
+ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+ sp = req->outstanding_cmds[cnt];
+ if (sp) {
+ if (!sp->ctx ||
+ (sp->flags & SRB_FCP_CMND_DMA_VALID)) {
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ qla_printk(KERN_INFO, ha,
+ "scsi(%ld): mbx abort command failed in %s\n",
+ vha->host_no, __func__);
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "scsi(%ld): mbx abort command success in %s\n",
+ vha->host_no, __func__);
+ }
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait for pending cmds (physical and virtual) to complete */
+ if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+ WAIT_HOST) == QLA_SUCCESS) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Done wait for pending commands\n"));
+ }
+ }
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e90f7c16b956..75a966c94860 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -506,7 +506,7 @@ qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str)
static inline srb_t *
qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
- struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+ struct scsi_cmnd *cmd)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
@@ -520,14 +520,13 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
sp->cmd = cmd;
sp->flags = 0;
CMD_SP(cmd) = (void *)sp;
- cmd->scsi_done = done;
sp->ctx = NULL;
return sp;
}
static int
-qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
@@ -537,7 +536,6 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)
srb_t *sp;
int rval;
- spin_unlock_irq(vha->host->host_lock);
if (ha->flags.eeh_busy) {
if (ha->flags.pci_channel_io_perm_failure)
cmd->result = DID_NO_CONNECT << 16;
@@ -569,40 +567,32 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)
goto qc24_target_busy;
}
- sp = qla2x00_get_new_sp(base_vha, fcport, cmd, done);
+ sp = qla2x00_get_new_sp(base_vha, fcport, cmd);
if (!sp)
- goto qc24_host_busy_lock;
+ goto qc24_host_busy;
rval = ha->isp_ops->start_scsi(sp);
if (rval != QLA_SUCCESS)
goto qc24_host_busy_free_sp;
- spin_lock_irq(vha->host->host_lock);
-
return 0;
qc24_host_busy_free_sp:
qla2x00_sp_free_dma(sp);
mempool_free(sp, ha->srb_mempool);
-qc24_host_busy_lock:
- spin_lock_irq(vha->host->host_lock);
+qc24_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
qc24_target_busy:
- spin_lock_irq(vha->host->host_lock);
return SCSI_MLQUEUE_TARGET_BUSY;
qc24_fail_command:
- spin_lock_irq(vha->host->host_lock);
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
-static DEF_SCSI_QCMD(qla2xxx_queuecommand)
-
-
/*
* qla2x00_eh_wait_on_command
* Waits for the command to be returned by the Firmware for some
@@ -821,17 +811,20 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
srb_t *sp;
- int ret = SUCCESS;
+ int ret;
unsigned int id, lun;
unsigned long flags;
int wait = 0;
struct qla_hw_data *ha = vha->hw;
- fc_block_scsi_eh(cmd);
-
if (!CMD_SP(cmd))
return SUCCESS;
+ ret = fc_block_scsi_eh(cmd);
+ if (ret != 0)
+ return ret;
+ ret = SUCCESS;
+
id = cmd->device->id;
lun = cmd->device->lun;
@@ -940,11 +933,13 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int err;
- fc_block_scsi_eh(cmd);
-
if (!fcport)
return FAILED;
+ err = fc_block_scsi_eh(cmd);
+ if (err != 0)
+ return err;
+
qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
vha->host_no, cmd->device->id, cmd->device->lun, name);
@@ -1018,14 +1013,17 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
int ret = FAILED;
unsigned int id, lun;
- fc_block_scsi_eh(cmd);
-
id = cmd->device->id;
lun = cmd->device->lun;
if (!fcport)
return ret;
+ ret = fc_block_scsi_eh(cmd);
+ if (ret != 0)
+ return ret;
+ ret = FAILED;
+
qla_printk(KERN_INFO, vha->hw,
"scsi(%ld:%d:%d): BUS RESET ISSUED.\n", vha->host_no, id, lun);
@@ -1078,14 +1076,17 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- fc_block_scsi_eh(cmd);
-
id = cmd->device->id;
lun = cmd->device->lun;
if (!fcport)
return ret;
+ ret = fc_block_scsi_eh(cmd);
+ if (ret != 0)
+ return ret;
+ ret = FAILED;
+
qla_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun);
@@ -3805,7 +3806,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
ha->flags.eeh_busy = 1;
/* For ISP82XX complete any pending mailbox cmd */
if (IS_QLA82XX(ha)) {
- ha->flags.fw_hung = 1;
+ ha->flags.isp82xx_fw_hung = 1;
if (ha->flags.mbox_busy) {
ha->flags.mbox_int = 1;
DEBUG2(qla_printk(KERN_ERR, ha,
@@ -3945,7 +3946,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
QLA82XX_DEV_READY);
qla82xx_idc_unlock(ha);
- ha->flags.fw_hung = 0;
+ ha->flags.isp82xx_fw_hung = 0;
rval = qla82xx_restart_isp(base_vha);
qla82xx_idc_lock(ha);
/* Clear driver state register */
@@ -3958,7 +3959,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
"This devfn is not reset owner = 0x%x\n", ha->pdev->devfn));
if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
QLA82XX_DEV_READY)) {
- ha->flags.fw_hung = 0;
+ ha->flags.isp82xx_fw_hung = 0;
rval = qla82xx_restart_isp(base_vha);
qla82xx_idc_lock(ha);
qla82xx_set_drv_active(base_vha);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index cf0075a2d0c2..3a260c3f055a 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.05-k0"
+#define QLA2XXX_VERSION "8.03.07.00"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 5
+#define QLA_DRIVER_PATCH_VER 7
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 6ffbe9727dff..03e028e6e809 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -1027,7 +1027,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
((ddb_entry->default_time2wait +
4) * HZ);
- DEBUG2(printk("scsi%ld: ddb [%d] initate"
+ DEBUG2(printk("scsi%ld: ddb [%d] initiate"
" RELOGIN after %d seconds\n",
ha->host_no,
ddb_entry->fw_ddb_index,
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 3fc1d256636f..967836ef5ab2 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -812,7 +812,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
);
start_dpc++;
DEBUG(printk("scsi%ld:%d:%d: ddb [%d] "
- "initate relogin after"
+ "initiate relogin after"
" %d seconds\n",
ha->host_no, ddb_entry->bus,
ddb_entry->target,
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index a6b2d72022fc..fa5758cbdedb 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -89,32 +89,34 @@ static const char * scsi_debug_version_date = "20100324";
/* With these defaults, this driver will make 1 host with 1 target
* (id 0) containing 1 logical unit (lun 0). That is 1 device.
*/
+#define DEF_ATO 1
#define DEF_DELAY 1
#define DEF_DEV_SIZE_MB 8
-#define DEF_EVERY_NTH 0
-#define DEF_NUM_PARTS 0
-#define DEF_OPTS 0
-#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
-#define DEF_PTYPE 0
+#define DEF_DIF 0
+#define DEF_DIX 0
#define DEF_D_SENSE 0
-#define DEF_NO_LUN_0 0
-#define DEF_VIRTUAL_GB 0
+#define DEF_EVERY_NTH 0
#define DEF_FAKE_RW 0
-#define DEF_VPD_USE_HOSTNO 1
-#define DEF_SECTOR_SIZE 512
-#define DEF_DIX 0
-#define DEF_DIF 0
#define DEF_GUARD 0
-#define DEF_ATO 1
-#define DEF_PHYSBLK_EXP 0
+#define DEF_LBPU 0
+#define DEF_LBPWS 0
+#define DEF_LBPWS10 0
#define DEF_LOWEST_ALIGNED 0
+#define DEF_NO_LUN_0 0
+#define DEF_NUM_PARTS 0
+#define DEF_OPTS 0
#define DEF_OPT_BLKS 64
+#define DEF_PHYSBLK_EXP 0
+#define DEF_PTYPE 0
+#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
+#define DEF_SECTOR_SIZE 512
+#define DEF_UNMAP_ALIGNMENT 0
+#define DEF_UNMAP_GRANULARITY 1
#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
#define DEF_UNMAP_MAX_DESC 256
-#define DEF_UNMAP_GRANULARITY 1
-#define DEF_UNMAP_ALIGNMENT 0
-#define DEF_TPWS 0
-#define DEF_TPU 0
+#define DEF_VIRTUAL_GB 0
+#define DEF_VPD_USE_HOSTNO 1
+#define DEF_WRITESAME_LENGTH 0xFFFF
/* bit mask values for scsi_debug_opts */
#define SCSI_DEBUG_OPT_NOISE 1
@@ -144,6 +146,7 @@ static const char * scsi_debug_version_date = "20100324";
/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
* sector on read commands: */
#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
+#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
* or "peripheral device" addressing (value 0) */
@@ -155,36 +158,38 @@ static const char * scsi_debug_version_date = "20100324";
#define SCSI_DEBUG_CANQUEUE 255
static int scsi_debug_add_host = DEF_NUM_HOST;
+static int scsi_debug_ato = DEF_ATO;
static int scsi_debug_delay = DEF_DELAY;
static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+static int scsi_debug_dif = DEF_DIF;
+static int scsi_debug_dix = DEF_DIX;
+static int scsi_debug_dsense = DEF_D_SENSE;
static int scsi_debug_every_nth = DEF_EVERY_NTH;
+static int scsi_debug_fake_rw = DEF_FAKE_RW;
+static int scsi_debug_guard = DEF_GUARD;
+static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
static int scsi_debug_max_luns = DEF_MAX_LUNS;
static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
-static int scsi_debug_num_parts = DEF_NUM_PARTS;
+static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
static int scsi_debug_no_uld = 0;
+static int scsi_debug_num_parts = DEF_NUM_PARTS;
static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
+static int scsi_debug_opt_blks = DEF_OPT_BLKS;
static int scsi_debug_opts = DEF_OPTS;
-static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
+static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
-static int scsi_debug_dsense = DEF_D_SENSE;
-static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
+static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
+static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
-static int scsi_debug_fake_rw = DEF_FAKE_RW;
static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
-static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
-static int scsi_debug_dix = DEF_DIX;
-static int scsi_debug_dif = DEF_DIF;
-static int scsi_debug_guard = DEF_GUARD;
-static int scsi_debug_ato = DEF_ATO;
-static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
-static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
-static int scsi_debug_opt_blks = DEF_OPT_BLKS;
-static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
-static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
-static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
+static unsigned int scsi_debug_lbpu = DEF_LBPU;
+static unsigned int scsi_debug_lbpws = DEF_LBPWS;
+static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
-static unsigned int scsi_debug_tpws = DEF_TPWS;
-static unsigned int scsi_debug_tpu = DEF_TPU;
+static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
+static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
+static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
+static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
static int scsi_debug_cmnd_count = 0;
@@ -206,6 +211,11 @@ static int sdebug_sectors_per; /* sectors per cylinder */
#define SCSI_DEBUG_MAX_CMD_LEN 32
+static unsigned int scsi_debug_lbp(void)
+{
+ return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
+}
+
struct sdebug_dev_info {
struct list_head dev_list;
unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
@@ -727,7 +737,7 @@ static int inquiry_evpd_b0(unsigned char * arr)
/* Optimal Transfer Length */
put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
- if (scsi_debug_tpu) {
+ if (scsi_debug_lbpu) {
/* Maximum Unmap LBA Count */
put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
@@ -744,7 +754,10 @@ static int inquiry_evpd_b0(unsigned char * arr)
/* Optimal Unmap Granularity */
put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
- return 0x3c; /* Mandatory page length for thin provisioning */
+ /* Maximum WRITE SAME Length */
+ put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
+
+ return 0x3c; /* Mandatory page length for Logical Block Provisioning */
return sizeof(vpdb0_data);
}
@@ -767,12 +780,15 @@ static int inquiry_evpd_b2(unsigned char *arr)
memset(arr, 0, 0x8);
arr[0] = 0; /* threshold exponent */
- if (scsi_debug_tpu)
+ if (scsi_debug_lbpu)
arr[1] = 1 << 7;
- if (scsi_debug_tpws)
+ if (scsi_debug_lbpws)
arr[1] |= 1 << 6;
+ if (scsi_debug_lbpws10)
+ arr[1] |= 1 << 5;
+
return 0x8;
}
@@ -831,7 +847,8 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
arr[n++] = 0x89; /* ATA information */
arr[n++] = 0xb0; /* Block limits (SBC) */
arr[n++] = 0xb1; /* Block characteristics (SBC) */
- arr[n++] = 0xb2; /* Thin provisioning (SBC) */
+ if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
+ arr[n++] = 0xb2;
arr[3] = n - 4; /* number of supported VPD pages */
} else if (0x80 == cmd[2]) { /* unit serial number */
arr[1] = cmd[2]; /*sanity */
@@ -879,7 +896,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
arr[1] = cmd[2]; /*sanity */
arr[3] = inquiry_evpd_b1(&arr[4]);
- } else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */
+ } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
arr[1] = cmd[2]; /*sanity */
arr[3] = inquiry_evpd_b2(&arr[4]);
} else {
@@ -1053,8 +1070,8 @@ static int resp_readcap16(struct scsi_cmnd * scp,
arr[13] = scsi_debug_physblk_exp & 0xf;
arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
- if (scsi_debug_tpu || scsi_debug_tpws)
- arr[14] |= 0x80; /* TPE */
+ if (scsi_debug_lbp())
+ arr[14] |= 0x80; /* LBPME */
arr[15] = scsi_debug_lowest_aligned & 0xff;
@@ -1791,15 +1808,15 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
return ret;
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
- (lba <= OPT_MEDIUM_ERR_ADDR) &&
+ (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
/* claim unrecoverable read error */
- mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
- 0);
+ mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
/* set info field and valid bit for fixed descriptor */
if (0x70 == (devip->sense_buff[0] & 0x7f)) {
devip->sense_buff[0] |= 0x80; /* Valid bit */
- ret = OPT_MEDIUM_ERR_ADDR;
+ ret = (lba < OPT_MEDIUM_ERR_ADDR)
+ ? OPT_MEDIUM_ERR_ADDR : (int)lba;
devip->sense_buff[3] = (ret >> 24) & 0xff;
devip->sense_buff[4] = (ret >> 16) & 0xff;
devip->sense_buff[5] = (ret >> 8) & 0xff;
@@ -2084,6 +2101,12 @@ static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
if (ret)
return ret;
+ if (num > scsi_debug_write_same_length) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
+
write_lock_irqsave(&atomic_rw, iflags);
if (unmap && scsi_debug_unmap_granularity) {
@@ -2695,37 +2718,40 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
/sys/bus/pseudo/drivers/scsi_debug directory is changed.
*/
module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
+module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
+module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
+module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
+module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
+module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
+module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
+module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
+module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
+module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
+module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
-module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
-module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
- S_IRUGO | S_IWUSR);
module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
-module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
-module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
-module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
-module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
-module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
-module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
-module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
+module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
+module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
-module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
-module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
-module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO);
-module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO);
+module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
+module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
+ S_IRUGO | S_IWUSR);
+module_param_named(write_same_length, scsi_debug_write_same_length, int,
+ S_IRUGO | S_IWUSR);
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -2733,36 +2759,38 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(SCSI_DEBUG_VERSION);
MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
+MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
+MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
+MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
+MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
+MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
+MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
+MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
+MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
+MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
-MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
-MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
-MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
-MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
-MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
-MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
-MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
-MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
-MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
+MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
+MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
-MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
-MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
-MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)");
-MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)");
+MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
+MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
+MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
static char sdebug_info[256];
@@ -3150,7 +3178,7 @@ static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
{
ssize_t count;
- if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0)
+ if (!scsi_debug_lbp())
return scnprintf(buf, PAGE_SIZE, "0-%u\n",
sdebug_store_sectors);
@@ -3333,8 +3361,8 @@ static int __init scsi_debug_init(void)
memset(dif_storep, 0xff, dif_size);
}
- /* Thin Provisioning */
- if (scsi_debug_tpu || scsi_debug_tpws) {
+ /* Logical Block Provisioning */
+ if (scsi_debug_lbp()) {
unsigned int map_bytes;
scsi_debug_unmap_max_blocks =
@@ -3664,7 +3692,7 @@ int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
errsts = resp_readcap16(SCpnt, devip);
else if (cmd[1] == SAI_GET_LBA_STATUS) {
- if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) {
+ if (scsi_debug_lbp() == 0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
@@ -3775,8 +3803,10 @@ write:
}
break;
case WRITE_SAME_16:
+ case WRITE_SAME:
if (cmd[1] & 0x8) {
- if (scsi_debug_tpws == 0) {
+ if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
+ (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
errsts = check_condition_result;
@@ -3785,8 +3815,6 @@ write:
}
if (errsts)
break;
- /* fall through */
- case WRITE_SAME:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
@@ -3798,7 +3826,7 @@ write:
if (errsts)
break;
- if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) {
+ if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_COMMAND_OPCODE, 0);
errsts = check_condition_result;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 43fad4c09beb..82e9e5c0476e 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -382,6 +382,91 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
/**
+ * scsi_dev_info_list_del_keyed - remove one dev_info list entry.
+ * @vendor: vendor string
+ * @model: model (product) string
+ * @key: specify list to use
+ *
+ * Description:
+ * Remove and destroy one dev_info entry for @vendor, @model
+ * in list specified by @key.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
+{
+ struct scsi_dev_info_list *devinfo, *found = NULL;
+ struct scsi_dev_info_list_table *devinfo_table =
+ scsi_devinfo_lookup_by_key(key);
+
+ if (IS_ERR(devinfo_table))
+ return PTR_ERR(devinfo_table);
+
+ list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
+ dev_info_list) {
+ if (devinfo->compatible) {
+ /*
+ * Behave like the older version of get_device_flags.
+ */
+ size_t max;
+ /*
+ * XXX why skip leading spaces? If an odd INQUIRY
+ * value, that should have been part of the
+ * scsi_static_device_list[] entry, such as " FOO"
+ * rather than "FOO". Since this code is already
+ * here, and we don't know what device it is
+ * trying to work with, leave it as-is.
+ */
+ max = 8; /* max length of vendor */
+ while ((max > 0) && *vendor == ' ') {
+ max--;
+ vendor++;
+ }
+ /*
+ * XXX removing the following strlen() would be
+ * good, using it means that for a an entry not in
+ * the list, we scan every byte of every vendor
+ * listed in scsi_static_device_list[], and never match
+ * a single one (and still have to compare at
+ * least the first byte of each vendor).
+ */
+ if (memcmp(devinfo->vendor, vendor,
+ min(max, strlen(devinfo->vendor))))
+ continue;
+ /*
+ * Skip spaces again.
+ */
+ max = 16; /* max length of model */
+ while ((max > 0) && *model == ' ') {
+ max--;
+ model++;
+ }
+ if (memcmp(devinfo->model, model,
+ min(max, strlen(devinfo->model))))
+ continue;
+ found = devinfo;
+ } else {
+ if (!memcmp(devinfo->vendor, vendor,
+ sizeof(devinfo->vendor)) &&
+ !memcmp(devinfo->model, model,
+ sizeof(devinfo->model)))
+ found = devinfo;
+ }
+ if (found)
+ break;
+ }
+
+ if (found) {
+ list_del(&found->dev_info_list);
+ kfree(found);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL(scsi_dev_info_list_del_keyed);
+
+/**
* scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
* @dev_list: string of device flags to add
*
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 45c75649b9e0..991de3c15cfc 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -223,7 +223,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
* @scmd: Cmd to have sense checked.
*
* Return value:
- * SUCCESS or FAILED or NEEDS_RETRY
+ * SUCCESS or FAILED or NEEDS_RETRY or TARGET_ERROR
*
* Notes:
* When a deferred error is detected the current command has
@@ -326,17 +326,19 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
*/
return SUCCESS;
- /* these three are not supported */
+ /* these are not supported */
case COPY_ABORTED:
case VOLUME_OVERFLOW:
case MISCOMPARE:
- return SUCCESS;
+ case BLANK_CHECK:
+ case DATA_PROTECT:
+ return TARGET_ERROR;
case MEDIUM_ERROR:
if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
sshdr.asc == 0x13 || /* AMNF DATA FIELD */
sshdr.asc == 0x14) { /* RECORD NOT FOUND */
- return SUCCESS;
+ return TARGET_ERROR;
}
return NEEDS_RETRY;
@@ -344,11 +346,9 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scmd->device->retry_hwerror)
return ADD_TO_MLQUEUE;
else
- return SUCCESS;
+ return TARGET_ERROR;
case ILLEGAL_REQUEST:
- case BLANK_CHECK:
- case DATA_PROTECT:
default:
return SUCCESS;
}
@@ -787,6 +787,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
case SUCCESS:
case NEEDS_RETRY:
case FAILED:
+ case TARGET_ERROR:
break;
case ADD_TO_MLQUEUE:
rtn = NEEDS_RETRY;
@@ -1469,6 +1470,14 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
rtn = scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
+ else if (rtn == TARGET_ERROR) {
+ /*
+ * Need to modify host byte to signal a
+ * permanent target failure
+ */
+ scmd->result |= (DID_TARGET_FAILURE << 16);
+ rtn = SUCCESS;
+ }
/* if rtn == FAILED, we have no sense information;
* returning FAILED will wake the error handler thread
* to collect the sense and redo the decide
@@ -1486,6 +1495,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
case RESERVATION_CONFLICT:
sdev_printk(KERN_INFO, scmd->device,
"reservation conflict\n");
+ scmd->result |= (DID_NEXUS_FAILURE << 16);
return SUCCESS; /* causes immediate i/o error */
default:
return FAILED;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index fb2bb35c62cb..2d63c8ad1442 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -667,6 +667,30 @@ void scsi_release_buffers(struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL(scsi_release_buffers);
+static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result)
+{
+ int error = 0;
+
+ switch(host_byte(result)) {
+ case DID_TRANSPORT_FAILFAST:
+ error = -ENOLINK;
+ break;
+ case DID_TARGET_FAILURE:
+ cmd->result |= (DID_OK << 16);
+ error = -EREMOTEIO;
+ break;
+ case DID_NEXUS_FAILURE:
+ cmd->result |= (DID_OK << 16);
+ error = -EBADE;
+ break;
+ default:
+ error = -EIO;
+ break;
+ }
+
+ return error;
+}
+
/*
* Function: scsi_io_completion()
*
@@ -737,7 +761,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
req->sense_len = len;
}
if (!sense_deferred)
- error = -EIO;
+ error = __scsi_error_from_host_byte(cmd, result);
}
req->resid_len = scsi_get_resid(cmd);
@@ -796,7 +820,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL)
return;
- error = -EIO;
+ error = __scsi_error_from_host_byte(cmd, result);
if (host_byte(result) == DID_RESET) {
/* Third party bus reset or reset for error recovery
@@ -843,6 +867,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
description = "Host Data Integrity Failure";
action = ACTION_FAIL;
error = -EILSEQ;
+ /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
+ } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
+ (cmd->cmnd[0] == UNMAP ||
+ cmd->cmnd[0] == WRITE_SAME_16 ||
+ cmd->cmnd[0] == WRITE_SAME)) {
+ description = "Discard failure";
+ action = ACTION_FAIL;
} else
action = ACTION_FAIL;
break;
@@ -1038,6 +1069,7 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
cmd->request = req;
cmd->cmnd = req->cmd;
+ cmd->prot_op = SCSI_PROT_NORMAL;
return cmd;
}
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 342ee1a9c41d..2a588955423a 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -45,6 +45,7 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
enum {
SCSI_DEVINFO_GLOBAL = 0,
SCSI_DEVINFO_SPI,
+ SCSI_DEVINFO_DH,
};
extern int scsi_get_device_flags(struct scsi_device *sdev,
@@ -56,6 +57,7 @@ extern int scsi_get_device_flags_keyed(struct scsi_device *sdev,
extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor,
char *model, char *strflags,
int flags, int key);
+extern int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key);
extern int scsi_dev_info_add_list(int key, const char *name);
extern int scsi_dev_info_remove_list(int key);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index f905ecb5704d..b4218390941e 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -954,6 +954,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
if (dd_size)
conn->dd_data = &conn[1];
+ mutex_init(&conn->ep_mutex);
INIT_LIST_HEAD(&conn->conn_list);
conn->transport = transport;
conn->cid = cid;
@@ -975,7 +976,6 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
spin_lock_irqsave(&connlock, flags);
list_add(&conn->conn_list, &connlist);
- conn->active = 1;
spin_unlock_irqrestore(&connlock, flags);
ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
@@ -1001,7 +1001,6 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
unsigned long flags;
spin_lock_irqsave(&connlock, flags);
- conn->active = 0;
list_del(&conn->conn_list);
spin_unlock_irqrestore(&connlock, flags);
@@ -1430,6 +1429,29 @@ release_host:
return err;
}
+static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
+ u64 ep_handle)
+{
+ struct iscsi_cls_conn *conn;
+ struct iscsi_endpoint *ep;
+
+ if (!transport->ep_disconnect)
+ return -EINVAL;
+
+ ep = iscsi_lookup_endpoint(ep_handle);
+ if (!ep)
+ return -EINVAL;
+ conn = ep->conn;
+ if (conn) {
+ mutex_lock(&conn->ep_mutex);
+ conn->ep = NULL;
+ mutex_unlock(&conn->ep_mutex);
+ }
+
+ transport->ep_disconnect(ep);
+ return 0;
+}
+
static int
iscsi_if_transport_ep(struct iscsi_transport *transport,
struct iscsi_uevent *ev, int msg_type)
@@ -1454,14 +1476,8 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
ev->u.ep_poll.timeout_ms);
break;
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
- if (!transport->ep_disconnect)
- return -EINVAL;
-
- ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
- if (!ep)
- return -EINVAL;
-
- transport->ep_disconnect(ep);
+ rc = iscsi_if_ep_disconnect(transport,
+ ev->u.ep_disconnect.ep_handle);
break;
}
return rc;
@@ -1609,12 +1625,31 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
session = iscsi_session_lookup(ev->u.b_conn.sid);
conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
- if (session && conn)
- ev->r.retcode = transport->bind_conn(session, conn,
- ev->u.b_conn.transport_eph,
- ev->u.b_conn.is_leading);
- else
+ if (conn && conn->ep)
+ iscsi_if_ep_disconnect(transport, conn->ep->id);
+
+ if (!session || !conn) {
err = -EINVAL;
+ break;
+ }
+
+ ev->r.retcode = transport->bind_conn(session, conn,
+ ev->u.b_conn.transport_eph,
+ ev->u.b_conn.is_leading);
+ if (ev->r.retcode || !transport->ep_connect)
+ break;
+
+ ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph);
+ if (ep) {
+ ep->conn = conn;
+
+ mutex_lock(&conn->ep_mutex);
+ conn->ep = ep;
+ mutex_unlock(&conn->ep_mutex);
+ } else
+ iscsi_cls_conn_printk(KERN_ERR, conn,
+ "Could not set ep conn "
+ "binding\n");
break;
case ISCSI_UEVENT_SET_PARAM:
err = iscsi_set_param(transport, ev);
@@ -1747,13 +1782,48 @@ iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
-iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
-iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
+#define iscsi_conn_ep_attr_show(param) \
+static ssize_t show_conn_ep_param_##param(struct device *dev, \
+ struct device_attribute *attr,\
+ char *buf) \
+{ \
+ struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \
+ struct iscsi_transport *t = conn->transport; \
+ struct iscsi_endpoint *ep; \
+ ssize_t rc; \
+ \
+ /* \
+ * Need to make sure ep_disconnect does not free the LLD's \
+ * interconnect resources while we are trying to read them. \
+ */ \
+ mutex_lock(&conn->ep_mutex); \
+ ep = conn->ep; \
+ if (!ep && t->ep_connect) { \
+ mutex_unlock(&conn->ep_mutex); \
+ return -ENOTCONN; \
+ } \
+ \
+ if (ep) \
+ rc = t->get_ep_param(ep, param, buf); \
+ else \
+ rc = t->get_conn_param(conn, param, buf); \
+ mutex_unlock(&conn->ep_mutex); \
+ return rc; \
+}
+
+#define iscsi_conn_ep_attr(field, param) \
+ iscsi_conn_ep_attr_show(param) \
+static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, \
+ show_conn_ep_param_##param, NULL);
+
+iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS);
+iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT);
+
/*
* iSCSI session attrs
*/
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index e56730214c05..3be5db5d6343 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -96,6 +96,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
#define SD_MINORS 0
#endif
+static void sd_config_discard(struct scsi_disk *, unsigned int);
static int sd_revalidate_disk(struct gendisk *);
static void sd_unlock_native_capacity(struct gendisk *disk);
static int sd_probe(struct device *);
@@ -294,7 +295,54 @@ sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr,
{
struct scsi_disk *sdkp = to_scsi_disk(dev);
- return snprintf(buf, 20, "%u\n", sdkp->thin_provisioning);
+ return snprintf(buf, 20, "%u\n", sdkp->lbpme);
+}
+
+static const char *lbp_mode[] = {
+ [SD_LBP_FULL] = "full",
+ [SD_LBP_UNMAP] = "unmap",
+ [SD_LBP_WS16] = "writesame_16",
+ [SD_LBP_WS10] = "writesame_10",
+ [SD_LBP_ZERO] = "writesame_zero",
+ [SD_LBP_DISABLE] = "disabled",
+};
+
+static ssize_t
+sd_show_provisioning_mode(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+ return snprintf(buf, 20, "%s\n", lbp_mode[sdkp->provisioning_mode]);
+}
+
+static ssize_t
+sd_store_provisioning_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (sdp->type != TYPE_DISK)
+ return -EINVAL;
+
+ if (!strncmp(buf, lbp_mode[SD_LBP_UNMAP], 20))
+ sd_config_discard(sdkp, SD_LBP_UNMAP);
+ else if (!strncmp(buf, lbp_mode[SD_LBP_WS16], 20))
+ sd_config_discard(sdkp, SD_LBP_WS16);
+ else if (!strncmp(buf, lbp_mode[SD_LBP_WS10], 20))
+ sd_config_discard(sdkp, SD_LBP_WS10);
+ else if (!strncmp(buf, lbp_mode[SD_LBP_ZERO], 20))
+ sd_config_discard(sdkp, SD_LBP_ZERO);
+ else if (!strncmp(buf, lbp_mode[SD_LBP_DISABLE], 20))
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ else
+ return -EINVAL;
+
+ return count;
}
static struct device_attribute sd_disk_attrs[] = {
@@ -309,6 +357,8 @@ static struct device_attribute sd_disk_attrs[] = {
__ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
__ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
__ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
+ __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode,
+ sd_store_provisioning_mode),
__ATTR_NULL,
};
@@ -433,6 +483,49 @@ static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif)
scsi_set_prot_type(scmd, dif);
}
+static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
+{
+ struct request_queue *q = sdkp->disk->queue;
+ unsigned int logical_block_size = sdkp->device->sector_size;
+ unsigned int max_blocks = 0;
+
+ q->limits.discard_zeroes_data = sdkp->lbprz;
+ q->limits.discard_alignment = sdkp->unmap_alignment;
+ q->limits.discard_granularity =
+ max(sdkp->physical_block_size,
+ sdkp->unmap_granularity * logical_block_size);
+
+ switch (mode) {
+
+ case SD_LBP_DISABLE:
+ q->limits.max_discard_sectors = 0;
+ queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
+ return;
+
+ case SD_LBP_UNMAP:
+ max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff);
+ break;
+
+ case SD_LBP_WS16:
+ max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff);
+ break;
+
+ case SD_LBP_WS10:
+ max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff);
+ break;
+
+ case SD_LBP_ZERO:
+ max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff);
+ q->limits.discard_zeroes_data = 1;
+ break;
+ }
+
+ q->limits.max_discard_sectors = max_blocks * (logical_block_size >> 9);
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+
+ sdkp->provisioning_mode = mode;
+}
+
/**
* scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device
* @sdp: scsi device to operate one
@@ -449,6 +542,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
unsigned int nr_sectors = bio_sectors(bio);
unsigned int len;
int ret;
+ char *buf;
struct page *page;
if (sdkp->device->sector_size == 4096) {
@@ -464,8 +558,9 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
if (!page)
return BLKPREP_DEFER;
- if (sdkp->unmap) {
- char *buf = page_address(page);
+ switch (sdkp->provisioning_mode) {
+ case SD_LBP_UNMAP:
+ buf = page_address(page);
rq->cmd_len = 10;
rq->cmd[0] = UNMAP;
@@ -477,7 +572,9 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
put_unaligned_be32(nr_sectors, &buf[16]);
len = 24;
- } else {
+ break;
+
+ case SD_LBP_WS16:
rq->cmd_len = 16;
rq->cmd[0] = WRITE_SAME_16;
rq->cmd[1] = 0x8; /* UNMAP */
@@ -485,11 +582,29 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
put_unaligned_be32(nr_sectors, &rq->cmd[10]);
len = sdkp->device->sector_size;
+ break;
+
+ case SD_LBP_WS10:
+ case SD_LBP_ZERO:
+ rq->cmd_len = 10;
+ rq->cmd[0] = WRITE_SAME;
+ if (sdkp->provisioning_mode == SD_LBP_WS10)
+ rq->cmd[1] = 0x8; /* UNMAP */
+ put_unaligned_be32(sector, &rq->cmd[2]);
+ put_unaligned_be16(nr_sectors, &rq->cmd[7]);
+
+ len = sdkp->device->sector_size;
+ break;
+
+ default:
+ goto out;
}
blk_add_request_payload(rq, page, len);
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
rq->buffer = page_address(page);
+
+out:
if (ret != BLKPREP_OK) {
__free_page(page);
rq->buffer = NULL;
@@ -1251,12 +1366,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
int sense_valid = 0;
int sense_deferred = 0;
+ unsigned char op = SCpnt->cmnd[0];
- if (SCpnt->request->cmd_flags & REQ_DISCARD) {
- if (!result)
- scsi_set_resid(SCpnt, 0);
- return good_bytes;
- }
+ if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result)
+ scsi_set_resid(SCpnt, 0);
if (result) {
sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
@@ -1295,10 +1408,17 @@ static int sd_done(struct scsi_cmnd *SCpnt)
SCpnt->result = 0;
memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
break;
- case ABORTED_COMMAND: /* DIF: Target detected corruption */
- case ILLEGAL_REQUEST: /* DIX: Host detected corruption */
- if (sshdr.asc == 0x10)
+ case ABORTED_COMMAND:
+ if (sshdr.asc == 0x10) /* DIF: Target detected corruption */
+ good_bytes = sd_completed_bytes(SCpnt);
+ break;
+ case ILLEGAL_REQUEST:
+ if (sshdr.asc == 0x10) /* DIX: Host detected corruption */
good_bytes = sd_completed_bytes(SCpnt);
+ /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
+ if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
+ (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME))
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
break;
default:
break;
@@ -1596,17 +1716,13 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
sd_printk(KERN_NOTICE, sdkp,
"physical block alignment offset: %u\n", alignment);
- if (buffer[14] & 0x80) { /* TPE */
- struct request_queue *q = sdp->request_queue;
+ if (buffer[14] & 0x80) { /* LBPME */
+ sdkp->lbpme = 1;
- sdkp->thin_provisioning = 1;
- q->limits.discard_granularity = sdkp->physical_block_size;
- q->limits.max_discard_sectors = 0xffffffff;
+ if (buffer[14] & 0x40) /* LBPRZ */
+ sdkp->lbprz = 1;
- if (buffer[14] & 0x40) /* TPRZ */
- q->limits.discard_zeroes_data = 1;
-
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+ sd_config_discard(sdkp, SD_LBP_WS16);
}
sdkp->capacity = lba + 1;
@@ -2091,7 +2207,6 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
*/
static void sd_read_block_limits(struct scsi_disk *sdkp)
{
- struct request_queue *q = sdkp->disk->queue;
unsigned int sector_sz = sdkp->device->sector_size;
const int vpd_len = 64;
unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
@@ -2106,39 +2221,46 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
blk_queue_io_opt(sdkp->disk->queue,
get_unaligned_be32(&buffer[12]) * sector_sz);
- /* Thin provisioning enabled and page length indicates TP support */
- if (sdkp->thin_provisioning && buffer[3] == 0x3c) {
- unsigned int lba_count, desc_count, granularity;
+ if (buffer[3] == 0x3c) {
+ unsigned int lba_count, desc_count;
- lba_count = get_unaligned_be32(&buffer[20]);
- desc_count = get_unaligned_be32(&buffer[24]);
-
- if (lba_count && desc_count) {
- if (sdkp->tpvpd && !sdkp->tpu)
- sdkp->unmap = 0;
- else
- sdkp->unmap = 1;
- }
+ sdkp->max_ws_blocks =
+ (u32) min_not_zero(get_unaligned_be64(&buffer[36]),
+ (u64)0xffffffff);
- if (sdkp->tpvpd && !sdkp->tpu && !sdkp->tpws) {
- sd_printk(KERN_ERR, sdkp, "Thin provisioning is " \
- "enabled but neither TPU, nor TPWS are " \
- "set. Disabling discard!\n");
+ if (!sdkp->lbpme)
goto out;
- }
- if (lba_count)
- q->limits.max_discard_sectors =
- lba_count * sector_sz >> 9;
+ lba_count = get_unaligned_be32(&buffer[20]);
+ desc_count = get_unaligned_be32(&buffer[24]);
- granularity = get_unaligned_be32(&buffer[28]);
+ if (lba_count && desc_count)
+ sdkp->max_unmap_blocks = lba_count;
- if (granularity)
- q->limits.discard_granularity = granularity * sector_sz;
+ sdkp->unmap_granularity = get_unaligned_be32(&buffer[28]);
if (buffer[32] & 0x80)
- q->limits.discard_alignment =
+ sdkp->unmap_alignment =
get_unaligned_be32(&buffer[32]) & ~(1 << 31);
+
+ if (!sdkp->lbpvpd) { /* LBP VPD page not provided */
+
+ if (sdkp->max_unmap_blocks)
+ sd_config_discard(sdkp, SD_LBP_UNMAP);
+ else
+ sd_config_discard(sdkp, SD_LBP_WS16);
+
+ } else { /* LBP VPD page tells us what to use */
+
+ if (sdkp->lbpu && sdkp->max_unmap_blocks)
+ sd_config_discard(sdkp, SD_LBP_UNMAP);
+ else if (sdkp->lbpws)
+ sd_config_discard(sdkp, SD_LBP_WS16);
+ else if (sdkp->lbpws10)
+ sd_config_discard(sdkp, SD_LBP_WS10);
+ else
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ }
}
out:
@@ -2172,15 +2294,15 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
}
/**
- * sd_read_thin_provisioning - Query thin provisioning VPD page
+ * sd_read_block_provisioning - Query provisioning VPD page
* @disk: disk to query
*/
-static void sd_read_thin_provisioning(struct scsi_disk *sdkp)
+static void sd_read_block_provisioning(struct scsi_disk *sdkp)
{
unsigned char *buffer;
const int vpd_len = 8;
- if (sdkp->thin_provisioning == 0)
+ if (sdkp->lbpme == 0)
return;
buffer = kmalloc(vpd_len, GFP_KERNEL);
@@ -2188,9 +2310,10 @@ static void sd_read_thin_provisioning(struct scsi_disk *sdkp)
if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len))
goto out;
- sdkp->tpvpd = 1;
- sdkp->tpu = (buffer[5] >> 7) & 1; /* UNMAP */
- sdkp->tpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */
+ sdkp->lbpvpd = 1;
+ sdkp->lbpu = (buffer[5] >> 7) & 1; /* UNMAP */
+ sdkp->lbpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */
+ sdkp->lbpws10 = (buffer[5] >> 5) & 1; /* WRITE SAME(10) with UNMAP */
out:
kfree(buffer);
@@ -2247,7 +2370,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_capacity(sdkp, buffer);
if (sd_try_extended_inquiry(sdp)) {
- sd_read_thin_provisioning(sdkp);
+ sd_read_block_provisioning(sdkp);
sd_read_block_limits(sdkp);
sd_read_block_characteristics(sdkp);
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index c9d8f6ca49e2..6ad798bfd52a 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -43,6 +43,15 @@ enum {
SD_MEMPOOL_SIZE = 2, /* CDB pool size */
};
+enum {
+ SD_LBP_FULL = 0, /* Full logical block provisioning */
+ SD_LBP_UNMAP, /* Use UNMAP command */
+ SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */
+ SD_LBP_WS10, /* Use WRITE SAME(10) with UNMAP bit */
+ SD_LBP_ZERO, /* Use WRITE SAME(10) with zero payload */
+ SD_LBP_DISABLE, /* Discard disabled due to failed cmd */
+};
+
struct scsi_disk {
struct scsi_driver *driver; /* always &sd_template */
struct scsi_device *device;
@@ -50,21 +59,27 @@ struct scsi_disk {
struct gendisk *disk;
atomic_t openers;
sector_t capacity; /* size in 512-byte sectors */
+ u32 max_ws_blocks;
+ u32 max_unmap_blocks;
+ u32 unmap_granularity;
+ u32 unmap_alignment;
u32 index;
unsigned int physical_block_size;
u8 media_present;
u8 write_prot;
u8 protection_type;/* Data Integrity Field */
+ u8 provisioning_mode;
unsigned ATO : 1; /* state of disk ATO bit */
unsigned WCE : 1; /* state of disk WCE bit */
unsigned RCD : 1; /* state of disk RCD bit, unused */
unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
unsigned first_scan : 1;
- unsigned thin_provisioning : 1;
- unsigned unmap : 1;
- unsigned tpws : 1;
- unsigned tpu : 1;
- unsigned tpvpd : 1;
+ unsigned lbpme : 1;
+ unsigned lbprz : 1;
+ unsigned lbpu : 1;
+ unsigned lbpws : 1;
+ unsigned lbpws10 : 1;
+ unsigned lbpvpd : 1;
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index cdeb01f45bc2..fc14b8dea0d7 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -167,13 +167,13 @@ config SPI_IMX_VER_0_0
def_bool y if SOC_IMX21 || SOC_IMX27
config SPI_IMX_VER_0_4
- def_bool y if ARCH_MX31
+ def_bool y if SOC_IMX31
config SPI_IMX_VER_0_7
- def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 || ARCH_MX53
+ def_bool y if ARCH_MX25 || SOC_IMX35 || SOC_IMX51 || SOC_IMX53
config SPI_IMX_VER_2_3
- def_bool y if ARCH_MX51 || ARCH_MX53
+ def_bool y if SOC_IMX51 || SOC_IMX53
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
@@ -369,6 +369,16 @@ config SPI_TEGRA
help
SPI driver for NVidia Tegra SoCs
+config SPI_TI_SSP
+ tristate "TI Sequencer Serial Port - SPI Support"
+ depends on MFD_TI_SSP
+ help
+ This selects an SPI master implementation using a TI sequencer
+ serial port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti-ssp-spi.
+
config SPI_TOPCLIFF_PCH
tristate "Topcliff PCH SPI Controller"
depends on PCI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8b5a315045a6..fd2fc5f6505f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
+obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index 14a451b2ad63..5c2b092a915e 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -2020,7 +2020,7 @@ static void pl022_cleanup(struct spi_device *spi)
static int __devinit
-pl022_probe(struct amba_device *adev, struct amba_id *id)
+pl022_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index e90c2d6a84b3..1f0ed8005c91 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -807,7 +807,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
struct resource *r, *mem;
resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
- resource_size_t dma_eventq = SPI_NO_RESOURCE;
int i = 0, ret = 0;
u32 spipc0;
@@ -895,17 +894,13 @@ static int davinci_spi_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (r)
dma_tx_chan = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (r)
- dma_eventq = r->start;
dspi->bitbang.txrx_bufs = davinci_spi_bufs;
if (dma_rx_chan != SPI_NO_RESOURCE &&
- dma_tx_chan != SPI_NO_RESOURCE &&
- dma_eventq != SPI_NO_RESOURCE) {
+ dma_tx_chan != SPI_NO_RESOURCE) {
dspi->dma.rx_channel = dma_rx_chan;
dspi->dma.tx_channel = dma_tx_chan;
- dspi->dma.eventq = dma_eventq;
+ dspi->dma.eventq = pdata->dma_event_q;
ret = davinci_spi_request_dma(dspi);
if (ret)
@@ -914,7 +909,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "DMA: supported\n");
dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, "
"event queue: %d\n", dma_rx_chan, dma_tx_chan,
- dma_eventq);
+ pdata->dma_event_q);
}
dspi->get_rx = davinci_spi_rx_buf_u8;
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 6a982a25b7c3..3a5ed06d3d2f 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2005, 2006 Nokia Corporation
* Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
- * Juha Yrjölä <juha.yrjola@nokia.com>
+ * Juha Yrj�l� <juha.yrjola@nokia.com>
*
* 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
@@ -33,6 +33,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -46,7 +47,6 @@
#define OMAP2_MCSPI_MAX_CTRL 4
#define OMAP2_MCSPI_REVISION 0x00
-#define OMAP2_MCSPI_SYSCONFIG 0x10
#define OMAP2_MCSPI_SYSSTATUS 0x14
#define OMAP2_MCSPI_IRQSTATUS 0x18
#define OMAP2_MCSPI_IRQENABLE 0x1c
@@ -63,13 +63,6 @@
/* per-register bitmasks: */
-#define OMAP2_MCSPI_SYSCONFIG_SMARTIDLE BIT(4)
-#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
-#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE BIT(0)
-#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET BIT(1)
-
-#define OMAP2_MCSPI_SYSSTATUS_RESETDONE BIT(0)
-
#define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0)
#define OMAP2_MCSPI_MODULCTRL_MS BIT(2)
#define OMAP2_MCSPI_MODULCTRL_STEST BIT(3)
@@ -122,13 +115,12 @@ struct omap2_mcspi {
spinlock_t lock;
struct list_head msg_queue;
struct spi_master *master;
- struct clk *ick;
- struct clk *fck;
/* Virtual base address of the controller */
void __iomem *base;
unsigned long phys;
/* SPI1 has 4 channels, while SPI2 has 2 */
struct omap2_mcspi_dma *dma_channels;
+ struct device *dev;
};
struct omap2_mcspi_cs {
@@ -144,7 +136,6 @@ struct omap2_mcspi_cs {
* corresponding registers are modified.
*/
struct omap2_mcspi_regs {
- u32 sysconfig;
u32 modulctrl;
u32 wakeupenable;
struct list_head cs;
@@ -268,9 +259,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL,
omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl);
- mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG,
- omap2_mcspi_ctx[spi_cntrl->bus_num - 1].sysconfig);
-
mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE,
omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable);
@@ -280,20 +268,12 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
}
static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
{
- clk_disable(mcspi->ick);
- clk_disable(mcspi->fck);
+ pm_runtime_put_sync(mcspi->dev);
}
static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
{
- if (clk_enable(mcspi->ick))
- return -ENODEV;
- if (clk_enable(mcspi->fck))
- return -ENODEV;
-
- omap2_mcspi_restore_ctx(mcspi);
-
- return 0;
+ return pm_runtime_get_sync(mcspi->dev);
}
static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
@@ -829,8 +809,9 @@ static int omap2_mcspi_setup(struct spi_device *spi)
return ret;
}
- if (omap2_mcspi_enable_clocks(mcspi))
- return -ENODEV;
+ ret = omap2_mcspi_enable_clocks(mcspi);
+ if (ret < 0)
+ return ret;
ret = omap2_mcspi_setup_transfer(spi, NULL);
omap2_mcspi_disable_clocks(mcspi);
@@ -873,10 +854,11 @@ static void omap2_mcspi_work(struct work_struct *work)
struct omap2_mcspi *mcspi;
mcspi = container_of(work, struct omap2_mcspi, work);
- spin_lock_irq(&mcspi->lock);
- if (omap2_mcspi_enable_clocks(mcspi))
- goto out;
+ if (omap2_mcspi_enable_clocks(mcspi) < 0)
+ return;
+
+ spin_lock_irq(&mcspi->lock);
/* We only enable one channel at a time -- the one whose message is
* at the head of the queue -- although this controller would gladly
@@ -989,10 +971,9 @@ static void omap2_mcspi_work(struct work_struct *work)
spin_lock_irq(&mcspi->lock);
}
- omap2_mcspi_disable_clocks(mcspi);
-
-out:
spin_unlock_irq(&mcspi->lock);
+
+ omap2_mcspi_disable_clocks(mcspi);
}
static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
@@ -1068,25 +1049,15 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
return 0;
}
-static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
+static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
{
struct spi_master *master = mcspi->master;
u32 tmp;
+ int ret = 0;
- if (omap2_mcspi_enable_clocks(mcspi))
- return -1;
-
- mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
- OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
- do {
- tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS);
- } while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
-
- tmp = OMAP2_MCSPI_SYSCONFIG_AUTOIDLE |
- OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP |
- OMAP2_MCSPI_SYSCONFIG_SMARTIDLE;
- mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, tmp);
- omap2_mcspi_ctx[master->bus_num - 1].sysconfig = tmp;
+ ret = omap2_mcspi_enable_clocks(mcspi);
+ if (ret < 0)
+ return ret;
tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp);
@@ -1097,91 +1068,26 @@ static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
return 0;
}
-static u8 __initdata spi1_rxdma_id [] = {
- OMAP24XX_DMA_SPI1_RX0,
- OMAP24XX_DMA_SPI1_RX1,
- OMAP24XX_DMA_SPI1_RX2,
- OMAP24XX_DMA_SPI1_RX3,
-};
-
-static u8 __initdata spi1_txdma_id [] = {
- OMAP24XX_DMA_SPI1_TX0,
- OMAP24XX_DMA_SPI1_TX1,
- OMAP24XX_DMA_SPI1_TX2,
- OMAP24XX_DMA_SPI1_TX3,
-};
-
-static u8 __initdata spi2_rxdma_id[] = {
- OMAP24XX_DMA_SPI2_RX0,
- OMAP24XX_DMA_SPI2_RX1,
-};
-
-static u8 __initdata spi2_txdma_id[] = {
- OMAP24XX_DMA_SPI2_TX0,
- OMAP24XX_DMA_SPI2_TX1,
-};
-
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
- || defined(CONFIG_ARCH_OMAP4)
-static u8 __initdata spi3_rxdma_id[] = {
- OMAP24XX_DMA_SPI3_RX0,
- OMAP24XX_DMA_SPI3_RX1,
-};
+static int omap_mcspi_runtime_resume(struct device *dev)
+{
+ struct omap2_mcspi *mcspi;
+ struct spi_master *master;
-static u8 __initdata spi3_txdma_id[] = {
- OMAP24XX_DMA_SPI3_TX0,
- OMAP24XX_DMA_SPI3_TX1,
-};
-#endif
+ master = dev_get_drvdata(dev);
+ mcspi = spi_master_get_devdata(master);
+ omap2_mcspi_restore_ctx(mcspi);
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-static u8 __initdata spi4_rxdma_id[] = {
- OMAP34XX_DMA_SPI4_RX0,
-};
+ return 0;
+}
-static u8 __initdata spi4_txdma_id[] = {
- OMAP34XX_DMA_SPI4_TX0,
-};
-#endif
static int __init omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
+ struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data;
struct omap2_mcspi *mcspi;
struct resource *r;
int status = 0, i;
- const u8 *rxdma_id, *txdma_id;
- unsigned num_chipselect;
-
- switch (pdev->id) {
- case 1:
- rxdma_id = spi1_rxdma_id;
- txdma_id = spi1_txdma_id;
- num_chipselect = 4;
- break;
- case 2:
- rxdma_id = spi2_rxdma_id;
- txdma_id = spi2_txdma_id;
- num_chipselect = 2;
- break;
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
- || defined(CONFIG_ARCH_OMAP4)
- case 3:
- rxdma_id = spi3_rxdma_id;
- txdma_id = spi3_txdma_id;
- num_chipselect = 2;
- break;
-#endif
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
- case 4:
- rxdma_id = spi4_rxdma_id;
- txdma_id = spi4_txdma_id;
- num_chipselect = 1;
- break;
-#endif
- default:
- return -EINVAL;
- }
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
if (master == NULL) {
@@ -1198,7 +1104,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
master->setup = omap2_mcspi_setup;
master->transfer = omap2_mcspi_transfer;
master->cleanup = omap2_mcspi_cleanup;
- master->num_chipselect = num_chipselect;
+ master->num_chipselect = pdata->num_cs;
dev_set_drvdata(&pdev->dev, master);
@@ -1216,49 +1122,62 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
goto err1;
}
+ r->start += pdata->regs_offset;
+ r->end += pdata->regs_offset;
mcspi->phys = r->start;
mcspi->base = ioremap(r->start, r->end - r->start + 1);
if (!mcspi->base) {
dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
status = -ENOMEM;
- goto err1aa;
+ goto err2;
}
+ mcspi->dev = &pdev->dev;
INIT_WORK(&mcspi->work, omap2_mcspi_work);
spin_lock_init(&mcspi->lock);
INIT_LIST_HEAD(&mcspi->msg_queue);
INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs);
- mcspi->ick = clk_get(&pdev->dev, "ick");
- if (IS_ERR(mcspi->ick)) {
- dev_dbg(&pdev->dev, "can't get mcspi_ick\n");
- status = PTR_ERR(mcspi->ick);
- goto err1a;
- }
- mcspi->fck = clk_get(&pdev->dev, "fck");
- if (IS_ERR(mcspi->fck)) {
- dev_dbg(&pdev->dev, "can't get mcspi_fck\n");
- status = PTR_ERR(mcspi->fck);
- goto err2;
- }
-
mcspi->dma_channels = kcalloc(master->num_chipselect,
sizeof(struct omap2_mcspi_dma),
GFP_KERNEL);
if (mcspi->dma_channels == NULL)
- goto err3;
+ goto err2;
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ char dma_ch_name[14];
+ struct resource *dma_res;
+
+ sprintf(dma_ch_name, "rx%d", i);
+ dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+ dma_ch_name);
+ if (!dma_res) {
+ dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
+ status = -ENODEV;
+ break;
+ }
- for (i = 0; i < num_chipselect; i++) {
mcspi->dma_channels[i].dma_rx_channel = -1;
- mcspi->dma_channels[i].dma_rx_sync_dev = rxdma_id[i];
+ mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
+ sprintf(dma_ch_name, "tx%d", i);
+ dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+ dma_ch_name);
+ if (!dma_res) {
+ dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
+ status = -ENODEV;
+ break;
+ }
+
mcspi->dma_channels[i].dma_tx_channel = -1;
- mcspi->dma_channels[i].dma_tx_sync_dev = txdma_id[i];
+ mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
}
- if (omap2_mcspi_reset(mcspi) < 0)
- goto err4;
+ pm_runtime_enable(&pdev->dev);
+
+ if (status || omap2_mcspi_master_setup(mcspi) < 0)
+ goto err3;
status = spi_register_master(master);
if (status < 0)
@@ -1267,17 +1186,13 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
return status;
err4:
- kfree(mcspi->dma_channels);
+ spi_master_put(master);
err3:
- clk_put(mcspi->fck);
+ kfree(mcspi->dma_channels);
err2:
- clk_put(mcspi->ick);
-err1a:
- iounmap(mcspi->base);
-err1aa:
release_mem_region(r->start, (r->end - r->start) + 1);
+ iounmap(mcspi->base);
err1:
- spi_master_put(master);
return status;
}
@@ -1293,9 +1208,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
mcspi = spi_master_get_devdata(master);
dma_channels = mcspi->dma_channels;
- clk_put(mcspi->fck);
- clk_put(mcspi->ick);
-
+ omap2_mcspi_disable_clocks(mcspi);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, (r->end - r->start) + 1);
@@ -1346,6 +1259,7 @@ static int omap2_mcspi_resume(struct device *dev)
static const struct dev_pm_ops omap2_mcspi_pm_ops = {
.resume = omap2_mcspi_resume,
+ .runtime_resume = omap_mcspi_runtime_resume,
};
static struct platform_driver omap2_mcspi_driver = {
diff --git a/drivers/spi/ti-ssp-spi.c b/drivers/spi/ti-ssp-spi.c
new file mode 100644
index 000000000000..ee22795c7973
--- /dev/null
+++ b/drivers/spi/ti-ssp-spi.c
@@ -0,0 +1,402 @@
+/*
+ * Sequencer Serial Port (SSP) based SPI master driver
+ *
+ * Copyright (C) 2010 Texas Instruments 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/ti_ssp.h>
+
+#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
+
+struct ti_ssp_spi {
+ struct spi_master *master;
+ struct device *dev;
+ spinlock_t lock;
+ struct list_head msg_queue;
+ struct completion complete;
+ bool shutdown;
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+ u8 mode, bpw;
+ int cs_active;
+ u32 pc_en, pc_dis, pc_wr, pc_rd;
+ void (*select)(int cs);
+};
+
+static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
+{
+ u32 ret;
+
+ ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
+ return ret;
+}
+
+static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
+{
+ ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
+}
+
+static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
+ struct spi_transfer *t)
+{
+ int count;
+
+ if (hw->bpw <= 8) {
+ u8 *rx = t->rx_buf;
+ const u8 *tx = t->tx_buf;
+
+ for (count = 0; count < t->len; count += 1) {
+ if (t->tx_buf)
+ ti_ssp_spi_tx(hw, *tx++);
+ if (t->rx_buf)
+ *rx++ = ti_ssp_spi_rx(hw);
+ }
+ } else if (hw->bpw <= 16) {
+ u16 *rx = t->rx_buf;
+ const u16 *tx = t->tx_buf;
+
+ for (count = 0; count < t->len; count += 2) {
+ if (t->tx_buf)
+ ti_ssp_spi_tx(hw, *tx++);
+ if (t->rx_buf)
+ *rx++ = ti_ssp_spi_rx(hw);
+ }
+ } else {
+ u32 *rx = t->rx_buf;
+ const u32 *tx = t->tx_buf;
+
+ for (count = 0; count < t->len; count += 4) {
+ if (t->tx_buf)
+ ti_ssp_spi_tx(hw, *tx++);
+ if (t->rx_buf)
+ *rx++ = ti_ssp_spi_rx(hw);
+ }
+ }
+
+ msg->actual_length += count; /* bytes transferred */
+
+ dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
+ t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
+ hw->bpw, count, (count < t->len) ? " (under)" : "");
+
+ return (count < t->len) ? -EIO : 0; /* left over data */
+}
+
+static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
+{
+ cs_active = !!cs_active;
+ if (cs_active == hw->cs_active)
+ return;
+ ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
+ hw->cs_active = cs_active;
+}
+
+#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
+ cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
+ cs_en | clk | SSP_COUNT((bits) * 2 - 1))
+
+static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
+{
+ int error, idx = 0;
+ u32 seqram[16];
+ u32 cs_en, cs_dis, clk;
+ u32 topbits, botbits;
+
+ mode &= MODE_BITS;
+ if (mode == hw->mode && bpw == hw->bpw)
+ return 0;
+
+ cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
+ cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
+ clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
+
+ /* Construct instructions */
+
+ /* Disable Chip Select */
+ hw->pc_dis = idx;
+ seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
+ seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
+
+ /* Enable Chip Select */
+ hw->pc_en = idx;
+ seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
+ seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
+
+ /* Reads and writes need to be split for bpw > 16 */
+ topbits = (bpw > 16) ? 16 : bpw;
+ botbits = bpw - topbits;
+
+ /* Write */
+ hw->pc_wr = idx;
+ seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
+ if (botbits)
+ seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
+ seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
+
+ /* Read */
+ hw->pc_rd = idx;
+ if (botbits)
+ seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
+ seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
+ seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
+
+ error = ti_ssp_load(hw->dev, 0, seqram, idx);
+ if (error < 0)
+ return error;
+
+ error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
+ 0 : SSP_EARLY_DIN));
+ if (error < 0)
+ return error;
+
+ hw->bpw = bpw;
+ hw->mode = mode;
+
+ return error;
+}
+
+static void ti_ssp_spi_work(struct work_struct *work)
+{
+ struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
+
+ spin_lock(&hw->lock);
+
+ while (!list_empty(&hw->msg_queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+
+ m = container_of(hw->msg_queue.next, struct spi_message,
+ queue);
+
+ list_del_init(&m->queue);
+
+ spin_unlock(&hw->lock);
+
+ spi = m->spi;
+
+ if (hw->select)
+ hw->select(spi->chip_select);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ int bpw = spi->bits_per_word;
+ int xfer_status;
+
+ if (t->bits_per_word)
+ bpw = t->bits_per_word;
+
+ if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
+ break;
+
+ ti_ssp_spi_chip_select(hw, 1);
+
+ xfer_status = ti_ssp_spi_txrx(hw, m, t);
+ if (xfer_status < 0)
+ status = xfer_status;
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (t->cs_change)
+ ti_ssp_spi_chip_select(hw, 0);
+ }
+
+ ti_ssp_spi_chip_select(hw, 0);
+ m->status = status;
+ m->complete(m->context);
+
+ spin_lock(&hw->lock);
+ }
+
+ if (hw->shutdown)
+ complete(&hw->complete);
+
+ spin_unlock(&hw->lock);
+}
+
+static int ti_ssp_spi_setup(struct spi_device *spi)
+{
+ if (spi->bits_per_word > 32)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct ti_ssp_spi *hw;
+ struct spi_transfer *t;
+ int error = 0;
+
+ m->actual_length = 0;
+ m->status = -EINPROGRESS;
+
+ hw = spi_master_get_devdata(spi->master);
+
+ if (list_empty(&m->transfers) || !m->complete)
+ return -EINVAL;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->len && !(t->rx_buf || t->tx_buf)) {
+ dev_err(&spi->dev, "invalid xfer, no buffer\n");
+ return -EINVAL;
+ }
+
+ if (t->len && t->rx_buf && t->tx_buf) {
+ dev_err(&spi->dev, "invalid xfer, full duplex\n");
+ return -EINVAL;
+ }
+
+ if (t->bits_per_word > 32) {
+ dev_err(&spi->dev, "invalid xfer width %d\n",
+ t->bits_per_word);
+ return -EINVAL;
+ }
+ }
+
+ spin_lock(&hw->lock);
+ if (hw->shutdown) {
+ error = -ESHUTDOWN;
+ goto error_unlock;
+ }
+ list_add_tail(&m->queue, &hw->msg_queue);
+ queue_work(hw->workqueue, &hw->work);
+error_unlock:
+ spin_unlock(&hw->lock);
+ return error;
+}
+
+static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
+{
+ const struct ti_ssp_spi_data *pdata;
+ struct ti_ssp_spi *hw;
+ struct spi_master *master;
+ struct device *dev = &pdev->dev;
+ int error = 0;
+
+ pdata = dev->platform_data;
+ if (!pdata) {
+ dev_err(dev, "platform data not found\n");
+ return -EINVAL;
+ }
+
+ master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
+ if (!master) {
+ dev_err(dev, "cannot allocate SPI master\n");
+ return -ENOMEM;
+ }
+
+ hw = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, hw);
+
+ hw->master = master;
+ hw->dev = dev;
+ hw->select = pdata->select;
+
+ spin_lock_init(&hw->lock);
+ init_completion(&hw->complete);
+ INIT_LIST_HEAD(&hw->msg_queue);
+ INIT_WORK(&hw->work, ti_ssp_spi_work);
+
+ hw->workqueue = create_singlethread_workqueue(dev_name(dev));
+ if (!hw->workqueue) {
+ error = -ENOMEM;
+ dev_err(dev, "work queue creation failed\n");
+ goto error_wq;
+ }
+
+ error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
+ if (error < 0) {
+ dev_err(dev, "io setup failed\n");
+ goto error_iosel;
+ }
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = pdata->num_cs;
+ master->mode_bits = MODE_BITS;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = ti_ssp_spi_setup;
+ master->transfer = ti_ssp_spi_transfer;
+
+ error = spi_register_master(master);
+ if (error) {
+ dev_err(dev, "master registration failed\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+error_reg:
+error_iosel:
+ destroy_workqueue(hw->workqueue);
+error_wq:
+ spi_master_put(master);
+ return error;
+}
+
+static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
+{
+ struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
+ int error;
+
+ hw->shutdown = 1;
+ while (!list_empty(&hw->msg_queue)) {
+ error = wait_for_completion_interruptible(&hw->complete);
+ if (error < 0) {
+ hw->shutdown = 0;
+ return error;
+ }
+ }
+ destroy_workqueue(hw->workqueue);
+ spi_unregister_master(hw->master);
+
+ return 0;
+}
+
+static struct platform_driver ti_ssp_spi_driver = {
+ .probe = ti_ssp_spi_probe,
+ .remove = __devexit_p(ti_ssp_spi_remove),
+ .driver = {
+ .name = "ti-ssp-spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ti_ssp_spi_init(void)
+{
+ return platform_driver_register(&ti_ssp_spi_driver);
+}
+module_init(ti_ssp_spi_init);
+
+static void __exit ti_ssp_spi_exit(void)
+{
+ platform_driver_unregister(&ti_ssp_spi_driver);
+}
+module_exit(ti_ssp_spi_exit);
+
+MODULE_DESCRIPTION("SSP SPI Master");
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ti-ssp-spi");
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 366080baf474..7f19c8b7b84c 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -667,7 +667,13 @@ target_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = SE_DEV(cmd);
unsigned char *buf = cmd->t_task->t_task_buf;
- u32 blocks = dev->transport->get_blocks(dev);
+ unsigned long long blocks_long = dev->transport->get_blocks(dev);
+ u32 blocks;
+
+ if (blocks_long >= 0x00000000ffffffff)
+ blocks = 0xffffffff;
+ else
+ blocks = (u32)blocks_long;
buf[0] = (blocks >> 24) & 0xff;
buf[1] = (blocks >> 16) & 0xff;
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
index 73f7d6d81b4c..6ec51cbc018e 100644
--- a/drivers/target/target_core_hba.c
+++ b/drivers/target/target_core_hba.c
@@ -37,7 +37,6 @@
#include <target/target_core_base.h>
#include <target/target_core_device.h>
-#include <target/target_core_device.h>
#include <target/target_core_tpg.h>
#include <target/target_core_transport.h>
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 3740e327f180..c35f1a73bc8b 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -177,6 +177,8 @@ static int __init xen_hvc_init(void)
}
if (xencons_irq < 0)
xencons_irq = 0; /* NO_IRQ */
+ else
+ set_irq_noprobe(xencons_irq);
hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256);
if (IS_ERR(hp))
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index bedc6c1b6fa5..bef238f9ffd7 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -292,7 +292,7 @@ struct hvcs_struct {
/*
* Any variable below the kref is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
- * whacked until the koject refcount reaches zero though some entries
+ * whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
struct kref kref; /* ref count & hvcs_struct lifetime */
@@ -309,6 +309,7 @@ struct hvcs_struct {
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
+static DEFINE_MUTEX(hvcs_init_mutex);
static void hvcs_unthrottle(struct tty_struct *tty);
static void hvcs_throttle(struct tty_struct *tty);
@@ -340,6 +341,7 @@ static int __devinit hvcs_probe(struct vio_dev *dev,
static int __devexit hvcs_remove(struct vio_dev *dev);
static int __init hvcs_module_init(void);
static void __exit hvcs_module_exit(void);
+static int __devinit hvcs_initialize(void);
#define HVCS_SCHED_READ 0x00000001
#define HVCS_QUICK_READ 0x00000002
@@ -762,7 +764,7 @@ static int __devinit hvcs_probe(
const struct vio_device_id *id)
{
struct hvcs_struct *hvcsd;
- int index;
+ int index, rc;
int retval;
if (!dev || !id) {
@@ -770,6 +772,13 @@ static int __devinit hvcs_probe(
return -EPERM;
}
+ /* Make sure we are properly initialized */
+ rc = hvcs_initialize();
+ if (rc) {
+ pr_err("HVCS: Failed to initialize core driver.\n");
+ return rc;
+ }
+
/* early to avoid cleanup on failure */
index = hvcs_get_index();
if (index < 0) {
@@ -1464,12 +1473,15 @@ static void hvcs_free_index_list(void)
hvcs_index_count = 0;
}
-static int __init hvcs_module_init(void)
+static int __devinit hvcs_initialize(void)
{
- int rc;
- int num_ttys_to_alloc;
+ int rc, num_ttys_to_alloc;
- printk(KERN_INFO "Initializing %s\n", hvcs_driver_string);
+ mutex_lock(&hvcs_init_mutex);
+ if (hvcs_task) {
+ mutex_unlock(&hvcs_init_mutex);
+ return 0;
+ }
/* Has the user specified an overload with an insmod param? */
if (hvcs_parm_num_devs <= 0 ||
@@ -1528,35 +1540,13 @@ static int __init hvcs_module_init(void)
hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
if (IS_ERR(hvcs_task)) {
- printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n");
+ printk(KERN_ERR "HVCS: khvcsd creation failed.\n");
rc = -EIO;
goto kthread_fail;
}
-
- rc = vio_register_driver(&hvcs_vio_driver);
- if (rc) {
- printk(KERN_ERR "HVCS: can't register vio driver\n");
- goto vio_fail;
- }
-
- /*
- * This needs to be done AFTER the vio_register_driver() call or else
- * the kobjects won't be initialized properly.
- */
- rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
- if (rc) {
- printk(KERN_ERR "HVCS: sysfs attr create failed\n");
- goto attr_fail;
- }
-
- printk(KERN_INFO "HVCS: driver module inserted.\n");
-
+ mutex_unlock(&hvcs_init_mutex);
return 0;
-attr_fail:
- vio_unregister_driver(&hvcs_vio_driver);
-vio_fail:
- kthread_stop(hvcs_task);
kthread_fail:
kfree(hvcs_pi_buff);
buff_alloc_fail:
@@ -1566,15 +1556,39 @@ register_fail:
index_fail:
put_tty_driver(hvcs_tty_driver);
hvcs_tty_driver = NULL;
+ mutex_unlock(&hvcs_init_mutex);
return rc;
}
+static int __init hvcs_module_init(void)
+{
+ int rc = vio_register_driver(&hvcs_vio_driver);
+ if (rc) {
+ printk(KERN_ERR "HVCS: can't register vio driver\n");
+ return rc;
+ }
+
+ pr_info("HVCS: Driver registered.\n");
+
+ /* This needs to be done AFTER the vio_register_driver() call or else
+ * the kobjects won't be initialized properly.
+ */
+ rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
+ if (rc)
+ pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc);
+
+ return 0;
+}
+
static void __exit hvcs_module_exit(void)
{
/*
* This driver receives hvcs_remove callbacks for each device upon
* module removal.
*/
+ vio_unregister_driver(&hvcs_vio_driver);
+ if (!hvcs_task)
+ return;
/*
* This synchronous operation will wake the khvcsd kthread if it is
@@ -1589,8 +1603,6 @@ static void __exit hvcs_module_exit(void)
driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
- vio_unregister_driver(&hvcs_vio_driver);
-
tty_unregister_driver(hvcs_tty_driver);
hvcs_free_index_list();
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index e461be164f67..e1aee37270f5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -537,8 +537,8 @@ config SERIAL_S3C6400
config SERIAL_S5PV210
tristate "Samsung S5PV210 Serial port support"
- depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310)
- select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310)
+ depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_EXYNOS4210)
+ select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210)
default y
help
Serial port support for Samsung's S5P Family of SoC's
@@ -1598,4 +1598,18 @@ config SERIAL_MSM_SMD
Enables userspace clients to read and write to some streaming SMD
ports via tty device interface for MSM chipset.
+config SERIAL_MXS_AUART
+ depends on ARCH_MXS
+ tristate "MXS AUART support"
+ select SERIAL_CORE
+ help
+ This driver supports the MXS Application UART (AUART) port.
+
+config SERIAL_MXS_AUART_CONSOLE
+ bool "MXS AUART console support"
+ depends on SERIAL_MXS_AUART=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Enable a MXS AUART port to be the system console.
+
endmenu
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 31e868cb49b2..fee0690ef8e3 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -93,3 +93,4 @@ obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
+obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 2904aa044126..d742dd2c525c 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -676,7 +676,7 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE,
};
-static int pl010_probe(struct amba_device *dev, struct amba_id *id)
+static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
void __iomem *base;
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e76d7d000128..57731e870085 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -96,6 +96,22 @@ static struct vendor_data vendor_st = {
};
/* Deals with DMA transactions */
+
+struct pl011_sgbuf {
+ struct scatterlist sg;
+ char *buf;
+};
+
+struct pl011_dmarx_data {
+ struct dma_chan *chan;
+ struct completion complete;
+ bool use_buf_b;
+ struct pl011_sgbuf sgbuf_a;
+ struct pl011_sgbuf sgbuf_b;
+ dma_cookie_t cookie;
+ bool running;
+};
+
struct pl011_dmatx_data {
struct dma_chan *chan;
struct scatterlist sg;
@@ -120,12 +136,70 @@ struct uart_amba_port {
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
- bool using_dma;
+ bool using_tx_dma;
+ bool using_rx_dma;
+ struct pl011_dmarx_data dmarx;
struct pl011_dmatx_data dmatx;
#endif
};
/*
+ * Reads up to 256 characters from the FIFO or until it's empty and
+ * inserts them into the TTY layer. Returns the number of characters
+ * read from the FIFO.
+ */
+static int pl011_fifo_to_tty(struct uart_amba_port *uap)
+{
+ u16 status, ch;
+ unsigned int flag, max_count = 256;
+ int fifotaken = 0;
+
+ while (max_count--) {
+ status = readw(uap->port.membase + UART01x_FR);
+ if (status & UART01x_FR_RXFE)
+ break;
+
+ /* Take chars from the FIFO and update status */
+ ch = readw(uap->port.membase + UART01x_DR) |
+ UART_DUMMY_DR_RX;
+ flag = TTY_NORMAL;
+ uap->port.icount.rx++;
+ fifotaken++;
+
+ if (unlikely(ch & UART_DR_ERROR)) {
+ if (ch & UART011_DR_BE) {
+ ch &= ~(UART011_DR_FE | UART011_DR_PE);
+ uap->port.icount.brk++;
+ if (uart_handle_break(&uap->port))
+ continue;
+ } else if (ch & UART011_DR_PE)
+ uap->port.icount.parity++;
+ else if (ch & UART011_DR_FE)
+ uap->port.icount.frame++;
+ if (ch & UART011_DR_OE)
+ uap->port.icount.overrun++;
+
+ ch &= uap->port.read_status_mask;
+
+ if (ch & UART011_DR_BE)
+ flag = TTY_BREAK;
+ else if (ch & UART011_DR_PE)
+ flag = TTY_PARITY;
+ else if (ch & UART011_DR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(&uap->port, ch & 255))
+ continue;
+
+ uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+ }
+
+ return fifotaken;
+}
+
+
+/*
* All the DMA operation mode stuff goes inside this ifdef.
* This assumes that you have a generic DMA device interface,
* no custom DMA interfaces are supported.
@@ -134,6 +208,31 @@ struct uart_amba_port {
#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
+ enum dma_data_direction dir)
+{
+ sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!sg->buf)
+ return -ENOMEM;
+
+ sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
+
+ if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
+ kfree(sg->buf);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
+ enum dma_data_direction dir)
+{
+ if (sg->buf) {
+ dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
+ kfree(sg->buf);
+ }
+}
+
static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
{
/* DMA is the sole user of the platform data right now */
@@ -153,7 +252,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
return;
}
- /* Try to acquire a generic DMA engine slave channel */
+ /* Try to acquire a generic DMA engine slave TX channel */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -168,6 +267,28 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
dev_info(uap->port.dev, "DMA channel TX %s\n",
dma_chan_name(uap->dmatx.chan));
+
+ /* Optionally make use of an RX channel as well */
+ if (plat->dma_rx_param) {
+ struct dma_slave_config rx_conf = {
+ .src_addr = uap->port.mapbase + UART01x_DR,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+ .direction = DMA_FROM_DEVICE,
+ .src_maxburst = uap->fifosize >> 1,
+ };
+
+ chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
+ if (!chan) {
+ dev_err(uap->port.dev, "no RX DMA channel!\n");
+ return;
+ }
+
+ dmaengine_slave_config(chan, &rx_conf);
+ uap->dmarx.chan = chan;
+
+ dev_info(uap->port.dev, "DMA channel RX %s\n",
+ dma_chan_name(uap->dmarx.chan));
+ }
}
#ifndef MODULE
@@ -219,9 +340,10 @@ static void pl011_dma_remove(struct uart_amba_port *uap)
/* TODO: remove the initcall if it has not yet executed */
if (uap->dmatx.chan)
dma_release_channel(uap->dmatx.chan);
+ if (uap->dmarx.chan)
+ dma_release_channel(uap->dmarx.chan);
}
-
/* Forward declare this for the refill routine */
static int pl011_dma_tx_refill(struct uart_amba_port *uap);
@@ -380,7 +502,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
*/
static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
{
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return false;
/*
@@ -432,7 +554,7 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
{
u16 dmacr;
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return false;
if (!uap->port.x_char) {
@@ -492,7 +614,7 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return;
/* Avoid deadlock with the DMA engine callback */
@@ -508,9 +630,219 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
}
}
+static void pl011_dma_rx_callback(void *data);
+
+static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
+{
+ struct dma_chan *rxchan = uap->dmarx.chan;
+ struct dma_device *dma_dev;
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ struct dma_async_tx_descriptor *desc;
+ struct pl011_sgbuf *sgbuf;
+
+ if (!rxchan)
+ return -EIO;
+
+ /* Start the RX DMA job */
+ sgbuf = uap->dmarx.use_buf_b ?
+ &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
+ dma_dev = rxchan->device;
+ desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ /*
+ * If the DMA engine is busy and cannot prepare a
+ * channel, no big deal, the driver will fall back
+ * to interrupt mode as a result of this error code.
+ */
+ if (!desc) {
+ uap->dmarx.running = false;
+ dmaengine_terminate_all(rxchan);
+ return -EBUSY;
+ }
+
+ /* Some data to go along to the callback */
+ desc->callback = pl011_dma_rx_callback;
+ desc->callback_param = uap;
+ dmarx->cookie = dmaengine_submit(desc);
+ dma_async_issue_pending(rxchan);
+
+ uap->dmacr |= UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->dmarx.running = true;
+
+ uap->im &= ~UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ return 0;
+}
+
+/*
+ * This is called when either the DMA job is complete, or
+ * the FIFO timeout interrupt occurred. This must be called
+ * with the port spinlock uap->port.lock held.
+ */
+static void pl011_dma_rx_chars(struct uart_amba_port *uap,
+ u32 pending, bool use_buf_b,
+ bool readfifo)
+{
+ struct tty_struct *tty = uap->port.state->port.tty;
+ struct pl011_sgbuf *sgbuf = use_buf_b ?
+ &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
+ struct device *dev = uap->dmarx.chan->device->dev;
+ int dma_count = 0;
+ u32 fifotaken = 0; /* only used for vdbg() */
+
+ /* Pick everything from the DMA first */
+ if (pending) {
+ /* Sync in buffer */
+ dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
+
+ /*
+ * First take all chars in the DMA pipe, then look in the FIFO.
+ * Note that tty_insert_flip_buf() tries to take as many chars
+ * as it can.
+ */
+ dma_count = tty_insert_flip_string(uap->port.state->port.tty,
+ sgbuf->buf, pending);
+
+ /* Return buffer to device */
+ dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
+
+ uap->port.icount.rx += dma_count;
+ if (dma_count < pending)
+ dev_warn(uap->port.dev,
+ "couldn't insert all characters (TTY is full?)\n");
+ }
+
+ /*
+ * Only continue with trying to read the FIFO if all DMA chars have
+ * been taken first.
+ */
+ if (dma_count == pending && readfifo) {
+ /* Clear any error flags */
+ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
+ uap->port.membase + UART011_ICR);
+
+ /*
+ * If we read all the DMA'd characters, and we had an
+ * incomplete buffer, that could be due to an rx error, or
+ * maybe we just timed out. Read any pending chars and check
+ * the error status.
+ *
+ * Error conditions will only occur in the FIFO, these will
+ * trigger an immediate interrupt and stop the DMA job, so we
+ * will always find the error in the FIFO, never in the DMA
+ * buffer.
+ */
+ fifotaken = pl011_fifo_to_tty(uap);
+ }
+
+ spin_unlock(&uap->port.lock);
+ dev_vdbg(uap->port.dev,
+ "Took %d chars from DMA buffer and %d chars from the FIFO\n",
+ dma_count, fifotaken);
+ tty_flip_buffer_push(tty);
+ spin_lock(&uap->port.lock);
+}
+
+static void pl011_dma_rx_irq(struct uart_amba_port *uap)
+{
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ struct dma_chan *rxchan = dmarx->chan;
+ struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
+ &dmarx->sgbuf_b : &dmarx->sgbuf_a;
+ size_t pending;
+ struct dma_tx_state state;
+ enum dma_status dmastat;
+
+ /*
+ * Pause the transfer so we can trust the current counter,
+ * do this before we pause the PL011 block, else we may
+ * overflow the FIFO.
+ */
+ if (dmaengine_pause(rxchan))
+ dev_err(uap->port.dev, "unable to pause DMA transfer\n");
+ dmastat = rxchan->device->device_tx_status(rxchan,
+ dmarx->cookie, &state);
+ if (dmastat != DMA_PAUSED)
+ dev_err(uap->port.dev, "unable to pause DMA transfer\n");
+
+ /* Disable RX DMA - incoming data will wait in the FIFO */
+ uap->dmacr &= ~UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->dmarx.running = false;
+
+ pending = sgbuf->sg.length - state.residue;
+ BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
+ /* Then we terminate the transfer - we now know our residue */
+ dmaengine_terminate_all(rxchan);
+
+ /*
+ * This will take the chars we have so far and insert
+ * into the framework.
+ */
+ pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
+
+ /* Switch buffer & re-trigger DMA job */
+ dmarx->use_buf_b = !dmarx->use_buf_b;
+ if (pl011_dma_rx_trigger_dma(uap)) {
+ dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
+ "fall back to interrupt mode\n");
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+}
+
+static void pl011_dma_rx_callback(void *data)
+{
+ struct uart_amba_port *uap = data;
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ bool lastbuf = dmarx->use_buf_b;
+ int ret;
+
+ /*
+ * This completion interrupt occurs typically when the
+ * RX buffer is totally stuffed but no timeout has yet
+ * occurred. When that happens, we just want the RX
+ * routine to flush out the secondary DMA buffer while
+ * we immediately trigger the next DMA job.
+ */
+ spin_lock_irq(&uap->port.lock);
+ uap->dmarx.running = false;
+ dmarx->use_buf_b = !lastbuf;
+ ret = pl011_dma_rx_trigger_dma(uap);
+
+ pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
+ spin_unlock_irq(&uap->port.lock);
+ /*
+ * Do this check after we picked the DMA chars so we don't
+ * get some IRQ immediately from RX.
+ */
+ if (ret) {
+ dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
+ "fall back to interrupt mode\n");
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+}
+
+/*
+ * Stop accepting received characters, when we're shutting down or
+ * suspending this port.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
+{
+ /* FIXME. Just disable the DMA enable */
+ uap->dmacr &= ~UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+}
static void pl011_dma_startup(struct uart_amba_port *uap)
{
+ int ret;
+
if (!uap->dmatx.chan)
return;
@@ -525,8 +857,33 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
/* The DMA buffer is now the FIFO the TTY subsystem can use */
uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
- uap->using_dma = true;
+ uap->using_tx_dma = true;
+
+ if (!uap->dmarx.chan)
+ goto skip_rx;
+
+ /* Allocate and map DMA RX buffers */
+ ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
+ DMA_FROM_DEVICE);
+ if (ret) {
+ dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
+ "RX buffer A", ret);
+ goto skip_rx;
+ }
+
+ ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b,
+ DMA_FROM_DEVICE);
+ if (ret) {
+ dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
+ "RX buffer B", ret);
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
+ DMA_FROM_DEVICE);
+ goto skip_rx;
+ }
+ uap->using_rx_dma = true;
+
+skip_rx:
/* Turn on DMA error (RX/TX will be enabled on demand) */
uap->dmacr |= UART011_DMAONERR;
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
@@ -539,11 +896,17 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
if (uap->vendor->dma_threshold)
writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
uap->port.membase + ST_UART011_DMAWM);
+
+ if (uap->using_rx_dma) {
+ if (pl011_dma_rx_trigger_dma(uap))
+ dev_dbg(uap->port.dev, "could not trigger initial "
+ "RX DMA job, fall back to interrupt mode\n");
+ }
}
static void pl011_dma_shutdown(struct uart_amba_port *uap)
{
- if (!uap->using_dma)
+ if (!(uap->using_tx_dma || uap->using_rx_dma))
return;
/* Disable RX and TX DMA */
@@ -555,19 +918,39 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
spin_unlock_irq(&uap->port.lock);
- /* In theory, this should already be done by pl011_dma_flush_buffer */
- dmaengine_terminate_all(uap->dmatx.chan);
- if (uap->dmatx.queued) {
- dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
- DMA_TO_DEVICE);
- uap->dmatx.queued = false;
+ if (uap->using_tx_dma) {
+ /* In theory, this should already be done by pl011_dma_flush_buffer */
+ dmaengine_terminate_all(uap->dmatx.chan);
+ if (uap->dmatx.queued) {
+ dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+ DMA_TO_DEVICE);
+ uap->dmatx.queued = false;
+ }
+
+ kfree(uap->dmatx.buf);
+ uap->using_tx_dma = false;
}
- kfree(uap->dmatx.buf);
+ if (uap->using_rx_dma) {
+ dmaengine_terminate_all(uap->dmarx.chan);
+ /* Clean up the RX DMA */
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
+ uap->using_rx_dma = false;
+ }
+}
- uap->using_dma = false;
+static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
+{
+ return uap->using_rx_dma;
}
+static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
+{
+ return uap->using_rx_dma && uap->dmarx.running;
+}
+
+
#else
/* Blank functions if the DMA engine is not available */
static inline void pl011_dma_probe(struct uart_amba_port *uap)
@@ -600,6 +983,29 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
return false;
}
+static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
+{
+ return -EIO;
+}
+
+static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
+{
+ return false;
+}
+
+static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
+{
+ return false;
+}
+
#define pl011_dma_flush_buffer NULL
#endif
@@ -630,6 +1036,8 @@ static void pl011_stop_rx(struct uart_port *port)
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ pl011_dma_rx_stop(uap);
}
static void pl011_enable_ms(struct uart_port *port)
@@ -643,51 +1051,24 @@ static void pl011_enable_ms(struct uart_port *port)
static void pl011_rx_chars(struct uart_amba_port *uap)
{
struct tty_struct *tty = uap->port.state->port.tty;
- unsigned int status, ch, flag, max_count = 256;
-
- status = readw(uap->port.membase + UART01x_FR);
- while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
- ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
- flag = TTY_NORMAL;
- uap->port.icount.rx++;
-
- /*
- * Note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(ch & UART_DR_ERROR)) {
- if (ch & UART011_DR_BE) {
- ch &= ~(UART011_DR_FE | UART011_DR_PE);
- uap->port.icount.brk++;
- if (uart_handle_break(&uap->port))
- goto ignore_char;
- } else if (ch & UART011_DR_PE)
- uap->port.icount.parity++;
- else if (ch & UART011_DR_FE)
- uap->port.icount.frame++;
- if (ch & UART011_DR_OE)
- uap->port.icount.overrun++;
-
- ch &= uap->port.read_status_mask;
-
- if (ch & UART011_DR_BE)
- flag = TTY_BREAK;
- else if (ch & UART011_DR_PE)
- flag = TTY_PARITY;
- else if (ch & UART011_DR_FE)
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(&uap->port, ch & 255))
- goto ignore_char;
-
- uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+ pl011_fifo_to_tty(uap);
- ignore_char:
- status = readw(uap->port.membase + UART01x_FR);
- }
spin_unlock(&uap->port.lock);
tty_flip_buffer_push(tty);
+ /*
+ * If we were temporarily out of DMA mode for a while,
+ * attempt to switch back to DMA mode again.
+ */
+ if (pl011_dma_rx_available(uap)) {
+ if (pl011_dma_rx_trigger_dma(uap)) {
+ dev_dbg(uap->port.dev, "could not trigger RX DMA job "
+ "fall back to interrupt mode again\n");
+ uap->im |= UART011_RXIM;
+ } else
+ uap->im &= ~UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
spin_lock(&uap->port.lock);
}
@@ -767,8 +1148,12 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
UART011_RXIS),
uap->port.membase + UART011_ICR);
- if (status & (UART011_RTIS|UART011_RXIS))
- pl011_rx_chars(uap);
+ if (status & (UART011_RTIS|UART011_RXIS)) {
+ if (pl011_dma_rx_running(uap))
+ pl011_dma_rx_irq(uap);
+ else
+ pl011_rx_chars(uap);
+ }
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
@@ -945,10 +1330,14 @@ static int pl011_startup(struct uart_port *port)
pl011_dma_startup(uap);
/*
- * Finally, enable interrupts
+ * Finally, enable interrupts, only timeouts when using DMA
+ * if initial RX DMA job failed, start in interrupt mode
+ * as well.
*/
spin_lock_irq(&uap->port.lock);
- uap->im = UART011_RXIM | UART011_RTIM;
+ uap->im = UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
@@ -1349,7 +1738,7 @@ static struct uart_driver amba_reg = {
.cons = AMBA_CONSOLE,
};
-static int pl011_probe(struct amba_device *dev, struct amba_id *id)
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
struct vendor_data *vendor = id->data;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8e43a7b69e64..bfee9b4c6661 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -31,6 +32,7 @@
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include "msm_serial.h"
@@ -38,9 +40,20 @@ struct msm_port {
struct uart_port uart;
char name[16];
struct clk *clk;
+ struct clk *pclk;
unsigned int imr;
+ unsigned int *gsbi_base;
+ int is_uartdm;
+ unsigned int old_snap_state;
};
+static inline void wait_for_xmitr(struct uart_port *port, int bits)
+{
+ if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY))
+ while ((msm_read(port, UART_ISR) & bits) != bits)
+ cpu_relax();
+}
+
static void msm_stop_tx(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -73,6 +86,61 @@ static void msm_enable_ms(struct uart_port *port)
msm_write(port, msm_port->imr, UART_IMR);
}
+static void handle_rx_dm(struct uart_port *port, unsigned int misr)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned int sr;
+ int count = 0;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ }
+
+ if (misr & UART_IMR_RXSTALE) {
+ count = msm_read(port, UARTDM_RX_TOTAL_SNAP) -
+ msm_port->old_snap_state;
+ msm_port->old_snap_state = 0;
+ } else {
+ count = 4 * (msm_read(port, UART_RFWR));
+ msm_port->old_snap_state += count;
+ }
+
+ /* TODO: Precise error reporting */
+
+ port->icount.rx += count;
+
+ while (count > 0) {
+ unsigned int c;
+
+ sr = msm_read(port, UART_SR);
+ if ((sr & UART_SR_RX_READY) == 0) {
+ msm_port->old_snap_state -= count;
+ break;
+ }
+ c = msm_read(port, UARTDM_RF);
+ if (sr & UART_SR_RX_BREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & UART_SR_PAR_FRAME_ERR)
+ port->icount.frame++;
+
+ /* TODO: handle sysrq */
+ tty_insert_flip_string(tty, (char *) &c,
+ (count > 4) ? 4 : count);
+ count -= 4;
+ }
+
+ tty_flip_buffer_push(tty);
+ if (misr & (UART_IMR_RXSTALE))
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+}
+
static void handle_rx(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
@@ -121,6 +189,12 @@ static void handle_rx(struct uart_port *port)
tty_flip_buffer_push(tty);
}
+static void reset_dm_count(struct uart_port *port)
+{
+ wait_for_xmitr(port, UART_ISR_TX_READY);
+ msm_write(port, 1, UARTDM_NCF_TX);
+}
+
static void handle_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
@@ -128,11 +202,18 @@ static void handle_tx(struct uart_port *port)
int sent_tx;
if (port->x_char) {
- msm_write(port, port->x_char, UART_TF);
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
+ msm_write(port, port->x_char,
+ msm_port->is_uartdm ? UARTDM_TF : UART_TF);
port->icount.tx++;
port->x_char = 0;
}
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
if (uart_circ_empty(xmit)) {
/* disable tx interrupts */
@@ -140,8 +221,11 @@ static void handle_tx(struct uart_port *port)
msm_write(port, msm_port->imr, UART_IMR);
break;
}
+ msm_write(port, xmit->buf[xmit->tail],
+ msm_port->is_uartdm ? UARTDM_TF : UART_TF);
- msm_write(port, xmit->buf[xmit->tail], UART_TF);
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
@@ -169,8 +253,12 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
misr = msm_read(port, UART_MISR);
msm_write(port, 0, UART_IMR); /* disable interrupt */
- if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
- handle_rx(port);
+ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
+ if (msm_port->is_uartdm)
+ handle_rx_dm(port, misr);
+ else
+ handle_rx(port);
+ }
if (misr & UART_IMR_TXLEV)
handle_tx(port);
if (misr & UART_IMR_DELTA_CTS)
@@ -192,10 +280,21 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
}
-static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+
+static void msm_reset(struct uart_port *port)
{
- unsigned int mr;
+ /* reset everything */
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int mr;
mr = msm_read(port, UART_MR1);
if (!(mctrl & TIOCM_RTS)) {
@@ -219,6 +318,7 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl)
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
{
unsigned int baud_code, rxstale, watermark;
+ struct msm_port *msm_port = UART_TO_MSM(port);
switch (baud) {
case 300:
@@ -273,6 +373,9 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
break;
}
+ if (msm_port->is_uartdm)
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+
msm_write(port, baud_code, UART_CSR);
/* RX stale watermark */
@@ -288,25 +391,23 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
/* set TX watermark */
msm_write(port, 10, UART_TFWR);
+ if (msm_port->is_uartdm) {
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+ }
+
return baud;
}
-static void msm_reset(struct uart_port *port)
-{
- /* reset everything */
- msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
- msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
-}
static void msm_init_clock(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
clk_enable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_enable(msm_port->pclk);
msm_serial_set_mnd_regs(port);
}
@@ -347,15 +448,31 @@ static int msm_startup(struct uart_port *port)
msm_write(port, data, UART_IPR);
}
- msm_reset(port);
+ data = 0;
+ if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) {
+ msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
+ msm_reset(port);
+ data = UART_CR_TX_ENABLE;
+ }
+
+ data |= UART_CR_RX_ENABLE;
+ msm_write(port, data, UART_CR); /* enable TX & RX */
- msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+ /* Make sure IPR is not 0 to start with*/
+ if (msm_port->is_uartdm)
+ msm_write(port, UART_IPR_STALE_LSB, UART_IPR);
/* turn on RX and CTS interrupts */
msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
UART_IMR_CURRENT_CTS;
- msm_write(port, msm_port->imr, UART_IMR);
+ if (msm_port->is_uartdm) {
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+ }
+
+ msm_write(port, msm_port->imr, UART_IMR);
return 0;
}
@@ -384,7 +501,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
baud = msm_set_baud_rate(port, baud);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
-
+
/* calculate parity */
mr = msm_read(port, UART_MR2);
mr &= ~UART_MR2_PARITY_MODE;
@@ -454,48 +571,105 @@ static const char *msm_type(struct uart_port *port)
static void msm_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *resource;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ struct resource *uart_resource;
+ struct resource *gsbi_resource;
resource_size_t size;
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
+ uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!uart_resource))
return;
- size = resource->end - resource->start + 1;
+ size = resource_size(uart_resource);
release_mem_region(port->mapbase, size);
iounmap(port->membase);
port->membase = NULL;
+
+ if (msm_port->gsbi_base) {
+ iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base +
+ GSBI_CONTROL);
+
+ gsbi_resource = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "gsbi_resource");
+
+ if (unlikely(!gsbi_resource))
+ return;
+
+ size = resource_size(gsbi_resource);
+ release_mem_region(gsbi_resource->start, size);
+ iounmap(msm_port->gsbi_base);
+ msm_port->gsbi_base = NULL;
+ }
}
static int msm_request_port(struct uart_port *port)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *resource;
+ struct resource *uart_resource;
+ struct resource *gsbi_resource;
resource_size_t size;
+ int ret;
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
+ uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "uart_resource");
+ if (unlikely(!uart_resource))
return -ENXIO;
- size = resource->end - resource->start + 1;
- if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+ size = resource_size(uart_resource);
+
+ if (!request_mem_region(port->mapbase, size, "msm_serial"))
return -EBUSY;
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
- release_mem_region(port->mapbase, size);
- return -EBUSY;
+ ret = -EBUSY;
+ goto fail_release_port;
+ }
+
+ gsbi_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "gsbi_resource");
+ /* Is this a GSBI-based port? */
+ if (gsbi_resource) {
+ size = resource_size(gsbi_resource);
+
+ if (!request_mem_region(gsbi_resource->start, size,
+ "msm_serial")) {
+ ret = -EBUSY;
+ goto fail_release_port;
+ }
+
+ msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
+ if (!msm_port->gsbi_base) {
+ ret = -EBUSY;
+ goto fail_release_gsbi;
+ }
}
return 0;
+
+fail_release_gsbi:
+ release_mem_region(gsbi_resource->start, size);
+fail_release_port:
+ release_mem_region(port->mapbase, size);
+ return ret;
}
static void msm_config_port(struct uart_port *port, int flags)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ int ret;
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_MSM;
- msm_request_port(port);
+ ret = msm_request_port(port);
+ if (ret)
+ return;
}
+
+ if (msm_port->is_uartdm)
+ iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base +
+ GSBI_CONTROL);
}
static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -515,9 +689,13 @@ static void msm_power(struct uart_port *port, unsigned int state,
switch (state) {
case 0:
clk_enable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_enable(msm_port->pclk);
break;
case 3:
clk_disable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_disable(msm_port->pclk);
break;
default:
printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
@@ -550,7 +728,7 @@ static struct msm_port msm_uart_ports[] = {
.iotype = UPIO_MEM,
.ops = &msm_uart_pops,
.flags = UPF_BOOT_AUTOCONF,
- .fifosize = 512,
+ .fifosize = 64,
.line = 0,
},
},
@@ -559,7 +737,7 @@ static struct msm_port msm_uart_ports[] = {
.iotype = UPIO_MEM,
.ops = &msm_uart_pops,
.flags = UPF_BOOT_AUTOCONF,
- .fifosize = 512,
+ .fifosize = 64,
.line = 1,
},
},
@@ -585,9 +763,14 @@ static inline struct uart_port *get_port_from_line(unsigned int line)
static void msm_console_putchar(struct uart_port *port, int c)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
;
- msm_write(port, c, UART_TF);
+ msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
}
static void msm_console_write(struct console *co, const char *s,
@@ -609,12 +792,14 @@ static void msm_console_write(struct console *co, const char *s,
static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ struct msm_port *msm_port;
int baud, flow, bits, parity;
if (unlikely(co->index >= UART_NR || co->index < 0))
return -ENXIO;
port = get_port_from_line(co->index);
+ msm_port = UART_TO_MSM(port);
if (unlikely(!port->membase))
return -ENXIO;
@@ -638,6 +823,11 @@ static int __init msm_console_setup(struct console *co, char *options)
msm_reset(port);
+ if (msm_port->is_uartdm) {
+ msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
+ msm_write(port, UART_CR_TX_ENABLE, UART_CR);
+ }
+
printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
return uart_set_options(port, co, baud, parity, bits, flow);
@@ -685,14 +875,32 @@ static int __init msm_serial_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
msm_port = UART_TO_MSM(port);
- msm_port->clk = clk_get(&pdev->dev, "uart_clk");
- if (IS_ERR(msm_port->clk))
- return PTR_ERR(msm_port->clk);
+ if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsbi_resource"))
+ msm_port->is_uartdm = 1;
+ else
+ msm_port->is_uartdm = 0;
+
+ if (msm_port->is_uartdm) {
+ msm_port->clk = clk_get(&pdev->dev, "gsbi_uart_clk");
+ msm_port->pclk = clk_get(&pdev->dev, "gsbi_pclk");
+ } else {
+ msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+ msm_port->pclk = ERR_PTR(-ENOENT);
+ }
+
+ if (unlikely(IS_ERR(msm_port->clk) || (IS_ERR(msm_port->pclk) &&
+ msm_port->is_uartdm)))
+ return PTR_ERR(msm_port->clk);
+
+ if (msm_port->is_uartdm)
+ clk_set_rate(msm_port->clk, 7372800);
+
port->uartclk = clk_get_rate(msm_port->clk);
printk(KERN_INFO "uartclk = %d\n", port->uartclk);
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "uart_resource");
if (unlikely(!resource))
return -ENXIO;
port->mapbase = resource->start;
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index f6ca9ca79e98..9b8dc5d0d855 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -54,6 +55,7 @@
#define UART_CSR_300 0x22
#define UART_TF 0x000C
+#define UARTDM_TF 0x0070
#define UART_CR 0x0010
#define UART_CR_CMD_NULL (0 << 4)
@@ -64,14 +66,17 @@
#define UART_CR_CMD_START_BREAK (5 << 4)
#define UART_CR_CMD_STOP_BREAK (6 << 4)
#define UART_CR_CMD_RESET_CTS (7 << 4)
+#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
#define UART_CR_CMD_PACKET_MODE (9 << 4)
#define UART_CR_CMD_MODE_RESET (12 << 4)
#define UART_CR_CMD_SET_RFR (13 << 4)
#define UART_CR_CMD_RESET_RFR (14 << 4)
+#define UART_CR_CMD_PROTECTION_EN (16 << 4)
+#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
#define UART_CR_TX_DISABLE (1 << 3)
-#define UART_CR_TX_ENABLE (1 << 3)
-#define UART_CR_RX_DISABLE (1 << 3)
-#define UART_CR_RX_ENABLE (1 << 3)
+#define UART_CR_TX_ENABLE (1 << 2)
+#define UART_CR_RX_DISABLE (1 << 1)
+#define UART_CR_RX_ENABLE (1 << 0)
#define UART_IMR 0x0014
#define UART_IMR_TXLEV (1 << 0)
@@ -110,9 +115,20 @@
#define UART_SR_RX_FULL (1 << 1)
#define UART_SR_RX_READY (1 << 0)
-#define UART_RF 0x000C
-#define UART_MISR 0x0010
-#define UART_ISR 0x0014
+#define UART_RF 0x000C
+#define UARTDM_RF 0x0070
+#define UART_MISR 0x0010
+#define UART_ISR 0x0014
+#define UART_ISR_TX_READY (1 << 7)
+
+#define GSBI_CONTROL 0x0
+#define GSBI_PROTOCOL_CODE 0x30
+#define GSBI_PROTOCOL_UART 0x40
+#define GSBI_PROTOCOL_IDLE 0x0
+
+#define UARTDM_DMRX 0x34
+#define UARTDM_NCF_TX 0x40
+#define UARTDM_RX_TOTAL_SNAP 0x38
#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
new file mode 100644
index 000000000000..7e02c9c344fe
--- /dev/null
+++ b/drivers/tty/serial/mxs-auart.c
@@ -0,0 +1,798 @@
+/*
+ * Freescale STMP37XX/STMP378X Application UART driver
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * 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
+ */
+
+#include <linux/kernel.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>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+
+#define MXS_AUART_PORTS 5
+
+#define AUART_CTRL0 0x00000000
+#define AUART_CTRL0_SET 0x00000004
+#define AUART_CTRL0_CLR 0x00000008
+#define AUART_CTRL0_TOG 0x0000000c
+#define AUART_CTRL1 0x00000010
+#define AUART_CTRL1_SET 0x00000014
+#define AUART_CTRL1_CLR 0x00000018
+#define AUART_CTRL1_TOG 0x0000001c
+#define AUART_CTRL2 0x00000020
+#define AUART_CTRL2_SET 0x00000024
+#define AUART_CTRL2_CLR 0x00000028
+#define AUART_CTRL2_TOG 0x0000002c
+#define AUART_LINECTRL 0x00000030
+#define AUART_LINECTRL_SET 0x00000034
+#define AUART_LINECTRL_CLR 0x00000038
+#define AUART_LINECTRL_TOG 0x0000003c
+#define AUART_LINECTRL2 0x00000040
+#define AUART_LINECTRL2_SET 0x00000044
+#define AUART_LINECTRL2_CLR 0x00000048
+#define AUART_LINECTRL2_TOG 0x0000004c
+#define AUART_INTR 0x00000050
+#define AUART_INTR_SET 0x00000054
+#define AUART_INTR_CLR 0x00000058
+#define AUART_INTR_TOG 0x0000005c
+#define AUART_DATA 0x00000060
+#define AUART_STAT 0x00000070
+#define AUART_DEBUG 0x00000080
+#define AUART_VERSION 0x00000090
+#define AUART_AUTOBAUD 0x000000a0
+
+#define AUART_CTRL0_SFTRST (1 << 31)
+#define AUART_CTRL0_CLKGATE (1 << 30)
+
+#define AUART_CTRL2_CTSEN (1 << 15)
+#define AUART_CTRL2_RTS (1 << 11)
+#define AUART_CTRL2_RXE (1 << 9)
+#define AUART_CTRL2_TXE (1 << 8)
+#define AUART_CTRL2_UARTEN (1 << 0)
+
+#define AUART_LINECTRL_BAUD_DIVINT_SHIFT 16
+#define AUART_LINECTRL_BAUD_DIVINT_MASK 0xffff0000
+#define AUART_LINECTRL_BAUD_DIVINT(v) (((v) & 0xffff) << 16)
+#define AUART_LINECTRL_BAUD_DIVFRAC_SHIFT 8
+#define AUART_LINECTRL_BAUD_DIVFRAC_MASK 0x00003f00
+#define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8)
+#define AUART_LINECTRL_WLEN_MASK 0x00000060
+#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5)
+#define AUART_LINECTRL_FEN (1 << 4)
+#define AUART_LINECTRL_STP2 (1 << 3)
+#define AUART_LINECTRL_EPS (1 << 2)
+#define AUART_LINECTRL_PEN (1 << 1)
+#define AUART_LINECTRL_BRK (1 << 0)
+
+#define AUART_INTR_RTIEN (1 << 22)
+#define AUART_INTR_TXIEN (1 << 21)
+#define AUART_INTR_RXIEN (1 << 20)
+#define AUART_INTR_CTSMIEN (1 << 17)
+#define AUART_INTR_RTIS (1 << 6)
+#define AUART_INTR_TXIS (1 << 5)
+#define AUART_INTR_RXIS (1 << 4)
+#define AUART_INTR_CTSMIS (1 << 1)
+
+#define AUART_STAT_BUSY (1 << 29)
+#define AUART_STAT_CTS (1 << 28)
+#define AUART_STAT_TXFE (1 << 27)
+#define AUART_STAT_TXFF (1 << 25)
+#define AUART_STAT_RXFE (1 << 24)
+#define AUART_STAT_OERR (1 << 19)
+#define AUART_STAT_BERR (1 << 18)
+#define AUART_STAT_PERR (1 << 17)
+#define AUART_STAT_FERR (1 << 16)
+
+static struct uart_driver auart_driver;
+
+struct mxs_auart_port {
+ struct uart_port port;
+
+ unsigned int flags;
+ unsigned int ctrl;
+
+ unsigned int irq;
+
+ struct clk *clk;
+ struct device *dev;
+};
+
+static void mxs_auart_stop_tx(struct uart_port *u);
+
+#define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
+
+static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
+{
+ struct circ_buf *xmit = &s->port.state->xmit;
+
+ while (!(readl(s->port.membase + AUART_STAT) &
+ AUART_STAT_TXFF)) {
+ if (s->port.x_char) {
+ s->port.icount.tx++;
+ writel(s->port.x_char,
+ s->port.membase + AUART_DATA);
+ s->port.x_char = 0;
+ continue;
+ }
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
+ s->port.icount.tx++;
+ writel(xmit->buf[xmit->tail],
+ s->port.membase + AUART_DATA);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+ } else
+ break;
+ }
+ if (uart_circ_empty(&(s->port.state->xmit)))
+ writel(AUART_INTR_TXIEN,
+ s->port.membase + AUART_INTR_CLR);
+ else
+ writel(AUART_INTR_TXIEN,
+ s->port.membase + AUART_INTR_SET);
+
+ if (uart_tx_stopped(&s->port))
+ mxs_auart_stop_tx(&s->port);
+}
+
+static void mxs_auart_rx_char(struct mxs_auart_port *s)
+{
+ int flag;
+ u32 stat;
+ u8 c;
+
+ c = readl(s->port.membase + AUART_DATA);
+ stat = readl(s->port.membase + AUART_STAT);
+
+ flag = TTY_NORMAL;
+ s->port.icount.rx++;
+
+ if (stat & AUART_STAT_BERR) {
+ s->port.icount.brk++;
+ if (uart_handle_break(&s->port))
+ goto out;
+ } else if (stat & AUART_STAT_PERR) {
+ s->port.icount.parity++;
+ } else if (stat & AUART_STAT_FERR) {
+ s->port.icount.frame++;
+ }
+
+ /*
+ * Mask off conditions which should be ingored.
+ */
+ stat &= s->port.read_status_mask;
+
+ if (stat & AUART_STAT_BERR) {
+ flag = TTY_BREAK;
+ } else if (stat & AUART_STAT_PERR)
+ flag = TTY_PARITY;
+ else if (stat & AUART_STAT_FERR)
+ flag = TTY_FRAME;
+
+ if (stat & AUART_STAT_OERR)
+ s->port.icount.overrun++;
+
+ if (uart_handle_sysrq_char(&s->port, c))
+ goto out;
+
+ uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag);
+out:
+ writel(stat, s->port.membase + AUART_STAT);
+}
+
+static void mxs_auart_rx_chars(struct mxs_auart_port *s)
+{
+ struct tty_struct *tty = s->port.state->port.tty;
+ u32 stat = 0;
+
+ for (;;) {
+ stat = readl(s->port.membase + AUART_STAT);
+ if (stat & AUART_STAT_RXFE)
+ break;
+ mxs_auart_rx_char(s);
+ }
+
+ writel(stat, s->port.membase + AUART_STAT);
+ tty_flip_buffer_push(tty);
+}
+
+static int mxs_auart_request_port(struct uart_port *u)
+{
+ return 0;
+}
+
+static int mxs_auart_verify_port(struct uart_port *u,
+ struct serial_struct *ser)
+{
+ if (u->type != PORT_UNKNOWN && u->type != PORT_IMX)
+ return -EINVAL;
+ return 0;
+}
+
+static void mxs_auart_config_port(struct uart_port *u, int flags)
+{
+}
+
+static const char *mxs_auart_type(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ return dev_name(s->dev);
+}
+
+static void mxs_auart_release_port(struct uart_port *u)
+{
+}
+
+static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ u32 ctrl = readl(u->membase + AUART_CTRL2);
+
+ ctrl &= ~AUART_CTRL2_RTS;
+ if (mctrl & TIOCM_RTS)
+ ctrl |= AUART_CTRL2_RTS;
+ s->ctrl = mctrl;
+ writel(ctrl, u->membase + AUART_CTRL2);
+}
+
+static u32 mxs_auart_get_mctrl(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+ u32 stat = readl(u->membase + AUART_STAT);
+ int ctrl2 = readl(u->membase + AUART_CTRL2);
+ u32 mctrl = s->ctrl;
+
+ mctrl &= ~TIOCM_CTS;
+ if (stat & AUART_STAT_CTS)
+ mctrl |= TIOCM_CTS;
+
+ if (ctrl2 & AUART_CTRL2_RTS)
+ mctrl |= TIOCM_RTS;
+
+ return mctrl;
+}
+
+static void mxs_auart_settermios(struct uart_port *u,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ u32 bm, ctrl, ctrl2, div;
+ unsigned int cflag, baud;
+
+ cflag = termios->c_cflag;
+
+ ctrl = AUART_LINECTRL_FEN;
+ ctrl2 = readl(u->membase + AUART_CTRL2);
+
+ /* byte size */
+ switch (cflag & CSIZE) {
+ case CS5:
+ bm = 0;
+ break;
+ case CS6:
+ bm = 1;
+ break;
+ case CS7:
+ bm = 2;
+ break;
+ case CS8:
+ bm = 3;
+ break;
+ default:
+ return;
+ }
+
+ ctrl |= AUART_LINECTRL_WLEN(bm);
+
+ /* parity */
+ if (cflag & PARENB) {
+ ctrl |= AUART_LINECTRL_PEN;
+ if ((cflag & PARODD) == 0)
+ ctrl |= AUART_LINECTRL_EPS;
+ }
+
+ u->read_status_mask = 0;
+
+ if (termios->c_iflag & INPCK)
+ u->read_status_mask |= AUART_STAT_PERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ u->read_status_mask |= AUART_STAT_BERR;
+
+ /*
+ * Characters to ignore
+ */
+ u->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ u->ignore_status_mask |= AUART_STAT_PERR;
+ if (termios->c_iflag & IGNBRK) {
+ u->ignore_status_mask |= AUART_STAT_BERR;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ u->ignore_status_mask |= AUART_STAT_OERR;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if (cflag & CREAD)
+ ctrl2 |= AUART_CTRL2_RXE;
+ else
+ ctrl2 &= ~AUART_CTRL2_RXE;
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ ctrl |= AUART_LINECTRL_STP2;
+
+ /* figure out the hardware flow control settings */
+ if (cflag & CRTSCTS)
+ ctrl2 |= AUART_CTRL2_CTSEN;
+ else
+ ctrl2 &= ~AUART_CTRL2_CTSEN;
+
+ /* set baud rate */
+ baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
+ div = u->uartclk * 32 / baud;
+ ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
+ ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6);
+
+ writel(ctrl, u->membase + AUART_LINECTRL);
+ writel(ctrl2, u->membase + AUART_CTRL2);
+}
+
+static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
+{
+ u32 istatus, istat;
+ struct mxs_auart_port *s = context;
+ u32 stat = readl(s->port.membase + AUART_STAT);
+
+ istatus = istat = readl(s->port.membase + AUART_INTR);
+
+ if (istat & AUART_INTR_CTSMIS) {
+ uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
+ writel(AUART_INTR_CTSMIS,
+ s->port.membase + AUART_INTR_CLR);
+ istat &= ~AUART_INTR_CTSMIS;
+ }
+
+ if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) {
+ mxs_auart_rx_chars(s);
+ istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS);
+ }
+
+ if (istat & AUART_INTR_TXIS) {
+ mxs_auart_tx_chars(s);
+ istat &= ~AUART_INTR_TXIS;
+ }
+
+ writel(istatus & (AUART_INTR_RTIS
+ | AUART_INTR_TXIS
+ | AUART_INTR_RXIS
+ | AUART_INTR_CTSMIS),
+ s->port.membase + AUART_INTR_CLR);
+
+ return IRQ_HANDLED;
+}
+
+static void mxs_auart_reset(struct uart_port *u)
+{
+ int i;
+ unsigned int reg;
+
+ writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR);
+
+ for (i = 0; i < 10000; i++) {
+ reg = readl(u->membase + AUART_CTRL0);
+ if (!(reg & AUART_CTRL0_SFTRST))
+ break;
+ udelay(3);
+ }
+ writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
+}
+
+static int mxs_auart_startup(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ clk_enable(s->clk);
+
+ writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
+
+ writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET);
+
+ writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
+ u->membase + AUART_INTR);
+
+ /*
+ * Enable fifo so all four bytes of a DMA word are written to
+ * output (otherwise, only the LSB is written, ie. 1 in 4 bytes)
+ */
+ writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
+
+ return 0;
+}
+
+static void mxs_auart_shutdown(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
+
+ writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
+
+ writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
+ u->membase + AUART_INTR_CLR);
+
+ clk_disable(s->clk);
+}
+
+static unsigned int mxs_auart_tx_empty(struct uart_port *u)
+{
+ if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE)
+ return TIOCSER_TEMT;
+ else
+ return 0;
+}
+
+static void mxs_auart_start_tx(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ /* enable transmitter */
+ writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);
+
+ mxs_auart_tx_chars(s);
+}
+
+static void mxs_auart_stop_tx(struct uart_port *u)
+{
+ writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR);
+}
+
+static void mxs_auart_stop_rx(struct uart_port *u)
+{
+ writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR);
+}
+
+static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
+{
+ if (ctl)
+ writel(AUART_LINECTRL_BRK,
+ u->membase + AUART_LINECTRL_SET);
+ else
+ writel(AUART_LINECTRL_BRK,
+ u->membase + AUART_LINECTRL_CLR);
+}
+
+static void mxs_auart_enable_ms(struct uart_port *port)
+{
+ /* just empty */
+}
+
+static struct uart_ops mxs_auart_ops = {
+ .tx_empty = mxs_auart_tx_empty,
+ .start_tx = mxs_auart_start_tx,
+ .stop_tx = mxs_auart_stop_tx,
+ .stop_rx = mxs_auart_stop_rx,
+ .enable_ms = mxs_auart_enable_ms,
+ .break_ctl = mxs_auart_break_ctl,
+ .set_mctrl = mxs_auart_set_mctrl,
+ .get_mctrl = mxs_auart_get_mctrl,
+ .startup = mxs_auart_startup,
+ .shutdown = mxs_auart_shutdown,
+ .set_termios = mxs_auart_settermios,
+ .type = mxs_auart_type,
+ .release_port = mxs_auart_release_port,
+ .request_port = mxs_auart_request_port,
+ .config_port = mxs_auart_config_port,
+ .verify_port = mxs_auart_verify_port,
+};
+
+static struct mxs_auart_port *auart_port[MXS_AUART_PORTS];
+
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+static void mxs_auart_console_putchar(struct uart_port *port, int ch)
+{
+ unsigned int to = 1000;
+
+ while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) {
+ if (!to--)
+ break;
+ udelay(1);
+ }
+
+ writel(ch, port->membase + AUART_DATA);
+}
+
+static void
+auart_console_write(struct console *co, const char *str, unsigned int count)
+{
+ struct mxs_auart_port *s;
+ struct uart_port *port;
+ unsigned int old_ctrl0, old_ctrl2;
+ unsigned int to = 1000;
+
+ if (co->index > MXS_AUART_PORTS || co->index < 0)
+ return;
+
+ s = auart_port[co->index];
+ port = &s->port;
+
+ clk_enable(s->clk);
+
+ /* First save the CR then disable the interrupts */
+ old_ctrl2 = readl(port->membase + AUART_CTRL2);
+ old_ctrl0 = readl(port->membase + AUART_CTRL0);
+
+ writel(AUART_CTRL0_CLKGATE,
+ port->membase + AUART_CTRL0_CLR);
+ writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE,
+ port->membase + AUART_CTRL2_SET);
+
+ uart_console_write(port, str, count, mxs_auart_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+ if (!to--)
+ break;
+ udelay(1);
+ }
+
+ writel(old_ctrl0, port->membase + AUART_CTRL0);
+ writel(old_ctrl2, port->membase + AUART_CTRL2);
+
+ clk_disable(s->clk);
+}
+
+static void __init
+auart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ unsigned int lcr_h, quot;
+
+ if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN))
+ return;
+
+ lcr_h = readl(port->membase + AUART_LINECTRL);
+
+ *parity = 'n';
+ if (lcr_h & AUART_LINECTRL_PEN) {
+ if (lcr_h & AUART_LINECTRL_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2))
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = ((readl(port->membase + AUART_LINECTRL)
+ & AUART_LINECTRL_BAUD_DIVINT_MASK))
+ >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6);
+ quot |= ((readl(port->membase + AUART_LINECTRL)
+ & AUART_LINECTRL_BAUD_DIVFRAC_MASK))
+ >> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT;
+ 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 *s;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret;
+
+ /*
+ * 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 == -1 || co->index >= ARRAY_SIZE(auart_port))
+ co->index = 0;
+ s = auart_port[co->index];
+ if (!s)
+ return -ENODEV;
+
+ clk_enable(s->clk);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ auart_console_get_options(&s->port, &baud, &parity, &bits);
+
+ ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
+
+ clk_disable(s->clk);
+
+ return ret;
+}
+
+static struct console auart_console = {
+ .name = "ttyAPP",
+ .write = auart_console_write,
+ .device = uart_console_device,
+ .setup = auart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &auart_driver,
+};
+#endif
+
+static struct uart_driver auart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttyAPP",
+ .dev_name = "ttyAPP",
+ .major = 0,
+ .minor = 0,
+ .nr = MXS_AUART_PORTS,
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+ .cons = &auart_console,
+#endif
+};
+
+static int __devinit mxs_auart_probe(struct platform_device *pdev)
+{
+ struct mxs_auart_port *s;
+ u32 version;
+ int ret = 0;
+ struct resource *r;
+
+ s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
+ if (!s) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ s->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(s->clk)) {
+ ret = PTR_ERR(s->clk);
+ goto out_free;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -ENXIO;
+ goto out_free_clk;
+ }
+
+ s->port.mapbase = r->start;
+ s->port.membase = ioremap(r->start, resource_size(r));
+ s->port.ops = &mxs_auart_ops;
+ s->port.iotype = UPIO_MEM;
+ s->port.line = pdev->id < 0 ? 0 : pdev->id;
+ s->port.fifosize = 16;
+ s->port.uartclk = clk_get_rate(s->clk);
+ s->port.type = PORT_IMX;
+ s->port.dev = s->dev = get_device(&pdev->dev);
+
+ s->flags = 0;
+ s->ctrl = 0;
+
+ s->irq = platform_get_irq(pdev, 0);
+ s->port.irq = s->irq;
+ ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
+ if (ret)
+ goto out_free_clk;
+
+ platform_set_drvdata(pdev, s);
+
+ auart_port[pdev->id] = s;
+
+ mxs_auart_reset(&s->port);
+
+ ret = uart_add_one_port(&auart_driver, &s->port);
+ if (ret)
+ goto out_free_irq;
+
+ version = readl(s->port.membase + AUART_VERSION);
+ dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
+ (version >> 24) & 0xff,
+ (version >> 16) & 0xff, version & 0xffff);
+
+ return 0;
+
+out_free_irq:
+ auart_port[pdev->id] = NULL;
+ free_irq(s->irq, s);
+out_free_clk:
+ clk_put(s->clk);
+out_free:
+ kfree(s);
+out:
+ return ret;
+}
+
+static int __devexit mxs_auart_remove(struct platform_device *pdev)
+{
+ struct mxs_auart_port *s = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&auart_driver, &s->port);
+
+ auart_port[pdev->id] = NULL;
+
+ clk_put(s->clk);
+ free_irq(s->irq, s);
+ kfree(s);
+
+ return 0;
+}
+
+static struct platform_driver mxs_auart_driver = {
+ .probe = mxs_auart_probe,
+ .remove = __devexit_p(mxs_auart_remove),
+ .driver = {
+ .name = "mxs-auart",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mxs_auart_init(void)
+{
+ int r;
+
+ r = uart_register_driver(&auart_driver);
+ if (r)
+ goto out;
+
+ r = platform_driver_register(&mxs_auart_driver);
+ if (r)
+ goto out_err;
+
+ return 0;
+out_err:
+ uart_unregister_driver(&auart_driver);
+out:
+ return r;
+}
+
+static void __exit mxs_auart_exit(void)
+{
+ platform_driver_unregister(&mxs_auart_driver);
+ uart_unregister_driver(&auart_driver);
+}
+
+module_init(mxs_auart_init);
+module_exit(mxs_auart_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MXS application uart driver");
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index a9ad7f33526d..26403b8e4b9b 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -15,7 +15,6 @@
*Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/serial_reg.h>
-#include <linux/pci.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/serial_core.h>
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index ff51dae1df0c..c327218cad44 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1269,13 +1269,12 @@ static int ucc_uart_probe(struct platform_device *ofdev)
ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
- kfree(qe_port);
- return ret;
+ goto out_free;
}
if (!res.start) {
dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.mapbase = res.start;
@@ -1285,17 +1284,17 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
iprop = of_get_property(np, "device-id", NULL);
if (!iprop) {
- kfree(qe_port);
dev_err(&ofdev->dev, "UCC is unspecified in "
"device tree\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
}
if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->ucc_num = *iprop - 1;
@@ -1309,16 +1308,16 @@ static int ucc_uart_probe(struct platform_device *ofdev)
sprop = of_get_property(np, "rx-clock-name", NULL);
if (!sprop) {
dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->us_info.rx_clock = qe_clock_source(sprop);
if ((qe_port->us_info.rx_clock < QE_BRG1) ||
(qe_port->us_info.rx_clock > QE_BRG16)) {
dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
#ifdef LOOPBACK
@@ -1328,39 +1327,39 @@ static int ucc_uart_probe(struct platform_device *ofdev)
sprop = of_get_property(np, "tx-clock-name", NULL);
if (!sprop) {
dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->us_info.tx_clock = qe_clock_source(sprop);
#endif
if ((qe_port->us_info.tx_clock < QE_BRG1) ||
(qe_port->us_info.tx_clock > QE_BRG16)) {
dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
/* Get the port number, numbered 0-3 */
iprop = of_get_property(np, "port-number", NULL);
if (!iprop) {
dev_err(&ofdev->dev, "missing port-number in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.line = *iprop;
if (qe_port->port.line >= UCC_MAX_UART) {
dev_err(&ofdev->dev, "port-number must be 0-%u\n",
UCC_MAX_UART - 1);
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.irq = irq_of_parse_and_map(np, 0);
if (qe_port->port.irq == NO_IRQ) {
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
qe_port->ucc_num + 1);
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
/*
@@ -1372,8 +1371,8 @@ static int ucc_uart_probe(struct platform_device *ofdev)
np = of_find_node_by_type(NULL, "qe");
if (!np) {
dev_err(&ofdev->dev, "could not find 'qe' node\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
}
@@ -1381,8 +1380,8 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
dev_err(&ofdev->dev,
"missing brg-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
if (*iprop)
@@ -1397,16 +1396,16 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
dev_err(&ofdev->dev,
"missing QE bus-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
if (*iprop)
qe_port->port.uartclk = *iprop / 2;
else {
dev_err(&ofdev->dev,
"invalid QE bus-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
}
@@ -1444,8 +1443,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (ret) {
dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
qe_port->port.line);
- kfree(qe_port);
- return ret;
+ goto out_np;
}
dev_set_drvdata(&ofdev->dev, qe_port);
@@ -1459,6 +1457,11 @@ static int ucc_uart_probe(struct platform_device *ofdev)
SERIAL_QE_MINOR + qe_port->port.line);
return 0;
+out_np:
+ of_node_put(np);
+out_free:
+ kfree(qe_port);
+ return ret;
}
static int ucc_uart_remove(struct platform_device *ofdev)
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index c8e360d7d975..25c8c10bb689 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -203,11 +203,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
mdelay(10);
}
- /* setup specific usb hw */
- ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
- if (ret < 0)
- goto err_init;
-
ehci = hcd_to_ehci(hcd);
/* EHCI registers start at offset 0x100 */
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index a914010d9d12..630ae7f3cd4c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1530,7 +1530,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
defined(CONFIG_ARCH_U5500)
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 4f0dd2ed3964..4bd9e2145ee4 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -212,8 +212,8 @@ enum musb_g_ep0_state {
* directly with the "flat" model, or after setting up an index register.
*/
-#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
- || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN) \
+#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \
+ || defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \
|| defined(CONFIG_ARCH_OMAP4)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 21056c924c74..320fd4afb93f 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -31,7 +31,7 @@
*
*/
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
#include "omap2430.h"
#endif
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index e00fa1b22ecd..8c6fdef61d1c 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -1510,7 +1510,7 @@ isp1301_start_hnp(struct otg_transceiver *dev)
/*-------------------------------------------------------------------------*/
-static int __init
+static int __devinit
isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
int status;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 2a753f1e9183..e6a8d8c0101d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -376,6 +376,24 @@ config FB_CYBER2000
Say Y if you have a NetWinder or a graphics card containing this
device, otherwise say N.
+config FB_CYBER2000_DDC
+ bool "DDC for CyberPro support"
+ depends on FB_CYBER2000
+ select FB_DDC
+ default y
+ help
+ Say Y here if you want DDC support for your CyberPro graphics
+ card. This is only I2C bus support, driver does not use EDID.
+
+config FB_CYBER2000_I2C
+ bool "CyberPro 2000/2010/5000 I2C support"
+ depends on FB_CYBER2000 && I2C && ARCH_NETWINDER
+ select I2C_ALGOBIT
+ help
+ Enable support for the I2C video decoder interface on the
+ Integraphics CyberPro 20x0 and 5000 VGA chips. This is used
+ on the Netwinder machines for the SAA7111 video capture.
+
config FB_APOLLO
bool
depends on (FB = y) && APOLLO
@@ -2303,6 +2321,15 @@ config FB_JZ4740
help
Framebuffer support for the JZ4740 SoC.
+config FB_MXS
+ tristate "MXS LCD framebuffer support"
+ depends on FB && ARCH_MXS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Framebuffer support for the MXS SoC.
+
config FB_PUV3_UNIGFX
tristate "PKUnity v3 Unigfx framebuffer support"
depends on FB && UNICORE32 && ARCH_PUV3
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index b0eb3da24670..2ea44b6625fe 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -154,6 +154,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o
obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
+obj-$(CONFIG_FB_MXS) += mxsfb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 1c2c68356ea7..013c8ce57205 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -461,7 +461,7 @@ static int clcdfb_register(struct clcd_fb *fb)
return ret;
}
-static int clcdfb_probe(struct amba_device *dev, struct amba_id *id)
+static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct clcd_board *board = dev->dev.platform_data;
struct clcd_fb *fb;
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 0c1afd13ddd3..850380795b05 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -47,6 +47,8 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -61,10 +63,10 @@ struct cfb_info {
struct fb_info fb;
struct display_switch *dispsw;
struct display *display;
- struct pci_dev *dev;
unsigned char __iomem *region;
unsigned char __iomem *regs;
u_int id;
+ u_int irq;
int func_use_count;
u_long ref_ps;
@@ -88,6 +90,19 @@ struct cfb_info {
u_char ramdac_powerdown;
u32 pseudo_palette[16];
+
+ spinlock_t reg_b0_lock;
+
+#ifdef CONFIG_FB_CYBER2000_DDC
+ bool ddc_registered;
+ struct i2c_adapter ddc_adapter;
+ struct i2c_algo_bit_data ddc_algo;
+#endif
+
+#ifdef CONFIG_FB_CYBER2000_I2C
+ struct i2c_adapter i2c_adapter;
+ struct i2c_algo_bit_data i2c_algo;
+#endif
};
static char *default_font = "Acorn8x8";
@@ -494,6 +509,7 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
cyber2000_attrw(0x14, 0x00, cfb);
/* PLL registers */
+ spin_lock(&cfb->reg_b0_lock);
cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
@@ -501,6 +517,7 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
cyber2000_grphw(0x90, 0x01, cfb);
cyber2000_grphw(0xb9, 0x80, cfb);
cyber2000_grphw(0xb9, 0x00, cfb);
+ spin_unlock(&cfb->reg_b0_lock);
cfb->ramdac_ctrl = hw->ramdac;
cyber2000fb_write_ramdac_ctrl(cfb);
@@ -681,9 +698,9 @@ cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
* pll_ps_calc = best_div1 / (ref_ps * best_mult)
*/
best_diff = 0x7fffffff;
- best_mult = 32;
- best_div1 = 255;
- for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
+ best_mult = 2;
+ best_div1 = 32;
+ for (t_div1 = 2; t_div1 < 32; t_div1 += 1) {
u_int rr, t_mult, t_pll_ps;
int diff;
@@ -1105,24 +1122,22 @@ void cyber2000fb_disable_extregs(struct cfb_info *cfb)
}
EXPORT_SYMBOL(cyber2000fb_disable_extregs);
-void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
-{
- memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
-}
-EXPORT_SYMBOL(cyber2000fb_get_fb_var);
-
/*
* Attach a capture/tv driver to the core CyberX0X0 driver.
*/
int cyber2000fb_attach(struct cyberpro_info *info, int idx)
{
if (int_cfb_info != NULL) {
- info->dev = int_cfb_info->dev;
+ info->dev = int_cfb_info->fb.device;
+#ifdef CONFIG_FB_CYBER2000_I2C
+ info->i2c = &int_cfb_info->i2c_adapter;
+#else
+ info->i2c = NULL;
+#endif
info->regs = int_cfb_info->regs;
+ info->irq = int_cfb_info->irq;
info->fb = int_cfb_info->fb.screen_base;
info->fb_size = int_cfb_info->fb.fix.smem_len;
- info->enable_extregs = cyber2000fb_enable_extregs;
- info->disable_extregs = cyber2000fb_disable_extregs;
info->info = int_cfb_info;
strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
@@ -1141,6 +1156,183 @@ void cyber2000fb_detach(int idx)
}
EXPORT_SYMBOL(cyber2000fb_detach);
+#ifdef CONFIG_FB_CYBER2000_DDC
+
+#define DDC_REG 0xb0
+#define DDC_SCL_OUT (1 << 0)
+#define DDC_SDA_OUT (1 << 4)
+#define DDC_SCL_IN (1 << 2)
+#define DDC_SDA_IN (1 << 6)
+
+static void cyber2000fb_enable_ddc(struct cfb_info *cfb)
+{
+ spin_lock(&cfb->reg_b0_lock);
+ cyber2000fb_writew(0x1bf, 0x3ce, cfb);
+}
+
+static void cyber2000fb_disable_ddc(struct cfb_info *cfb)
+{
+ cyber2000fb_writew(0x0bf, 0x3ce, cfb);
+ spin_unlock(&cfb->reg_b0_lock);
+}
+
+
+static void cyber2000fb_ddc_setscl(void *data, int val)
+{
+ struct cfb_info *cfb = data;
+ unsigned char reg;
+
+ cyber2000fb_enable_ddc(cfb);
+ reg = cyber2000_grphr(DDC_REG, cfb);
+ if (!val) /* bit is inverted */
+ reg |= DDC_SCL_OUT;
+ else
+ reg &= ~DDC_SCL_OUT;
+ cyber2000_grphw(DDC_REG, reg, cfb);
+ cyber2000fb_disable_ddc(cfb);
+}
+
+static void cyber2000fb_ddc_setsda(void *data, int val)
+{
+ struct cfb_info *cfb = data;
+ unsigned char reg;
+
+ cyber2000fb_enable_ddc(cfb);
+ reg = cyber2000_grphr(DDC_REG, cfb);
+ if (!val) /* bit is inverted */
+ reg |= DDC_SDA_OUT;
+ else
+ reg &= ~DDC_SDA_OUT;
+ cyber2000_grphw(DDC_REG, reg, cfb);
+ cyber2000fb_disable_ddc(cfb);
+}
+
+static int cyber2000fb_ddc_getscl(void *data)
+{
+ struct cfb_info *cfb = data;
+ int retval;
+
+ cyber2000fb_enable_ddc(cfb);
+ retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SCL_IN);
+ cyber2000fb_disable_ddc(cfb);
+
+ return retval;
+}
+
+static int cyber2000fb_ddc_getsda(void *data)
+{
+ struct cfb_info *cfb = data;
+ int retval;
+
+ cyber2000fb_enable_ddc(cfb);
+ retval = !!(cyber2000_grphr(DDC_REG, cfb) & DDC_SDA_IN);
+ cyber2000fb_disable_ddc(cfb);
+
+ return retval;
+}
+
+static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+{
+ strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
+ sizeof(cfb->ddc_adapter.name));
+ cfb->ddc_adapter.owner = THIS_MODULE;
+ cfb->ddc_adapter.class = I2C_CLASS_DDC;
+ cfb->ddc_adapter.algo_data = &cfb->ddc_algo;
+ cfb->ddc_adapter.dev.parent = cfb->fb.device;
+ cfb->ddc_algo.setsda = cyber2000fb_ddc_setsda;
+ cfb->ddc_algo.setscl = cyber2000fb_ddc_setscl;
+ cfb->ddc_algo.getsda = cyber2000fb_ddc_getsda;
+ cfb->ddc_algo.getscl = cyber2000fb_ddc_getscl;
+ cfb->ddc_algo.udelay = 10;
+ cfb->ddc_algo.timeout = 20;
+ cfb->ddc_algo.data = cfb;
+
+ i2c_set_adapdata(&cfb->ddc_adapter, cfb);
+
+ return i2c_bit_add_bus(&cfb->ddc_adapter);
+}
+#endif /* CONFIG_FB_CYBER2000_DDC */
+
+#ifdef CONFIG_FB_CYBER2000_I2C
+static void cyber2000fb_i2c_setsda(void *data, int state)
+{
+ struct cfb_info *cfb = data;
+ unsigned int latch2;
+
+ spin_lock(&cfb->reg_b0_lock);
+ latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
+ latch2 &= EXT_LATCH2_I2C_CLKEN;
+ if (state)
+ latch2 |= EXT_LATCH2_I2C_DATEN;
+ cyber2000_grphw(EXT_LATCH2, latch2, cfb);
+ spin_unlock(&cfb->reg_b0_lock);
+}
+
+static void cyber2000fb_i2c_setscl(void *data, int state)
+{
+ struct cfb_info *cfb = data;
+ unsigned int latch2;
+
+ spin_lock(&cfb->reg_b0_lock);
+ latch2 = cyber2000_grphr(EXT_LATCH2, cfb);
+ latch2 &= EXT_LATCH2_I2C_DATEN;
+ if (state)
+ latch2 |= EXT_LATCH2_I2C_CLKEN;
+ cyber2000_grphw(EXT_LATCH2, latch2, cfb);
+ spin_unlock(&cfb->reg_b0_lock);
+}
+
+static int cyber2000fb_i2c_getsda(void *data)
+{
+ struct cfb_info *cfb = data;
+ int ret;
+
+ spin_lock(&cfb->reg_b0_lock);
+ ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_DAT);
+ spin_unlock(&cfb->reg_b0_lock);
+
+ return ret;
+}
+
+static int cyber2000fb_i2c_getscl(void *data)
+{
+ struct cfb_info *cfb = data;
+ int ret;
+
+ spin_lock(&cfb->reg_b0_lock);
+ ret = !!(cyber2000_grphr(EXT_LATCH2, cfb) & EXT_LATCH2_I2C_CLK);
+ spin_unlock(&cfb->reg_b0_lock);
+
+ return ret;
+}
+
+static int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb)
+{
+ strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
+ sizeof(cfb->i2c_adapter.name));
+ cfb->i2c_adapter.owner = THIS_MODULE;
+ cfb->i2c_adapter.algo_data = &cfb->i2c_algo;
+ cfb->i2c_adapter.dev.parent = cfb->fb.device;
+ cfb->i2c_algo.setsda = cyber2000fb_i2c_setsda;
+ cfb->i2c_algo.setscl = cyber2000fb_i2c_setscl;
+ cfb->i2c_algo.getsda = cyber2000fb_i2c_getsda;
+ cfb->i2c_algo.getscl = cyber2000fb_i2c_getscl;
+ cfb->i2c_algo.udelay = 5;
+ cfb->i2c_algo.timeout = msecs_to_jiffies(100);
+ cfb->i2c_algo.data = cfb;
+
+ return i2c_bit_add_bus(&cfb->i2c_adapter);
+}
+
+static void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
+{
+ i2c_del_adapter(&cfb->i2c_adapter);
+}
+#else
+#define cyber2000fb_i2c_register(cfb) (0)
+#define cyber2000fb_i2c_unregister(cfb) do { } while (0)
+#endif
+
/*
* These parameters give
* 640x480, hsync 31.5kHz, vsync 60Hz
@@ -1275,6 +1467,8 @@ static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id,
cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
cfb->fb.pseudo_palette = cfb->pseudo_palette;
+ spin_lock_init(&cfb->reg_b0_lock);
+
fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
return cfb;
@@ -1369,6 +1563,11 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
cfb->fb.fix.mmio_len = MMIO_SIZE;
cfb->fb.screen_base = cfb->region;
+#ifdef CONFIG_FB_CYBER2000_DDC
+ if (cyber2000fb_setup_ddc_bus(cfb) == 0)
+ cfb->ddc_registered = true;
+#endif
+
err = -EINVAL;
if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
&cyber2000fb_default_mode, 8)) {
@@ -1401,14 +1600,32 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
cfb->fb.var.xres, cfb->fb.var.yres,
h_sync / 1000, h_sync % 1000, v_sync);
- if (cfb->dev)
- cfb->fb.device = &cfb->dev->dev;
+ err = cyber2000fb_i2c_register(cfb);
+ if (err)
+ goto failed;
+
err = register_framebuffer(&cfb->fb);
+ if (err)
+ cyber2000fb_i2c_unregister(cfb);
failed:
+#ifdef CONFIG_FB_CYBER2000_DDC
+ if (err && cfb->ddc_registered)
+ i2c_del_adapter(&cfb->ddc_adapter);
+#endif
return err;
}
+static void __devexit cyberpro_common_remove(struct cfb_info *cfb)
+{
+ unregister_framebuffer(&cfb->fb);
+#ifdef CONFIG_FB_CYBER2000_DDC
+ if (cfb->ddc_registered)
+ i2c_del_adapter(&cfb->ddc_adapter);
+#endif
+ cyber2000fb_i2c_unregister(cfb);
+}
+
static void cyberpro_common_resume(struct cfb_info *cfb)
{
cyberpro_init_hw(cfb);
@@ -1442,12 +1659,13 @@ static int __devinit cyberpro_vl_probe(void)
if (!cfb)
goto failed_release;
- cfb->dev = NULL;
+ cfb->irq = -1;
cfb->region = ioremap(FB_START, FB_SIZE);
if (!cfb->region)
goto failed_ioremap;
cfb->regs = cfb->region + MMIO_OFFSET;
+ cfb->fb.device = NULL;
cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET;
cfb->fb.fix.smem_start = FB_START;
@@ -1585,12 +1803,13 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (err)
goto failed_regions;
- cfb->dev = dev;
+ cfb->irq = dev->irq;
cfb->region = pci_ioremap_bar(dev, 0);
if (!cfb->region)
goto failed_ioremap;
cfb->regs = cfb->region + MMIO_OFFSET;
+ cfb->fb.device = &dev->dev;
cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
@@ -1648,15 +1867,7 @@ static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
struct cfb_info *cfb = pci_get_drvdata(dev);
if (cfb) {
- /*
- * If unregister_framebuffer fails, then
- * we will be leaving hooks that could cause
- * oopsen laying around.
- */
- if (unregister_framebuffer(&cfb->fb))
- printk(KERN_WARNING "%s: danger Will Robinson, "
- "danger danger! Oopsen imminent!\n",
- cfb->fb.fix.id);
+ cyberpro_common_remove(cfb);
iounmap(cfb->region);
cyberpro_free_fb_info(cfb);
diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h
index de4fc43e51c1..bad69102e774 100644
--- a/drivers/video/cyber2000fb.h
+++ b/drivers/video/cyber2000fb.h
@@ -464,12 +464,14 @@ static void debug_printf(char *fmt, ...)
struct cfb_info;
struct cyberpro_info {
- struct pci_dev *dev;
+ struct device *dev;
+ struct i2c_adapter *i2c;
unsigned char __iomem *regs;
char __iomem *fb;
char dev_name[32];
unsigned int fb_size;
unsigned int chip_id;
+ unsigned int irq;
/*
* The following is a pointer to be passed into the
@@ -478,15 +480,6 @@ struct cyberpro_info {
* is within this structure.
*/
struct cfb_info *info;
-
- /*
- * Use these to enable the BM or TV registers. In an SMP
- * environment, these two function pointers should only be
- * called from the module_init() or module_exit()
- * functions.
- */
- void (*enable_extregs)(struct cfb_info *);
- void (*disable_extregs)(struct cfb_info *);
};
#define ID_IGA_1682 0
@@ -494,8 +487,6 @@ struct cyberpro_info {
#define ID_CYBERPRO_2010 2
#define ID_CYBERPRO_5000 3
-struct fb_var_screeninfo;
-
/*
* Note! Writing to the Cyber20x0 registers from an interrupt
* routine is definitely a bad idea atm.
@@ -504,4 +495,3 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx);
void cyber2000fb_detach(int idx);
void cyber2000fb_enable_extregs(struct cfb_info *cfb);
void cyber2000fb_disable_extregs(struct cfb_info *cfb);
-void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var);
diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h
index 4e3deb4e592b..d80477415caa 100644
--- a/drivers/video/msm/mdp_hw.h
+++ b/drivers/video/msm/mdp_hw.h
@@ -449,6 +449,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
#define PPP_CFG_MDP_XRGB_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
#define PPP_CFG_MDP_RGBA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
#define PPP_CFG_MDP_BGRA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
+#define PPP_CFG_MDP_RGBX_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
#define PPP_CFG_MDP_Y_CBCR_H2V2(dir) (PPP_##dir##_C2R_8BIT | \
PPP_##dir##_C0G_8BIT | \
@@ -488,12 +489,14 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8)
#define PPP_PACK_PATTERN_MDP_RGB_888 PPP_PACK_PATTERN_MDP_RGB_565
#define PPP_PACK_PATTERN_MDP_XRGB_8888 \
- MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
+ MDP_GET_PACK_PATTERN(CLR_B, CLR_G, CLR_R, CLR_ALPHA, 8)
#define PPP_PACK_PATTERN_MDP_ARGB_8888 PPP_PACK_PATTERN_MDP_XRGB_8888
#define PPP_PACK_PATTERN_MDP_RGBA_8888 \
MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8)
#define PPP_PACK_PATTERN_MDP_BGRA_8888 \
MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
+#define PPP_PACK_PATTERN_MDP_RGBX_8888 \
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8)
#define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1 \
MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8)
#define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V2 PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1
@@ -509,6 +512,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
#define PPP_CHROMA_SAMP_MDP_ARGB_8888(dir) PPP_OP_##dir##_CHROMA_RGB
#define PPP_CHROMA_SAMP_MDP_RGBA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
#define PPP_CHROMA_SAMP_MDP_BGRA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
+#define PPP_CHROMA_SAMP_MDP_RGBX_8888(dir) PPP_OP_##dir##_CHROMA_RGB
#define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
#define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V2(dir) PPP_OP_##dir##_CHROMA_420
#define PPP_CHROMA_SAMP_MDP_Y_CRCB_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
@@ -523,6 +527,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
[MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888,\
[MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888,\
[MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888,\
+ [MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888,\
[MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1,\
[MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2,\
[MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1,\
@@ -536,6 +541,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
[MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888(dir),\
[MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888(dir),\
[MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888(dir),\
+ [MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888(dir),\
[MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1(dir),\
[MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2(dir),\
[MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1(dir),\
@@ -547,7 +553,8 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
(img == MDP_YCRYCB_H2V1))
#define IS_RGB(img) ((img == MDP_RGB_565) | (img == MDP_RGB_888) | \
(img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
- (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888))
+ (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888) | \
+ (img == MDP_RGBX_8888))
#define HAS_ALPHA(img) ((img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
(img == MDP_BGRA_8888))
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 4ff001f4cbbd..2b6564e8bfea 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -69,6 +69,7 @@ static uint32_t bytes_per_pixel[] = {
[MDP_ARGB_8888] = 4,
[MDP_RGBA_8888] = 4,
[MDP_BGRA_8888] = 4,
+ [MDP_RGBX_8888] = 4,
[MDP_Y_CBCR_H2V1] = 1,
[MDP_Y_CBCR_H2V2] = 1,
[MDP_Y_CRCB_H2V1] = 1,
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index debe5933fd2e..ec351309e607 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -81,7 +81,6 @@ struct msmfb_info {
spinlock_t update_lock;
struct mutex panel_init_lock;
wait_queue_head_t frame_wq;
- struct workqueue_struct *resume_workqueue;
struct work_struct resume_work;
struct msmfb_callback dma_callback;
struct msmfb_callback vsync_callback;
@@ -111,7 +110,7 @@ static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback)
if (msmfb->sleeping == UPDATING &&
msmfb->frame_done == msmfb->update_frame) {
DLOG(SUSPEND_RESUME, "full update completed\n");
- queue_work(msmfb->resume_workqueue, &msmfb->resume_work);
+ schedule_work(&msmfb->resume_work);
}
spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
wake_up(&msmfb->frame_wq);
@@ -220,8 +219,8 @@ restart:
sleeping = msmfb->sleeping;
/* on a full update, if the last frame has not completed, wait for it */
- if (pan_display && (msmfb->frame_requested != msmfb->frame_done ||
- sleeping == UPDATING)) {
+ if ((pan_display && msmfb->frame_requested != msmfb->frame_done) ||
+ sleeping == UPDATING) {
int ret;
spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
ret = wait_event_interruptible_timeout(msmfb->frame_wq,
@@ -470,6 +469,18 @@ static void setup_fb_info(struct msmfb_info *msmfb)
fb_info->var.yoffset = 0;
if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) {
+ /*
+ * Set the param in the fixed screen, so userspace can't
+ * change it. This will be used to check for the
+ * capability.
+ */
+ fb_info->fix.reserved[0] = 0x5444;
+ fb_info->fix.reserved[1] = 0x5055;
+
+ /*
+ * This preloads the value so that if userspace doesn't
+ * change it, it will be a full update
+ */
fb_info->var.reserved[0] = 0x54445055;
fb_info->var.reserved[1] = 0;
fb_info->var.reserved[2] = (uint16_t)msmfb->xres |
@@ -559,12 +570,6 @@ static int msmfb_probe(struct platform_device *pdev)
spin_lock_init(&msmfb->update_lock);
mutex_init(&msmfb->panel_init_lock);
init_waitqueue_head(&msmfb->frame_wq);
- msmfb->resume_workqueue = create_workqueue("panel_on");
- if (msmfb->resume_workqueue == NULL) {
- printk(KERN_ERR "failed to create panel_on workqueue\n");
- ret = -ENOMEM;
- goto error_create_workqueue;
- }
INIT_WORK(&msmfb->resume_work, power_on_panel);
msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres,
GFP_KERNEL);
@@ -589,8 +594,6 @@ static int msmfb_probe(struct platform_device *pdev)
return 0;
error_register_framebuffer:
- destroy_workqueue(msmfb->resume_workqueue);
-error_create_workqueue:
iounmap(fb->screen_base);
error_setup_fbmem:
framebuffer_release(msmfb->fb);
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
new file mode 100644
index 000000000000..7d0284882984
--- /dev/null
+++ b/drivers/video/mxsfb.c
@@ -0,0 +1,919 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ *
+ * This code is based on:
+ * Author: Vitaly Wool <vital@embeddedalley.com>
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define DRIVER_NAME "mxsfb"
+
+/**
+ * @file
+ * @brief LCDIF driver for i.MX23 and i.MX28
+ *
+ * The LCDIF support four modes of operation
+ * - MPU interface (to drive smart displays) -> not supported yet
+ * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet
+ * - Dotclock interface (to drive LC displays with RGB data and sync signals)
+ * - DVI (to drive ITU-R BT656) -> not supported yet
+ *
+ * This driver depends on a correct setup of the pins used for this purpose
+ * (platform specific).
+ *
+ * For the developer: Don't forget to set the data bus width to the display
+ * in the imx_fb_videomode structure. You will else end up with ugly colours.
+ * If you fight against jitter you can vary the clock delay. This is a feature
+ * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give
+ * the required value in the imx_fb_videomode structure.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <mach/mxsfb.h>
+
+#define REG_SET 4
+#define REG_CLR 8
+
+#define LCDC_CTRL 0x00
+#define LCDC_CTRL1 0x10
+#define LCDC_V4_CTRL2 0x20
+#define LCDC_V3_TRANSFER_COUNT 0x20
+#define LCDC_V4_TRANSFER_COUNT 0x30
+#define LCDC_V4_CUR_BUF 0x40
+#define LCDC_V4_NEXT_BUF 0x50
+#define LCDC_V3_CUR_BUF 0x30
+#define LCDC_V3_NEXT_BUF 0x40
+#define LCDC_TIMING 0x60
+#define LCDC_VDCTRL0 0x70
+#define LCDC_VDCTRL1 0x80
+#define LCDC_VDCTRL2 0x90
+#define LCDC_VDCTRL3 0xa0
+#define LCDC_VDCTRL4 0xb0
+#define LCDC_DVICTRL0 0xc0
+#define LCDC_DVICTRL1 0xd0
+#define LCDC_DVICTRL2 0xe0
+#define LCDC_DVICTRL3 0xf0
+#define LCDC_DVICTRL4 0x100
+#define LCDC_V4_DATA 0x180
+#define LCDC_V3_DATA 0x1b0
+#define LCDC_V4_DEBUG0 0x1d0
+#define LCDC_V3_DEBUG0 0x1f0
+
+#define CTRL_SFTRST (1 << 31)
+#define CTRL_CLKGATE (1 << 30)
+#define CTRL_BYPASS_COUNT (1 << 19)
+#define CTRL_VSYNC_MODE (1 << 18)
+#define CTRL_DOTCLK_MODE (1 << 17)
+#define CTRL_DATA_SELECT (1 << 16)
+#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10)
+#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3)
+#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8)
+#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3)
+#define CTRL_MASTER (1 << 5)
+#define CTRL_DF16 (1 << 3)
+#define CTRL_DF18 (1 << 2)
+#define CTRL_DF24 (1 << 1)
+#define CTRL_RUN (1 << 0)
+
+#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
+
+
+#define VDCTRL0_ENABLE_PRESENT (1 << 28)
+#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27)
+#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26)
+#define VDCTRL0_DOTCLK_ACT_FAILING (1 << 25)
+#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20)
+#define VDCTRL0_HALF_LINE (1 << 19)
+#define VDCTRL0_HALF_LINE_MODE (1 << 18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29)
+#define VDCTRL3_VSYNC_ONLY (1 << 28)
+#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+
+#define DEBUG0_HSYNC (1 < 26)
+#define DEBUG0_VSYNC (1 < 25)
+
+#define MIN_XRES 120
+#define MIN_YRES 120
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+enum mxsfb_devtype {
+ MXSFB_V3,
+ MXSFB_V4,
+};
+
+/* CPU dependent register offsets */
+struct mxsfb_devdata {
+ unsigned transfer_count;
+ unsigned cur_buf;
+ unsigned next_buf;
+ unsigned debug0;
+ unsigned hs_wdth_mask;
+ unsigned hs_wdth_shift;
+ unsigned ipversion;
+};
+
+struct mxsfb_info {
+ struct fb_info fb_info;
+ struct platform_device *pdev;
+ struct clk *clk;
+ void __iomem *base; /* registers */
+ unsigned allocated_size;
+ int enabled;
+ unsigned ld_intf_width;
+ unsigned dotclk_delay;
+ const struct mxsfb_devdata *devdata;
+ int mapped;
+};
+
+#define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
+#define mxsfb_is_v4(host) (host->devdata->ipversion == 4)
+
+static const struct mxsfb_devdata mxsfb_devdata[] = {
+ [MXSFB_V3] = {
+ .transfer_count = LCDC_V3_TRANSFER_COUNT,
+ .cur_buf = LCDC_V3_CUR_BUF,
+ .next_buf = LCDC_V3_NEXT_BUF,
+ .debug0 = LCDC_V3_DEBUG0,
+ .hs_wdth_mask = 0xff,
+ .hs_wdth_shift = 24,
+ .ipversion = 3,
+ },
+ [MXSFB_V4] = {
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
+ .cur_buf = LCDC_V4_CUR_BUF,
+ .next_buf = LCDC_V4_NEXT_BUF,
+ .debug0 = LCDC_V4_DEBUG0,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ .ipversion = 4,
+ },
+};
+
+#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info))
+
+/* mask and shift depends on architecture */
+static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
+{
+ return (val & host->devdata->hs_wdth_mask) <<
+ host->devdata->hs_wdth_shift;
+}
+
+static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
+{
+ return (val >> host->devdata->hs_wdth_shift) &
+ host->devdata->hs_wdth_mask;
+}
+
+static const struct fb_bitfield def_rgb565[] = {
+ [RED] = {
+ .offset = 11,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_rgb666[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 6,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 6,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_rgb888[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int mxsfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ const struct fb_bitfield *rgb = NULL;
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+
+ var->xres_virtual = var->xres;
+
+ var->yres_virtual = var->yres;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ /* always expect RGB 565 */
+ rgb = def_rgb565;
+ break;
+ case 32:
+ switch (host->ld_intf_width) {
+ case STMLCDIF_8BIT:
+ pr_debug("Unsupported LCD bus width mapping\n");
+ break;
+ case STMLCDIF_16BIT:
+ case STMLCDIF_18BIT:
+ /* 24 bit to 18 bit mapping */
+ rgb = def_rgb666;
+ break;
+ case STMLCDIF_24BIT:
+ /* real 24 bit */
+ rgb = def_rgb888;
+ break;
+ }
+ break;
+ default:
+ pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /*
+ * Copy the RGB parameters for this display
+ * from the machine specific parameters.
+ */
+ var->red = rgb[RED];
+ var->green = rgb[GREEN];
+ var->blue = rgb[BLUE];
+ var->transp = rgb[TRANSP];
+
+ return 0;
+}
+
+static void mxsfb_enable_controller(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ u32 reg;
+
+ dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+ clk_enable(host->clk);
+ clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
+
+ /* if it was disabled, re-enable the mode again */
+ writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
+
+ /* enable the SYNC signals first, then the DMA engine */
+ reg = readl(host->base + LCDC_VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, host->base + LCDC_VDCTRL4);
+
+ writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET);
+
+ host->enabled = 1;
+}
+
+static void mxsfb_disable_controller(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ unsigned loop;
+ u32 reg;
+
+ dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_CLR);
+
+ loop = 1000;
+ while (loop) {
+ reg = readl(host->base + LCDC_CTRL);
+ if (!(reg & CTRL_RUN))
+ break;
+ loop--;
+ }
+
+ writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR);
+
+ clk_disable(host->clk);
+
+ host->enabled = 0;
+}
+
+static int mxsfb_set_par(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ u32 ctrl, vdctrl0, vdctrl4;
+ int line_size, fb_size;
+ int reenable = 0;
+
+ line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
+ fb_size = fb_info->var.yres_virtual * line_size;
+
+ if (fb_size > fb_info->fix.smem_len)
+ return -ENOMEM;
+
+ fb_info->fix.line_length = line_size;
+
+ /*
+ * It seems, you can't re-program the controller if it is still running.
+ * This may lead into shifted pictures (FIFO issue?).
+ * So, first stop the controller and drain its FIFOs
+ */
+ if (host->enabled) {
+ reenable = 1;
+ mxsfb_disable_controller(fb_info);
+ }
+
+ /* clear the FIFOs */
+ writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
+
+ ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER |
+ CTRL_SET_BUS_WIDTH(host->ld_intf_width);;
+
+ switch (fb_info->var.bits_per_pixel) {
+ case 16:
+ dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n");
+ ctrl |= CTRL_SET_WORD_LENGTH(0);
+ writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + LCDC_CTRL1);
+ break;
+ case 32:
+ dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n");
+ ctrl |= CTRL_SET_WORD_LENGTH(3);
+ switch (host->ld_intf_width) {
+ case STMLCDIF_8BIT:
+ dev_dbg(&host->pdev->dev,
+ "Unsupported LCD bus width mapping\n");
+ return -EINVAL;
+ case STMLCDIF_16BIT:
+ case STMLCDIF_18BIT:
+ /* 24 bit to 18 bit mapping */
+ ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
+ * each colour component
+ */
+ break;
+ case STMLCDIF_24BIT:
+ /* real 24 bit */
+ break;
+ }
+ /* do not use packed pixels = one pixel per word instead */
+ writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1);
+ break;
+ default:
+ dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n",
+ fb_info->var.bits_per_pixel);
+ return -EINVAL;
+ }
+
+ writel(ctrl, host->base + LCDC_CTRL);
+
+ writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) |
+ TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres),
+ host->base + host->devdata->transfer_count);
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len);
+ if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT)
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING;
+
+ writel(vdctrl0, host->base + LCDC_VDCTRL0);
+
+ /* frame length in lines */
+ writel(fb_info->var.upper_margin + fb_info->var.vsync_len +
+ fb_info->var.lower_margin + fb_info->var.yres,
+ host->base + LCDC_VDCTRL1);
+
+ /* line length in units of clocks or pixels */
+ writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin +
+ fb_info->var.hsync_len + fb_info->var.right_margin +
+ fb_info->var.xres),
+ host->base + LCDC_VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin +
+ fb_info->var.hsync_len) |
+ SET_VERT_WAIT_CNT(fb_info->var.upper_margin +
+ fb_info->var.vsync_len),
+ host->base + LCDC_VDCTRL3);
+
+ vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres);
+ if (mxsfb_is_v4(host))
+ vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay);
+ writel(vdctrl4, host->base + LCDC_VDCTRL4);
+
+ writel(fb_info->fix.smem_start +
+ fb_info->fix.line_length * fb_info->var.yoffset,
+ host->base + host->devdata->next_buf);
+
+ if (reenable)
+ mxsfb_enable_controller(fb_info);
+
+ return 0;
+}
+
+static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb_info)
+{
+ unsigned int val;
+ int ret = -EINVAL;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (fb_info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+
+ switch (fb_info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 12 or 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = fb_info->pseudo_palette;
+
+ val = chan_to_field(red, &fb_info->var.red);
+ val |= chan_to_field(green, &fb_info->var.green);
+ val |= chan_to_field(blue, &fb_info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+static int mxsfb_blank(int blank, struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ if (host->enabled)
+ mxsfb_disable_controller(fb_info);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ if (!host->enabled)
+ mxsfb_enable_controller(fb_info);
+ break;
+ }
+ return 0;
+}
+
+static int mxsfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ unsigned offset;
+
+ if (var->xoffset != 0)
+ return -EINVAL;
+
+ offset = fb_info->fix.line_length * var->yoffset;
+
+ /* update on next VSYNC */
+ writel(fb_info->fix.smem_start + offset,
+ host->base + host->devdata->next_buf);
+
+ return 0;
+}
+
+static struct fb_ops mxsfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mxsfb_check_var,
+ .fb_set_par = mxsfb_set_par,
+ .fb_setcolreg = mxsfb_setcolreg,
+ .fb_blank = mxsfb_blank,
+ .fb_pan_display = mxsfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __devinit mxsfb_restore_mode(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+ unsigned line_count;
+ unsigned period;
+ unsigned long pa, fbsize;
+ int bits_per_pixel, ofs;
+ u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
+ struct fb_videomode vmode;
+
+ /* Only restore the mode when the controller is running */
+ ctrl = readl(host->base + LCDC_CTRL);
+ if (!(ctrl & CTRL_RUN))
+ return -EINVAL;
+
+ vdctrl0 = readl(host->base + LCDC_VDCTRL0);
+ vdctrl2 = readl(host->base + LCDC_VDCTRL2);
+ vdctrl3 = readl(host->base + LCDC_VDCTRL3);
+ vdctrl4 = readl(host->base + LCDC_VDCTRL4);
+
+ transfer_count = readl(host->base + host->devdata->transfer_count);
+
+ vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+ vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count);
+
+ switch (CTRL_GET_WORD_LENGTH(ctrl)) {
+ case 0:
+ bits_per_pixel = 16;
+ break;
+ case 3:
+ bits_per_pixel = 32;
+ case 1:
+ default:
+ return -EINVAL;
+ }
+
+ fb_info->var.bits_per_pixel = bits_per_pixel;
+
+ vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U);
+ vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2);
+ vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len;
+ vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len -
+ vmode.left_margin - vmode.xres;
+ vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0);
+ period = readl(host->base + LCDC_VDCTRL1);
+ vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len;
+ vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres;
+
+ vmode.vmode = FB_VMODE_NONINTERLACED;
+
+ vmode.sync = 0;
+ if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH)
+ vmode.sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH)
+ vmode.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ pr_debug("Reconstructed video mode:\n");
+ pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n",
+ vmode.xres, vmode.yres,
+ vmode.hsync_len, vmode.left_margin, vmode.right_margin,
+ vmode.vsync_len, vmode.upper_margin, vmode.lower_margin);
+ pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock));
+
+ fb_add_videomode(&vmode, &fb_info->modelist);
+
+ host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl);
+ host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4);
+
+ fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3);
+
+ pa = readl(host->base + host->devdata->cur_buf);
+ fbsize = fb_info->fix.line_length * vmode.yres;
+ if (pa < fb_info->fix.smem_start)
+ return -EINVAL;
+ if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len)
+ return -EINVAL;
+ ofs = pa - fb_info->fix.smem_start;
+ if (ofs) {
+ memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
+ writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf);
+ }
+
+ line_count = fb_info->fix.smem_len / fb_info->fix.line_length;
+ fb_info->fix.ypanstep = 1;
+
+ clk_enable(host->clk);
+ host->enabled = 1;
+
+ return 0;
+}
+
+static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+ struct fb_var_screeninfo *var = &fb_info->var;
+ struct mxsfb_platform_data *pdata = host->pdev->dev.platform_data;
+ dma_addr_t fb_phys;
+ void *fb_virt;
+ unsigned fb_size = pdata->fb_size;
+
+ fb_info->fbops = &mxsfb_ops;
+ fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
+ strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id));
+ fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb_info->fix.ypanstep = 1;
+ fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
+ fb_info->fix.accel = FB_ACCEL_NONE;
+
+ var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16;
+ var->nonstd = 0;
+ var->activate = FB_ACTIVATE_NOW;
+ var->accel_flags = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ host->dotclk_delay = pdata->dotclk_delay;
+ host->ld_intf_width = pdata->ld_intf_width;
+
+ /* Memory allocation for framebuffer */
+ if (pdata->fb_phys) {
+ if (!fb_size)
+ return -EINVAL;
+
+ fb_phys = pdata->fb_phys;
+
+ if (!request_mem_region(fb_phys, fb_size, host->pdev->name))
+ return -ENOMEM;
+
+ fb_virt = ioremap(fb_phys, fb_size);
+ if (!fb_virt) {
+ release_mem_region(fb_phys, fb_size);
+ return -ENOMEM;
+ }
+ host->mapped = 1;
+ } else {
+ if (!fb_size)
+ fb_size = SZ_2M; /* default */
+ fb_virt = alloc_pages_exact(fb_size, GFP_DMA);
+ if (!fb_virt)
+ return -ENOMEM;
+
+ fb_phys = virt_to_phys(fb_virt);
+ }
+
+ fb_info->fix.smem_start = fb_phys;
+ fb_info->screen_base = fb_virt;
+ fb_info->screen_size = fb_info->fix.smem_len = fb_size;
+
+ if (mxsfb_restore_mode(host))
+ memset(fb_virt, 0, fb_size);
+
+ return 0;
+}
+
+static void __devexit mxsfb_free_videomem(struct mxsfb_info *host)
+{
+ struct fb_info *fb_info = &host->fb_info;
+
+ if (host->mapped) {
+ iounmap(fb_info->screen_base);
+ release_mem_region(fb_info->fix.smem_start,
+ fb_info->screen_size);
+ } else {
+ free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len);
+ }
+}
+
+static int __devinit mxsfb_probe(struct platform_device *pdev)
+{
+ struct mxsfb_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct mxsfb_info *host;
+ struct fb_info *fb_info;
+ struct fb_modelist *modelist;
+ int i, ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platformdata. Giving up\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Cannot get memory IO resource\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name))
+ return -EBUSY;
+
+ fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev);
+ if (!fb_info) {
+ dev_err(&pdev->dev, "Failed to allocate fbdev\n");
+ ret = -ENOMEM;
+ goto error_alloc_info;
+ }
+
+ host = to_imxfb_host(fb_info);
+
+ host->base = ioremap(res->start, resource_size(res));
+ if (!host->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto error_ioremap;
+ }
+
+ host->pdev = pdev;
+ platform_set_drvdata(pdev, host);
+
+ host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+
+ host->clk = clk_get(&host->pdev->dev, NULL);
+ if (IS_ERR(host->clk)) {
+ ret = PTR_ERR(host->clk);
+ goto error_getclock;
+ }
+
+ fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (!fb_info->pseudo_palette) {
+ ret = -ENOMEM;
+ goto error_pseudo_pallette;
+ }
+
+ INIT_LIST_HEAD(&fb_info->modelist);
+
+ ret = mxsfb_init_fbinfo(host);
+ if (ret != 0)
+ goto error_init_fb;
+
+ for (i = 0; i < pdata->mode_count; i++)
+ fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist);
+
+ modelist = list_first_entry(&fb_info->modelist,
+ struct fb_modelist, list);
+ fb_videomode_to_var(&fb_info->var, &modelist->mode);
+
+ /* init the color fields */
+ mxsfb_check_var(&fb_info->var, fb_info);
+
+ platform_set_drvdata(pdev, fb_info);
+
+ ret = register_framebuffer(fb_info);
+ if (ret != 0) {
+ dev_err(&pdev->dev,"Failed to register framebuffer\n");
+ goto error_register;
+ }
+
+ if (!host->enabled) {
+ writel(0, host->base + LCDC_CTRL);
+ mxsfb_set_par(fb_info);
+ mxsfb_enable_controller(fb_info);
+ }
+
+ dev_info(&pdev->dev, "initialized\n");
+
+ return 0;
+
+error_register:
+ if (host->enabled)
+ clk_disable(host->clk);
+ fb_destroy_modelist(&fb_info->modelist);
+error_init_fb:
+ kfree(fb_info->pseudo_palette);
+error_pseudo_pallette:
+ clk_put(host->clk);
+error_getclock:
+ iounmap(host->base);
+error_ioremap:
+ framebuffer_release(fb_info);
+error_alloc_info:
+ release_mem_region(res->start, resource_size(res));
+
+ return ret;
+}
+
+static int __devexit mxsfb_remove(struct platform_device *pdev)
+{
+ struct fb_info *fb_info = platform_get_drvdata(pdev);
+ struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (host->enabled)
+ mxsfb_disable_controller(fb_info);
+
+ unregister_framebuffer(fb_info);
+ kfree(fb_info->pseudo_palette);
+ mxsfb_free_videomem(host);
+ iounmap(host->base);
+ clk_put(host->clk);
+
+ framebuffer_release(fb_info);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_device_id mxsfb_devtype[] = {
+ {
+ .name = "imx23-fb",
+ .driver_data = MXSFB_V3,
+ }, {
+ .name = "imx28-fb",
+ .driver_data = MXSFB_V4,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
+
+static struct platform_driver mxsfb_driver = {
+ .probe = mxsfb_probe,
+ .remove = __devexit_p(mxsfb_remove),
+ .id_table = mxsfb_devtype,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init mxsfb_init(void)
+{
+ return platform_driver_register(&mxsfb_driver);
+}
+
+static void __exit mxsfb_exit(void)
+{
+ platform_driver_unregister(&mxsfb_driver);
+}
+
+module_init(mxsfb_init);
+module_exit(mxsfb_exit);
+
+MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 80b3b123dd7f..7c608c5ccf84 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -60,7 +60,7 @@ config W1_MASTER_GPIO
config HDQ_MASTER_OMAP
tristate "OMAP HDQ driver"
- depends on ARCH_OMAP2430 || ARCH_OMAP3
+ depends on SOC_OMAP2430 || ARCH_OMAP3
help
Say Y here if you want support for the 1-wire or HDQ Interface
on an OMAP processor.
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 908160e938dc..b69d71482554 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -533,6 +533,16 @@ config I6300ESB_WDT
To compile this driver as a module, choose M here: the
module will be called i6300esb.
+config INTEL_SCU_WATCHDOG
+ bool "Intel SCU Watchdog for Mobile Platforms"
+ depends on WATCHDOG
+ depends on INTEL_SCU_IPC
+ ---help---
+ Hardware driver for the watchdog time built into the Intel SCU
+ for Intel Mobile Platforms.
+
+ To compile this driver as a module, choose M here.
+
config ITCO_WDT
tristate "Intel TCO Timer/Watchdog"
depends on (X86 || IA64) && PCI
@@ -580,7 +590,7 @@ config IT87_WDT
depends on X86 && EXPERIMENTAL
---help---
This is the driver for the hardware watchdog on the ITE IT8702,
- IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips.
+ IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
@@ -589,18 +599,20 @@ config IT87_WDT
be called it87_wdt.
config HP_WATCHDOG
- tristate "HP Proliant iLO2+ Hardware Watchdog Timer"
+ tristate "HP ProLiant iLO2+ Hardware Watchdog Timer"
depends on X86
+ default m
help
A software monitoring watchdog and NMI sourcing driver. This driver
will detect lockups and provide a stack trace. This is a driver that
- will only load on a HP ProLiant system with a minimum of iLO2 support.
+ will only load on an HP ProLiant system with a minimum of iLO2 support.
To compile this driver as a module, choose M here: the module will be
called hpwdt.
config HPWDT_NMI_DECODING
bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer"
depends on HP_WATCHDOG
+ default y
help
When an NMI occurs this feature will make the necessary BIOS calls to
log the cause of the NMI.
@@ -903,6 +915,12 @@ config INDYDOG
timer expired and no process has written to /dev/watchdog during
that time.
+config JZ4740_WDT
+ tristate "Ingenic jz4740 SoC hardware watchdog"
+ depends on MACH_JZ4740
+ help
+ Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs.
+
config WDT_MTX1
tristate "MTX-1 Hardware Watchdog"
depends on MIPS_MTX1
@@ -1111,6 +1129,16 @@ config WATCHDOG_RIO
# XTENSA Architecture
+# Xen Architecture
+
+config XEN_WDT
+ tristate "Xen Watchdog support"
+ depends on XEN
+ help
+ Say Y here to support the hypervisor watchdog capability provided
+ by Xen 4.0 and newer. The watchdog timeout period is normally one
+ minute but can be changed with a boot-time parameter.
+
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 20e44c4782b3..d520bf9c3355 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
+obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
# M32R Architecture
@@ -114,6 +115,7 @@ obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
@@ -148,6 +150,9 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o
# XTENSA Architecture
+# Xen
+obj-$(CONFIG_XEN_WDT) += xen_wdt.o
+
# Architecture Independant
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index fa4d36033552..f16dcbd475fb 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
* want to register another driver on the same PCI id.
*/
-static struct pci_device_id ali_pci_tbl[] __used = {
+static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = {
{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
@@ -362,12 +362,12 @@ static int __init ali_find_watchdog(void)
*/
static const struct file_operations ali_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
.write = ali_write,
.unlocked_ioctl = ali_ioctl,
- .open = ali_open,
- .release = ali_release,
+ .open = ali_open,
+ .release = ali_release,
};
static struct miscdevice ali_miscdev = {
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 4b7a2b4138ed..46f4b85b46de 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -430,7 +430,7 @@ err_out:
module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
-static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = {
+static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 5f245522397b..bd44417c84d4 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -150,8 +150,8 @@ static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
}
static const struct watchdog_info bcm47xx_wdt_info = {
- .identity = DRV_NAME,
- .options = WDIOF_SETTIMEOUT |
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 9042a95fc98c..b9fa9b71583a 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(bfin_wdt_spinlock);
/**
* bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
*
- * The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ * The Userspace watchdog got a KeepAlive: schedule the next timeout.
*/
static int bfin_wdt_keepalive(void)
{
@@ -337,7 +337,7 @@ static int bfin_wdt_resume(struct platform_device *pdev)
static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .write = bfin_wdt_write,
+ .write = bfin_wdt_write,
.unlocked_ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open,
.release = bfin_wdt_release,
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index 7e7ec9c35b6a..337265b47305 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
* Author: Matthew McClintock
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
- * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc.
+ * Copyright 2005, 2008, 2010-2011 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 the
@@ -221,9 +221,8 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
on_each_cpu(__booke_wdt_enable, NULL, 0);
- printk(KERN_INFO
- "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
- booke_wdt_period);
+ pr_debug("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+ period_to_sec(booke_wdt_period));
}
spin_unlock(&booke_wdt_lock);
@@ -240,6 +239,7 @@ static int booke_wdt_release(struct inode *inode, struct file *file)
*/
on_each_cpu(__booke_wdt_disable, NULL, 0);
booke_wdt_enabled = 0;
+ pr_debug("booke_wdt: watchdog disabled\n");
#endif
clear_bit(0, &wdt_is_active);
@@ -271,21 +271,20 @@ static int __init booke_wdt_init(void)
{
int ret = 0;
- printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+ pr_info("booke_wdt: powerpc book-e watchdog driver loaded\n");
ident.firmware_version = cur_cpu_spec->pvr_value;
ret = misc_register(&booke_wdt_miscdev);
if (ret) {
- printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n",
- WATCHDOG_MINOR, ret);
+ pr_err("booke_wdt: cannot register device (minor=%u, ret=%i)\n",
+ WATCHDOG_MINOR, ret);
return ret;
}
spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) {
- printk(KERN_INFO
- "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
- booke_wdt_period);
+ pr_info("booke_wdt: watchdog enabled (timeout = %llu sec)\n",
+ period_to_sec(booke_wdt_period));
on_each_cpu(__booke_wdt_enable, NULL, 0);
}
spin_unlock(&booke_wdt_lock);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 65911678453d..1e013e8457b7 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -5,10 +5,10 @@
* interface and Solaris-compatible ioctls as best it is
* able.
*
- * NOTE: CP1400 systems appear to have a defective intr_mask
- * register on the PLD, preventing the disabling of
- * timer interrupts. We use a timer to periodically
- * reset 'stopped' watchdogs on affected platforms.
+ * NOTE: CP1400 systems appear to have a defective intr_mask
+ * register on the PLD, preventing the disabling of
+ * timer interrupts. We use a timer to periodically
+ * reset 'stopped' watchdogs on affected platforms.
*
* Copyright (c) 2000 Eric Brower (ebrower@usa.net)
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
@@ -107,13 +107,13 @@ static struct cpwd *cpwd_device;
* -------------------
* |- counter val -|
* -------------------
- * dcntr - Current 16-bit downcounter value.
- * When downcounter reaches '0' watchdog expires.
- * Reading this register resets downcounter with
- * 'limit' value.
- * limit - 16-bit countdown value in 1/10th second increments.
- * Writing this register begins countdown with input value.
- * Reading from this register does not affect counter.
+ * dcntr - Current 16-bit downcounter value.
+ * When downcounter reaches '0' watchdog expires.
+ * Reading this register resets downcounter with
+ * 'limit' value.
+ * limit - 16-bit countdown value in 1/10th second increments.
+ * Writing this register begins countdown with input value.
+ * Reading from this register does not affect counter.
* NOTES: After watchdog reset, dcntr and limit contain '1'
*
* status register (byte access):
@@ -123,7 +123,7 @@ static struct cpwd *cpwd_device;
* |- UNUSED -| EXP | RUN |
* ---------------------------
* status- Bit 0 - Watchdog is running
- * Bit 1 - Watchdog has expired
+ * Bit 1 - Watchdog has expired
*
*** PLD register block definition (struct wd_pld_regblk)
*
@@ -197,7 +197,7 @@ static u8 cpwd_readb(void __iomem *addr)
* Because of the CP1400 defect this should only be
* called during initialzation or by wd_[start|stop]timer()
*
- * index - sub-device index, or -1 for 'all'
+ * index - sub-device index, or -1 for 'all'
* enable - non-zero to enable interrupts, zero to disable
*/
static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
@@ -317,13 +317,13 @@ static int cpwd_getstatus(struct cpwd *p, int index)
} else {
/* Fudge WD_EXPIRED status for defective CP1400--
* IF timer is running
- * AND brokenstop is set
- * AND an interrupt has been serviced
+ * AND brokenstop is set
+ * AND an interrupt has been serviced
* we are WD_EXPIRED.
*
* IF timer is running
- * AND brokenstop is set
- * AND no interrupt has been serviced
+ * AND brokenstop is set
+ * AND no interrupt has been serviced
* we are WD_FREERUN.
*/
if (p->broken &&
@@ -613,7 +613,7 @@ static int __devinit cpwd_probe(struct platform_device *op)
if (p->broken) {
init_timer(&cpwd_timer);
- cpwd_timer.function = cpwd_brokentimer;
+ cpwd_timer.function = cpwd_brokentimer;
cpwd_timer.data = (unsigned long) p;
cpwd_timer.expires = WD_BTIMEOUT;
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index 3f3dc093ad68..f1d1da662fbe 100644
--- a/drivers/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
@@ -201,7 +201,7 @@ static void eurwdt_ping(void)
static ssize_t eurwdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- if (count) {
+ if (count) {
if (!nowayout) {
size_t i;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 204a5603c4ae..8cb26855bfed 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -52,7 +52,7 @@ static void __iomem *pci_mem_addr; /* the PCI-memory address */
static unsigned long __iomem *hpwdt_timer_reg;
static unsigned long __iomem *hpwdt_timer_con;
-static struct pci_device_id hpwdt_devices[] = {
+static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */
{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */
{0}, /* terminate list */
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index bb9750a03942..db45091ef434 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = {
/*
* Data for PCI driver interface
*/
-static struct pci_device_id esb_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
{ 0, }, /* End of list */
};
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 2c6c2b4ad8bf..35a0d12dad73 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -247,7 +247,7 @@ static struct {
{NULL, 0}
};
-#define ITCO_PCI_DEVICE(dev, data) \
+#define ITCO_PCI_DEVICE(dev, data) \
.vendor = PCI_VENDOR_ID_INTEL, \
.device = dev, \
.subvendor = PCI_ANY_ID, \
@@ -262,7 +262,7 @@ static struct {
* pci_driver, because the I/O Controller Hub has also other
* functions that probably will be registered by other drivers.
*/
-static struct pci_device_id iTCO_wdt_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)},
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
new file mode 100644
index 000000000000..919bdd16136f
--- /dev/null
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -0,0 +1,572 @@
+/*
+ * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
+ * for Intel part #(s):
+ * - AF82MP20 PCH
+ *
+ * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sfi.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/intel_scu_ipc.h>
+#include <asm/apb_timer.h>
+#include <asm/mrst.h>
+
+#include "intel_scu_watchdog.h"
+
+/* Bounds number of times we will retry loading time count */
+/* This retry is a work around for a silicon bug. */
+#define MAX_RETRY 16
+
+#define IPC_SET_WATCHDOG_TIMER 0xF8
+
+static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
+module_param(timer_margin, int, 0);
+MODULE_PARM_DESC(timer_margin,
+ "Watchdog timer margin"
+ "Time between interrupt and resetting the system"
+ "The range is from 1 to 160"
+ "This is the time for all keep alives to arrive");
+
+static int timer_set = DEFAULT_TIME;
+module_param(timer_set, int, 0);
+MODULE_PARM_DESC(timer_set,
+ "Default Watchdog timer setting"
+ "Complete cycle time"
+ "The range is from 1 to 170"
+ "This is the time for all keep alives to arrive");
+
+/* After watchdog device is closed, check force_boot. If:
+ * force_boot == 0, then force boot on next watchdog interrupt after close,
+ * force_boot == 1, then force boot immediately when device is closed.
+ */
+static int force_boot;
+module_param(force_boot, int, 0);
+MODULE_PARM_DESC(force_boot,
+ "A value of 1 means that the driver will reboot"
+ "the system immediately if the /dev/watchdog device is closed"
+ "A value of 0 means that when /dev/watchdog device is closed"
+ "the watchdog timer will be refreshed for one more interval"
+ "of length: timer_set. At the end of this interval, the"
+ "watchdog timer will reset the system."
+ );
+
+/* there is only one device in the system now; this can be made into
+ * an array in the future if we have more than one device */
+
+static struct intel_scu_watchdog_dev watchdog_device;
+
+/* Forces restart, if force_reboot is set */
+static void watchdog_fire(void)
+{
+ if (force_boot) {
+ printk(KERN_CRIT PFX "Initiating system reboot.\n");
+ emergency_restart();
+ printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+ }
+
+ else {
+ printk(KERN_CRIT PFX "Immediate Reboot Disabled\n");
+ printk(KERN_CRIT PFX
+ "System will reset when watchdog timer times out!\n");
+ }
+}
+
+static int check_timer_margin(int new_margin)
+{
+ if ((new_margin < MIN_TIME_CYCLE) ||
+ (new_margin > MAX_TIME - timer_set)) {
+ pr_debug("Watchdog timer: value of new_margin %d is out of the range %d to %d\n",
+ new_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * IPC operations
+ */
+static int watchdog_set_ipc(int soft_threshold, int threshold)
+{
+ u32 *ipc_wbuf;
+ u8 cbuf[16] = { '\0' };
+ int ipc_ret = 0;
+
+ ipc_wbuf = (u32 *)&cbuf;
+ ipc_wbuf[0] = soft_threshold;
+ ipc_wbuf[1] = threshold;
+
+ ipc_ret = intel_scu_ipc_command(
+ IPC_SET_WATCHDOG_TIMER,
+ 0,
+ ipc_wbuf,
+ 2,
+ NULL,
+ 0);
+
+ if (ipc_ret != 0)
+ pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
+
+ return ipc_ret;
+};
+
+/*
+ * Intel_SCU operations
+ */
+
+/* timer interrupt handler */
+static irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
+{
+ int int_status;
+ int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
+
+ pr_debug("Watchdog timer: irq, int_status: %x\n", int_status);
+
+ if (int_status != 0)
+ return IRQ_NONE;
+
+ /* has the timer been started? If not, then this is spurious */
+ if (watchdog_device.timer_started == 0) {
+ pr_debug("Watchdog timer: spurious interrupt received\n");
+ return IRQ_HANDLED;
+ }
+
+ /* temporarily disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+ /* set the timer to the threshold */
+ iowrite32(watchdog_device.threshold,
+ watchdog_device.timer_load_count_addr);
+
+ /* allow the timer to run */
+ iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+ return IRQ_HANDLED;
+}
+
+static int intel_scu_keepalive(void)
+{
+
+ /* read eoi register - clears interrupt */
+ ioread32(watchdog_device.timer_clear_interrupt_addr);
+
+ /* temporarily disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+ /* set the timer to the soft_threshold */
+ iowrite32(watchdog_device.soft_threshold,
+ watchdog_device.timer_load_count_addr);
+
+ /* allow the timer to run */
+ iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+ return 0;
+}
+
+static int intel_scu_stop(void)
+{
+ iowrite32(0, watchdog_device.timer_control_addr);
+ return 0;
+}
+
+static int intel_scu_set_heartbeat(u32 t)
+{
+ int ipc_ret;
+ int retry_count;
+ u32 soft_value;
+ u32 hw_pre_value;
+ u32 hw_value;
+
+ watchdog_device.timer_set = t;
+ watchdog_device.threshold =
+ timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+ watchdog_device.soft_threshold =
+ (watchdog_device.timer_set - timer_margin)
+ * watchdog_device.timer_tbl_ptr->freq_hz;
+
+ pr_debug("Watchdog timer: set_heartbeat: timer freq is %d\n",
+ watchdog_device.timer_tbl_ptr->freq_hz);
+ pr_debug("Watchdog timer: set_heartbeat: timer_set is %x (hex)\n",
+ watchdog_device.timer_set);
+ pr_debug("Watchdog timer: set_hearbeat: timer_margin is %x (hex)\n",
+ timer_margin);
+ pr_debug("Watchdog timer: set_heartbeat: threshold is %x (hex)\n",
+ watchdog_device.threshold);
+ pr_debug("Watchdog timer: set_heartbeat: soft_threshold is %x (hex)\n",
+ watchdog_device.soft_threshold);
+
+ /* Adjust thresholds by FREQ_ADJUSTMENT factor, to make the */
+ /* watchdog timing come out right. */
+ watchdog_device.threshold =
+ watchdog_device.threshold / FREQ_ADJUSTMENT;
+ watchdog_device.soft_threshold =
+ watchdog_device.soft_threshold / FREQ_ADJUSTMENT;
+
+ /* temporarily disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+ /* send the threshold and soft_threshold via IPC to the processor */
+ ipc_ret = watchdog_set_ipc(watchdog_device.soft_threshold,
+ watchdog_device.threshold);
+
+ if (ipc_ret != 0) {
+ /* Make sure the watchdog timer is stopped */
+ intel_scu_stop();
+ return ipc_ret;
+ }
+
+ /* Soft Threshold set loop. Early versions of silicon did */
+ /* not always set this count correctly. This loop checks */
+ /* the value and retries if it was not set correctly. */
+
+ retry_count = 0;
+ soft_value = watchdog_device.soft_threshold & 0xFFFF0000;
+ do {
+
+ /* Make sure timer is stopped */
+ intel_scu_stop();
+
+ if (MAX_RETRY < retry_count++) {
+ /* Unable to set timer value */
+ pr_err("Watchdog timer: Unable to set timer\n");
+ return -ENODEV;
+ }
+
+ /* set the timer to the soft threshold */
+ iowrite32(watchdog_device.soft_threshold,
+ watchdog_device.timer_load_count_addr);
+
+ /* read count value before starting timer */
+ hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
+ hw_pre_value = hw_pre_value & 0xFFFF0000;
+
+ /* Start the timer */
+ iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+ /* read the value the time loaded into its count reg */
+ hw_value = ioread32(watchdog_device.timer_load_count_addr);
+ hw_value = hw_value & 0xFFFF0000;
+
+
+ } while (soft_value != hw_value);
+
+ watchdog_device.timer_started = 1;
+
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int intel_scu_open(struct inode *inode, struct file *file)
+{
+
+ /* Set flag to indicate that watchdog device is open */
+ if (test_and_set_bit(0, &watchdog_device.driver_open))
+ return -EBUSY;
+
+ /* Check for reopen of driver. Reopens are not allowed */
+ if (watchdog_device.driver_closed)
+ return -EPERM;
+
+ return nonseekable_open(inode, file);
+}
+
+static int intel_scu_release(struct inode *inode, struct file *file)
+{
+ /*
+ * This watchdog should not be closed, after the timer
+ * is started with the WDIPC_SETTIMEOUT ioctl
+ * If force_boot is set watchdog_fire() will cause an
+ * immediate reset. If force_boot is not set, the watchdog
+ * timer is refreshed for one more interval. At the end
+ * of that interval, the watchdog timer will reset the system.
+ */
+
+ if (!test_and_clear_bit(0, &watchdog_device.driver_open)) {
+ pr_debug("Watchdog timer: intel_scu_release, without open\n");
+ return -ENOTTY;
+ }
+
+ if (!watchdog_device.timer_started) {
+ /* Just close, since timer has not been started */
+ pr_debug("Watchdog timer: closed, without starting timer\n");
+ return 0;
+ }
+
+ printk(KERN_CRIT PFX
+ "Unexpected close of /dev/watchdog!\n");
+
+ /* Since the timer was started, prevent future reopens */
+ watchdog_device.driver_closed = 1;
+
+ /* Refresh the timer for one more interval */
+ intel_scu_keepalive();
+
+ /* Reboot system (if force_boot is set) */
+ watchdog_fire();
+
+ /* We should only reach this point if force_boot is not set */
+ return 0;
+}
+
+static ssize_t intel_scu_write(struct file *file,
+ char const *data,
+ size_t len,
+ loff_t *ppos)
+{
+
+ if (watchdog_device.timer_started)
+ /* Watchdog already started, keep it alive */
+ intel_scu_keepalive();
+ else
+ /* Start watchdog with timer value set by init */
+ intel_scu_set_heartbeat(watchdog_device.timer_set);
+
+ return len;
+}
+
+static long intel_scu_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ u32 __user *p = argp;
+ u32 new_margin;
+
+
+ static const struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT
+ | WDIOF_KEEPALIVEPING,
+ .firmware_version = 0, /* @todo Get from SCU via
+ ipc_get_scu_fw_version()? */
+ .identity = "Intel_SCU IOH Watchdog" /* len < 32 */
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp,
+ &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ intel_scu_keepalive();
+
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, p))
+ return -EFAULT;
+
+ if (check_timer_margin(new_margin))
+ return -EINVAL;
+
+ if (intel_scu_set_heartbeat(new_margin))
+ return -EINVAL;
+ return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(watchdog_device.soft_threshold, p);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Notifier for system down
+ */
+static int intel_scu_notify_sys(struct notifier_block *this,
+ unsigned long code,
+ void *another_unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ /* Turn off the watchdog timer. */
+ intel_scu_stop();
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+static const struct file_operations intel_scu_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = intel_scu_write,
+ .unlocked_ioctl = intel_scu_ioctl,
+ .open = intel_scu_open,
+ .release = intel_scu_release,
+};
+
+static int __init intel_scu_watchdog_init(void)
+{
+ int ret;
+ u32 __iomem *tmp_addr;
+
+ /*
+ * We don't really need to check this as the SFI timer get will fail
+ * but if we do so we can exit with a clearer reason and no noise.
+ *
+ * If it isn't an intel MID device then it doesn't have this watchdog
+ */
+ if (!mrst_identify_cpu())
+ return -ENODEV;
+
+ /* Check boot parameters to verify that their initial values */
+ /* are in range. */
+ /* Check value of timer_set boot parameter */
+ if ((timer_set < MIN_TIME_CYCLE) ||
+ (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
+ pr_err("Watchdog timer: value of timer_set %x (hex) "
+ "is out of range from %x to %x (hex)\n",
+ timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+ return -EINVAL;
+ }
+
+ /* Check value of timer_margin boot parameter */
+ if (check_timer_margin(timer_margin))
+ return -EINVAL;
+
+ watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
+
+ if (watchdog_device.timer_tbl_ptr == NULL) {
+ pr_debug("Watchdog timer - Intel SCU watchdog: timer is not available\n");
+ return -ENODEV;
+ }
+ /* make sure the timer exists */
+ if (watchdog_device.timer_tbl_ptr->phys_addr == 0) {
+ pr_debug("Watchdog timer - Intel SCU watchdog - timer %d does not have valid physical memory\n",
+ sfi_mtimer_num);
+ return -ENODEV;
+ }
+
+ if (watchdog_device.timer_tbl_ptr->irq == 0) {
+ pr_debug("Watchdog timer: timer %d invalid irq\n",
+ sfi_mtimer_num);
+ return -ENODEV;
+ }
+
+ tmp_addr = ioremap_nocache(watchdog_device.timer_tbl_ptr->phys_addr,
+ 20);
+
+ if (tmp_addr == NULL) {
+ pr_debug("Watchdog timer: timer unable to ioremap\n");
+ return -ENOMEM;
+ }
+
+ watchdog_device.timer_load_count_addr = tmp_addr++;
+ watchdog_device.timer_current_value_addr = tmp_addr++;
+ watchdog_device.timer_control_addr = tmp_addr++;
+ watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
+ watchdog_device.timer_interrupt_status_addr = tmp_addr++;
+
+ /* Set the default time values in device structure */
+
+ watchdog_device.timer_set = timer_set;
+ watchdog_device.threshold =
+ timer_margin * watchdog_device.timer_tbl_ptr->freq_hz;
+ watchdog_device.soft_threshold =
+ (watchdog_device.timer_set - timer_margin)
+ * watchdog_device.timer_tbl_ptr->freq_hz;
+
+
+ watchdog_device.intel_scu_notifier.notifier_call =
+ intel_scu_notify_sys;
+
+ ret = register_reboot_notifier(&watchdog_device.intel_scu_notifier);
+ if (ret) {
+ pr_err("Watchdog timer: cannot register notifier %d)\n", ret);
+ goto register_reboot_error;
+ }
+
+ watchdog_device.miscdev.minor = WATCHDOG_MINOR;
+ watchdog_device.miscdev.name = "watchdog";
+ watchdog_device.miscdev.fops = &intel_scu_fops;
+
+ ret = misc_register(&watchdog_device.miscdev);
+ if (ret) {
+ pr_err("Watchdog timer: cannot register miscdev %d err =%d\n",
+ WATCHDOG_MINOR, ret);
+ goto misc_register_error;
+ }
+
+ ret = request_irq((unsigned int)watchdog_device.timer_tbl_ptr->irq,
+ watchdog_timer_interrupt,
+ IRQF_SHARED, "watchdog",
+ &watchdog_device.timer_load_count_addr);
+ if (ret) {
+ pr_err("Watchdog timer: error requesting irq %d\n", ret);
+ goto request_irq_error;
+ }
+ /* Make sure timer is disabled before returning */
+ intel_scu_stop();
+ return 0;
+
+/* error cleanup */
+
+request_irq_error:
+ misc_deregister(&watchdog_device.miscdev);
+misc_register_error:
+ unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+register_reboot_error:
+ intel_scu_stop();
+ iounmap(watchdog_device.timer_load_count_addr);
+ return ret;
+}
+
+static void __exit intel_scu_watchdog_exit(void)
+{
+
+ misc_deregister(&watchdog_device.miscdev);
+ unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
+ /* disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+ iounmap(watchdog_device.timer_load_count_addr);
+}
+
+late_initcall(intel_scu_watchdog_init);
+module_exit(intel_scu_watchdog_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel SCU Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_VERSION(WDT_VER);
diff --git a/drivers/watchdog/intel_scu_watchdog.h b/drivers/watchdog/intel_scu_watchdog.h
new file mode 100644
index 000000000000..d2b074a82db6
--- /dev/null
+++ b/drivers/watchdog/intel_scu_watchdog.h
@@ -0,0 +1,66 @@
+/*
+ * Intel_SCU 0.2: An Intel SCU IOH Based Watchdog Device
+ * for Intel part #(s):
+ * - AF82MP20 PCH
+ *
+ * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#ifndef __INTEL_SCU_WATCHDOG_H
+#define __INTEL_SCU_WATCHDOG_H
+
+#define PFX "Intel_SCU: "
+#define WDT_VER "0.3"
+
+/* minimum time between interrupts */
+#define MIN_TIME_CYCLE 1
+
+/* Time from warning to reboot is 2 seconds */
+#define DEFAULT_SOFT_TO_HARD_MARGIN 2
+
+#define MAX_TIME 170
+
+#define DEFAULT_TIME 5
+
+#define MAX_SOFT_TO_HARD_MARGIN (MAX_TIME-MIN_TIME_CYCLE)
+
+/* Ajustment to clock tick frequency to make timing come out right */
+#define FREQ_ADJUSTMENT 8
+
+struct intel_scu_watchdog_dev {
+ ulong driver_open;
+ ulong driver_closed;
+ u32 timer_started;
+ u32 timer_set;
+ u32 threshold;
+ u32 soft_threshold;
+ u32 __iomem *timer_load_count_addr;
+ u32 __iomem *timer_current_value_addr;
+ u32 __iomem *timer_control_addr;
+ u32 __iomem *timer_clear_interrupt_addr;
+ u32 __iomem *timer_interrupt_status_addr;
+ struct sfi_timer_table_entry *timer_tbl_ptr;
+ struct notifier_block intel_scu_notifier;
+ struct miscdevice miscdev;
+};
+
+extern int sfi_mtimer_num;
+
+/* extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); */
+#endif /* __INTEL_SCU_WATCHDOG_H */
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index b32c6c045b1a..6143f52ba6b8 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -69,7 +69,7 @@ static unsigned short address;
#define IT8712F_DEVID 0x8712
#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */
-#define LDN_GAME 0x09 /* Game Port */
+#define LDN_GAME 0x09 /* Game Port */
#define WDT_CONTROL 0x71 /* WDT Register: Control */
#define WDT_CONFIG 0x72 /* WDT Register: Configuration */
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index dad29245a6a7..b1bc72f9a209 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,7 +12,7 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
- * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726.
+ * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -45,7 +45,7 @@
#include <asm/system.h>
-#define WATCHDOG_VERSION "1.13"
+#define WATCHDOG_VERSION "1.14"
#define WATCHDOG_NAME "IT87 WDT"
#define PFX WATCHDOG_NAME ": "
#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
@@ -54,7 +54,7 @@
/* Defaults for Module Parameter */
#define DEFAULT_NOGAMEPORT 0
#define DEFAULT_EXCLUSIVE 1
-#define DEFAULT_TIMEOUT 60
+#define DEFAULT_TIMEOUT 60
#define DEFAULT_TESTMODE 0
#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
@@ -70,9 +70,9 @@
/* Configuration Registers and Functions */
#define LDNREG 0x07
#define CHIPID 0x20
-#define CHIPREV 0x22
+#define CHIPREV 0x22
#define ACTREG 0x30
-#define BASEREG 0x60
+#define BASEREG 0x60
/* Chip Id numbers */
#define NO_DEV_ID 0xffff
@@ -82,10 +82,11 @@
#define IT8716_ID 0x8716
#define IT8718_ID 0x8718
#define IT8720_ID 0x8720
+#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
/* GPIO Configuration Registers LDN=0x07 */
-#define WDTCTRL 0x71
+#define WDTCTRL 0x71
#define WDTCFG 0x72
#define WDTVALLSB 0x73
#define WDTVALMSB 0x74
@@ -94,7 +95,7 @@
#define WDT_CIRINT 0x80
#define WDT_MOUSEINT 0x40
#define WDT_KYBINT 0x20
-#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */
+#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721 */
#define WDT_FORCE 0x02
#define WDT_ZERO 0x01
@@ -102,11 +103,11 @@
#define WDT_TOV1 0x80
#define WDT_KRST 0x40
#define WDT_TOVE 0x20
-#define WDT_PWROK 0x10
+#define WDT_PWROK 0x10 /* not in it8721 */
#define WDT_INT_MASK 0x0f
/* CIR Configuration Register LDN=0x0a */
-#define CIR_ILS 0x70
+#define CIR_ILS 0x70
/* The default Base address is not always available, we use this */
#define CIR_BASE 0x0208
@@ -134,7 +135,7 @@
#define WDTS_USE_GP 4
#define WDTS_EXPECTED 5
-static unsigned int base, gpact, ciract, max_units;
+static unsigned int base, gpact, ciract, max_units, chip_type;
static unsigned long wdt_status;
static DEFINE_SPINLOCK(spinlock);
@@ -215,7 +216,7 @@ static inline void superio_outw(int val, int reg)
/* Internal function, should be called after superio_select(GPIO) */
static void wdt_update_timeout(void)
{
- unsigned char cfg = WDT_KRST | WDT_PWROK;
+ unsigned char cfg = WDT_KRST;
int tm = timeout;
if (testmode)
@@ -226,6 +227,9 @@ static void wdt_update_timeout(void)
else
tm /= 60;
+ if (chip_type != IT8721_ID)
+ cfg |= WDT_PWROK;
+
superio_outb(cfg, WDTCFG);
superio_outb(tm, WDTVALLSB);
if (max_units > 255)
@@ -555,7 +559,6 @@ static int __init it87_wdt_init(void)
{
int rc = 0;
int try_gameport = !nogameport;
- u16 chip_type;
u8 chip_rev;
unsigned long flags;
@@ -581,6 +584,7 @@ static int __init it87_wdt_init(void)
break;
case IT8718_ID:
case IT8720_ID:
+ case IT8721_ID:
max_units = 65535;
try_gameport = 0;
break;
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
new file mode 100644
index 000000000000..684ba01fb540
--- /dev/null
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2010, Paul Cercueil <paul@crapouillou.net>
+ * JZ4740 Watchdog driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <asm/mach-jz4740/timer.h>
+
+#define JZ_REG_WDT_TIMER_DATA 0x0
+#define JZ_REG_WDT_COUNTER_ENABLE 0x4
+#define JZ_REG_WDT_TIMER_COUNTER 0x8
+#define JZ_REG_WDT_TIMER_CONTROL 0xC
+
+#define JZ_WDT_CLOCK_PCLK 0x1
+#define JZ_WDT_CLOCK_RTC 0x2
+#define JZ_WDT_CLOCK_EXT 0x4
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+
+#define JZ_WDT_CLOCK_DIV_SHIFT 3
+
+#define JZ_WDT_CLOCK_DIV_1 (0 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_4 (1 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_16 (2 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_64 (3 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_256 (4 << JZ_WDT_CLOCK_DIV_SHIFT)
+#define JZ_WDT_CLOCK_DIV_1024 (5 << JZ_WDT_CLOCK_DIV_SHIFT)
+
+#define DEFAULT_HEARTBEAT 5
+#define MAX_HEARTBEAT 2048
+
+static struct {
+ void __iomem *base;
+ struct resource *mem;
+ struct clk *rtc_clk;
+ unsigned long status;
+} jz4740_wdt;
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+
+static void jz4740_wdt_service(void)
+{
+ writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+}
+
+static void jz4740_wdt_set_heartbeat(int new_heartbeat)
+{
+ unsigned int rtc_clk_rate;
+ unsigned int timeout_value;
+ unsigned short clock_div = JZ_WDT_CLOCK_DIV_1;
+
+ heartbeat = new_heartbeat;
+
+ rtc_clk_rate = clk_get_rate(jz4740_wdt.rtc_clk);
+
+ timeout_value = rtc_clk_rate * heartbeat;
+ while (timeout_value > 0xffff) {
+ if (clock_div == JZ_WDT_CLOCK_DIV_1024) {
+ /* Requested timeout too high;
+ * use highest possible value. */
+ timeout_value = 0xffff;
+ break;
+ }
+ timeout_value >>= 2;
+ clock_div += (1 << JZ_WDT_CLOCK_DIV_SHIFT);
+ }
+
+ writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+ writew(clock_div, jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+
+ writew((u16)timeout_value, jz4740_wdt.base + JZ_REG_WDT_TIMER_DATA);
+ writew(0x0, jz4740_wdt.base + JZ_REG_WDT_TIMER_COUNTER);
+ writew(clock_div | JZ_WDT_CLOCK_RTC,
+ jz4740_wdt.base + JZ_REG_WDT_TIMER_CONTROL);
+
+ writeb(0x1, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+}
+
+static void jz4740_wdt_enable(void)
+{
+ jz4740_timer_enable_watchdog();
+ jz4740_wdt_set_heartbeat(heartbeat);
+}
+
+static void jz4740_wdt_disable(void)
+{
+ jz4740_timer_disable_watchdog();
+ writeb(0x0, jz4740_wdt.base + JZ_REG_WDT_COUNTER_ENABLE);
+}
+
+static int jz4740_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &jz4740_wdt.status))
+ return -EBUSY;
+
+ jz4740_wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t jz4740_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status);
+ }
+ jz4740_wdt_service();
+ }
+
+ return len;
+}
+
+static const struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING,
+ .identity = "jz4740 Watchdog",
+};
+
+static long jz4740_wdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int heartbeat_seconds;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ jz4740_wdt_service();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(heartbeat_seconds, (int __user *)arg))
+ return -EFAULT;
+
+ jz4740_wdt_set_heartbeat(heartbeat_seconds);
+ return 0;
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, (int *)arg);
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int jz4740_wdt_release(struct inode *inode, struct file *file)
+{
+ jz4740_wdt_service();
+
+ if (test_and_clear_bit(WDT_OK_TO_CLOSE, &jz4740_wdt.status))
+ jz4740_wdt_disable();
+
+ clear_bit(WDT_IN_USE, &jz4740_wdt.status);
+ return 0;
+}
+
+static const struct file_operations jz4740_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = jz4740_wdt_write,
+ .unlocked_ioctl = jz4740_wdt_ioctl,
+ .open = jz4740_wdt_open,
+ .release = jz4740_wdt_release,
+};
+
+static struct miscdevice jz4740_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &jz4740_wdt_fops,
+};
+
+static int __devinit jz4740_wdt_probe(struct platform_device *pdev)
+{
+ int ret = 0, size;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "failed to get memory region resource\n");
+ return -ENXIO;
+ }
+
+ size = resource_size(res);
+ jz4740_wdt.mem = request_mem_region(res->start, size, pdev->name);
+ if (jz4740_wdt.mem == NULL) {
+ dev_err(dev, "failed to get memory region\n");
+ return -EBUSY;
+ }
+
+ jz4740_wdt.base = ioremap_nocache(res->start, size);
+ if (jz4740_wdt.base == NULL) {
+ dev_err(dev, "failed to map memory region\n");
+ ret = -EBUSY;
+ goto err_release_region;
+ }
+
+ jz4740_wdt.rtc_clk = clk_get(NULL, "rtc");
+ if (IS_ERR(jz4740_wdt.rtc_clk)) {
+ dev_err(dev, "cannot find RTC clock\n");
+ ret = PTR_ERR(jz4740_wdt.rtc_clk);
+ goto err_iounmap;
+ }
+
+ ret = misc_register(&jz4740_wdt_miscdev);
+ if (ret < 0) {
+ dev_err(dev, "cannot register misc device\n");
+ goto err_disable_clk;
+ }
+
+ return 0;
+
+err_disable_clk:
+ clk_put(jz4740_wdt.rtc_clk);
+err_iounmap:
+ iounmap(jz4740_wdt.base);
+err_release_region:
+ release_mem_region(jz4740_wdt.mem->start,
+ resource_size(jz4740_wdt.mem));
+ return ret;
+}
+
+
+static int __devexit jz4740_wdt_remove(struct platform_device *pdev)
+{
+ jz4740_wdt_disable();
+ misc_deregister(&jz4740_wdt_miscdev);
+ clk_put(jz4740_wdt.rtc_clk);
+
+ iounmap(jz4740_wdt.base);
+ jz4740_wdt.base = NULL;
+
+ release_mem_region(jz4740_wdt.mem->start,
+ resource_size(jz4740_wdt.mem));
+ jz4740_wdt.mem = NULL;
+
+ return 0;
+}
+
+
+static struct platform_driver jz4740_wdt_driver = {
+ .probe = jz4740_wdt_probe,
+ .remove = __devexit_p(jz4740_wdt_remove),
+ .driver = {
+ .name = "jz4740-wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static int __init jz4740_wdt_init(void)
+{
+ return platform_driver_register(&jz4740_wdt_driver);
+}
+module_init(jz4740_wdt_init);
+
+static void __exit jz4740_wdt_exit(void)
+{
+ platform_driver_unregister(&jz4740_wdt_driver);
+}
+module_exit(jz4740_wdt_exit);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("jz4740 Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:jz4740-wdt");
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 928035069396..1332b838cc58 100644
--- a/drivers/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -54,7 +54,7 @@
/* indexes */ /* size */
#define ZFL_VERSION 0x02 /* 16 */
-#define CONTROL 0x10 /* 16 */
+#define CONTROL 0x10 /* 16 */
#define STATUS 0x12 /* 8 */
#define COUNTER_1 0x0C /* 16 */
#define COUNTER_2 0x0E /* 8 */
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index 3053ff05ca41..7a82ce5a6337 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -41,7 +41,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
* to ping the watchdog.
*/
#define MAX6369_WDSET (7 << 0)
-#define MAX6369_WDI (1 << 3)
+#define MAX6369_WDI (1 << 3)
static DEFINE_SPINLOCK(io_lock);
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index ea438ad53055..6709d723e017 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -2,9 +2,9 @@
* mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface
*
* Authors: Dave Updegraff <dave@cray.org>
- * Kumar Gala <galak@kernel.crashing.org>
- * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
- * ..and from sc520_wdt
+ * Kumar Gala <galak@kernel.crashing.org>
+ * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
+ * ..and from sc520_wdt
* Copyright (c) 2008 MontaVista Software, Inc.
* Anton Vorontsov <avorontsov@ru.mvista.com>
*
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index b8ec7aca3c8e..2b4af222b5f2 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -172,7 +172,7 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
/*
* Shut off the timer.
- * Lock it in if it's a module and we set nowayout
+ * Lock it in if it's a module and we set nowayout
*/
if (wdt->expect_close == 42)
mpcore_wdt_stop(wdt);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 08e8a6ab74e1..5ec5ac1f7878 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -190,19 +190,19 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
}
static const struct file_operations mtx1_wdt_fops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = mtx1_wdt_ioctl,
- .open = mtx1_wdt_open,
- .write = mtx1_wdt_write,
- .release = mtx1_wdt_release,
+ .open = mtx1_wdt_open,
+ .write = mtx1_wdt_write,
+ .release = mtx1_wdt_release,
};
static struct miscdevice mtx1_wdt_misc = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &mtx1_wdt_fops,
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mtx1_wdt_fops,
};
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
index 1a50aa7079bf..267377a5a83e 100644
--- a/drivers/watchdog/nv_tco.c
+++ b/drivers/watchdog/nv_tco.c
@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = {
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
-static struct pci_device_id tco_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(tco_pci_tbl) = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3dd4971160ef..2b4acb86c191 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -124,6 +124,8 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
u32 pre_margin = GET_WLDR_VAL(timer_margin);
void __iomem *base = wdev->base;
+ pm_runtime_get_sync(wdev->dev);
+
/* just count up at 32 KHz */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
@@ -131,6 +133,8 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
__raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax();
+
+ pm_runtime_put_sync(wdev->dev);
}
/*
@@ -160,6 +164,8 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
omap_wdt_ping(wdev); /* trigger loading of new timeout value */
omap_wdt_enable(wdev);
+ pm_runtime_put_sync(wdev->dev);
+
return nonseekable_open(inode, file);
}
@@ -171,6 +177,7 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
* Shut off the timer unless NOWAYOUT is defined.
*/
#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev);
@@ -190,9 +197,11 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
/* Refresh LOAD_TIME. */
if (len) {
+ pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock);
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
+ pm_runtime_put_sync(wdev->dev);
}
return len;
}
@@ -224,15 +233,18 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
return put_user(omap_prcm_get_reset_sources(),
(int __user *)arg);
case WDIOC_KEEPALIVE:
+ pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock);
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
+ pm_runtime_put_sync(wdev->dev);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int __user *)arg))
return -EFAULT;
omap_wdt_adjust_timeout(new_margin);
+ pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock);
omap_wdt_disable(wdev);
omap_wdt_set_timeout(wdev);
@@ -240,6 +252,7 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
omap_wdt_ping(wdev);
spin_unlock(&wdt_lock);
+ pm_runtime_put_sync(wdev->dev);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg);
@@ -345,8 +358,11 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
- if (wdev->omap_wdt_users)
+ if (wdev->omap_wdt_users) {
+ pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev);
+ pm_runtime_put_sync(wdev->dev);
+ }
}
static int __devexit omap_wdt_remove(struct platform_device *pdev)
@@ -381,8 +397,11 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
- if (wdev->omap_wdt_users)
+ if (wdev->omap_wdt_users) {
+ pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev);
+ pm_runtime_put_sync(wdev->dev);
+ }
return 0;
}
@@ -392,8 +411,10 @@ static int omap_wdt_resume(struct platform_device *pdev)
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) {
+ pm_runtime_get_sync(wdev->dev);
omap_wdt_enable(wdev);
omap_wdt_ping(wdev);
+ pm_runtime_put_sync(wdev->dev);
}
return 0;
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index fc02ec6a0386..09b774cf75b9 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -44,7 +44,7 @@
* months before firing. These limits work without scaling,
* with the 60 second default assumed by most tools and docs.
*/
-#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
+#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
#define TIMER_MARGIN_MIN 1
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 3a56bc360924..139d773300c6 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -514,7 +514,7 @@ static struct miscdevice pc87413_miscdev = {
/* -- Module init functions -------------------------------------*/
/**
- * pc87413_init: module's "constructor"
+ * pc87413_init: module's "constructor"
*
* Set up the WDT watchdog board. All we have to do is grab the
* resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index 64374d636f09..b8d14f88f0b5 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -817,7 +817,7 @@ static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
cards_found--;
}
-static struct pci_device_id pcipcwd_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = {
{ PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }, /* End of list */
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index bf5b97c546eb..c7cf4cbf8ab3 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -4,7 +4,7 @@
* Watchdog driver for PNX4008 board
*
* Authors: Dmitry Chigirev <source@mvista.com>,
- * Vitaly Wool <vitalywool@gmail.com>
+ * Vitaly Wool <vitalywool@gmail.com>
* Based on sa1100 driver,
* Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
*
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index ae53662c29bc..25b39bf35925 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -224,7 +224,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we set nowayout
+ * Lock it in if it's a module and we set nowayout
*/
if (expect_close == 42)
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 68e2e2d6f73d..514ec23050f7 100644
--- a/drivers/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -114,7 +114,7 @@ static char expect_close;
* C | 6.5s 65s 650s 1300s
* D | 7s 70s 700s 1400s
* E | 7.5s 75s 750s 1500s
- * F | 8s 80s 800s 1600s
+ * F | 8s 80s 800s 1600s
*
* Another way to say the same things is:
* For N=1, Timeout = (M+1) * 0.5s
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index 28f1214457bd..3066a5127ca8 100644
--- a/drivers/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -220,7 +220,7 @@ module_exit(watchdog_exit);
MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC. "
"Note that there is no way to probe for this device -- "
- "so only use it if you are *sure* you are runnning on this specific "
+ "so only use it if you are *sure* you are running on this specific "
"SBC system from Winsystems! It writes to IO ports 0x1ee and 0x1ef!");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sbc_fitpc2_wdt.c b/drivers/watchdog/sbc_fitpc2_wdt.c
index 79906255eeb6..d5d399464599 100644
--- a/drivers/watchdog/sbc_fitpc2_wdt.c
+++ b/drivers/watchdog/sbc_fitpc2_wdt.c
@@ -41,7 +41,7 @@ static DEFINE_MUTEX(wdt_lock);
#define IFACE_ON_COMMAND 1
#define REBOOT_COMMAND 2
-#define WATCHDOG_NAME "SBC-FITPC2 Watchdog"
+#define WATCHDOG_NAME "SBC-FITPC2 Watchdog"
static void wdt_send_data(unsigned char command, unsigned char data)
{
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index 8a1f0bc3e271..df88cfa05f35 100644
--- a/drivers/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -434,11 +434,11 @@ static long wb_smsc_wdt_ioctl(struct file *file,
} uarg;
static const struct watchdog_info ident = {
- .options = WDIOF_KEEPALIVEPING |
+ .options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
- .identity = "SMsC 37B787 Watchdog",
+ .identity = "SMsC 37B787 Watchdog",
};
uarg.i = (int __user *)arg;
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 833f49f43d43..100b114e3c3c 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -151,7 +151,7 @@ static int softdog_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we set nowayout
+ * Lock it in if it's a module and we set nowayout
*/
if (expect_close == 42) {
softdog_stop();
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 808372883e88..1bc493848ed4 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -259,7 +259,7 @@ static struct miscdevice sp5100_tco_miscdev = {
* register a pci_driver, because someone else might
* want to register another driver on the same PCI id.
*/
-static struct pci_device_id sp5100_tco_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sp5100_tco_pci_tbl) = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
PCI_ANY_ID, },
{ 0, }, /* End of list */
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 9127eda2145b..0a0efe713bc8 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -278,7 +278,7 @@ static struct miscdevice sp805_wdt_miscdev = {
};
static int __devinit
-sp805_wdt_probe(struct amba_device *adev, struct amba_id *id)
+sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c
index 18cdeb4c4258..5a90a4a871dd 100644
--- a/drivers/watchdog/ts72xx_wdt.c
+++ b/drivers/watchdog/ts72xx_wdt.c
@@ -68,7 +68,7 @@ struct platform_device *ts72xx_wdt_pdev;
* to control register):
* value description
* -------------------------
- * 0x00 watchdog disabled
+ * 0x00 watchdog disabled
* 0x01 250ms
* 0x02 500ms
* 0x03 1s
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
index df2a64dc9672..be9c4d839e15 100644
--- a/drivers/watchdog/w83697ug_wdt.c
+++ b/drivers/watchdog/w83697ug_wdt.c
@@ -87,10 +87,10 @@ static int w83697ug_select_wd_register(void)
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
outb_p(0x87, WDT_EFER); /* Again according to manual */
- outb(0x20, WDT_EFER); /* check chip version */
+ outb(0x20, WDT_EFER); /* check chip version */
version = inb(WDT_EFDR);
- if (version == 0x68) { /* W83697UG */
+ if (version == 0x68) { /* W83697UG */
printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
"W83697UG/UF found at 0x%04x\n", version, wdt_io);
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 552a4381e78f..bb03e151a1d0 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -581,7 +581,7 @@ static void __exit wdt_exit(void)
}
/**
- * wdt_init:
+ * wdt_init:
*
* Set up the WDT watchdog board. All we have to do is grab the
* resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 5c2521fc836c..a2f01c9f5c34 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -281,7 +281,7 @@ static int wdt977_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
- * Lock it in if it's a module and we set nowayout
+ * Lock it in if it's a module and we set nowayout
*/
if (expect_close == 42) {
wdt977_stop();
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 6130c88fa5ac..172dad6c7693 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -31,7 +31,7 @@
* Jeff Garzik : PCI cleanups
* Tigran Aivazian : Restructured wdtpci_init_one() to handle
* failures
- * Joel Becker : Added WDIOC_GET/SETTIMEOUT
+ * Joel Becker : Added WDIOC_GET/SETTIMEOUT
* Zwane Mwaikambo : Magic char closing, locking changes,
* cleanups
* Matt Domsch : nowayout module option
@@ -727,7 +727,7 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
}
-static struct pci_device_id wdtpci_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(wdtpci_pci_tbl) = {
{
.vendor = PCI_VENDOR_ID_ACCESSIO,
.device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
@@ -764,7 +764,7 @@ static void __exit wdtpci_cleanup(void)
/**
- * wdtpci_init:
+ * wdtpci_init:
*
* Set up the WDT watchdog board. All we have to do is grab the
* resources we require and bitch if anyone beat us to them.
diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c
new file mode 100644
index 000000000000..49bd9d395562
--- /dev/null
+++ b/drivers/watchdog/xen_wdt.c
@@ -0,0 +1,359 @@
+/*
+ * Xen Watchdog Driver
+ *
+ * (c) Copyright 2010 Novell, 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 the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define DRV_NAME "wdt"
+#define DRV_VERSION "0.01"
+#define PFX DRV_NAME ": "
+
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+#include <xen/xen.h>
+#include <asm/xen/hypercall.h>
+#include <xen/interface/sched.h>
+
+static struct platform_device *platform_device;
+static DEFINE_SPINLOCK(wdt_lock);
+static struct sched_watchdog wdt;
+static __kernel_time_t wdt_expires;
+static bool is_active, expect_release;
+
+#define WATCHDOG_TIMEOUT 60 /* in seconds */
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
+ "(default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static inline __kernel_time_t set_timeout(void)
+{
+ wdt.timeout = timeout;
+ return ktime_to_timespec(ktime_get()).tv_sec + timeout;
+}
+
+static int xen_wdt_start(void)
+{
+ __kernel_time_t expires;
+ int err;
+
+ spin_lock(&wdt_lock);
+
+ expires = set_timeout();
+ if (!wdt.id)
+ err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+ else
+ err = -EBUSY;
+ if (err > 0) {
+ wdt.id = err;
+ wdt_expires = expires;
+ err = 0;
+ } else
+ BUG_ON(!err);
+
+ spin_unlock(&wdt_lock);
+
+ return err;
+}
+
+static int xen_wdt_stop(void)
+{
+ int err = 0;
+
+ spin_lock(&wdt_lock);
+
+ wdt.timeout = 0;
+ if (wdt.id)
+ err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+ if (!err)
+ wdt.id = 0;
+
+ spin_unlock(&wdt_lock);
+
+ return err;
+}
+
+static int xen_wdt_kick(void)
+{
+ __kernel_time_t expires;
+ int err;
+
+ spin_lock(&wdt_lock);
+
+ expires = set_timeout();
+ if (wdt.id)
+ err = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wdt);
+ else
+ err = -ENXIO;
+ if (!err)
+ wdt_expires = expires;
+
+ spin_unlock(&wdt_lock);
+
+ return err;
+}
+
+static int xen_wdt_open(struct inode *inode, struct file *file)
+{
+ int err;
+
+ /* /dev/watchdog can only be opened once */
+ if (xchg(&is_active, true))
+ return -EBUSY;
+
+ err = xen_wdt_start();
+ if (err == -EBUSY)
+ err = xen_wdt_kick();
+ return err ?: nonseekable_open(inode, file);
+}
+
+static int xen_wdt_release(struct inode *inode, struct file *file)
+{
+ if (expect_release)
+ xen_wdt_stop();
+ else {
+ printk(KERN_CRIT PFX
+ "unexpected close, not stopping watchdog!\n");
+ xen_wdt_kick();
+ }
+ is_active = false;
+ expect_release = false;
+ return 0;
+}
+
+static ssize_t xen_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* in case it was set long ago */
+ expect_release = false;
+
+ /* scan to see whether or not we got the magic
+ character */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_release = true;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ xen_wdt_kick();
+ }
+ return len;
+}
+
+static long xen_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_timeout;
+ int __user *argp = (void __user *)arg;
+ static const struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = DRV_NAME,
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, argp);
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(new_options, argp))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD)
+ retval = xen_wdt_stop();
+ if (new_options & WDIOS_ENABLECARD) {
+ retval = xen_wdt_start();
+ if (retval == -EBUSY)
+ retval = xen_wdt_kick();
+ }
+ return retval;
+
+ case WDIOC_KEEPALIVE:
+ xen_wdt_kick();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, argp))
+ return -EFAULT;
+ if (!new_timeout)
+ return -EINVAL;
+ timeout = new_timeout;
+ xen_wdt_kick();
+ /* fall through */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, argp);
+
+ case WDIOC_GETTIMELEFT:
+ retval = wdt_expires - ktime_to_timespec(ktime_get()).tv_sec;
+ return put_user(retval, argp);
+ }
+
+ return -ENOTTY;
+}
+
+static const struct file_operations xen_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = xen_wdt_write,
+ .unlocked_ioctl = xen_wdt_ioctl,
+ .open = xen_wdt_open,
+ .release = xen_wdt_release,
+};
+
+static struct miscdevice xen_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &xen_wdt_fops,
+};
+
+static int __devinit xen_wdt_probe(struct platform_device *dev)
+{
+ struct sched_watchdog wd = { .id = ~0 };
+ int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd);
+
+ switch (ret) {
+ case -EINVAL:
+ if (!timeout) {
+ timeout = WATCHDOG_TIMEOUT;
+ printk(KERN_INFO PFX
+ "timeout value invalid, using %d\n", timeout);
+ }
+
+ ret = misc_register(&xen_wdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX
+ "cannot register miscdev on minor=%d (%d)\n",
+ WATCHDOG_MINOR, ret);
+ break;
+ }
+
+ printk(KERN_INFO PFX
+ "initialized (timeout=%ds, nowayout=%d)\n",
+ timeout, nowayout);
+ break;
+
+ case -ENOSYS:
+ printk(KERN_INFO PFX "not supported\n");
+ ret = -ENODEV;
+ break;
+
+ default:
+ printk(KERN_INFO PFX "bogus return value %d\n", ret);
+ break;
+ }
+
+ return ret;
+}
+
+static int __devexit xen_wdt_remove(struct platform_device *dev)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ xen_wdt_stop();
+
+ misc_deregister(&xen_wdt_miscdev);
+
+ return 0;
+}
+
+static void xen_wdt_shutdown(struct platform_device *dev)
+{
+ xen_wdt_stop();
+}
+
+static int xen_wdt_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return xen_wdt_stop();
+}
+
+static int xen_wdt_resume(struct platform_device *dev)
+{
+ return xen_wdt_start();
+}
+
+static struct platform_driver xen_wdt_driver = {
+ .probe = xen_wdt_probe,
+ .remove = __devexit_p(xen_wdt_remove),
+ .shutdown = xen_wdt_shutdown,
+ .suspend = xen_wdt_suspend,
+ .resume = xen_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init xen_wdt_init_module(void)
+{
+ int err;
+
+ if (!xen_domain())
+ return -ENODEV;
+
+ printk(KERN_INFO PFX "Xen WatchDog Timer Driver v%s\n", DRV_VERSION);
+
+ err = platform_driver_register(&xen_wdt_driver);
+ if (err)
+ return err;
+
+ platform_device = platform_device_register_simple(DRV_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(platform_device)) {
+ err = PTR_ERR(platform_device);
+ platform_driver_unregister(&xen_wdt_driver);
+ }
+
+ return err;
+}
+
+static void __exit xen_wdt_cleanup_module(void)
+{
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&xen_wdt_driver);
+ printk(KERN_INFO PFX "module unloaded\n");
+}
+
+module_init(xen_wdt_init_module);
+module_exit(xen_wdt_cleanup_module);
+
+MODULE_AUTHOR("Jan Beulich <jbeulich@novell.com>");
+MODULE_DESCRIPTION("Xen WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 07bec09d1dad..a59638b37c1a 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -76,10 +76,20 @@ config XEN_XENBUS_FRONTEND
config XEN_GNTDEV
tristate "userspace grant access device driver"
depends on XEN
+ default m
select MMU_NOTIFIER
help
Allows userspace processes to use grants.
+config XEN_GRANT_DEV_ALLOC
+ tristate "User-space grant reference allocator driver"
+ depends on XEN
+ default m
+ help
+ Allows userspace processes to create pages with access granted
+ to other domains. This can be used to implement frontend drivers
+ or as part of an inter-domain shared memory channel.
+
config XEN_PLATFORM_PCI
tristate "xen platform pci device driver"
depends on XEN_PVHVM && PCI
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 5088cc2e6fe2..f420f1ff7f13 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,4 +1,4 @@
-obj-y += grant-table.o features.o events.o manage.o
+obj-y += grant-table.o features.o events.o manage.o balloon.o
obj-y += xenbus/
nostackp := $(call cc-option, -fno-stack-protector)
@@ -7,9 +7,10 @@ CFLAGS_features.o := $(nostackp)
obj-$(CONFIG_BLOCK) += biomerge.o
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
-obj-$(CONFIG_XEN_BALLOON) += balloon.o
+obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o
obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
+obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
obj-$(CONFIG_XENFS) += xenfs/
obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
@@ -18,5 +19,6 @@ obj-$(CONFIG_XEN_DOM0) += pci.o
xen-evtchn-y := evtchn.o
xen-gntdev-y := gntdev.o
+xen-gntalloc-y := gntalloc.o
xen-platform-pci-y := platform-pci.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 718050ace08f..043af8ad6b60 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -1,6 +1,4 @@
/******************************************************************************
- * balloon.c
- *
* Xen balloon driver - enables returning/claiming memory to/from Xen.
*
* Copyright (c) 2003, B Dragovic
@@ -33,7 +31,6 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/mm.h>
@@ -42,13 +39,11 @@
#include <linux/highmem.h>
#include <linux/mutex.h>
#include <linux/list.h>
-#include <linux/sysdev.h>
#include <linux/gfp.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
-#include <asm/uaccess.h>
#include <asm/tlb.h>
#include <asm/e820.h>
@@ -58,35 +53,29 @@
#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/interface/memory.h>
-#include <xen/xenbus.h>
+#include <xen/balloon.h>
#include <xen/features.h>
#include <xen/page.h>
-#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
-
-#define BALLOON_CLASS_NAME "xen_memory"
+/*
+ * balloon_process() state:
+ *
+ * BP_DONE: done or nothing to do,
+ * BP_EAGAIN: error, go to sleep,
+ * BP_ECANCELED: error, balloon operation canceled.
+ */
-struct balloon_stats {
- /* We aim for 'current allocation' == 'target allocation'. */
- unsigned long current_pages;
- unsigned long target_pages;
- /*
- * Drivers may alter the memory reservation independently, but they
- * must inform the balloon driver so we avoid hitting the hard limit.
- */
- unsigned long driver_pages;
- /* Number of pages in high- and low-memory balloons. */
- unsigned long balloon_low;
- unsigned long balloon_high;
+enum bp_state {
+ BP_DONE,
+ BP_EAGAIN,
+ BP_ECANCELED
};
-static DEFINE_MUTEX(balloon_mutex);
-
-static struct sys_device balloon_sysdev;
-static int register_balloon(struct sys_device *sysdev);
+static DEFINE_MUTEX(balloon_mutex);
-static struct balloon_stats balloon_stats;
+struct balloon_stats balloon_stats;
+EXPORT_SYMBOL_GPL(balloon_stats);
/* We increase/decrease in batches which fit in a page */
static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
@@ -104,8 +93,7 @@ static LIST_HEAD(ballooned_pages);
/* Main work function, always executed in process context. */
static void balloon_process(struct work_struct *work);
-static DECLARE_WORK(balloon_worker, balloon_process);
-static struct timer_list balloon_timer;
+static DECLARE_DELAYED_WORK(balloon_worker, balloon_process);
/* When ballooning out (allocating memory to return to Xen) we don't really
want the kernel to try too hard since that can trigger the oom killer. */
@@ -140,14 +128,17 @@ static void balloon_append(struct page *page)
}
/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
-static struct page *balloon_retrieve(void)
+static struct page *balloon_retrieve(bool prefer_highmem)
{
struct page *page;
if (list_empty(&ballooned_pages))
return NULL;
- page = list_entry(ballooned_pages.next, struct page, lru);
+ if (prefer_highmem)
+ page = list_entry(ballooned_pages.prev, struct page, lru);
+ else
+ page = list_entry(ballooned_pages.next, struct page, lru);
list_del(&page->lru);
if (PageHighMem(page)) {
@@ -177,9 +168,29 @@ static struct page *balloon_next_page(struct page *page)
return list_entry(next, struct page, lru);
}
-static void balloon_alarm(unsigned long unused)
+static enum bp_state update_schedule(enum bp_state state)
{
- schedule_work(&balloon_worker);
+ if (state == BP_DONE) {
+ balloon_stats.schedule_delay = 1;
+ balloon_stats.retry_count = 1;
+ return BP_DONE;
+ }
+
+ ++balloon_stats.retry_count;
+
+ if (balloon_stats.max_retry_count != RETRY_UNLIMITED &&
+ balloon_stats.retry_count > balloon_stats.max_retry_count) {
+ balloon_stats.schedule_delay = 1;
+ balloon_stats.retry_count = 1;
+ return BP_ECANCELED;
+ }
+
+ balloon_stats.schedule_delay <<= 1;
+
+ if (balloon_stats.schedule_delay > balloon_stats.max_schedule_delay)
+ balloon_stats.schedule_delay = balloon_stats.max_schedule_delay;
+
+ return BP_EAGAIN;
}
static unsigned long current_target(void)
@@ -194,11 +205,11 @@ static unsigned long current_target(void)
return target;
}
-static int increase_reservation(unsigned long nr_pages)
+static enum bp_state increase_reservation(unsigned long nr_pages)
{
+ int rc;
unsigned long pfn, i;
struct page *page;
- long rc;
struct xen_memory_reservation reservation = {
.address_bits = 0,
.extent_order = 0,
@@ -210,7 +221,10 @@ static int increase_reservation(unsigned long nr_pages)
page = balloon_first_page();
for (i = 0; i < nr_pages; i++) {
- BUG_ON(page == NULL);
+ if (!page) {
+ nr_pages = i;
+ break;
+ }
frame_list[i] = page_to_pfn(page);
page = balloon_next_page(page);
}
@@ -218,11 +232,11 @@ static int increase_reservation(unsigned long nr_pages)
set_xen_guest_handle(reservation.extent_start, frame_list);
reservation.nr_extents = nr_pages;
rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
- if (rc < 0)
- goto out;
+ if (rc <= 0)
+ return BP_EAGAIN;
for (i = 0; i < rc; i++) {
- page = balloon_retrieve();
+ page = balloon_retrieve(false);
BUG_ON(page == NULL);
pfn = page_to_pfn(page);
@@ -249,15 +263,14 @@ static int increase_reservation(unsigned long nr_pages)
balloon_stats.current_pages += rc;
- out:
- return rc < 0 ? rc : rc != nr_pages;
+ return BP_DONE;
}
-static int decrease_reservation(unsigned long nr_pages)
+static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
{
+ enum bp_state state = BP_DONE;
unsigned long pfn, i;
struct page *page;
- int need_sleep = 0;
int ret;
struct xen_memory_reservation reservation = {
.address_bits = 0,
@@ -269,9 +282,9 @@ static int decrease_reservation(unsigned long nr_pages)
nr_pages = ARRAY_SIZE(frame_list);
for (i = 0; i < nr_pages; i++) {
- if ((page = alloc_page(GFP_BALLOON)) == NULL) {
+ if ((page = alloc_page(gfp)) == NULL) {
nr_pages = i;
- need_sleep = 1;
+ state = BP_EAGAIN;
break;
}
@@ -307,7 +320,7 @@ static int decrease_reservation(unsigned long nr_pages)
balloon_stats.current_pages -= nr_pages;
- return need_sleep;
+ return state;
}
/*
@@ -318,77 +331,101 @@ static int decrease_reservation(unsigned long nr_pages)
*/
static void balloon_process(struct work_struct *work)
{
- int need_sleep = 0;
+ enum bp_state state = BP_DONE;
long credit;
mutex_lock(&balloon_mutex);
do {
credit = current_target() - balloon_stats.current_pages;
+
if (credit > 0)
- need_sleep = (increase_reservation(credit) != 0);
+ state = increase_reservation(credit);
+
if (credit < 0)
- need_sleep = (decrease_reservation(-credit) != 0);
+ state = decrease_reservation(-credit, GFP_BALLOON);
+
+ state = update_schedule(state);
#ifndef CONFIG_PREEMPT
if (need_resched())
schedule();
#endif
- } while ((credit != 0) && !need_sleep);
+ } while (credit && state == BP_DONE);
/* Schedule more work if there is some still to be done. */
- if (current_target() != balloon_stats.current_pages)
- mod_timer(&balloon_timer, jiffies + HZ);
+ if (state == BP_EAGAIN)
+ schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);
mutex_unlock(&balloon_mutex);
}
/* Resets the Xen limit, sets new target, and kicks off processing. */
-static void balloon_set_new_target(unsigned long target)
+void balloon_set_new_target(unsigned long target)
{
/* No need for lock. Not read-modify-write updates. */
balloon_stats.target_pages = target;
- schedule_work(&balloon_worker);
+ schedule_delayed_work(&balloon_worker, 0);
}
+EXPORT_SYMBOL_GPL(balloon_set_new_target);
-static struct xenbus_watch target_watch =
-{
- .node = "memory/target"
-};
-
-/* React to a change in the target key */
-static void watch_target(struct xenbus_watch *watch,
- const char **vec, unsigned int len)
+/**
+ * alloc_xenballooned_pages - get pages that have been ballooned out
+ * @nr_pages: Number of pages to get
+ * @pages: pages returned
+ * @return 0 on success, error otherwise
+ */
+int alloc_xenballooned_pages(int nr_pages, struct page** pages)
{
- unsigned long long new_target;
- int err;
-
- err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
- if (err != 1) {
- /* This is ok (for domain0 at least) - so just return */
- return;
+ int pgno = 0;
+ struct page* page;
+ mutex_lock(&balloon_mutex);
+ while (pgno < nr_pages) {
+ page = balloon_retrieve(true);
+ if (page) {
+ pages[pgno++] = page;
+ } else {
+ enum bp_state st;
+ st = decrease_reservation(nr_pages - pgno, GFP_HIGHUSER);
+ if (st != BP_DONE)
+ goto out_undo;
+ }
}
-
- /* The given memory/target value is in KiB, so it needs converting to
- * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
- */
- balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
+ mutex_unlock(&balloon_mutex);
+ return 0;
+ out_undo:
+ while (pgno)
+ balloon_append(pages[--pgno]);
+ /* Free the memory back to the kernel soon */
+ schedule_delayed_work(&balloon_worker, 0);
+ mutex_unlock(&balloon_mutex);
+ return -ENOMEM;
}
+EXPORT_SYMBOL(alloc_xenballooned_pages);
-static int balloon_init_watcher(struct notifier_block *notifier,
- unsigned long event,
- void *data)
+/**
+ * free_xenballooned_pages - return pages retrieved with get_ballooned_pages
+ * @nr_pages: Number of pages
+ * @pages: pages to return
+ */
+void free_xenballooned_pages(int nr_pages, struct page** pages)
{
- int err;
+ int i;
- err = register_xenbus_watch(&target_watch);
- if (err)
- printk(KERN_ERR "Failed to set balloon watcher\n");
+ mutex_lock(&balloon_mutex);
- return NOTIFY_DONE;
-}
+ for (i = 0; i < nr_pages; i++) {
+ if (pages[i])
+ balloon_append(pages[i]);
+ }
+
+ /* The balloon may be too large now. Shrink it if needed. */
+ if (current_target() != balloon_stats.current_pages)
+ schedule_delayed_work(&balloon_worker, 0);
-static struct notifier_block xenstore_notifier;
+ mutex_unlock(&balloon_mutex);
+}
+EXPORT_SYMBOL(free_xenballooned_pages);
static int __init balloon_init(void)
{
@@ -398,7 +435,7 @@ static int __init balloon_init(void)
if (!xen_domain())
return -ENODEV;
- pr_info("xen_balloon: Initialising balloon driver.\n");
+ pr_info("xen/balloon: Initialising balloon driver.\n");
if (xen_pv_domain())
nr_pages = xen_start_info->nr_pages;
@@ -408,13 +445,11 @@ static int __init balloon_init(void)
balloon_stats.target_pages = balloon_stats.current_pages;
balloon_stats.balloon_low = 0;
balloon_stats.balloon_high = 0;
- balloon_stats.driver_pages = 0UL;
-
- init_timer(&balloon_timer);
- balloon_timer.data = 0;
- balloon_timer.function = balloon_alarm;
- register_balloon(&balloon_sysdev);
+ balloon_stats.schedule_delay = 1;
+ balloon_stats.max_schedule_delay = 32;
+ balloon_stats.retry_count = 1;
+ balloon_stats.max_retry_count = RETRY_UNLIMITED;
/*
* Initialise the balloon with excess memory space. We need
@@ -436,153 +471,9 @@ static int __init balloon_init(void)
__balloon_append(page);
}
- target_watch.callback = watch_target;
- xenstore_notifier.notifier_call = balloon_init_watcher;
-
- register_xenstore_notifier(&xenstore_notifier);
-
return 0;
}
subsys_initcall(balloon_init);
-static void balloon_exit(void)
-{
- /* XXX - release balloon here */
- return;
-}
-
-module_exit(balloon_exit);
-
-#define BALLOON_SHOW(name, format, args...) \
- static ssize_t show_##name(struct sys_device *dev, \
- struct sysdev_attribute *attr, \
- char *buf) \
- { \
- return sprintf(buf, format, ##args); \
- } \
- static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
-
-BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
-BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
-BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
-BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
-
-static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
-}
-
-static ssize_t store_target_kb(struct sys_device *dev,
- struct sysdev_attribute *attr,
- const char *buf,
- size_t count)
-{
- char *endchar;
- unsigned long long target_bytes;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- target_bytes = simple_strtoull(buf, &endchar, 0) * 1024;
-
- balloon_set_new_target(target_bytes >> PAGE_SHIFT);
-
- return count;
-}
-
-static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
- show_target_kb, store_target_kb);
-
-
-static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%llu\n",
- (unsigned long long)balloon_stats.target_pages
- << PAGE_SHIFT);
-}
-
-static ssize_t store_target(struct sys_device *dev,
- struct sysdev_attribute *attr,
- const char *buf,
- size_t count)
-{
- char *endchar;
- unsigned long long target_bytes;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- target_bytes = memparse(buf, &endchar);
-
- balloon_set_new_target(target_bytes >> PAGE_SHIFT);
-
- return count;
-}
-
-static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR,
- show_target, store_target);
-
-
-static struct sysdev_attribute *balloon_attrs[] = {
- &attr_target_kb,
- &attr_target,
-};
-
-static struct attribute *balloon_info_attrs[] = {
- &attr_current_kb.attr,
- &attr_low_kb.attr,
- &attr_high_kb.attr,
- &attr_driver_kb.attr,
- NULL
-};
-
-static struct attribute_group balloon_info_group = {
- .name = "info",
- .attrs = balloon_info_attrs,
-};
-
-static struct sysdev_class balloon_sysdev_class = {
- .name = BALLOON_CLASS_NAME,
-};
-
-static int register_balloon(struct sys_device *sysdev)
-{
- int i, error;
-
- error = sysdev_class_register(&balloon_sysdev_class);
- if (error)
- return error;
-
- sysdev->id = 0;
- sysdev->cls = &balloon_sysdev_class;
-
- error = sysdev_register(sysdev);
- if (error) {
- sysdev_class_unregister(&balloon_sysdev_class);
- return error;
- }
-
- for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
- error = sysdev_create_file(sysdev, balloon_attrs[i]);
- if (error)
- goto fail;
- }
-
- error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
- if (error)
- goto fail;
-
- return 0;
-
- fail:
- while (--i >= 0)
- sysdev_remove_file(sysdev, balloon_attrs[i]);
- sysdev_unregister(sysdev);
- sysdev_class_unregister(&balloon_sysdev_class);
- return error;
-}
-
MODULE_LICENSE("GPL");
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 65f5068afd84..02b5a9c05cfa 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -56,6 +56,8 @@
*/
static DEFINE_SPINLOCK(irq_mapping_update_lock);
+static LIST_HEAD(xen_irq_list_head);
+
/* IRQ <-> VIRQ mapping. */
static DEFINE_PER_CPU(int [NR_VIRQS], virq_to_irq) = {[0 ... NR_VIRQS-1] = -1};
@@ -85,7 +87,9 @@ enum xen_irq_type {
*/
struct irq_info
{
+ struct list_head list;
enum xen_irq_type type; /* type */
+ unsigned irq;
unsigned short evtchn; /* event channel */
unsigned short cpu; /* cpu bound */
@@ -103,23 +107,10 @@ struct irq_info
#define PIRQ_NEEDS_EOI (1 << 0)
#define PIRQ_SHAREABLE (1 << 1)
-static struct irq_info *irq_info;
-static int *pirq_to_irq;
-
static int *evtchn_to_irq;
-struct cpu_evtchn_s {
- unsigned long bits[NR_EVENT_CHANNELS/BITS_PER_LONG];
-};
-static __initdata struct cpu_evtchn_s init_evtchn_mask = {
- .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul,
-};
-static struct cpu_evtchn_s __refdata *cpu_evtchn_mask_p = &init_evtchn_mask;
-
-static inline unsigned long *cpu_evtchn_mask(int cpu)
-{
- return cpu_evtchn_mask_p[cpu].bits;
-}
+static DEFINE_PER_CPU(unsigned long [NR_EVENT_CHANNELS/BITS_PER_LONG],
+ cpu_evtchn_mask);
/* Xen will never allocate port zero for any purpose. */
#define VALID_EVTCHN(chn) ((chn) != 0)
@@ -128,46 +119,86 @@ static struct irq_chip xen_dynamic_chip;
static struct irq_chip xen_percpu_chip;
static struct irq_chip xen_pirq_chip;
-/* Constructor for packed IRQ information. */
-static struct irq_info mk_unbound_info(void)
+/* Get info for IRQ */
+static struct irq_info *info_for_irq(unsigned irq)
+{
+ return get_irq_data(irq);
+}
+
+/* Constructors for packed IRQ information. */
+static void xen_irq_info_common_init(struct irq_info *info,
+ unsigned irq,
+ enum xen_irq_type type,
+ unsigned short evtchn,
+ unsigned short cpu)
{
- return (struct irq_info) { .type = IRQT_UNBOUND };
+
+ BUG_ON(info->type != IRQT_UNBOUND && info->type != type);
+
+ info->type = type;
+ info->irq = irq;
+ info->evtchn = evtchn;
+ info->cpu = cpu;
+
+ evtchn_to_irq[evtchn] = irq;
}
-static struct irq_info mk_evtchn_info(unsigned short evtchn)
+static void xen_irq_info_evtchn_init(unsigned irq,
+ unsigned short evtchn)
{
- return (struct irq_info) { .type = IRQT_EVTCHN, .evtchn = evtchn,
- .cpu = 0 };
+ struct irq_info *info = info_for_irq(irq);
+
+ xen_irq_info_common_init(info, irq, IRQT_EVTCHN, evtchn, 0);
}
-static struct irq_info mk_ipi_info(unsigned short evtchn, enum ipi_vector ipi)
+static void xen_irq_info_ipi_init(unsigned cpu,
+ unsigned irq,
+ unsigned short evtchn,
+ enum ipi_vector ipi)
{
- return (struct irq_info) { .type = IRQT_IPI, .evtchn = evtchn,
- .cpu = 0, .u.ipi = ipi };
+ struct irq_info *info = info_for_irq(irq);
+
+ xen_irq_info_common_init(info, irq, IRQT_IPI, evtchn, 0);
+
+ info->u.ipi = ipi;
+
+ per_cpu(ipi_to_irq, cpu)[ipi] = irq;
}
-static struct irq_info mk_virq_info(unsigned short evtchn, unsigned short virq)
+static void xen_irq_info_virq_init(unsigned cpu,
+ unsigned irq,
+ unsigned short evtchn,
+ unsigned short virq)
{
- return (struct irq_info) { .type = IRQT_VIRQ, .evtchn = evtchn,
- .cpu = 0, .u.virq = virq };
+ struct irq_info *info = info_for_irq(irq);
+
+ xen_irq_info_common_init(info, irq, IRQT_VIRQ, evtchn, 0);
+
+ info->u.virq = virq;
+
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
}
-static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned short pirq,
- unsigned short gsi, unsigned short vector)
+static void xen_irq_info_pirq_init(unsigned irq,
+ unsigned short evtchn,
+ unsigned short pirq,
+ unsigned short gsi,
+ unsigned short vector,
+ unsigned char flags)
{
- return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn,
- .cpu = 0,
- .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } };
+ struct irq_info *info = info_for_irq(irq);
+
+ xen_irq_info_common_init(info, irq, IRQT_PIRQ, evtchn, 0);
+
+ info->u.pirq.pirq = pirq;
+ info->u.pirq.gsi = gsi;
+ info->u.pirq.vector = vector;
+ info->u.pirq.flags = flags;
}
/*
* Accessors for packed IRQ information.
*/
-static struct irq_info *info_for_irq(unsigned irq)
-{
- return &irq_info[irq];
-}
-
static unsigned int evtchn_from_irq(unsigned irq)
{
if (unlikely(WARN(irq < 0 || irq >= nr_irqs, "Invalid irq %d!\n", irq)))
@@ -212,26 +243,6 @@ static unsigned pirq_from_irq(unsigned irq)
return info->u.pirq.pirq;
}
-static unsigned gsi_from_irq(unsigned irq)
-{
- struct irq_info *info = info_for_irq(irq);
-
- BUG_ON(info == NULL);
- BUG_ON(info->type != IRQT_PIRQ);
-
- return info->u.pirq.gsi;
-}
-
-static unsigned vector_from_irq(unsigned irq)
-{
- struct irq_info *info = info_for_irq(irq);
-
- BUG_ON(info == NULL);
- BUG_ON(info->type != IRQT_PIRQ);
-
- return info->u.pirq.vector;
-}
-
static enum xen_irq_type type_from_irq(unsigned irq)
{
return info_for_irq(irq)->type;
@@ -267,7 +278,7 @@ static inline unsigned long active_evtchns(unsigned int cpu,
unsigned int idx)
{
return (sh->evtchn_pending[idx] &
- cpu_evtchn_mask(cpu)[idx] &
+ per_cpu(cpu_evtchn_mask, cpu)[idx] &
~sh->evtchn_mask[idx]);
}
@@ -280,28 +291,28 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
#endif
- clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
- set_bit(chn, cpu_evtchn_mask(cpu));
+ clear_bit(chn, per_cpu(cpu_evtchn_mask, cpu_from_irq(irq)));
+ set_bit(chn, per_cpu(cpu_evtchn_mask, cpu));
- irq_info[irq].cpu = cpu;
+ info_for_irq(irq)->cpu = cpu;
}
static void init_evtchn_cpu_bindings(void)
{
int i;
#ifdef CONFIG_SMP
- struct irq_desc *desc;
+ struct irq_info *info;
/* By default all event channels notify CPU#0. */
- for_each_irq_desc(i, desc) {
+ list_for_each_entry(info, &xen_irq_list_head, list) {
+ struct irq_desc *desc = irq_to_desc(info->irq);
cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
}
#endif
for_each_possible_cpu(i)
- memset(cpu_evtchn_mask(i),
- (i == 0) ? ~0 : 0, sizeof(struct cpu_evtchn_s));
-
+ memset(per_cpu(cpu_evtchn_mask, i),
+ (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i)));
}
static inline void clear_evtchn(int port)
@@ -376,7 +387,28 @@ static void unmask_evtchn(int port)
put_cpu();
}
-static int xen_allocate_irq_dynamic(void)
+static void xen_irq_init(unsigned irq)
+{
+ struct irq_info *info;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+#ifdef CONFIG_SMP
+ /* By default all event channels notify CPU#0. */
+ cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
+#endif
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL)
+ panic("Unable to allocate metadata for IRQ%d\n", irq);
+
+ info->type = IRQT_UNBOUND;
+
+ set_irq_data(irq, info);
+
+ list_add_tail(&info->list, &xen_irq_list_head);
+}
+
+static int __must_check xen_allocate_irq_dynamic(void)
{
int first = 0;
int irq;
@@ -393,22 +425,14 @@ static int xen_allocate_irq_dynamic(void)
first = get_nr_irqs_gsi();
#endif
-retry:
irq = irq_alloc_desc_from(first, -1);
- if (irq == -ENOMEM && first > NR_IRQS_LEGACY) {
- printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should increase nr_irqs\n");
- first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY);
- goto retry;
- }
-
- if (irq < 0)
- panic("No available IRQ to bind to: increase nr_irqs!\n");
+ xen_irq_init(irq);
return irq;
}
-static int xen_allocate_irq_gsi(unsigned gsi)
+static int __must_check xen_allocate_irq_gsi(unsigned gsi)
{
int irq;
@@ -423,17 +447,25 @@ static int xen_allocate_irq_gsi(unsigned gsi)
/* Legacy IRQ descriptors are already allocated by the arch. */
if (gsi < NR_IRQS_LEGACY)
- return gsi;
+ irq = gsi;
+ else
+ irq = irq_alloc_desc_at(gsi, -1);
- irq = irq_alloc_desc_at(gsi, -1);
- if (irq < 0)
- panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq);
+ xen_irq_init(irq);
return irq;
}
static void xen_free_irq(unsigned irq)
{
+ struct irq_info *info = get_irq_data(irq);
+
+ list_del(&info->list);
+
+ set_irq_data(irq, NULL);
+
+ kfree(info);
+
/* Legacy IRQ descriptors are managed by the arch. */
if (irq < NR_IRQS_LEGACY)
return;
@@ -563,51 +595,39 @@ static void ack_pirq(struct irq_data *data)
static int find_irq_by_gsi(unsigned gsi)
{
- int irq;
+ struct irq_info *info;
- for (irq = 0; irq < nr_irqs; irq++) {
- struct irq_info *info = info_for_irq(irq);
-
- if (info == NULL || info->type != IRQT_PIRQ)
+ list_for_each_entry(info, &xen_irq_list_head, list) {
+ if (info->type != IRQT_PIRQ)
continue;
- if (gsi_from_irq(irq) == gsi)
- return irq;
+ if (info->u.pirq.gsi == gsi)
+ return info->irq;
}
return -1;
}
-int xen_allocate_pirq(unsigned gsi, int shareable, char *name)
+int xen_allocate_pirq_gsi(unsigned gsi)
{
- return xen_map_pirq_gsi(gsi, gsi, shareable, name);
+ return gsi;
}
-/* xen_map_pirq_gsi might allocate irqs from the top down, as a
- * consequence don't assume that the irq number returned has a low value
- * or can be used as a pirq number unless you know otherwise.
- *
- * One notable exception is when xen_map_pirq_gsi is called passing an
- * hardware gsi as argument, in that case the irq number returned
- * matches the gsi number passed as second argument.
+/*
+ * Do not make any assumptions regarding the relationship between the
+ * IRQ number returned here and the Xen pirq argument.
*
* Note: We don't assign an event channel until the irq actually started
* up. Return an existing irq if we've already got one for the gsi.
*/
-int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
+int xen_bind_pirq_gsi_to_irq(unsigned gsi,
+ unsigned pirq, int shareable, char *name)
{
- int irq = 0;
+ int irq = -1;
struct physdev_irq irq_op;
spin_lock(&irq_mapping_update_lock);
- if ((pirq > nr_irqs) || (gsi > nr_irqs)) {
- printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n",
- pirq > nr_irqs ? "pirq" :"",
- gsi > nr_irqs ? "gsi" : "");
- goto out;
- }
-
irq = find_irq_by_gsi(gsi);
if (irq != -1) {
printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n",
@@ -616,6 +636,8 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
}
irq = xen_allocate_irq_gsi(gsi);
+ if (irq < 0)
+ goto out;
set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
handle_level_irq, name);
@@ -633,9 +655,8 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
goto out;
}
- irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector);
- irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0;
- pirq_to_irq[pirq] = irq;
+ xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector,
+ shareable ? PIRQ_SHAREABLE : 0);
out:
spin_unlock(&irq_mapping_update_lock);
@@ -672,8 +693,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
handle_level_irq, name);
- irq_info[irq] = mk_pirq_info(0, pirq, 0, vector);
- pirq_to_irq[pirq] = irq;
+ xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0);
ret = irq_set_msi_desc(irq, msidesc);
if (ret < 0)
goto error_irq;
@@ -709,9 +729,6 @@ int xen_destroy_irq(int irq)
goto out;
}
}
- pirq_to_irq[info->u.pirq.pirq] = -1;
-
- irq_info[irq] = mk_unbound_info();
xen_free_irq(irq);
@@ -720,19 +737,26 @@ out:
return rc;
}
-int xen_vector_from_irq(unsigned irq)
+int xen_irq_from_pirq(unsigned pirq)
{
- return vector_from_irq(irq);
-}
+ int irq;
-int xen_gsi_from_irq(unsigned irq)
-{
- return gsi_from_irq(irq);
-}
+ struct irq_info *info;
-int xen_irq_from_pirq(unsigned pirq)
-{
- return pirq_to_irq[pirq];
+ spin_lock(&irq_mapping_update_lock);
+
+ list_for_each_entry(info, &xen_irq_list_head, list) {
+ if (info == NULL || info->type != IRQT_PIRQ)
+ continue;
+ irq = info->irq;
+ if (info->u.pirq.pirq == pirq)
+ goto out;
+ }
+ irq = -1;
+out:
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
}
int bind_evtchn_to_irq(unsigned int evtchn)
@@ -745,14 +769,16 @@ int bind_evtchn_to_irq(unsigned int evtchn)
if (irq == -1) {
irq = xen_allocate_irq_dynamic();
+ if (irq == -1)
+ goto out;
set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
handle_fasteoi_irq, "event");
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_evtchn_info(evtchn);
+ xen_irq_info_evtchn_init(irq, evtchn);
}
+out:
spin_unlock(&irq_mapping_update_lock);
return irq;
@@ -782,9 +808,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
BUG();
evtchn = bind_ipi.port;
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_ipi_info(evtchn, ipi);
- per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+ xen_irq_info_ipi_init(cpu, irq, evtchn, ipi);
bind_evtchn_to_cpu(evtchn, cpu);
}
@@ -821,6 +845,8 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
if (irq == -1) {
irq = xen_allocate_irq_dynamic();
+ if (irq == -1)
+ goto out;
set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
handle_percpu_irq, "virq");
@@ -832,14 +858,12 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
BUG();
evtchn = bind_virq.port;
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_virq_info(evtchn, virq);
-
- per_cpu(virq_to_irq, cpu)[virq] = irq;
+ xen_irq_info_virq_init(cpu, irq, evtchn, virq);
bind_evtchn_to_cpu(evtchn, cpu);
}
+out:
spin_unlock(&irq_mapping_update_lock);
return irq;
@@ -876,11 +900,9 @@ static void unbind_from_irq(unsigned int irq)
evtchn_to_irq[evtchn] = -1;
}
- if (irq_info[irq].type != IRQT_UNBOUND) {
- irq_info[irq] = mk_unbound_info();
+ BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND);
- xen_free_irq(irq);
- }
+ xen_free_irq(irq);
spin_unlock(&irq_mapping_update_lock);
}
@@ -894,6 +916,8 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
int retval;
irq = bind_evtchn_to_irq(evtchn);
+ if (irq < 0)
+ return irq;
retval = request_irq(irq, handler, irqflags, devname, dev_id);
if (retval != 0) {
unbind_from_irq(irq);
@@ -935,6 +959,8 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
int retval;
irq = bind_virq_to_irq(virq, cpu);
+ if (irq < 0)
+ return irq;
retval = request_irq(irq, handler, irqflags, devname, dev_id);
if (retval != 0) {
unbind_from_irq(irq);
@@ -986,7 +1012,7 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
{
struct shared_info *sh = HYPERVISOR_shared_info;
int cpu = smp_processor_id();
- unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu);
+ unsigned long *cpu_evtchn = per_cpu(cpu_evtchn_mask, cpu);
int i;
unsigned long flags;
static DEFINE_SPINLOCK(debug_lock);
@@ -1064,6 +1090,13 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
}
static DEFINE_PER_CPU(unsigned, xed_nesting_count);
+static DEFINE_PER_CPU(unsigned int, current_word_idx);
+static DEFINE_PER_CPU(unsigned int, current_bit_idx);
+
+/*
+ * Mask out the i least significant bits of w
+ */
+#define MASK_LSBS(w, i) (w & ((~0UL) << i))
/*
* Search the CPUs pending events bitmasks. For each one found, map
@@ -1076,6 +1109,9 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count);
*/
static void __xen_evtchn_do_upcall(void)
{
+ int start_word_idx, start_bit_idx;
+ int word_idx, bit_idx;
+ int i;
int cpu = get_cpu();
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
@@ -1094,17 +1130,57 @@ static void __xen_evtchn_do_upcall(void)
wmb();
#endif
pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
- while (pending_words != 0) {
+
+ start_word_idx = __this_cpu_read(current_word_idx);
+ start_bit_idx = __this_cpu_read(current_bit_idx);
+
+ word_idx = start_word_idx;
+
+ for (i = 0; pending_words != 0; i++) {
unsigned long pending_bits;
- int word_idx = __ffs(pending_words);
- pending_words &= ~(1UL << word_idx);
+ unsigned long words;
- while ((pending_bits = active_evtchns(cpu, s, word_idx)) != 0) {
- int bit_idx = __ffs(pending_bits);
- int port = (word_idx * BITS_PER_LONG) + bit_idx;
- int irq = evtchn_to_irq[port];
+ words = MASK_LSBS(pending_words, word_idx);
+
+ /*
+ * If we masked out all events, wrap to beginning.
+ */
+ if (words == 0) {
+ word_idx = 0;
+ bit_idx = 0;
+ continue;
+ }
+ word_idx = __ffs(words);
+
+ pending_bits = active_evtchns(cpu, s, word_idx);
+ bit_idx = 0; /* usually scan entire word from start */
+ if (word_idx == start_word_idx) {
+ /* We scan the starting word in two parts */
+ if (i == 0)
+ /* 1st time: start in the middle */
+ bit_idx = start_bit_idx;
+ else
+ /* 2nd time: mask bits done already */
+ bit_idx &= (1UL << start_bit_idx) - 1;
+ }
+
+ do {
+ unsigned long bits;
+ int port, irq;
struct irq_desc *desc;
+ bits = MASK_LSBS(pending_bits, bit_idx);
+
+ /* If we masked out all events, move on. */
+ if (bits == 0)
+ break;
+
+ bit_idx = __ffs(bits);
+
+ /* Process port. */
+ port = (word_idx * BITS_PER_LONG) + bit_idx;
+ irq = evtchn_to_irq[port];
+
mask_evtchn(port);
clear_evtchn(port);
@@ -1113,7 +1189,21 @@ static void __xen_evtchn_do_upcall(void)
if (desc)
generic_handle_irq_desc(irq, desc);
}
- }
+
+ bit_idx = (bit_idx + 1) % BITS_PER_LONG;
+
+ /* Next caller starts at last processed + 1 */
+ __this_cpu_write(current_word_idx,
+ bit_idx ? word_idx :
+ (word_idx+1) % BITS_PER_LONG);
+ __this_cpu_write(current_bit_idx, bit_idx);
+ } while (bit_idx != 0);
+
+ /* Scan start_l1i twice; all others once. */
+ if ((word_idx != start_word_idx) || (i != 0))
+ pending_words &= ~(1UL << word_idx);
+
+ word_idx = (word_idx + 1) % BITS_PER_LONG;
}
BUG_ON(!irqs_disabled());
@@ -1163,8 +1253,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
so there should be a proper type */
BUG_ON(info->type == IRQT_UNBOUND);
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_evtchn_info(evtchn);
+ xen_irq_info_evtchn_init(irq, evtchn);
spin_unlock(&irq_mapping_update_lock);
@@ -1181,10 +1270,14 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
struct evtchn_bind_vcpu bind_vcpu;
int evtchn = evtchn_from_irq(irq);
- /* events delivered via platform PCI interrupts are always
- * routed to vcpu 0 */
- if (!VALID_EVTCHN(evtchn) ||
- (xen_hvm_domain() && !xen_have_vector_callback))
+ if (!VALID_EVTCHN(evtchn))
+ return -1;
+
+ /*
+ * Events delivered via platform PCI interrupts are always
+ * routed to vcpu 0 and hence cannot be rebound.
+ */
+ if (xen_hvm_domain() && !xen_have_vector_callback)
return -1;
/* Send future instances of this interrupt to other vcpu. */
@@ -1271,19 +1364,22 @@ static int retrigger_dynirq(struct irq_data *data)
return ret;
}
-static void restore_cpu_pirqs(void)
+static void restore_pirqs(void)
{
int pirq, rc, irq, gsi;
struct physdev_map_pirq map_irq;
+ struct irq_info *info;
- for (pirq = 0; pirq < nr_irqs; pirq++) {
- irq = pirq_to_irq[pirq];
- if (irq == -1)
+ list_for_each_entry(info, &xen_irq_list_head, list) {
+ if (info->type != IRQT_PIRQ)
continue;
+ pirq = info->u.pirq.pirq;
+ gsi = info->u.pirq.gsi;
+ irq = info->irq;
+
/* save/restore of PT devices doesn't work, so at this point the
* only devices present are GSI based emulated devices */
- gsi = gsi_from_irq(irq);
if (!gsi)
continue;
@@ -1296,8 +1392,7 @@ static void restore_cpu_pirqs(void)
if (rc) {
printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n",
gsi, irq, pirq, rc);
- irq_info[irq] = mk_unbound_info();
- pirq_to_irq[pirq] = -1;
+ xen_free_irq(irq);
continue;
}
@@ -1327,8 +1422,7 @@ static void restore_cpu_virqs(unsigned int cpu)
evtchn = bind_virq.port;
/* Record the new mapping. */
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_virq_info(evtchn, virq);
+ xen_irq_info_virq_init(cpu, irq, evtchn, virq);
bind_evtchn_to_cpu(evtchn, cpu);
}
}
@@ -1352,8 +1446,7 @@ static void restore_cpu_ipis(unsigned int cpu)
evtchn = bind_ipi.port;
/* Record the new mapping. */
- evtchn_to_irq[evtchn] = irq;
- irq_info[irq] = mk_ipi_info(evtchn, ipi);
+ xen_irq_info_ipi_init(cpu, irq, evtchn, ipi);
bind_evtchn_to_cpu(evtchn, cpu);
}
}
@@ -1413,7 +1506,8 @@ void xen_poll_irq(int irq)
void xen_irq_resume(void)
{
- unsigned int cpu, irq, evtchn;
+ unsigned int cpu, evtchn;
+ struct irq_info *info;
init_evtchn_cpu_bindings();
@@ -1422,8 +1516,8 @@ void xen_irq_resume(void)
mask_evtchn(evtchn);
/* No IRQ <-> event-channel mappings. */
- for (irq = 0; irq < nr_irqs; irq++)
- irq_info[irq].evtchn = 0; /* zap event-channel binding */
+ list_for_each_entry(info, &xen_irq_list_head, list)
+ info->evtchn = 0; /* zap event-channel binding */
for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
evtchn_to_irq[evtchn] = -1;
@@ -1433,7 +1527,7 @@ void xen_irq_resume(void)
restore_cpu_ipis(cpu);
}
- restore_cpu_pirqs();
+ restore_pirqs();
}
static struct irq_chip xen_dynamic_chip __read_mostly = {
@@ -1519,17 +1613,6 @@ void __init xen_init_IRQ(void)
{
int i;
- cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s),
- GFP_KERNEL);
- irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL);
-
- /* We are using nr_irqs as the maximum number of pirq available but
- * that number is actually chosen by Xen and we don't know exactly
- * what it is. Be careful choosing high pirq numbers. */
- pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL);
- for (i = 0; i < nr_irqs; i++)
- pirq_to_irq[i] = -1;
-
evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq),
GFP_KERNEL);
for (i = 0; i < NR_EVENT_CHANNELS; i++)
diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
new file mode 100644
index 000000000000..a7ffdfe19fc9
--- /dev/null
+++ b/drivers/xen/gntalloc.c
@@ -0,0 +1,545 @@
+/******************************************************************************
+ * gntalloc.c
+ *
+ * Device for creating grant references (in user-space) that may be shared
+ * with other domains.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This driver exists to allow userspace programs in Linux to allocate kernel
+ * memory that will later be shared with another domain. Without this device,
+ * Linux userspace programs cannot create grant references.
+ *
+ * How this stuff works:
+ * X -> granting a page to Y
+ * Y -> mapping the grant from X
+ *
+ * 1. X uses the gntalloc device to allocate a page of kernel memory, P.
+ * 2. X creates an entry in the grant table that says domid(Y) can access P.
+ * This is done without a hypercall unless the grant table needs expansion.
+ * 3. X gives the grant reference identifier, GREF, to Y.
+ * 4. Y maps the page, either directly into kernel memory for use in a backend
+ * driver, or via a the gntdev device to map into the address space of an
+ * application running in Y. This is the first point at which Xen does any
+ * tracking of the page.
+ * 5. A program in X mmap()s a segment of the gntalloc device that corresponds
+ * to the shared page, and can now communicate with Y over the shared page.
+ *
+ *
+ * NOTE TO USERSPACE LIBRARIES:
+ * The grant allocation and mmap()ing are, naturally, two separate operations.
+ * You set up the sharing by calling the create ioctl() and then the mmap().
+ * Teardown requires munmap() and either close() or ioctl().
+ *
+ * WARNING: Since Xen does not allow a guest to forcibly end the use of a grant
+ * reference, this device can be used to consume kernel memory by leaving grant
+ * references mapped by another domain when an application exits. Therefore,
+ * there is a global limit on the number of pages that can be allocated. When
+ * all references to the page are unmapped, it will be freed during the next
+ * grant operation.
+ */
+
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+
+#include <xen/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/gntalloc.h>
+#include <xen/events.h>
+
+static int limit = 1024;
+module_param(limit, int, 0644);
+MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
+ "the gntalloc device");
+
+static LIST_HEAD(gref_list);
+static DEFINE_SPINLOCK(gref_lock);
+static int gref_size;
+
+struct notify_info {
+ uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
+ uint16_t flags:2; /* Bits 12-13: Unmap notification flags */
+ int event; /* Port (event channel) to notify */
+};
+
+/* Metadata on a grant reference. */
+struct gntalloc_gref {
+ struct list_head next_gref; /* list entry gref_list */
+ struct list_head next_file; /* list entry file->list, if open */
+ struct page *page; /* The shared page */
+ uint64_t file_index; /* File offset for mmap() */
+ unsigned int users; /* Use count - when zero, waiting on Xen */
+ grant_ref_t gref_id; /* The grant reference number */
+ struct notify_info notify; /* Unmap notification */
+};
+
+struct gntalloc_file_private_data {
+ struct list_head list;
+ uint64_t index;
+};
+
+static void __del_gref(struct gntalloc_gref *gref);
+
+static void do_cleanup(void)
+{
+ struct gntalloc_gref *gref, *n;
+ list_for_each_entry_safe(gref, n, &gref_list, next_gref) {
+ if (!gref->users)
+ __del_gref(gref);
+ }
+}
+
+static int add_grefs(struct ioctl_gntalloc_alloc_gref *op,
+ uint32_t *gref_ids, struct gntalloc_file_private_data *priv)
+{
+ int i, rc, readonly;
+ LIST_HEAD(queue_gref);
+ LIST_HEAD(queue_file);
+ struct gntalloc_gref *gref;
+
+ readonly = !(op->flags & GNTALLOC_FLAG_WRITABLE);
+ rc = -ENOMEM;
+ for (i = 0; i < op->count; i++) {
+ gref = kzalloc(sizeof(*gref), GFP_KERNEL);
+ if (!gref)
+ goto undo;
+ list_add_tail(&gref->next_gref, &queue_gref);
+ list_add_tail(&gref->next_file, &queue_file);
+ gref->users = 1;
+ gref->file_index = op->index + i * PAGE_SIZE;
+ gref->page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ if (!gref->page)
+ goto undo;
+
+ /* Grant foreign access to the page. */
+ gref->gref_id = gnttab_grant_foreign_access(op->domid,
+ pfn_to_mfn(page_to_pfn(gref->page)), readonly);
+ if (gref->gref_id < 0) {
+ rc = gref->gref_id;
+ goto undo;
+ }
+ gref_ids[i] = gref->gref_id;
+ }
+
+ /* Add to gref lists. */
+ spin_lock(&gref_lock);
+ list_splice_tail(&queue_gref, &gref_list);
+ list_splice_tail(&queue_file, &priv->list);
+ spin_unlock(&gref_lock);
+
+ return 0;
+
+undo:
+ spin_lock(&gref_lock);
+ gref_size -= (op->count - i);
+
+ list_for_each_entry(gref, &queue_file, next_file) {
+ /* __del_gref does not remove from queue_file */
+ __del_gref(gref);
+ }
+
+ /* It's possible for the target domain to map the just-allocated grant
+ * references by blindly guessing their IDs; if this is done, then
+ * __del_gref will leave them in the queue_gref list. They need to be
+ * added to the global list so that we can free them when they are no
+ * longer referenced.
+ */
+ if (unlikely(!list_empty(&queue_gref)))
+ list_splice_tail(&queue_gref, &gref_list);
+ spin_unlock(&gref_lock);
+ return rc;
+}
+
+static void __del_gref(struct gntalloc_gref *gref)
+{
+ if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
+ uint8_t *tmp = kmap(gref->page);
+ tmp[gref->notify.pgoff] = 0;
+ kunmap(gref->page);
+ }
+ if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
+ notify_remote_via_evtchn(gref->notify.event);
+
+ gref->notify.flags = 0;
+
+ if (gref->gref_id > 0) {
+ if (gnttab_query_foreign_access(gref->gref_id))
+ return;
+
+ if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
+ return;
+ }
+
+ gref_size--;
+ list_del(&gref->next_gref);
+
+ if (gref->page)
+ __free_page(gref->page);
+
+ kfree(gref);
+}
+
+/* finds contiguous grant references in a file, returns the first */
+static struct gntalloc_gref *find_grefs(struct gntalloc_file_private_data *priv,
+ uint64_t index, uint32_t count)
+{
+ struct gntalloc_gref *rv = NULL, *gref;
+ list_for_each_entry(gref, &priv->list, next_file) {
+ if (gref->file_index == index && !rv)
+ rv = gref;
+ if (rv) {
+ if (gref->file_index != index)
+ return NULL;
+ index += PAGE_SIZE;
+ count--;
+ if (count == 0)
+ return rv;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * -------------------------------------
+ * File operations.
+ * -------------------------------------
+ */
+static int gntalloc_open(struct inode *inode, struct file *filp)
+{
+ struct gntalloc_file_private_data *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ goto out_nomem;
+ INIT_LIST_HEAD(&priv->list);
+
+ filp->private_data = priv;
+
+ pr_debug("%s: priv %p\n", __func__, priv);
+
+ return 0;
+
+out_nomem:
+ return -ENOMEM;
+}
+
+static int gntalloc_release(struct inode *inode, struct file *filp)
+{
+ struct gntalloc_file_private_data *priv = filp->private_data;
+ struct gntalloc_gref *gref;
+
+ pr_debug("%s: priv %p\n", __func__, priv);
+
+ spin_lock(&gref_lock);
+ while (!list_empty(&priv->list)) {
+ gref = list_entry(priv->list.next,
+ struct gntalloc_gref, next_file);
+ list_del(&gref->next_file);
+ gref->users--;
+ if (gref->users == 0)
+ __del_gref(gref);
+ }
+ kfree(priv);
+ spin_unlock(&gref_lock);
+
+ return 0;
+}
+
+static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
+ struct ioctl_gntalloc_alloc_gref __user *arg)
+{
+ int rc = 0;
+ struct ioctl_gntalloc_alloc_gref op;
+ uint32_t *gref_ids;
+
+ pr_debug("%s: priv %p\n", __func__, priv);
+
+ if (copy_from_user(&op, arg, sizeof(op))) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY);
+ if (!gref_ids) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock(&gref_lock);
+ /* Clean up pages that were at zero (local) users but were still mapped
+ * by remote domains. Since those pages count towards the limit that we
+ * are about to enforce, removing them here is a good idea.
+ */
+ do_cleanup();
+ if (gref_size + op.count > limit) {
+ spin_unlock(&gref_lock);
+ rc = -ENOSPC;
+ goto out_free;
+ }
+ gref_size += op.count;
+ op.index = priv->index;
+ priv->index += op.count * PAGE_SIZE;
+ spin_unlock(&gref_lock);
+
+ rc = add_grefs(&op, gref_ids, priv);
+ if (rc < 0)
+ goto out_free;
+
+ /* Once we finish add_grefs, it is unsafe to touch the new reference,
+ * since it is possible for a concurrent ioctl to remove it (by guessing
+ * its index). If the userspace application doesn't provide valid memory
+ * to write the IDs to, then it will need to close the file in order to
+ * release - which it will do by segfaulting when it tries to access the
+ * IDs to close them.
+ */
+ if (copy_to_user(arg, &op, sizeof(op))) {
+ rc = -EFAULT;
+ goto out_free;
+ }
+ if (copy_to_user(arg->gref_ids, gref_ids,
+ sizeof(gref_ids[0]) * op.count)) {
+ rc = -EFAULT;
+ goto out_free;
+ }
+
+out_free:
+ kfree(gref_ids);
+out:
+ return rc;
+}
+
+static long gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv,
+ void __user *arg)
+{
+ int i, rc = 0;
+ struct ioctl_gntalloc_dealloc_gref op;
+ struct gntalloc_gref *gref, *n;
+
+ pr_debug("%s: priv %p\n", __func__, priv);
+
+ if (copy_from_user(&op, arg, sizeof(op))) {
+ rc = -EFAULT;
+ goto dealloc_grant_out;
+ }
+
+ spin_lock(&gref_lock);
+ gref = find_grefs(priv, op.index, op.count);
+ if (gref) {
+ /* Remove from the file list only, and decrease reference count.
+ * The later call to do_cleanup() will remove from gref_list and
+ * free the memory if the pages aren't mapped anywhere.
+ */
+ for (i = 0; i < op.count; i++) {
+ n = list_entry(gref->next_file.next,
+ struct gntalloc_gref, next_file);
+ list_del(&gref->next_file);
+ gref->users--;
+ gref = n;
+ }
+ } else {
+ rc = -EINVAL;
+ }
+
+ do_cleanup();
+
+ spin_unlock(&gref_lock);
+dealloc_grant_out:
+ return rc;
+}
+
+static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
+ void __user *arg)
+{
+ struct ioctl_gntalloc_unmap_notify op;
+ struct gntalloc_gref *gref;
+ uint64_t index;
+ int pgoff;
+ int rc;
+
+ if (copy_from_user(&op, arg, sizeof(op)))
+ return -EFAULT;
+
+ index = op.index & ~(PAGE_SIZE - 1);
+ pgoff = op.index & (PAGE_SIZE - 1);
+
+ spin_lock(&gref_lock);
+
+ gref = find_grefs(priv, index, 1);
+ if (!gref) {
+ rc = -ENOENT;
+ goto unlock_out;
+ }
+
+ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) {
+ rc = -EINVAL;
+ goto unlock_out;
+ }
+
+ gref->notify.flags = op.action;
+ gref->notify.pgoff = pgoff;
+ gref->notify.event = op.event_channel_port;
+ rc = 0;
+ unlock_out:
+ spin_unlock(&gref_lock);
+ return rc;
+}
+
+static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct gntalloc_file_private_data *priv = filp->private_data;
+
+ switch (cmd) {
+ case IOCTL_GNTALLOC_ALLOC_GREF:
+ return gntalloc_ioctl_alloc(priv, (void __user *)arg);
+
+ case IOCTL_GNTALLOC_DEALLOC_GREF:
+ return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
+
+ case IOCTL_GNTALLOC_SET_UNMAP_NOTIFY:
+ return gntalloc_ioctl_unmap_notify(priv, (void __user *)arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static void gntalloc_vma_close(struct vm_area_struct *vma)
+{
+ struct gntalloc_gref *gref = vma->vm_private_data;
+ if (!gref)
+ return;
+
+ spin_lock(&gref_lock);
+ gref->users--;
+ if (gref->users == 0)
+ __del_gref(gref);
+ spin_unlock(&gref_lock);
+}
+
+static struct vm_operations_struct gntalloc_vmops = {
+ .close = gntalloc_vma_close,
+};
+
+static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct gntalloc_file_private_data *priv = filp->private_data;
+ struct gntalloc_gref *gref;
+ int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ int rv, i;
+
+ pr_debug("%s: priv %p, page %lu+%d\n", __func__,
+ priv, vma->vm_pgoff, count);
+
+ if (!(vma->vm_flags & VM_SHARED)) {
+ printk(KERN_ERR "%s: Mapping must be shared.\n", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock(&gref_lock);
+ gref = find_grefs(priv, vma->vm_pgoff << PAGE_SHIFT, count);
+ if (gref == NULL) {
+ rv = -ENOENT;
+ pr_debug("%s: Could not find grant reference",
+ __func__);
+ goto out_unlock;
+ }
+
+ vma->vm_private_data = gref;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_flags |= VM_DONTCOPY;
+ vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP;
+
+ vma->vm_ops = &gntalloc_vmops;
+
+ for (i = 0; i < count; i++) {
+ gref->users++;
+ rv = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
+ gref->page);
+ if (rv)
+ goto out_unlock;
+
+ gref = list_entry(gref->next_file.next,
+ struct gntalloc_gref, next_file);
+ }
+ rv = 0;
+
+out_unlock:
+ spin_unlock(&gref_lock);
+ return rv;
+}
+
+static const struct file_operations gntalloc_fops = {
+ .owner = THIS_MODULE,
+ .open = gntalloc_open,
+ .release = gntalloc_release,
+ .unlocked_ioctl = gntalloc_ioctl,
+ .mmap = gntalloc_mmap
+};
+
+/*
+ * -------------------------------------
+ * Module creation/destruction.
+ * -------------------------------------
+ */
+static struct miscdevice gntalloc_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "xen/gntalloc",
+ .fops = &gntalloc_fops,
+};
+
+static int __init gntalloc_init(void)
+{
+ int err;
+
+ if (!xen_domain())
+ return -ENODEV;
+
+ err = misc_register(&gntalloc_miscdev);
+ if (err != 0) {
+ printk(KERN_ERR "Could not register misc gntalloc device\n");
+ return err;
+ }
+
+ pr_debug("Created grant allocation device at %d,%d\n",
+ MISC_MAJOR, gntalloc_miscdev.minor);
+
+ return 0;
+}
+
+static void __exit gntalloc_exit(void)
+{
+ misc_deregister(&gntalloc_miscdev);
+}
+
+module_init(gntalloc_init);
+module_exit(gntalloc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Carter Weatherly <carter.weatherly@jhuapl.edu>, "
+ "Daniel De Graaf <dgdegra@tycho.nsa.gov>");
+MODULE_DESCRIPTION("User-space grant reference allocator driver");
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 1e31cdcdae1e..017ce600fbc6 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -32,10 +32,13 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/highmem.h>
#include <xen/xen.h>
#include <xen/grant_table.h>
+#include <xen/balloon.h>
#include <xen/gntdev.h>
+#include <xen/events.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/page.h>
@@ -45,35 +48,46 @@ MODULE_AUTHOR("Derek G. Murray <Derek.Murray@cl.cam.ac.uk>, "
"Gerd Hoffmann <kraxel@redhat.com>");
MODULE_DESCRIPTION("User-space granted page access driver");
-static int limit = 1024;
+static int limit = 1024*1024;
module_param(limit, int, 0644);
-MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped at "
- "once by a gntdev instance");
+MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
+ "the gntdev device");
+
+static atomic_t pages_mapped = ATOMIC_INIT(0);
+
+static int use_ptemod;
struct gntdev_priv {
struct list_head maps;
- uint32_t used;
- uint32_t limit;
/* lock protects maps from concurrent changes */
spinlock_t lock;
struct mm_struct *mm;
struct mmu_notifier mn;
};
+struct unmap_notify {
+ int flags;
+ /* Address relative to the start of the grant_map */
+ int addr;
+ int event;
+};
+
struct grant_map {
struct list_head next;
- struct gntdev_priv *priv;
struct vm_area_struct *vma;
int index;
int count;
int flags;
- int is_mapped;
+ atomic_t users;
+ struct unmap_notify notify;
struct ioctl_gntdev_grant_ref *grants;
struct gnttab_map_grant_ref *map_ops;
struct gnttab_unmap_grant_ref *unmap_ops;
struct page **pages;
};
+static int unmap_grant_pages(struct grant_map *map, int offset, int pages);
+
/* ------------------------------------------------------------------ */
static void gntdev_print_maps(struct gntdev_priv *priv,
@@ -82,9 +96,7 @@ static void gntdev_print_maps(struct gntdev_priv *priv,
#ifdef DEBUG
struct grant_map *map;
- pr_debug("maps list (priv %p, usage %d/%d)\n",
- priv, priv->used, priv->limit);
-
+ pr_debug("%s: maps list (priv %p)\n", __func__, priv);
list_for_each_entry(map, &priv->maps, next)
pr_debug(" index %2d, count %2d %s\n",
map->index, map->count,
@@ -111,27 +123,21 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
NULL == add->pages)
goto err;
+ if (alloc_xenballooned_pages(count, add->pages))
+ goto err;
+
for (i = 0; i < count; i++) {
- add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
- if (add->pages[i] == NULL)
- goto err;
+ add->map_ops[i].handle = -1;
+ add->unmap_ops[i].handle = -1;
}
add->index = 0;
add->count = count;
- add->priv = priv;
-
- if (add->count + priv->used > priv->limit)
- goto err;
+ atomic_set(&add->users, 1);
return add;
err:
- if (add->pages)
- for (i = 0; i < count; i++) {
- if (add->pages[i])
- __free_page(add->pages[i]);
- }
kfree(add->pages);
kfree(add->grants);
kfree(add->map_ops);
@@ -154,7 +160,6 @@ static void gntdev_add_map(struct gntdev_priv *priv, struct grant_map *add)
list_add_tail(&add->next, &priv->maps);
done:
- priv->used += add->count;
gntdev_print_maps(priv, "[new]", add->index);
}
@@ -166,57 +171,33 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
list_for_each_entry(map, &priv->maps, next) {
if (map->index != index)
continue;
- if (map->count != count)
+ if (count && map->count != count)
continue;
return map;
}
return NULL;
}
-static struct grant_map *gntdev_find_map_vaddr(struct gntdev_priv *priv,
- unsigned long vaddr)
+static void gntdev_put_map(struct grant_map *map)
{
- struct grant_map *map;
-
- list_for_each_entry(map, &priv->maps, next) {
- if (!map->vma)
- continue;
- if (vaddr < map->vma->vm_start)
- continue;
- if (vaddr >= map->vma->vm_end)
- continue;
- return map;
- }
- return NULL;
-}
-
-static int gntdev_del_map(struct grant_map *map)
-{
- int i;
+ if (!map)
+ return;
- if (map->vma)
- return -EBUSY;
- for (i = 0; i < map->count; i++)
- if (map->unmap_ops[i].handle)
- return -EBUSY;
+ if (!atomic_dec_and_test(&map->users))
+ return;
- map->priv->used -= map->count;
- list_del(&map->next);
- return 0;
-}
+ atomic_sub(map->count, &pages_mapped);
-static void gntdev_free_map(struct grant_map *map)
-{
- int i;
+ if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
+ notify_remote_via_evtchn(map->notify.event);
+ }
- if (!map)
- return;
+ if (map->pages) {
+ if (!use_ptemod)
+ unmap_grant_pages(map, 0, map->count);
- if (map->pages)
- for (i = 0; i < map->count; i++) {
- if (map->pages[i])
- __free_page(map->pages[i]);
- }
+ free_xenballooned_pages(map->count, map->pages);
+ }
kfree(map->pages);
kfree(map->grants);
kfree(map->map_ops);
@@ -231,18 +212,17 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
{
struct grant_map *map = data;
unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
+ int flags = map->flags | GNTMAP_application_map | GNTMAP_contains_pte;
u64 pte_maddr;
BUG_ON(pgnr >= map->count);
pte_maddr = arbitrary_virt_to_machine(pte).maddr;
- gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr,
- GNTMAP_contains_pte | map->flags,
+ gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, flags,
map->grants[pgnr].ref,
map->grants[pgnr].domid);
- gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr,
- GNTMAP_contains_pte | map->flags,
- 0 /* handle */);
+ gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, flags,
+ -1 /* handle */);
return 0;
}
@@ -250,6 +230,21 @@ static int map_grant_pages(struct grant_map *map)
{
int i, err = 0;
+ if (!use_ptemod) {
+ /* Note: it could already be mapped */
+ if (map->map_ops[0].handle != -1)
+ return 0;
+ for (i = 0; i < map->count; i++) {
+ unsigned long addr = (unsigned long)
+ pfn_to_kaddr(page_to_pfn(map->pages[i]));
+ gnttab_set_map_op(&map->map_ops[i], addr, map->flags,
+ map->grants[i].ref,
+ map->grants[i].domid);
+ gnttab_set_unmap_op(&map->unmap_ops[i], addr,
+ map->flags, -1 /* handle */);
+ }
+ }
+
pr_debug("map %d+%d\n", map->index, map->count);
err = gnttab_map_refs(map->map_ops, map->pages, map->count);
if (err)
@@ -258,28 +253,81 @@ static int map_grant_pages(struct grant_map *map)
for (i = 0; i < map->count; i++) {
if (map->map_ops[i].status)
err = -EINVAL;
- map->unmap_ops[i].handle = map->map_ops[i].handle;
+ else {
+ BUG_ON(map->map_ops[i].handle == -1);
+ map->unmap_ops[i].handle = map->map_ops[i].handle;
+ pr_debug("map handle=%d\n", map->map_ops[i].handle);
+ }
}
return err;
}
-static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
+static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
{
int i, err = 0;
- pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset, pages);
- err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
+ if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
+ int pgno = (map->notify.addr >> PAGE_SHIFT);
+ if (pgno >= offset && pgno < offset + pages && use_ptemod) {
+ void __user *tmp = (void __user *)
+ map->vma->vm_start + map->notify.addr;
+ err = copy_to_user(tmp, &err, 1);
+ if (err)
+ return err;
+ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
+ } else if (pgno >= offset && pgno < offset + pages) {
+ uint8_t *tmp = kmap(map->pages[pgno]);
+ tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
+ kunmap(map->pages[pgno]);
+ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
+ }
+ }
+
+ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages);
if (err)
return err;
for (i = 0; i < pages; i++) {
if (map->unmap_ops[offset+i].status)
err = -EINVAL;
- map->unmap_ops[offset+i].handle = 0;
+ pr_debug("unmap handle=%d st=%d\n",
+ map->unmap_ops[offset+i].handle,
+ map->unmap_ops[offset+i].status);
+ map->unmap_ops[offset+i].handle = -1;
}
return err;
}
+static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
+{
+ int range, err = 0;
+
+ pr_debug("unmap %d+%d [%d+%d]\n", map->index, map->count, offset, pages);
+
+ /* It is possible the requested range will have a "hole" where we
+ * already unmapped some of the grants. Only unmap valid ranges.
+ */
+ while (pages && !err) {
+ while (pages && map->unmap_ops[offset].handle == -1) {
+ offset++;
+ pages--;
+ }
+ range = 0;
+ while (range < pages) {
+ if (map->unmap_ops[offset+range].handle == -1) {
+ range--;
+ break;
+ }
+ range++;
+ }
+ err = __unmap_grant_pages(map, offset, range);
+ offset += range;
+ pages -= range;
+ }
+
+ return err;
+}
+
/* ------------------------------------------------------------------ */
static void gntdev_vma_close(struct vm_area_struct *vma)
@@ -287,22 +335,13 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
struct grant_map *map = vma->vm_private_data;
pr_debug("close %p\n", vma);
- map->is_mapped = 0;
map->vma = NULL;
vma->vm_private_data = NULL;
-}
-
-static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
- pr_debug("vaddr %p, pgoff %ld (shouldn't happen)\n",
- vmf->virtual_address, vmf->pgoff);
- vmf->flags = VM_FAULT_ERROR;
- return 0;
+ gntdev_put_map(map);
}
static struct vm_operations_struct gntdev_vmops = {
.close = gntdev_vma_close,
- .fault = gntdev_vma_fault,
};
/* ------------------------------------------------------------------ */
@@ -320,8 +359,6 @@ static void mn_invl_range_start(struct mmu_notifier *mn,
list_for_each_entry(map, &priv->maps, next) {
if (!map->vma)
continue;
- if (!map->is_mapped)
- continue;
if (map->vma->vm_start >= end)
continue;
if (map->vma->vm_end <= start)
@@ -386,16 +423,17 @@ static int gntdev_open(struct inode *inode, struct file *flip)
INIT_LIST_HEAD(&priv->maps);
spin_lock_init(&priv->lock);
- priv->limit = limit;
- priv->mm = get_task_mm(current);
- if (!priv->mm) {
- kfree(priv);
- return -ENOMEM;
+ if (use_ptemod) {
+ priv->mm = get_task_mm(current);
+ if (!priv->mm) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+ priv->mn.ops = &gntdev_mmu_ops;
+ ret = mmu_notifier_register(&priv->mn, priv->mm);
+ mmput(priv->mm);
}
- priv->mn.ops = &gntdev_mmu_ops;
- ret = mmu_notifier_register(&priv->mn, priv->mm);
- mmput(priv->mm);
if (ret) {
kfree(priv);
@@ -412,21 +450,19 @@ static int gntdev_release(struct inode *inode, struct file *flip)
{
struct gntdev_priv *priv = flip->private_data;
struct grant_map *map;
- int err;
pr_debug("priv %p\n", priv);
spin_lock(&priv->lock);
while (!list_empty(&priv->maps)) {
map = list_entry(priv->maps.next, struct grant_map, next);
- err = gntdev_del_map(map);
- if (WARN_ON(err))
- gntdev_free_map(map);
-
+ list_del(&map->next);
+ gntdev_put_map(map);
}
spin_unlock(&priv->lock);
- mmu_notifier_unregister(&priv->mn, priv->mm);
+ if (use_ptemod)
+ mmu_notifier_unregister(&priv->mn, priv->mm);
kfree(priv);
return 0;
}
@@ -443,16 +479,21 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
pr_debug("priv %p, add %d\n", priv, op.count);
if (unlikely(op.count <= 0))
return -EINVAL;
- if (unlikely(op.count > priv->limit))
- return -EINVAL;
err = -ENOMEM;
map = gntdev_alloc_map(priv, op.count);
if (!map)
return err;
+
+ if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
+ pr_debug("can't map: over limit\n");
+ gntdev_put_map(map);
+ return err;
+ }
+
if (copy_from_user(map->grants, &u->refs,
sizeof(map->grants[0]) * op.count) != 0) {
- gntdev_free_map(map);
+ gntdev_put_map(map);
return err;
}
@@ -461,13 +502,9 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
op.index = map->index << PAGE_SHIFT;
spin_unlock(&priv->lock);
- if (copy_to_user(u, &op, sizeof(op)) != 0) {
- spin_lock(&priv->lock);
- gntdev_del_map(map);
- spin_unlock(&priv->lock);
- gntdev_free_map(map);
- return err;
- }
+ if (copy_to_user(u, &op, sizeof(op)) != 0)
+ return -EFAULT;
+
return 0;
}
@@ -484,11 +521,12 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
spin_lock(&priv->lock);
map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
- if (map)
- err = gntdev_del_map(map);
+ if (map) {
+ list_del(&map->next);
+ gntdev_put_map(map);
+ err = 0;
+ }
spin_unlock(&priv->lock);
- if (!err)
- gntdev_free_map(map);
return err;
}
@@ -496,43 +534,66 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv,
struct ioctl_gntdev_get_offset_for_vaddr __user *u)
{
struct ioctl_gntdev_get_offset_for_vaddr op;
+ struct vm_area_struct *vma;
struct grant_map *map;
if (copy_from_user(&op, u, sizeof(op)) != 0)
return -EFAULT;
pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
- spin_lock(&priv->lock);
- map = gntdev_find_map_vaddr(priv, op.vaddr);
- if (map == NULL ||
- map->vma->vm_start != op.vaddr) {
- spin_unlock(&priv->lock);
+ vma = find_vma(current->mm, op.vaddr);
+ if (!vma || vma->vm_ops != &gntdev_vmops)
return -EINVAL;
- }
+
+ map = vma->vm_private_data;
+ if (!map)
+ return -EINVAL;
+
op.offset = map->index << PAGE_SHIFT;
op.count = map->count;
- spin_unlock(&priv->lock);
if (copy_to_user(u, &op, sizeof(op)) != 0)
return -EFAULT;
return 0;
}
-static long gntdev_ioctl_set_max_grants(struct gntdev_priv *priv,
- struct ioctl_gntdev_set_max_grants __user *u)
+static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
{
- struct ioctl_gntdev_set_max_grants op;
+ struct ioctl_gntdev_unmap_notify op;
+ struct grant_map *map;
+ int rc;
- if (copy_from_user(&op, u, sizeof(op)) != 0)
+ if (copy_from_user(&op, u, sizeof(op)))
return -EFAULT;
- pr_debug("priv %p, limit %d\n", priv, op.count);
- if (op.count > limit)
- return -E2BIG;
+
+ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
+ return -EINVAL;
spin_lock(&priv->lock);
- priv->limit = op.count;
+
+ list_for_each_entry(map, &priv->maps, next) {
+ uint64_t begin = map->index << PAGE_SHIFT;
+ uint64_t end = (map->index + map->count) << PAGE_SHIFT;
+ if (op.index >= begin && op.index < end)
+ goto found;
+ }
+ rc = -ENOENT;
+ goto unlock_out;
+
+ found:
+ if ((op.action & UNMAP_NOTIFY_CLEAR_BYTE) &&
+ (map->flags & GNTMAP_readonly)) {
+ rc = -EINVAL;
+ goto unlock_out;
+ }
+
+ map->notify.flags = op.action;
+ map->notify.addr = op.index - (map->index << PAGE_SHIFT);
+ map->notify.event = op.event_channel_port;
+ rc = 0;
+ unlock_out:
spin_unlock(&priv->lock);
- return 0;
+ return rc;
}
static long gntdev_ioctl(struct file *flip,
@@ -551,8 +612,8 @@ static long gntdev_ioctl(struct file *flip,
case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
- case IOCTL_GNTDEV_SET_MAX_GRANTS:
- return gntdev_ioctl_set_max_grants(priv, ptr);
+ case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
+ return gntdev_ioctl_notify(priv, ptr);
default:
pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
@@ -568,7 +629,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
int index = vma->vm_pgoff;
int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
struct grant_map *map;
- int err = -EINVAL;
+ int i, err = -EINVAL;
if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
return -EINVAL;
@@ -580,47 +641,70 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
map = gntdev_find_map_index(priv, index, count);
if (!map)
goto unlock_out;
- if (map->vma)
+ if (use_ptemod && map->vma)
goto unlock_out;
- if (priv->mm != vma->vm_mm) {
+ if (use_ptemod && priv->mm != vma->vm_mm) {
printk(KERN_WARNING "Huh? Other mm?\n");
goto unlock_out;
}
+ atomic_inc(&map->users);
+
vma->vm_ops = &gntdev_vmops;
vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
vma->vm_private_data = map;
- map->vma = vma;
- map->flags = GNTMAP_host_map | GNTMAP_application_map;
- if (!(vma->vm_flags & VM_WRITE))
- map->flags |= GNTMAP_readonly;
+ if (use_ptemod)
+ map->vma = vma;
+
+ if (map->flags) {
+ if ((vma->vm_flags & VM_WRITE) &&
+ (map->flags & GNTMAP_readonly))
+ return -EINVAL;
+ } else {
+ map->flags = GNTMAP_host_map;
+ if (!(vma->vm_flags & VM_WRITE))
+ map->flags |= GNTMAP_readonly;
+ }
spin_unlock(&priv->lock);
- err = apply_to_page_range(vma->vm_mm, vma->vm_start,
- vma->vm_end - vma->vm_start,
- find_grant_ptes, map);
- if (err) {
- printk(KERN_WARNING "find_grant_ptes() failure.\n");
- return err;
+ if (use_ptemod) {
+ err = apply_to_page_range(vma->vm_mm, vma->vm_start,
+ vma->vm_end - vma->vm_start,
+ find_grant_ptes, map);
+ if (err) {
+ printk(KERN_WARNING "find_grant_ptes() failure.\n");
+ goto out_put_map;
+ }
}
err = map_grant_pages(map);
- if (err) {
- printk(KERN_WARNING "map_grant_pages() failure.\n");
- return err;
- }
+ if (err)
+ goto out_put_map;
- map->is_mapped = 1;
+ if (!use_ptemod) {
+ for (i = 0; i < count; i++) {
+ err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
+ map->pages[i]);
+ if (err)
+ goto out_put_map;
+ }
+ }
return 0;
unlock_out:
spin_unlock(&priv->lock);
return err;
+
+out_put_map:
+ if (use_ptemod)
+ map->vma = NULL;
+ gntdev_put_map(map);
+ return err;
}
static const struct file_operations gntdev_fops = {
@@ -646,6 +730,8 @@ static int __init gntdev_init(void)
if (!xen_domain())
return -ENODEV;
+ use_ptemod = xen_pv_domain();
+
err = misc_register(&gntdev_miscdev);
if (err != 0) {
printk(KERN_ERR "Could not register gntdev device\n");
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 9ef54ebc1194..3745a318defc 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -458,7 +458,14 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
if (ret)
return ret;
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return ret;
+
for (i = 0; i < count; i++) {
+ /* Do not add to override if the map failed. */
+ if (map_ops[i].status)
+ continue;
+
/* m2p override only supported for GNTMAP_contains_pte mappings */
if (!(map_ops[i].flags & GNTMAP_contains_pte))
continue;
@@ -483,6 +490,9 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
if (ret)
return ret;
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return ret;
+
for (i = 0; i < count; i++) {
ret = m2p_remove_override(pages[i]);
if (ret)
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index ebb292859b59..95143dd6904d 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -61,7 +61,7 @@ static void xen_post_suspend(int cancelled)
xen_mm_unpin_all();
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_HIBERNATION
static int xen_suspend(void *data)
{
struct suspend_info *si = data;
@@ -69,7 +69,7 @@ static int xen_suspend(void *data)
BUG_ON(!irqs_disabled());
- err = sysdev_suspend(PMSG_SUSPEND);
+ err = sysdev_suspend(PMSG_FREEZE);
if (err) {
printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
err);
@@ -118,7 +118,7 @@ static void do_suspend(void)
}
#endif
- err = dpm_suspend_start(PMSG_SUSPEND);
+ err = dpm_suspend_start(PMSG_FREEZE);
if (err) {
printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
goto out_thaw;
@@ -127,7 +127,7 @@ static void do_suspend(void)
printk(KERN_DEBUG "suspending xenstore...\n");
xs_suspend();
- err = dpm_suspend_noirq(PMSG_SUSPEND);
+ err = dpm_suspend_noirq(PMSG_FREEZE);
if (err) {
printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
goto out_resume;
@@ -147,7 +147,7 @@ static void do_suspend(void)
err = stop_machine(xen_suspend, &si, cpumask_of(0));
- dpm_resume_noirq(PMSG_RESUME);
+ dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
if (err) {
printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
@@ -161,7 +161,7 @@ out_resume:
} else
xs_suspend_cancel();
- dpm_resume_end(PMSG_RESUME);
+ dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
/* Make sure timer events get retriggered on all CPUs */
clock_was_set();
@@ -173,7 +173,7 @@ out:
#endif
shutting_down = SHUTDOWN_INVALID;
}
-#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_HIBERNATION */
struct shutdown_handler {
const char *command;
@@ -202,7 +202,7 @@ static void shutdown_handler(struct xenbus_watch *watch,
{ "poweroff", do_poweroff },
{ "halt", do_poweroff },
{ "reboot", do_reboot },
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_HIBERNATION
{ "suspend", do_suspend },
#endif
{NULL, NULL},
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c
new file mode 100644
index 000000000000..a4ff225ee868
--- /dev/null
+++ b/drivers/xen/xen-balloon.c
@@ -0,0 +1,256 @@
+/******************************************************************************
+ * Xen balloon driver - enables returning/claiming memory to/from Xen.
+ *
+ * Copyright (c) 2003, B Dragovic
+ * Copyright (c) 2003-2004, M Williamson, K Fraser
+ * Copyright (c) 2005 Dan M. Smith, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/capability.h>
+
+#include <xen/xen.h>
+#include <xen/interface/xen.h>
+#include <xen/balloon.h>
+#include <xen/xenbus.h>
+#include <xen/features.h>
+#include <xen/page.h>
+
+#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
+
+#define BALLOON_CLASS_NAME "xen_memory"
+
+static struct sys_device balloon_sysdev;
+
+static int register_balloon(struct sys_device *sysdev);
+
+static struct xenbus_watch target_watch =
+{
+ .node = "memory/target"
+};
+
+/* React to a change in the target key */
+static void watch_target(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ unsigned long long new_target;
+ int err;
+
+ err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
+ if (err != 1) {
+ /* This is ok (for domain0 at least) - so just return */
+ return;
+ }
+
+ /* The given memory/target value is in KiB, so it needs converting to
+ * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
+ */
+ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
+}
+
+static int balloon_init_watcher(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ int err;
+
+ err = register_xenbus_watch(&target_watch);
+ if (err)
+ printk(KERN_ERR "Failed to set balloon watcher\n");
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block xenstore_notifier;
+
+static int __init balloon_init(void)
+{
+ if (!xen_domain())
+ return -ENODEV;
+
+ pr_info("xen-balloon: Initialising balloon driver.\n");
+
+ register_balloon(&balloon_sysdev);
+
+ target_watch.callback = watch_target;
+ xenstore_notifier.notifier_call = balloon_init_watcher;
+
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+subsys_initcall(balloon_init);
+
+static void balloon_exit(void)
+{
+ /* XXX - release balloon here */
+ return;
+}
+
+module_exit(balloon_exit);
+
+#define BALLOON_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct sys_device *dev, \
+ struct sysdev_attribute *attr, \
+ char *buf) \
+ { \
+ return sprintf(buf, format, ##args); \
+ } \
+ static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
+
+BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
+BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
+BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
+
+static SYSDEV_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay);
+static SYSDEV_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay);
+static SYSDEV_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count);
+static SYSDEV_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count);
+
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
+}
+
+static ssize_t store_target_kb(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ char *endchar;
+ unsigned long long target_bytes;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ target_bytes = simple_strtoull(buf, &endchar, 0) * 1024;
+
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
+ show_target_kb, store_target_kb);
+
+
+static ssize_t show_target(struct sys_device *dev, struct sysdev_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%llu\n",
+ (unsigned long long)balloon_stats.target_pages
+ << PAGE_SHIFT);
+}
+
+static ssize_t store_target(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ char *endchar;
+ unsigned long long target_bytes;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ target_bytes = memparse(buf, &endchar);
+
+ balloon_set_new_target(target_bytes >> PAGE_SHIFT);
+
+ return count;
+}
+
+static SYSDEV_ATTR(target, S_IRUGO | S_IWUSR,
+ show_target, store_target);
+
+
+static struct sysdev_attribute *balloon_attrs[] = {
+ &attr_target_kb,
+ &attr_target,
+ &attr_schedule_delay.attr,
+ &attr_max_schedule_delay.attr,
+ &attr_retry_count.attr,
+ &attr_max_retry_count.attr
+};
+
+static struct attribute *balloon_info_attrs[] = {
+ &attr_current_kb.attr,
+ &attr_low_kb.attr,
+ &attr_high_kb.attr,
+ NULL
+};
+
+static struct attribute_group balloon_info_group = {
+ .name = "info",
+ .attrs = balloon_info_attrs
+};
+
+static struct sysdev_class balloon_sysdev_class = {
+ .name = BALLOON_CLASS_NAME
+};
+
+static int register_balloon(struct sys_device *sysdev)
+{
+ int i, error;
+
+ error = sysdev_class_register(&balloon_sysdev_class);
+ if (error)
+ return error;
+
+ sysdev->id = 0;
+ sysdev->cls = &balloon_sysdev_class;
+
+ error = sysdev_register(sysdev);
+ if (error) {
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
+ error = sysdev_create_file(sysdev, balloon_attrs[i]);
+ if (error)
+ goto fail;
+ }
+
+ error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
+ if (error)
+ goto fail;
+
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ sysdev_remove_file(sysdev, balloon_attrs[i]);
+ sysdev_unregister(sysdev);
+ sysdev_class_unregister(&balloon_sysdev_class);
+ return error;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index baa65e7fbbc7..739769551e33 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -577,7 +577,7 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
}
EXPORT_SYMBOL_GPL(xenbus_dev_changed);
-int xenbus_dev_suspend(struct device *dev, pm_message_t state)
+int xenbus_dev_suspend(struct device *dev)
{
int err = 0;
struct xenbus_driver *drv;
@@ -590,7 +590,7 @@ int xenbus_dev_suspend(struct device *dev, pm_message_t state)
return 0;
drv = to_xenbus_driver(dev->driver);
if (drv->suspend)
- err = drv->suspend(xdev, state);
+ err = drv->suspend(xdev);
if (err)
printk(KERN_WARNING
"xenbus: suspend %s failed: %i\n", dev_name(dev), err);
@@ -642,6 +642,14 @@ int xenbus_dev_resume(struct device *dev)
}
EXPORT_SYMBOL_GPL(xenbus_dev_resume);
+int xenbus_dev_cancel(struct device *dev)
+{
+ /* Do nothing */
+ DPRINTK("cancel");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_cancel);
+
/* A flag to determine if xenstored is 'ready' (i.e. has started) */
int xenstored_ready = 0;
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
index 24665812316a..888b9900ca08 100644
--- a/drivers/xen/xenbus/xenbus_probe.h
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -64,8 +64,9 @@ extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
extern void xenbus_dev_shutdown(struct device *_dev);
-extern int xenbus_dev_suspend(struct device *dev, pm_message_t state);
+extern int xenbus_dev_suspend(struct device *dev);
extern int xenbus_dev_resume(struct device *dev);
+extern int xenbus_dev_cancel(struct device *dev);
extern void xenbus_otherend_changed(struct xenbus_watch *watch,
const char **vec, unsigned int len,
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 5bcc2d6cf129..b6a2690c9d49 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -85,6 +85,14 @@ static struct device_attribute xenbus_frontend_dev_attrs[] = {
__ATTR_NULL
};
+static const struct dev_pm_ops xenbus_pm_ops = {
+ .suspend = xenbus_dev_suspend,
+ .resume = xenbus_dev_resume,
+ .freeze = xenbus_dev_suspend,
+ .thaw = xenbus_dev_cancel,
+ .restore = xenbus_dev_resume,
+};
+
static struct xen_bus_type xenbus_frontend = {
.root = "device",
.levels = 2, /* device/type/<id> */
@@ -100,8 +108,7 @@ static struct xen_bus_type xenbus_frontend = {
.shutdown = xenbus_dev_shutdown,
.dev_attrs = xenbus_frontend_dev_attrs,
- .suspend = xenbus_dev_suspend,
- .resume = xenbus_dev_resume,
+ .pm = &xenbus_pm_ops,
},
};
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 014e7aba3b08..e6f84d26f4cf 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -36,7 +36,7 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
static struct vfsmount *autofs4_d_automount(struct path *);
-static int autofs4_d_manage(struct dentry *, bool, bool);
+static int autofs4_d_manage(struct dentry *, bool);
static void autofs4_dentry_release(struct dentry *);
const struct file_operations autofs4_root_operations = {
@@ -446,7 +446,7 @@ done:
return NULL;
}
-int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
+int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
@@ -454,7 +454,7 @@ int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
dentry, dentry->d_name.len, dentry->d_name.name);
/* The daemon never waits. */
- if (autofs4_oz_mode(sbi) || mounting_here) {
+ if (autofs4_oz_mode(sbi)) {
if (!d_mountpoint(dentry))
return -EISDIR;
return 0;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index e1aa8d607bc7..100b07f021b4 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2493,7 +2493,7 @@ int close_ctree(struct btrfs_root *root)
* ERROR state on disk.
*
* 2. when btrfs flips readonly just in btrfs_commit_super,
- * and in such case, btrfs cannnot write sb via btrfs_commit_super,
+ * and in such case, btrfs cannot write sb via btrfs_commit_super,
* and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag,
* btrfs will cleanup all FS resources first and write sb then.
*/
diff --git a/fs/dcache.c b/fs/dcache.c
index a39fe47c466f..ad25c4cec7d5 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1612,10 +1612,13 @@ struct dentry *d_obtain_alias(struct inode *inode)
__bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first);
spin_unlock(&tmp->d_lock);
spin_unlock(&inode->i_lock);
+ security_d_instantiate(tmp, inode);
return tmp;
out_iput:
+ if (res && !IS_ERR(res))
+ security_d_instantiate(res, inode);
iput(inode);
return res;
}
@@ -1808,7 +1811,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
* false-negative result. d_lookup() protects against concurrent
* renames using rename_lock seqlock.
*
- * See Documentation/vfs/dcache-locking.txt for more details.
+ * See Documentation/filesystems/path-lookup.txt for more details.
*/
hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) {
struct inode *i;
@@ -1928,7 +1931,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
* false-negative result. d_lookup() protects against concurrent
* renames using rename_lock seqlock.
*
- * See Documentation/vfs/dcache-locking.txt for more details.
+ * See Documentation/filesystems/path-lookup.txt for more details.
*/
rcu_read_lock();
diff --git a/fs/direct-io.c b/fs/direct-io.c
index b044705eedd4..dcb5577cde1d 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -645,11 +645,11 @@ static int dio_send_cur_page(struct dio *dio)
/*
* See whether this new request is contiguous with the old.
*
- * Btrfs cannot handl having logically non-contiguous requests
- * submitted. For exmple if you have
+ * Btrfs cannot handle having logically non-contiguous requests
+ * submitted. For example if you have
*
* Logical: [0-4095][HOLE][8192-12287]
- * Phyiscal: [0-4095] [4096-8181]
+ * Physical: [0-4095] [4096-8191]
*
* We cannot submit those pages together as one BIO. So if our
* current logical offset in the file does not equal what would
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index 4314f0d48d85..abc49f292454 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -18,6 +18,7 @@
#define WAKE_ASTS 0
+static uint64_t ast_seq_count;
static struct list_head ast_queue;
static spinlock_t ast_queue_lock;
static struct task_struct * astd_task;
@@ -25,40 +26,186 @@ static unsigned long astd_wakeflags;
static struct mutex astd_running;
+static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
+{
+ int i;
+
+ log_print("last_bast %x %llu flags %x mode %d sb %d %x",
+ lkb->lkb_id,
+ (unsigned long long)lkb->lkb_last_bast.seq,
+ lkb->lkb_last_bast.flags,
+ lkb->lkb_last_bast.mode,
+ lkb->lkb_last_bast.sb_status,
+ lkb->lkb_last_bast.sb_flags);
+
+ log_print("last_cast %x %llu flags %x mode %d sb %d %x",
+ lkb->lkb_id,
+ (unsigned long long)lkb->lkb_last_cast.seq,
+ lkb->lkb_last_cast.flags,
+ lkb->lkb_last_cast.mode,
+ lkb->lkb_last_cast.sb_status,
+ lkb->lkb_last_cast.sb_flags);
+
+ for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
+ log_print("cb %x %llu flags %x mode %d sb %d %x",
+ lkb->lkb_id,
+ (unsigned long long)lkb->lkb_callbacks[i].seq,
+ lkb->lkb_callbacks[i].flags,
+ lkb->lkb_callbacks[i].mode,
+ lkb->lkb_callbacks[i].sb_status,
+ lkb->lkb_callbacks[i].sb_flags);
+ }
+}
+
void dlm_del_ast(struct dlm_lkb *lkb)
{
spin_lock(&ast_queue_lock);
- if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
- list_del(&lkb->lkb_astqueue);
+ if (!list_empty(&lkb->lkb_astqueue))
+ list_del_init(&lkb->lkb_astqueue);
spin_unlock(&ast_queue_lock);
}
-void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode)
+int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags, uint64_t seq)
{
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+ uint64_t prev_seq;
+ int prev_mode;
+ int i;
+
+ for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
+ if (lkb->lkb_callbacks[i].seq)
+ continue;
+
+ /*
+ * Suppress some redundant basts here, do more on removal.
+ * Don't even add a bast if the callback just before it
+ * is a bast for the same mode or a more restrictive mode.
+ * (the addional > PR check is needed for PR/CW inversion)
+ */
+
+ if ((i > 0) && (flags & DLM_CB_BAST) &&
+ (lkb->lkb_callbacks[i-1].flags & DLM_CB_BAST)) {
+
+ prev_seq = lkb->lkb_callbacks[i-1].seq;
+ prev_mode = lkb->lkb_callbacks[i-1].mode;
+
+ if ((prev_mode == mode) ||
+ (prev_mode > mode && prev_mode > DLM_LOCK_PR)) {
+
+ log_debug(ls, "skip %x add bast %llu mode %d "
+ "for bast %llu mode %d",
+ lkb->lkb_id,
+ (unsigned long long)seq,
+ mode,
+ (unsigned long long)prev_seq,
+ prev_mode);
+ return 0;
+ }
+ }
+
+ lkb->lkb_callbacks[i].seq = seq;
+ lkb->lkb_callbacks[i].flags = flags;
+ lkb->lkb_callbacks[i].mode = mode;
+ lkb->lkb_callbacks[i].sb_status = status;
+ lkb->lkb_callbacks[i].sb_flags = (sbflags & 0x000000FF);
+ break;
+ }
+
+ if (i == DLM_CALLBACKS_SIZE) {
+ log_error(ls, "no callbacks %x %llu flags %x mode %d sb %d %x",
+ lkb->lkb_id, (unsigned long long)seq,
+ flags, mode, status, sbflags);
+ dlm_dump_lkb_callbacks(lkb);
+ return -1;
+ }
+
+ return 0;
+}
+
+int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_callback *cb, int *resid)
+{
+ int i;
+
+ *resid = 0;
+
+ if (!lkb->lkb_callbacks[0].seq)
+ return -ENOENT;
+
+ /* oldest undelivered cb is callbacks[0] */
+
+ memcpy(cb, &lkb->lkb_callbacks[0], sizeof(struct dlm_callback));
+ memset(&lkb->lkb_callbacks[0], 0, sizeof(struct dlm_callback));
+
+ /* shift others down */
+
+ for (i = 1; i < DLM_CALLBACKS_SIZE; i++) {
+ if (!lkb->lkb_callbacks[i].seq)
+ break;
+ memcpy(&lkb->lkb_callbacks[i-1], &lkb->lkb_callbacks[i],
+ sizeof(struct dlm_callback));
+ memset(&lkb->lkb_callbacks[i], 0, sizeof(struct dlm_callback));
+ (*resid)++;
+ }
+
+ /* if cb is a bast, it should be skipped if the blocking mode is
+ compatible with the last granted mode */
+
+ if ((cb->flags & DLM_CB_BAST) && lkb->lkb_last_cast.seq) {
+ if (dlm_modes_compat(cb->mode, lkb->lkb_last_cast.mode)) {
+ cb->flags |= DLM_CB_SKIP;
+
+ log_debug(ls, "skip %x bast %llu mode %d "
+ "for cast %llu mode %d",
+ lkb->lkb_id,
+ (unsigned long long)cb->seq,
+ cb->mode,
+ (unsigned long long)lkb->lkb_last_cast.seq,
+ lkb->lkb_last_cast.mode);
+ return 0;
+ }
+ }
+
+ if (cb->flags & DLM_CB_CAST) {
+ memcpy(&lkb->lkb_last_cast, cb, sizeof(struct dlm_callback));
+ lkb->lkb_last_cast_time = ktime_get();
+ }
+
+ if (cb->flags & DLM_CB_BAST) {
+ memcpy(&lkb->lkb_last_bast, cb, sizeof(struct dlm_callback));
+ lkb->lkb_last_bast_time = ktime_get();
+ }
+
+ return 0;
+}
+
+void dlm_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
+ uint32_t sbflags)
+{
+ uint64_t seq;
+ int rv;
+
+ spin_lock(&ast_queue_lock);
+
+ seq = ++ast_seq_count;
+
if (lkb->lkb_flags & DLM_IFL_USER) {
- dlm_user_add_ast(lkb, type, mode);
+ spin_unlock(&ast_queue_lock);
+ dlm_user_add_ast(lkb, flags, mode, status, sbflags, seq);
return;
}
- spin_lock(&ast_queue_lock);
- if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+ rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
+ if (rv < 0) {
+ spin_unlock(&ast_queue_lock);
+ return;
+ }
+
+ if (list_empty(&lkb->lkb_astqueue)) {
kref_get(&lkb->lkb_ref);
list_add_tail(&lkb->lkb_astqueue, &ast_queue);
- lkb->lkb_ast_first = type;
}
-
- /* sanity check, this should not happen */
-
- if ((type == AST_COMP) && (lkb->lkb_ast_type & AST_COMP))
- log_print("repeat cast %d castmode %d lock %x %s",
- mode, lkb->lkb_castmode,
- lkb->lkb_id, lkb->lkb_resource->res_name);
-
- lkb->lkb_ast_type |= type;
- if (type == AST_BAST)
- lkb->lkb_bastmode = mode;
- else
- lkb->lkb_castmode = mode;
spin_unlock(&ast_queue_lock);
set_bit(WAKE_ASTS, &astd_wakeflags);
@@ -72,7 +219,8 @@ static void process_asts(void)
struct dlm_lkb *lkb;
void (*castfn) (void *astparam);
void (*bastfn) (void *astparam, int mode);
- int type, first, bastmode, castmode, do_bast, do_cast, last_castmode;
+ struct dlm_callback callbacks[DLM_CALLBACKS_SIZE];
+ int i, rv, resid;
repeat:
spin_lock(&ast_queue_lock);
@@ -83,54 +231,45 @@ repeat:
if (dlm_locking_stopped(ls))
continue;
- list_del(&lkb->lkb_astqueue);
- type = lkb->lkb_ast_type;
- lkb->lkb_ast_type = 0;
- first = lkb->lkb_ast_first;
- lkb->lkb_ast_first = 0;
- bastmode = lkb->lkb_bastmode;
- castmode = lkb->lkb_castmode;
+ /* we remove from astqueue list and remove everything in
+ lkb_callbacks before releasing the spinlock so empty
+ lkb_astqueue is always consistent with empty lkb_callbacks */
+
+ list_del_init(&lkb->lkb_astqueue);
+
castfn = lkb->lkb_astfn;
bastfn = lkb->lkb_bastfn;
- spin_unlock(&ast_queue_lock);
- do_cast = (type & AST_COMP) && castfn;
- do_bast = (type & AST_BAST) && bastfn;
+ memset(&callbacks, 0, sizeof(callbacks));
- /* Skip a bast if its blocking mode is compatible with the
- granted mode of the preceding cast. */
+ for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
+ rv = dlm_rem_lkb_callback(ls, lkb, &callbacks[i], &resid);
+ if (rv < 0)
+ break;
+ }
+ spin_unlock(&ast_queue_lock);
- if (do_bast) {
- if (first == AST_COMP)
- last_castmode = castmode;
- else
- last_castmode = lkb->lkb_castmode_done;
- if (dlm_modes_compat(bastmode, last_castmode))
- do_bast = 0;
+ if (resid) {
+ /* shouldn't happen, for loop should have removed all */
+ log_error(ls, "callback resid %d lkb %x",
+ resid, lkb->lkb_id);
}
- if (first == AST_COMP) {
- if (do_cast)
- castfn(lkb->lkb_astparam);
- if (do_bast)
- bastfn(lkb->lkb_astparam, bastmode);
- } else if (first == AST_BAST) {
- if (do_bast)
- bastfn(lkb->lkb_astparam, bastmode);
- if (do_cast)
+ for (i = 0; i < DLM_CALLBACKS_SIZE; i++) {
+ if (!callbacks[i].seq)
+ break;
+ if (callbacks[i].flags & DLM_CB_SKIP) {
+ continue;
+ } else if (callbacks[i].flags & DLM_CB_BAST) {
+ bastfn(lkb->lkb_astparam, callbacks[i].mode);
+ } else if (callbacks[i].flags & DLM_CB_CAST) {
+ lkb->lkb_lksb->sb_status = callbacks[i].sb_status;
+ lkb->lkb_lksb->sb_flags = callbacks[i].sb_flags;
castfn(lkb->lkb_astparam);
- } else {
- log_error(ls, "bad ast_first %d ast_type %d",
- first, type);
+ }
}
- if (do_cast)
- lkb->lkb_castmode_done = castmode;
- if (do_bast)
- lkb->lkb_bastmode_done = bastmode;
-
- /* this removes the reference added by dlm_add_ast
- and may result in the lkb being freed */
+ /* removes ref for ast_queue, may cause lkb to be freed */
dlm_put_lkb(lkb);
cond_resched();
diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h
index bcb1aaba519d..8aa89c9b5611 100644
--- a/fs/dlm/ast.h
+++ b/fs/dlm/ast.h
@@ -13,8 +13,13 @@
#ifndef __ASTD_DOT_H__
#define __ASTD_DOT_H__
-void dlm_add_ast(struct dlm_lkb *lkb, int type, int mode);
void dlm_del_ast(struct dlm_lkb *lkb);
+int dlm_add_lkb_callback(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags, uint64_t seq);
+int dlm_rem_lkb_callback(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_callback *cb, int *resid);
+void dlm_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode, int status,
+ uint32_t sbflags);
void dlm_astd_wake(void);
int dlm_astd_start(void);
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index b54bca03d92f..0d329ff8ed4c 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -977,9 +977,9 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
/* Config file defaults */
#define DEFAULT_TCP_PORT 21064
#define DEFAULT_BUFFER_SIZE 4096
-#define DEFAULT_RSBTBL_SIZE 256
+#define DEFAULT_RSBTBL_SIZE 1024
#define DEFAULT_LKBTBL_SIZE 1024
-#define DEFAULT_DIRTBL_SIZE 512
+#define DEFAULT_DIRTBL_SIZE 1024
#define DEFAULT_RECOVER_TIMER 5
#define DEFAULT_TOSS_SECS 10
#define DEFAULT_SCAN_SECS 5
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
index 6b42ba807dfd..59779237e2b4 100644
--- a/fs/dlm/debug_fs.c
+++ b/fs/dlm/debug_fs.c
@@ -257,12 +257,12 @@ static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
lkb->lkb_status,
lkb->lkb_grmode,
lkb->lkb_rqmode,
- lkb->lkb_bastmode,
+ lkb->lkb_last_bast.mode,
rsb_lookup,
lkb->lkb_wait_type,
lkb->lkb_lvbseq,
(unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
- (unsigned long long)ktime_to_ns(lkb->lkb_time_bast));
+ (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));
return rv;
}
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index f632b58cd222..b94204913011 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -192,11 +192,6 @@ struct dlm_args {
* lkb is a process copy, the nodeid specifies the lock master.
*/
-/* lkb_ast_type */
-
-#define AST_COMP 1
-#define AST_BAST 2
-
/* lkb_status */
#define DLM_LKSTS_WAITING 1
@@ -217,6 +212,20 @@ struct dlm_args {
#define DLM_IFL_USER 0x00000001
#define DLM_IFL_ORPHAN 0x00000002
+#define DLM_CALLBACKS_SIZE 6
+
+#define DLM_CB_CAST 0x00000001
+#define DLM_CB_BAST 0x00000002
+#define DLM_CB_SKIP 0x00000004
+
+struct dlm_callback {
+ uint64_t seq;
+ uint32_t flags; /* DLM_CBF_ */
+ int sb_status; /* copy to lksb status */
+ uint8_t sb_flags; /* copy to lksb flags */
+ int8_t mode; /* rq mode of bast, gr mode of cast */
+};
+
struct dlm_lkb {
struct dlm_rsb *lkb_resource; /* the rsb */
struct kref lkb_ref;
@@ -236,13 +245,6 @@ struct dlm_lkb {
int8_t lkb_wait_type; /* type of reply waiting for */
int8_t lkb_wait_count;
- int8_t lkb_ast_type; /* type of ast queued for */
- int8_t lkb_ast_first; /* type of first ast queued */
-
- int8_t lkb_bastmode; /* req mode of queued bast */
- int8_t lkb_castmode; /* gr mode of queued cast */
- int8_t lkb_bastmode_done; /* last delivered bastmode */
- int8_t lkb_castmode_done; /* last delivered castmode */
struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
struct list_head lkb_statequeue; /* rsb g/c/w list */
@@ -251,10 +253,15 @@ struct dlm_lkb {
struct list_head lkb_astqueue; /* need ast to be sent */
struct list_head lkb_ownqueue; /* list of locks for a process */
struct list_head lkb_time_list;
- ktime_t lkb_time_bast; /* for debugging */
ktime_t lkb_timestamp;
unsigned long lkb_timeout_cs;
+ struct dlm_callback lkb_callbacks[DLM_CALLBACKS_SIZE];
+ struct dlm_callback lkb_last_cast;
+ struct dlm_callback lkb_last_bast;
+ ktime_t lkb_last_cast_time; /* for debugging */
+ ktime_t lkb_last_bast_time; /* for debugging */
+
char *lkb_lvbptr;
struct dlm_lksb *lkb_lksb; /* caller's status block */
void (*lkb_astfn) (void *astparam);
@@ -544,8 +551,6 @@ struct dlm_user_args {
(dlm_user_proc) on the struct file,
the process's locks point back to it*/
struct dlm_lksb lksb;
- int old_mode;
- int update_user_lvb;
struct dlm_lksb __user *user_lksb;
void __user *castparam;
void __user *castaddr;
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 64e5f3efdd81..04b8c449303f 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -160,10 +160,10 @@ static const int __quecvt_compat_matrix[8][8] = {
void dlm_print_lkb(struct dlm_lkb *lkb)
{
printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
- " status %d rqmode %d grmode %d wait_type %d ast_type %d\n",
+ " status %d rqmode %d grmode %d wait_type %d\n",
lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
- lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
+ lkb->lkb_grmode, lkb->lkb_wait_type);
}
static void dlm_print_rsb(struct dlm_rsb *r)
@@ -305,10 +305,7 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
rv = -EDEADLK;
}
- lkb->lkb_lksb->sb_status = rv;
- lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
-
- dlm_add_ast(lkb, AST_COMP, lkb->lkb_grmode);
+ dlm_add_ast(lkb, DLM_CB_CAST, lkb->lkb_grmode, rv, lkb->lkb_sbflags);
}
static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -319,13 +316,10 @@ static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
{
- lkb->lkb_time_bast = ktime_get();
-
if (is_master_copy(lkb)) {
- lkb->lkb_bastmode = rqmode; /* printed by debugfs */
send_bast(r, lkb, rqmode);
} else {
- dlm_add_ast(lkb, AST_BAST, rqmode);
+ dlm_add_ast(lkb, DLM_CB_BAST, rqmode, 0, 0);
}
}
@@ -600,6 +594,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
INIT_LIST_HEAD(&lkb->lkb_ownqueue);
INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
INIT_LIST_HEAD(&lkb->lkb_time_list);
+ INIT_LIST_HEAD(&lkb->lkb_astqueue);
get_random_bytes(&bucket, sizeof(bucket));
bucket &= (ls->ls_lkbtbl_size - 1);
@@ -2819,9 +2814,9 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
not from lkb fields */
if (lkb->lkb_bastfn)
- ms->m_asts |= AST_BAST;
+ ms->m_asts |= DLM_CB_BAST;
if (lkb->lkb_astfn)
- ms->m_asts |= AST_COMP;
+ ms->m_asts |= DLM_CB_CAST;
/* compare with switch in create_message; send_remove() doesn't
use send_args() */
@@ -3122,8 +3117,8 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
lkb->lkb_grmode = DLM_LOCK_IV;
lkb->lkb_rqmode = ms->m_rqmode;
- lkb->lkb_bastfn = (ms->m_asts & AST_BAST) ? &fake_bastfn : NULL;
- lkb->lkb_astfn = (ms->m_asts & AST_COMP) ? &fake_astfn : NULL;
+ lkb->lkb_bastfn = (ms->m_asts & DLM_CB_BAST) ? &fake_bastfn : NULL;
+ lkb->lkb_astfn = (ms->m_asts & DLM_CB_CAST) ? &fake_astfn : NULL;
if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
/* lkb was just created so there won't be an lvb yet */
@@ -4412,8 +4407,8 @@ static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
lkb->lkb_grmode = rl->rl_grmode;
/* don't set lkb_status because add_lkb wants to itself */
- lkb->lkb_bastfn = (rl->rl_asts & AST_BAST) ? &fake_bastfn : NULL;
- lkb->lkb_astfn = (rl->rl_asts & AST_COMP) ? &fake_astfn : NULL;
+ lkb->lkb_bastfn = (rl->rl_asts & DLM_CB_BAST) ? &fake_bastfn : NULL;
+ lkb->lkb_astfn = (rl->rl_asts & DLM_CB_CAST) ? &fake_astfn : NULL;
if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
int lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
@@ -4589,7 +4584,6 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
error = set_lock_args(mode, &ua->lksb, flags, namelen, timeout_cs,
fake_astfn, ua, fake_bastfn, &args);
lkb->lkb_flags |= DLM_IFL_USER;
- ua->old_mode = DLM_LOCK_IV;
if (error) {
__put_lkb(ls, lkb);
@@ -4658,7 +4652,6 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
ua->bastparam = ua_tmp->bastparam;
ua->bastaddr = ua_tmp->bastaddr;
ua->user_lksb = ua_tmp->user_lksb;
- ua->old_mode = lkb->lkb_grmode;
error = set_lock_args(mode, &ua->lksb, flags, 0, timeout_cs,
fake_astfn, ua, fake_bastfn, &args);
@@ -4917,8 +4910,9 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
}
list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
- lkb->lkb_ast_type = 0;
- list_del(&lkb->lkb_astqueue);
+ memset(&lkb->lkb_callbacks, 0,
+ sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE);
+ list_del_init(&lkb->lkb_astqueue);
dlm_put_lkb(lkb);
}
@@ -4958,7 +4952,9 @@ static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
spin_lock(&proc->asts_spin);
list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
- list_del(&lkb->lkb_astqueue);
+ memset(&lkb->lkb_callbacks, 0,
+ sizeof(struct dlm_callback) * DLM_CALLBACKS_SIZE);
+ list_del_init(&lkb->lkb_astqueue);
dlm_put_lkb(lkb);
}
spin_unlock(&proc->asts_spin);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 2d8c87b951c2..bffa1e73b9a9 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1468,13 +1468,15 @@ static void work_stop(void)
static int work_start(void)
{
- recv_workqueue = create_singlethread_workqueue("dlm_recv");
+ recv_workqueue = alloc_workqueue("dlm_recv",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!recv_workqueue) {
log_print("can't start dlm_recv");
return -ENOMEM;
}
- send_workqueue = create_singlethread_workqueue("dlm_send");
+ send_workqueue = alloc_workqueue("dlm_send",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!send_workqueue) {
log_print("can't start dlm_send");
destroy_workqueue(recv_workqueue);
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 3c83a49a48a3..f10a50f24e8f 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -321,9 +321,9 @@ static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
rl->rl_wait_type = cpu_to_le16(lkb->lkb_wait_type);
if (lkb->lkb_bastfn)
- rl->rl_asts |= AST_BAST;
+ rl->rl_asts |= DLM_CB_BAST;
if (lkb->lkb_astfn)
- rl->rl_asts |= AST_COMP;
+ rl->rl_asts |= DLM_CB_CAST;
rl->rl_namelen = cpu_to_le16(r->res_length);
memcpy(rl->rl_name, r->res_name, r->res_length);
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 66d6c16bf440..d5ab3fe7c198 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -24,6 +24,7 @@
#include "lock.h"
#include "lvb_table.h"
#include "user.h"
+#include "ast.h"
static const char name_prefix[] = "dlm";
static const struct file_operations device_fops;
@@ -152,19 +153,16 @@ static void compat_output(struct dlm_lock_result *res,
not related to the lifetime of the lkb struct which is managed
entirely by refcount. */
-static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)
+static int lkb_is_endoflife(int mode, int status)
{
- switch (sb_status) {
+ switch (status) {
case -DLM_EUNLOCK:
return 1;
case -DLM_ECANCEL:
case -ETIMEDOUT:
case -EDEADLK:
- if (lkb->lkb_grmode == DLM_LOCK_IV)
- return 1;
- break;
case -EAGAIN:
- if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV)
+ if (mode == DLM_LOCK_IV)
return 1;
break;
}
@@ -174,12 +172,13 @@ static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)
/* we could possibly check if the cancel of an orphan has resulted in the lkb
being removed and then remove that lkb from the orphans list and free it */
-void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode)
+void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags, uint64_t seq)
{
struct dlm_ls *ls;
struct dlm_user_args *ua;
struct dlm_user_proc *proc;
- int eol = 0, ast_type;
+ int rv;
if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
return;
@@ -200,49 +199,29 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode)
ua = lkb->lkb_ua;
proc = ua->proc;
- if (type == AST_BAST && ua->bastaddr == NULL)
+ if ((flags & DLM_CB_BAST) && ua->bastaddr == NULL)
goto out;
+ if ((flags & DLM_CB_CAST) && lkb_is_endoflife(mode, status))
+ lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
+
spin_lock(&proc->asts_spin);
- ast_type = lkb->lkb_ast_type;
- lkb->lkb_ast_type |= type;
- if (type == AST_BAST)
- lkb->lkb_bastmode = mode;
- else
- lkb->lkb_castmode = mode;
+ rv = dlm_add_lkb_callback(lkb, flags, mode, status, sbflags, seq);
+ if (rv < 0) {
+ spin_unlock(&proc->asts_spin);
+ goto out;
+ }
- if (!ast_type) {
+ if (list_empty(&lkb->lkb_astqueue)) {
kref_get(&lkb->lkb_ref);
list_add_tail(&lkb->lkb_astqueue, &proc->asts);
- lkb->lkb_ast_first = type;
wake_up_interruptible(&proc->wait);
}
- if (type == AST_COMP && (ast_type & AST_COMP))
- log_debug(ls, "ast overlap %x status %x %x",
- lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
-
- eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type);
- if (eol) {
- lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
- }
-
- /* We want to copy the lvb to userspace when the completion
- ast is read if the status is 0, the lock has an lvb and
- lvb_ops says we should. We could probably have set_lvb_lock()
- set update_user_lvb instead and not need old_mode */
-
- if ((lkb->lkb_ast_type & AST_COMP) &&
- (lkb->lkb_lksb->sb_status == 0) &&
- lkb->lkb_lksb->sb_lvbptr &&
- dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
- ua->update_user_lvb = 1;
- else
- ua->update_user_lvb = 0;
-
spin_unlock(&proc->asts_spin);
- if (eol) {
+ if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
+ /* N.B. spin_lock locks_spin, not asts_spin */
spin_lock(&proc->locks_spin);
if (!list_empty(&lkb->lkb_ownqueue)) {
list_del_init(&lkb->lkb_ownqueue);
@@ -705,8 +684,9 @@ static int device_close(struct inode *inode, struct file *file)
return 0;
}
-static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
- int mode, char __user *buf, size_t count)
+static int copy_result_to_user(struct dlm_user_args *ua, int compat,
+ uint32_t flags, int mode, int copy_lvb,
+ char __user *buf, size_t count)
{
#ifdef CONFIG_COMPAT
struct dlm_lock_result32 result32;
@@ -730,7 +710,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
notes that a new blocking AST address and parameter are set even if
the conversion fails, so maybe we should just do that. */
- if (type == AST_BAST) {
+ if (flags & DLM_CB_BAST) {
result.user_astaddr = ua->bastaddr;
result.user_astparam = ua->bastparam;
result.bast_mode = mode;
@@ -750,8 +730,7 @@ static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
/* copy lvb to userspace if there is one, it's been updated, and
the user buffer has space for it */
- if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
- count >= len + DLM_USER_LVB_LEN) {
+ if (copy_lvb && ua->lksb.sb_lvbptr && count >= len + DLM_USER_LVB_LEN) {
if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
DLM_USER_LVB_LEN)) {
error = -EFAULT;
@@ -801,13 +780,12 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
struct dlm_user_proc *proc = file->private_data;
struct dlm_lkb *lkb;
DECLARE_WAITQUEUE(wait, current);
- int error = 0, removed;
- int ret_type, ret_mode;
- int bastmode, castmode, do_bast, do_cast;
+ struct dlm_callback cb;
+ int rv, resid, copy_lvb = 0;
if (count == sizeof(struct dlm_device_version)) {
- error = copy_version_to_user(buf, count);
- return error;
+ rv = copy_version_to_user(buf, count);
+ return rv;
}
if (!proc) {
@@ -854,92 +832,57 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count,
}
}
- /* there may be both completion and blocking asts to return for
- the lkb, don't remove lkb from asts list unless no asts remain */
+ /* if we empty lkb_callbacks, we don't want to unlock the spinlock
+ without removing lkb_astqueue; so empty lkb_astqueue is always
+ consistent with empty lkb_callbacks */
lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
- removed = 0;
- ret_type = 0;
- ret_mode = 0;
- do_bast = lkb->lkb_ast_type & AST_BAST;
- do_cast = lkb->lkb_ast_type & AST_COMP;
- bastmode = lkb->lkb_bastmode;
- castmode = lkb->lkb_castmode;
-
- /* when both are queued figure out which to do first and
- switch first so the other goes in the next read */
-
- if (do_cast && do_bast) {
- if (lkb->lkb_ast_first == AST_COMP) {
- ret_type = AST_COMP;
- ret_mode = castmode;
- lkb->lkb_ast_type &= ~AST_COMP;
- lkb->lkb_ast_first = AST_BAST;
- } else {
- ret_type = AST_BAST;
- ret_mode = bastmode;
- lkb->lkb_ast_type &= ~AST_BAST;
- lkb->lkb_ast_first = AST_COMP;
- }
- } else {
- ret_type = lkb->lkb_ast_first;
- ret_mode = (ret_type == AST_COMP) ? castmode : bastmode;
- lkb->lkb_ast_type &= ~ret_type;
- lkb->lkb_ast_first = 0;
+ rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid);
+ if (rv < 0) {
+ /* this shouldn't happen; lkb should have been removed from
+ list when resid was zero */
+ log_print("dlm_rem_lkb_callback empty %x", lkb->lkb_id);
+ list_del_init(&lkb->lkb_astqueue);
+ spin_unlock(&proc->asts_spin);
+ /* removes ref for proc->asts, may cause lkb to be freed */
+ dlm_put_lkb(lkb);
+ goto try_another;
}
+ if (!resid)
+ list_del_init(&lkb->lkb_astqueue);
+ spin_unlock(&proc->asts_spin);
- /* if we're doing a bast but the bast is unnecessary, then
- switch to do nothing or do a cast if that was needed next */
-
- if ((ret_type == AST_BAST) &&
- dlm_modes_compat(bastmode, lkb->lkb_castmode_done)) {
- ret_type = 0;
- ret_mode = 0;
-
- if (do_cast) {
- ret_type = AST_COMP;
- ret_mode = castmode;
- lkb->lkb_ast_type &= ~AST_COMP;
- lkb->lkb_ast_first = 0;
- }
+ if (cb.flags & DLM_CB_SKIP) {
+ /* removes ref for proc->asts, may cause lkb to be freed */
+ if (!resid)
+ dlm_put_lkb(lkb);
+ goto try_another;
}
- if (lkb->lkb_ast_first != lkb->lkb_ast_type) {
- log_print("device_read %x ast_first %x ast_type %x",
- lkb->lkb_id, lkb->lkb_ast_first, lkb->lkb_ast_type);
- }
+ if (cb.flags & DLM_CB_CAST) {
+ int old_mode, new_mode;
- if (!lkb->lkb_ast_type) {
- list_del(&lkb->lkb_astqueue);
- removed = 1;
- }
- spin_unlock(&proc->asts_spin);
+ old_mode = lkb->lkb_last_cast.mode;
+ new_mode = cb.mode;
- if (ret_type) {
- error = copy_result_to_user(lkb->lkb_ua,
- test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
- ret_type, ret_mode, buf, count);
+ if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr &&
+ dlm_lvb_operations[old_mode + 1][new_mode + 1])
+ copy_lvb = 1;
- if (ret_type == AST_COMP)
- lkb->lkb_castmode_done = castmode;
- if (ret_type == AST_BAST)
- lkb->lkb_bastmode_done = bastmode;
+ lkb->lkb_lksb->sb_status = cb.sb_status;
+ lkb->lkb_lksb->sb_flags = cb.sb_flags;
}
- /* removes reference for the proc->asts lists added by
- dlm_user_add_ast() and may result in the lkb being freed */
+ rv = copy_result_to_user(lkb->lkb_ua,
+ test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
+ cb.flags, cb.mode, copy_lvb, buf, count);
- if (removed)
+ /* removes ref for proc->asts, may cause lkb to be freed */
+ if (!resid)
dlm_put_lkb(lkb);
- /* the bast that was queued was eliminated (see unnecessary above),
- leaving nothing to return */
-
- if (!ret_type)
- goto try_another;
-
- return error;
+ return rv;
}
static unsigned int device_poll(struct file *file, poll_table *wait)
diff --git a/fs/dlm/user.h b/fs/dlm/user.h
index f196091dd7ff..00499ab8835f 100644
--- a/fs/dlm/user.h
+++ b/fs/dlm/user.h
@@ -9,7 +9,8 @@
#ifndef __USER_DOT_H__
#define __USER_DOT_H__
-void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int mode);
+void dlm_user_add_ast(struct dlm_lkb *lkb, uint32_t flags, int mode,
+ int status, uint32_t sbflags, uint64_t seq);
int dlm_user_init(void);
void dlm_user_exit(void);
int dlm_device_deregister(struct dlm_ls *ls);
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 4a09af9e9a63..ff12f7ac73ef 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -62,7 +62,7 @@
* This mutex is acquired by ep_free() during the epoll file
* cleanup path and it is also acquired by eventpoll_release_file()
* if a file has been pushed inside an epoll set and it is then
- * close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL).
+ * close()d without a previous call to epoll_ctl(EPOLL_CTL_DEL).
* It is also acquired when inserting an epoll fd onto another epoll
* fd. We do this so that we walk the epoll tree and ensure that this
* insertion does not create a cycle of epoll file descriptors, which
@@ -152,11 +152,11 @@ struct epitem {
/*
* This structure is stored inside the "private_data" member of the file
- * structure and rapresent the main data sructure for the eventpoll
+ * structure and represents the main data structure for the eventpoll
* interface.
*/
struct eventpoll {
- /* Protect the this structure access */
+ /* Protect the access to this structure */
spinlock_t lock;
/*
@@ -793,7 +793,7 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
/*
* This is the callback that is passed to the wait queue wakeup
- * machanism. It is called by the stored file descriptors when they
+ * mechanism. It is called by the stored file descriptors when they
* have events to report.
*/
static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
@@ -824,9 +824,9 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
goto out_unlock;
/*
- * If we are trasfering events to userspace, we can hold no locks
+ * If we are transferring events to userspace, we can hold no locks
* (because we're accessing user memory, and because of linux f_op->poll()
- * semantics). All the events that happens during that period of time are
+ * semantics). All the events that happen during that period of time are
* chained in ep->ovflist and requeued later on.
*/
if (unlikely(ep->ovflist != EP_UNACTIVE_PTR)) {
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 045995c8ce5a..153242187fce 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1991,6 +1991,7 @@ ext3_grpblk_t ext3_trim_all_free(struct super_block *sb, unsigned int group,
spin_unlock(sb_bgl_lock(sbi, group));
percpu_counter_sub(&sbi->s_freeblocks_counter, next - start);
+ free_blocks -= next - start;
/* Do not issue a TRIM on extents smaller than minblocks */
if ((next - start) < minblocks)
goto free_extent;
@@ -2040,7 +2041,7 @@ free_extent:
cond_resched();
/* No more suitable extents */
- if ((free_blocks - count) < minblocks)
+ if (free_blocks < minblocks)
break;
}
@@ -2090,7 +2091,8 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
ext3_fsblk_t max_blks = le32_to_cpu(es->s_blocks_count);
int ret = 0;
- start = range->start >> sb->s_blocksize_bits;
+ start = (range->start >> sb->s_blocksize_bits) +
+ le32_to_cpu(es->s_first_data_block);
len = range->len >> sb->s_blocksize_bits;
minlen = range->minlen >> sb->s_blocksize_bits;
trimmed = 0;
@@ -2099,10 +2101,6 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
return -EINVAL;
if (start >= max_blks)
goto out;
- if (start < le32_to_cpu(es->s_first_data_block)) {
- len -= le32_to_cpu(es->s_first_data_block) - start;
- start = le32_to_cpu(es->s_first_data_block);
- }
if (start + len > max_blks)
len = max_blks - start;
@@ -2129,10 +2127,15 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
if (free_blocks < minlen)
continue;
- if (len >= EXT3_BLOCKS_PER_GROUP(sb))
- len -= (EXT3_BLOCKS_PER_GROUP(sb) - first_block);
- else
+ /*
+ * For all the groups except the last one, last block will
+ * always be EXT3_BLOCKS_PER_GROUP(sb), so we only need to
+ * change it for the last group in which case first_block +
+ * len < EXT3_BLOCKS_PER_GROUP(sb).
+ */
+ if (first_block + len < EXT3_BLOCKS_PER_GROUP(sb))
last_block = first_block + len;
+ len -= last_block - first_block;
ret = ext3_trim_all_free(sb, group, first_block,
last_block, minlen);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 0521a007ae6d..32f3b8695859 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1540,8 +1540,8 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
goto cleanup;
node2 = (struct dx_node *)(bh2->b_data);
entries2 = node2->entries;
+ memset(&node2->fake, 0, sizeof(struct fake_dirent));
node2->fake.rec_len = ext3_rec_len_to_disk(sb->s_blocksize);
- node2->fake.inode = 0;
BUFFER_TRACE(frame->bh, "get_write_access");
err = ext3_journal_get_write_access(handle, frame->bh);
if (err)
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 9cc19a1dea8e..071689f86e18 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1464,6 +1464,13 @@ static void ext3_orphan_cleanup (struct super_block * sb,
return;
}
+ /* Check if feature set allows readwrite operations */
+ if (EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP)) {
+ ext3_msg(sb, KERN_INFO, "Skipping orphan cleanup due to "
+ "unknown ROCOMPAT features");
+ return;
+ }
+
if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) {
if (es->s_last_orphan)
jbd_debug(1, "Errors on filesystem, "
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ccce8a7e94ed..7516fb9c0bd5 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -131,7 +131,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
* fragmenting the file system's free space. Maybe we
* should have some hueristics or some way to allow
* userspace to pass a hint to file system,
- * especiially if the latter case turns out to be
+ * especially if the latter case turns out to be
* common.
*/
ex = path[depth].p_ext;
@@ -2844,7 +2844,7 @@ fix_extent_len:
* ext4_get_blocks_dio_write() when DIO to write
* to an uninitialized extent.
*
- * Writing to an uninitized extent may result in splitting the uninitialized
+ * Writing to an uninitialized extent may result in splitting the uninitialized
* extent into multiple /initialized uninitialized extents (up to three)
* There are three possibilities:
* a> There is no split required: Entire extent should be uninitialized
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index 3e87cce5837d..7c39b885f969 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -458,7 +458,7 @@ static void cuse_fc_release(struct fuse_conn *fc)
* @file: file struct being opened
*
* Userland CUSE server can create a CUSE device by opening /dev/cuse
- * and replying to the initilaization request kernel sends. This
+ * and replying to the initialization request kernel sends. This
* function is responsible for handling CUSE device initialization.
* Because the fd opened by this function is used during
* initialization, this function only creates cuse_conn and sends
diff --git a/fs/internal.h b/fs/internal.h
index f3d15de44b15..17191546d527 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -12,6 +12,7 @@
#include <linux/lglock.h>
struct super_block;
+struct file_system_type;
struct linux_binprm;
struct path;
@@ -61,8 +62,6 @@ extern int check_unsafe_exec(struct linux_binprm *);
extern int copy_mount_options(const void __user *, unsigned long *);
extern int copy_mount_string(const void __user *, char **);
-extern void free_vfsmnt(struct vfsmount *);
-extern struct vfsmount *alloc_vfsmnt(const char *);
extern unsigned int mnt_get_count(struct vfsmount *mnt);
extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
@@ -99,6 +98,8 @@ extern struct file *get_empty_filp(void);
extern int do_remount_sb(struct super_block *, int, void *, int);
extern void __put_super(struct super_block *sb);
extern void put_super(struct super_block *sb);
+extern struct dentry *mount_fs(struct file_system_type *,
+ int, const char *, void *);
/*
* open.c
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index da1b5e4ffce1..eb11601f2e00 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -839,7 +839,7 @@ journal_t * journal_init_inode (struct inode *inode)
err = journal_bmap(journal, 0, &blocknr);
/* If that failed, give up */
if (err) {
- printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+ printk(KERN_ERR "%s: Cannot locate journal superblock\n",
__func__);
goto out_err;
}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 97e73469b2c4..90407b8fece7 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -991,7 +991,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
err = jbd2_journal_bmap(journal, 0, &blocknr);
/* If that failed, give up */
if (err) {
- printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+ printk(KERN_ERR "%s: Cannot locate journal superblock\n",
__func__);
goto out_err;
}
diff --git a/fs/namei.c b/fs/namei.c
index b912b7abe747..5a9a6c3094da 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -933,8 +933,7 @@ static int follow_managed(struct path *path, unsigned flags)
if (managed & DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
- ret = path->dentry->d_op->d_manage(path->dentry,
- false, false);
+ ret = path->dentry->d_op->d_manage(path->dentry, false);
if (ret < 0)
return ret == -EISDIR ? 0 : ret;
}
@@ -999,7 +998,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
struct vfsmount *mounted;
if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
!reverse_transit &&
- path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
+ path->dentry->d_op->d_manage(path->dentry, true) < 0)
return false;
mounted = __lookup_mnt(path->mnt, path->dentry, 1);
if (!mounted)
@@ -1065,7 +1064,7 @@ failed:
* Care must be taken as namespace_sem may be held (indicated by mounting_here
* being true).
*/
-int follow_down(struct path *path, bool mounting_here)
+int follow_down(struct path *path)
{
unsigned managed;
int ret;
@@ -1086,7 +1085,7 @@ int follow_down(struct path *path, bool mounting_here)
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
ret = path->dentry->d_op->d_manage(
- path->dentry, mounting_here, false);
+ path->dentry, false);
if (ret < 0)
return ret == -EISDIR ? 0 : ret;
}
diff --git a/fs/namespace.c b/fs/namespace.c
index d7513485c1f3..9263995bf6a1 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt)
#endif
}
-struct vfsmount *alloc_vfsmnt(const char *name)
+static struct vfsmount *alloc_vfsmnt(const char *name)
{
struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
if (mnt) {
@@ -466,15 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt)
br_write_unlock(vfsmount_lock);
}
-void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
-{
- mnt->mnt_sb = sb;
- mnt->mnt_root = dget(sb->s_root);
-}
-
-EXPORT_SYMBOL(simple_set_mnt);
-
-void free_vfsmnt(struct vfsmount *mnt)
+static void free_vfsmnt(struct vfsmount *mnt)
{
kfree(mnt->mnt_devname);
mnt_free_id(mnt);
@@ -678,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p)
return p;
}
+struct vfsmount *
+vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
+{
+ struct vfsmount *mnt;
+ struct dentry *root;
+
+ if (!type)
+ return ERR_PTR(-ENODEV);
+
+ mnt = alloc_vfsmnt(name);
+ if (!mnt)
+ return ERR_PTR(-ENOMEM);
+
+ if (flags & MS_KERNMOUNT)
+ mnt->mnt_flags = MNT_INTERNAL;
+
+ root = mount_fs(type, flags, name, data);
+ if (IS_ERR(root)) {
+ free_vfsmnt(mnt);
+ return ERR_CAST(root);
+ }
+
+ mnt->mnt_root = root;
+ mnt->mnt_sb = root->d_sb;
+ mnt->mnt_mountpoint = mnt->mnt_root;
+ mnt->mnt_parent = mnt;
+ return mnt;
+}
+EXPORT_SYMBOL_GPL(vfs_kern_mount);
+
static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
int flag)
{
@@ -1641,9 +1663,35 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
return err;
}
+static int lock_mount(struct path *path)
+{
+ struct vfsmount *mnt;
+retry:
+ mutex_lock(&path->dentry->d_inode->i_mutex);
+ if (unlikely(cant_mount(path->dentry))) {
+ mutex_unlock(&path->dentry->d_inode->i_mutex);
+ return -ENOENT;
+ }
+ down_write(&namespace_sem);
+ mnt = lookup_mnt(path);
+ if (likely(!mnt))
+ return 0;
+ up_write(&namespace_sem);
+ mutex_unlock(&path->dentry->d_inode->i_mutex);
+ path_put(path);
+ path->mnt = mnt;
+ path->dentry = dget(mnt->mnt_root);
+ goto retry;
+}
+
+static void unlock_mount(struct path *path)
+{
+ up_write(&namespace_sem);
+ mutex_unlock(&path->dentry->d_inode->i_mutex);
+}
+
static int graft_tree(struct vfsmount *mnt, struct path *path)
{
- int err;
if (mnt->mnt_sb->s_flags & MS_NOUSER)
return -EINVAL;
@@ -1651,16 +1699,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
S_ISDIR(mnt->mnt_root->d_inode->i_mode))
return -ENOTDIR;
- err = -ENOENT;
- mutex_lock(&path->dentry->d_inode->i_mutex);
- if (cant_mount(path->dentry))
- goto out_unlock;
+ if (d_unlinked(path->dentry))
+ return -ENOENT;
- if (!d_unlinked(path->dentry))
- err = attach_recursive_mnt(mnt, path, NULL);
-out_unlock:
- mutex_unlock(&path->dentry->d_inode->i_mutex);
- return err;
+ return attach_recursive_mnt(mnt, path, NULL);
}
/*
@@ -1723,6 +1765,7 @@ static int do_change_type(struct path *path, int flag)
static int do_loopback(struct path *path, char *old_name,
int recurse)
{
+ LIST_HEAD(umount_list);
struct path old_path;
struct vfsmount *mnt = NULL;
int err = mount_is_safe(path);
@@ -1734,13 +1777,16 @@ static int do_loopback(struct path *path, char *old_name,
if (err)
return err;
- down_write(&namespace_sem);
+ err = lock_mount(path);
+ if (err)
+ goto out;
+
err = -EINVAL;
if (IS_MNT_UNBINDABLE(old_path.mnt))
- goto out;
+ goto out2;
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
- goto out;
+ goto out2;
err = -ENOMEM;
if (recurse)
@@ -1749,20 +1795,18 @@ static int do_loopback(struct path *path, char *old_name,
mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
if (!mnt)
- goto out;
+ goto out2;
err = graft_tree(mnt, path);
if (err) {
- LIST_HEAD(umount_list);
-
br_write_lock(vfsmount_lock);
umount_tree(mnt, 0, &umount_list);
br_write_unlock(vfsmount_lock);
- release_mounts(&umount_list);
}
-
+out2:
+ unlock_mount(path);
+ release_mounts(&umount_list);
out:
- up_write(&namespace_sem);
path_put(&old_path);
return err;
}
@@ -1851,18 +1895,12 @@ static int do_move_mount(struct path *path, char *old_name)
if (err)
return err;
- down_write(&namespace_sem);
- err = follow_down(path, true);
+ err = lock_mount(path);
if (err < 0)
goto out;
err = -EINVAL;
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
- goto out;
-
- err = -ENOENT;
- mutex_lock(&path->dentry->d_inode->i_mutex);
- if (cant_mount(path->dentry))
goto out1;
if (d_unlinked(path->dentry))
@@ -1904,16 +1942,87 @@ static int do_move_mount(struct path *path, char *old_name)
* automatically */
list_del_init(&old_path.mnt->mnt_expire);
out1:
- mutex_unlock(&path->dentry->d_inode->i_mutex);
+ unlock_mount(path);
out:
- up_write(&namespace_sem);
if (!err)
path_put(&parent_path);
path_put(&old_path);
return err;
}
-static int do_add_mount(struct vfsmount *, struct path *, int);
+static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
+{
+ int err;
+ const char *subtype = strchr(fstype, '.');
+ if (subtype) {
+ subtype++;
+ err = -EINVAL;
+ if (!subtype[0])
+ goto err;
+ } else
+ subtype = "";
+
+ mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
+ err = -ENOMEM;
+ if (!mnt->mnt_sb->s_subtype)
+ goto err;
+ return mnt;
+
+ err:
+ mntput(mnt);
+ return ERR_PTR(err);
+}
+
+struct vfsmount *
+do_kern_mount(const char *fstype, int flags, const char *name, void *data)
+{
+ struct file_system_type *type = get_fs_type(fstype);
+ struct vfsmount *mnt;
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ mnt = vfs_kern_mount(type, flags, name, data);
+ if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
+ !mnt->mnt_sb->s_subtype)
+ mnt = fs_set_subtype(mnt, fstype);
+ put_filesystem(type);
+ return mnt;
+}
+EXPORT_SYMBOL_GPL(do_kern_mount);
+
+/*
+ * add a mount into a namespace's mount tree
+ */
+static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
+{
+ int err;
+
+ mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
+
+ err = lock_mount(path);
+ if (err)
+ return err;
+
+ err = -EINVAL;
+ if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
+ goto unlock;
+
+ /* Refuse the same filesystem on the same mount point */
+ err = -EBUSY;
+ if (path->mnt->mnt_sb == newmnt->mnt_sb &&
+ path->mnt->mnt_root == path->dentry)
+ goto unlock;
+
+ err = -EINVAL;
+ if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
+ goto unlock;
+
+ newmnt->mnt_flags = mnt_flags;
+ err = graft_tree(newmnt, path);
+
+unlock:
+ unlock_mount(path);
+ return err;
+}
/*
* create a new mount for userspace and request it to be added into the
@@ -1973,43 +2082,6 @@ fail:
return err;
}
-/*
- * add a mount into a namespace's mount tree
- */
-static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
-{
- int err;
-
- mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
-
- down_write(&namespace_sem);
- /* Something was mounted here while we slept */
- err = follow_down(path, true);
- if (err < 0)
- goto unlock;
-
- err = -EINVAL;
- if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
- goto unlock;
-
- /* Refuse the same filesystem on the same mount point */
- err = -EBUSY;
- if (path->mnt->mnt_sb == newmnt->mnt_sb &&
- path->mnt->mnt_root == path->dentry)
- goto unlock;
-
- err = -EINVAL;
- if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
- goto unlock;
-
- newmnt->mnt_flags = mnt_flags;
- err = graft_tree(newmnt, path);
-
-unlock:
- up_write(&namespace_sem);
- return err;
-}
-
/**
* mnt_set_expiry - Put a mount on an expiration list
* @mnt: The mount to list.
@@ -2510,65 +2582,60 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
error = user_path_dir(new_root, &new);
if (error)
goto out0;
- error = -EINVAL;
- if (!check_mnt(new.mnt))
- goto out1;
error = user_path_dir(put_old, &old);
if (error)
goto out1;
error = security_sb_pivotroot(&old, &new);
- if (error) {
- path_put(&old);
- goto out1;
- }
+ if (error)
+ goto out2;
get_fs_root(current->fs, &root);
- down_write(&namespace_sem);
- mutex_lock(&old.dentry->d_inode->i_mutex);
+ error = lock_mount(&old);
+ if (error)
+ goto out3;
+
error = -EINVAL;
if (IS_MNT_SHARED(old.mnt) ||
IS_MNT_SHARED(new.mnt->mnt_parent) ||
IS_MNT_SHARED(root.mnt->mnt_parent))
- goto out2;
- if (!check_mnt(root.mnt))
- goto out2;
+ goto out4;
+ if (!check_mnt(root.mnt) || !check_mnt(new.mnt))
+ goto out4;
error = -ENOENT;
- if (cant_mount(old.dentry))
- goto out2;
if (d_unlinked(new.dentry))
- goto out2;
+ goto out4;
if (d_unlinked(old.dentry))
- goto out2;
+ goto out4;
error = -EBUSY;
if (new.mnt == root.mnt ||
old.mnt == root.mnt)
- goto out2; /* loop, on the same file system */
+ goto out4; /* loop, on the same file system */
error = -EINVAL;
if (root.mnt->mnt_root != root.dentry)
- goto out2; /* not a mountpoint */
+ goto out4; /* not a mountpoint */
if (root.mnt->mnt_parent == root.mnt)
- goto out2; /* not attached */
+ goto out4; /* not attached */
if (new.mnt->mnt_root != new.dentry)
- goto out2; /* not a mountpoint */
+ goto out4; /* not a mountpoint */
if (new.mnt->mnt_parent == new.mnt)
- goto out2; /* not attached */
+ goto out4; /* not attached */
/* make sure we can reach put_old from new_root */
tmp = old.mnt;
- br_write_lock(vfsmount_lock);
if (tmp != new.mnt) {
for (;;) {
if (tmp->mnt_parent == tmp)
- goto out3; /* already mounted on put_old */
+ goto out4; /* already mounted on put_old */
if (tmp->mnt_parent == new.mnt)
break;
tmp = tmp->mnt_parent;
}
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
- goto out3;
+ goto out4;
} else if (!is_subdir(old.dentry, new.dentry))
- goto out3;
+ goto out4;
+ br_write_lock(vfsmount_lock);
detach_mnt(new.mnt, &parent_path);
detach_mnt(root.mnt, &root_parent);
/* mount old root on put_old */
@@ -2578,22 +2645,21 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
touch_mnt_namespace(current->nsproxy->mnt_ns);
br_write_unlock(vfsmount_lock);
chroot_fs_refs(&root, &new);
-
error = 0;
- path_put(&root_parent);
- path_put(&parent_path);
-out2:
- mutex_unlock(&old.dentry->d_inode->i_mutex);
- up_write(&namespace_sem);
+out4:
+ unlock_mount(&old);
+ if (!error) {
+ path_put(&root_parent);
+ path_put(&parent_path);
+ }
+out3:
path_put(&root);
+out2:
path_put(&old);
out1:
path_put(&new);
out0:
return error;
-out3:
- br_write_unlock(vfsmount_lock);
- goto out2;
}
static void __init init_mount_tree(void)
@@ -2668,3 +2734,9 @@ void put_mnt_ns(struct mnt_namespace *ns)
kfree(ns);
}
EXPORT_SYMBOL(put_mnt_ns);
+
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+{
+ return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
+}
+EXPORT_SYMBOL_GPL(kern_mount_data);
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 89587573fe50..2f41dccea18e 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -188,10 +188,10 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
rv = NFS4ERR_DELAY;
list_del_init(&lo->plh_bulk_recall);
spin_unlock(&ino->i_lock);
+ pnfs_free_lseg_list(&free_me_list);
put_layout_hdr(lo);
iput(ino);
}
- pnfs_free_lseg_list(&free_me_list);
return rv;
}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index bd3ca32879e7..139be9647d80 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -82,6 +82,11 @@ retry:
#endif /* CONFIG_NFS_V4 */
/*
+ * Turn off NFSv4 uid/gid mapping when using AUTH_SYS
+ */
+static int nfs4_disable_idmapping = 0;
+
+/*
* RPC cruft for NFS
*/
static struct rpc_version *nfs_version[5] = {
@@ -481,7 +486,12 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
* Look up a client by IP address and protocol version
* - creates a new record if one doesn't yet exist
*/
-static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
+static struct nfs_client *
+nfs_get_client(const struct nfs_client_initdata *cl_init,
+ const struct rpc_timeout *timeparms,
+ const char *ip_addr,
+ rpc_authflavor_t authflavour,
+ int noresvport)
{
struct nfs_client *clp, *new = NULL;
int error;
@@ -512,6 +522,13 @@ install_client:
clp = new;
list_add(&clp->cl_share_link, &nfs_client_list);
spin_unlock(&nfs_client_lock);
+
+ error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
+ authflavour, noresvport);
+ if (error < 0) {
+ nfs_put_client(clp);
+ return ERR_PTR(error);
+ }
dprintk("--> nfs_get_client() = %p [new]\n", clp);
return clp;
@@ -767,9 +784,9 @@ static int nfs_init_server_rpcclient(struct nfs_server *server,
/*
* Initialise an NFS2 or NFS3 client
*/
-static int nfs_init_client(struct nfs_client *clp,
- const struct rpc_timeout *timeparms,
- const struct nfs_parsed_mount_data *data)
+int nfs_init_client(struct nfs_client *clp, const struct rpc_timeout *timeparms,
+ const char *ip_addr, rpc_authflavor_t authflavour,
+ int noresvport)
{
int error;
@@ -784,7 +801,7 @@ static int nfs_init_client(struct nfs_client *clp,
* - RFC 2623, sec 2.3.2
*/
error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX,
- 0, data->flags & NFS_MOUNT_NORESVPORT);
+ 0, noresvport);
if (error < 0)
goto error;
nfs_mark_client_ready(clp, NFS_CS_READY);
@@ -820,19 +837,17 @@ static int nfs_init_server(struct nfs_server *server,
cl_init.rpc_ops = &nfs_v3_clientops;
#endif
+ nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
+ data->timeo, data->retrans);
+
/* Allocate or find a client reference we can use */
- clp = nfs_get_client(&cl_init);
+ clp = nfs_get_client(&cl_init, &timeparms, NULL, RPC_AUTH_UNIX,
+ data->flags & NFS_MOUNT_NORESVPORT);
if (IS_ERR(clp)) {
dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
return PTR_ERR(clp);
}
- nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
- data->timeo, data->retrans);
- error = nfs_init_client(clp, &timeparms, data);
- if (error < 0)
- goto error;
-
server->nfs_client = clp;
/* Initialise the client representation from the mount data */
@@ -1009,14 +1024,19 @@ static void nfs_server_insert_lists(struct nfs_server *server)
spin_lock(&nfs_client_lock);
list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
list_add_tail(&server->master_link, &nfs_volume_list);
+ clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
spin_unlock(&nfs_client_lock);
}
static void nfs_server_remove_lists(struct nfs_server *server)
{
+ struct nfs_client *clp = server->nfs_client;
+
spin_lock(&nfs_client_lock);
list_del_rcu(&server->client_link);
+ if (clp && list_empty(&clp->cl_superblocks))
+ set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
list_del(&server->master_link);
spin_unlock(&nfs_client_lock);
@@ -1307,11 +1327,11 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
/*
* Initialise an NFS4 client record
*/
-static int nfs4_init_client(struct nfs_client *clp,
- const struct rpc_timeout *timeparms,
- const char *ip_addr,
- rpc_authflavor_t authflavour,
- int flags)
+int nfs4_init_client(struct nfs_client *clp,
+ const struct rpc_timeout *timeparms,
+ const char *ip_addr,
+ rpc_authflavor_t authflavour,
+ int noresvport)
{
int error;
@@ -1325,7 +1345,7 @@ static int nfs4_init_client(struct nfs_client *clp,
clp->rpc_ops = &nfs_v4_clientops;
error = nfs_create_rpc_client(clp, timeparms, authflavour,
- 1, flags & NFS_MOUNT_NORESVPORT);
+ 1, noresvport);
if (error < 0)
goto error;
strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
@@ -1378,27 +1398,71 @@ static int nfs4_set_client(struct nfs_server *server,
dprintk("--> nfs4_set_client()\n");
/* Allocate or find a client reference we can use */
- clp = nfs_get_client(&cl_init);
+ clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour,
+ server->flags & NFS_MOUNT_NORESVPORT);
if (IS_ERR(clp)) {
error = PTR_ERR(clp);
goto error;
}
- error = nfs4_init_client(clp, timeparms, ip_addr, authflavour,
- server->flags);
- if (error < 0)
- goto error_put;
+
+ /*
+ * Query for the lease time on clientid setup or renewal
+ *
+ * Note that this will be set on nfs_clients that were created
+ * only for the DS role and did not set this bit, but now will
+ * serve a dual role.
+ */
+ set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
server->nfs_client = clp;
dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
return 0;
-
-error_put:
- nfs_put_client(clp);
error:
dprintk("<-- nfs4_set_client() = xerror %d\n", error);
return error;
}
+/*
+ * Set up a pNFS Data Server client.
+ *
+ * Return any existing nfs_client that matches server address,port,version
+ * and minorversion.
+ *
+ * For a new nfs_client, use a soft mount (default), a low retrans and a
+ * low timeout interval so that if a connection is lost, we retry through
+ * the MDS.
+ */
+struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
+ const struct sockaddr *ds_addr,
+ int ds_addrlen, int ds_proto)
+{
+ struct nfs_client_initdata cl_init = {
+ .addr = ds_addr,
+ .addrlen = ds_addrlen,
+ .rpc_ops = &nfs_v4_clientops,
+ .proto = ds_proto,
+ .minorversion = mds_clp->cl_minorversion,
+ };
+ struct rpc_timeout ds_timeout = {
+ .to_initval = 15 * HZ,
+ .to_maxval = 15 * HZ,
+ .to_retries = 1,
+ .to_exponential = 1,
+ };
+ struct nfs_client *clp;
+
+ /*
+ * Set an authflavor equual to the MDS value. Use the MDS nfs_client
+ * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
+ * (section 13.1 RFC 5661).
+ */
+ clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr,
+ mds_clp->cl_rpcclient->cl_auth->au_flavor, 0);
+
+ dprintk("<-- %s %p\n", __func__, clp);
+ return clp;
+}
+EXPORT_SYMBOL(nfs4_set_ds_client);
/*
* Session has been established, and the client marked ready.
@@ -1435,6 +1499,10 @@ static int nfs4_server_common_setup(struct nfs_server *server,
BUG_ON(!server->nfs_client->rpc_ops);
BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
+ /* data servers support only a subset of NFSv4.1 */
+ if (is_ds_only_client(server->nfs_client))
+ return -EPROTONOSUPPORT;
+
fattr = nfs_alloc_fattr();
if (fattr == NULL)
return -ENOMEM;
@@ -1504,6 +1572,13 @@ static int nfs4_init_server(struct nfs_server *server,
if (error < 0)
goto error;
+ /*
+ * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
+ * authentication.
+ */
+ if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
+ server->caps |= NFS_CAP_UIDGID_NOMAP;
+
if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL);
if (data->wsize)
@@ -1921,3 +1996,7 @@ void nfs_fs_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
+
+module_param(nfs4_disable_idmapping, bool, 0644);
+MODULE_PARM_DESC(nfs4_disable_idmapping,
+ "Turn off NFSv4 idmapping when using 'sec=sys'");
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 9943a75bb6d1..8eea25366717 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -45,6 +45,7 @@
#include <linux/pagemap.h>
#include <linux/kref.h>
#include <linux/slab.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
@@ -649,8 +650,7 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
- if (nfs_writeback_done(task, data) != 0)
- return;
+ nfs_writeback_done(task, data);
}
/*
@@ -938,6 +938,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
if (retval)
goto out;
+ task_io_account_read(count);
+
retval = nfs_direct_read(iocb, iov, nr_segs, pos);
if (retval > 0)
iocb->ki_pos = pos + retval;
@@ -999,6 +1001,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
if (retval)
goto out;
+ task_io_account_write(count);
+
retval = nfs_direct_write(iocb, iov, nr_segs, pos, count);
if (retval > 0)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 7bf029ef4084..d85a534b15cd 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -387,10 +387,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
file->f_path.dentry->d_name.name,
mapping->host->i_ino, len, (long long) pos);
- pnfs_update_layout(mapping->host,
- nfs_file_open_context(file),
- IOMODE_RW);
-
start:
/*
* Prevent starvation issues if someone is doing a consistency
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 18696882f1c6..79664a1025af 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -33,16 +33,41 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
+{
+ unsigned long val;
+ char buf[16];
+
+ if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf))
+ return 0;
+ memcpy(buf, name, namelen);
+ buf[namelen] = '\0';
+ if (strict_strtoul(buf, 0, &val) != 0)
+ return 0;
+ *res = val;
+ return 1;
+}
+
+static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
+{
+ return snprintf(buf, buflen, "%u", id);
+}
#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
#include <linux/slab.h>
#include <linux/cred.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs_sb.h>
#include <linux/nfs_idmap.h>
#include <linux/keyctl.h>
#include <linux/key-type.h>
#include <linux/rcupdate.h>
-#include <linux/kernel.h>
#include <linux/err.h>
#include <keys/user-type.h>
@@ -219,23 +244,39 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen,
return ret;
}
-int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
{
+ if (nfs_map_string_to_numeric(name, namelen, uid))
+ return 0;
return nfs_idmap_lookup_id(name, namelen, "uid", uid);
}
-int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *gid)
+int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
{
+ if (nfs_map_string_to_numeric(name, namelen, gid))
+ return 0;
return nfs_idmap_lookup_id(name, namelen, "gid", gid);
}
-int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
+int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
{
- return nfs_idmap_lookup_name(uid, "user", buf, buflen);
+ int ret = -EINVAL;
+
+ if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+ ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
+ if (ret < 0)
+ ret = nfs_map_numeric_to_string(uid, buf, buflen);
+ return ret;
}
-int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t buflen)
+int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
{
- return nfs_idmap_lookup_name(gid, "group", buf, buflen);
+ int ret = -EINVAL;
+
+ if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+ ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
+ if (ret < 0)
+ ret = nfs_map_numeric_to_string(gid, buf, buflen);
+ return ret;
}
#else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
@@ -243,7 +284,6 @@ int nfs_map_gid_to_group(struct nfs_client *clp, __u32 gid, char *buf, size_t bu
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/init.h>
-#include <linux/types.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/in.h>
@@ -695,31 +735,45 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
return hash;
}
-int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
{
- struct idmap *idmap = clp->cl_idmap;
+ struct idmap *idmap = server->nfs_client->cl_idmap;
+ if (nfs_map_string_to_numeric(name, namelen, uid))
+ return 0;
return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
}
-int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
+int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
{
- struct idmap *idmap = clp->cl_idmap;
+ struct idmap *idmap = server->nfs_client->cl_idmap;
+ if (nfs_map_string_to_numeric(name, namelen, uid))
+ return 0;
return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
}
-int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
+int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
{
- struct idmap *idmap = clp->cl_idmap;
+ struct idmap *idmap = server->nfs_client->cl_idmap;
+ int ret = -EINVAL;
- return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+ if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+ ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
+ if (ret < 0)
+ ret = nfs_map_numeric_to_string(uid, buf, buflen);
+ return ret;
}
-int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf, size_t buflen)
+int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
{
- struct idmap *idmap = clp->cl_idmap;
+ struct idmap *idmap = server->nfs_client->cl_idmap;
+ int ret = -EINVAL;
- return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
+ if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
+ ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
+ if (ret < 0)
+ ret = nfs_map_numeric_to_string(uid, buf, buflen);
+ return ret;
}
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index e94ad22da5d2..72e0bddf7a2f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -148,6 +148,9 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fattr *);
extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
extern int nfs4_check_client_ready(struct nfs_client *clp);
+extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
+ const struct sockaddr *ds_addr,
+ int ds_addrlen, int ds_proto);
#ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void);
@@ -213,8 +216,14 @@ extern const u32 nfs41_maxwrite_overhead;
extern struct rpc_procinfo nfs4_procedures[];
#endif
+extern int nfs4_init_ds_session(struct nfs_client *clp);
+
/* proc.c */
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
+extern int nfs_init_client(struct nfs_client *clp,
+ const struct rpc_timeout *timeparms,
+ const char *ip_addr, rpc_authflavor_t authflavour,
+ int noresvport);
/* dir.c */
extern int nfs_access_cache_shrinker(struct shrinker *shrink,
@@ -262,9 +271,15 @@ extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
#endif
/* read.c */
+extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
+ const struct rpc_call_ops *call_ops);
extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
/* write.c */
+extern int nfs_initiate_write(struct nfs_write_data *data,
+ struct rpc_clnt *clnt,
+ const struct rpc_call_ops *call_ops,
+ int how);
extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
#ifdef CONFIG_MIGRATION
extern int nfs_migrate_page(struct address_space *,
@@ -274,6 +289,13 @@ extern int nfs_migrate_page(struct address_space *,
#endif
/* nfs4proc.c */
+extern void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data);
+extern int nfs4_init_client(struct nfs_client *clp,
+ const struct rpc_timeout *timeparms,
+ const char *ip_addr,
+ rpc_authflavor_t authflavour,
+ int noresvport);
+extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data);
extern int _nfs4_call_sync(struct nfs_server *server,
struct rpc_message *msg,
struct nfs4_sequence_args *args,
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index ce939c062a52..d0c80d8b3f96 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -885,4 +885,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls,
.close_context = nfs_close_context,
+ .init_client = nfs_init_client,
};
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1be36cf65bfc..c64be1cff080 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -252,6 +252,9 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
extern int nfs4_setup_sequence(const struct nfs_server *server,
struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
int cache_reply, struct rpc_task *task);
+extern int nfs41_setup_sequence(struct nfs4_session *session,
+ struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
+ int cache_reply, struct rpc_task *task);
extern void nfs4_destroy_session(struct nfs4_session *session);
extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
extern int nfs4_proc_create_session(struct nfs_client *);
@@ -259,6 +262,19 @@ extern int nfs4_proc_destroy_session(struct nfs4_session *);
extern int nfs4_init_session(struct nfs_server *server);
extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
struct nfs_fsinfo *fsinfo);
+
+static inline bool
+is_ds_only_client(struct nfs_client *clp)
+{
+ return (clp->cl_exchange_flags & EXCHGID4_FLAG_MASK_PNFS) ==
+ EXCHGID4_FLAG_USE_PNFS_DS;
+}
+
+static inline bool
+is_ds_client(struct nfs_client *clp)
+{
+ return clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_DS;
+}
#else /* CONFIG_NFS_v4_1 */
static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
{
@@ -276,6 +292,18 @@ static inline int nfs4_init_session(struct nfs_server *server)
{
return 0;
}
+
+static inline bool
+is_ds_only_client(struct nfs_client *clp)
+{
+ return false;
+}
+
+static inline bool
+is_ds_client(struct nfs_client *clp)
+{
+ return false;
+}
#endif /* CONFIG_NFS_V4_1 */
extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 23f930caf1e2..428558464817 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -40,32 +40,309 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
MODULE_DESCRIPTION("The NFSv4 file layout driver");
-static int
-filelayout_set_layoutdriver(struct nfs_server *nfss)
+#define FILELAYOUT_POLL_RETRY_MAX (15*HZ)
+
+static loff_t
+filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
+ loff_t offset)
{
- int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client,
- nfs4_fl_free_deviceid_callback);
- if (status) {
- printk(KERN_WARNING "%s: deviceid cache could not be "
- "initialized\n", __func__);
- return status;
+ u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
+ u64 tmp;
+
+ offset -= flseg->pattern_offset;
+ tmp = offset;
+ do_div(tmp, stripe_width);
+
+ return tmp * flseg->stripe_unit + do_div(offset, flseg->stripe_unit);
+}
+
+/* This function is used by the layout driver to calculate the
+ * offset of the file on the dserver based on whether the
+ * layout type is STRIPE_DENSE or STRIPE_SPARSE
+ */
+static loff_t
+filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
+{
+ struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
+
+ switch (flseg->stripe_type) {
+ case STRIPE_SPARSE:
+ return offset;
+
+ case STRIPE_DENSE:
+ return filelayout_get_dense_offset(flseg, offset);
}
- dprintk("%s: deviceid cache has been initialized successfully\n",
- __func__);
+
+ BUG();
+}
+
+/* For data server errors we don't recover from */
+static void
+filelayout_set_lo_fail(struct pnfs_layout_segment *lseg)
+{
+ if (lseg->pls_range.iomode == IOMODE_RW) {
+ dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
+ set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+ } else {
+ dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
+ set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+ }
+}
+
+static int filelayout_async_handle_error(struct rpc_task *task,
+ struct nfs4_state *state,
+ struct nfs_client *clp,
+ int *reset)
+{
+ if (task->tk_status >= 0)
+ return 0;
+
+ *reset = 0;
+
+ switch (task->tk_status) {
+ case -NFS4ERR_BADSESSION:
+ case -NFS4ERR_BADSLOT:
+ case -NFS4ERR_BAD_HIGH_SLOT:
+ case -NFS4ERR_DEADSESSION:
+ case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+ case -NFS4ERR_SEQ_FALSE_RETRY:
+ case -NFS4ERR_SEQ_MISORDERED:
+ dprintk("%s ERROR %d, Reset session. Exchangeid "
+ "flags 0x%x\n", __func__, task->tk_status,
+ clp->cl_exchange_flags);
+ nfs4_schedule_session_recovery(clp->cl_session);
+ break;
+ case -NFS4ERR_DELAY:
+ case -NFS4ERR_GRACE:
+ case -EKEYEXPIRED:
+ rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
+ break;
+ default:
+ dprintk("%s DS error. Retry through MDS %d\n", __func__,
+ task->tk_status);
+ *reset = 1;
+ break;
+ }
+ task->tk_status = 0;
+ return -EAGAIN;
+}
+
+/* NFS_PROTO call done callback routines */
+
+static int filelayout_read_done_cb(struct rpc_task *task,
+ struct nfs_read_data *data)
+{
+ struct nfs_client *clp = data->ds_clp;
+ int reset = 0;
+
+ dprintk("%s DS read\n", __func__);
+
+ if (filelayout_async_handle_error(task, data->args.context->state,
+ data->ds_clp, &reset) == -EAGAIN) {
+ dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
+ __func__, data->ds_clp, data->ds_clp->cl_session);
+ if (reset) {
+ filelayout_set_lo_fail(data->lseg);
+ nfs4_reset_read(task, data);
+ clp = NFS_SERVER(data->inode)->nfs_client;
+ }
+ nfs_restart_rpc(task, clp);
+ return -EAGAIN;
+ }
+
return 0;
}
-/* Clear out the layout by destroying its device list */
-static int
-filelayout_clear_layoutdriver(struct nfs_server *nfss)
+/*
+ * Call ops for the async read/write cases
+ * In the case of dense layouts, the offset needs to be reset to its
+ * original value.
+ */
+static void filelayout_read_prepare(struct rpc_task *task, void *data)
{
- dprintk("--> %s\n", __func__);
+ struct nfs_read_data *rdata = (struct nfs_read_data *)data;
+
+ rdata->read_done_cb = filelayout_read_done_cb;
+
+ if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
+ &rdata->args.seq_args, &rdata->res.seq_res,
+ 0, task))
+ return;
+
+ rpc_call_start(task);
+}
+
+static void filelayout_read_call_done(struct rpc_task *task, void *data)
+{
+ struct nfs_read_data *rdata = (struct nfs_read_data *)data;
+
+ dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
+
+ /* Note this may cause RPC to be resent */
+ rdata->mds_ops->rpc_call_done(task, data);
+}
+
+static void filelayout_read_release(void *data)
+{
+ struct nfs_read_data *rdata = (struct nfs_read_data *)data;
+
+ rdata->mds_ops->rpc_release(data);
+}
+
+static int filelayout_write_done_cb(struct rpc_task *task,
+ struct nfs_write_data *data)
+{
+ int reset = 0;
+
+ if (filelayout_async_handle_error(task, data->args.context->state,
+ data->ds_clp, &reset) == -EAGAIN) {
+ struct nfs_client *clp;
+
+ dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
+ __func__, data->ds_clp, data->ds_clp->cl_session);
+ if (reset) {
+ filelayout_set_lo_fail(data->lseg);
+ nfs4_reset_write(task, data);
+ clp = NFS_SERVER(data->inode)->nfs_client;
+ } else
+ clp = data->ds_clp;
+ nfs_restart_rpc(task, clp);
+ return -EAGAIN;
+ }
- if (nfss->nfs_client->cl_devid_cache)
- pnfs_put_deviceid_cache(nfss->nfs_client);
return 0;
}
+static void filelayout_write_prepare(struct rpc_task *task, void *data)
+{
+ struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+ if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
+ &wdata->args.seq_args, &wdata->res.seq_res,
+ 0, task))
+ return;
+
+ rpc_call_start(task);
+}
+
+static void filelayout_write_call_done(struct rpc_task *task, void *data)
+{
+ struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+ /* Note this may cause RPC to be resent */
+ wdata->mds_ops->rpc_call_done(task, data);
+}
+
+static void filelayout_write_release(void *data)
+{
+ struct nfs_write_data *wdata = (struct nfs_write_data *)data;
+
+ wdata->mds_ops->rpc_release(data);
+}
+
+struct rpc_call_ops filelayout_read_call_ops = {
+ .rpc_call_prepare = filelayout_read_prepare,
+ .rpc_call_done = filelayout_read_call_done,
+ .rpc_release = filelayout_read_release,
+};
+
+struct rpc_call_ops filelayout_write_call_ops = {
+ .rpc_call_prepare = filelayout_write_prepare,
+ .rpc_call_done = filelayout_write_call_done,
+ .rpc_release = filelayout_write_release,
+};
+
+static enum pnfs_try_status
+filelayout_read_pagelist(struct nfs_read_data *data)
+{
+ struct pnfs_layout_segment *lseg = data->lseg;
+ struct nfs4_pnfs_ds *ds;
+ loff_t offset = data->args.offset;
+ u32 j, idx;
+ struct nfs_fh *fh;
+ int status;
+
+ dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
+ __func__, data->inode->i_ino,
+ data->args.pgbase, (size_t)data->args.count, offset);
+
+ /* Retrieve the correct rpc_client for the byte range */
+ j = nfs4_fl_calc_j_index(lseg, offset);
+ idx = nfs4_fl_calc_ds_index(lseg, j);
+ ds = nfs4_fl_prepare_ds(lseg, idx);
+ if (!ds) {
+ /* Either layout fh index faulty, or ds connect failed */
+ set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+ set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+ return PNFS_NOT_ATTEMPTED;
+ }
+ dprintk("%s USE DS:ip %x %hu\n", __func__,
+ ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+
+ /* No multipath support. Use first DS */
+ data->ds_clp = ds->ds_clp;
+ fh = nfs4_fl_select_ds_fh(lseg, j);
+ if (fh)
+ data->args.fh = fh;
+
+ data->args.offset = filelayout_get_dserver_offset(lseg, offset);
+ data->mds_offset = offset;
+
+ /* Perform an asynchronous read to ds */
+ status = nfs_initiate_read(data, ds->ds_clp->cl_rpcclient,
+ &filelayout_read_call_ops);
+ BUG_ON(status != 0);
+ return PNFS_ATTEMPTED;
+}
+
+/* Perform async writes. */
+static enum pnfs_try_status
+filelayout_write_pagelist(struct nfs_write_data *data, int sync)
+{
+ struct pnfs_layout_segment *lseg = data->lseg;
+ struct nfs4_pnfs_ds *ds;
+ loff_t offset = data->args.offset;
+ u32 j, idx;
+ struct nfs_fh *fh;
+ int status;
+
+ /* Retrieve the correct rpc_client for the byte range */
+ j = nfs4_fl_calc_j_index(lseg, offset);
+ idx = nfs4_fl_calc_ds_index(lseg, j);
+ ds = nfs4_fl_prepare_ds(lseg, idx);
+ if (!ds) {
+ printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__);
+ set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+ set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+ return PNFS_NOT_ATTEMPTED;
+ }
+ dprintk("%s ino %lu sync %d req %Zu@%llu DS:%x:%hu\n", __func__,
+ data->inode->i_ino, sync, (size_t) data->args.count, offset,
+ ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+
+ /* We can't handle commit to ds yet */
+ if (!FILELAYOUT_LSEG(lseg)->commit_through_mds)
+ data->args.stable = NFS_FILE_SYNC;
+
+ data->write_done_cb = filelayout_write_done_cb;
+ data->ds_clp = ds->ds_clp;
+ fh = nfs4_fl_select_ds_fh(lseg, j);
+ if (fh)
+ data->args.fh = fh;
+ /*
+ * Get the file offset on the dserver. Set the write offset to
+ * this offset and save the original offset.
+ */
+ data->args.offset = filelayout_get_dserver_offset(lseg, offset);
+ data->mds_offset = offset;
+
+ /* Perform an asynchronous write */
+ status = nfs_initiate_write(data, ds->ds_clp->cl_rpcclient,
+ &filelayout_write_call_ops, sync);
+ BUG_ON(status != 0);
+ return PNFS_ATTEMPTED;
+}
+
/*
* filelayout_check_layout()
*
@@ -92,14 +369,14 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
goto out;
}
- if (fl->stripe_unit % PAGE_SIZE) {
- dprintk("%s Stripe unit (%u) not page aligned\n",
+ if (!fl->stripe_unit || fl->stripe_unit % PAGE_SIZE) {
+ dprintk("%s Invalid stripe unit (%u)\n",
__func__, fl->stripe_unit);
goto out;
}
/* find and reference the deviceid */
- dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id);
+ dsaddr = nfs4_fl_find_get_deviceid(id);
if (dsaddr == NULL) {
dsaddr = get_device_info(lo->plh_inode, id);
if (dsaddr == NULL)
@@ -134,7 +411,7 @@ out:
dprintk("--> %s returns %d\n", __func__, status);
return status;
out_put:
- pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid);
+ nfs4_fl_put_deviceid(dsaddr);
goto out;
}
@@ -243,23 +520,47 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
static void
filelayout_free_lseg(struct pnfs_layout_segment *lseg)
{
- struct nfs_server *nfss = NFS_SERVER(lseg->pls_layout->plh_inode);
struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
dprintk("--> %s\n", __func__);
- pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache,
- &fl->dsaddr->deviceid);
+ nfs4_fl_put_deviceid(fl->dsaddr);
_filelayout_free_lseg(fl);
}
+/*
+ * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
+ *
+ * return 1 : coalesce page
+ * return 0 : don't coalesce page
+ */
+int
+filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+ struct nfs_page *req)
+{
+ u64 p_stripe, r_stripe;
+ u32 stripe_unit;
+
+ if (!pgio->pg_lseg)
+ return 1;
+ p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT;
+ r_stripe = (u64)req->wb_index << PAGE_CACHE_SHIFT;
+ stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
+
+ do_div(p_stripe, stripe_unit);
+ do_div(r_stripe, stripe_unit);
+
+ return (p_stripe == r_stripe);
+}
+
static struct pnfs_layoutdriver_type filelayout_type = {
- .id = LAYOUT_NFSV4_1_FILES,
- .name = "LAYOUT_NFSV4_1_FILES",
- .owner = THIS_MODULE,
- .set_layoutdriver = filelayout_set_layoutdriver,
- .clear_layoutdriver = filelayout_clear_layoutdriver,
- .alloc_lseg = filelayout_alloc_lseg,
- .free_lseg = filelayout_free_lseg,
+ .id = LAYOUT_NFSV4_1_FILES,
+ .name = "LAYOUT_NFSV4_1_FILES",
+ .owner = THIS_MODULE,
+ .alloc_lseg = filelayout_alloc_lseg,
+ .free_lseg = filelayout_free_lseg,
+ .pg_test = filelayout_pg_test,
+ .read_pagelist = filelayout_read_pagelist,
+ .write_pagelist = filelayout_write_pagelist,
};
static int __init nfs4filelayout_init(void)
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index bbf60dd2ab9d..ee0c907742b5 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -55,8 +55,14 @@ struct nfs4_pnfs_ds {
atomic_t ds_count;
};
+/* nfs4_file_layout_dsaddr flags */
+#define NFS4_DEVICE_ID_NEG_ENTRY 0x00000001
+
struct nfs4_file_layout_dsaddr {
- struct pnfs_deviceid_node deviceid;
+ struct hlist_node node;
+ struct nfs4_deviceid deviceid;
+ atomic_t ref;
+ unsigned long flags;
u32 stripe_count;
u8 *stripe_indices;
u32 ds_num;
@@ -83,11 +89,18 @@ FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
generic_hdr);
}
-extern void nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *);
+extern struct nfs_fh *
+nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
+
extern void print_ds(struct nfs4_pnfs_ds *ds);
extern void print_deviceid(struct nfs4_deviceid *dev_id);
+u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset);
+u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j);
+struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
+ u32 ds_idx);
extern struct nfs4_file_layout_dsaddr *
-nfs4_fl_find_get_deviceid(struct nfs_client *, struct nfs4_deviceid *dev_id);
+nfs4_fl_find_get_deviceid(struct nfs4_deviceid *dev_id);
+extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
struct nfs4_file_layout_dsaddr *
get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id);
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index b73c34375f60..68143c162e3b 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -37,6 +37,30 @@
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
/*
+ * Device ID RCU cache. A device ID is unique per client ID and layout type.
+ */
+#define NFS4_FL_DEVICE_ID_HASH_BITS 5
+#define NFS4_FL_DEVICE_ID_HASH_SIZE (1 << NFS4_FL_DEVICE_ID_HASH_BITS)
+#define NFS4_FL_DEVICE_ID_HASH_MASK (NFS4_FL_DEVICE_ID_HASH_SIZE - 1)
+
+static inline u32
+nfs4_fl_deviceid_hash(struct nfs4_deviceid *id)
+{
+ unsigned char *cptr = (unsigned char *)id->data;
+ unsigned int nbytes = NFS4_DEVICEID4_SIZE;
+ u32 x = 0;
+
+ while (nbytes--) {
+ x *= 37;
+ x += *cptr++;
+ }
+ return x & NFS4_FL_DEVICE_ID_HASH_MASK;
+}
+
+static struct hlist_head filelayout_deviceid_cache[NFS4_FL_DEVICE_ID_HASH_SIZE];
+static DEFINE_SPINLOCK(filelayout_deviceid_lock);
+
+/*
* Data server cache
*
* Data servers can be mapped to different device ids.
@@ -104,6 +128,67 @@ _data_server_lookup_locked(u32 ip_addr, u32 port)
return NULL;
}
+/*
+ * Create an rpc connection to the nfs4_pnfs_ds data server
+ * Currently only support IPv4
+ */
+static int
+nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
+{
+ struct nfs_client *clp;
+ struct sockaddr_in sin;
+ int status = 0;
+
+ dprintk("--> %s ip:port %x:%hu au_flavor %d\n", __func__,
+ ntohl(ds->ds_ip_addr), ntohs(ds->ds_port),
+ mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = ds->ds_ip_addr;
+ sin.sin_port = ds->ds_port;
+
+ clp = nfs4_set_ds_client(mds_srv->nfs_client, (struct sockaddr *)&sin,
+ sizeof(sin), IPPROTO_TCP);
+ if (IS_ERR(clp)) {
+ status = PTR_ERR(clp);
+ goto out;
+ }
+
+ if ((clp->cl_exchange_flags & EXCHGID4_FLAG_MASK_PNFS) != 0) {
+ if (!is_ds_client(clp)) {
+ status = -ENODEV;
+ goto out_put;
+ }
+ ds->ds_clp = clp;
+ dprintk("%s [existing] ip=%x, port=%hu\n", __func__,
+ ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+ goto out;
+ }
+
+ /*
+ * Do not set NFS_CS_CHECK_LEASE_TIME instead set the DS lease to
+ * be equal to the MDS lease. Renewal is scheduled in create_session.
+ */
+ spin_lock(&mds_srv->nfs_client->cl_lock);
+ clp->cl_lease_time = mds_srv->nfs_client->cl_lease_time;
+ spin_unlock(&mds_srv->nfs_client->cl_lock);
+ clp->cl_last_renewal = jiffies;
+
+ /* New nfs_client */
+ status = nfs4_init_ds_session(clp);
+ if (status)
+ goto out_put;
+
+ ds->ds_clp = clp;
+ dprintk("%s [new] ip=%x, port=%hu\n", __func__, ntohl(ds->ds_ip_addr),
+ ntohs(ds->ds_port));
+out:
+ return status;
+out_put:
+ nfs_put_client(clp);
+ goto out;
+}
+
static void
destroy_ds(struct nfs4_pnfs_ds *ds)
{
@@ -122,7 +207,7 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
struct nfs4_pnfs_ds *ds;
int i;
- print_deviceid(&dsaddr->deviceid.de_id);
+ print_deviceid(&dsaddr->deviceid);
for (i = 0; i < dsaddr->ds_num; i++) {
ds = dsaddr->ds_list[i];
@@ -139,15 +224,6 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
kfree(dsaddr);
}
-void
-nfs4_fl_free_deviceid_callback(struct pnfs_deviceid_node *device)
-{
- struct nfs4_file_layout_dsaddr *dsaddr =
- container_of(device, struct nfs4_file_layout_dsaddr, deviceid);
-
- nfs4_fl_free_deviceid(dsaddr);
-}
-
static struct nfs4_pnfs_ds *
nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port)
{
@@ -300,7 +376,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev)
dsaddr->stripe_count = cnt;
dsaddr->ds_num = num;
- memcpy(&dsaddr->deviceid.de_id, &pdev->dev_id, sizeof(pdev->dev_id));
+ memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id));
/* Go back an read stripe indices */
p = indicesp;
@@ -350,28 +426,37 @@ out_err:
}
/*
- * Decode the opaque device specified in 'dev'
- * and add it to the list of available devices.
- * If the deviceid is already cached, nfs4_add_deviceid will return
- * a pointer to the cached struct and throw away the new.
+ * Decode the opaque device specified in 'dev' and add it to the cache of
+ * available devices.
*/
-static struct nfs4_file_layout_dsaddr*
+static struct nfs4_file_layout_dsaddr *
decode_and_add_device(struct inode *inode, struct pnfs_device *dev)
{
- struct nfs4_file_layout_dsaddr *dsaddr;
- struct pnfs_deviceid_node *d;
+ struct nfs4_file_layout_dsaddr *d, *new;
+ long hash;
- dsaddr = decode_device(inode, dev);
- if (!dsaddr) {
+ new = decode_device(inode, dev);
+ if (!new) {
printk(KERN_WARNING "%s: Could not decode or add device\n",
__func__);
return NULL;
}
- d = pnfs_add_deviceid(NFS_SERVER(inode)->nfs_client->cl_devid_cache,
- &dsaddr->deviceid);
+ spin_lock(&filelayout_deviceid_lock);
+ d = nfs4_fl_find_get_deviceid(&new->deviceid);
+ if (d) {
+ spin_unlock(&filelayout_deviceid_lock);
+ nfs4_fl_free_deviceid(new);
+ return d;
+ }
+
+ INIT_HLIST_NODE(&new->node);
+ atomic_set(&new->ref, 1);
+ hash = nfs4_fl_deviceid_hash(&new->deviceid);
+ hlist_add_head_rcu(&new->node, &filelayout_deviceid_cache[hash]);
+ spin_unlock(&filelayout_deviceid_lock);
- return container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+ return new;
}
/*
@@ -446,12 +531,123 @@ out_free:
return dsaddr;
}
+void
+nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
+{
+ if (atomic_dec_and_lock(&dsaddr->ref, &filelayout_deviceid_lock)) {
+ hlist_del_rcu(&dsaddr->node);
+ spin_unlock(&filelayout_deviceid_lock);
+
+ synchronize_rcu();
+ nfs4_fl_free_deviceid(dsaddr);
+ }
+}
+
struct nfs4_file_layout_dsaddr *
-nfs4_fl_find_get_deviceid(struct nfs_client *clp, struct nfs4_deviceid *id)
+nfs4_fl_find_get_deviceid(struct nfs4_deviceid *id)
+{
+ struct nfs4_file_layout_dsaddr *d;
+ struct hlist_node *n;
+ long hash = nfs4_fl_deviceid_hash(id);
+
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(d, n, &filelayout_deviceid_cache[hash], node) {
+ if (!memcmp(&d->deviceid, id, sizeof(*id))) {
+ if (!atomic_inc_not_zero(&d->ref))
+ goto fail;
+ rcu_read_unlock();
+ return d;
+ }
+ }
+fail:
+ rcu_read_unlock();
+ return NULL;
+}
+
+/*
+ * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
+ * Then: ((res + fsi) % dsaddr->stripe_count)
+ */
+u32
+nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset)
+{
+ struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
+ u64 tmp;
+
+ tmp = offset - flseg->pattern_offset;
+ do_div(tmp, flseg->stripe_unit);
+ tmp += flseg->first_stripe_index;
+ return do_div(tmp, flseg->dsaddr->stripe_count);
+}
+
+u32
+nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j)
+{
+ return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j];
+}
+
+struct nfs_fh *
+nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
+{
+ struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
+ u32 i;
+
+ if (flseg->stripe_type == STRIPE_SPARSE) {
+ if (flseg->num_fh == 1)
+ i = 0;
+ else if (flseg->num_fh == 0)
+ /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
+ return NULL;
+ else
+ i = nfs4_fl_calc_ds_index(lseg, j);
+ } else
+ i = j;
+ return flseg->fh_array[i];
+}
+
+static void
+filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr,
+ int err, u32 ds_addr)
+{
+ u32 *p = (u32 *)&dsaddr->deviceid;
+
+ printk(KERN_ERR "NFS: data server %x connection error %d."
+ " Deviceid [%x%x%x%x] marked out of use.\n",
+ ds_addr, err, p[0], p[1], p[2], p[3]);
+
+ spin_lock(&filelayout_deviceid_lock);
+ dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY;
+ spin_unlock(&filelayout_deviceid_lock);
+}
+
+struct nfs4_pnfs_ds *
+nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
{
- struct pnfs_deviceid_node *d;
+ struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
+ struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
- d = pnfs_find_get_deviceid(clp->cl_devid_cache, id);
- return (d == NULL) ? NULL :
- container_of(d, struct nfs4_file_layout_dsaddr, deviceid);
+ if (ds == NULL) {
+ printk(KERN_ERR "%s: No data server for offset index %d\n",
+ __func__, ds_idx);
+ return NULL;
+ }
+
+ if (!ds->ds_clp) {
+ struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
+ int err;
+
+ if (dsaddr->flags & NFS4_DEVICE_ID_NEG_ENTRY) {
+ /* Already tried to connect, don't try again */
+ dprintk("%s Deviceid marked out of use\n", __func__);
+ return NULL;
+ }
+ err = nfs4_ds_connect(s, ds);
+ if (err) {
+ filelayout_mark_devid_negative(dsaddr, err,
+ ntohl(ds->ds_ip_addr));
+ return NULL;
+ }
+ }
+ return ds;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 0a07e353a961..1d84e7088af9 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -85,6 +85,9 @@ static int nfs4_map_errors(int err)
switch (err) {
case -NFS4ERR_RESOURCE:
return -EREMOTEIO;
+ case -NFS4ERR_BADOWNER:
+ case -NFS4ERR_BADNAME:
+ return -EINVAL;
default:
dprintk("%s could not handle NFSv4 error %d\n",
__func__, -err);
@@ -241,7 +244,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
/* This is the error handling routine for processes that are allowed
* to sleep.
*/
-static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
+static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
{
struct nfs_client *clp = server->nfs_client;
struct nfs4_state *state = exception->state;
@@ -293,6 +296,19 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
break;
case -NFS4ERR_OLD_STATEID:
exception->retry = 1;
+ break;
+ case -NFS4ERR_BADOWNER:
+ /* The following works around a Linux server bug! */
+ case -NFS4ERR_BADNAME:
+ if (server->caps & NFS_CAP_UIDGID_NOMAP) {
+ server->caps &= ~NFS_CAP_UIDGID_NOMAP;
+ exception->retry = 1;
+ printk(KERN_WARNING "NFS: v4 server %s "
+ "does not accept raw "
+ "uid/gids. "
+ "Reenabling the idmapper.\n",
+ server->nfs_client->cl_hostname);
+ }
}
/* We failed to handle the error */
return nfs4_map_errors(ret);
@@ -505,7 +521,7 @@ out:
return ret_id;
}
-static int nfs41_setup_sequence(struct nfs4_session *session,
+int nfs41_setup_sequence(struct nfs4_session *session,
struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res,
int cache_reply,
@@ -571,6 +587,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
res->sr_status = 1;
return 0;
}
+EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
int nfs4_setup_sequence(const struct nfs_server *server,
struct nfs4_sequence_args *args,
@@ -1573,9 +1590,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return 0;
}
-static int nfs4_recover_expired_lease(struct nfs_server *server)
+static int nfs4_client_recover_expired_lease(struct nfs_client *clp)
{
- struct nfs_client *clp = server->nfs_client;
unsigned int loop;
int ret;
@@ -1592,6 +1608,11 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
return ret;
}
+static int nfs4_recover_expired_lease(struct nfs_server *server)
+{
+ return nfs4_client_recover_expired_lease(server->nfs_client);
+}
+
/*
* OPEN_EXPIRED:
* reclaim state on the server after a network partition.
@@ -3069,15 +3090,10 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return err;
}
-static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
+static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
{
struct nfs_server *server = NFS_SERVER(data->inode);
- dprintk("--> %s\n", __func__);
-
- if (!nfs4_sequence_done(task, &data->res.seq_res))
- return -EAGAIN;
-
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
nfs_restart_rpc(task, server->nfs_client);
return -EAGAIN;
@@ -3089,19 +3105,44 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
return 0;
}
+static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
+{
+
+ dprintk("--> %s\n", __func__);
+
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return -EAGAIN;
+
+ return data->read_done_cb(task, data);
+}
+
static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
{
data->timestamp = jiffies;
+ data->read_done_cb = nfs4_read_done_cb;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
}
-static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
+/* Reset the the nfs_read_data to send the read to the MDS. */
+void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data)
+{
+ dprintk("%s Reset task for i/o through\n", __func__);
+ put_lseg(data->lseg);
+ data->lseg = NULL;
+ /* offsets will differ in the dense stripe case */
+ data->args.offset = data->mds_offset;
+ data->ds_clp = NULL;
+ data->args.fh = NFS_FH(data->inode);
+ data->read_done_cb = nfs4_read_done_cb;
+ task->tk_ops = data->mds_ops;
+ rpc_task_reset_client(task, NFS_CLIENT(data->inode));
+}
+EXPORT_SYMBOL_GPL(nfs4_reset_read);
+
+static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
{
struct inode *inode = data->inode;
- if (!nfs4_sequence_done(task, &data->res.seq_res))
- return -EAGAIN;
-
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
return -EAGAIN;
@@ -3113,11 +3154,41 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
return 0;
}
+static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
+{
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
+ return -EAGAIN;
+ return data->write_done_cb(task, data);
+}
+
+/* Reset the the nfs_write_data to send the write to the MDS. */
+void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data)
+{
+ dprintk("%s Reset task for i/o through\n", __func__);
+ put_lseg(data->lseg);
+ data->lseg = NULL;
+ data->ds_clp = NULL;
+ data->write_done_cb = nfs4_write_done_cb;
+ data->args.fh = NFS_FH(data->inode);
+ data->args.bitmask = data->res.server->cache_consistency_bitmask;
+ data->args.offset = data->mds_offset;
+ data->res.fattr = &data->fattr;
+ task->tk_ops = data->mds_ops;
+ rpc_task_reset_client(task, NFS_CLIENT(data->inode));
+}
+EXPORT_SYMBOL_GPL(nfs4_reset_write);
+
static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
{
struct nfs_server *server = NFS_SERVER(data->inode);
- data->args.bitmask = server->cache_consistency_bitmask;
+ if (data->lseg) {
+ data->args.bitmask = NULL;
+ data->res.fattr = NULL;
+ } else
+ data->args.bitmask = server->cache_consistency_bitmask;
+ if (!data->write_done_cb)
+ data->write_done_cb = nfs4_write_done_cb;
data->res.server = server;
data->timestamp = jiffies;
@@ -5118,6 +5189,27 @@ int nfs4_init_session(struct nfs_server *server)
return ret;
}
+int nfs4_init_ds_session(struct nfs_client *clp)
+{
+ struct nfs4_session *session = clp->cl_session;
+ int ret;
+
+ if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
+ return 0;
+
+ ret = nfs4_client_recover_expired_lease(clp);
+ if (!ret)
+ /* Test for the DS role */
+ if (!is_ds_client(clp))
+ ret = -ENODEV;
+ if (!ret)
+ ret = nfs4_check_client_ready(clp);
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
+
+
/*
* Renew the cl_session lease.
*/
@@ -5648,6 +5740,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.clear_acl_cache = nfs4_zap_acl_attr,
.close_context = nfs4_close_context,
.open_context = nfs4_atomic_open,
+ .init_client = nfs4_init_client,
};
static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index 402143d75fc5..df8e7f3ca56d 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -64,12 +64,8 @@ nfs4_renew_state(struct work_struct *work)
ops = clp->cl_mvops->state_renewal_ops;
dprintk("%s: start\n", __func__);
- rcu_read_lock();
- if (list_empty(&clp->cl_superblocks)) {
- rcu_read_unlock();
+ if (test_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state))
goto out;
- }
- rcu_read_unlock();
spin_lock(&clp->cl_lock);
lease = clp->cl_lease_time;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 0592288f9f06..ab1bf5bb021f 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -153,6 +153,11 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
int status;
struct nfs_fsinfo fsinfo;
+ if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
+ nfs4_schedule_state_renewal(clp);
+ return 0;
+ }
+
status = nfs4_proc_get_lease_time(clp, &fsinfo);
if (status == 0) {
/* Update lease time and schedule renewal */
@@ -1448,6 +1453,7 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session)
{
nfs4_schedule_lease_recovery(session->clp);
}
+EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
void nfs41_handle_recall_slot(struct nfs_client *clp)
{
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 94d50e86a124..0cf560f77884 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -844,7 +844,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
if (iap->ia_valid & ATTR_MODE)
len += 4;
if (iap->ia_valid & ATTR_UID) {
- owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name, IDMAP_NAMESZ);
+ owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
if (owner_namelen < 0) {
dprintk("nfs: couldn't resolve uid %d to string\n",
iap->ia_uid);
@@ -856,7 +856,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
}
if (iap->ia_valid & ATTR_GID) {
- owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group, IDMAP_NAMESZ);
+ owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
if (owner_grouplen < 0) {
dprintk("nfs: couldn't resolve gid %d to string\n",
iap->ia_gid);
@@ -1384,7 +1384,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
hdr->replen += decode_putrootfh_maxsz;
}
-static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx)
+static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
{
nfs4_stateid stateid;
__be32 *p;
@@ -1392,6 +1392,8 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context
p = reserve_space(xdr, NFS4_STATEID_SIZE);
if (ctx->state != NULL) {
nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
+ if (zero_seqid)
+ stateid.stateid.seqid = 0;
xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
} else
xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
@@ -1404,7 +1406,8 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
p = reserve_space(xdr, 4);
*p = cpu_to_be32(OP_READ);
- encode_stateid(xdr, args->context, args->lock_context);
+ encode_stateid(xdr, args->context, args->lock_context,
+ hdr->minorversion);
p = reserve_space(xdr, 12);
p = xdr_encode_hyper(p, args->offset);
@@ -1592,7 +1595,8 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
p = reserve_space(xdr, 4);
*p = cpu_to_be32(OP_WRITE);
- encode_stateid(xdr, args->context, args->lock_context);
+ encode_stateid(xdr, args->context, args->lock_context,
+ hdr->minorversion);
p = reserve_space(xdr, 16);
p = xdr_encode_hyper(p, args->offset);
@@ -2271,7 +2275,8 @@ static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_putfh(xdr, args->fh, &hdr);
encode_write(xdr, args, &hdr);
req->rq_snd_buf.flags |= XDRBUF_WRITE;
- encode_getfattr(xdr, args->bitmask, &hdr);
+ if (args->bitmask)
+ encode_getfattr(xdr, args->bitmask, &hdr);
encode_nops(&hdr);
}
@@ -3382,7 +3387,7 @@ out_overflow:
}
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
- struct nfs_client *clp, uint32_t *uid, int may_sleep)
+ const struct nfs_server *server, uint32_t *uid, int may_sleep)
{
uint32_t len;
__be32 *p;
@@ -3402,7 +3407,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
if (!may_sleep) {
/* do nothing */
} else if (len < XDR_MAX_NETOBJ) {
- if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
+ if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
ret = NFS_ATTR_FATTR_OWNER;
else
dprintk("%s: nfs_map_name_to_uid failed!\n",
@@ -3420,7 +3425,7 @@ out_overflow:
}
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
- struct nfs_client *clp, uint32_t *gid, int may_sleep)
+ const struct nfs_server *server, uint32_t *gid, int may_sleep)
{
uint32_t len;
__be32 *p;
@@ -3440,7 +3445,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
if (!may_sleep) {
/* do nothing */
} else if (len < XDR_MAX_NETOBJ) {
- if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
+ if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
ret = NFS_ATTR_FATTR_GROUP;
else
dprintk("%s: nfs_map_group_to_gid failed!\n",
@@ -3939,14 +3944,12 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
goto xdr_error;
fattr->valid |= status;
- status = decode_attr_owner(xdr, bitmap, server->nfs_client,
- &fattr->uid, may_sleep);
+ status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep);
if (status < 0)
goto xdr_error;
fattr->valid |= status;
- status = decode_attr_group(xdr, bitmap, server->nfs_client,
- &fattr->gid, may_sleep);
+ status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep);
if (status < 0)
goto xdr_error;
fattr->valid |= status;
@@ -5690,8 +5693,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_write(xdr, res);
if (status)
goto out;
- decode_getfattr(xdr, res->fattr, res->server,
- !RPC_IS_ASYNC(rqstp->rq_task));
+ if (res->fattr)
+ decode_getfattr(xdr, res->fattr, res->server,
+ !RPC_IS_ASYNC(rqstp->rq_task));
if (!status)
status = res->count;
out:
@@ -6167,8 +6171,6 @@ static struct {
{ NFS4ERR_DQUOT, -EDQUOT },
{ NFS4ERR_STALE, -ESTALE },
{ NFS4ERR_BADHANDLE, -EBADHANDLE },
- { NFS4ERR_BADOWNER, -EINVAL },
- { NFS4ERR_BADNAME, -EINVAL },
{ NFS4ERR_BAD_COOKIE, -EBADCOOKIE },
{ NFS4ERR_NOTSUPP, -ENOTSUPP },
{ NFS4ERR_TOOSMALL, -ETOOSMALL },
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index e1164e3f9e69..23e794410669 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -20,6 +20,7 @@
#include <linux/nfs_mount.h>
#include "internal.h"
+#include "pnfs.h"
static struct kmem_cache *nfs_page_cachep;
@@ -213,7 +214,7 @@ nfs_wait_on_request(struct nfs_page *req)
*/
void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
struct inode *inode,
- int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+ int (*doio)(struct nfs_pageio_descriptor *),
size_t bsize,
int io_flags)
{
@@ -226,6 +227,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
desc->pg_doio = doio;
desc->pg_ioflags = io_flags;
desc->pg_error = 0;
+ desc->pg_lseg = NULL;
}
/**
@@ -240,7 +242,8 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
* Return 'true' if this is the case, else return 'false'.
*/
static int nfs_can_coalesce_requests(struct nfs_page *prev,
- struct nfs_page *req)
+ struct nfs_page *req,
+ struct nfs_pageio_descriptor *pgio)
{
if (req->wb_context->cred != prev->wb_context->cred)
return 0;
@@ -254,6 +257,12 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev,
return 0;
if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
return 0;
+ /*
+ * Non-whole file layouts need to check that req is inside of
+ * pgio->pg_lseg.
+ */
+ if (pgio->pg_test && !pgio->pg_test(pgio, prev, req))
+ return 0;
return 1;
}
@@ -286,7 +295,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
if (newlen > desc->pg_bsize)
return 0;
prev = nfs_list_entry(desc->pg_list.prev);
- if (!nfs_can_coalesce_requests(prev, req))
+ if (!nfs_can_coalesce_requests(prev, req, desc))
return 0;
} else
desc->pg_base = req->wb_pgbase;
@@ -302,12 +311,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
{
if (!list_empty(&desc->pg_list)) {
- int error = desc->pg_doio(desc->pg_inode,
- &desc->pg_list,
- nfs_page_array_len(desc->pg_base,
- desc->pg_count),
- desc->pg_count,
- desc->pg_ioflags);
+ int error = desc->pg_doio(desc);
if (error < 0)
desc->pg_error = error;
else
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 1b1bc1a0fb0a..f38813a0a295 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -30,6 +30,7 @@
#include <linux/nfs_fs.h>
#include "internal.h"
#include "pnfs.h"
+#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_PNFS
@@ -74,10 +75,8 @@ find_pnfs_driver(u32 id)
void
unset_pnfs_layoutdriver(struct nfs_server *nfss)
{
- if (nfss->pnfs_curr_ld) {
- nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
+ if (nfss->pnfs_curr_ld)
module_put(nfss->pnfs_curr_ld->owner);
- }
nfss->pnfs_curr_ld = NULL;
}
@@ -115,13 +114,7 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
goto out_no_driver;
}
server->pnfs_curr_ld = ld_type;
- if (ld_type->set_layoutdriver(server)) {
- printk(KERN_ERR
- "%s: Error initializing mount point for layout driver %u.\n",
- __func__, id);
- module_put(ld_type->owner);
- goto out_no_driver;
- }
+
dprintk("%s: pNFS module for %u set\n", __func__, id);
return;
@@ -230,37 +223,41 @@ static void free_lseg(struct pnfs_layout_segment *lseg)
put_layout_hdr(NFS_I(ino)->layout);
}
-/* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg
- * could sleep, so must be called outside of the lock.
- * Returns 1 if object was removed, otherwise return 0.
- */
-static int
-put_lseg_locked(struct pnfs_layout_segment *lseg,
- struct list_head *tmp_list)
+static void
+put_lseg_common(struct pnfs_layout_segment *lseg)
+{
+ struct inode *inode = lseg->pls_layout->plh_inode;
+
+ BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
+ list_del_init(&lseg->pls_list);
+ if (list_empty(&lseg->pls_layout->plh_segs)) {
+ set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags);
+ /* Matched by initial refcount set in alloc_init_layout_hdr */
+ put_layout_hdr_locked(lseg->pls_layout);
+ }
+ rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
+}
+
+void
+put_lseg(struct pnfs_layout_segment *lseg)
{
+ struct inode *inode;
+
+ if (!lseg)
+ return;
+
dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg,
atomic_read(&lseg->pls_refcount),
test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
- if (atomic_dec_and_test(&lseg->pls_refcount)) {
- struct inode *ino = lseg->pls_layout->plh_inode;
+ inode = lseg->pls_layout->plh_inode;
+ if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
+ LIST_HEAD(free_me);
- BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
- list_del(&lseg->pls_list);
- if (list_empty(&lseg->pls_layout->plh_segs)) {
- struct nfs_client *clp;
-
- clp = NFS_SERVER(ino)->nfs_client;
- spin_lock(&clp->cl_lock);
- /* List does not take a reference, so no need for put here */
- list_del_init(&lseg->pls_layout->plh_layouts);
- spin_unlock(&clp->cl_lock);
- clear_bit(NFS_LAYOUT_BULK_RECALL, &lseg->pls_layout->plh_flags);
- }
- rpc_wake_up(&NFS_SERVER(ino)->roc_rpcwaitq);
- list_add(&lseg->pls_list, tmp_list);
- return 1;
+ put_lseg_common(lseg);
+ list_add(&lseg->pls_list, &free_me);
+ spin_unlock(&inode->i_lock);
+ pnfs_free_lseg_list(&free_me);
}
- return 0;
}
static bool
@@ -281,7 +278,13 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
* list. It will now be removed when all
* outstanding io is finished.
*/
- rv = put_lseg_locked(lseg, tmp_list);
+ dprintk("%s: lseg %p ref %d\n", __func__, lseg,
+ atomic_read(&lseg->pls_refcount));
+ if (atomic_dec_and_test(&lseg->pls_refcount)) {
+ put_lseg_common(lseg);
+ list_add(&lseg->pls_list, tmp_list);
+ rv = 1;
+ }
}
return rv;
}
@@ -299,6 +302,11 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
dprintk("%s:Begin lo %p\n", __func__, lo);
+ if (list_empty(&lo->plh_segs)) {
+ if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags))
+ put_layout_hdr_locked(lo);
+ return 0;
+ }
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
if (should_free_lseg(lseg->pls_range.iomode, iomode)) {
dprintk("%s: freeing lseg %p iomode %d "
@@ -312,11 +320,27 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
return invalid - removed;
}
+/* note free_me must contain lsegs from a single layout_hdr */
void
pnfs_free_lseg_list(struct list_head *free_me)
{
struct pnfs_layout_segment *lseg, *tmp;
+ struct pnfs_layout_hdr *lo;
+
+ if (list_empty(free_me))
+ return;
+ lo = list_first_entry(free_me, struct pnfs_layout_segment,
+ pls_list)->pls_layout;
+
+ if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) {
+ struct nfs_client *clp;
+
+ clp = NFS_SERVER(lo->plh_inode)->nfs_client;
+ spin_lock(&clp->cl_lock);
+ list_del_init(&lo->plh_layouts);
+ spin_unlock(&clp->cl_lock);
+ }
list_for_each_entry_safe(lseg, tmp, free_me, pls_list) {
list_del(&lseg->pls_list);
free_lseg(lseg);
@@ -332,10 +356,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
spin_lock(&nfsi->vfs_inode.i_lock);
lo = nfsi->layout;
if (lo) {
- set_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags);
+ lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY);
- /* Matched by refcount set to 1 in alloc_init_layout_hdr */
- put_layout_hdr_locked(lo);
}
spin_unlock(&nfsi->vfs_inode.i_lock);
pnfs_free_lseg_list(&tmp_list);
@@ -403,6 +425,7 @@ pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid,
(int)(lo->plh_barrier - be32_to_cpu(stateid->stateid.seqid)) >= 0)
return true;
return lo->plh_block_lgets ||
+ test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) ||
test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
(list_empty(&lo->plh_segs) &&
(atomic_read(&lo->plh_outstanding) > lget));
@@ -674,7 +697,7 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode)
list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
is_matching_lseg(lseg, iomode)) {
- ret = lseg;
+ ret = get_lseg(lseg);
break;
}
if (cmp_layout(iomode, lseg->pls_range.iomode) > 0)
@@ -699,6 +722,7 @@ pnfs_update_layout(struct inode *ino,
struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
struct pnfs_layout_hdr *lo;
struct pnfs_layout_segment *lseg = NULL;
+ bool first = false;
if (!pnfs_enabled_sb(NFS_SERVER(ino)))
return NULL;
@@ -715,21 +739,25 @@ pnfs_update_layout(struct inode *ino,
dprintk("%s matches recall, use MDS\n", __func__);
goto out_unlock;
}
- /* Check to see if the layout for the given range already exists */
- lseg = pnfs_find_lseg(lo, iomode);
- if (lseg)
- goto out_unlock;
/* if LAYOUTGET already failed once we don't try again */
if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags))
goto out_unlock;
+ /* Check to see if the layout for the given range already exists */
+ lseg = pnfs_find_lseg(lo, iomode);
+ if (lseg)
+ goto out_unlock;
+
if (pnfs_layoutgets_blocked(lo, NULL, 0))
goto out_unlock;
atomic_inc(&lo->plh_outstanding);
get_layout_hdr(lo);
- if (list_empty(&lo->plh_segs)) {
+ if (list_empty(&lo->plh_segs))
+ first = true;
+ spin_unlock(&ino->i_lock);
+ if (first) {
/* The lo must be on the clp list if there is any
* chance of a CB_LAYOUTRECALL(FILE) coming in.
*/
@@ -738,24 +766,18 @@ pnfs_update_layout(struct inode *ino,
list_add_tail(&lo->plh_layouts, &clp->cl_layouts);
spin_unlock(&clp->cl_lock);
}
- spin_unlock(&ino->i_lock);
lseg = send_layoutget(lo, ctx, iomode);
- if (!lseg) {
- spin_lock(&ino->i_lock);
- if (list_empty(&lo->plh_segs)) {
- spin_lock(&clp->cl_lock);
- list_del_init(&lo->plh_layouts);
- spin_unlock(&clp->cl_lock);
- clear_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
- }
- spin_unlock(&ino->i_lock);
+ if (!lseg && first) {
+ spin_lock(&clp->cl_lock);
+ list_del_init(&lo->plh_layouts);
+ spin_unlock(&clp->cl_lock);
}
atomic_dec(&lo->plh_outstanding);
put_layout_hdr(lo);
out:
dprintk("%s end, state 0x%lx lseg %p\n", __func__,
- nfsi->layout->plh_flags, lseg);
+ nfsi->layout ? nfsi->layout->plh_flags : -1, lseg);
return lseg;
out_unlock:
spin_unlock(&ino->i_lock);
@@ -808,7 +830,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
}
init_lseg(lo, lseg);
lseg->pls_range = res->range;
- *lgp->lsegpp = lseg;
+ *lgp->lsegpp = get_lseg(lseg);
pnfs_insert_layout(lo, lseg);
if (res->return_on_close) {
@@ -829,137 +851,97 @@ out_forget_reply:
goto out;
}
-/*
- * Device ID cache. Currently supports one layout type per struct nfs_client.
- * Add layout type to the lookup key to expand to support multiple types.
- */
-int
-pnfs_alloc_init_deviceid_cache(struct nfs_client *clp,
- void (*free_callback)(struct pnfs_deviceid_node *))
+static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *prev,
+ struct nfs_page *req)
{
- struct pnfs_deviceid_cache *c;
-
- c = kzalloc(sizeof(struct pnfs_deviceid_cache), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
- spin_lock(&clp->cl_lock);
- if (clp->cl_devid_cache != NULL) {
- atomic_inc(&clp->cl_devid_cache->dc_ref);
- dprintk("%s [kref [%d]]\n", __func__,
- atomic_read(&clp->cl_devid_cache->dc_ref));
- kfree(c);
- } else {
- /* kzalloc initializes hlists */
- spin_lock_init(&c->dc_lock);
- atomic_set(&c->dc_ref, 1);
- c->dc_free_callback = free_callback;
- clp->cl_devid_cache = c;
- dprintk("%s [new]\n", __func__);
+ if (pgio->pg_count == prev->wb_bytes) {
+ /* This is first coelesce call for a series of nfs_pages */
+ pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+ prev->wb_context,
+ IOMODE_READ);
}
- spin_unlock(&clp->cl_lock);
- return 0;
+ return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
}
-EXPORT_SYMBOL_GPL(pnfs_alloc_init_deviceid_cache);
-/*
- * Called from pnfs_layoutdriver_type->free_lseg
- * last layout segment reference frees deviceid
- */
void
-pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
- struct pnfs_deviceid_node *devid)
+pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
{
- struct nfs4_deviceid *id = &devid->de_id;
- struct pnfs_deviceid_node *d;
- struct hlist_node *n;
- long h = nfs4_deviceid_hash(id);
+ struct pnfs_layoutdriver_type *ld;
- dprintk("%s [%d]\n", __func__, atomic_read(&devid->de_ref));
- if (!atomic_dec_and_lock(&devid->de_ref, &c->dc_lock))
- return;
+ ld = NFS_SERVER(inode)->pnfs_curr_ld;
+ pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL;
+}
- hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[h], de_node)
- if (!memcmp(&d->de_id, id, sizeof(*id))) {
- hlist_del_rcu(&d->de_node);
- spin_unlock(&c->dc_lock);
- synchronize_rcu();
- c->dc_free_callback(devid);
- return;
- }
- spin_unlock(&c->dc_lock);
- /* Why wasn't it found in the list? */
- BUG();
-}
-EXPORT_SYMBOL_GPL(pnfs_put_deviceid);
-
-/* Find and reference a deviceid */
-struct pnfs_deviceid_node *
-pnfs_find_get_deviceid(struct pnfs_deviceid_cache *c, struct nfs4_deviceid *id)
-{
- struct pnfs_deviceid_node *d;
- struct hlist_node *n;
- long hash = nfs4_deviceid_hash(id);
-
- dprintk("--> %s hash %ld\n", __func__, hash);
- rcu_read_lock();
- hlist_for_each_entry_rcu(d, n, &c->dc_deviceids[hash], de_node) {
- if (!memcmp(&d->de_id, id, sizeof(*id))) {
- if (!atomic_inc_not_zero(&d->de_ref)) {
- goto fail;
- } else {
- rcu_read_unlock();
- return d;
- }
- }
+static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio,
+ struct nfs_page *prev,
+ struct nfs_page *req)
+{
+ if (pgio->pg_count == prev->wb_bytes) {
+ /* This is first coelesce call for a series of nfs_pages */
+ pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+ prev->wb_context,
+ IOMODE_RW);
}
-fail:
- rcu_read_unlock();
- return NULL;
+ return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
+}
+
+void
+pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode)
+{
+ struct pnfs_layoutdriver_type *ld;
+
+ ld = NFS_SERVER(inode)->pnfs_curr_ld;
+ pgio->pg_test = (ld && ld->pg_test) ? pnfs_write_pg_test : NULL;
+}
+
+enum pnfs_try_status
+pnfs_try_to_write_data(struct nfs_write_data *wdata,
+ const struct rpc_call_ops *call_ops, int how)
+{
+ struct inode *inode = wdata->inode;
+ enum pnfs_try_status trypnfs;
+ struct nfs_server *nfss = NFS_SERVER(inode);
+
+ wdata->mds_ops = call_ops;
+
+ dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__,
+ inode->i_ino, wdata->args.count, wdata->args.offset, how);
+
+ trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how);
+ if (trypnfs == PNFS_NOT_ATTEMPTED) {
+ put_lseg(wdata->lseg);
+ wdata->lseg = NULL;
+ } else
+ nfs_inc_stats(inode, NFSIOS_PNFS_WRITE);
+
+ dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
+ return trypnfs;
}
-EXPORT_SYMBOL_GPL(pnfs_find_get_deviceid);
/*
- * Add a deviceid to the cache.
- * GETDEVICEINFOs for same deviceid can race. If deviceid is found, discard new
+ * Call the appropriate parallel I/O subsystem read function.
*/
-struct pnfs_deviceid_node *
-pnfs_add_deviceid(struct pnfs_deviceid_cache *c, struct pnfs_deviceid_node *new)
-{
- struct pnfs_deviceid_node *d;
- long hash = nfs4_deviceid_hash(&new->de_id);
-
- dprintk("--> %s hash %ld\n", __func__, hash);
- spin_lock(&c->dc_lock);
- d = pnfs_find_get_deviceid(c, &new->de_id);
- if (d) {
- spin_unlock(&c->dc_lock);
- dprintk("%s [discard]\n", __func__);
- c->dc_free_callback(new);
- return d;
- }
- INIT_HLIST_NODE(&new->de_node);
- atomic_set(&new->de_ref, 1);
- hlist_add_head_rcu(&new->de_node, &c->dc_deviceids[hash]);
- spin_unlock(&c->dc_lock);
- dprintk("%s [new]\n", __func__);
- return new;
-}
-EXPORT_SYMBOL_GPL(pnfs_add_deviceid);
-
-void
-pnfs_put_deviceid_cache(struct nfs_client *clp)
+enum pnfs_try_status
+pnfs_try_to_read_data(struct nfs_read_data *rdata,
+ const struct rpc_call_ops *call_ops)
{
- struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
+ struct inode *inode = rdata->inode;
+ struct nfs_server *nfss = NFS_SERVER(inode);
+ enum pnfs_try_status trypnfs;
- dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref));
- if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
- int i;
- /* Verify cache is empty */
- for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i++)
- BUG_ON(!hlist_empty(&local->dc_deviceids[i]));
- clp->cl_devid_cache = NULL;
- spin_unlock(&clp->cl_lock);
- kfree(local);
+ rdata->mds_ops = call_ops;
+
+ dprintk("%s: Reading ino:%lu %u@%llu\n",
+ __func__, inode->i_ino, rdata->args.count, rdata->args.offset);
+
+ trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata);
+ if (trypnfs == PNFS_NOT_ATTEMPTED) {
+ put_lseg(rdata->lseg);
+ rdata->lseg = NULL;
+ } else {
+ nfs_inc_stats(inode, NFSIOS_PNFS_READ);
}
+ dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
+ return trypnfs;
}
-EXPORT_SYMBOL_GPL(pnfs_put_deviceid_cache);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index e2612ea0cbed..6380b9405bcd 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -30,6 +30,8 @@
#ifndef FS_NFS_PNFS_H
#define FS_NFS_PNFS_H
+#include <linux/nfs_page.h>
+
enum {
NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */
NFS_LSEG_ROC, /* roc bit received from server */
@@ -43,6 +45,11 @@ struct pnfs_layout_segment {
struct pnfs_layout_hdr *pls_layout;
};
+enum pnfs_try_status {
+ PNFS_ATTEMPTED = 0,
+ PNFS_NOT_ATTEMPTED = 1,
+};
+
#ifdef CONFIG_NFS_V4_1
#define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
@@ -61,10 +68,18 @@ struct pnfs_layoutdriver_type {
const u32 id;
const char *name;
struct module *owner;
- int (*set_layoutdriver) (struct nfs_server *);
- int (*clear_layoutdriver) (struct nfs_server *);
struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr);
void (*free_lseg) (struct pnfs_layout_segment *lseg);
+
+ /* test for nfs page cache coalescing */
+ int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+
+ /*
+ * Return PNFS_ATTEMPTED to indicate the layout code has attempted
+ * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
+ */
+ enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data);
+ enum pnfs_try_status (*write_pagelist) (struct nfs_write_data *nfs_data, int how);
};
struct pnfs_layout_hdr {
@@ -90,52 +105,6 @@ struct pnfs_device {
unsigned int pglen;
};
-/*
- * Device ID RCU cache. A device ID is unique per client ID and layout type.
- */
-#define NFS4_DEVICE_ID_HASH_BITS 5
-#define NFS4_DEVICE_ID_HASH_SIZE (1 << NFS4_DEVICE_ID_HASH_BITS)
-#define NFS4_DEVICE_ID_HASH_MASK (NFS4_DEVICE_ID_HASH_SIZE - 1)
-
-static inline u32
-nfs4_deviceid_hash(struct nfs4_deviceid *id)
-{
- unsigned char *cptr = (unsigned char *)id->data;
- unsigned int nbytes = NFS4_DEVICEID4_SIZE;
- u32 x = 0;
-
- while (nbytes--) {
- x *= 37;
- x += *cptr++;
- }
- return x & NFS4_DEVICE_ID_HASH_MASK;
-}
-
-struct pnfs_deviceid_node {
- struct hlist_node de_node;
- struct nfs4_deviceid de_id;
- atomic_t de_ref;
-};
-
-struct pnfs_deviceid_cache {
- spinlock_t dc_lock;
- atomic_t dc_ref;
- void (*dc_free_callback)(struct pnfs_deviceid_node *);
- struct hlist_head dc_deviceids[NFS4_DEVICE_ID_HASH_SIZE];
-};
-
-extern int pnfs_alloc_init_deviceid_cache(struct nfs_client *,
- void (*free_callback)(struct pnfs_deviceid_node *));
-extern void pnfs_put_deviceid_cache(struct nfs_client *);
-extern struct pnfs_deviceid_node *pnfs_find_get_deviceid(
- struct pnfs_deviceid_cache *,
- struct nfs4_deviceid *);
-extern struct pnfs_deviceid_node *pnfs_add_deviceid(
- struct pnfs_deviceid_cache *,
- struct pnfs_deviceid_node *);
-extern void pnfs_put_deviceid(struct pnfs_deviceid_cache *c,
- struct pnfs_deviceid_node *devid);
-
extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
@@ -146,11 +115,18 @@ extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
/* pnfs.c */
void get_layout_hdr(struct pnfs_layout_hdr *lo);
+void put_lseg(struct pnfs_layout_segment *lseg);
struct pnfs_layout_segment *
pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
enum pnfs_iomode access_type);
void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
void unset_pnfs_layoutdriver(struct nfs_server *);
+enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *,
+ const struct rpc_call_ops *, int);
+enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *,
+ const struct rpc_call_ops *);
+void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
+void pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *);
int pnfs_layout_process(struct nfs4_layoutget *lgp);
void pnfs_free_lseg_list(struct list_head *tmp_list);
void pnfs_destroy_layout(struct nfs_inode *);
@@ -177,6 +153,16 @@ static inline int lo_fail_bit(u32 iomode)
NFS_LAYOUT_RW_FAILED : NFS_LAYOUT_RO_FAILED;
}
+static inline struct pnfs_layout_segment *
+get_lseg(struct pnfs_layout_segment *lseg)
+{
+ if (lseg) {
+ atomic_inc(&lseg->pls_refcount);
+ smp_mb__after_atomic_inc();
+ }
+ return lseg;
+}
+
/* Return true if a layout driver is being used for this mountpoint */
static inline int pnfs_enabled_sb(struct nfs_server *nfss)
{
@@ -194,12 +180,36 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
}
static inline struct pnfs_layout_segment *
+get_lseg(struct pnfs_layout_segment *lseg)
+{
+ return NULL;
+}
+
+static inline void put_lseg(struct pnfs_layout_segment *lseg)
+{
+}
+
+static inline struct pnfs_layout_segment *
pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
enum pnfs_iomode access_type)
{
return NULL;
}
+static inline enum pnfs_try_status
+pnfs_try_to_read_data(struct nfs_read_data *data,
+ const struct rpc_call_ops *call_ops)
+{
+ return PNFS_NOT_ATTEMPTED;
+}
+
+static inline enum pnfs_try_status
+pnfs_try_to_write_data(struct nfs_write_data *data,
+ const struct rpc_call_ops *call_ops, int how)
+{
+ return PNFS_NOT_ATTEMPTED;
+}
+
static inline bool
pnfs_roc(struct inode *ino)
{
@@ -230,6 +240,18 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
{
}
+static inline void
+pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *ino)
+{
+ pgio->pg_test = NULL;
+}
+
+static inline void
+pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
+{
+ pgio->pg_test = NULL;
+}
+
#endif /* CONFIG_NFS_V4_1 */
#endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 77d5e21c4ad6..b8ec170f2a0f 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -741,4 +741,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.lock = nfs_proc_lock,
.lock_check_bounds = nfs_lock_check_bounds,
.close_context = nfs_close_context,
+ .init_client = nfs_init_client,
};
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index aedcaa7f291f..7cded2b12a05 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -18,19 +18,20 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
+#include <linux/module.h>
#include <asm/system.h>
+#include "pnfs.h"
#include "nfs4_fs.h"
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
-#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
-static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc);
+static int nfs_pagein_one(struct nfs_pageio_descriptor *desc);
static const struct rpc_call_ops nfs_read_partial_ops;
static const struct rpc_call_ops nfs_read_full_ops;
@@ -69,6 +70,7 @@ void nfs_readdata_free(struct nfs_read_data *p)
static void nfs_readdata_release(struct nfs_read_data *rdata)
{
+ put_lseg(rdata->lseg);
put_nfs_open_context(rdata->args.context);
nfs_readdata_free(rdata);
}
@@ -114,14 +116,13 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
struct page *page)
{
- LIST_HEAD(one_request);
struct nfs_page *new;
unsigned int len;
+ struct nfs_pageio_descriptor pgio;
len = nfs_page_length(page);
if (len == 0)
return nfs_return_empty_page(page);
- pnfs_update_layout(inode, ctx, IOMODE_READ);
new = nfs_create_request(ctx, inode, page, 0, len);
if (IS_ERR(new)) {
unlock_page(page);
@@ -130,11 +131,14 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
if (len < PAGE_CACHE_SIZE)
zero_user_segment(page, len, PAGE_CACHE_SIZE);
- nfs_list_add_request(new, &one_request);
+ nfs_pageio_init(&pgio, inode, NULL, 0, 0);
+ nfs_list_add_request(new, &pgio.pg_list);
+ pgio.pg_count = len;
+
if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
- nfs_pagein_multi(inode, &one_request, 1, len, 0);
+ nfs_pagein_multi(&pgio);
else
- nfs_pagein_one(inode, &one_request, 1, len, 0);
+ nfs_pagein_one(&pgio);
return 0;
}
@@ -155,24 +159,20 @@ static void nfs_readpage_release(struct nfs_page *req)
nfs_release_request(req);
}
-/*
- * Set up the NFS read request struct
- */
-static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
- const struct rpc_call_ops *call_ops,
- unsigned int count, unsigned int offset)
+int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
+ const struct rpc_call_ops *call_ops)
{
- struct inode *inode = req->wb_context->path.dentry->d_inode;
+ struct inode *inode = data->inode;
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
struct rpc_task *task;
struct rpc_message msg = {
.rpc_argp = &data->args,
.rpc_resp = &data->res,
- .rpc_cred = req->wb_context->cred,
+ .rpc_cred = data->cred,
};
struct rpc_task_setup task_setup_data = {
.task = &data->task,
- .rpc_client = NFS_CLIENT(inode),
+ .rpc_client = clnt,
.rpc_message = &msg,
.callback_ops = call_ops,
.callback_data = data,
@@ -180,9 +180,39 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
.flags = RPC_TASK_ASYNC | swap_flags,
};
+ /* Set up the initial task struct. */
+ NFS_PROTO(inode)->read_setup(data, &msg);
+
+ dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ "
+ "offset %llu)\n",
+ data->task.tk_pid,
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode),
+ data->args.count,
+ (unsigned long long)data->args.offset);
+
+ task = rpc_run_task(&task_setup_data);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ rpc_put_task(task);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nfs_initiate_read);
+
+/*
+ * Set up the NFS read request struct
+ */
+static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
+ const struct rpc_call_ops *call_ops,
+ unsigned int count, unsigned int offset,
+ struct pnfs_layout_segment *lseg)
+{
+ struct inode *inode = req->wb_context->path.dentry->d_inode;
+
data->req = req;
data->inode = inode;
- data->cred = msg.rpc_cred;
+ data->cred = req->wb_context->cred;
+ data->lseg = get_lseg(lseg);
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset;
@@ -197,21 +227,11 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
data->res.eof = 0;
nfs_fattr_init(&data->fattr);
- /* Set up the initial task struct. */
- NFS_PROTO(inode)->read_setup(data, &msg);
-
- dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
- data->task.tk_pid,
- inode->i_sb->s_id,
- (long long)NFS_FILEID(inode),
- count,
- (unsigned long long)data->args.offset);
+ if (data->lseg &&
+ (pnfs_try_to_read_data(data, call_ops) == PNFS_ATTEMPTED))
+ return 0;
- task = rpc_run_task(&task_setup_data);
- if (IS_ERR(task))
- return PTR_ERR(task);
- rpc_put_task(task);
- return 0;
+ return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops);
}
static void
@@ -240,20 +260,21 @@ nfs_async_read_error(struct list_head *head)
* won't see the new data until our attribute cache is updated. This is more
* or less conventional NFS client behavior.
*/
-static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
+static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc)
{
- struct nfs_page *req = nfs_list_entry(head->next);
+ struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
struct page *page = req->wb_page;
struct nfs_read_data *data;
- size_t rsize = NFS_SERVER(inode)->rsize, nbytes;
+ size_t rsize = NFS_SERVER(desc->pg_inode)->rsize, nbytes;
unsigned int offset;
int requests = 0;
int ret = 0;
+ struct pnfs_layout_segment *lseg;
LIST_HEAD(list);
nfs_list_remove_request(req);
- nbytes = count;
+ nbytes = desc->pg_count;
do {
size_t len = min(nbytes,rsize);
@@ -266,9 +287,11 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
} while(nbytes != 0);
atomic_set(&req->wb_complete, requests);
+ BUG_ON(desc->pg_lseg != NULL);
+ lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ);
ClearPageError(page);
offset = 0;
- nbytes = count;
+ nbytes = desc->pg_count;
do {
int ret2;
@@ -280,12 +303,14 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
if (nbytes < rsize)
rsize = nbytes;
ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
- rsize, offset);
+ rsize, offset, lseg);
if (ret == 0)
ret = ret2;
offset += rsize;
nbytes -= rsize;
} while (nbytes != 0);
+ put_lseg(lseg);
+ desc->pg_lseg = NULL;
return ret;
@@ -300,16 +325,21 @@ out_bad:
return -ENOMEM;
}
-static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
+static int nfs_pagein_one(struct nfs_pageio_descriptor *desc)
{
struct nfs_page *req;
struct page **pages;
struct nfs_read_data *data;
+ struct list_head *head = &desc->pg_list;
+ struct pnfs_layout_segment *lseg = desc->pg_lseg;
int ret = -ENOMEM;
- data = nfs_readdata_alloc(npages);
- if (!data)
- goto out_bad;
+ data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base,
+ desc->pg_count));
+ if (!data) {
+ nfs_async_read_error(head);
+ goto out;
+ }
pages = data->pagevec;
while (!list_empty(head)) {
@@ -320,10 +350,14 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned
*pages++ = req->wb_page;
}
req = nfs_list_entry(data->pages.next);
+ if ((!lseg) && list_is_singular(&data->pages))
+ lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ);
- return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0);
-out_bad:
- nfs_async_read_error(head);
+ ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count,
+ 0, lseg);
+out:
+ put_lseg(lseg);
+ desc->pg_lseg = NULL;
return ret;
}
@@ -366,6 +400,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
return;
/* Yes, so retry the read at the end of the data */
+ data->mds_offset += resp->count;
argp->offset += resp->count;
argp->pgbase += resp->count;
argp->count -= resp->count;
@@ -625,7 +660,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
if (ret == 0)
goto read_complete; /* all pages were read */
- pnfs_update_layout(inode, desc.ctx, IOMODE_READ);
+ pnfs_pageio_init_read(&pgio, inode);
if (rsize < PAGE_CACHE_SIZE)
nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
else
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d3286583009a..2b8e9a5e366a 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1008,6 +1008,27 @@ static int nfs_parse_security_flavors(char *value,
return 1;
}
+static int nfs_get_option_str(substring_t args[], char **option)
+{
+ kfree(*option);
+ *option = match_strdup(args);
+ return !option;
+}
+
+static int nfs_get_option_ul(substring_t args[], unsigned long *option)
+{
+ int rc;
+ char *string;
+
+ string = match_strdup(args);
+ if (string == NULL)
+ return -ENOMEM;
+ rc = strict_strtoul(string, 10, option);
+ kfree(string);
+
+ return rc;
+}
+
/*
* Error-check and convert a string of mount options from user space into
* a data structure. The whole mount string is processed; bad options are
@@ -1156,155 +1177,82 @@ static int nfs_parse_mount_options(char *raw,
* options that take numeric values
*/
case Opt_port:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0 || option > USHRT_MAX)
+ if (nfs_get_option_ul(args, &option) ||
+ option > USHRT_MAX)
goto out_invalid_value;
mnt->nfs_server.port = option;
break;
case Opt_rsize:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->rsize = option;
break;
case Opt_wsize:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->wsize = option;
break;
case Opt_bsize:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->bsize = option;
break;
case Opt_timeo:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0 || option == 0)
+ if (nfs_get_option_ul(args, &option) || option == 0)
goto out_invalid_value;
mnt->timeo = option;
break;
case Opt_retrans:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0 || option == 0)
+ if (nfs_get_option_ul(args, &option) || option == 0)
goto out_invalid_value;
mnt->retrans = option;
break;
case Opt_acregmin:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->acregmin = option;
break;
case Opt_acregmax:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->acregmax = option;
break;
case Opt_acdirmin:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->acdirmin = option;
break;
case Opt_acdirmax:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->acdirmax = option;
break;
case Opt_actimeo:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->acregmin = mnt->acregmax =
mnt->acdirmin = mnt->acdirmax = option;
break;
case Opt_namelen:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
mnt->namlen = option;
break;
case Opt_mountport:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0 || option > USHRT_MAX)
+ if (nfs_get_option_ul(args, &option) ||
+ option > USHRT_MAX)
goto out_invalid_value;
mnt->mount_server.port = option;
break;
case Opt_mountvers:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0 ||
+ if (nfs_get_option_ul(args, &option) ||
option < NFS_MNT_VERSION ||
option > NFS_MNT3_VERSION)
goto out_invalid_value;
mnt->mount_server.version = option;
break;
case Opt_nfsvers:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
switch (option) {
case NFS2_VERSION:
@@ -1324,12 +1272,7 @@ static int nfs_parse_mount_options(char *raw,
}
break;
case Opt_minorversion:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = strict_strtoul(string, 10, &option);
- kfree(string);
- if (rc != 0)
+ if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
if (option > NFS4_MAX_MINOR_VERSION)
goto out_invalid_value;
@@ -1365,21 +1308,18 @@ static int nfs_parse_mount_options(char *raw,
case Opt_xprt_udp:
mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- kfree(string);
break;
case Opt_xprt_tcp6:
protofamily = AF_INET6;
case Opt_xprt_tcp:
mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- kfree(string);
break;
case Opt_xprt_rdma:
/* vector side protocols to TCP */
mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string);
- kfree(string);
break;
default:
dfprintk(MOUNT, "NFS: unrecognized "
@@ -1387,6 +1327,7 @@ static int nfs_parse_mount_options(char *raw,
kfree(string);
return 0;
}
+ kfree(string);
break;
case Opt_mountproto:
string = match_strdup(args);
@@ -1429,18 +1370,13 @@ static int nfs_parse_mount_options(char *raw,
goto out_invalid_address;
break;
case Opt_clientaddr:
- string = match_strdup(args);
- if (string == NULL)
+ if (nfs_get_option_str(args, &mnt->client_address))
goto out_nomem;
- kfree(mnt->client_address);
- mnt->client_address = string;
break;
case Opt_mounthost:
- string = match_strdup(args);
- if (string == NULL)
+ if (nfs_get_option_str(args,
+ &mnt->mount_server.hostname))
goto out_nomem;
- kfree(mnt->mount_server.hostname);
- mnt->mount_server.hostname = string;
break;
case Opt_mountaddr:
string = match_strdup(args);
@@ -1480,11 +1416,8 @@ static int nfs_parse_mount_options(char *raw,
};
break;
case Opt_fscache_uniq:
- string = match_strdup(args);
- if (string == NULL)
+ if (nfs_get_option_str(args, &mnt->fscache_uniq))
goto out_nomem;
- kfree(mnt->fscache_uniq);
- mnt->fscache_uniq = string;
mnt->options |= NFS_OPTION_FSCACHE;
break;
case Opt_local_lock:
@@ -1694,99 +1627,59 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
return nfs_walk_authlist(args, &request);
}
-static int nfs_parse_simple_hostname(const char *dev_name,
- char **hostname, size_t maxnamlen,
- char **export_path, size_t maxpathlen)
+/*
+ * Split "dev_name" into "hostname:export_path".
+ *
+ * The leftmost colon demarks the split between the server's hostname
+ * and the export path. If the hostname starts with a left square
+ * bracket, then it may contain colons.
+ *
+ * Note: caller frees hostname and export path, even on error.
+ */
+static int nfs_parse_devname(const char *dev_name,
+ char **hostname, size_t maxnamlen,
+ char **export_path, size_t maxpathlen)
{
size_t len;
- char *colon, *comma;
+ char *end;
- colon = strchr(dev_name, ':');
- if (colon == NULL)
- goto out_bad_devname;
-
- len = colon - dev_name;
- if (len > maxnamlen)
- goto out_hostname;
-
- /* N.B. caller will free nfs_server.hostname in all cases */
- *hostname = kstrndup(dev_name, len, GFP_KERNEL);
- if (!*hostname)
- goto out_nomem;
-
- /* kill possible hostname list: not supported */
- comma = strchr(*hostname, ',');
- if (comma != NULL) {
- if (comma == *hostname)
+ /* Is the host name protected with square brakcets? */
+ if (*dev_name == '[') {
+ end = strchr(++dev_name, ']');
+ if (end == NULL || end[1] != ':')
goto out_bad_devname;
- *comma = '\0';
- }
-
- colon++;
- len = strlen(colon);
- if (len > maxpathlen)
- goto out_path;
- *export_path = kstrndup(colon, len, GFP_KERNEL);
- if (!*export_path)
- goto out_nomem;
-
- dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
- return 0;
-
-out_bad_devname:
- dfprintk(MOUNT, "NFS: device name not in host:path format\n");
- return -EINVAL;
-out_nomem:
- dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
- return -ENOMEM;
-
-out_hostname:
- dfprintk(MOUNT, "NFS: server hostname too long\n");
- return -ENAMETOOLONG;
-
-out_path:
- dfprintk(MOUNT, "NFS: export pathname too long\n");
- return -ENAMETOOLONG;
-}
-
-/*
- * Hostname has square brackets around it because it contains one or
- * more colons. We look for the first closing square bracket, and a
- * colon must follow it.
- */
-static int nfs_parse_protected_hostname(const char *dev_name,
- char **hostname, size_t maxnamlen,
- char **export_path, size_t maxpathlen)
-{
- size_t len;
- char *start, *end;
+ len = end - dev_name;
+ end++;
+ } else {
+ char *comma;
- start = (char *)(dev_name + 1);
+ end = strchr(dev_name, ':');
+ if (end == NULL)
+ goto out_bad_devname;
+ len = end - dev_name;
- end = strchr(start, ']');
- if (end == NULL)
- goto out_bad_devname;
- if (*(end + 1) != ':')
- goto out_bad_devname;
+ /* kill possible hostname list: not supported */
+ comma = strchr(dev_name, ',');
+ if (comma != NULL && comma < end)
+ *comma = 0;
+ }
- len = end - start;
if (len > maxnamlen)
goto out_hostname;
/* N.B. caller will free nfs_server.hostname in all cases */
- *hostname = kstrndup(start, len, GFP_KERNEL);
+ *hostname = kstrndup(dev_name, len, GFP_KERNEL);
if (*hostname == NULL)
goto out_nomem;
-
- end += 2;
- len = strlen(end);
+ len = strlen(++end);
if (len > maxpathlen)
goto out_path;
*export_path = kstrndup(end, len, GFP_KERNEL);
if (!*export_path)
goto out_nomem;
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
return 0;
out_bad_devname:
@@ -1807,29 +1700,6 @@ out_path:
}
/*
- * Split "dev_name" into "hostname:export_path".
- *
- * The leftmost colon demarks the split between the server's hostname
- * and the export path. If the hostname starts with a left square
- * bracket, then it may contain colons.
- *
- * Note: caller frees hostname and export path, even on error.
- */
-static int nfs_parse_devname(const char *dev_name,
- char **hostname, size_t maxnamlen,
- char **export_path, size_t maxpathlen)
-{
- if (*dev_name == '[')
- return nfs_parse_protected_hostname(dev_name,
- hostname, maxnamlen,
- export_path, maxpathlen);
-
- return nfs_parse_simple_hostname(dev_name,
- hostname, maxnamlen,
- export_path, maxpathlen);
-}
-
-/*
* Validate the NFS2/NFS3 mount data
* - fills in the mount root filehandle
*
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 42b92d7a9cc4..47a3ad63e0d5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -28,6 +28,7 @@
#include "iostat.h"
#include "nfs4_fs.h"
#include "fscache.h"
+#include "pnfs.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
@@ -96,6 +97,7 @@ void nfs_writedata_free(struct nfs_write_data *p)
static void nfs_writedata_release(struct nfs_write_data *wdata)
{
+ put_lseg(wdata->lseg);
put_nfs_open_context(wdata->args.context);
nfs_writedata_free(wdata);
}
@@ -781,25 +783,21 @@ static int flush_task_priority(int how)
return RPC_PRIORITY_NORMAL;
}
-/*
- * Set up the argument/result storage required for the RPC call.
- */
-static int nfs_write_rpcsetup(struct nfs_page *req,
- struct nfs_write_data *data,
- const struct rpc_call_ops *call_ops,
- unsigned int count, unsigned int offset,
- int how)
+int nfs_initiate_write(struct nfs_write_data *data,
+ struct rpc_clnt *clnt,
+ const struct rpc_call_ops *call_ops,
+ int how)
{
- struct inode *inode = req->wb_context->path.dentry->d_inode;
+ struct inode *inode = data->inode;
int priority = flush_task_priority(how);
struct rpc_task *task;
struct rpc_message msg = {
.rpc_argp = &data->args,
.rpc_resp = &data->res,
- .rpc_cred = req->wb_context->cred,
+ .rpc_cred = data->cred,
};
struct rpc_task_setup task_setup_data = {
- .rpc_client = NFS_CLIENT(inode),
+ .rpc_client = clnt,
.task = &data->task,
.rpc_message = &msg,
.callback_ops = call_ops,
@@ -810,12 +808,52 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
};
int ret = 0;
+ /* Set up the initial task struct. */
+ NFS_PROTO(inode)->write_setup(data, &msg);
+
+ dprintk("NFS: %5u initiated write call "
+ "(req %s/%lld, %u bytes @ offset %llu)\n",
+ data->task.tk_pid,
+ inode->i_sb->s_id,
+ (long long)NFS_FILEID(inode),
+ data->args.count,
+ (unsigned long long)data->args.offset);
+
+ task = rpc_run_task(&task_setup_data);
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ goto out;
+ }
+ if (how & FLUSH_SYNC) {
+ ret = rpc_wait_for_completion_task(task);
+ if (ret == 0)
+ ret = task->tk_status;
+ }
+ rpc_put_task(task);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nfs_initiate_write);
+
+/*
+ * Set up the argument/result storage required for the RPC call.
+ */
+static int nfs_write_rpcsetup(struct nfs_page *req,
+ struct nfs_write_data *data,
+ const struct rpc_call_ops *call_ops,
+ unsigned int count, unsigned int offset,
+ struct pnfs_layout_segment *lseg,
+ int how)
+{
+ struct inode *inode = req->wb_context->path.dentry->d_inode;
+
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
data->req = req;
data->inode = inode = req->wb_context->path.dentry->d_inode;
- data->cred = msg.rpc_cred;
+ data->cred = req->wb_context->cred;
+ data->lseg = get_lseg(lseg);
data->args.fh = NFS_FH(inode);
data->args.offset = req_offset(req) + offset;
@@ -836,30 +874,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
data->res.verf = &data->verf;
nfs_fattr_init(&data->fattr);
- /* Set up the initial task struct. */
- NFS_PROTO(inode)->write_setup(data, &msg);
-
- dprintk("NFS: %5u initiated write call "
- "(req %s/%lld, %u bytes @ offset %llu)\n",
- data->task.tk_pid,
- inode->i_sb->s_id,
- (long long)NFS_FILEID(inode),
- count,
- (unsigned long long)data->args.offset);
+ if (data->lseg &&
+ (pnfs_try_to_write_data(data, call_ops, how) == PNFS_ATTEMPTED))
+ return 0;
- task = rpc_run_task(&task_setup_data);
- if (IS_ERR(task)) {
- ret = PTR_ERR(task);
- goto out;
- }
- if (how & FLUSH_SYNC) {
- ret = rpc_wait_for_completion_task(task);
- if (ret == 0)
- ret = task->tk_status;
- }
- rpc_put_task(task);
-out:
- return ret;
+ return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how);
}
/* If a nfs_flush_* function fails, it should remove reqs from @head and
@@ -879,20 +898,21 @@ static void nfs_redirty_request(struct nfs_page *req)
* Generate multiple small requests to write out a single
* contiguous dirty area on one page.
*/
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
+static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
{
- struct nfs_page *req = nfs_list_entry(head->next);
+ struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
struct page *page = req->wb_page;
struct nfs_write_data *data;
- size_t wsize = NFS_SERVER(inode)->wsize, nbytes;
+ size_t wsize = NFS_SERVER(desc->pg_inode)->wsize, nbytes;
unsigned int offset;
int requests = 0;
int ret = 0;
+ struct pnfs_layout_segment *lseg;
LIST_HEAD(list);
nfs_list_remove_request(req);
- nbytes = count;
+ nbytes = desc->pg_count;
do {
size_t len = min(nbytes, wsize);
@@ -905,9 +925,11 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
} while (nbytes != 0);
atomic_set(&req->wb_complete, requests);
+ BUG_ON(desc->pg_lseg);
+ lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW);
ClearPageError(page);
offset = 0;
- nbytes = count;
+ nbytes = desc->pg_count;
do {
int ret2;
@@ -919,13 +941,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
if (nbytes < wsize)
wsize = nbytes;
ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
- wsize, offset, how);
+ wsize, offset, lseg, desc->pg_ioflags);
if (ret == 0)
ret = ret2;
offset += wsize;
nbytes -= wsize;
} while (nbytes != 0);
+ put_lseg(lseg);
+ desc->pg_lseg = NULL;
return ret;
out_bad:
@@ -946,16 +970,26 @@ out_bad:
* This is the case if nfs_updatepage detects a conflicting request
* that has been written but not committed.
*/
-static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
+static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
{
struct nfs_page *req;
struct page **pages;
struct nfs_write_data *data;
+ struct list_head *head = &desc->pg_list;
+ struct pnfs_layout_segment *lseg = desc->pg_lseg;
+ int ret;
- data = nfs_writedata_alloc(npages);
- if (!data)
- goto out_bad;
-
+ data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base,
+ desc->pg_count));
+ if (!data) {
+ while (!list_empty(head)) {
+ req = nfs_list_entry(head->next);
+ nfs_list_remove_request(req);
+ nfs_redirty_request(req);
+ }
+ ret = -ENOMEM;
+ goto out;
+ }
pages = data->pagevec;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
@@ -965,16 +999,15 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
*pages++ = req->wb_page;
}
req = nfs_list_entry(data->pages.next);
+ if ((!lseg) && list_is_singular(&data->pages))
+ lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW);
/* Set up the argument struct */
- return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how);
- out_bad:
- while (!list_empty(head)) {
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_redirty_request(req);
- }
- return -ENOMEM;
+ ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags);
+out:
+ put_lseg(lseg); /* Cleans any gotten in ->pg_test */
+ desc->pg_lseg = NULL;
+ return ret;
}
static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
@@ -982,6 +1015,8 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
{
size_t wsize = NFS_SERVER(inode)->wsize;
+ pnfs_pageio_init_write(pgio, inode);
+
if (wsize < PAGE_CACHE_SIZE)
nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
else
@@ -1132,7 +1167,7 @@ static const struct rpc_call_ops nfs_write_full_ops = {
/*
* This function is called when the WRITE call is complete.
*/
-int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
+void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct nfs_writeargs *argp = &data->args;
struct nfs_writeres *resp = &data->res;
@@ -1151,7 +1186,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
*/
status = NFS_PROTO(data->inode)->write_done(task, data);
if (status != 0)
- return status;
+ return;
nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count);
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
@@ -1166,6 +1201,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
*/
static unsigned long complain;
+ /* Note this will print the MDS for a DS write */
if (time_before(complain, jiffies)) {
dprintk("NFS: faulty NFS server %s:"
" (committed = %d) != (stable = %d)\n",
@@ -1186,6 +1222,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
/* Was this an NFSv2 write or an NFSv3 stable write? */
if (resp->verf->committed != NFS_UNSTABLE) {
/* Resend from where the server left off */
+ data->mds_offset += resp->count;
argp->offset += resp->count;
argp->pgbase += resp->count;
argp->count -= resp->count;
@@ -1196,7 +1233,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
argp->stable = NFS_FILE_SYNC;
}
nfs_restart_rpc(task, server->nfs_client);
- return -EAGAIN;
+ return;
}
if (time_before(complain, jiffies)) {
printk(KERN_WARNING
@@ -1207,7 +1244,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
/* Can't do anything about it except throw an error. */
task->tk_status = -EIO;
}
- return 0;
+ return;
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index da1d9701f8e4..ff93025ae2f7 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -87,7 +87,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
.dentry = dget(dentry)};
int err = 0;
- err = follow_down(&path, false);
+ err = follow_down(&path);
if (err < 0)
goto out;
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 8b61220cffc5..6b1305dc26c0 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -876,7 +876,7 @@ SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark);
#endif
/*
- * fanotify_user_setup - Our initialization function. Note that we cannnot return
+ * fanotify_user_setup - Our initialization function. Note that we cannot return
* error because we have compiled-in VFS hooks. So an (unlikely) failure here
* must result in panic().
*/
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 4cd5d5d78f9f..bd46e7c8a0ef 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -841,7 +841,7 @@ out:
}
/*
- * inotify_user_setup - Our initialization function. Note that we cannnot return
+ * inotify_user_setup - Our initialization function. Note that we cannot return
* error because we have compiled-in VFS hooks. So an (unlikely) failure here
* must result in panic().
*/
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index d417b3f9b0c7..f97b6f1c61dd 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -354,7 +354,7 @@ static inline int ocfs2_match(int len,
/*
* Returns 0 if not found, -1 on failure, and 1 on success
*/
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
+static inline int ocfs2_search_dirblock(struct buffer_head *bh,
struct inode *dir,
const char *name, int namelen,
unsigned long offset,
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index 393f3f659da7..de4ff29f1e05 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -235,33 +235,22 @@ static int omfs_dir_is_empty(struct inode *inode)
return *ptr != ~0;
}
-static int omfs_unlink(struct inode *dir, struct dentry *dentry)
+static int omfs_remove(struct inode *dir, struct dentry *dentry)
{
- int ret;
struct inode *inode = dentry->d_inode;
+ int ret;
+
+ if (S_ISDIR(inode->i_mode) && !omfs_dir_is_empty(inode))
+ return -ENOTEMPTY;
ret = omfs_delete_entry(dentry);
if (ret)
- goto end_unlink;
-
- inode_dec_link_count(inode);
+ return ret;
+
+ clear_nlink(inode);
+ mark_inode_dirty(inode);
mark_inode_dirty(dir);
-
-end_unlink:
- return ret;
-}
-
-static int omfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
- int err = -ENOTEMPTY;
- struct inode *inode = dentry->d_inode;
-
- if (omfs_dir_is_empty(inode)) {
- err = omfs_unlink(dir, dentry);
- if (!err)
- inode_dec_link_count(inode);
- }
- return err;
+ return 0;
}
static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode)
@@ -372,9 +361,10 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir,
res = filldir(dirent, oi->i_name, strnlen(oi->i_name,
OMFS_NAMELEN), filp->f_pos, self, d_type);
- if (res == 0)
- filp->f_pos++;
brelse(bh);
+ if (res < 0)
+ break;
+ filp->f_pos++;
}
out:
return res;
@@ -385,44 +375,28 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
struct inode *new_inode = new_dentry->d_inode;
struct inode *old_inode = old_dentry->d_inode;
- struct buffer_head *bh;
- int is_dir;
int err;
- is_dir = S_ISDIR(old_inode->i_mode);
-
if (new_inode) {
/* overwriting existing file/dir */
- err = -ENOTEMPTY;
- if (is_dir && !omfs_dir_is_empty(new_inode))
- goto out;
-
- err = -ENOENT;
- bh = omfs_find_entry(new_dir, new_dentry->d_name.name,
- new_dentry->d_name.len);
- if (IS_ERR(bh))
- goto out;
- brelse(bh);
-
- err = omfs_unlink(new_dir, new_dentry);
+ err = omfs_remove(new_dir, new_dentry);
if (err)
goto out;
}
/* since omfs locates files by name, we need to unlink _before_
* adding the new link or we won't find the old one */
- inode_inc_link_count(old_inode);
- err = omfs_unlink(old_dir, old_dentry);
- if (err) {
- inode_dec_link_count(old_inode);
+ err = omfs_delete_entry(old_dentry);
+ if (err)
goto out;
- }
+ mark_inode_dirty(old_dir);
err = omfs_add_link(new_dentry, old_inode);
if (err)
goto out;
old_inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(old_inode);
out:
return err;
}
@@ -488,8 +462,8 @@ const struct inode_operations omfs_dir_inops = {
.mkdir = omfs_mkdir,
.rename = omfs_rename,
.create = omfs_create,
- .unlink = omfs_unlink,
- .rmdir = omfs_rmdir,
+ .unlink = omfs_remove,
+ .rmdir = omfs_remove,
};
const struct file_operations omfs_dir_operations = {
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 549d245d0b42..08342232cb1c 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -40,9 +40,29 @@
struct pstore_private {
u64 id;
int (*erase)(u64);
+ ssize_t size;
+ char data[];
};
-#define pstore_get_inode ramfs_get_inode
+static int pstore_file_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct pstore_private *ps = file->private_data;
+
+ return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size);
+}
+
+static const struct file_operations pstore_file_operations = {
+ .open = pstore_file_open,
+ .read = pstore_file_read,
+ .llseek = default_llseek,
+};
/*
* When a file is unlinked from our file system we call the
@@ -63,6 +83,30 @@ static const struct inode_operations pstore_dir_inode_operations = {
.unlink = pstore_unlink,
};
+static struct inode *pstore_get_inode(struct super_block *sb,
+ const struct inode *dir, int mode, dev_t dev)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode) {
+ inode->i_ino = get_next_ino();
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_mode = mode;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_fop = &pstore_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &pstore_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inc_nlink(inode);
+ break;
+ }
+ }
+ return inode;
+}
+
static const struct super_operations pstore_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
@@ -70,37 +114,10 @@ static const struct super_operations pstore_ops = {
};
static struct super_block *pstore_sb;
-static struct vfsmount *pstore_mnt;
int pstore_is_mounted(void)
{
- return pstore_mnt != NULL;
-}
-
-/*
- * Set up a file structure as if we had opened this file and
- * write our data to it.
- */
-static int pstore_writefile(struct inode *inode, struct dentry *dentry,
- char *data, size_t size)
-{
- struct file f;
- ssize_t n;
- mm_segment_t old_fs = get_fs();
-
- memset(&f, '0', sizeof f);
- f.f_mapping = inode->i_mapping;
- f.f_path.dentry = dentry;
- f.f_path.mnt = pstore_mnt;
- f.f_pos = 0;
- f.f_op = inode->i_fop;
- set_fs(KERNEL_DS);
- n = do_sync_write(&f, data, size, &f.f_pos);
- set_fs(old_fs);
-
- fsnotify_modify(&f);
-
- return n == size;
+ return pstore_sb != NULL;
}
/*
@@ -123,8 +140,7 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0);
if (!inode)
goto fail;
- inode->i_uid = inode->i_gid = 0;
- private = kmalloc(sizeof *private, GFP_KERNEL);
+ private = kmalloc(sizeof *private + size, GFP_KERNEL);
if (!private)
goto fail_alloc;
private->id = id;
@@ -152,28 +168,19 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
if (IS_ERR(dentry))
goto fail_lockedalloc;
- d_add(dentry, inode);
-
- mutex_unlock(&root->d_inode->i_mutex);
-
- if (!pstore_writefile(inode, dentry, data, size))
- goto fail_write;
+ memcpy(private->data, data, size);
+ inode->i_size = private->size = size;
inode->i_private = private;
if (time.tv_sec)
inode->i_mtime = inode->i_ctime = time;
- return 0;
+ d_add(dentry, inode);
-fail_write:
- kfree(private);
- inode->i_nlink--;
- mutex_lock(&root->d_inode->i_mutex);
- d_delete(dentry);
- dput(dentry);
mutex_unlock(&root->d_inode->i_mutex);
- goto fail;
+
+ return 0;
fail_lockedalloc:
mutex_unlock(&root->d_inode->i_mutex);
@@ -225,32 +232,21 @@ fail:
return err;
}
-static int pstore_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *pstore_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- struct dentry *root;
-
- root = mount_nodev(fs_type, flags, data, pstore_fill_super);
- if (IS_ERR(root))
- return -ENOMEM;
-
- mnt->mnt_root = root;
- mnt->mnt_sb = root->d_sb;
- pstore_mnt = mnt;
-
- return 0;
+ return mount_single(fs_type, flags, data, pstore_fill_super);
}
static void pstore_kill_sb(struct super_block *sb)
{
kill_litter_super(sb);
pstore_sb = NULL;
- pstore_mnt = NULL;
}
static struct file_system_type pstore_fs_type = {
.name = "pstore",
- .get_sb = pstore_get_sb,
+ .mount = pstore_mount,
.kill_sb = pstore_kill_sb,
};
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index 65444d29406b..f1ab3604db5a 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -112,7 +112,7 @@ static int v2_read_file_info(struct super_block *sb, int type)
if (!info->dqi_priv) {
printk(KERN_WARNING
"Not enough memory for quota information structure.\n");
- return -1;
+ return -ENOMEM;
}
qinfo = info->dqi_priv;
if (version == 0) {
diff --git a/fs/super.c b/fs/super.c
index 4bae0ef6110e..e84864908264 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type,
}
EXPORT_SYMBOL(mount_single);
-struct vfsmount *
-vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
+struct dentry *
+mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
- struct vfsmount *mnt;
struct dentry *root;
+ struct super_block *sb;
char *secdata = NULL;
- int error;
-
- if (!type)
- return ERR_PTR(-ENODEV);
-
- error = -ENOMEM;
- mnt = alloc_vfsmnt(name);
- if (!mnt)
- goto out;
-
- if (flags & MS_KERNMOUNT)
- mnt->mnt_flags = MNT_INTERNAL;
+ int error = -ENOMEM;
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
secdata = alloc_secdata();
if (!secdata)
- goto out_mnt;
+ goto out;
error = security_sb_copy_data(data, secdata);
if (error)
@@ -944,13 +933,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
error = PTR_ERR(root);
goto out_free_secdata;
}
- mnt->mnt_root = root;
- mnt->mnt_sb = root->d_sb;
- BUG_ON(!mnt->mnt_sb);
- WARN_ON(!mnt->mnt_sb->s_bdi);
- mnt->mnt_sb->s_flags |= MS_BORN;
+ sb = root->d_sb;
+ BUG_ON(!sb);
+ WARN_ON(!sb->s_bdi);
+ sb->s_flags |= MS_BORN;
- error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
+ error = security_sb_kern_mount(sb, flags, secdata);
if (error)
goto out_sb;
@@ -961,27 +949,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
* violate this rule. This warning should be either removed or
* converted to a BUG() in 2.6.34.
*/
- WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
- "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);
+ WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
+ "negative value (%lld)\n", type->name, sb->s_maxbytes);
- mnt->mnt_mountpoint = mnt->mnt_root;
- mnt->mnt_parent = mnt;
- up_write(&mnt->mnt_sb->s_umount);
+ up_write(&sb->s_umount);
free_secdata(secdata);
- return mnt;
+ return root;
out_sb:
- dput(mnt->mnt_root);
- deactivate_locked_super(mnt->mnt_sb);
+ dput(root);
+ deactivate_locked_super(sb);
out_free_secdata:
free_secdata(secdata);
-out_mnt:
- free_vfsmnt(mnt);
out:
return ERR_PTR(error);
}
-EXPORT_SYMBOL_GPL(vfs_kern_mount);
-
/**
* freeze_super - lock the filesystem and force it into a consistent state
* @sb: the super to lock
@@ -1071,49 +1053,3 @@ out:
return 0;
}
EXPORT_SYMBOL(thaw_super);
-
-static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
-{
- int err;
- const char *subtype = strchr(fstype, '.');
- if (subtype) {
- subtype++;
- err = -EINVAL;
- if (!subtype[0])
- goto err;
- } else
- subtype = "";
-
- mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
- err = -ENOMEM;
- if (!mnt->mnt_sb->s_subtype)
- goto err;
- return mnt;
-
- err:
- mntput(mnt);
- return ERR_PTR(err);
-}
-
-struct vfsmount *
-do_kern_mount(const char *fstype, int flags, const char *name, void *data)
-{
- struct file_system_type *type = get_fs_type(fstype);
- struct vfsmount *mnt;
- if (!type)
- return ERR_PTR(-ENODEV);
- mnt = vfs_kern_mount(type, flags, name, data);
- if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
- !mnt->mnt_sb->s_subtype)
- mnt = fs_set_subtype(mnt, fstype);
- put_filesystem(type);
- return mnt;
-}
-EXPORT_SYMBOL_GPL(do_kern_mount);
-
-struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
-{
- return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
-}
-
-EXPORT_SYMBOL_GPL(kern_mount_data);
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index 830e3f76f442..1d1859dc3de5 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -44,23 +44,20 @@ config UBIFS_FS_ZLIB
# Debugging-related stuff
config UBIFS_FS_DEBUG
- bool "Enable debugging"
+ bool "Enable debugging support"
depends on UBIFS_FS
select DEBUG_FS
select KALLSYMS_ALL
help
- This option enables UBIFS debugging.
-
-config UBIFS_FS_DEBUG_MSG_LVL
- int "Default message level (0 = no extra messages, 3 = lots)"
- depends on UBIFS_FS_DEBUG
- default "0"
- help
- This controls the amount of debugging messages produced by UBIFS.
- If reporting bugs, please try to have available a full dump of the
- messages at level 1 while the misbehaviour was occurring. Level 2
- may become necessary if level 1 messages were not enough to find the
- bug. Generally Level 3 should be avoided.
+ This option enables UBIFS debugging support. It makes sure various
+ assertions, self-checks, debugging messages and test modes are compiled
+ in (this all is compiled out otherwise). Assertions are light-weight
+ and this option also enables them. Self-checks, debugging messages and
+ test modes are switched off by default. Thus, it is safe and actually
+ recommended to have debugging support enabled, and it should not slow
+ down UBIFS. You can then further enable / disable individual debugging
+ features using UBIFS module parameters and the corresponding sysfs
+ interfaces.
config UBIFS_FS_DEBUG_CHKS
bool "Enable extra checks"
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index 02429d81ca33..b148fbc80f8d 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -48,6 +48,56 @@
#include <linux/slab.h>
#include "ubifs.h"
+/*
+ * nothing_to_commit - check if there is nothing to commit.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which checks if there is anything to commit. It is
+ * used as an optimization to avoid starting the commit if it is not really
+ * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
+ * writing the commit start node to the log), and it is better to avoid doing
+ * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
+ * nothing to commit, it is more optimal to avoid any flash I/O.
+ *
+ * This function has to be called with @c->commit_sem locked for writing -
+ * this function does not take LPT/TNC locks because the @c->commit_sem
+ * guarantees that we have exclusive access to the TNC and LPT data structures.
+ *
+ * This function returns %1 if there is nothing to commit and %0 otherwise.
+ */
+static int nothing_to_commit(struct ubifs_info *c)
+{
+ /*
+ * During mounting or remounting from R/O mode to R/W mode we may
+ * commit for various recovery-related reasons.
+ */
+ if (c->mounting || c->remounting_rw)
+ return 0;
+
+ /*
+ * If the root TNC node is dirty, we definitely have something to
+ * commit.
+ */
+ if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags))
+ return 0;
+
+ /*
+ * Even though the TNC is clean, the LPT tree may have dirty nodes. For
+ * example, this may happen if the budgeting subsystem invoked GC to
+ * make some free space, and the GC found an LEB with only dirty and
+ * free space. In this case GC would just change the lprops of this
+ * LEB (by turning all space into free space) and unmap it.
+ */
+ if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
+ return 0;
+
+ ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
+ ubifs_assert(c->dirty_pn_cnt == 0);
+ ubifs_assert(c->dirty_nn_cnt == 0);
+
+ return 1;
+}
+
/**
* do_commit - commit the journal.
* @c: UBIFS file-system description object
@@ -70,6 +120,12 @@ static int do_commit(struct ubifs_info *c)
goto out_up;
}
+ if (nothing_to_commit(c)) {
+ up_write(&c->commit_sem);
+ err = 0;
+ goto out_cancel;
+ }
+
/* Sync all write buffers (necessary for recovery) */
for (i = 0; i < c->jhead_cnt; i++) {
err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
@@ -162,12 +218,12 @@ static int do_commit(struct ubifs_info *c)
if (err)
goto out;
+out_cancel:
spin_lock(&c->cs_lock);
c->cmt_state = COMMIT_RESTING;
wake_up(&c->cmt_wq);
dbg_cmt("commit end");
spin_unlock(&c->cs_lock);
-
return 0;
out_up:
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 0bee4dbffc31..01c2b028e525 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -43,8 +43,8 @@ DEFINE_SPINLOCK(dbg_lock);
static char dbg_key_buf0[128];
static char dbg_key_buf1[128];
-unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
-unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+unsigned int ubifs_msg_flags;
+unsigned int ubifs_chk_flags;
unsigned int ubifs_tst_flags;
module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
@@ -810,16 +810,24 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
{
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
+ void *buf;
if (dbg_failure_mode)
return;
printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
current->pid, lnum);
- sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+
+ buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
+ return;
+ }
+
+ sleb = ubifs_scan(c, lnum, 0, buf, 0);
if (IS_ERR(sleb)) {
ubifs_err("scan error %d", (int)PTR_ERR(sleb));
- return;
+ goto out;
}
printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
@@ -835,6 +843,9 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
current->pid, lnum);
ubifs_scan_destroy(sleb);
+
+out:
+ vfree(buf);
return;
}
@@ -2690,16 +2701,8 @@ int ubifs_debugging_init(struct ubifs_info *c)
if (!c->dbg)
return -ENOMEM;
- c->dbg->buf = vmalloc(c->leb_size);
- if (!c->dbg->buf)
- goto out;
-
failure_mode_init(c);
return 0;
-
-out:
- kfree(c->dbg);
- return -ENOMEM;
}
/**
@@ -2709,7 +2712,6 @@ out:
void ubifs_debugging_exit(struct ubifs_info *c)
{
failure_mode_exit(c);
- vfree(c->dbg->buf);
kfree(c->dbg);
}
@@ -2813,19 +2815,19 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
}
fname = "dump_lprops";
- dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+ dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dfs_dump_lprops = dent;
fname = "dump_budg";
- dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+ dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dfs_dump_budg = dent;
fname = "dump_tnc";
- dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+ dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
if (IS_ERR(dent))
goto out_remove;
d->dfs_dump_tnc = dent;
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 69ebe4729151..919f0de29d8f 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -27,7 +27,6 @@
/**
* ubifs_debug_info - per-FS debugging information.
- * @buf: a buffer of LEB size, used for various purposes
* @old_zroot: old index root - used by 'dbg_check_old_index()'
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
@@ -54,7 +53,6 @@
* dfs_dump_tnc: "dump TNC" debugfs knob
*/
struct ubifs_debug_info {
- void *buf;
struct ubifs_zbranch old_zroot;
int old_zroot_level;
unsigned long long old_zroot_sqnum;
@@ -173,7 +171,7 @@ const char *dbg_key_str1(const struct ubifs_info *c,
#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
/*
- * Debugging message type flags (must match msg_type_names in debug.c).
+ * Debugging message type flags.
*
* UBIFS_MSG_GEN: general messages
* UBIFS_MSG_JNL: journal messages
@@ -205,14 +203,8 @@ enum {
UBIFS_MSG_RCVRY = 0x1000,
};
-/* Debugging message type flags for each default debug message level */
-#define UBIFS_MSG_LVL_0 0
-#define UBIFS_MSG_LVL_1 0x1
-#define UBIFS_MSG_LVL_2 0x7f
-#define UBIFS_MSG_LVL_3 0xffff
-
/*
- * Debugging check flags (must match chk_names in debug.c).
+ * Debugging check flags.
*
* UBIFS_CHK_GEN: general checks
* UBIFS_CHK_TNC: check TNC
@@ -233,7 +225,7 @@ enum {
};
/*
- * Special testing flags (must match tst_names in debug.c).
+ * Special testing flags.
*
* UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
* UBIFS_TST_RCVRY: failure mode for recovery testing
@@ -243,22 +235,6 @@ enum {
UBIFS_TST_RCVRY = 0x4,
};
-#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
-#else
-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
-#endif
-
-#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
-#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
-#else
-#define UBIFS_CHK_FLAGS_DEFAULT 0
-#endif
-
extern spinlock_t dbg_lock;
extern unsigned int ubifs_msg_flags;
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index d82173182eeb..dfd168b7807e 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -31,6 +31,26 @@
* buffer is full or when it is not used for some time (by timer). This is
* similar to the mechanism is used by JFFS2.
*
+ * UBIFS distinguishes between minimum write size (@c->min_io_size) and maximum
+ * write size (@c->max_write_size). The latter is the maximum amount of bytes
+ * the underlying flash is able to program at a time, and writing in
+ * @c->max_write_size units should presumably be faster. Obviously,
+ * @c->min_io_size <= @c->max_write_size. Write-buffers are of
+ * @c->max_write_size bytes in size for maximum performance. However, when a
+ * write-buffer is flushed, only the portion of it (aligned to @c->min_io_size
+ * boundary) which contains data is written, not the whole write-buffer,
+ * because this is more space-efficient.
+ *
+ * This optimization adds few complications to the code. Indeed, on the one
+ * hand, we want to write in optimal @c->max_write_size bytes chunks, which
+ * also means aligning writes at the @c->max_write_size bytes offsets. On the
+ * other hand, we do not want to waste space when synchronizing the write
+ * buffer, so during synchronization we writes in smaller chunks. And this makes
+ * the next write offset to be not aligned to @c->max_write_size bytes. So the
+ * have to make sure that the write-buffer offset (@wbuf->offs) becomes aligned
+ * to @c->max_write_size bytes again. We do this by temporarily shrinking
+ * write-buffer size (@wbuf->size).
+ *
* Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
* mutexes defined inside these objects. Since sometimes upper-level code
* has to lock the write-buffer (e.g. journal space reservation code), many
@@ -46,8 +66,8 @@
* UBIFS uses padding when it pads to the next min. I/O unit. In this case it
* uses padding nodes or padding bytes, if the padding node does not fit.
*
- * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
- * every time they are read from the flash media.
+ * All UBIFS nodes are protected by CRC checksums and UBIFS checks CRC when
+ * they are read from the flash media.
*/
#include <linux/crc32.h>
@@ -88,8 +108,12 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
* This function may skip data nodes CRC checking if @c->no_chk_data_crc is
* true, which is controlled by corresponding UBIFS mount option. However, if
* @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
- * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
- * ignored and CRC is checked.
+ * checked. Similarly, if @c->mounting or @c->remounting_rw is true (we are
+ * mounting or re-mounting to R/W mode), @c->no_chk_data_crc is ignored and CRC
+ * is checked. This is because during mounting or re-mounting from R/O mode to
+ * R/W mode we may read journal nodes (when replying the journal or doing the
+ * recovery) and the journal nodes may potentially be corrupted, so checking is
+ * required.
*
* This function returns zero in case of success and %-EUCLEAN in case of bad
* CRC or magic.
@@ -131,8 +155,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
node_len > c->ranges[type].max_len)
goto out_len;
- if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
- c->no_chk_data_crc)
+ if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->mounting &&
+ !c->remounting_rw && c->no_chk_data_crc)
return 0;
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
@@ -343,11 +367,17 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
*
* This function synchronizes write-buffer @buf and returns zero in case of
* success or a negative error code in case of failure.
+ *
+ * Note, although write-buffers are of @c->max_write_size, this function does
+ * not necessarily writes all @c->max_write_size bytes to the flash. Instead,
+ * if the write-buffer is only partially filled with data, only the used part
+ * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized.
+ * This way we waste less space.
*/
int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
{
struct ubifs_info *c = wbuf->c;
- int err, dirt;
+ int err, dirt, sync_len;
cancel_wbuf_timer_nolock(wbuf);
if (!wbuf->used || wbuf->lnum == -1)
@@ -357,27 +387,53 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dbg_io("LEB %d:%d, %d bytes, jhead %s",
wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead));
ubifs_assert(!(wbuf->avail & 7));
- ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
+ ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size);
+ ubifs_assert(wbuf->size >= c->min_io_size);
+ ubifs_assert(wbuf->size <= c->max_write_size);
+ ubifs_assert(wbuf->size % c->min_io_size == 0);
ubifs_assert(!c->ro_media && !c->ro_mount);
+ if (c->leb_size - wbuf->offs >= c->max_write_size)
+ ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
if (c->ro_error)
return -EROFS;
- ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
+ /*
+ * Do not write whole write buffer but write only the minimum necessary
+ * amount of min. I/O units.
+ */
+ sync_len = ALIGN(wbuf->used, c->min_io_size);
+ dirt = sync_len - wbuf->used;
+ if (dirt)
+ ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
- c->min_io_size, wbuf->dtype);
+ sync_len, wbuf->dtype);
if (err) {
ubifs_err("cannot write %d bytes to LEB %d:%d",
- c->min_io_size, wbuf->lnum, wbuf->offs);
+ sync_len, wbuf->lnum, wbuf->offs);
dbg_dump_stack();
return err;
}
- dirt = wbuf->avail;
-
spin_lock(&wbuf->lock);
- wbuf->offs += c->min_io_size;
- wbuf->avail = c->min_io_size;
+ wbuf->offs += sync_len;
+ /*
+ * Now @wbuf->offs is not necessarily aligned to @c->max_write_size.
+ * But our goal is to optimize writes and make sure we write in
+ * @c->max_write_size chunks and to @c->max_write_size-aligned offset.
+ * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make
+ * sure that @wbuf->offs + @wbuf->size is aligned to
+ * @c->max_write_size. This way we make sure that after next
+ * write-buffer flush we are again at the optimal offset (aligned to
+ * @c->max_write_size).
+ */
+ if (c->leb_size - wbuf->offs < c->max_write_size)
+ wbuf->size = c->leb_size - wbuf->offs;
+ else if (wbuf->offs & (c->max_write_size - 1))
+ wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
+ else
+ wbuf->size = c->max_write_size;
+ wbuf->avail = wbuf->size;
wbuf->used = 0;
wbuf->next_ino = 0;
spin_unlock(&wbuf->lock);
@@ -420,7 +476,13 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
spin_lock(&wbuf->lock);
wbuf->lnum = lnum;
wbuf->offs = offs;
- wbuf->avail = c->min_io_size;
+ if (c->leb_size - wbuf->offs < c->max_write_size)
+ wbuf->size = c->leb_size - wbuf->offs;
+ else if (wbuf->offs & (c->max_write_size - 1))
+ wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
+ else
+ wbuf->size = c->max_write_size;
+ wbuf->avail = wbuf->size;
wbuf->used = 0;
spin_unlock(&wbuf->lock);
wbuf->dtype = dtype;
@@ -500,8 +562,9 @@ out_timers:
*
* This function writes data to flash via write-buffer @wbuf. This means that
* the last piece of the node won't reach the flash media immediately if it
- * does not take whole minimal I/O unit. Instead, the node will sit in RAM
- * until the write-buffer is synchronized (e.g., by timer).
+ * does not take whole max. write unit (@c->max_write_size). Instead, the node
+ * will sit in RAM until the write-buffer is synchronized (e.g., by timer, or
+ * because more data are appended to the write-buffer).
*
* This function returns zero in case of success and a negative error code in
* case of failure. If the node cannot be written because there is no more
@@ -518,9 +581,14 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
- ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
+ ubifs_assert(wbuf->avail > 0 && wbuf->avail <= wbuf->size);
+ ubifs_assert(wbuf->size >= c->min_io_size);
+ ubifs_assert(wbuf->size <= c->max_write_size);
+ ubifs_assert(wbuf->size % c->min_io_size == 0);
ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
ubifs_assert(!c->ro_media && !c->ro_mount);
+ if (c->leb_size - wbuf->offs >= c->max_write_size)
+ ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
err = -ENOSPC;
@@ -543,14 +611,18 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
- wbuf->offs, c->min_io_size,
+ wbuf->offs, wbuf->size,
wbuf->dtype);
if (err)
goto out;
spin_lock(&wbuf->lock);
- wbuf->offs += c->min_io_size;
- wbuf->avail = c->min_io_size;
+ wbuf->offs += wbuf->size;
+ if (c->leb_size - wbuf->offs >= c->max_write_size)
+ wbuf->size = c->max_write_size;
+ else
+ wbuf->size = c->leb_size - wbuf->offs;
+ wbuf->avail = wbuf->size;
wbuf->used = 0;
wbuf->next_ino = 0;
spin_unlock(&wbuf->lock);
@@ -564,33 +636,57 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
goto exit;
}
- /*
- * The node is large enough and does not fit entirely within current
- * minimal I/O unit. We have to fill and flush write-buffer and switch
- * to the next min. I/O unit.
- */
- dbg_io("flush jhead %s wbuf to LEB %d:%d",
- dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
- memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
- err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
- c->min_io_size, wbuf->dtype);
- if (err)
- goto out;
+ offs = wbuf->offs;
+ written = 0;
- offs = wbuf->offs + c->min_io_size;
- len -= wbuf->avail;
- aligned_len -= wbuf->avail;
- written = wbuf->avail;
+ if (wbuf->used) {
+ /*
+ * The node is large enough and does not fit entirely within
+ * current available space. We have to fill and flush
+ * write-buffer and switch to the next max. write unit.
+ */
+ dbg_io("flush jhead %s wbuf to LEB %d:%d",
+ dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+ memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
+ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+ wbuf->size, wbuf->dtype);
+ if (err)
+ goto out;
+
+ offs += wbuf->size;
+ len -= wbuf->avail;
+ aligned_len -= wbuf->avail;
+ written += wbuf->avail;
+ } else if (wbuf->offs & (c->max_write_size - 1)) {
+ /*
+ * The write-buffer offset is not aligned to
+ * @c->max_write_size and @wbuf->size is less than
+ * @c->max_write_size. Write @wbuf->size bytes to make sure the
+ * following writes are done in optimal @c->max_write_size
+ * chunks.
+ */
+ dbg_io("write %d bytes to LEB %d:%d",
+ wbuf->size, wbuf->lnum, wbuf->offs);
+ err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs,
+ wbuf->size, wbuf->dtype);
+ if (err)
+ goto out;
+
+ offs += wbuf->size;
+ len -= wbuf->size;
+ aligned_len -= wbuf->size;
+ written += wbuf->size;
+ }
/*
- * The remaining data may take more whole min. I/O units, so write the
- * remains multiple to min. I/O unit size directly to the flash media.
+ * The remaining data may take more whole max. write units, so write the
+ * remains multiple to max. write unit size directly to the flash media.
* We align node length to 8-byte boundary because we anyway flash wbuf
* if the remaining space is less than 8 bytes.
*/
- n = aligned_len >> c->min_io_shift;
+ n = aligned_len >> c->max_write_shift;
if (n) {
- n <<= c->min_io_shift;
+ n <<= c->max_write_shift;
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
wbuf->dtype);
@@ -606,14 +702,18 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
if (aligned_len)
/*
* And now we have what's left and what does not take whole
- * min. I/O unit, so write it to the write-buffer and we are
+ * max. write unit, so write it to the write-buffer and we are
* done.
*/
memcpy(wbuf->buf, buf + written, len);
wbuf->offs = offs;
+ if (c->leb_size - wbuf->offs >= c->max_write_size)
+ wbuf->size = c->max_write_size;
+ else
+ wbuf->size = c->leb_size - wbuf->offs;
+ wbuf->avail = wbuf->size - aligned_len;
wbuf->used = aligned_len;
- wbuf->avail = c->min_io_size - aligned_len;
wbuf->next_ino = 0;
spin_unlock(&wbuf->lock);
@@ -837,11 +937,11 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
{
size_t size;
- wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
+ wbuf->buf = kmalloc(c->max_write_size, GFP_KERNEL);
if (!wbuf->buf)
return -ENOMEM;
- size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
+ size = (c->max_write_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
wbuf->inodes = kmalloc(size, GFP_KERNEL);
if (!wbuf->inodes) {
kfree(wbuf->buf);
@@ -851,7 +951,14 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
wbuf->used = 0;
wbuf->lnum = wbuf->offs = -1;
- wbuf->avail = c->min_io_size;
+ /*
+ * If the LEB starts at the max. write size aligned address, then
+ * write-buffer size has to be set to @c->max_write_size. Otherwise,
+ * set it to something smaller so that it ends at the closest max.
+ * write size boundary.
+ */
+ size = c->max_write_size - (c->leb_start % c->max_write_size);
+ wbuf->avail = wbuf->size = size;
wbuf->dtype = UBI_UNKNOWN;
wbuf->sync_callback = NULL;
mutex_init(&wbuf->io_mutex);
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 914f1bd89e57..aed25e864227 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -690,7 +690,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
{
struct ubifs_data_node *data;
int err, lnum, offs, compr_type, out_len;
- int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
+ int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
struct ubifs_inode *ui = ubifs_inode(inode);
dbg_jnl("ino %lu, blk %u, len %d, key %s",
@@ -698,9 +698,19 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
DBGKEY(key));
ubifs_assert(len <= UBIFS_BLOCK_SIZE);
- data = kmalloc(dlen, GFP_NOFS);
- if (!data)
- return -ENOMEM;
+ data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
+ if (!data) {
+ /*
+ * Fall-back to the write reserve buffer. Note, we might be
+ * currently on the memory reclaim path, when the kernel is
+ * trying to free some memory by writing out dirty pages. The
+ * write reserve buffer helps us to guarantee that we are
+ * always able to write the data.
+ */
+ allocated = 0;
+ mutex_lock(&c->write_reserve_mutex);
+ data = c->write_reserve_buf;
+ }
data->ch.node_type = UBIFS_DATA_NODE;
key_write(c, key, &data->key);
@@ -736,7 +746,10 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
goto out_ro;
finish_reservation(c);
- kfree(data);
+ if (!allocated)
+ mutex_unlock(&c->write_reserve_mutex);
+ else
+ kfree(data);
return 0;
out_release:
@@ -745,7 +758,10 @@ out_ro:
ubifs_ro_mode(c, err);
finish_reservation(c);
out_free:
- kfree(data);
+ if (!allocated)
+ mutex_unlock(&c->write_reserve_mutex);
+ else
+ kfree(data);
return err;
}
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index 4d4ca388889b..c7b25e2f7764 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -1035,7 +1035,8 @@ static int scan_check_cb(struct ubifs_info *c,
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
struct ubifs_lp_stats *lst = &data->lst;
- int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty;
+ int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
+ void *buf = NULL;
cat = lp->flags & LPROPS_CAT_MASK;
if (cat != LPROPS_UNCAT) {
@@ -1093,7 +1094,13 @@ static int scan_check_cb(struct ubifs_info *c,
}
}
- sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+ buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubifs_err("cannot allocate memory to scan LEB %d", lnum);
+ goto out;
+ }
+
+ sleb = ubifs_scan(c, lnum, 0, buf, 0);
if (IS_ERR(sleb)) {
/*
* After an unclean unmount, empty and freeable LEBs
@@ -1105,7 +1112,8 @@ static int scan_check_cb(struct ubifs_info *c,
lst->empty_lebs += 1;
lst->total_free += c->leb_size;
lst->total_dark += ubifs_calc_dark(c, c->leb_size);
- return LPT_SCAN_CONTINUE;
+ ret = LPT_SCAN_CONTINUE;
+ goto exit;
}
if (lp->free + lp->dirty == c->leb_size &&
@@ -1115,10 +1123,12 @@ static int scan_check_cb(struct ubifs_info *c,
lst->total_free += lp->free;
lst->total_dirty += lp->dirty;
lst->total_dark += ubifs_calc_dark(c, c->leb_size);
- return LPT_SCAN_CONTINUE;
+ ret = LPT_SCAN_CONTINUE;
+ goto exit;
}
data->err = PTR_ERR(sleb);
- return LPT_SCAN_STOP;
+ ret = LPT_SCAN_STOP;
+ goto exit;
}
is_idx = -1;
@@ -1236,7 +1246,10 @@ static int scan_check_cb(struct ubifs_info *c,
}
ubifs_scan_destroy(sleb);
- return LPT_SCAN_CONTINUE;
+ ret = LPT_SCAN_CONTINUE;
+exit:
+ vfree(buf);
+ return ret;
out_print:
ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
@@ -1246,6 +1259,7 @@ out_print:
out_destroy:
ubifs_scan_destroy(sleb);
out:
+ vfree(buf);
data->err = -EINVAL;
return LPT_SCAN_STOP;
}
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 5c90dec5db0b..0a3c2c3f5c4a 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -1628,29 +1628,35 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
{
int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
int ret;
- void *buf = c->dbg->buf;
+ void *buf, *p;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
return 0;
+ buf = p = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubifs_err("cannot allocate memory for ltab checking");
+ return 0;
+ }
+
dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
- return err;
+ goto out;
}
while (1) {
- if (!is_a_node(c, buf, len)) {
+ if (!is_a_node(c, p, len)) {
int i, pad_len;
- pad_len = get_pad_len(c, buf, len);
+ pad_len = get_pad_len(c, p, len);
if (pad_len) {
- buf += pad_len;
+ p += pad_len;
len -= pad_len;
dirty += pad_len;
continue;
}
- if (!dbg_is_all_ff(buf, len)) {
+ if (!dbg_is_all_ff(p, len)) {
dbg_msg("invalid empty space in LEB %d at %d",
lnum, c->leb_size - len);
err = -EINVAL;
@@ -1668,16 +1674,21 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
lnum, dirty, c->ltab[i].dirty);
err = -EINVAL;
}
- return err;
+ goto out;
}
- node_type = get_lpt_node_type(c, buf, &node_num);
+ node_type = get_lpt_node_type(c, p, &node_num);
node_len = get_lpt_node_len(c, node_type);
ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
if (ret == 1)
dirty += node_len;
- buf += node_len;
+ p += node_len;
len -= node_len;
}
+
+ err = 0;
+out:
+ vfree(buf);
+ return err;
}
/**
@@ -1870,25 +1881,31 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
{
int err, len = c->leb_size, node_type, node_num, node_len, offs;
- void *buf = c->dbg->buf;
+ void *buf, *p;
printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
current->pid, lnum);
+ buf = p = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubifs_err("cannot allocate memory to dump LPT");
+ return;
+ }
+
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
- return;
+ goto out;
}
while (1) {
offs = c->leb_size - len;
- if (!is_a_node(c, buf, len)) {
+ if (!is_a_node(c, p, len)) {
int pad_len;
- pad_len = get_pad_len(c, buf, len);
+ pad_len = get_pad_len(c, p, len);
if (pad_len) {
printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
lnum, offs, pad_len);
- buf += pad_len;
+ p += pad_len;
len -= pad_len;
continue;
}
@@ -1898,7 +1915,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
break;
}
- node_type = get_lpt_node_type(c, buf, &node_num);
+ node_type = get_lpt_node_type(c, p, &node_num);
switch (node_type) {
case UBIFS_LPT_PNODE:
{
@@ -1923,7 +1940,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
else
printk(KERN_DEBUG "LEB %d:%d, nnode, ",
lnum, offs);
- err = ubifs_unpack_nnode(c, buf, &nnode);
+ err = ubifs_unpack_nnode(c, p, &nnode);
for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
printk(KERN_CONT "%d:%d", nnode.nbranch[i].lnum,
nnode.nbranch[i].offs);
@@ -1944,15 +1961,18 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
break;
default:
ubifs_err("LPT node type %d not recognized", node_type);
- return;
+ goto out;
}
- buf += node_len;
+ p += node_len;
len -= node_len;
}
printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
current->pid, lnum);
+out:
+ vfree(buf);
+ return;
}
/**
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index 82009c74b6a3..2cdbd31641d7 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -892,15 +892,22 @@ static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
{
int lnum, err = 0;
+ void *buf;
/* Check no-orphans flag and skip this if no orphans */
if (c->no_orphs)
return 0;
+ buf = __vmalloc(c->leb_size, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL);
+ if (!buf) {
+ ubifs_err("cannot allocate memory to check orphans");
+ return 0;
+ }
+
for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
struct ubifs_scan_leb *sleb;
- sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+ sleb = ubifs_scan(c, lnum, 0, buf, 0);
if (IS_ERR(sleb)) {
err = PTR_ERR(sleb);
break;
@@ -912,6 +919,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
break;
}
+ vfree(buf);
return err;
}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 77e9b874b6c2..936f2cbfe6b6 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -28,6 +28,23 @@
* UBIFS always cleans away all remnants of an unclean un-mount, so that
* errors do not accumulate. However UBIFS defers recovery if it is mounted
* read-only, and the flash is not modified in that case.
+ *
+ * The general UBIFS approach to the recovery is that it recovers from
+ * corruptions which could be caused by power cuts, but it refuses to recover
+ * from corruption caused by other reasons. And UBIFS tries to distinguish
+ * between these 2 reasons of corruptions and silently recover in the former
+ * case and loudly complain in the latter case.
+ *
+ * UBIFS writes only to erased LEBs, so it writes only to the flash space
+ * containing only 0xFFs. UBIFS also always writes strictly from the beginning
+ * of the LEB to the end. And UBIFS assumes that the underlying flash media
+ * writes in @c->max_write_size bytes at a time.
+ *
+ * Hence, if UBIFS finds a corrupted node at offset X, it expects only the min.
+ * I/O unit corresponding to offset X to contain corrupted data, all the
+ * following min. I/O units have to contain empty space (all 0xFFs). If this is
+ * not true, the corruption cannot be the result of a power cut, and UBIFS
+ * refuses to mount.
*/
#include <linux/crc32.h>
@@ -362,8 +379,9 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
* @offs: offset to check
*
* This function returns %1 if @offs was in the last write to the LEB whose data
- * is in @buf, otherwise %0 is returned. The determination is made by checking
- * for subsequent empty space starting from the next @c->min_io_size boundary.
+ * is in @buf, otherwise %0 is returned. The determination is made by checking
+ * for subsequent empty space starting from the next @c->max_write_size
+ * boundary.
*/
static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
{
@@ -371,10 +389,10 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
uint8_t *p;
/*
- * Round up to the next @c->min_io_size boundary i.e. @offs is in the
- * last wbuf written. After that should be empty space.
+ * Round up to the next @c->max_write_size boundary i.e. @offs is in
+ * the last wbuf written. After that should be empty space.
*/
- empty_offs = ALIGN(offs + 1, c->min_io_size);
+ empty_offs = ALIGN(offs + 1, c->max_write_size);
check_len = c->leb_size - empty_offs;
p = buf + empty_offs - offs;
return is_empty(p, check_len);
@@ -429,7 +447,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
int skip, dlen = le32_to_cpu(ch->len);
/* Check for empty space after the corrupt node's common header */
- skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
+ skip = ALIGN(offs + UBIFS_CH_SZ, c->max_write_size) - offs;
if (is_empty(buf + skip, len - skip))
return 1;
/*
@@ -441,7 +459,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
return 0;
}
/* Now we know the corrupt node's length we can skip over it */
- skip = ALIGN(offs + dlen, c->min_io_size) - offs;
+ skip = ALIGN(offs + dlen, c->max_write_size) - offs;
/* After which there should be empty space */
if (is_empty(buf + skip, len - skip))
return 1;
@@ -671,10 +689,14 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
} else {
int corruption = first_non_ff(buf, len);
+ /*
+ * See header comment for this file for more
+ * explanations about the reasons we have this check.
+ */
ubifs_err("corrupt empty space LEB %d:%d, corruption "
"starts at %d", lnum, offs, corruption);
/* Make sure we dump interesting non-0xFF data */
- offs = corruption;
+ offs += corruption;
buf += corruption;
goto corrupted;
}
@@ -836,12 +858,8 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
static int recover_head(const struct ubifs_info *c, int lnum, int offs,
void *sbuf)
{
- int len, err;
+ int len = c->max_write_size, err;
- if (c->min_io_size > 1)
- len = c->min_io_size;
- else
- len = 512;
if (offs + len > c->leb_size)
len = c->leb_size - offs;
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 3e1ee57dbeaa..36216b46f772 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -328,7 +328,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
if (!quiet)
ubifs_err("empty space starts at non-aligned offset %d",
offs);
- goto corrupted;;
+ goto corrupted;
}
ubifs_end_scan(c, sleb, lnum, offs);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 6e11c2975dcf..e5dc1e120e8d 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -512,9 +512,12 @@ static int init_constants_early(struct ubifs_info *c)
c->leb_cnt = c->vi.size;
c->leb_size = c->vi.usable_leb_size;
+ c->leb_start = c->di.leb_start;
c->half_leb_size = c->leb_size / 2;
c->min_io_size = c->di.min_io_size;
c->min_io_shift = fls(c->min_io_size) - 1;
+ c->max_write_size = c->di.max_write_size;
+ c->max_write_shift = fls(c->max_write_size) - 1;
if (c->leb_size < UBIFS_MIN_LEB_SZ) {
ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
@@ -534,6 +537,18 @@ static int init_constants_early(struct ubifs_info *c)
}
/*
+ * Maximum write size has to be greater or equivalent to min. I/O
+ * size, and be multiple of min. I/O size.
+ */
+ if (c->max_write_size < c->min_io_size ||
+ c->max_write_size % c->min_io_size ||
+ !is_power_of_2(c->max_write_size)) {
+ ubifs_err("bad write buffer size %d for %d min. I/O unit",
+ c->max_write_size, c->min_io_size);
+ return -EINVAL;
+ }
+
+ /*
* UBIFS aligns all node to 8-byte boundary, so to make function in
* io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
* less than 8.
@@ -541,6 +556,10 @@ static int init_constants_early(struct ubifs_info *c)
if (c->min_io_size < 8) {
c->min_io_size = 8;
c->min_io_shift = 3;
+ if (c->max_write_size < c->min_io_size) {
+ c->max_write_size = c->min_io_size;
+ c->max_write_shift = c->min_io_shift;
+ }
}
c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
@@ -1202,11 +1221,14 @@ static int mount_ubifs(struct ubifs_info *c)
if (c->bulk_read == 1)
bu_init(c);
- /*
- * We have to check all CRCs, even for data nodes, when we mount the FS
- * (specifically, when we are replaying).
- */
- c->always_chk_crc = 1;
+ if (!c->ro_mount) {
+ c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
+ GFP_KERNEL);
+ if (!c->write_reserve_buf)
+ goto out_free;
+ }
+
+ c->mounting = 1;
err = ubifs_read_superblock(c);
if (err)
@@ -1382,7 +1404,7 @@ static int mount_ubifs(struct ubifs_info *c)
if (err)
goto out_infos;
- c->always_chk_crc = 0;
+ c->mounting = 0;
ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
c->vi.ubi_num, c->vi.vol_id, c->vi.name);
@@ -1403,6 +1425,7 @@ static int mount_ubifs(struct ubifs_info *c)
dbg_msg("compiled on: " __DATE__ " at " __TIME__);
dbg_msg("min. I/O unit size: %d bytes", c->min_io_size);
+ dbg_msg("max. write size: %d bytes", c->max_write_size);
dbg_msg("LEB size: %d bytes (%d KiB)",
c->leb_size, c->leb_size >> 10);
dbg_msg("data journal heads: %d",
@@ -1432,9 +1455,9 @@ static int mount_ubifs(struct ubifs_info *c)
UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
dbg_msg("node sizes: ref %zu, cmt. start %zu, orph %zu",
UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
- dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu",
+ dbg_msg("max. node sizes: data %zu, inode %zu dentry %zu, idx %d",
UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
- UBIFS_MAX_DENT_NODE_SZ);
+ UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
dbg_msg("dead watermark: %d", c->dead_wm);
dbg_msg("dark watermark: %d", c->dark_wm);
dbg_msg("LEB overhead: %d", c->leb_overhead);
@@ -1474,6 +1497,7 @@ out_wbufs:
out_cbuf:
kfree(c->cbuf);
out_free:
+ kfree(c->write_reserve_buf);
kfree(c->bu.buf);
vfree(c->ileb_buf);
vfree(c->sbuf);
@@ -1512,6 +1536,7 @@ static void ubifs_umount(struct ubifs_info *c)
kfree(c->cbuf);
kfree(c->rcvrd_mst_node);
kfree(c->mst_node);
+ kfree(c->write_reserve_buf);
kfree(c->bu.buf);
vfree(c->ileb_buf);
vfree(c->sbuf);
@@ -1543,7 +1568,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
mutex_lock(&c->umount_mutex);
dbg_save_space_info(c);
c->remounting_rw = 1;
- c->always_chk_crc = 1;
err = check_free_space(c);
if (err)
@@ -1598,6 +1622,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out;
}
+ c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
+ if (!c->write_reserve_buf)
+ goto out;
+
err = ubifs_lpt_init(c, 0, 1);
if (err)
goto out;
@@ -1650,7 +1678,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
dbg_gen("re-mounted read-write");
c->ro_mount = 0;
c->remounting_rw = 0;
- c->always_chk_crc = 0;
err = dbg_check_space_info(c);
mutex_unlock(&c->umount_mutex);
return err;
@@ -1663,11 +1690,12 @@ out:
c->bgt = NULL;
}
free_wbufs(c);
+ kfree(c->write_reserve_buf);
+ c->write_reserve_buf = NULL;
vfree(c->ileb_buf);
c->ileb_buf = NULL;
ubifs_lpt_free(c, 1);
c->remounting_rw = 0;
- c->always_chk_crc = 0;
mutex_unlock(&c->umount_mutex);
return err;
}
@@ -1707,6 +1735,8 @@ static void ubifs_remount_ro(struct ubifs_info *c)
free_wbufs(c);
vfree(c->orph_buf);
c->orph_buf = NULL;
+ kfree(c->write_reserve_buf);
+ c->write_reserve_buf = NULL;
vfree(c->ileb_buf);
c->ileb_buf = NULL;
ubifs_lpt_free(c, 1);
@@ -1937,6 +1967,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
mutex_init(&c->mst_mutex);
mutex_init(&c->umount_mutex);
mutex_init(&c->bu_mutex);
+ mutex_init(&c->write_reserve_mutex);
init_waitqueue_head(&c->cmt_wq);
c->buds = RB_ROOT;
c->old_idx = RB_ROOT;
@@ -1954,6 +1985,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->old_buds);
INIT_LIST_HEAD(&c->orph_list);
INIT_LIST_HEAD(&c->orph_new);
+ c->no_chk_data_crc = 1;
c->vfs_sb = sb;
c->highest_inum = UBIFS_FIRST_INO;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index ad9cf0133622..de485979ca39 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -447,8 +447,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
*
* Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
* is true (it is controlled by corresponding mount option). However, if
- * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
- * checked.
+ * @c->mounting or @c->remounting_rw is true (we are mounting or re-mounting to
+ * R/W mode), @c->no_chk_data_crc is ignored and CRC is checked. This is
+ * because during mounting or re-mounting from R/O mode to R/W mode we may read
+ * journal nodes (when replying the journal or doing the recovery) and the
+ * journal nodes may potentially be corrupted, so checking is required.
*/
static int try_read_node(const struct ubifs_info *c, void *buf, int type,
int len, int lnum, int offs)
@@ -476,7 +479,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
if (node_len != len)
return 0;
- if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
+ if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
+ !c->remounting_rw)
return 1;
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 381d6b207a52..8c40ad3c6721 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -151,6 +151,12 @@
*/
#define WORST_COMPR_FACTOR 2
+/*
+ * How much memory is needed for a buffer where we comress a data node.
+ */
+#define COMPRESSED_DATA_NODE_BUF_SZ \
+ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+
/* Maximum expected tree height for use by bottom_up_buf */
#define BOTTOM_UP_HEIGHT 64
@@ -646,6 +652,7 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @offs: write-buffer offset in this logical eraseblock
* @avail: number of bytes available in the write-buffer
* @used: number of used bytes in the write-buffer
+ * @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
* @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
* %UBI_UNKNOWN)
* @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
@@ -680,6 +687,7 @@ struct ubifs_wbuf {
int offs;
int avail;
int used;
+ int size;
int dtype;
int jhead;
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
@@ -1003,6 +1011,11 @@ struct ubifs_debug_info;
* @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
* @bu: pre-allocated bulk-read information
*
+ * @write_reserve_mutex: protects @write_reserve_buf
+ * @write_reserve_buf: on the write path we allocate memory, which might
+ * sometimes be unavailable, in which case we use this
+ * write reserve buffer
+ *
* @log_lebs: number of logical eraseblocks in the log
* @log_bytes: log size in bytes
* @log_last: last LEB of the log
@@ -1024,7 +1037,12 @@ struct ubifs_debug_info;
*
* @min_io_size: minimal input/output unit size
* @min_io_shift: number of bits in @min_io_size minus one
+ * @max_write_size: maximum amount of bytes the underlying flash can write at a
+ * time (MTD write buffer size)
+ * @max_write_shift: number of bits in @max_write_size minus one
* @leb_size: logical eraseblock size in bytes
+ * @leb_start: starting offset of logical eraseblocks within physical
+ * eraseblocks
* @half_leb_size: half LEB size
* @idx_leb_size: how many bytes of an LEB are effectively available when it is
* used to store indexing nodes (@leb_size - @max_idx_node_sz)
@@ -1166,22 +1184,21 @@ struct ubifs_debug_info;
* @rp_uid: reserved pool user ID
* @rp_gid: reserved pool group ID
*
- * @empty: if the UBI device is empty
+ * @empty: %1 if the UBI device is empty
+ * @need_recovery: %1 if the file-system needs recovery
+ * @replaying: %1 during journal replay
+ * @mounting: %1 while mounting
+ * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
* @replay_tree: temporary tree used during journal replay
* @replay_list: temporary list used during journal replay
* @replay_buds: list of buds to replay
* @cs_sqnum: sequence number of first node in the log (commit start node)
* @replay_sqnum: sequence number of node currently being replayed
- * @need_recovery: file-system needs recovery
- * @replaying: set to %1 during journal replay
* @unclean_leb_list: LEBs to recover when re-mounting R/O mounted FS to R/W
* mode
* @rcvrd_mst_node: recovered master node to write when re-mounting R/O mounted
* FS to R/W mode
* @size_tree: inode size information for recovery
- * @remounting_rw: set while re-mounting from R/O mode to R/W mode
- * @always_chk_crc: always check CRCs (while mounting and remounting to R/W
- * mode)
* @mount_opts: UBIFS-specific mount options
*
* @dbg: debugging-related information
@@ -1250,6 +1267,9 @@ struct ubifs_info {
struct mutex bu_mutex;
struct bu_info bu;
+ struct mutex write_reserve_mutex;
+ void *write_reserve_buf;
+
int log_lebs;
long long log_bytes;
int log_last;
@@ -1271,7 +1291,10 @@ struct ubifs_info {
int min_io_size;
int min_io_shift;
+ int max_write_size;
+ int max_write_shift;
int leb_size;
+ int leb_start;
int half_leb_size;
int idx_leb_size;
int leb_cnt;
@@ -1402,19 +1425,19 @@ struct ubifs_info {
gid_t rp_gid;
/* The below fields are used only during mounting and re-mounting */
- int empty;
+ unsigned int empty:1;
+ unsigned int need_recovery:1;
+ unsigned int replaying:1;
+ unsigned int mounting:1;
+ unsigned int remounting_rw:1;
struct rb_root replay_tree;
struct list_head replay_list;
struct list_head replay_buds;
unsigned long long cs_sqnum;
unsigned long long replay_sqnum;
- int need_recovery;
- int replaying;
struct list_head unclean_leb_list;
struct ubifs_mst_node *rcvrd_mst_node;
struct rb_root size_tree;
- int remounting_rw;
- int always_chk_crc;
struct ubifs_mount_opts mount_opts;
#ifdef CONFIG_UBIFS_FS_DEBUG
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 306ee39ef2c3..8994dd041660 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -31,7 +31,7 @@
#define udf_set_bit(nr, addr) ext2_set_bit(nr, addr)
#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
#define udf_find_next_one_bit(addr, size, offset) \
- ext2_find_next_bit(addr, size, offset)
+ ext2_find_next_bit((unsigned long *)(addr), size, offset)
static int read_block_bitmap(struct super_block *sb,
struct udf_bitmap *bitmap, unsigned int block,
@@ -297,7 +297,7 @@ repeat:
break;
}
} else {
- bit = udf_find_next_one_bit((char *)bh->b_data,
+ bit = udf_find_next_one_bit(bh->b_data,
sb->s_blocksize << 3,
group_start << 3);
if (bit < sb->s_blocksize << 3)
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 89c78486cbbe..f391a2adc699 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -123,8 +123,8 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (inode->i_sb->s_blocksize <
(udf_file_entry_alloc_offset(inode) +
pos + count)) {
- udf_expand_file_adinicb(inode, pos + count, &err);
- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ err = udf_expand_file_adinicb(inode);
+ if (err) {
udf_debug("udf_expand_adinicb: err=%d\n", err);
up_write(&iinfo->i_data_sem);
return err;
@@ -237,7 +237,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size != i_size_read(inode)) {
- error = vmtruncate(inode, attr->ia_size);
+ error = udf_setsize(inode, attr->ia_size);
if (error)
return error;
}
@@ -249,5 +249,4 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
const struct inode_operations udf_file_inode_operations = {
.setattr = udf_setattr,
- .truncate = udf_truncate,
};
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index c6a2e782b97b..ccc814321414 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -73,14 +73,12 @@ void udf_evict_inode(struct inode *inode)
struct udf_inode_info *iinfo = UDF_I(inode);
int want_delete = 0;
- truncate_inode_pages(&inode->i_data, 0);
-
if (!inode->i_nlink && !is_bad_inode(inode)) {
want_delete = 1;
- inode->i_size = 0;
- udf_truncate(inode);
+ udf_setsize(inode, 0);
udf_update_inode(inode, IS_SYNC(inode));
- }
+ } else
+ truncate_inode_pages(&inode->i_data, 0);
invalidate_inode_buffers(inode);
end_writeback(inode);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
@@ -117,9 +115,18 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
if (unlikely(ret)) {
- loff_t isize = mapping->host->i_size;
- if (pos + len > isize)
- vmtruncate(mapping->host, isize);
+ struct inode *inode = mapping->host;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ loff_t isize = inode->i_size;
+
+ if (pos + len > isize) {
+ truncate_pagecache(inode, pos + len, isize);
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ down_write(&iinfo->i_data_sem);
+ udf_truncate_extents(inode);
+ up_write(&iinfo->i_data_sem);
+ }
+ }
}
return ret;
@@ -139,30 +146,31 @@ const struct address_space_operations udf_aops = {
.bmap = udf_bmap,
};
-void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
+int udf_expand_file_adinicb(struct inode *inode)
{
struct page *page;
char *kaddr;
struct udf_inode_info *iinfo = UDF_I(inode);
+ int err;
struct writeback_control udf_wbc = {
.sync_mode = WB_SYNC_NONE,
.nr_to_write = 1,
};
- /* from now on we have normal address_space methods */
- inode->i_data.a_ops = &udf_aops;
-
if (!iinfo->i_lenAlloc) {
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
+ /* from now on we have normal address_space methods */
+ inode->i_data.a_ops = &udf_aops;
mark_inode_dirty(inode);
- return;
+ return 0;
}
- page = grab_cache_page(inode->i_mapping, 0);
- BUG_ON(!PageLocked(page));
+ page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
+ if (!page)
+ return -ENOMEM;
if (!PageUptodate(page)) {
kaddr = kmap(page);
@@ -181,11 +189,24 @@ void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
-
- inode->i_data.a_ops->writepage(page, &udf_wbc);
+ /* from now on we have normal address_space methods */
+ inode->i_data.a_ops = &udf_aops;
+ err = inode->i_data.a_ops->writepage(page, &udf_wbc);
+ if (err) {
+ /* Restore everything back so that we don't lose data... */
+ lock_page(page);
+ kaddr = kmap(page);
+ memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
+ inode->i_size);
+ kunmap(page);
+ unlock_page(page);
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ }
page_cache_release(page);
-
mark_inode_dirty(inode);
+
+ return err;
}
struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
@@ -348,8 +369,10 @@ static struct buffer_head *udf_getblk(struct inode *inode, long block,
}
/* Extend the file by 'blocks' blocks, return the number of extents added */
-int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
- struct kernel_long_ad *last_ext, sector_t blocks)
+static int udf_do_extend_file(struct inode *inode,
+ struct extent_position *last_pos,
+ struct kernel_long_ad *last_ext,
+ sector_t blocks)
{
sector_t add;
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
@@ -357,6 +380,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
struct kernel_lb_addr prealloc_loc = {};
int prealloc_len = 0;
struct udf_inode_info *iinfo;
+ int err;
/* The previous extent is fake and we should not extend by anything
* - there's nothing to do... */
@@ -422,26 +446,29 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
/* Create enough extents to cover the whole hole */
while (blocks > add) {
blocks -= add;
- if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
- last_ext->extLength, 1) == -1)
- return -1;
+ err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+ if (err)
+ return err;
count++;
}
if (blocks) {
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
(blocks << sb->s_blocksize_bits);
- if (udf_add_aext(inode, last_pos, &last_ext->extLocation,
- last_ext->extLength, 1) == -1)
- return -1;
+ err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+ if (err)
+ return err;
count++;
}
out:
/* Do we have some preallocated blocks saved? */
if (prealloc_len) {
- if (udf_add_aext(inode, last_pos, &prealloc_loc,
- prealloc_len, 1) == -1)
- return -1;
+ err = udf_add_aext(inode, last_pos, &prealloc_loc,
+ prealloc_len, 1);
+ if (err)
+ return err;
last_ext->extLocation = prealloc_loc;
last_ext->extLength = prealloc_len;
count++;
@@ -453,11 +480,68 @@ out:
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
last_pos->offset -= sizeof(struct long_ad);
else
- return -1;
+ return -EIO;
return count;
}
+static int udf_extend_file(struct inode *inode, loff_t newsize)
+{
+
+ struct extent_position epos;
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ int8_t etype;
+ struct super_block *sb = inode->i_sb;
+ sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
+ int adsize;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ struct kernel_long_ad extent;
+ int err;
+
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
+ else
+ BUG();
+
+ etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+
+ /* File has extent covering the new size (could happen when extending
+ * inside a block)? */
+ if (etype != -1)
+ return 0;
+ if (newsize & (sb->s_blocksize - 1))
+ offset++;
+ /* Extended file just to the boundary of the last file block? */
+ if (offset == 0)
+ return 0;
+
+ /* Truncate is extending the file by 'offset' blocks */
+ if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+ (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
+ /* File has no extents at all or has empty last
+ * indirect extent! Create a fake extent... */
+ extent.extLocation.logicalBlockNum = 0;
+ extent.extLocation.partitionReferenceNum = 0;
+ extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
+ } else {
+ epos.offset -= adsize;
+ etype = udf_next_aext(inode, &epos, &extent.extLocation,
+ &extent.extLength, 0);
+ extent.extLength |= etype << 30;
+ }
+ err = udf_do_extend_file(inode, &epos, &extent, offset);
+ if (err < 0)
+ goto out;
+ err = 0;
+ iinfo->i_lenExtents = newsize;
+out:
+ brelse(epos.bh);
+ return err;
+}
+
static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
int *err, sector_t *phys, int *new)
{
@@ -540,7 +624,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) &
~(inode->i_sb->s_blocksize - 1));
- etype = udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
+ udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
}
brelse(prev_epos.bh);
brelse(cur_epos.bh);
@@ -564,19 +648,17 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
memset(&laarr[0].extLocation, 0x00,
sizeof(struct kernel_lb_addr));
laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
- /* Will udf_extend_file() create real extent from
+ /* Will udf_do_extend_file() create real extent from
a fake one? */
startnum = (offset > 0);
}
/* Create extents for the hole between EOF and offset */
- ret = udf_extend_file(inode, &prev_epos, laarr, offset);
- if (ret == -1) {
+ ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
+ if (ret < 0) {
brelse(prev_epos.bh);
brelse(cur_epos.bh);
brelse(next_epos.bh);
- /* We don't really know the error here so we just make
- * something up */
- *err = -ENOSPC;
+ *err = ret;
return NULL;
}
c = 0;
@@ -1005,52 +1087,66 @@ struct buffer_head *udf_bread(struct inode *inode, int block,
return NULL;
}
-void udf_truncate(struct inode *inode)
+int udf_setsize(struct inode *inode, loff_t newsize)
{
- int offset;
int err;
struct udf_inode_info *iinfo;
+ int bsize = 1 << inode->i_blkbits;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
- return;
+ return -EINVAL;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
+ return -EPERM;
iinfo = UDF_I(inode);
- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ if (newsize > inode->i_size) {
down_write(&iinfo->i_data_sem);
- if (inode->i_sb->s_blocksize <
- (udf_file_entry_alloc_offset(inode) +
- inode->i_size)) {
- udf_expand_file_adinicb(inode, inode->i_size, &err);
- if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
- inode->i_size = iinfo->i_lenAlloc;
- up_write(&iinfo->i_data_sem);
- return;
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ if (bsize <
+ (udf_file_entry_alloc_offset(inode) + newsize)) {
+ err = udf_expand_file_adinicb(inode);
+ if (err) {
+ up_write(&iinfo->i_data_sem);
+ return err;
+ }
} else
- udf_truncate_extents(inode);
- } else {
- offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
- memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
- 0x00, inode->i_sb->s_blocksize -
- offset - udf_file_entry_alloc_offset(inode));
- iinfo->i_lenAlloc = inode->i_size;
+ iinfo->i_lenAlloc = newsize;
+ }
+ err = udf_extend_file(inode, newsize);
+ if (err) {
+ up_write(&iinfo->i_data_sem);
+ return err;
}
+ truncate_setsize(inode, newsize);
up_write(&iinfo->i_data_sem);
} else {
- block_truncate_page(inode->i_mapping, inode->i_size,
- udf_get_block);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ down_write(&iinfo->i_data_sem);
+ memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize,
+ 0x00, bsize - newsize -
+ udf_file_entry_alloc_offset(inode));
+ iinfo->i_lenAlloc = newsize;
+ truncate_setsize(inode, newsize);
+ up_write(&iinfo->i_data_sem);
+ goto update_time;
+ }
+ err = block_truncate_page(inode->i_mapping, newsize,
+ udf_get_block);
+ if (err)
+ return err;
down_write(&iinfo->i_data_sem);
+ truncate_setsize(inode, newsize);
udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem);
}
-
+update_time:
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode))
udf_sync_inode(inode);
else
mark_inode_dirty(inode);
+ return 0;
}
static void __udf_read_inode(struct inode *inode)
@@ -1637,14 +1733,13 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
return NULL;
}
-int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
- struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+int udf_add_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
int adsize;
struct short_ad *sad = NULL;
struct long_ad *lad = NULL;
struct allocExtDesc *aed;
- int8_t etype;
uint8_t *ptr;
struct udf_inode_info *iinfo = UDF_I(inode);
@@ -1660,7 +1755,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
- return -1;
+ return -EIO;
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
unsigned char *sptr, *dptr;
@@ -1672,12 +1767,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
obloc.partitionReferenceNum,
obloc.logicalBlockNum, &err);
if (!epos->block.logicalBlockNum)
- return -1;
+ return -ENOSPC;
nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
&epos->block,
0));
if (!nbh)
- return -1;
+ return -EIO;
lock_buffer(nbh);
memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(nbh);
@@ -1746,7 +1841,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
epos->bh = nbh;
}
- etype = udf_write_aext(inode, epos, eloc, elen, inc);
+ udf_write_aext(inode, epos, eloc, elen, inc);
if (!epos->bh) {
iinfo->i_lenAlloc += adsize;
@@ -1764,11 +1859,11 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
mark_buffer_dirty_inode(epos->bh, inode);
}
- return etype;
+ return 0;
}
-int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
- struct kernel_lb_addr *eloc, uint32_t elen, int inc)
+void udf_write_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
int adsize;
uint8_t *ptr;
@@ -1798,7 +1893,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
adsize = sizeof(struct long_ad);
break;
default:
- return -1;
+ return;
}
if (epos->bh) {
@@ -1817,8 +1912,6 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
if (inc)
epos->offset += adsize;
-
- return (elen >> 30);
}
int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 225527cdc885..8424308db4b4 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -197,6 +197,11 @@ static void udf_update_alloc_ext_desc(struct inode *inode,
mark_buffer_dirty_inode(epos->bh, inode);
}
+/*
+ * Truncate extents of inode to inode->i_size. This function can be used only
+ * for making file shorter. For making file longer, udf_extend_file() has to
+ * be used.
+ */
void udf_truncate_extents(struct inode *inode)
{
struct extent_position epos;
@@ -219,96 +224,65 @@ void udf_truncate_extents(struct inode *inode)
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
byte_offset = (offset << sb->s_blocksize_bits) +
(inode->i_size & (sb->s_blocksize - 1));
- if (etype != -1) {
- epos.offset -= adsize;
- extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
- epos.offset += adsize;
- if (byte_offset)
- lenalloc = epos.offset;
- else
- lenalloc = epos.offset - adsize;
-
- if (!epos.bh)
- lenalloc -= udf_file_entry_alloc_offset(inode);
- else
- lenalloc -= sizeof(struct allocExtDesc);
-
- while ((etype = udf_current_aext(inode, &epos, &eloc,
- &elen, 0)) != -1) {
- if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
- udf_write_aext(inode, &epos, &neloc, nelen, 0);
- if (indirect_ext_len) {
- /* We managed to free all extents in the
- * indirect extent - free it too */
- BUG_ON(!epos.bh);
- udf_free_blocks(sb, inode, &epos.block,
- 0, indirect_ext_len);
- } else if (!epos.bh) {
- iinfo->i_lenAlloc = lenalloc;
- mark_inode_dirty(inode);
- } else
- udf_update_alloc_ext_desc(inode,
- &epos, lenalloc);
- brelse(epos.bh);
- epos.offset = sizeof(struct allocExtDesc);
- epos.block = eloc;
- epos.bh = udf_tread(sb,
- udf_get_lb_pblock(sb, &eloc, 0));
- if (elen)
- indirect_ext_len =
- (elen + sb->s_blocksize - 1) >>
- sb->s_blocksize_bits;
- else
- indirect_ext_len = 1;
- } else {
- extent_trunc(inode, &epos, &eloc, etype,
- elen, 0);
- epos.offset += adsize;
- }
- }
+ if (etype == -1) {
+ /* We should extend the file? */
+ WARN_ON(byte_offset);
+ return;
+ }
+ epos.offset -= adsize;
+ extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
+ epos.offset += adsize;
+ if (byte_offset)
+ lenalloc = epos.offset;
+ else
+ lenalloc = epos.offset - adsize;
- if (indirect_ext_len) {
- BUG_ON(!epos.bh);
- udf_free_blocks(sb, inode, &epos.block, 0,
- indirect_ext_len);
- } else if (!epos.bh) {
- iinfo->i_lenAlloc = lenalloc;
- mark_inode_dirty(inode);
- } else
- udf_update_alloc_ext_desc(inode, &epos, lenalloc);
- } else if (inode->i_size) {
- if (byte_offset) {
- struct kernel_long_ad extent;
+ if (!epos.bh)
+ lenalloc -= udf_file_entry_alloc_offset(inode);
+ else
+ lenalloc -= sizeof(struct allocExtDesc);
- /*
- * OK, there is not extent covering inode->i_size and
- * no extent above inode->i_size => truncate is
- * extending the file by 'offset' blocks.
- */
- if ((!epos.bh &&
- epos.offset ==
- udf_file_entry_alloc_offset(inode)) ||
- (epos.bh && epos.offset ==
- sizeof(struct allocExtDesc))) {
- /* File has no extents at all or has empty last
- * indirect extent! Create a fake extent... */
- extent.extLocation.logicalBlockNum = 0;
- extent.extLocation.partitionReferenceNum = 0;
- extent.extLength =
- EXT_NOT_RECORDED_NOT_ALLOCATED;
- } else {
- epos.offset -= adsize;
- etype = udf_next_aext(inode, &epos,
- &extent.extLocation,
- &extent.extLength, 0);
- extent.extLength |= etype << 30;
- }
- udf_extend_file(inode, &epos, &extent,
- offset +
- ((inode->i_size &
- (sb->s_blocksize - 1)) != 0));
+ while ((etype = udf_current_aext(inode, &epos, &eloc,
+ &elen, 0)) != -1) {
+ if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
+ udf_write_aext(inode, &epos, &neloc, nelen, 0);
+ if (indirect_ext_len) {
+ /* We managed to free all extents in the
+ * indirect extent - free it too */
+ BUG_ON(!epos.bh);
+ udf_free_blocks(sb, inode, &epos.block,
+ 0, indirect_ext_len);
+ } else if (!epos.bh) {
+ iinfo->i_lenAlloc = lenalloc;
+ mark_inode_dirty(inode);
+ } else
+ udf_update_alloc_ext_desc(inode,
+ &epos, lenalloc);
+ brelse(epos.bh);
+ epos.offset = sizeof(struct allocExtDesc);
+ epos.block = eloc;
+ epos.bh = udf_tread(sb,
+ udf_get_lb_pblock(sb, &eloc, 0));
+ if (elen)
+ indirect_ext_len =
+ (elen + sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
+ else
+ indirect_ext_len = 1;
+ } else {
+ extent_trunc(inode, &epos, &eloc, etype, elen, 0);
+ epos.offset += adsize;
}
}
+
+ if (indirect_ext_len) {
+ BUG_ON(!epos.bh);
+ udf_free_blocks(sb, inode, &epos.block, 0, indirect_ext_len);
+ } else if (!epos.bh) {
+ iinfo->i_lenAlloc = lenalloc;
+ mark_inode_dirty(inode);
+ } else
+ udf_update_alloc_ext_desc(inode, &epos, lenalloc);
iinfo->i_lenExtents = inode->i_size;
brelse(epos.bh);
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index eba48209f9f3..dbd52d4b5eed 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -136,22 +136,20 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */
extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
-extern void udf_expand_file_adinicb(struct inode *, int, int *);
+extern int udf_expand_file_adinicb(struct inode *);
extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
-extern void udf_truncate(struct inode *);
+extern int udf_setsize(struct inode *, loff_t);
extern void udf_read_inode(struct inode *);
extern void udf_evict_inode(struct inode *);
extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
extern long udf_block_map(struct inode *, sector_t);
-extern int udf_extend_file(struct inode *, struct extent_position *,
- struct kernel_long_ad *, sector_t);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, sector_t *);
-extern int8_t udf_add_aext(struct inode *, struct extent_position *,
+extern int udf_add_aext(struct inode *, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t, int);
+extern void udf_write_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
-extern int8_t udf_write_aext(struct inode *, struct extent_position *,
- struct kernel_lb_addr *, uint32_t, int);
extern int8_t udf_delete_aext(struct inode *, struct extent_position,
struct kernel_lb_addr, uint32_t);
extern int8_t udf_next_aext(struct inode *, struct extent_position *,
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index 28cc03bf19e6..a1331ce50445 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -108,4 +108,6 @@
#define ERFKILL 132 /* Operation not possible due to RF-kill */
+#define EHWPOISON 133 /* Memory page has hardware error */
+
#endif
diff --git a/include/asm-generic/user.h b/include/asm-generic/user.h
index 8b9c3c960aeb..35638c34700f 100644
--- a/include/asm-generic/user.h
+++ b/include/asm-generic/user.h
@@ -1,8 +1,8 @@
#ifndef __ASM_GENERIC_USER_H
#define __ASM_GENERIC_USER_H
/*
- * This file may define a 'struct user' structure. However, it it only
- * used for a.out file, which are not supported on new architectures.
+ * This file may define a 'struct user' structure. However, it is only
+ * used for a.out files, which are not supported on new architectures.
*/
#endif /* __ASM_GENERIC_USER_H */
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 9e7f259346e1..fcbbe71a3cc1 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -43,12 +43,12 @@ struct amba_id {
struct amba_driver {
struct device_driver drv;
- int (*probe)(struct amba_device *, struct amba_id *);
+ int (*probe)(struct amba_device *, const struct amba_id *);
int (*remove)(struct amba_device *);
void (*shutdown)(struct amba_device *);
int (*suspend)(struct amba_device *, pm_message_t);
int (*resume)(struct amba_device *);
- struct amba_id *id_table;
+ const struct amba_id *id_table;
};
enum amba_vendor {
@@ -56,6 +56,10 @@ enum amba_vendor {
AMBA_VENDOR_ST = 0x80,
};
+extern struct bus_type amba_bustype;
+
+#define to_amba_device(d) container_of(d, struct amba_device, dev)
+
#define amba_get_drvdata(d) dev_get_drvdata(&d->dev)
#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p)
diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h
index f4ee9acc9721..f60227088b7b 100644
--- a/include/linux/amba/mmci.h
+++ b/include/linux/amba/mmci.h
@@ -6,6 +6,9 @@
#include <linux/mmc/host.h>
+/* Just some dummy forwarding */
+struct dma_chan;
+
/**
* struct mmci_platform_data - platform configuration for the MMCI
* (also known as PL180) block.
@@ -27,6 +30,17 @@
* @cd_invert: true if the gpio_cd pin value is active low
* @capabilities: the capabilities of the block as implemented in
* this platform, signify anything MMC_CAP_* from mmc/host.h
+ * @dma_filter: function used to select an apropriate RX and TX
+ * DMA channel to be used for DMA, if and only if you're deploying the
+ * generic DMA engine
+ * @dma_rx_param: parameter passed to the DMA allocation
+ * filter in order to select an apropriate RX channel. If
+ * there is a bidirectional RX+TX channel, then just specify
+ * this and leave dma_tx_param set to NULL
+ * @dma_tx_param: parameter passed to the DMA allocation
+ * filter in order to select an apropriate TX channel. If this
+ * is NULL the driver will attempt to use the RX channel as a
+ * bidirectional channel
*/
struct mmci_platform_data {
unsigned int f_max;
@@ -38,6 +52,9 @@ struct mmci_platform_data {
int gpio_cd;
bool cd_invert;
unsigned long capabilities;
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+ void *dma_rx_param;
+ void *dma_tx_param;
};
#endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index c3e9de8321c6..9343dd3de858 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -230,7 +230,7 @@ struct cpufreq_driver {
int (*bios_limit) (int cpu, unsigned int *limit);
int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
+ int (*suspend) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
};
@@ -281,19 +281,10 @@ __ATTR(_name, 0444, show_##_name, NULL)
static struct freq_attr _name = \
__ATTR(_name, _perm, show_##_name, NULL)
-#define cpufreq_freq_attr_ro_old(_name) \
-static struct freq_attr _name##_old = \
-__ATTR(_name, 0444, show_##_name##_old, NULL)
-
#define cpufreq_freq_attr_rw(_name) \
static struct freq_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
-#define cpufreq_freq_attr_rw_old(_name) \
-static struct freq_attr _name##_old = \
-__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
-
-
struct global_attr {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj,
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index f958c19e3ca5..1a87760d6532 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -168,7 +168,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool, bool);
+ int (*d_manage)(struct dentry *, bool);
} ____cacheline_aligned;
/*
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 9a3f5f9383f6..fc023d67676f 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -42,6 +42,10 @@
#define CSR_BROADCAST_CHANNEL 0x234
#define CSR_CONFIG_ROM 0x400
#define CSR_CONFIG_ROM_END 0x800
+#define CSR_OMPR 0x900
+#define CSR_OPCR(i) (0x904 + (i) * 4)
+#define CSR_IMPR 0x980
+#define CSR_IPCR(i) (0x984 + (i) * 4)
#define CSR_FCP_COMMAND 0xB00
#define CSR_FCP_RESPONSE 0xD00
#define CSR_FCP_END 0xF00
@@ -441,5 +445,8 @@ int fw_iso_context_start(struct fw_iso_context *ctx,
int cycle, int sync, int tags);
int fw_iso_context_stop(struct fw_iso_context *ctx);
void fw_iso_context_destroy(struct fw_iso_context *ctx);
+void fw_iso_resource_manage(struct fw_card *card, int generation,
+ u64 channels_mask, int *channel, int *bandwidth,
+ bool allocate, __be32 buffer[2]);
#endif /* _LINUX_FIREWIRE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 92f7e04aea11..7061a8587ee3 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1839,7 +1839,6 @@ extern struct dentry *mount_pseudo(struct file_system_type *, char *,
const struct super_operations *ops,
const struct dentry_operations *dops,
unsigned long);
-extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
static inline void sb_mark_dirty(struct super_block *sb)
{
diff --git a/drivers/hid/hid-roccat.h b/include/linux/hid-roccat.h
index 5784281d613f..24e1ca01f9a0 100644
--- a/drivers/hid/hid-roccat.h
+++ b/include/linux/hid-roccat.h
@@ -15,18 +15,15 @@
#include <linux/hid.h>
#include <linux/types.h>
-#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
-int roccat_connect(struct class *klass, struct hid_device *hid);
+#define ROCCATIOCGREPSIZE _IOR('H', 0xf1, int)
+
+#ifdef __KERNEL__
+
+int roccat_connect(struct class *klass, struct hid_device *hid,
+ int report_size);
void roccat_disconnect(int minor);
-int roccat_report_event(int minor, u8 const *data, int len);
-#else
-static inline int roccat_connect(struct class *klass,
- struct hid_device *hid) { return -1; }
-static inline void roccat_disconnect(int minor) {}
-static inline int roccat_report_event(int minor, u8 const *data, int len)
-{
- return 0;
-}
+int roccat_report_event(int minor, u8 const *data);
+
#endif
#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index d91c25e253c8..bb29bb1dbd2f 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -504,6 +504,9 @@ struct hid_device { /* device report descriptor */
struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
+ /* handler for raw input (Get_Report) data, used by hidraw */
+ int (*hid_get_raw_report) (struct hid_device *, unsigned char, __u8 *, size_t, unsigned char);
+
/* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
@@ -638,7 +641,7 @@ struct hid_driver {
struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max);
void (*feature_mapping)(struct hid_device *hdev,
- struct hid_input *hidinput, struct hid_field *field,
+ struct hid_field *field,
struct hid_usage *usage);
#ifdef CONFIG_PM
int (*suspend)(struct hid_device *hdev, pm_message_t message);
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
index dd8d69269176..4b88e697c4e9 100644
--- a/include/linux/hidraw.h
+++ b/include/linux/hidraw.h
@@ -35,6 +35,9 @@ struct hidraw_devinfo {
#define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo)
#define HIDIOCGRAWNAME(len) _IOC(_IOC_READ, 'H', 0x04, len)
#define HIDIOCGRAWPHYS(len) _IOC(_IOC_READ, 'H', 0x05, len)
+/* The first byte of SFEATURE and GFEATURE is the report number */
+#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
+#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#define HIDRAW_FIRST_MINOR 0
#define HIDRAW_MAX_DEVICES 64
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
new file mode 100644
index 000000000000..8390efc457eb
--- /dev/null
+++ b/include/linux/hwspinlock.h
@@ -0,0 +1,292 @@
+/*
+ * Hardware spinlock public header
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Contact: Ohad Ben-Cohen <ohad@wizery.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_HWSPINLOCK_H
+#define __LINUX_HWSPINLOCK_H
+
+#include <linux/err.h>
+#include <linux/sched.h>
+
+/* hwspinlock mode argument */
+#define HWLOCK_IRQSTATE 0x01 /* Disable interrupts, save state */
+#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
+
+struct hwspinlock;
+
+#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE)
+
+int hwspin_lock_register(struct hwspinlock *lock);
+struct hwspinlock *hwspin_lock_unregister(unsigned int id);
+struct hwspinlock *hwspin_lock_request(void);
+struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
+int hwspin_lock_free(struct hwspinlock *hwlock);
+int hwspin_lock_get_id(struct hwspinlock *hwlock);
+int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
+ unsigned long *);
+int __hwspin_trylock(struct hwspinlock *, int, unsigned long *);
+void __hwspin_unlock(struct hwspinlock *, int, unsigned long *);
+
+#else /* !CONFIG_HWSPINLOCK */
+
+/*
+ * We don't want these functions to fail if CONFIG_HWSPINLOCK is not
+ * enabled. We prefer to silently succeed in this case, and let the
+ * code path get compiled away. This way, if CONFIG_HWSPINLOCK is not
+ * required on a given setup, users will still work.
+ *
+ * The only exception is hwspin_lock_register/hwspin_lock_unregister, with which
+ * we _do_ want users to fail (no point in registering hwspinlock instances if
+ * the framework is not available).
+ *
+ * Note: ERR_PTR(-ENODEV) will still be considered a success for NULL-checking
+ * users. Others, which care, can still check this with IS_ERR.
+ */
+static inline struct hwspinlock *hwspin_lock_request(void)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline int hwspin_lock_free(struct hwspinlock *hwlock)
+{
+ return 0;
+}
+
+static inline
+int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
+ int mode, unsigned long *flags)
+{
+ return 0;
+}
+
+static inline
+int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
+{
+ return 0;
+}
+
+static inline
+void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
+{
+ return 0;
+}
+
+static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
+{
+ return 0;
+}
+
+static inline int hwspin_lock_register(struct hwspinlock *hwlock)
+{
+ return -ENODEV;
+}
+
+static inline struct hwspinlock *hwspin_lock_unregister(unsigned int id)
+{
+ return NULL;
+}
+
+#endif /* !CONFIG_HWSPINLOCK */
+
+/**
+ * hwspin_trylock_irqsave() - try to lock an hwspinlock, disable interrupts
+ * @hwlock: an hwspinlock which we want to trylock
+ * @flags: a pointer to where the caller's interrupt state will be saved at
+ *
+ * This function attempts to lock the underlying hwspinlock, and will
+ * immediately fail if the hwspinlock is already locked.
+ *
+ * Upon a successful return from this function, preemption and local
+ * interrupts are disabled (previous interrupts state is saved at @flags),
+ * so the caller must not sleep, and is advised to release the hwspinlock
+ * as soon as possible.
+ *
+ * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
+ * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
+ */
+static inline
+int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags)
+{
+ return __hwspin_trylock(hwlock, HWLOCK_IRQSTATE, flags);
+}
+
+/**
+ * hwspin_trylock_irq() - try to lock an hwspinlock, disable interrupts
+ * @hwlock: an hwspinlock which we want to trylock
+ *
+ * This function attempts to lock the underlying hwspinlock, and will
+ * immediately fail if the hwspinlock is already locked.
+ *
+ * Upon a successful return from this function, preemption and local
+ * interrupts are disabled, so the caller must not sleep, and is advised
+ * to release the hwspinlock as soon as possible.
+ *
+ * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
+ * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
+ */
+static inline int hwspin_trylock_irq(struct hwspinlock *hwlock)
+{
+ return __hwspin_trylock(hwlock, HWLOCK_IRQ, NULL);
+}
+
+/**
+ * hwspin_trylock() - attempt to lock a specific hwspinlock
+ * @hwlock: an hwspinlock which we want to trylock
+ *
+ * This function attempts to lock an hwspinlock, and will immediately fail
+ * if the hwspinlock is already taken.
+ *
+ * Upon a successful return from this function, preemption is disabled,
+ * so the caller must not sleep, and is advised to release the hwspinlock
+ * as soon as possible. This is required in order to minimize remote cores
+ * polling on the hardware interconnect.
+ *
+ * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
+ * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
+ */
+static inline int hwspin_trylock(struct hwspinlock *hwlock)
+{
+ return __hwspin_trylock(hwlock, 0, NULL);
+}
+
+/**
+ * hwspin_lock_timeout_irqsave() - lock hwspinlock, with timeout, disable irqs
+ * @hwlock: the hwspinlock to be locked
+ * @to: timeout value in msecs
+ * @flags: a pointer to where the caller's interrupt state will be saved at
+ *
+ * This function locks the underlying @hwlock. If the @hwlock
+ * is already taken, the function will busy loop waiting for it to
+ * be released, but give up when @timeout msecs have elapsed.
+ *
+ * Upon a successful return from this function, preemption and local interrupts
+ * are disabled (plus previous interrupt state is saved), so the caller must
+ * not sleep, and is advised to release the hwspinlock as soon as possible.
+ *
+ * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
+ * busy after @timeout msecs). The function will never sleep.
+ */
+static inline int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock,
+ unsigned int to, unsigned long *flags)
+{
+ return __hwspin_lock_timeout(hwlock, to, HWLOCK_IRQSTATE, flags);
+}
+
+/**
+ * hwspin_lock_timeout_irq() - lock hwspinlock, with timeout, disable irqs
+ * @hwlock: the hwspinlock to be locked
+ * @to: timeout value in msecs
+ *
+ * This function locks the underlying @hwlock. If the @hwlock
+ * is already taken, the function will busy loop waiting for it to
+ * be released, but give up when @timeout msecs have elapsed.
+ *
+ * Upon a successful return from this function, preemption and local interrupts
+ * are disabled so the caller must not sleep, and is advised to release the
+ * hwspinlock as soon as possible.
+ *
+ * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
+ * busy after @timeout msecs). The function will never sleep.
+ */
+static inline
+int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int to)
+{
+ return __hwspin_lock_timeout(hwlock, to, HWLOCK_IRQ, NULL);
+}
+
+/**
+ * hwspin_lock_timeout() - lock an hwspinlock with timeout limit
+ * @hwlock: the hwspinlock to be locked
+ * @to: timeout value in msecs
+ *
+ * This function locks the underlying @hwlock. If the @hwlock
+ * is already taken, the function will busy loop waiting for it to
+ * be released, but give up when @timeout msecs have elapsed.
+ *
+ * Upon a successful return from this function, preemption is disabled
+ * so the caller must not sleep, and is advised to release the hwspinlock
+ * as soon as possible.
+ * This is required in order to minimize remote cores polling on the
+ * hardware interconnect.
+ *
+ * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
+ * busy after @timeout msecs). The function will never sleep.
+ */
+static inline
+int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to)
+{
+ return __hwspin_lock_timeout(hwlock, to, 0, NULL);
+}
+
+/**
+ * hwspin_unlock_irqrestore() - unlock hwspinlock, restore irq state
+ * @hwlock: a previously-acquired hwspinlock which we want to unlock
+ * @flags: previous caller's interrupt state to restore
+ *
+ * This function will unlock a specific hwspinlock, enable preemption and
+ * restore the previous state of the local interrupts. It should be used
+ * to undo, e.g., hwspin_trylock_irqsave().
+ *
+ * @hwlock must be already locked before calling this function: it is a bug
+ * to call unlock on a @hwlock that is already unlocked.
+ */
+static inline void hwspin_unlock_irqrestore(struct hwspinlock *hwlock,
+ unsigned long *flags)
+{
+ __hwspin_unlock(hwlock, HWLOCK_IRQSTATE, flags);
+}
+
+/**
+ * hwspin_unlock_irq() - unlock hwspinlock, enable interrupts
+ * @hwlock: a previously-acquired hwspinlock which we want to unlock
+ *
+ * This function will unlock a specific hwspinlock, enable preemption and
+ * enable local interrupts. Should be used to undo hwspin_lock_irq().
+ *
+ * @hwlock must be already locked (e.g. by hwspin_trylock_irq()) before
+ * calling this function: it is a bug to call unlock on a @hwlock that is
+ * already unlocked.
+ */
+static inline void hwspin_unlock_irq(struct hwspinlock *hwlock)
+{
+ __hwspin_unlock(hwlock, HWLOCK_IRQ, NULL);
+}
+
+/**
+ * hwspin_unlock() - unlock hwspinlock
+ * @hwlock: a previously-acquired hwspinlock which we want to unlock
+ *
+ * This function will unlock a specific hwspinlock and enable preemption
+ * back.
+ *
+ * @hwlock must be already locked (e.g. by hwspin_trylock()) before calling
+ * this function: it is a bug to call unlock on a @hwlock that is already
+ * unlocked.
+ */
+static inline void hwspin_unlock(struct hwspinlock *hwlock)
+{
+ __hwspin_unlock(hwlock, 0, NULL);
+}
+
+#endif /* __LINUX_HWSPINLOCK_H */
diff --git a/include/linux/i2c-tegra.h b/include/linux/i2c-tegra.h
new file mode 100644
index 000000000000..9c85da49857a
--- /dev/null
+++ b/include/linux/i2c-tegra.h
@@ -0,0 +1,25 @@
+/*
+ * drivers/i2c/busses/i2c-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_I2C_TEGRA_H
+#define _LINUX_I2C_TEGRA_H
+
+struct tegra_i2c_platform_data {
+ unsigned long bus_clk_rate;
+};
+
+#endif /* _LINUX_I2C_TEGRA_H */
diff --git a/include/linux/i2c/max6639.h b/include/linux/i2c/max6639.h
new file mode 100644
index 000000000000..6011c42034da
--- /dev/null
+++ b/include/linux/i2c/max6639.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_MAX6639_H
+#define _LINUX_MAX6639_H
+
+#include <linux/types.h>
+
+/* platform data for the MAX6639 temperature sensor and fan control */
+
+struct max6639_platform_data {
+ bool pwm_polarity; /* Polarity low (0) or high (1, default) */
+ int ppr; /* Pulses per rotation 1..4 (default == 2) */
+ int rpm_range; /* 2000, 4000 (default), 8000 or 16000 */
+};
+
+#endif /* _LINUX_MAX6639_H */
diff --git a/include/linux/i2c/pmbus.h b/include/linux/i2c/pmbus.h
new file mode 100644
index 000000000000..69280db02c41
--- /dev/null
+++ b/include/linux/i2c/pmbus.h
@@ -0,0 +1,45 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PMBUS_H_
+#define _PMBUS_H_
+
+/* flags */
+
+/*
+ * PMBUS_SKIP_STATUS_CHECK
+ *
+ * During register detection, skip checking the status register for
+ * communication or command errors.
+ *
+ * Some PMBus chips respond with valid data when trying to read an unsupported
+ * register. For such chips, checking the status register is mandatory when
+ * trying to determine if a chip register exists or not.
+ * Other PMBus chips don't support the STATUS_CML register, or report
+ * communication errors for no explicable reason. For such chips, checking
+ * the status register must be disabled.
+ */
+#define PMBUS_SKIP_STATUS_CHECK (1 << 0)
+
+struct pmbus_platform_data {
+ u32 flags; /* Device specific flags */
+};
+
+#endif /* _PMBUS_H_ */
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index a4bd05b7bd22..58afd9d2c438 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -639,7 +639,6 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
extern int twl4030_remove_script(u8 flags);
struct twl4030_codec_audio_data {
- unsigned int audio_mclk; /* not used, will be removed */
unsigned int digimic_delay; /* in ms */
unsigned int ramp_delay_value;
unsigned int offset_cncl_path;
@@ -650,7 +649,6 @@ struct twl4030_codec_audio_data {
};
struct twl4030_codec_vibra_data {
- unsigned int audio_mclk;
unsigned int coexist;
};
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b5021db21858..ab428552af8e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -43,6 +43,7 @@
#define KVM_REQ_DEACTIVATE_FPU 10
#define KVM_REQ_EVENT 11
#define KVM_REQ_APF_HALT 12
+#define KVM_REQ_NMI 13
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
@@ -98,23 +99,31 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu);
#endif
+enum {
+ OUTSIDE_GUEST_MODE,
+ IN_GUEST_MODE,
+ EXITING_GUEST_MODE
+};
+
struct kvm_vcpu {
struct kvm *kvm;
#ifdef CONFIG_PREEMPT_NOTIFIERS
struct preempt_notifier preempt_notifier;
#endif
+ int cpu;
int vcpu_id;
- struct mutex mutex;
- int cpu;
- atomic_t guest_mode;
- struct kvm_run *run;
+ int srcu_idx;
+ int mode;
unsigned long requests;
unsigned long guest_debug;
- int srcu_idx;
+
+ struct mutex mutex;
+ struct kvm_run *run;
int fpu_active;
int guest_fpu_loaded, guest_xcr0_loaded;
wait_queue_head_t wq;
+ struct pid *pid;
int sigset_active;
sigset_t sigset;
struct kvm_vcpu_stat stat;
@@ -140,6 +149,11 @@ struct kvm_vcpu {
struct kvm_vcpu_arch arch;
};
+static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
+{
+ return cmpxchg(&vcpu->mode, IN_GUEST_MODE, EXITING_GUEST_MODE);
+}
+
/*
* Some of the bitops functions do not support too long bitmaps.
* This number must be determined not to exceed such limits.
@@ -212,7 +226,6 @@ struct kvm_memslots {
struct kvm {
spinlock_t mmu_lock;
- raw_spinlock_t requests_lock;
struct mutex slots_lock;
struct mm_struct *mm; /* userspace tied to this vm */
struct kvm_memslots *memslots;
@@ -223,6 +236,7 @@ struct kvm {
#endif
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
atomic_t online_vcpus;
+ int last_boosted_vcpu;
struct list_head vm_list;
struct mutex lock;
struct kvm_io_bus *buses[KVM_NR_BUSES];
@@ -719,11 +733,6 @@ static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
set_bit(req, &vcpu->requests);
}
-static inline bool kvm_make_check_request(int req, struct kvm_vcpu *vcpu)
-{
- return test_and_set_bit(req, &vcpu->requests);
-}
-
static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu)
{
if (test_bit(req, &vcpu->requests)) {
diff --git a/include/linux/mfd/ti_ssp.h b/include/linux/mfd/ti_ssp.h
new file mode 100644
index 000000000000..dbb4b43bd20e
--- /dev/null
+++ b/include/linux/mfd/ti_ssp.h
@@ -0,0 +1,93 @@
+/*
+ * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __TI_SSP_H__
+#define __TI_SSP_H__
+
+struct ti_ssp_dev_data {
+ const char *dev_name;
+ void *pdata;
+ size_t pdata_size;
+};
+
+struct ti_ssp_data {
+ unsigned long out_clock;
+ struct ti_ssp_dev_data dev_data[2];
+};
+
+struct ti_ssp_spi_data {
+ unsigned long iosel;
+ int num_cs;
+ void (*select)(int cs);
+};
+
+/*
+ * Sequencer port IO pin configuration bits. These do not correlate 1-1 with
+ * the hardware. The iosel field in the port data combines iosel1 and iosel2,
+ * and is therefore not a direct map to register space. It is best to use the
+ * macros below to construct iosel values.
+ *
+ * least significant 16 bits --> iosel1
+ * most significant 16 bits --> iosel2
+ */
+
+#define SSP_IN 0x0000
+#define SSP_DATA 0x0001
+#define SSP_CLOCK 0x0002
+#define SSP_CHIPSEL 0x0003
+#define SSP_OUT 0x0004
+#define SSP_PIN_SEL(pin, v) ((v) << ((pin) * 3))
+#define SSP_PIN_MASK(pin) SSP_PIN_SEL(pin, 0x7)
+#define SSP_INPUT_SEL(pin) ((pin) << 16)
+
+/* Sequencer port config bits */
+#define SSP_EARLY_DIN BIT(8)
+#define SSP_DELAY_DOUT BIT(9)
+
+/* Sequence map definitions */
+#define SSP_CLK_HIGH BIT(0)
+#define SSP_CLK_LOW 0
+#define SSP_DATA_HIGH BIT(1)
+#define SSP_DATA_LOW 0
+#define SSP_CS_HIGH BIT(2)
+#define SSP_CS_LOW 0
+#define SSP_OUT_MODE BIT(3)
+#define SSP_IN_MODE 0
+#define SSP_DATA_REG BIT(4)
+#define SSP_ADDR_REG 0
+
+#define SSP_OPCODE_DIRECT ((0x0) << 5)
+#define SSP_OPCODE_TOGGLE ((0x1) << 5)
+#define SSP_OPCODE_SHIFT ((0x2) << 5)
+#define SSP_OPCODE_BRANCH0 ((0x4) << 5)
+#define SSP_OPCODE_BRANCH1 ((0x5) << 5)
+#define SSP_OPCODE_BRANCH ((0x6) << 5)
+#define SSP_OPCODE_STOP ((0x7) << 5)
+#define SSP_BRANCH(addr) ((addr) << 8)
+#define SSP_COUNT(cycles) ((cycles) << 8)
+
+int ti_ssp_raw_read(struct device *dev);
+int ti_ssp_raw_write(struct device *dev, u32 val);
+int ti_ssp_load(struct device *dev, int offs, u32* prog, int len);
+int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output);
+int ti_ssp_set_mode(struct device *dev, int mode);
+int ti_ssp_set_iosel(struct device *dev, u32 iosel);
+
+#endif /* __TI_SSP_H__ */
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h
index 9eab263658be..466b1c777aff 100644
--- a/include/linux/mfd/wm8994/pdata.h
+++ b/include/linux/mfd/wm8994/pdata.h
@@ -103,13 +103,21 @@ struct wm8994_pdata {
unsigned int lineout1fb:1;
unsigned int lineout2fb:1;
- /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
+ /* IRQ for microphone detection if brought out directly as a
+ * signal.
+ */
+ int micdet_irq;
+
+ /* WM8994 microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
unsigned int micbias1_lvl:1;
unsigned int micbias2_lvl:1;
- /* Jack detect threashold levels, see datasheet for values */
+ /* WM8994 jack detect threashold levels, see datasheet for values */
unsigned int jd_scthr:2;
unsigned int jd_thr:2;
+
+ /* WM8958 microphone bias configuration */
+ int micbias[2];
};
#endif
diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h
index be072faec6f0..f3ee84284670 100644
--- a/include/linux/mfd/wm8994/registers.h
+++ b/include/linux/mfd/wm8994/registers.h
@@ -63,6 +63,8 @@
#define WM8994_MICBIAS 0x3A
#define WM8994_LDO_1 0x3B
#define WM8994_LDO_2 0x3C
+#define WM8958_MICBIAS1 0x3D
+#define WM8958_MICBIAS2 0x3E
#define WM8994_CHARGE_PUMP_1 0x4C
#define WM8958_CHARGE_PUMP_2 0x4D
#define WM8994_CLASS_W_1 0x51
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 679300c050f5..581703d86fbd 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -402,16 +402,23 @@ static inline void init_page_count(struct page *page)
/*
* PageBuddy() indicate that the page is free and in the buddy system
* (see mm/page_alloc.c).
+ *
+ * PAGE_BUDDY_MAPCOUNT_VALUE must be <= -2 but better not too close to
+ * -2 so that an underflow of the page_mapcount() won't be mistaken
+ * for a genuine PAGE_BUDDY_MAPCOUNT_VALUE. -128 can be created very
+ * efficiently by most CPU architectures.
*/
+#define PAGE_BUDDY_MAPCOUNT_VALUE (-128)
+
static inline int PageBuddy(struct page *page)
{
- return atomic_read(&page->_mapcount) == -2;
+ return atomic_read(&page->_mapcount) == PAGE_BUDDY_MAPCOUNT_VALUE;
}
static inline void __SetPageBuddy(struct page *page)
{
VM_BUG_ON(atomic_read(&page->_mapcount) != -1);
- atomic_set(&page->_mapcount, -2);
+ atomic_set(&page->_mapcount, PAGE_BUDDY_MAPCOUNT_VALUE);
}
static inline void __ClearPageBuddy(struct page *page)
@@ -965,6 +972,10 @@ static inline int handle_mm_fault(struct mm_struct *mm,
extern int make_pages_present(unsigned long addr, unsigned long end);
extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
+int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, int len, unsigned int foll_flags,
+ struct page **pages, struct vm_area_struct **vmas,
+ int *nonblocking);
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
unsigned long start, int nr_pages, int write, int force,
struct page **pages, struct vm_area_struct **vmas);
@@ -1528,6 +1539,7 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address,
#define FOLL_FORCE 0x10 /* get_user_pages read/write w/o permission */
#define FOLL_MLOCK 0x40 /* mark page as mlocked */
#define FOLL_SPLIT 0x80 /* don't return transhuge pages, split them */
+#define FOLL_HWPOISON 0x100 /* check page is hwpoisoned */
typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
void *data);
@@ -1620,14 +1632,6 @@ extern int sysctl_memory_failure_recovery;
extern void shake_page(struct page *p, int access);
extern atomic_long_t mce_bad_pages;
extern int soft_offline_page(struct page *page, int flags);
-#ifdef CONFIG_MEMORY_FAILURE
-int is_hwpoison_address(unsigned long addr);
-#else
-static inline int is_hwpoison_address(unsigned long addr)
-{
- return 0;
-}
-#endif
extern void dump_page(struct page *page);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 02ecb0189b1d..e56f835274c9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -472,7 +472,7 @@ static inline int zone_is_oom_locked(const struct zone *zone)
#ifdef CONFIG_NUMA
/*
- * The NUMA zonelists are doubled becausse we need zonelists that restrict the
+ * The NUMA zonelists are doubled because we need zonelists that restrict the
* allocations to a single node for GFP_THISNODE.
*
* [0] : Zonelist with fallback
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index d11fe0f2f956..fe722c1fb61d 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -32,6 +32,7 @@ enum {
MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planar w/ Cr is in MSB */
MDP_RGBA_8888, /* ARGB 888 */
MDP_BGRA_8888, /* ABGR 888 */
+ MDP_RGBX_8888, /* RGBX 888 */
MDP_IMGTYPE_LIMIT /* Non valid image type after this enum */
};
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index cd6f3b431195..d60130f88eed 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -168,6 +168,7 @@
#define ONENAND_SYS_CFG1_INT (1 << 6)
#define ONENAND_SYS_CFG1_IOBE (1 << 5)
#define ONENAND_SYS_CFG1_RDY_CONF (1 << 4)
+#define ONENAND_SYS_CFG1_VHF (1 << 3)
#define ONENAND_SYS_CFG1_HF (1 << 2)
#define ONENAND_SYS_CFG1_SYNC_WRITE (1 << 1)
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index b31bd9e9bca3..84854edf4436 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -116,18 +116,40 @@ struct ubi_volume_info {
* struct ubi_device_info - UBI device description data structure.
* @ubi_num: ubi device number
* @leb_size: logical eraseblock size on this UBI device
+ * @leb_start: starting offset of logical eraseblocks within physical
+ * eraseblocks
* @min_io_size: minimal I/O unit size
+ * @max_write_size: maximum amount of bytes the underlying flash can write at a
+ * time (MTD write buffer size)
* @ro_mode: if this device is in read-only mode
* @cdev: UBI character device major and minor numbers
*
* Note, @leb_size is the logical eraseblock size offered by the UBI device.
* Volumes of this UBI device may have smaller logical eraseblock size if their
* alignment is not equivalent to %1.
+ *
+ * The @max_write_size field describes flash write maximum write unit. For
+ * example, NOR flash allows for changing individual bytes, so @min_io_size is
+ * %1. However, it does not mean than NOR flash has to write data byte-by-byte.
+ * Instead, CFI NOR flashes have a write-buffer of, e.g., 64 bytes, and when
+ * writing large chunks of data, they write 64-bytes at a time. Obviously, this
+ * improves write throughput.
+ *
+ * Also, the MTD device may have N interleaved (striped) flash chips
+ * underneath, in which case @min_io_size can be physical min. I/O size of
+ * single flash chip, while @max_write_size can be N * @min_io_size.
+ *
+ * The @max_write_size field is always greater or equivalent to @min_io_size.
+ * E.g., some NOR flashes may have (@min_io_size = 1, @max_write_size = 64). In
+ * contrast, NAND flashes usually have @min_io_size = @max_write_size = NAND
+ * page size.
*/
struct ubi_device_info {
int ubi_num;
int leb_size;
+ int leb_start;
int min_io_size;
+ int max_write_size;
int ro_mode;
dev_t cdev;
};
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 9c8603872c36..eba45ea10298 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -85,7 +85,7 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
extern int follow_down_one(struct path *);
-extern int follow_down(struct path *, bool);
+extern int follow_down(struct path *);
extern int follow_up(struct path *);
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 6023efa9f5d9..f88522b10a38 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -501,7 +501,7 @@ extern int nfs_writepage(struct page *page, struct writeback_control *wbc);
extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
-extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
+extern void nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
/*
* Try to write back everything synchronously (but check the
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 3e112de12d8d..216cea5db0aa 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -30,6 +30,8 @@ struct nfs_client {
#define NFS_CS_CALLBACK 1 /* - callback started */
#define NFS_CS_IDMAP 2 /* - idmap started */
#define NFS_CS_RENEWD 3 /* - renewd started */
+#define NFS_CS_STOP_RENEW 4 /* no more state to renew */
+#define NFS_CS_CHECK_LEASE_TIME 5 /* need to check lease time */
struct sockaddr_storage cl_addr; /* server identifier */
size_t cl_addrlen;
char * cl_hostname; /* hostname of server */
@@ -75,7 +77,6 @@ struct nfs_client {
u32 cl_exchange_flags;
struct nfs4_session *cl_session; /* sharred session */
struct list_head cl_layouts;
- struct pnfs_deviceid_cache *cl_devid_cache; /* pNFS deviceid cache */
#endif /* CONFIG_NFS_V4 */
#ifdef CONFIG_NFS_FSCACHE
@@ -176,6 +177,7 @@ struct nfs_server {
#define NFS_CAP_CTIME (1U << 12)
#define NFS_CAP_MTIME (1U << 13)
#define NFS_CAP_POSIX_LOCK (1U << 14)
+#define NFS_CAP_UIDGID_NOMAP (1U << 15)
/* maximum number of slots to use */
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h
index e8352dc5afb5..ae7d6a380dae 100644
--- a/include/linux/nfs_idmap.h
+++ b/include/linux/nfs_idmap.h
@@ -65,6 +65,7 @@ struct idmap_msg {
/* Forward declaration to make this header independent of others */
struct nfs_client;
+struct nfs_server;
#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
@@ -96,10 +97,10 @@ void nfs_idmap_delete(struct nfs_client *);
#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */
-int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *);
-int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *);
-int nfs_map_uid_to_name(struct nfs_client *, __u32, char *, size_t);
-int nfs_map_gid_to_group(struct nfs_client *, __u32, char *, size_t);
+int nfs_map_name_to_uid(const struct nfs_server *, const char *, size_t, __u32 *);
+int nfs_map_group_to_gid(const struct nfs_server *, const char *, size_t, __u32 *);
+int nfs_map_uid_to_name(const struct nfs_server *, __u32, char *, size_t);
+int nfs_map_gid_to_group(const struct nfs_server *, __u32, char *, size_t);
extern unsigned int nfs_idmap_cache_timeout;
#endif /* __KERNEL__ */
diff --git a/include/linux/nfs_iostat.h b/include/linux/nfs_iostat.h
index 68b10f5f8907..8866bb3502ee 100644
--- a/include/linux/nfs_iostat.h
+++ b/include/linux/nfs_iostat.h
@@ -113,6 +113,8 @@ enum nfs_stat_eventcounters {
NFSIOS_SHORTREAD,
NFSIOS_SHORTWRITE,
NFSIOS_DELAY,
+ NFSIOS_PNFS_READ,
+ NFSIOS_PNFS_WRITE,
__NFSIOS_COUNTSMAX,
};
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index d55cee73f634..90907ada6d52 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -59,9 +59,11 @@ struct nfs_pageio_descriptor {
unsigned int pg_base;
struct inode *pg_inode;
- int (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
+ int (*pg_doio)(struct nfs_pageio_descriptor *);
int pg_ioflags;
int pg_error;
+ struct pnfs_layout_segment *pg_lseg;
+ int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
};
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
@@ -79,7 +81,7 @@ extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
pgoff_t idx_start, unsigned int npages, int tag);
extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
struct inode *inode,
- int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+ int (*doio)(struct nfs_pageio_descriptor *desc),
size_t bsize,
int how);
extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index b0068579bec2..2c2c67d2eb42 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1016,9 +1016,12 @@ struct nfs_read_data {
unsigned int npages; /* Max length of pagevec */
struct nfs_readargs args;
struct nfs_readres res;
-#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
-#endif
+ struct pnfs_layout_segment *lseg;
+ struct nfs_client *ds_clp; /* pNFS data server */
+ const struct rpc_call_ops *mds_ops;
+ int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);
+ __u64 mds_offset;
struct page *page_array[NFS_PAGEVEC_SIZE];
};
@@ -1035,13 +1038,20 @@ struct nfs_write_data {
unsigned int npages; /* Max length of pagevec */
struct nfs_writeargs args; /* argument struct */
struct nfs_writeres res; /* result struct */
+ struct pnfs_layout_segment *lseg;
+ struct nfs_client *ds_clp; /* pNFS data server */
+ const struct rpc_call_ops *mds_ops;
+ int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data);
#ifdef CONFIG_NFS_V4
unsigned long timestamp; /* For lease renewal */
#endif
+ __u64 mds_offset; /* Filelayout dense stripe */
struct page *page_array[NFS_PAGEVEC_SIZE];
};
struct nfs_access_entry;
+struct nfs_client;
+struct rpc_timeout;
/*
* RPC procedure vector for NFSv2/NFSv3 demuxing
@@ -1106,6 +1116,8 @@ struct nfs_rpc_ops {
struct nfs_open_context *ctx,
int open_flags,
struct iattr *iattr);
+ int (*init_client) (struct nfs_client *, const struct rpc_timeout *,
+ const char *, rpc_authflavor_t, int);
};
/*
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 1ca64113efe8..7f5cfd3b37dd 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -106,6 +106,13 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event);
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel);
+/**
+ * Add an hardware sample.
+ */
+void oprofile_add_ext_hw_sample(unsigned long pc, struct pt_regs * const regs,
+ unsigned long event, int is_kernel,
+ struct task_struct *task);
+
/* Use this instead when the PC value is not from the regs. Doesn't
* backtrace. */
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 580de67f318b..511e5ee809ef 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -517,7 +517,7 @@
#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302
#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303
#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304
-#define PCI_DEVICE_ID_AMD_15H_NB_MISC 0x1603
+#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603
#define PCI_DEVICE_ID_AMD_15H_NB_LINK 0x1604
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
@@ -2079,6 +2079,8 @@
#define PCI_DEVICE_ID_TIGON3_5723 0x165b
#define PCI_DEVICE_ID_TIGON3_5705M 0x165d
#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
+#define PCI_DEVICE_ID_NX2_57712 0x1662
+#define PCI_DEVICE_ID_NX2_57712E 0x1663
#define PCI_DEVICE_ID_TIGON3_5714 0x1668
#define PCI_DEVICE_ID_TIGON3_5714S 0x1669
#define PCI_DEVICE_ID_TIGON3_5780 0x166a
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 614615b8d42b..f495c0147240 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -878,8 +878,8 @@ enum perf_event_context_type {
* Used as a container for task events and CPU events as well:
*/
struct perf_event_context {
- enum perf_event_context_type type;
struct pmu *pmu;
+ enum perf_event_context_type type;
/*
* Protect the states of the events in the list,
* nr_active, and the list:
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index ef9476a36ff7..db7bcaf7c5bd 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -129,6 +129,7 @@ struct rpc_create_args {
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
struct rpc_program *, u32);
+void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index bef0f535f746..a0f998c07c65 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -12,7 +12,6 @@
#include <linux/uio.h>
#include <linux/socket.h>
#include <linux/in.h>
-#include <linux/kref.h>
#include <linux/ktime.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h>
@@ -146,7 +145,7 @@ enum xprt_transports {
};
struct rpc_xprt {
- struct kref kref; /* Reference count */
+ atomic_t count; /* Reference count */
struct rpc_xprt_ops * ops; /* transport methods */
const struct rpc_timeout *timeout; /* timeout parms */
diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h
index 185015dd1166..f7751d53f1d3 100644
--- a/include/scsi/fc/fc_ns.h
+++ b/include/scsi/fc/fc_ns.h
@@ -41,6 +41,7 @@ enum fc_ns_req {
FC_NS_GI_A = 0x0101, /* get identifiers - scope */
FC_NS_GPN_ID = 0x0112, /* get port name by ID */
FC_NS_GNN_ID = 0x0113, /* get node name by ID */
+ FC_NS_GSPN_ID = 0x0118, /* get symbolic port name */
FC_NS_GID_PN = 0x0121, /* get ID for port name */
FC_NS_GID_NN = 0x0131, /* get IDs for node name */
FC_NS_GID_FT = 0x0171, /* get IDs by FC4 type */
@@ -144,7 +145,7 @@ struct fc_ns_gid_pn {
};
/*
- * GID_PN response
+ * GID_PN response or GSPN_ID request
*/
struct fc_gid_pn_resp {
__u8 fp_resvd;
@@ -152,6 +153,14 @@ struct fc_gid_pn_resp {
};
/*
+ * GSPN_ID response
+ */
+struct fc_gspn_resp {
+ __u8 fp_name_len;
+ char fp_name[];
+};
+
+/*
* RFT_ID request - register FC-4 types for ID.
*/
struct fc_ns_rft_id {
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 6d293c846a46..be418d8448a5 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -46,16 +46,11 @@ struct fc_ct_req {
} payload;
};
-/**
- * fill FC header fields in specified fc_frame
- */
-static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
- u32 did, u32 sid, enum fc_fh_type type,
- u32 f_ctl, u32 parm_offset)
+static inline void __fc_fill_fc_hdr(struct fc_frame_header *fh,
+ enum fc_rctl r_ctl,
+ u32 did, u32 sid, enum fc_fh_type type,
+ u32 f_ctl, u32 parm_offset)
{
- struct fc_frame_header *fh;
-
- fh = fc_frame_header_get(fp);
WARN_ON(r_ctl == 0);
fh->fh_r_ctl = r_ctl;
hton24(fh->fh_d_id, did);
@@ -68,6 +63,19 @@ static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
}
/**
+ * fill FC header fields in specified fc_frame
+ */
+static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
+ u32 did, u32 sid, enum fc_fh_type type,
+ u32 f_ctl, u32 parm_offset)
+{
+ struct fc_frame_header *fh;
+
+ fh = fc_frame_header_get(fp);
+ __fc_fill_fc_hdr(fh, r_ctl, did, sid, type, f_ctl, parm_offset);
+}
+
+/**
* fc_adisc_fill() - Fill in adisc request frame
* @lport: local port.
* @fp: fc frame where payload will be placed.
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index f53c8e31d5fb..24193c1b0da0 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -35,6 +35,8 @@
#include <scsi/fc_frame.h>
+#define FC_FC4_PROV_SIZE (FC_TYPE_FCP + 1) /* size of tables */
+
/*
* libfc error codes
*/
@@ -156,6 +158,7 @@ struct fc_rport_libfc_priv {
#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
#define FC_RP_FLAGS_RETRY (1 << 1)
#define FC_RP_STARTED (1 << 2)
+ #define FC_RP_FLAGS_CONF_REQ (1 << 3)
unsigned int e_d_tov;
unsigned int r_a_tov;
};
@@ -179,6 +182,7 @@ struct fc_rport_libfc_priv {
* @rp_mutex: The mutex that protects the remote port
* @retry_work: Handle for retries
* @event_callback: Callback when READY, FAILED or LOGO states complete
+ * @prli_count: Count of open PRLI sessions in providers
* @rcu: Structure used for freeing in an RCU-safe manner
*/
struct fc_rport_priv {
@@ -202,7 +206,13 @@ struct fc_rport_priv {
struct list_head peers;
struct work_struct event_work;
u32 supported_classes;
+ u16 prli_count;
struct rcu_head rcu;
+ u16 sp_features;
+ u8 spp_type;
+ void (*lld_event_callback)(struct fc_lport *,
+ struct fc_rport_priv *,
+ enum fc_rport_event);
};
/**
@@ -551,6 +561,16 @@ struct libfc_function_template {
struct fc_seq *(*seq_start_next)(struct fc_seq *);
/*
+ * Set a response handler for the exchange of the sequence.
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*seq_set_resp)(struct fc_seq *sp,
+ void (*resp)(struct fc_seq *, struct fc_frame *,
+ void *),
+ void *arg);
+
+ /*
* Assign a sequence for an incoming request frame.
*
* STATUS: OPTIONAL
@@ -558,6 +578,13 @@ struct libfc_function_template {
struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *);
/*
+ * Release the reference on the sequence returned by seq_assign().
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*seq_release)(struct fc_seq *);
+
+ /*
* Reset an exchange manager, completing all sequences and exchanges.
* If s_id is non-zero, reset only exchanges originating from that FID.
* If d_id is non-zero, reset only exchanges sending to that FID.
@@ -656,6 +683,15 @@ struct libfc_function_template {
void (*rport_destroy)(struct kref *);
/*
+ * Callback routine after the remote port is logged in
+ *
+ * STATUS: OPTIONAL
+ */
+ void (*rport_event_callback)(struct fc_lport *,
+ struct fc_rport_priv *,
+ enum fc_rport_event);
+
+ /*
* Send a fcp cmd from fsp pkt.
* Called with the SCSI host lock unlocked and irqs disabled.
*
@@ -749,6 +785,15 @@ struct fc_disc {
enum fc_disc_event);
};
+/*
+ * Local port notifier and events.
+ */
+extern struct blocking_notifier_head fc_lport_notifier_head;
+enum fc_lport_event {
+ FC_LPORT_EV_ADD,
+ FC_LPORT_EV_DEL,
+};
+
/**
* struct fc_lport - Local port
* @host: The SCSI host associated with a local port
@@ -789,8 +834,10 @@ struct fc_disc {
* @lso_max: The maximum large offload send size
* @fcts: FC-4 type mask
* @lp_mutex: Mutex to protect the local port
- * @list: Handle for list of local ports
+ * @list: Linkage on list of vport peers
* @retry_work: Handle to local port for delayed retry context
+ * @prov: Pointers available for use by passive FC-4 providers
+ * @lport_list: Linkage on module-wide list of local ports
*/
struct fc_lport {
/* Associations */
@@ -846,8 +893,32 @@ struct fc_lport {
struct mutex lp_mutex;
struct list_head list;
struct delayed_work retry_work;
+ void *prov[FC_FC4_PROV_SIZE];
+ struct list_head lport_list;
};
+/**
+ * struct fc4_prov - FC-4 provider registration
+ * @prli: Handler for incoming PRLI
+ * @prlo: Handler for session reset
+ * @recv: Handler for incoming request
+ * @module: Pointer to module. May be NULL.
+ */
+struct fc4_prov {
+ int (*prli)(struct fc_rport_priv *, u32 spp_len,
+ const struct fc_els_spp *spp_in,
+ struct fc_els_spp *spp_out);
+ void (*prlo)(struct fc_rport_priv *);
+ void (*recv)(struct fc_lport *, struct fc_frame *);
+ struct module *module;
+};
+
+/*
+ * Register FC-4 provider with libfc.
+ */
+int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *);
+void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *);
+
/*
* FC_LPORT HELPER FUNCTIONS
*****************************/
@@ -978,6 +1049,7 @@ struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
int fc_lport_bsg_request(struct fc_bsg_job *);
void fc_lport_set_local_id(struct fc_lport *, u32 port_id);
+void fc_lport_iterate(void (*func)(struct fc_lport *, void *), void *);
/*
* REMOTE PORT LAYER
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index feb6a94c90ea..8c1638b8c28e 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -33,6 +33,12 @@
#define FCOE_MAX_CMD_LEN 16 /* Supported CDB length */
/*
+ * Max MTU for FCoE: 14 (FCoE header) + 24 (FC header) + 2112 (max FC payload)
+ * + 4 (FC CRC) + 4 (FCoE trailer) = 2158 bytes
+ */
+#define FCOE_MTU 2158
+
+/*
* FIP tunable parameters.
*/
#define FCOE_CTLR_START_DELAY 2000 /* mS after first adv. to choose FCF */
@@ -221,6 +227,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *,
u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *,
const struct libfc_function_template *, int init_fcp);
+u32 fcoe_fc_crc(struct fc_frame *fp);
+int fcoe_start_io(struct sk_buff *skb);
/**
* is_fip_mode() - returns true if FIP mode selected.
@@ -231,5 +239,102 @@ static inline bool is_fip_mode(struct fcoe_ctlr *fip)
return fip->state == FIP_ST_ENABLED;
}
+/* helper for FCoE SW HBA drivers, can include subven and subdev if needed. The
+ * modpost would use pci_device_id table to auto-generate formatted module alias
+ * into the corresponding .mod.c file, but there may or may not be a pci device
+ * id table for FCoE drivers so we use the following helper for build the fcoe
+ * driver module alias.
+ */
+#define MODULE_ALIAS_FCOE_PCI(ven, dev) \
+ MODULE_ALIAS("fcoe-pci:" \
+ "v" __stringify(ven) \
+ "d" __stringify(dev) "sv*sd*bc*sc*i*")
+
+/* the name of the default FCoE transport driver fcoe.ko */
+#define FCOE_TRANSPORT_DEFAULT "fcoe"
+
+/* struct fcoe_transport - The FCoE transport interface
+ * @name: a vendor specific name for their FCoE transport driver
+ * @attached: whether this transport is already attached
+ * @list: list linkage to all attached transports
+ * @match: handler to allow the transport driver to match up a given netdev
+ * @create: handler to sysfs entry of create for FCoE instances
+ * @destroy: handler to sysfs entry of destroy for FCoE instances
+ * @enable: handler to sysfs entry of enable for FCoE instances
+ * @disable: handler to sysfs entry of disable for FCoE instances
+ */
+struct fcoe_transport {
+ char name[IFNAMSIZ];
+ bool attached;
+ struct list_head list;
+ bool (*match) (struct net_device *device);
+ int (*create) (struct net_device *device, enum fip_state fip_mode);
+ int (*destroy) (struct net_device *device);
+ int (*enable) (struct net_device *device);
+ int (*disable) (struct net_device *device);
+};
+
+/**
+ * struct fcoe_percpu_s - The context for FCoE receive thread(s)
+ * @thread: The thread context
+ * @fcoe_rx_list: The queue of pending packets to process
+ * @page: The memory page for calculating frame trailer CRCs
+ * @crc_eof_offset: The offset into the CRC page pointing to available
+ * memory for a new trailer
+ */
+struct fcoe_percpu_s {
+ struct task_struct *thread;
+ struct sk_buff_head fcoe_rx_list;
+ struct page *crc_eof_page;
+ int crc_eof_offset;
+};
+
+/**
+ * struct fcoe_port - The FCoE private structure
+ * @priv: The associated fcoe interface. The structure is
+ * defined by the low level driver
+ * @lport: The associated local port
+ * @fcoe_pending_queue: The pending Rx queue of skbs
+ * @fcoe_pending_queue_active: Indicates if the pending queue is active
+ * @max_queue_depth: Max queue depth of pending queue
+ * @min_queue_depth: Min queue depth of pending queue
+ * @timer: The queue timer
+ * @destroy_work: Handle for work context
+ * (to prevent RTNL deadlocks)
+ * @data_srt_addr: Source address for data
+ *
+ * An instance of this structure is to be allocated along with the
+ * Scsi_Host and libfc fc_lport structures.
+ */
+struct fcoe_port {
+ void *priv;
+ struct fc_lport *lport;
+ struct sk_buff_head fcoe_pending_queue;
+ u8 fcoe_pending_queue_active;
+ u32 max_queue_depth;
+ u32 min_queue_depth;
+ struct timer_list timer;
+ struct work_struct destroy_work;
+ u8 data_src_addr[ETH_ALEN];
+};
+void fcoe_clean_pending_queue(struct fc_lport *);
+void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb);
+void fcoe_queue_timer(ulong lport);
+int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen,
+ struct fcoe_percpu_s *fps);
+
+/**
+ * struct netdev_list
+ * A mapping from netdevice to fcoe_transport
+ */
+struct fcoe_netdev_mapping {
+ struct list_head list;
+ struct net_device *netdev;
+ struct fcoe_transport *ft;
+};
+
+/* fcoe transports registration and deregistration */
+int fcoe_transport_attach(struct fcoe_transport *ft);
+int fcoe_transport_detach(struct fcoe_transport *ft);
#endif /* _LIBFCOE_H */
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 748382b32b52..0f4367751b71 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -212,9 +212,6 @@ struct iscsi_conn {
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
- /* remote portal currently connected to */
- int portal_port;
- char portal_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
@@ -319,9 +316,6 @@ struct iscsi_host {
/* hw address or netdev iscsi connection is bound to */
char *hwaddress;
char *netdev;
- /* local address */
- int local_port;
- char local_address[ISCSI_ADDRESS_BUF_LEN];
wait_queue_head_t session_removal_wq;
/* protects sessions and state */
@@ -394,6 +388,8 @@ extern void iscsi_session_failure(struct iscsi_session *session,
enum iscsi_err err);
extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf);
+extern int iscsi_conn_get_addr_param(struct sockaddr_storage *addr,
+ enum iscsi_param param, char *buf);
extern void iscsi_suspend_tx(struct iscsi_conn *conn);
extern void iscsi_suspend_queue(struct iscsi_conn *conn);
extern void iscsi_conn_queue_work(struct iscsi_conn *conn);
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index b76d4006e36d..3668903e397b 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -435,6 +435,10 @@ static inline int scsi_is_wlun(unsigned int lun)
* recover the link. Transport class will
* retry or fail IO */
#define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */
+#define DID_TARGET_FAILURE 0x10 /* Permanent target failure, do not retry on
+ * other paths */
+#define DID_NEXUS_FAILURE 0x11 /* Permanent nexus failure, retry on other
+ * paths might yield different results */
#define DRIVER_OK 0x00 /* Driver status */
/*
@@ -464,6 +468,7 @@ static inline int scsi_is_wlun(unsigned int lun)
#define TIMEOUT_ERROR 0x2007
#define SCSI_RETURN_NOT_HANDLED 0x2008
#define FAST_IO_FAIL 0x2009
+#define TARGET_ERROR 0x200A
/*
* Midlevel queue return values.
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 85867dcde335..f171c65dc5a8 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -184,6 +184,7 @@ typedef void (*activate_complete)(void *, int);
struct scsi_device_handler {
/* Used by the infrastructure */
struct list_head list; /* list of scsi_device_handlers */
+ int idx;
/* Filled by the hardware handler */
struct module *module;
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 7fff94b3b2a8..bf8f52965675 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -101,6 +101,8 @@ struct iscsi_transport {
void (*destroy_conn) (struct iscsi_cls_conn *conn);
int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param,
char *buf, int buflen);
+ int (*get_ep_param) (struct iscsi_endpoint *ep, enum iscsi_param param,
+ char *buf);
int (*get_conn_param) (struct iscsi_cls_conn *conn,
enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
@@ -160,8 +162,9 @@ struct iscsi_cls_conn {
void *dd_data; /* LLD private data */
struct iscsi_transport *transport;
uint32_t cid; /* connection id */
+ struct mutex ep_mutex;
+ struct iscsi_endpoint *ep;
- int active; /* must be accessed with the connlock */
struct device dev; /* sysfs transport/container device */
};
@@ -222,6 +225,7 @@ struct iscsi_endpoint {
void *dd_data; /* LLD private data */
struct device dev;
uint64_t id;
+ struct iscsi_cls_conn *conn;
};
/*
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index b602f475cdbb..f1dcefe4532b 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -96,6 +96,10 @@
#define AC97_FUNC_INFO 0x68 /* Function Information */
#define AC97_SENSE_INFO 0x6a /* Sense Details */
+/* volume controls */
+#define AC97_MUTE_MASK_MONO 0x8000
+#define AC97_MUTE_MASK_STEREO 0x8080
+
/* slot allocation */
#define AC97_SLOT_TAG 0
#define AC97_SLOT_CMD_ADDR 1
@@ -138,6 +142,7 @@
#define AC97_BC_18BIT_ADC 0x0100 /* 18-bit ADC resolution */
#define AC97_BC_20BIT_ADC 0x0200 /* 20-bit ADC resolution */
#define AC97_BC_ADC_MASK 0x0300
+#define AC97_BC_3D_TECH_ID_MASK 0x7c00 /* Per-vendor ID of 3D enhancement */
/* general purpose */
#define AC97_GP_DRSS_MASK 0x0c00 /* double rate slot select */
diff --git a/include/sound/control.h b/include/sound/control.h
index 7715e6f00d38..e67db2869360 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -115,6 +115,8 @@ int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
+int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
+ int active);
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
diff --git a/include/sound/cs4271.h b/include/sound/cs4271.h
new file mode 100644
index 000000000000..50a059e7d116
--- /dev/null
+++ b/include/sound/cs4271.h
@@ -0,0 +1,24 @@
+/*
+ * Definitions for CS4271 ASoC codec driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CS4271_H
+#define __CS4271_H
+
+struct cs4271_platform_data {
+ int gpio_nreset; /* GPIO driving Reset pin, if any */
+};
+
+#endif /* __CS4271_H */
diff --git a/include/sound/hdspm.h b/include/sound/hdspm.h
index 81990b2bcc98..1774ff5ff632 100644
--- a/include/sound/hdspm.h
+++ b/include/sound/hdspm.h
@@ -3,8 +3,8 @@
/*
* Copyright (C) 2003 Winfried Ritsch (IEM)
* based on hdsp.h from Thomas Charbonnel (thomas@undata.org)
- *
- *
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -23,50 +23,41 @@
/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
#define HDSPM_MAX_CHANNELS 64
-/* -------------------- IOCTL Peak/RMS Meters -------------------- */
-
-/* peam rms level structure like we get from hardware
-
- maybe in future we can memory map it so I just copy it
- to user on ioctl call now an dont change anything
- rms are made out of low and high values
- where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24)
- (i asume so from the code)
-*/
-
-struct hdspm_peak_rms {
-
- unsigned int level_offset[1024];
+enum hdspm_io_type {
+ MADI,
+ MADIface,
+ AIO,
+ AES32,
+ RayDAT
+};
- unsigned int input_peak[64];
- unsigned int playback_peak[64];
- unsigned int output_peak[64];
- unsigned int xxx_peak[64]; /* not used */
+enum hdspm_speed {
+ ss,
+ ds,
+ qs
+};
- unsigned int reserved[256]; /* not used */
+/* -------------------- IOCTL Peak/RMS Meters -------------------- */
- unsigned int input_rms_l[64];
- unsigned int playback_rms_l[64];
- unsigned int output_rms_l[64];
- unsigned int xxx_rms_l[64]; /* not used */
+struct hdspm_peak_rms {
+ uint32_t input_peaks[64];
+ uint32_t playback_peaks[64];
+ uint32_t output_peaks[64];
- unsigned int input_rms_h[64];
- unsigned int playback_rms_h[64];
- unsigned int output_rms_h[64];
- unsigned int xxx_rms_h[64]; /* not used */
-};
+ uint64_t input_rms[64];
+ uint64_t playback_rms[64];
+ uint64_t output_rms[64];
-struct hdspm_peak_rms_ioctl {
- struct hdspm_peak_rms *peak;
+ uint8_t speed; /* enum {ss, ds, qs} */
+ int status2;
};
-/* use indirect access due to the limit of ioctl bit size */
#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS \
- _IOR('H', 0x40, struct hdspm_peak_rms_ioctl)
+ _IOR('H', 0x42, struct hdspm_peak_rms)
/* ------------ CONFIG block IOCTL ---------------------- */
-struct hdspm_config_info {
+struct hdspm_config {
unsigned char pref_sync_ref;
unsigned char wordclock_sync_check;
unsigned char madi_sync_check;
@@ -80,18 +71,121 @@ struct hdspm_config_info {
unsigned int analog_out;
};
-#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO \
- _IOR('H', 0x41, struct hdspm_config_info)
+#define SNDRV_HDSPM_IOCTL_GET_CONFIG \
+ _IOR('H', 0x41, struct hdspm_config)
+
+/**
+ * If there's a TCO (TimeCode Option) board installed,
+ * there are further options and status data available.
+ * The hdspm_ltc structure contains the current SMPTE
+ * timecode and some status information and can be
+ * obtained via SNDRV_HDSPM_IOCTL_GET_LTC or in the
+ * hdspm_status struct.
+ **/
+
+enum hdspm_ltc_format {
+ format_invalid,
+ fps_24,
+ fps_25,
+ fps_2997,
+ fps_30
+};
+
+enum hdspm_ltc_frame {
+ frame_invalid,
+ drop_frame,
+ full_frame
+};
+
+enum hdspm_ltc_input_format {
+ ntsc,
+ pal,
+ no_video
+};
+
+struct hdspm_ltc {
+ unsigned int ltc;
+ enum hdspm_ltc_format format;
+ enum hdspm_ltc_frame frame;
+ enum hdspm_ltc_input_format input_format;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_mixer_ioctl)
+
+/**
+ * The status data reflects the device's current state
+ * as determined by the card's configuration and
+ * connection status.
+ **/
+
+enum hdspm_sync {
+ hdspm_sync_no_lock = 0,
+ hdspm_sync_lock = 1,
+ hdspm_sync_sync = 2
+};
-/* get Soundcard Version */
+enum hdspm_madi_input {
+ hdspm_input_optical = 0,
+ hdspm_input_coax = 1
+};
+
+enum hdspm_madi_channel_format {
+ hdspm_format_ch_64 = 0,
+ hdspm_format_ch_56 = 1
+};
+
+enum hdspm_madi_frame_format {
+ hdspm_frame_48 = 0,
+ hdspm_frame_96 = 1
+};
+
+enum hdspm_syncsource {
+ syncsource_wc = 0,
+ syncsource_madi = 1,
+ syncsource_tco = 2,
+ syncsource_sync = 3,
+ syncsource_none = 4
+};
+
+struct hdspm_status {
+ uint8_t card_type; /* enum hdspm_io_type */
+ enum hdspm_syncsource autosync_source;
+
+ uint64_t card_clock;
+ uint32_t master_period;
+
+ union {
+ struct {
+ uint8_t sync_wc; /* enum hdspm_sync */
+ uint8_t sync_madi; /* enum hdspm_sync */
+ uint8_t sync_tco; /* enum hdspm_sync */
+ uint8_t sync_in; /* enum hdspm_sync */
+ uint8_t madi_input; /* enum hdspm_madi_input */
+ uint8_t channel_format; /* enum hdspm_madi_channel_format */
+ uint8_t frame_format; /* enum hdspm_madi_frame_format */
+ } madi;
+ } card_specific;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_STATUS \
+ _IOR('H', 0x47, struct hdspm_status)
+
+/**
+ * Get information about the card and its add-ons.
+ **/
+
+#define HDSPM_ADDON_TCO 1
struct hdspm_version {
+ uint8_t card_type; /* enum hdspm_io_type */
+ char cardname[20];
+ unsigned int serial;
unsigned short firmware_rev;
+ int addons;
};
-#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, struct hdspm_version)
-
+#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x48, struct hdspm_version)
/* ------------- get Matrix Mixer IOCTL --------------- */
@@ -103,7 +197,7 @@ struct hdspm_version {
/* equivalent to hardware definition, maybe for future feature of mmap of
* them
*/
-/* each of 64 outputs has 64 infader and 64 outfader:
+/* each of 64 outputs has 64 infader and 64 outfader:
Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */
#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS
@@ -131,4 +225,5 @@ typedef struct hdspm_version hdspm_version_t;
typedef struct hdspm_channelfader snd_hdspm_channelfader_t;
typedef struct hdspm_mixer hdspm_mixer_t;
-#endif /* __SOUND_HDSPM_H */
+
+#endif
diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h
index 51fbcb4a277a..13cb0b430a1b 100644
--- a/include/sound/mixer_oss.h
+++ b/include/sound/mixer_oss.h
@@ -73,6 +73,9 @@ struct snd_mixer_oss_file {
struct snd_mixer_oss *mixer;
};
+int snd_mixer_oss_ioctl_card(struct snd_card *card,
+ unsigned int cmd, unsigned long arg);
+
#endif /* CONFIG_SND_MIXER_OSS */
#endif /* __SOUND_MIXER_OSS_H */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index e731f8d71934..430a9cc045e2 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -136,48 +136,49 @@ struct snd_pcm_ops {
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
#define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
SNDRV_PCM_RATE_192000)
-#define SNDRV_PCM_FMTBIT_S8 (1ULL << SNDRV_PCM_FORMAT_S8)
-#define SNDRV_PCM_FMTBIT_U8 (1ULL << SNDRV_PCM_FORMAT_U8)
-#define SNDRV_PCM_FMTBIT_S16_LE (1ULL << SNDRV_PCM_FORMAT_S16_LE)
-#define SNDRV_PCM_FMTBIT_S16_BE (1ULL << SNDRV_PCM_FORMAT_S16_BE)
-#define SNDRV_PCM_FMTBIT_U16_LE (1ULL << SNDRV_PCM_FORMAT_U16_LE)
-#define SNDRV_PCM_FMTBIT_U16_BE (1ULL << SNDRV_PCM_FORMAT_U16_BE)
-#define SNDRV_PCM_FMTBIT_S24_LE (1ULL << SNDRV_PCM_FORMAT_S24_LE)
-#define SNDRV_PCM_FMTBIT_S24_BE (1ULL << SNDRV_PCM_FORMAT_S24_BE)
-#define SNDRV_PCM_FMTBIT_U24_LE (1ULL << SNDRV_PCM_FORMAT_U24_LE)
-#define SNDRV_PCM_FMTBIT_U24_BE (1ULL << SNDRV_PCM_FORMAT_U24_BE)
-#define SNDRV_PCM_FMTBIT_S32_LE (1ULL << SNDRV_PCM_FORMAT_S32_LE)
-#define SNDRV_PCM_FMTBIT_S32_BE (1ULL << SNDRV_PCM_FORMAT_S32_BE)
-#define SNDRV_PCM_FMTBIT_U32_LE (1ULL << SNDRV_PCM_FORMAT_U32_LE)
-#define SNDRV_PCM_FMTBIT_U32_BE (1ULL << SNDRV_PCM_FORMAT_U32_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
-#define SNDRV_PCM_FMTBIT_MU_LAW (1ULL << SNDRV_PCM_FORMAT_MU_LAW)
-#define SNDRV_PCM_FMTBIT_A_LAW (1ULL << SNDRV_PCM_FORMAT_A_LAW)
-#define SNDRV_PCM_FMTBIT_IMA_ADPCM (1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM)
-#define SNDRV_PCM_FMTBIT_MPEG (1ULL << SNDRV_PCM_FORMAT_MPEG)
-#define SNDRV_PCM_FMTBIT_GSM (1ULL << SNDRV_PCM_FORMAT_GSM)
-#define SNDRV_PCM_FMTBIT_SPECIAL (1ULL << SNDRV_PCM_FORMAT_SPECIAL)
-#define SNDRV_PCM_FMTBIT_S24_3LE (1ULL << SNDRV_PCM_FORMAT_S24_3LE)
-#define SNDRV_PCM_FMTBIT_U24_3LE (1ULL << SNDRV_PCM_FORMAT_U24_3LE)
-#define SNDRV_PCM_FMTBIT_S24_3BE (1ULL << SNDRV_PCM_FORMAT_S24_3BE)
-#define SNDRV_PCM_FMTBIT_U24_3BE (1ULL << SNDRV_PCM_FORMAT_U24_3BE)
-#define SNDRV_PCM_FMTBIT_S20_3LE (1ULL << SNDRV_PCM_FORMAT_S20_3LE)
-#define SNDRV_PCM_FMTBIT_U20_3LE (1ULL << SNDRV_PCM_FORMAT_U20_3LE)
-#define SNDRV_PCM_FMTBIT_S20_3BE (1ULL << SNDRV_PCM_FORMAT_S20_3BE)
-#define SNDRV_PCM_FMTBIT_U20_3BE (1ULL << SNDRV_PCM_FORMAT_U20_3BE)
-#define SNDRV_PCM_FMTBIT_S18_3LE (1ULL << SNDRV_PCM_FORMAT_S18_3LE)
-#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE)
-#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE)
-#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE)
-#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24)
-#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
-#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40)
-#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
+#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
+#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
+#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
+#define SNDRV_PCM_FMTBIT_S16_LE _SNDRV_PCM_FMTBIT(S16_LE)
+#define SNDRV_PCM_FMTBIT_S16_BE _SNDRV_PCM_FMTBIT(S16_BE)
+#define SNDRV_PCM_FMTBIT_U16_LE _SNDRV_PCM_FMTBIT(U16_LE)
+#define SNDRV_PCM_FMTBIT_U16_BE _SNDRV_PCM_FMTBIT(U16_BE)
+#define SNDRV_PCM_FMTBIT_S24_LE _SNDRV_PCM_FMTBIT(S24_LE)
+#define SNDRV_PCM_FMTBIT_S24_BE _SNDRV_PCM_FMTBIT(S24_BE)
+#define SNDRV_PCM_FMTBIT_U24_LE _SNDRV_PCM_FMTBIT(U24_LE)
+#define SNDRV_PCM_FMTBIT_U24_BE _SNDRV_PCM_FMTBIT(U24_BE)
+#define SNDRV_PCM_FMTBIT_S32_LE _SNDRV_PCM_FMTBIT(S32_LE)
+#define SNDRV_PCM_FMTBIT_S32_BE _SNDRV_PCM_FMTBIT(S32_BE)
+#define SNDRV_PCM_FMTBIT_U32_LE _SNDRV_PCM_FMTBIT(U32_LE)
+#define SNDRV_PCM_FMTBIT_U32_BE _SNDRV_PCM_FMTBIT(U32_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT_LE _SNDRV_PCM_FMTBIT(FLOAT_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT_BE _SNDRV_PCM_FMTBIT(FLOAT_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_LE _SNDRV_PCM_FMTBIT(FLOAT64_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_BE _SNDRV_PCM_FMTBIT(FLOAT64_BE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_LE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_BE)
+#define SNDRV_PCM_FMTBIT_MU_LAW _SNDRV_PCM_FMTBIT(MU_LAW)
+#define SNDRV_PCM_FMTBIT_A_LAW _SNDRV_PCM_FMTBIT(A_LAW)
+#define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM)
+#define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG)
+#define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM)
+#define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL)
+#define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE)
+#define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE)
+#define SNDRV_PCM_FMTBIT_S24_3BE _SNDRV_PCM_FMTBIT(S24_3BE)
+#define SNDRV_PCM_FMTBIT_U24_3BE _SNDRV_PCM_FMTBIT(U24_3BE)
+#define SNDRV_PCM_FMTBIT_S20_3LE _SNDRV_PCM_FMTBIT(S20_3LE)
+#define SNDRV_PCM_FMTBIT_U20_3LE _SNDRV_PCM_FMTBIT(U20_3LE)
+#define SNDRV_PCM_FMTBIT_S20_3BE _SNDRV_PCM_FMTBIT(S20_3BE)
+#define SNDRV_PCM_FMTBIT_U20_3BE _SNDRV_PCM_FMTBIT(U20_3BE)
+#define SNDRV_PCM_FMTBIT_S18_3LE _SNDRV_PCM_FMTBIT(S18_3LE)
+#define SNDRV_PCM_FMTBIT_U18_3LE _SNDRV_PCM_FMTBIT(U18_3LE)
+#define SNDRV_PCM_FMTBIT_S18_3BE _SNDRV_PCM_FMTBIT(S18_3BE)
+#define SNDRV_PCM_FMTBIT_U18_3BE _SNDRV_PCM_FMTBIT(U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24 _SNDRV_PCM_FMTBIT(G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
@@ -490,7 +491,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
int snd_pcm_status(struct snd_pcm_substream *substream,
struct snd_pcm_status *status);
int snd_pcm_start(struct snd_pcm_substream *substream);
-int snd_pcm_stop(struct snd_pcm_substream *substream, int status);
+int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream);
#ifdef CONFIG_PM
int snd_pcm_suspend(struct snd_pcm_substream *substream);
@@ -748,8 +749,8 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
return &params->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
}
-#define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))
-#define params_format(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT))
+#define params_access(p) ((__force snd_pcm_access_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)))
+#define params_format(p) ((__force snd_pcm_format_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT)))
#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min
#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index d79894192ae3..9a155f9d0a12 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -15,67 +15,29 @@
#define FSI_PORT_A 0
#define FSI_PORT_B 1
-/* flags format
-
- * 0xABCDEEFF
- *
- * A: channel size for TDM (input)
- * B: channel size for TDM (ooutput)
- * C: inversion
- * D: mode
- * E: input format
- * F: output format
- */
-
#include <linux/clk.h>
#include <sound/soc.h>
-/* TDM channel */
-#define SH_FSI_SET_CH_I(x) ((x & 0xF) << 28)
-#define SH_FSI_SET_CH_O(x) ((x & 0xF) << 24)
-
-#define SH_FSI_CH_IMASK 0xF0000000
-#define SH_FSI_CH_OMASK 0x0F000000
-#define SH_FSI_GET_CH_I(x) ((x & SH_FSI_CH_IMASK) >> 28)
-#define SH_FSI_GET_CH_O(x) ((x & SH_FSI_CH_OMASK) >> 24)
-
-/* clock inversion */
-#define SH_FSI_INVERSION_MASK 0x00F00000
-#define SH_FSI_LRM_INV (1 << 20)
-#define SH_FSI_BRM_INV (1 << 21)
-#define SH_FSI_LRS_INV (1 << 22)
-#define SH_FSI_BRS_INV (1 << 23)
-
-/* mode */
-#define SH_FSI_MODE_MASK 0x000F0000
-#define SH_FSI_IN_SLAVE_MODE (1 << 16) /* default master mode */
-#define SH_FSI_OUT_SLAVE_MODE (1 << 17) /* default master mode */
-
-/* DI format */
-#define SH_FSI_FMT_MASK 0x000000FF
-#define SH_FSI_IFMT(x) (((SH_FSI_FMT_ ## x) & SH_FSI_FMT_MASK) << 8)
-#define SH_FSI_OFMT(x) (((SH_FSI_FMT_ ## x) & SH_FSI_FMT_MASK) << 0)
-#define SH_FSI_GET_IFMT(x) ((x >> 8) & SH_FSI_FMT_MASK)
-#define SH_FSI_GET_OFMT(x) ((x >> 0) & SH_FSI_FMT_MASK)
-
-#define SH_FSI_FMT_MONO 0
-#define SH_FSI_FMT_MONO_DELAY 1
-#define SH_FSI_FMT_PCM 2
-#define SH_FSI_FMT_I2S 3
-#define SH_FSI_FMT_TDM 4
-#define SH_FSI_FMT_TDM_DELAY 5
-#define SH_FSI_FMT_SPDIF 6
-
-
-#define SH_FSI_IFMT_TDM_CH(x) \
- (SH_FSI_IFMT(TDM) | SH_FSI_SET_CH_I(x))
-#define SH_FSI_IFMT_TDM_DELAY_CH(x) \
- (SH_FSI_IFMT(TDM_DELAY) | SH_FSI_SET_CH_I(x))
+/*
+ * flags format
+ *
+ * 0x000000BA
+ *
+ * A: inversion
+ * B: format mode
+ */
-#define SH_FSI_OFMT_TDM_CH(x) \
- (SH_FSI_OFMT(TDM) | SH_FSI_SET_CH_O(x))
-#define SH_FSI_OFMT_TDM_DELAY_CH(x) \
- (SH_FSI_OFMT(TDM_DELAY) | SH_FSI_SET_CH_O(x))
+/* A: clock inversion */
+#define SH_FSI_INVERSION_MASK 0x0000000F
+#define SH_FSI_LRM_INV (1 << 0)
+#define SH_FSI_BRM_INV (1 << 1)
+#define SH_FSI_LRS_INV (1 << 2)
+#define SH_FSI_BRS_INV (1 << 3)
+
+/* B: format mode */
+#define SH_FSI_FMT_MASK 0x000000F0
+#define SH_FSI_FMT_DAI (0 << 4)
+#define SH_FSI_FMT_SPDIF (1 << 4)
/*
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 8031769ac485..979ed84e07d6 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -157,6 +157,18 @@
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
+/* additional sequencing control within an event type */
+#define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
+ wevent, wflags) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
+ .invert = winvert, .event = wevent, .event_flags = wflags, \
+ .subseq = wsubseq}
+#define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
+ wflags) \
+{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \
+ .shift = wshift, .invert = winvert, .event = wevent, \
+ .event_flags = wflags, .subseq = wsubseq}
+
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
@@ -450,6 +462,7 @@ struct snd_soc_dapm_widget {
unsigned char ext:1; /* has external widgets */
unsigned char force:1; /* force state */
unsigned char ignore_suspend:1; /* kept enabled over suspend */
+ int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w);
@@ -487,6 +500,9 @@ struct snd_soc_dapm_context {
struct snd_soc_dapm_update *update;
+ void (*seq_notifier)(struct snd_soc_dapm_context *,
+ enum snd_soc_dapm_type, int);
+
struct device *dev; /* from parent - for debug */
struct snd_soc_codec *codec; /* parent codec */
struct snd_soc_card *card; /* parent card */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 74921f20a1d8..bfa4836ea107 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -234,6 +234,7 @@ struct snd_soc_codec;
struct snd_soc_codec_driver;
struct soc_enum;
struct snd_soc_jack;
+struct snd_soc_jack_zone;
struct snd_soc_jack_pin;
struct snd_soc_cache_ops;
#include <sound/soc-dapm.h>
@@ -258,6 +259,16 @@ enum snd_soc_compress_type {
SND_SOC_RBTREE_COMPRESSION
};
+int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+ unsigned int freq, int dir);
+int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out);
+
+int snd_soc_register_card(struct snd_soc_card *card);
+int snd_soc_unregister_card(struct snd_soc_card *card);
+int snd_soc_suspend(struct device *dev);
+int snd_soc_resume(struct device *dev);
+int snd_soc_poweroff(struct device *dev);
int snd_soc_register_platform(struct device *dev,
struct snd_soc_platform_driver *platform_drv);
void snd_soc_unregister_platform(struct device *dev);
@@ -265,7 +276,8 @@ int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai);
void snd_soc_unregister_codec(struct device *dev);
-int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
+int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
@@ -276,6 +288,10 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value);
int snd_soc_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value);
+int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg);
+int snd_soc_default_readable_register(struct snd_soc_codec *codec,
+ unsigned int reg);
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -297,6 +313,9 @@ void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
struct notifier_block *nb);
void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack,
struct notifier_block *nb);
+int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_zone *zones);
+int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage);
#ifdef CONFIG_GPIOLIB
int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios);
@@ -321,7 +340,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
*Controls
*/
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
- void *data, char *long_name);
+ void *data, char *long_name,
+ const char *prefix);
int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls);
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
@@ -367,6 +387,22 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/**
+ * struct snd_soc_reg_access - Describes whether a given register is
+ * readable, writable or volatile.
+ *
+ * @reg: the register number
+ * @read: whether this register is readable
+ * @write: whether this register is writable
+ * @vol: whether this register is volatile
+ */
+struct snd_soc_reg_access {
+ u16 reg;
+ u16 read;
+ u16 write;
+ u16 vol;
+};
+
+/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
*
* @pin: name of the pin to update
@@ -381,6 +417,24 @@ struct snd_soc_jack_pin {
};
/**
+ * struct snd_soc_jack_zone - Describes voltage zones of jack detection
+ *
+ * @min_mv: start voltage in mv
+ * @max_mv: end voltage in mv
+ * @jack_type: type of jack that is expected for this voltage
+ * @debounce_time: debounce_time for jack, codec driver should wait for this
+ * duration before reading the adc for voltages
+ * @:list: list container
+ */
+struct snd_soc_jack_zone {
+ unsigned int min_mv;
+ unsigned int max_mv;
+ unsigned int jack_type;
+ unsigned int debounce_time;
+ struct list_head list;
+};
+
+/**
* struct snd_soc_jack_gpio - Describes a gpio pin for jack detection
*
* @gpio: gpio number
@@ -388,6 +442,10 @@ struct snd_soc_jack_pin {
* @report: value to report when jack detected
* @invert: report presence in low state
* @debouce_time: debouce time in ms
+ * @wake: enable as wake source
+ * @jack_status_check: callback function which overrides the detection
+ * to provide more complex checks (eg, reading an
+ * ADC).
*/
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio {
@@ -396,6 +454,8 @@ struct snd_soc_jack_gpio {
int report;
int invert;
int debounce_time;
+ bool wake;
+
struct snd_soc_jack *jack;
struct delayed_work work;
@@ -409,6 +469,7 @@ struct snd_soc_jack {
struct list_head pins;
int status;
struct blocking_notifier_head notifier;
+ struct list_head jack_zones;
};
/* SoC PCM stream information */
@@ -459,18 +520,22 @@ struct snd_soc_codec {
struct list_head card_list;
int num_dai;
enum snd_soc_compress_type compress_type;
+ size_t reg_size; /* reg_cache_size * reg_word_size */
+ int (*volatile_register)(struct snd_soc_codec *, unsigned int);
+ int (*readable_register)(struct snd_soc_codec *, unsigned int);
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
- unsigned int cache_only:1; /* Suppress writes to hardware */
- unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+ unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int probed:1; /* Codec has been probed */
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
unsigned int cache_init:1; /* codec cache has been initialized */
+ u32 cache_only; /* Suppress writes to hardware */
+ u32 cache_sync; /* Cache needs to be synced to hardware */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
@@ -503,22 +568,39 @@ struct snd_soc_codec_driver {
pm_message_t state);
int (*resume)(struct snd_soc_codec *);
+ /* Default DAPM setup, added after probe() is run */
+ const struct snd_soc_dapm_widget *dapm_widgets;
+ int num_dapm_widgets;
+ const struct snd_soc_dapm_route *dapm_routes;
+ int num_dapm_routes;
+
+ /* codec wide operations */
+ int (*set_sysclk)(struct snd_soc_codec *codec,
+ int clk_id, unsigned int freq, int dir);
+ int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out);
+
/* codec IO */
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
int (*display_register)(struct snd_soc_codec *, char *,
size_t, unsigned int);
- int (*volatile_register)(unsigned int);
- int (*readable_register)(unsigned int);
+ int (*volatile_register)(struct snd_soc_codec *, unsigned int);
+ int (*readable_register)(struct snd_soc_codec *, unsigned int);
short reg_cache_size;
short reg_cache_step;
short reg_word_size;
const void *reg_cache_default;
+ short reg_access_size;
+ const struct snd_soc_reg_access *reg_access_default;
enum snd_soc_compress_type compress_type;
/* codec bias level */
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
+
+ void (*seq_notifier)(struct snd_soc_dapm_context *,
+ enum snd_soc_dapm_type, int);
};
/* SoC platform interface */
@@ -617,15 +699,16 @@ struct snd_soc_card {
bool instantiated;
- int (*probe)(struct platform_device *pdev);
- int (*remove)(struct platform_device *pdev);
+ int (*probe)(struct snd_soc_card *card);
+ int (*late_probe)(struct snd_soc_card *card);
+ int (*remove)(struct snd_soc_card *card);
/* the pre and post PM functions are used to do any PM work before and
* after the codec and DAI's do any PM work. */
- int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
- int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
- int (*resume_pre)(struct platform_device *pdev);
- int (*resume_post)(struct platform_device *pdev);
+ int (*suspend_pre)(struct snd_soc_card *card);
+ int (*suspend_post)(struct snd_soc_card *card);
+ int (*resume_pre)(struct snd_soc_card *card);
+ int (*resume_post)(struct snd_soc_card *card);
/* callbacks */
int (*set_bias_level)(struct snd_soc_card *,
@@ -654,6 +737,14 @@ struct snd_soc_card {
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
+ /*
+ * Card-specific routes and widgets.
+ */
+ struct snd_soc_dapm_widget *dapm_widgets;
+ int num_dapm_widgets;
+ struct snd_soc_dapm_route *dapm_routes;
+ int num_dapm_routes;
+
struct work_struct deferred_resume_work;
/* lists of probed devices belonging to this card */
@@ -665,11 +756,16 @@ struct snd_soc_card {
struct list_head paths;
struct list_head dapm_list;
+ /* Generic DAPM context for the card */
+ struct snd_soc_dapm_context dapm;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root;
struct dentry *debugfs_pop_time;
#endif
u32 pop_time;
+
+ void *drvdata;
};
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
@@ -721,6 +817,17 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec,
/* device driver data */
+static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
+ void *data)
+{
+ card->drvdata = data;
+}
+
+static inline void *snd_soc_card_get_drvdata(struct snd_soc_card *card)
+{
+ return card->drvdata;
+}
+
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
void *data)
{
@@ -754,6 +861,22 @@ static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
return dev_get_drvdata(&rtd->dev);
}
+static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
+{
+ INIT_LIST_HEAD(&card->dai_dev_list);
+ INIT_LIST_HEAD(&card->codec_dev_list);
+ INIT_LIST_HEAD(&card->platform_dev_list);
+ INIT_LIST_HEAD(&card->widgets);
+ INIT_LIST_HEAD(&card->paths);
+ INIT_LIST_HEAD(&card->dapm_list);
+}
+
#include <sound/soc-dai.h>
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *snd_soc_debugfs_root;
+#endif
+
+extern const struct dev_pm_ops snd_soc_pm_ops;
+
#endif
diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h
new file mode 100644
index 000000000000..c009f70b4029
--- /dev/null
+++ b/include/sound/tlv320aic32x4.h
@@ -0,0 +1,31 @@
+/*
+ * tlv320aic32x4.h -- TLV320AIC32X4 Soc Audio driver platform data
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _AIC32X4_PDATA_H
+#define _AIC32X4_PDATA_H
+
+#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001
+#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002
+#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004
+#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008
+#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010
+
+#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001
+#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002
+
+struct aic32x4_pdata {
+ u32 power_cfg;
+ u32 micpga_routing;
+ bool swapdacs;
+};
+
+#endif
diff --git a/include/sound/version.h b/include/sound/version.h
index bf69a5b7e65f..8fc5321e1ecc 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h */
-#define CONFIG_SND_VERSION "1.0.23"
+#define CONFIG_SND_VERSION "1.0.24"
#define CONFIG_SND_DATE ""
diff --git a/include/sound/wm8903.h b/include/sound/wm8903.h
index 1eeebd534f7e..cf7ccb76a8de 100644
--- a/include/sound/wm8903.h
+++ b/include/sound/wm8903.h
@@ -33,6 +33,21 @@
#define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
/*
+ * WM8903_GPn_FN values
+ *
+ * See datasheets for list of valid values per pin
+ */
+#define WM8903_GPn_FN_GPIO_OUTPUT 0
+#define WM8903_GPn_FN_BCLK 1
+#define WM8903_GPn_FN_IRQ_OUTPT 2
+#define WM8903_GPn_FN_GPIO_INPUT 3
+#define WM8903_GPn_FN_MICBIAS_CURRENT_DETECT 4
+#define WM8903_GPn_FN_MICBIAS_SHORT_DETECT 5
+#define WM8903_GPn_FN_DMIC_LR_CLK_OUTPUT 6
+#define WM8903_GPn_FN_FLL_LOCK_OUTPUT 8
+#define WM8903_GPn_FN_FLL_CLOCK_OUTPUT 9
+
+/*
* R116 (0x74) - GPIO Control 1
*/
#define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */
@@ -227,6 +242,8 @@
#define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */
#define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */
+#define WM8903_NUM_GPIO 5
+
struct wm8903_platform_data {
bool irq_active_low; /* Set if IRQ active low, default high */
@@ -239,7 +256,8 @@ struct wm8903_platform_data {
int micdet_delay; /* Delay after microphone detection (ms) */
- u32 gpio_cfg[5]; /* Default register values for GPIO pin mux */
+ int gpio_base;
+ u32 gpio_cfg[WM8903_NUM_GPIO]; /* Default register values for GPIO pin mux */
};
#endif
diff --git a/include/sound/wm9081.h b/include/sound/wm9081.h
index e173ddbf6bd4..f34b0b1716d8 100644
--- a/include/sound/wm9081.h
+++ b/include/sound/wm9081.h
@@ -17,9 +17,12 @@ struct wm9081_retune_mobile_setting {
u16 config[20];
};
-struct wm9081_retune_mobile_config {
- struct wm9081_retune_mobile_setting *configs;
- int num_configs;
+struct wm9081_pdata {
+ bool irq_high; /* IRQ is active high */
+ bool irq_cmos; /* IRQ is in CMOS mode */
+
+ struct wm9081_retune_mobile_setting *retune_configs;
+ int num_retune_configs;
};
#endif
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index 186e84db4b54..ae973d2e27a1 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -229,6 +229,31 @@ TRACE_EVENT(snd_soc_jack_notify,
TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
);
+TRACE_EVENT(snd_soc_cache_sync,
+
+ TP_PROTO(struct snd_soc_codec *codec, const char *type,
+ const char *status),
+
+ TP_ARGS(codec, type, status),
+
+ TP_STRUCT__entry(
+ __string( name, codec->name )
+ __string( status, status )
+ __string( type, type )
+ __field( int, id )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, codec->name);
+ __assign_str(status, status);
+ __assign_str(type, type);
+ __entry->id = codec->id;
+ ),
+
+ TP_printk("codec=%s.%d type=%s status=%s", __get_str(name),
+ (int)__entry->id, __get_str(type), __get_str(status))
+);
+
#endif /* _TRACE_ASOC_H */
/* This part must be outside protection */
diff --git a/include/trace/events/scsi.h b/include/trace/events/scsi.h
index 25fbefdf2f2e..db6c93510f74 100644
--- a/include/trace/events/scsi.h
+++ b/include/trace/events/scsi.h
@@ -184,6 +184,17 @@
scsi_statusbyte_name(SAM_STAT_ACA_ACTIVE), \
scsi_statusbyte_name(SAM_STAT_TASK_ABORTED))
+#define scsi_prot_op_name(result) { result, #result }
+#define show_prot_op_name(val) \
+ __print_symbolic(val, \
+ scsi_prot_op_name(SCSI_PROT_NORMAL), \
+ scsi_prot_op_name(SCSI_PROT_READ_INSERT), \
+ scsi_prot_op_name(SCSI_PROT_WRITE_STRIP), \
+ scsi_prot_op_name(SCSI_PROT_READ_STRIP), \
+ scsi_prot_op_name(SCSI_PROT_WRITE_INSERT), \
+ scsi_prot_op_name(SCSI_PROT_READ_PASS), \
+ scsi_prot_op_name(SCSI_PROT_WRITE_PASS))
+
const char *scsi_trace_parse_cdb(struct trace_seq*, unsigned char*, int);
#define __parse_cdb(cdb, len) scsi_trace_parse_cdb(p, cdb, len)
@@ -202,6 +213,7 @@ TRACE_EVENT(scsi_dispatch_cmd_start,
__field( unsigned int, cmd_len )
__field( unsigned int, data_sglen )
__field( unsigned int, prot_sglen )
+ __field( unsigned char, prot_op )
__dynamic_array(unsigned char, cmnd, cmd->cmd_len)
),
@@ -214,13 +226,15 @@ TRACE_EVENT(scsi_dispatch_cmd_start,
__entry->cmd_len = cmd->cmd_len;
__entry->data_sglen = scsi_sg_count(cmd);
__entry->prot_sglen = scsi_prot_sg_count(cmd);
+ __entry->prot_op = scsi_get_prot_op(cmd);
memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
),
TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \
- " cmnd=(%s %s raw=%s)",
+ " prot_op=%s cmnd=(%s %s raw=%s)",
__entry->host_no, __entry->channel, __entry->id,
__entry->lun, __entry->data_sglen, __entry->prot_sglen,
+ show_prot_op_name(__entry->prot_op),
show_opcode_name(__entry->opcode),
__parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
__print_hex(__get_dynamic_array(cmnd), __entry->cmd_len))
@@ -242,6 +256,7 @@ TRACE_EVENT(scsi_dispatch_cmd_error,
__field( unsigned int, cmd_len )
__field( unsigned int, data_sglen )
__field( unsigned int, prot_sglen )
+ __field( unsigned char, prot_op )
__dynamic_array(unsigned char, cmnd, cmd->cmd_len)
),
@@ -255,13 +270,15 @@ TRACE_EVENT(scsi_dispatch_cmd_error,
__entry->cmd_len = cmd->cmd_len;
__entry->data_sglen = scsi_sg_count(cmd);
__entry->prot_sglen = scsi_prot_sg_count(cmd);
+ __entry->prot_op = scsi_get_prot_op(cmd);
memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
),
TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \
- " cmnd=(%s %s raw=%s) rtn=%d",
+ " prot_op=%s cmnd=(%s %s raw=%s) rtn=%d",
__entry->host_no, __entry->channel, __entry->id,
__entry->lun, __entry->data_sglen, __entry->prot_sglen,
+ show_prot_op_name(__entry->prot_op),
show_opcode_name(__entry->opcode),
__parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
__print_hex(__get_dynamic_array(cmnd), __entry->cmd_len),
@@ -284,6 +301,7 @@ DECLARE_EVENT_CLASS(scsi_cmd_done_timeout_template,
__field( unsigned int, cmd_len )
__field( unsigned int, data_sglen )
__field( unsigned int, prot_sglen )
+ __field( unsigned char, prot_op )
__dynamic_array(unsigned char, cmnd, cmd->cmd_len)
),
@@ -297,14 +315,16 @@ DECLARE_EVENT_CLASS(scsi_cmd_done_timeout_template,
__entry->cmd_len = cmd->cmd_len;
__entry->data_sglen = scsi_sg_count(cmd);
__entry->prot_sglen = scsi_prot_sg_count(cmd);
+ __entry->prot_op = scsi_get_prot_op(cmd);
memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
),
TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u " \
- "prot_sgl=%u cmnd=(%s %s raw=%s) result=(driver=%s host=%s " \
- "message=%s status=%s)",
+ "prot_sgl=%u prot_op=%s cmnd=(%s %s raw=%s) result=(driver=" \
+ "%s host=%s message=%s status=%s)",
__entry->host_no, __entry->channel, __entry->id,
__entry->lun, __entry->data_sglen, __entry->prot_sglen,
+ show_prot_op_name(__entry->prot_op),
show_opcode_name(__entry->opcode),
__parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
__print_hex(__get_dynamic_array(cmnd), __entry->cmd_len),
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
new file mode 100644
index 000000000000..a2b22f01a51d
--- /dev/null
+++ b/include/xen/balloon.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Xen balloon functionality
+ */
+
+#define RETRY_UNLIMITED 0
+
+struct balloon_stats {
+ /* We aim for 'current allocation' == 'target allocation'. */
+ unsigned long current_pages;
+ unsigned long target_pages;
+ /* Number of pages in high- and low-memory balloons. */
+ unsigned long balloon_low;
+ unsigned long balloon_high;
+ unsigned long schedule_delay;
+ unsigned long max_schedule_delay;
+ unsigned long retry_count;
+ unsigned long max_retry_count;
+};
+
+extern struct balloon_stats balloon_stats;
+
+void balloon_set_new_target(unsigned long target);
+
+int alloc_xenballooned_pages(int nr_pages, struct page** pages);
+void free_xenballooned_pages(int nr_pages, struct page** pages);
diff --git a/include/xen/events.h b/include/xen/events.h
index d3b9010ee96a..f1b87ad48ac7 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -47,9 +47,9 @@ static inline void notify_remote_via_evtchn(int port)
(void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
}
-extern void notify_remote_via_irq(int irq);
+void notify_remote_via_irq(int irq);
-extern void xen_irq_resume(void);
+void xen_irq_resume(void);
/* Clear an irq's pending state, in preparation for polling on it */
void xen_clear_irq_pending(int irq);
@@ -68,20 +68,22 @@ void xen_poll_irq_timeout(int irq, u64 timeout);
unsigned irq_from_evtchn(unsigned int evtchn);
/* Xen HVM evtchn vector callback */
-extern void xen_hvm_callback_vector(void);
+void xen_hvm_callback_vector(void);
extern int xen_have_vector_callback;
int xen_set_callback_via(uint64_t via);
void xen_evtchn_do_upcall(struct pt_regs *regs);
void xen_hvm_evtchn_do_upcall(void);
-/* Allocate an irq for a physical interrupt, given a gsi. "Legacy"
- * GSIs are identity mapped; others are dynamically allocated as
- * usual. */
-int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
-int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
+/* Allocate a pirq for a physical interrupt, given a gsi. */
+int xen_allocate_pirq_gsi(unsigned gsi);
+/* Bind a pirq for a physical interrupt to an irq. */
+int xen_bind_pirq_gsi_to_irq(unsigned gsi,
+ unsigned pirq, int shareable, char *name);
#ifdef CONFIG_PCI_MSI
+/* Allocate a pirq for a MSI style physical interrupt. */
int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
+/* Bind an PSI pirq to an irq. */
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int pirq, int vector, const char *name);
#endif
@@ -89,12 +91,6 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
/* De-allocates the above mentioned physical interrupt. */
int xen_destroy_irq(int irq);
-/* Return vector allocated to pirq */
-int xen_vector_from_irq(unsigned pirq);
-
-/* Return gsi allocated to pirq */
-int xen_gsi_from_irq(unsigned pirq);
-
/* Return irq from pirq */
int xen_irq_from_pirq(unsigned pirq);
diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
new file mode 100644
index 000000000000..76bd58065f4f
--- /dev/null
+++ b/include/xen/gntalloc.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * gntalloc.h
+ *
+ * Interface to /dev/xen/gntalloc.
+ *
+ * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * This file is in the public domain.
+ */
+
+#ifndef __LINUX_PUBLIC_GNTALLOC_H__
+#define __LINUX_PUBLIC_GNTALLOC_H__
+
+/*
+ * Allocates a new page and creates a new grant reference.
+ */
+#define IOCTL_GNTALLOC_ALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
+struct ioctl_gntalloc_alloc_gref {
+ /* IN parameters */
+ /* The ID of the domain to be given access to the grants. */
+ uint16_t domid;
+ /* Flags for this mapping */
+ uint16_t flags;
+ /* Number of pages to map */
+ uint32_t count;
+ /* OUT parameters */
+ /* The offset to be used on a subsequent call to mmap(). */
+ uint64_t index;
+ /* The grant references of the newly created grant, one per page */
+ /* Variable size, depending on count */
+ uint32_t gref_ids[1];
+};
+
+#define GNTALLOC_FLAG_WRITABLE 1
+
+/*
+ * Deallocates the grant reference, allowing the associated page to be freed if
+ * no other domains are using it.
+ */
+#define IOCTL_GNTALLOC_DEALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
+struct ioctl_gntalloc_dealloc_gref {
+ /* IN parameters */
+ /* The offset returned in the map operation */
+ uint64_t index;
+ /* Number of references to unmap */
+ uint32_t count;
+};
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
+struct ioctl_gntalloc_unmap_notify {
+ /* IN parameters */
+ /* Offset in the file descriptor for a byte within the page (same as
+ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+ * be cleared. Otherwise, it can be any byte in the page whose
+ * notification we are adjusting.
+ */
+ uint64_t index;
+ /* Action(s) to take on unmap */
+ uint32_t action;
+ /* Event channel to notify */
+ uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
diff --git a/include/xen/gntdev.h b/include/xen/gntdev.h
index eb23f4188f5a..5304bd3c84c5 100644
--- a/include/xen/gntdev.h
+++ b/include/xen/gntdev.h
@@ -116,4 +116,35 @@ struct ioctl_gntdev_set_max_grants {
uint32_t count;
};
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
+struct ioctl_gntdev_unmap_notify {
+ /* IN parameters */
+ /* Offset in the file descriptor for a byte within the page (same as
+ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+ * be cleared. Otherwise, it can be any byte in the page whose
+ * notification we are adjusting.
+ */
+ uint64_t index;
+ /* Action(s) to take on unmap */
+ uint32_t action;
+ /* Event channel to notify */
+ uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h
index 5fec575a800a..dd55dac340de 100644
--- a/include/xen/interface/sched.h
+++ b/include/xen/interface/sched.h
@@ -65,6 +65,39 @@ struct sched_poll {
DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
/*
+ * Declare a shutdown for another domain. The main use of this function is
+ * in interpreting shutdown requests and reasons for fully-virtualized
+ * domains. A para-virtualized domain may use SCHEDOP_shutdown directly.
+ * @arg == pointer to sched_remote_shutdown structure.
+ */
+#define SCHEDOP_remote_shutdown 4
+struct sched_remote_shutdown {
+ domid_t domain_id; /* Remote domain ID */
+ unsigned int reason; /* SHUTDOWN_xxx reason */
+};
+
+/*
+ * Latch a shutdown code, so that when the domain later shuts down it
+ * reports this code to the control tools.
+ * @arg == as for SCHEDOP_shutdown.
+ */
+#define SCHEDOP_shutdown_code 5
+
+/*
+ * Setup, poke and destroy a domain watchdog timer.
+ * @arg == pointer to sched_watchdog structure.
+ * With id == 0, setup a domain watchdog timer to cause domain shutdown
+ * after timeout, returns watchdog id.
+ * With id != 0 and timeout == 0, destroy domain watchdog timer.
+ * With id != 0 and timeout != 0, poke watchdog timer and set new timeout.
+ */
+#define SCHEDOP_watchdog 6
+struct sched_watchdog {
+ uint32_t id; /* watchdog ID */
+ uint32_t timeout; /* timeout */
+};
+
+/*
* Reason codes for SCHEDOP_shutdown. These may be interpreted by control
* software to determine the appropriate action. For the most part, Xen does
* not care about the shutdown code.
@@ -73,5 +106,6 @@ DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
+#define SHUTDOWN_watchdog 4 /* Restart because watchdog time expired. */
#endif /* __XEN_PUBLIC_SCHED_H__ */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index 7a1d15ff19b7..5467369e0889 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -92,7 +92,7 @@ struct xenbus_driver {
void (*otherend_changed)(struct xenbus_device *dev,
enum xenbus_state backend_state);
int (*remove)(struct xenbus_device *dev);
- int (*suspend)(struct xenbus_device *dev, pm_message_t state);
+ int (*suspend)(struct xenbus_device *dev);
int (*resume)(struct xenbus_device *dev);
int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *);
struct device_driver driver;
diff --git a/init/Kconfig b/init/Kconfig
index d91de16cf637..56240e724d9a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -745,9 +745,9 @@ config BLK_CGROUP
This option only enables generic Block IO controller infrastructure.
One needs to also enable actual IO controlling logic/policy. For
- enabling proportional weight division of disk bandwidth in CFQ seti
- CONFIG_CFQ_GROUP_IOSCHED=y and for enabling throttling policy set
- CONFIG_BLK_THROTTLE=y.
+ enabling proportional weight division of disk bandwidth in CFQ, set
+ CONFIG_CFQ_GROUP_IOSCHED=y; for enabling throttling policy, set
+ CONFIG_BLK_DEV_THROTTLING=y.
See Documentation/cgroups/blkio-controller.txt for more information.
diff --git a/kernel/fork.c b/kernel/fork.c
index 25e429152ddc..05b92c457010 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -193,6 +193,7 @@ void __put_task_struct(struct task_struct *tsk)
if (!profile_handoff_task(tsk))
free_task(tsk);
}
+EXPORT_SYMBOL_GPL(__put_task_struct);
/*
* macro override instead of weak attribute alias, to workaround
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index acd599a43bfb..0a2aa73e536c 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1064,10 +1064,10 @@ mismatch:
ret = -EBUSY;
out_mask:
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
free_cpumask_var(mask);
out_thread:
- raw_spin_unlock_irqrestore(&desc->lock, flags);
if (new->thread) {
struct task_struct *t = new->thread;
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 4cc2e5ed0bec..760248de109d 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -405,7 +405,8 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
seq_printf(p, " %8s", desc->irq_data.chip->name);
- seq_printf(p, "-%-8s", desc->name);
+ if (desc->name)
+ seq_printf(p, "-%-8s", desc->name);
if (action) {
seq_printf(p, " %s", action->name);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index ed253aa24ba4..3472bb1a070c 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -5122,7 +5122,7 @@ static int perf_exclude_event(struct perf_event *event,
struct pt_regs *regs)
{
if (event->hw.state & PERF_HES_STOPPED)
- return 0;
+ return 1;
if (regs) {
if (event->attr.exclude_user && user_mode(regs))
@@ -5478,6 +5478,8 @@ static int perf_tp_event_match(struct perf_event *event,
struct perf_sample_data *data,
struct pt_regs *regs)
{
+ if (event->hw.state & PERF_HES_STOPPED)
+ return 0;
/*
* All tracepoints are from kernel-space.
*/
@@ -6720,17 +6722,20 @@ __perf_event_exit_task(struct perf_event *child_event,
struct perf_event_context *child_ctx,
struct task_struct *child)
{
- struct perf_event *parent_event;
+ if (child_event->parent) {
+ raw_spin_lock_irq(&child_ctx->lock);
+ perf_group_detach(child_event);
+ raw_spin_unlock_irq(&child_ctx->lock);
+ }
perf_remove_from_context(child_event);
- parent_event = child_event->parent;
/*
- * It can happen that parent exits first, and has events
+ * It can happen that the parent exits first, and has events
* that are still around due to the child reference. These
- * events need to be zapped - but otherwise linger.
+ * events need to be zapped.
*/
- if (parent_event) {
+ if (child_event->parent) {
sync_child_event(child_event, child);
free_event(child_event);
}
diff --git a/kernel/pid.c b/kernel/pid.c
index 39b65b69584f..02f221274265 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -435,6 +435,7 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
rcu_read_unlock();
return pid;
}
+EXPORT_SYMBOL_GPL(get_task_pid);
struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
@@ -446,6 +447,7 @@ struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
rcu_read_unlock();
return result;
}
+EXPORT_SYMBOL_GPL(get_pid_task);
struct pid *find_get_pid(pid_t nr)
{
diff --git a/kernel/smp.c b/kernel/smp.c
index 9910744f0856..7cbd0f293df4 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -194,7 +194,7 @@ void generic_smp_call_function_interrupt(void)
*/
list_for_each_entry_rcu(data, &call_function.queue, csd.list) {
int refs;
- void (*func) (void *info);
+ smp_call_func_t func;
/*
* Since we walk the list without any locks, we might
@@ -214,17 +214,17 @@ void generic_smp_call_function_interrupt(void)
if (atomic_read(&data->refs) == 0)
continue;
- func = data->csd.func; /* for later warn */
- data->csd.func(data->csd.info);
+ func = data->csd.func; /* save for later warn */
+ func(data->csd.info);
/*
- * If the cpu mask is not still set then it enabled interrupts,
- * we took another smp interrupt, and executed the function
- * twice on this cpu. In theory that copy decremented refs.
+ * If the cpu mask is not still set then func enabled
+ * interrupts (BUG), and this cpu took another smp call
+ * function interrupt and executed func(info) twice
+ * on this cpu. That nested execution decremented refs.
*/
if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) {
- WARN(1, "%pS enabled interrupts and double executed\n",
- func);
+ WARN(1, "%pf enabled interrupts and double executed\n", func);
continue;
}
@@ -450,7 +450,7 @@ void smp_call_function_many(const struct cpumask *mask,
{
struct call_function_data *data;
unsigned long flags;
- int cpu, next_cpu, this_cpu = smp_processor_id();
+ int refs, cpu, next_cpu, this_cpu = smp_processor_id();
/*
* Can deadlock when called with interrupts disabled.
@@ -461,7 +461,7 @@ void smp_call_function_many(const struct cpumask *mask,
WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
&& !oops_in_progress && !early_boot_irqs_disabled);
- /* So, what's a CPU they want? Ignoring this one. */
+ /* Try to fastpath. So, what's a CPU they want? Ignoring this one. */
cpu = cpumask_first_and(mask, cpu_online_mask);
if (cpu == this_cpu)
cpu = cpumask_next_and(cpu, mask, cpu_online_mask);
@@ -483,22 +483,49 @@ void smp_call_function_many(const struct cpumask *mask,
data = &__get_cpu_var(cfd_data);
csd_lock(&data->csd);
+
+ /* This BUG_ON verifies our reuse assertions and can be removed */
BUG_ON(atomic_read(&data->refs) || !cpumask_empty(data->cpumask));
+ /*
+ * The global call function queue list add and delete are protected
+ * by a lock, but the list is traversed without any lock, relying
+ * on the rcu list add and delete to allow safe concurrent traversal.
+ * We reuse the call function data without waiting for any grace
+ * period after some other cpu removes it from the global queue.
+ * This means a cpu might find our data block as it is being
+ * filled out.
+ *
+ * We hold off the interrupt handler on the other cpu by
+ * ordering our writes to the cpu mask vs our setting of the
+ * refs counter. We assert only the cpu owning the data block
+ * will set a bit in cpumask, and each bit will only be cleared
+ * by the subject cpu. Each cpu must first find its bit is
+ * set and then check that refs is set indicating the element is
+ * ready to be processed, otherwise it must skip the entry.
+ *
+ * On the previous iteration refs was set to 0 by another cpu.
+ * To avoid the use of transitivity, set the counter to 0 here
+ * so the wmb will pair with the rmb in the interrupt handler.
+ */
+ atomic_set(&data->refs, 0); /* convert 3rd to 1st party write */
+
data->csd.func = func;
data->csd.info = info;
- cpumask_and(data->cpumask, mask, cpu_online_mask);
- cpumask_clear_cpu(this_cpu, data->cpumask);
- /*
- * To ensure the interrupt handler gets an complete view
- * we order the cpumask and refs writes and order the read
- * of them in the interrupt handler. In addition we may
- * only clear our own cpu bit from the mask.
- */
+ /* Ensure 0 refs is visible before mask. Also orders func and info */
smp_wmb();
- atomic_set(&data->refs, cpumask_weight(data->cpumask));
+ /* We rely on the "and" being processed before the store */
+ cpumask_and(data->cpumask, mask, cpu_online_mask);
+ cpumask_clear_cpu(this_cpu, data->cpumask);
+ refs = cpumask_weight(data->cpumask);
+
+ /* Some callers race with other cpus changing the passed mask */
+ if (unlikely(!refs)) {
+ csd_unlock(&data->csd);
+ return;
+ }
raw_spin_lock_irqsave(&call_function.lock, flags);
/*
@@ -507,6 +534,12 @@ void smp_call_function_many(const struct cpumask *mask,
* will not miss any other list entries:
*/
list_add_rcu(&data->csd.list, &call_function.queue);
+ /*
+ * We rely on the wmb() in list_add_rcu to complete our writes
+ * to the cpumask before this write to refs, which indicates
+ * data is on the list and is ready to be processed.
+ */
+ atomic_set(&data->refs, refs);
raw_spin_unlock_irqrestore(&call_function.lock, flags);
/*
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 14674dce77a6..61d7d59f4a1a 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -275,7 +275,7 @@ config PROFILE_ANNOTATED_BRANCHES
This tracer profiles all the the likely and unlikely macros
in the kernel. It will display the results in:
- /sys/kernel/debug/tracing/profile_annotated_branch
+ /sys/kernel/debug/tracing/trace_stat/branch_annotated
Note: this will add a significant overhead; only turn this
on if you need to profile the system's use of these macros.
@@ -288,7 +288,7 @@ config PROFILE_ALL_BRANCHES
taken in the kernel is recorded whether it hit or miss.
The results will be displayed in:
- /sys/kernel/debug/tracing/profile_branch
+ /sys/kernel/debug/tracing/trace_stat/branch_all
This option also enables the likely/unlikely profiler.
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index db7b439d23ee..d9c8bcafb120 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -668,7 +668,7 @@ static struct list_head *rb_list_head(struct list_head *list)
* the reader page). But if the next page is a header page,
* its flags will be non zero.
*/
-static int inline
+static inline int
rb_is_head_page(struct ring_buffer_per_cpu *cpu_buffer,
struct buffer_page *page, struct list_head *list)
{
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 3249b4f77ef0..8008ddcfbf20 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -391,8 +391,8 @@ static int process_ops(struct filter_pred *preds,
struct filter_pred *op, void *rec)
{
struct filter_pred *pred;
+ int match = 0;
int type;
- int match;
int i;
/*
diff --git a/mm/internal.h b/mm/internal.h
index 69488205723d..3438dd43a062 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -245,11 +245,6 @@ static inline void mminit_validate_memmodel_limits(unsigned long *start_pfn,
}
#endif /* CONFIG_SPARSEMEM */
-int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long start, int len, unsigned int foll_flags,
- struct page **pages, struct vm_area_struct **vmas,
- int *nonblocking);
-
#define ZONE_RECLAIM_NOSCAN -2
#define ZONE_RECLAIM_FULL -1
#define ZONE_RECLAIM_SOME 0
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 0207c2f6f8bd..99ccb4472623 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1487,35 +1487,3 @@ done:
/* keep elevated page count for bad page */
return ret;
}
-
-/*
- * The caller must hold current->mm->mmap_sem in read mode.
- */
-int is_hwpoison_address(unsigned long addr)
-{
- pgd_t *pgdp;
- pud_t pud, *pudp;
- pmd_t pmd, *pmdp;
- pte_t pte, *ptep;
- swp_entry_t entry;
-
- pgdp = pgd_offset(current->mm, addr);
- if (!pgd_present(*pgdp))
- return 0;
- pudp = pud_offset(pgdp, addr);
- pud = *pudp;
- if (!pud_present(pud) || pud_large(pud))
- return 0;
- pmdp = pmd_offset(pudp, addr);
- pmd = *pmdp;
- if (!pmd_present(pmd) || pmd_large(pmd))
- return 0;
- ptep = pte_offset_map(pmdp, addr);
- pte = *ptep;
- pte_unmap(ptep);
- if (!is_swap_pte(pte))
- return 0;
- entry = pte_to_swp_entry(pte);
- return is_hwpoison_entry(entry);
-}
-EXPORT_SYMBOL_GPL(is_hwpoison_address);
diff --git a/mm/memory.c b/mm/memory.c
index 5823698c2b71..e48945ab362b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1410,6 +1410,55 @@ no_page_table:
return page;
}
+/**
+ * __get_user_pages() - pin user pages in memory
+ * @tsk: task_struct of target task
+ * @mm: mm_struct of target mm
+ * @start: starting user address
+ * @nr_pages: number of pages from start to pin
+ * @gup_flags: flags modifying pin behaviour
+ * @pages: array that receives pointers to the pages pinned.
+ * Should be at least nr_pages long. Or NULL, if caller
+ * only intends to ensure the pages are faulted in.
+ * @vmas: array of pointers to vmas corresponding to each page.
+ * Or NULL if the caller does not require them.
+ * @nonblocking: whether waiting for disk IO or mmap_sem contention
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno. Each page returned must be released
+ * with a put_page() call when it is finished with. vmas will only
+ * remain valid while mmap_sem is held.
+ *
+ * Must be called with mmap_sem held for read or write.
+ *
+ * __get_user_pages walks a process's page tables and takes a reference to
+ * each struct page that each user address corresponds to at a given
+ * instant. That is, it takes the page that would be accessed if a user
+ * thread accesses the given user virtual address at that instant.
+ *
+ * This does not guarantee that the page exists in the user mappings when
+ * __get_user_pages returns, and there may even be a completely different
+ * page there in some cases (eg. if mmapped pagecache has been invalidated
+ * and subsequently re faulted). However it does guarantee that the page
+ * won't be freed completely. And mostly callers simply care that the page
+ * contains data that was valid *at some point in time*. Typically, an IO
+ * or similar operation cannot guarantee anything stronger anyway because
+ * locks can't be held over the syscall boundary.
+ *
+ * If @gup_flags & FOLL_WRITE == 0, the page must not be written to. If
+ * the page is written to, set_page_dirty (or set_page_dirty_lock, as
+ * appropriate) must be called after the page is finished with, and
+ * before put_page is called.
+ *
+ * If @nonblocking != NULL, __get_user_pages will not wait for disk IO
+ * or mmap_sem contention, and if waiting is needed to pin all pages,
+ * *@nonblocking will be set to 0.
+ *
+ * In most cases, get_user_pages or get_user_pages_fast should be used
+ * instead of __get_user_pages. __get_user_pages should be used only if
+ * you need some special @gup_flags.
+ */
int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
unsigned long start, int nr_pages, unsigned int gup_flags,
struct page **pages, struct vm_area_struct **vmas,
@@ -1527,9 +1576,16 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
if (ret & VM_FAULT_ERROR) {
if (ret & VM_FAULT_OOM)
return i ? i : -ENOMEM;
- if (ret &
- (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE|
- VM_FAULT_SIGBUS))
+ if (ret & (VM_FAULT_HWPOISON |
+ VM_FAULT_HWPOISON_LARGE)) {
+ if (i)
+ return i;
+ else if (gup_flags & FOLL_HWPOISON)
+ return -EHWPOISON;
+ else
+ return -EFAULT;
+ }
+ if (ret & VM_FAULT_SIGBUS)
return i ? i : -EFAULT;
BUG();
}
@@ -1578,6 +1634,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
} while (nr_pages);
return i;
}
+EXPORT_SYMBOL(__get_user_pages);
/**
* get_user_pages() - pin user pages in memory
@@ -2115,10 +2172,10 @@ EXPORT_SYMBOL_GPL(apply_to_page_range);
* handle_pte_fault chooses page fault handler according to an entry
* which was read non-atomically. Before making any commitment, on
* those architectures or configurations (e.g. i386 with PAE) which
- * might give a mix of unmatched parts, do_swap_page and do_file_page
+ * might give a mix of unmatched parts, do_swap_page and do_nonlinear_fault
* must check under lock before unmapping the pte and proceeding
* (but do_wp_page is only called after already making such a check;
- * and do_anonymous_page and do_no_page can safely check later on).
+ * and do_anonymous_page can safely check later on).
*/
static inline int pte_unmap_same(struct mm_struct *mm, pmd_t *pmd,
pte_t *page_table, pte_t orig_pte)
@@ -2314,7 +2371,7 @@ reuse:
* bit after it clear all dirty ptes, but before a racing
* do_wp_page installs a dirty pte.
*
- * do_no_page is protected similarly.
+ * __do_fault is protected similarly.
*/
if (!page_mkwrite) {
wait_on_page_locked(dirty_page);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b53ec99f1428..78062ab641ff 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -993,7 +993,7 @@ int do_migrate_pages(struct mm_struct *mm,
* most recent <s, d> pair that moved (s != d). If we find a pair
* that not only moved, but what's better, moved to an empty slot
* (d is not set in tmp), then we break out then, with that pair.
- * Otherwise when we finish scannng from_tmp, we at least have the
+ * Otherwise when we finish scanning from_tmp, we at least have the
* most recent <s, d> pair that moved. If we get all the way through
* the scan of tmp without finding any node that moved, much less
* moved to an empty node, then there is nothing left worth migrating.
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bd7625676a64..7945247b1e53 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -286,7 +286,7 @@ static void bad_page(struct page *page)
/* Don't complain about poisoned pages */
if (PageHWPoison(page)) {
- __ClearPageBuddy(page);
+ reset_page_mapcount(page); /* remove PageBuddy */
return;
}
@@ -317,7 +317,7 @@ static void bad_page(struct page *page)
dump_stack();
out:
/* Leave bad fields for debug, except PageBuddy could make trouble */
- __ClearPageBuddy(page);
+ reset_page_mapcount(page); /* remove PageBuddy */
add_taint(TAINT_BAD_PAGE);
}
diff --git a/mm/shmem.c b/mm/shmem.c
index 41f82bb59eec..048a95a5244d 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -779,7 +779,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
* If truncating down to a partial page, then
* if that page is already allocated, hold it
* in memory until the truncation is over, so
- * truncate_partial_page cannnot miss it were
+ * truncate_partial_page cannot miss it were
* it assigned to swap.
*/
if (newsize & (PAGE_CACHE_SIZE-1)) {
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 2429ca2d7b06..5ec12971af6b 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -36,6 +36,7 @@
#include <linux/file.h>
#include <linux/init.h>
#include <linux/wait.h>
+#include <linux/mutex.h>
#include <net/sock.h>
#include <linux/input.h>
@@ -316,24 +317,144 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
return hidp_queue_report(session, buf, rsize);
}
+static int hidp_get_raw_report(struct hid_device *hid,
+ unsigned char report_number,
+ unsigned char *data, size_t count,
+ unsigned char report_type)
+{
+ struct hidp_session *session = hid->driver_data;
+ struct sk_buff *skb;
+ size_t len;
+ int numbered_reports = hid->report_enum[report_type].numbered;
+
+ switch (report_type) {
+ case HID_FEATURE_REPORT:
+ report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
+ break;
+ case HID_INPUT_REPORT:
+ report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_INPUT;
+ break;
+ case HID_OUTPUT_REPORT:
+ report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_OUPUT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&session->report_mutex))
+ return -ERESTARTSYS;
+
+ /* Set up our wait, and send the report request to the device. */
+ session->waiting_report_type = report_type & HIDP_DATA_RTYPE_MASK;
+ session->waiting_report_number = numbered_reports ? report_number : -1;
+ set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ data[0] = report_number;
+ if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1))
+ goto err_eio;
+
+ /* Wait for the return of the report. The returned report
+ gets put in session->report_return. */
+ while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
+ int res;
+
+ res = wait_event_interruptible_timeout(session->report_queue,
+ !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
+ 5*HZ);
+ if (res == 0) {
+ /* timeout */
+ goto err_eio;
+ }
+ if (res < 0) {
+ /* signal */
+ goto err_restartsys;
+ }
+ }
+
+ skb = session->report_return;
+ if (skb) {
+ len = skb->len < count ? skb->len : count;
+ memcpy(data, skb->data, len);
+
+ kfree_skb(skb);
+ session->report_return = NULL;
+ } else {
+ /* Device returned a HANDSHAKE, indicating protocol error. */
+ len = -EIO;
+ }
+
+ clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ mutex_unlock(&session->report_mutex);
+
+ return len;
+
+err_restartsys:
+ clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ mutex_unlock(&session->report_mutex);
+ return -ERESTARTSYS;
+err_eio:
+ clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ mutex_unlock(&session->report_mutex);
+ return -EIO;
+}
+
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
unsigned char report_type)
{
+ struct hidp_session *session = hid->driver_data;
+ int ret;
+
switch (report_type) {
case HID_FEATURE_REPORT:
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
break;
case HID_OUTPUT_REPORT:
- report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
+ report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
break;
default:
return -EINVAL;
}
+ if (mutex_lock_interruptible(&session->report_mutex))
+ return -ERESTARTSYS;
+
+ /* Set up our wait, and send the report request to the device. */
+ set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
if (hidp_send_ctrl_message(hid->driver_data, report_type,
- data, count))
- return -ENOMEM;
- return count;
+ data, count)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Wait for the ACK from the device. */
+ while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
+ int res;
+
+ res = wait_event_interruptible_timeout(session->report_queue,
+ !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
+ 10*HZ);
+ if (res == 0) {
+ /* timeout */
+ ret = -EIO;
+ goto err;
+ }
+ if (res < 0) {
+ /* signal */
+ ret = -ERESTARTSYS;
+ goto err;
+ }
+ }
+
+ if (!session->output_report_success) {
+ ret = -EIO;
+ goto err;
+ }
+
+ ret = count;
+
+err:
+ clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+ mutex_unlock(&session->report_mutex);
+ return ret;
}
static void hidp_idle_timeout(unsigned long arg)
@@ -360,16 +481,22 @@ static void hidp_process_handshake(struct hidp_session *session,
unsigned char param)
{
BT_DBG("session %p param 0x%02x", session, param);
+ session->output_report_success = 0; /* default condition */
switch (param) {
case HIDP_HSHK_SUCCESSFUL:
/* FIXME: Call into SET_ GET_ handlers here */
+ session->output_report_success = 1;
break;
case HIDP_HSHK_NOT_READY:
case HIDP_HSHK_ERR_INVALID_REPORT_ID:
case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
case HIDP_HSHK_ERR_INVALID_PARAMETER:
+ if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
+ clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ wake_up_interruptible(&session->report_queue);
+ }
/* FIXME: Call into SET_ GET_ handlers here */
break;
@@ -388,6 +515,12 @@ static void hidp_process_handshake(struct hidp_session *session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
break;
}
+
+ /* Wake up the waiting thread. */
+ if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
+ clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+ wake_up_interruptible(&session->report_queue);
+ }
}
static void hidp_process_hid_control(struct hidp_session *session,
@@ -406,9 +539,11 @@ static void hidp_process_hid_control(struct hidp_session *session,
}
}
-static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
+/* Returns true if the passed-in skb should be freed by the caller. */
+static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
unsigned char param)
{
+ int done_with_skb = 1;
BT_DBG("session %p skb %p len %d param 0x%02x", session, skb, skb->len, param);
switch (param) {
@@ -420,7 +555,6 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
if (session->hid)
hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
-
break;
case HIDP_DATA_RTYPE_OTHER:
@@ -432,12 +566,27 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
__hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
}
+
+ if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
+ param == session->waiting_report_type) {
+ if (session->waiting_report_number < 0 ||
+ session->waiting_report_number == skb->data[0]) {
+ /* hidp_get_raw_report() is waiting on this report. */
+ session->report_return = skb;
+ done_with_skb = 0;
+ clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+ wake_up_interruptible(&session->report_queue);
+ }
+ }
+
+ return done_with_skb;
}
static void hidp_recv_ctrl_frame(struct hidp_session *session,
struct sk_buff *skb)
{
unsigned char hdr, type, param;
+ int free_skb = 1;
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
@@ -457,7 +606,7 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
break;
case HIDP_TRANS_DATA:
- hidp_process_data(session, skb, param);
+ free_skb = hidp_process_data(session, skb, param);
break;
default:
@@ -466,7 +615,8 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
break;
}
- kfree_skb(skb);
+ if (free_skb)
+ kfree_skb(skb);
}
static void hidp_recv_intr_frame(struct hidp_session *session,
@@ -566,6 +716,8 @@ static int hidp_session(void *arg)
init_waitqueue_entry(&intr_wait, current);
add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
add_wait_queue(sk_sleep(intr_sk), &intr_wait);
+ session->waiting_for_startup = 0;
+ wake_up_interruptible(&session->startup_queue);
while (!atomic_read(&session->terminate)) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -757,6 +909,8 @@ static struct hid_ll_driver hidp_hid_driver = {
.hidinput_input_event = hidp_hidinput_event,
};
+/* This function sets up the hid device. It does not add it
+ to the HID system. That is done in hidp_add_connection(). */
static int hidp_setup_hid(struct hidp_session *session,
struct hidp_connadd_req *req)
{
@@ -796,18 +950,11 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->dev.parent = hidp_get_device(session);
hid->ll_driver = &hidp_hid_driver;
+ hid->hid_get_raw_report = hidp_get_raw_report;
hid->hid_output_raw_report = hidp_output_raw_report;
- err = hid_add_device(hid);
- if (err < 0)
- goto failed;
-
return 0;
-failed:
- hid_destroy_device(hid);
- session->hid = NULL;
-
fault:
kfree(session->rd_data);
session->rd_data = NULL;
@@ -856,6 +1003,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
skb_queue_head_init(&session->ctrl_transmit);
skb_queue_head_init(&session->intr_transmit);
+ mutex_init(&session->report_mutex);
+ init_waitqueue_head(&session->report_queue);
+ init_waitqueue_head(&session->startup_queue);
+ session->waiting_for_startup = 1;
session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
session->idle_to = req->idle_to;
@@ -878,6 +1029,14 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
err = kernel_thread(hidp_session, session, CLONE_KERNEL);
if (err < 0)
goto unlink;
+ while (session->waiting_for_startup) {
+ wait_event_interruptible(session->startup_queue,
+ !session->waiting_for_startup);
+ }
+
+ err = hid_add_device(session->hid);
+ if (err < 0)
+ goto err_add_device;
if (session->input) {
hidp_send_ctrl_message(session,
@@ -891,6 +1050,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
up_write(&hidp_session_sem);
return 0;
+err_add_device:
+ hid_destroy_device(session->hid);
+ session->hid = NULL;
+ atomic_inc(&session->terminate);
+ hidp_schedule(session);
+
unlink:
hidp_del_timer(session);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 8d934a19da0a..13de5fa03480 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -80,6 +80,8 @@
#define HIDP_VIRTUAL_CABLE_UNPLUG 0
#define HIDP_BOOT_PROTOCOL_MODE 1
#define HIDP_BLUETOOTH_VENDOR_ID 9
+#define HIDP_WAITING_FOR_RETURN 10
+#define HIDP_WAITING_FOR_SEND_ACK 11
struct hidp_connadd_req {
int ctrl_sock; // Connected control socket
@@ -154,9 +156,22 @@ struct hidp_session {
struct sk_buff_head ctrl_transmit;
struct sk_buff_head intr_transmit;
+ /* Used in hidp_get_raw_report() */
+ int waiting_report_type; /* HIDP_DATA_RTYPE_* */
+ int waiting_report_number; /* -1 for not numbered */
+ struct mutex report_mutex;
+ struct sk_buff *report_return;
+ wait_queue_head_t report_queue;
+
+ /* Used in hidp_output_raw_report() */
+ int output_report_success; /* boolean */
+
/* Report descriptor */
__u8 *rd_data;
uint rd_size;
+
+ wait_queue_head_t startup_queue;
+ int waiting_for_startup;
};
static inline void hidp_schedule(struct hidp_session *session)
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 133fd22ea287..7b39f3ed2fda 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -357,8 +357,8 @@ EXPORT_SYMBOL(dev_addr_add_multiple);
/**
* dev_addr_del_multiple - Delete device addresses by another device
* @to_dev: device where the addresses will be deleted
- * @from_dev: device by which addresses the addresses will be deleted
- * @addr_type: address type - 0 means type will used from from_dev
+ * @from_dev: device supplying the addresses to be deleted
+ * @addr_type: address type - 0 means type will be used from from_dev
*
* Deletes addresses in to device by the list of addresses in from device.
*
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 633a6c266136..b53197233709 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -124,7 +124,7 @@ out:
}
EXPORT_SYMBOL(__inet6_lookup_established);
-static int inline compute_score(struct sock *sk, struct net *net,
+static inline int compute_score(struct sock *sk, struct net *net,
const unsigned short hnum,
const struct in6_addr *daddr,
const int dif)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 081dcaf6577b..ce4596ed1268 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -169,7 +169,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
return cpu_to_le16(dur);
}
-static int inline is_ieee80211_device(struct ieee80211_local *local,
+static inline int is_ieee80211_device(struct ieee80211_local *local,
struct net_device *dev)
{
return local == wdev_priv(dev->ieee80211_ptr);
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 45dbf1521b9a..f3914d0c5079 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -417,7 +417,7 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
gss_msg->msg.len += len;
}
if (mech->gm_upcall_enctypes) {
- len = sprintf(p, mech->gm_upcall_enctypes);
+ len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes);
p += len;
gss_msg->msg.len += len;
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index f375decc024b..9022f0a6503e 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -750,7 +750,7 @@ static struct gss_api_mech gss_kerberos_mech = {
.gm_ops = &gss_kerberos_ops,
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
.gm_pfs = gss_kerberos_pfs,
- .gm_upcall_enctypes = "enctypes=18,17,16,23,3,1,2 ",
+ .gm_upcall_enctypes = "18,17,16,23,3,1,2",
};
static int __init init_kerberos_module(void)
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 57d344cf2256..e7a96e478f63 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -436,7 +436,9 @@ void rpc_killall_tasks(struct rpc_clnt *clnt)
if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
rovr->tk_flags |= RPC_TASK_KILLED;
rpc_exit(rovr, -EIO);
- rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr);
+ if (RPC_IS_QUEUED(rovr))
+ rpc_wake_up_queued_task(rovr->tk_waitqueue,
+ rovr);
}
}
spin_unlock(&clnt->cl_lock);
@@ -597,6 +599,14 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
}
}
+void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt)
+{
+ rpc_task_release_client(task);
+ rpc_task_set_client(task, clnt);
+}
+EXPORT_SYMBOL_GPL(rpc_task_reset_client);
+
+
static void
rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
{
@@ -636,12 +646,6 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
rpc_task_set_client(task, task_setup_data->rpc_client);
rpc_task_set_rpc_message(task, task_setup_data->rpc_message);
- if (task->tk_status != 0) {
- int ret = task->tk_status;
- rpc_put_task(task);
- return ERR_PTR(ret);
- }
-
if (task->tk_action == NULL)
rpc_call_start(task);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 3fc8624fcd17..ffb687671da0 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -299,15 +299,8 @@ static void rpc_make_runnable(struct rpc_task *task)
if (rpc_test_and_set_running(task))
return;
if (RPC_IS_ASYNC(task)) {
- int status;
-
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
- status = queue_work(rpciod_workqueue, &task->u.tk_work);
- if (status < 0) {
- printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
- task->tk_status = status;
- return;
- }
+ queue_work(rpciod_workqueue, &task->u.tk_work);
} else
wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);
}
@@ -637,14 +630,12 @@ static void __rpc_execute(struct rpc_task *task)
save_callback = task->tk_callback;
task->tk_callback = NULL;
save_callback(task);
- }
-
- /*
- * Perform the next FSM step.
- * tk_action may be NULL when the task has been killed
- * by someone else.
- */
- if (!RPC_IS_QUEUED(task)) {
+ } else {
+ /*
+ * Perform the next FSM step.
+ * tk_action may be NULL when the task has been killed
+ * by someone else.
+ */
if (task->tk_action == NULL)
break;
task->tk_action(task);
@@ -843,12 +834,6 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
}
rpc_init_task(task, setup_data);
- if (task->tk_status < 0) {
- int err = task->tk_status;
- rpc_put_task(task);
- return ERR_PTR(err);
- }
-
task->tk_flags |= flags;
dprintk("RPC: allocated task %p\n", task);
return task;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 856274d7e85c..9494c3767356 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -202,10 +202,9 @@ int xprt_reserve_xprt(struct rpc_task *task)
goto out_sleep;
}
xprt->snd_task = task;
- if (req) {
- req->rq_bytes_sent = 0;
- req->rq_ntrans++;
- }
+ req->rq_bytes_sent = 0;
+ req->rq_ntrans++;
+
return 1;
out_sleep:
@@ -213,7 +212,7 @@ out_sleep:
task->tk_pid, xprt);
task->tk_timeout = 0;
task->tk_status = -EAGAIN;
- if (req && req->rq_ntrans)
+ if (req->rq_ntrans)
rpc_sleep_on(&xprt->resend, task, NULL);
else
rpc_sleep_on(&xprt->sending, task, NULL);
@@ -965,7 +964,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
xprt = kzalloc(size, GFP_KERNEL);
if (xprt == NULL)
goto out;
- kref_init(&xprt->kref);
+ atomic_set(&xprt->count, 1);
xprt->max_reqs = max_req;
xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
@@ -1145,13 +1144,11 @@ found:
/**
* xprt_destroy - destroy an RPC transport, killing off all requests.
- * @kref: kref for the transport to destroy
+ * @xprt: transport to destroy
*
*/
-static void xprt_destroy(struct kref *kref)
+static void xprt_destroy(struct rpc_xprt *xprt)
{
- struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref);
-
dprintk("RPC: destroying transport %p\n", xprt);
xprt->shutdown = 1;
del_timer_sync(&xprt->timer);
@@ -1175,7 +1172,8 @@ static void xprt_destroy(struct kref *kref)
*/
void xprt_put(struct rpc_xprt *xprt)
{
- kref_put(&xprt->kref, xprt_destroy);
+ if (atomic_dec_and_test(&xprt->count))
+ xprt_destroy(xprt);
}
/**
@@ -1185,6 +1183,7 @@ void xprt_put(struct rpc_xprt *xprt)
*/
struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
{
- kref_get(&xprt->kref);
- return xprt;
+ if (atomic_inc_not_zero(&xprt->count))
+ return xprt;
+ return NULL;
}
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index 2ac3f6e8adff..554d0814c875 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -87,6 +87,8 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs)
{
int len, n = 0, p;
+ int page_base;
+ struct page **ppages;
if (pos == 0 && xdrbuf->head[0].iov_len) {
seg[n].mr_page = NULL;
@@ -95,34 +97,32 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos,
++n;
}
- if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) {
- if (n == nsegs)
- return 0;
- seg[n].mr_page = xdrbuf->pages[0];
- seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base;
- seg[n].mr_len = min_t(u32,
- PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len);
- len = xdrbuf->page_len - seg[n].mr_len;
+ len = xdrbuf->page_len;
+ ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT);
+ page_base = xdrbuf->page_base & ~PAGE_MASK;
+ p = 0;
+ while (len && n < nsegs) {
+ seg[n].mr_page = ppages[p];
+ seg[n].mr_offset = (void *)(unsigned long) page_base;
+ seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len);
+ BUG_ON(seg[n].mr_len > PAGE_SIZE);
+ len -= seg[n].mr_len;
++n;
- p = 1;
- while (len > 0) {
- if (n == nsegs)
- return 0;
- seg[n].mr_page = xdrbuf->pages[p];
- seg[n].mr_offset = NULL;
- seg[n].mr_len = min_t(u32, PAGE_SIZE, len);
- len -= seg[n].mr_len;
- ++n;
- ++p;
- }
+ ++p;
+ page_base = 0; /* page offset only applies to first page */
}
+ /* Message overflows the seg array */
+ if (len && n == nsegs)
+ return 0;
+
if (xdrbuf->tail[0].iov_len) {
/* the rpcrdma protocol allows us to omit any trailing
* xdr pad bytes, saving the server an RDMA operation. */
if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize)
return n;
if (n == nsegs)
+ /* Tail remains, but we're out of segments */
return 0;
seg[n].mr_page = NULL;
seg[n].mr_offset = xdrbuf->tail[0].iov_base;
@@ -296,6 +296,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
int copy_len;
unsigned char *srcp, *destp;
struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt);
+ int page_base;
+ struct page **ppages;
destp = rqst->rq_svec[0].iov_base;
curlen = rqst->rq_svec[0].iov_len;
@@ -324,28 +326,25 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad)
__func__, destp + copy_len, curlen);
rqst->rq_svec[0].iov_len += curlen;
}
-
r_xprt->rx_stats.pullup_copy_count += copy_len;
- npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT;
+
+ page_base = rqst->rq_snd_buf.page_base;
+ ppages = rqst->rq_snd_buf.pages + (page_base >> PAGE_SHIFT);
+ page_base &= ~PAGE_MASK;
+ npages = PAGE_ALIGN(page_base+copy_len) >> PAGE_SHIFT;
for (i = 0; copy_len && i < npages; i++) {
- if (i == 0)
- curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base;
- else
- curlen = PAGE_SIZE;
+ curlen = PAGE_SIZE - page_base;
if (curlen > copy_len)
curlen = copy_len;
dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n",
__func__, i, destp, copy_len, curlen);
- srcp = kmap_atomic(rqst->rq_snd_buf.pages[i],
- KM_SKB_SUNRPC_DATA);
- if (i == 0)
- memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen);
- else
- memcpy(destp, srcp, curlen);
+ srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA);
+ memcpy(destp, srcp+page_base, curlen);
kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA);
rqst->rq_svec[0].iov_len += curlen;
destp += curlen;
copy_len -= curlen;
+ page_base = 0;
}
/* header now contains entire send message */
return pad;
@@ -606,6 +605,8 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
{
int i, npages, curlen, olen;
char *destp;
+ struct page **ppages;
+ int page_base;
curlen = rqst->rq_rcv_buf.head[0].iov_len;
if (curlen > copy_len) { /* write chunk header fixup */
@@ -624,32 +625,29 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
olen = copy_len;
i = 0;
rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen;
+ page_base = rqst->rq_rcv_buf.page_base;
+ ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT);
+ page_base &= ~PAGE_MASK;
+
if (copy_len && rqst->rq_rcv_buf.page_len) {
- npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base +
+ npages = PAGE_ALIGN(page_base +
rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT;
for (; i < npages; i++) {
- if (i == 0)
- curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base;
- else
- curlen = PAGE_SIZE;
+ curlen = PAGE_SIZE - page_base;
if (curlen > copy_len)
curlen = copy_len;
dprintk("RPC: %s: page %d"
" srcp 0x%p len %d curlen %d\n",
__func__, i, srcp, copy_len, curlen);
- destp = kmap_atomic(rqst->rq_rcv_buf.pages[i],
- KM_SKB_SUNRPC_DATA);
- if (i == 0)
- memcpy(destp + rqst->rq_rcv_buf.page_base,
- srcp, curlen);
- else
- memcpy(destp, srcp, curlen);
- flush_dcache_page(rqst->rq_rcv_buf.pages[i]);
+ destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA);
+ memcpy(destp + page_base, srcp, curlen);
+ flush_dcache_page(ppages[i]);
kunmap_atomic(destp, KM_SKB_SUNRPC_DATA);
srcp += curlen;
copy_len -= curlen;
if (copy_len == 0)
break;
+ page_base = 0;
}
rqst->rq_rcv_buf.page_len = olen - copy_len;
} else
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 5f4c7b3bc711..d4297dc43dc4 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -144,6 +144,7 @@ rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
static inline
void rpcrdma_event_process(struct ib_wc *wc)
{
+ struct rpcrdma_mw *frmr;
struct rpcrdma_rep *rep =
(struct rpcrdma_rep *)(unsigned long) wc->wr_id;
@@ -154,15 +155,23 @@ void rpcrdma_event_process(struct ib_wc *wc)
return;
if (IB_WC_SUCCESS != wc->status) {
- dprintk("RPC: %s: %s WC status %X, connection lost\n",
- __func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send",
- wc->status);
+ dprintk("RPC: %s: WC opcode %d status %X, connection lost\n",
+ __func__, wc->opcode, wc->status);
rep->rr_len = ~0U;
- rpcrdma_schedule_tasklet(rep);
+ if (wc->opcode != IB_WC_FAST_REG_MR && wc->opcode != IB_WC_LOCAL_INV)
+ rpcrdma_schedule_tasklet(rep);
return;
}
switch (wc->opcode) {
+ case IB_WC_FAST_REG_MR:
+ frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
+ frmr->r.frmr.state = FRMR_IS_VALID;
+ break;
+ case IB_WC_LOCAL_INV:
+ frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id;
+ frmr->r.frmr.state = FRMR_IS_INVALID;
+ break;
case IB_WC_RECV:
rep->rr_len = wc->byte_len;
ib_dma_sync_single_for_cpu(
@@ -1450,6 +1459,12 @@ rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing)
seg->mr_dma = ib_dma_map_single(ia->ri_id->device,
seg->mr_offset,
seg->mr_dmalen, seg->mr_dir);
+ if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) {
+ dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n",
+ __func__,
+ (unsigned long long)seg->mr_dma,
+ seg->mr_offset, seg->mr_dmalen);
+ }
}
static void
@@ -1469,7 +1484,8 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
struct rpcrdma_xprt *r_xprt)
{
struct rpcrdma_mr_seg *seg1 = seg;
- struct ib_send_wr frmr_wr, *bad_wr;
+ struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr;
+
u8 key;
int len, pageoff;
int i, rc;
@@ -1484,6 +1500,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
rpcrdma_map_one(ia, seg, writing);
seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma;
len += seg->mr_len;
+ BUG_ON(seg->mr_len > PAGE_SIZE);
++seg;
++i;
/* Check for holes */
@@ -1494,26 +1511,45 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg,
dprintk("RPC: %s: Using frmr %p to map %d segments\n",
__func__, seg1->mr_chunk.rl_mw, i);
+ if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) {
+ dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n",
+ __func__,
+ seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey);
+ /* Invalidate before using. */
+ memset(&invalidate_wr, 0, sizeof invalidate_wr);
+ invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
+ invalidate_wr.next = &frmr_wr;
+ invalidate_wr.opcode = IB_WR_LOCAL_INV;
+ invalidate_wr.send_flags = IB_SEND_SIGNALED;
+ invalidate_wr.ex.invalidate_rkey =
+ seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
+ DECR_CQCOUNT(&r_xprt->rx_ep);
+ post_wr = &invalidate_wr;
+ } else
+ post_wr = &frmr_wr;
+
/* Bump the key */
key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF);
ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key);
/* Prepare FRMR WR */
memset(&frmr_wr, 0, sizeof frmr_wr);
+ frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
frmr_wr.opcode = IB_WR_FAST_REG_MR;
- frmr_wr.send_flags = 0; /* unsignaled */
+ frmr_wr.send_flags = IB_SEND_SIGNALED;
frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma;
frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl;
frmr_wr.wr.fast_reg.page_list_len = i;
frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT;
+ BUG_ON(frmr_wr.wr.fast_reg.length < len);
frmr_wr.wr.fast_reg.access_flags = (writing ?
IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
IB_ACCESS_REMOTE_READ);
frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
DECR_CQCOUNT(&r_xprt->rx_ep);
- rc = ib_post_send(ia->ri_id->qp, &frmr_wr, &bad_wr);
+ rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr);
if (rc) {
dprintk("RPC: %s: failed ib_post_send for register,"
@@ -1542,8 +1578,9 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg,
rpcrdma_unmap_one(ia, seg++);
memset(&invalidate_wr, 0, sizeof invalidate_wr);
+ invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw;
invalidate_wr.opcode = IB_WR_LOCAL_INV;
- invalidate_wr.send_flags = 0; /* unsignaled */
+ invalidate_wr.send_flags = IB_SEND_SIGNALED;
invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey;
DECR_CQCOUNT(&r_xprt->rx_ep);
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index c7a7eba991bc..cae761a8536c 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -164,6 +164,7 @@ struct rpcrdma_mr_seg { /* chunk descriptors */
struct {
struct ib_fast_reg_page_list *fr_pgl;
struct ib_mr *fr_mr;
+ enum { FRMR_IS_INVALID, FRMR_IS_VALID } state;
} frmr;
} r;
struct list_head mw_list;
diff --git a/sound/Kconfig b/sound/Kconfig
index fcad760f5691..1fef141ef8e7 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -97,6 +97,8 @@ source "sound/sh/Kconfig"
# here assuming USB is defined before ALSA
source "sound/usb/Kconfig"
+source "sound/firewire/Kconfig"
+
# the following will depend on the order of config.
# here assuming PCMCIA is defined before ALSA
source "sound/pcmcia/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index ec467decfa79..ce9132b1c395 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
- sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
+ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 7c1fc64cb53d..d0cead38d5fb 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -210,6 +210,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
if (mask & ISR_RXINTR) {
struct aaci_runtime *aacirun = &aaci->capture;
+ bool period_elapsed = false;
void *ptr;
if (!aacirun->substream || !aacirun->start) {
@@ -222,15 +223,12 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
ptr = aacirun->ptr;
do {
- unsigned int len = aacirun->fifosz;
+ unsigned int len = aacirun->fifo_bytes;
u32 val;
if (aacirun->bytes <= 0) {
aacirun->bytes += aacirun->period;
- aacirun->ptr = ptr;
- spin_unlock(&aacirun->lock);
- snd_pcm_period_elapsed(aacirun->substream);
- spin_lock(&aacirun->lock);
+ period_elapsed = true;
}
if (!(aacirun->cr & CR_EN))
break;
@@ -260,6 +258,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
aacirun->ptr = ptr;
spin_unlock(&aacirun->lock);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(aacirun->substream);
}
if (mask & ISR_URINTR) {
@@ -269,6 +270,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
if (mask & ISR_TXINTR) {
struct aaci_runtime *aacirun = &aaci->playback;
+ bool period_elapsed = false;
void *ptr;
if (!aacirun->substream || !aacirun->start) {
@@ -281,15 +283,12 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
ptr = aacirun->ptr;
do {
- unsigned int len = aacirun->fifosz;
+ unsigned int len = aacirun->fifo_bytes;
u32 val;
if (aacirun->bytes <= 0) {
aacirun->bytes += aacirun->period;
- aacirun->ptr = ptr;
- spin_unlock(&aacirun->lock);
- snd_pcm_period_elapsed(aacirun->substream);
- spin_lock(&aacirun->lock);
+ period_elapsed = true;
}
if (!(aacirun->cr & CR_EN))
break;
@@ -319,6 +318,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
aacirun->ptr = ptr;
spin_unlock(&aacirun->lock);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(aacirun->substream);
}
}
@@ -361,7 +363,7 @@ static struct snd_pcm_hardware aaci_hw_info = {
/* rates are setup from the AC'97 codec */
.channels_min = 2,
- .channels_max = 6,
+ .channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 256,
.period_bytes_max = PAGE_SIZE,
@@ -369,12 +371,46 @@ static struct snd_pcm_hardware aaci_hw_info = {
.periods_max = PAGE_SIZE / 16,
};
-static int __aaci_pcm_open(struct aaci *aaci,
- struct snd_pcm_substream *substream,
- struct aaci_runtime *aacirun)
+/*
+ * We can support two and four channel audio. Unfortunately
+ * six channel audio requires a non-standard channel ordering:
+ * 2 -> FL(3), FR(4)
+ * 4 -> FL(3), FR(4), SL(7), SR(8)
+ * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
+ * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
+ * This requires an ALSA configuration file to correct.
+ */
+static int aaci_rule_channels(struct snd_pcm_hw_params *p,
+ struct snd_pcm_hw_rule *rule)
+{
+ static unsigned int channel_list[] = { 2, 4, 6 };
+ struct aaci *aaci = rule->private;
+ unsigned int mask = 1 << 0, slots;
+
+ /* pcms[0] is the our 5.1 PCM instance. */
+ slots = aaci->ac97_bus->pcms[0].r[0].slots;
+ if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
+ mask |= 1 << 1;
+ if (slots & (1 << AC97_SLOT_LFE))
+ mask |= 1 << 2;
+ }
+
+ return snd_interval_list(hw_param_interval(p, rule->var),
+ ARRAY_SIZE(channel_list), channel_list, mask);
+}
+
+static int aaci_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- int ret;
+ struct aaci *aaci = substream->private_data;
+ struct aaci_runtime *aacirun;
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ aacirun = &aaci->playback;
+ } else {
+ aacirun = &aaci->capture;
+ }
aacirun->substream = substream;
runtime->private_data = aacirun;
@@ -382,27 +418,37 @@ static int __aaci_pcm_open(struct aaci *aaci,
runtime->hw.rates = aacirun->pcm->rates;
snd_pcm_limit_hw_rates(runtime);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- aacirun->pcm->r[1].slots)
- snd_ac97_pcm_double_rate_rules(runtime);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw.channels_max = 6;
+
+ /* Add rule describing channel dependency. */
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ aaci_rule_channels, aaci,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (ret)
+ return ret;
+
+ if (aacirun->pcm->r[1].slots)
+ snd_ac97_pcm_double_rate_rules(runtime);
+ }
/*
- * FIXME: ALSA specifies fifo_size in bytes. If we're in normal
- * mode, each 32-bit word contains one sample. If we're in
- * compact mode, each 32-bit word contains two samples, effectively
- * halving the FIFO size. However, we don't know for sure which
- * we'll be using at this point. We set this to the lower limit.
+ * ALSA wants the byte-size of the FIFOs. As we only support
+ * 16-bit samples, this is twice the FIFO depth irrespective
+ * of whether it's in compact mode or not.
*/
- runtime->hw.fifo_size = aaci->fifosize * 2;
-
- ret = request_irq(aaci->dev->irq[0], aaci_irq, IRQF_SHARED|IRQF_DISABLED,
- DRIVER_NAME, aaci);
- if (ret)
- goto out;
-
- return 0;
+ runtime->hw.fifo_size = aaci->fifo_depth * 2;
+
+ mutex_lock(&aaci->irq_lock);
+ if (!aaci->users++) {
+ ret = request_irq(aaci->dev->irq[0], aaci_irq,
+ IRQF_SHARED | IRQF_DISABLED, DRIVER_NAME, aaci);
+ if (ret != 0)
+ aaci->users--;
+ }
+ mutex_unlock(&aaci->irq_lock);
- out:
return ret;
}
@@ -418,7 +464,11 @@ static int aaci_pcm_close(struct snd_pcm_substream *substream)
WARN_ON(aacirun->cr & CR_EN);
aacirun->substream = NULL;
- free_irq(aaci->dev->irq[0], aaci);
+
+ mutex_lock(&aaci->irq_lock);
+ if (!--aaci->users)
+ free_irq(aaci->dev->irq[0], aaci);
+ mutex_unlock(&aaci->irq_lock);
return 0;
}
@@ -444,12 +494,21 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+/* Channel to slot mask */
+static const u32 channels_to_slotmask[] = {
+ [2] = CR_SL3 | CR_SL4,
+ [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
+ [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
+};
+
static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
- struct aaci_runtime *aacirun,
struct snd_pcm_hw_params *params)
{
+ struct aaci_runtime *aacirun = substream->runtime->private_data;
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+ int dbl = rate > 48000;
int err;
- struct aaci *aaci = substream->private_data;
aaci_pcm_hw_free(substream);
if (aacirun->pcm_open) {
@@ -457,22 +516,28 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
aacirun->pcm_open = 0;
}
+ /* channels is already limited to 2, 4, or 6 by aaci_rule_channels */
+ if (dbl && channels != 2)
+ return -EINVAL;
+
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(params));
if (err >= 0) {
- unsigned int rate = params_rate(params);
- int dbl = rate > 48000;
+ struct aaci *aaci = substream->private_data;
- err = snd_ac97_pcm_open(aacirun->pcm, rate,
- params_channels(params),
+ err = snd_ac97_pcm_open(aacirun->pcm, rate, channels,
aacirun->pcm->r[dbl].slots);
aacirun->pcm_open = err == 0;
aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
- aacirun->fifosz = aaci->fifosize * 4;
-
- if (aacirun->cr & CR_COMPACT)
- aacirun->fifosz >>= 1;
+ aacirun->cr |= channels_to_slotmask[channels + dbl * 2];
+
+ /*
+ * fifo_bytes is the number of bytes we transfer to/from
+ * the FIFO, including padding. So that's x4. As we're
+ * in compact mode, the FIFO is half the size.
+ */
+ aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
}
return err;
@@ -483,11 +548,11 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct aaci_runtime *aacirun = runtime->private_data;
+ aacirun->period = snd_pcm_lib_period_bytes(substream);
aacirun->start = runtime->dma_area;
aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream);
aacirun->ptr = aacirun->start;
- aacirun->period =
- aacirun->bytes = frames_to_bytes(runtime, runtime->period_size);
+ aacirun->bytes = aacirun->period;
return 0;
}
@@ -505,89 +570,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
/*
* Playback specific ALSA stuff
*/
-static const u32 channels_to_txmask[] = {
- [2] = CR_SL3 | CR_SL4,
- [4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
- [6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
-};
-
-/*
- * We can support two and four channel audio. Unfortunately
- * six channel audio requires a non-standard channel ordering:
- * 2 -> FL(3), FR(4)
- * 4 -> FL(3), FR(4), SL(7), SR(8)
- * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
- * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
- * This requires an ALSA configuration file to correct.
- */
-static unsigned int channel_list[] = { 2, 4, 6 };
-
-static int
-aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule)
-{
- struct aaci *aaci = rule->private;
- unsigned int chan_mask = 1 << 0, slots;
-
- /*
- * pcms[0] is the our 5.1 PCM instance.
- */
- slots = aaci->ac97_bus->pcms[0].r[0].slots;
- if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
- chan_mask |= 1 << 1;
- if (slots & (1 << AC97_SLOT_LFE))
- chan_mask |= 1 << 2;
- }
-
- return snd_interval_list(hw_param_interval(p, rule->var),
- ARRAY_SIZE(channel_list), channel_list,
- chan_mask);
-}
-
-static int aaci_pcm_open(struct snd_pcm_substream *substream)
-{
- struct aaci *aaci = substream->private_data;
- int ret;
-
- /*
- * Add rule describing channel dependency.
- */
- ret = snd_pcm_hw_rule_add(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- aaci_rule_channels, aaci,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- if (ret)
- return ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = __aaci_pcm_open(aaci, substream, &aaci->playback);
- } else {
- ret = __aaci_pcm_open(aaci, substream, &aaci->capture);
- }
- return ret;
-}
-
-static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct aaci_runtime *aacirun = substream->runtime->private_data;
- unsigned int channels = params_channels(params);
- int ret;
-
- WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) ||
- !channels_to_txmask[channels]);
-
- ret = aaci_pcm_hw_params(substream, aacirun, params);
-
- /*
- * Enable FIFO, compact mode, 16 bits per sample.
- * FIXME: double rate slots?
- */
- if (ret >= 0)
- aacirun->cr |= channels_to_txmask[channels];
-
- return ret;
-}
-
static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
{
u32 ie;
@@ -657,27 +639,13 @@ static struct snd_pcm_ops aaci_playback_ops = {
.open = aaci_pcm_open,
.close = aaci_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = aaci_pcm_playback_hw_params,
+ .hw_params = aaci_pcm_hw_params,
.hw_free = aaci_pcm_hw_free,
.prepare = aaci_pcm_prepare,
.trigger = aaci_pcm_playback_trigger,
.pointer = aaci_pcm_pointer,
};
-static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct aaci_runtime *aacirun = substream->runtime->private_data;
- int ret;
-
- ret = aaci_pcm_hw_params(substream, aacirun, params);
- if (ret >= 0)
- /* Line in record: slot 3 and 4 */
- aacirun->cr |= CR_SL3 | CR_SL4;
-
- return ret;
-}
-
static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun)
{
u32 ie;
@@ -774,7 +742,7 @@ static struct snd_pcm_ops aaci_capture_ops = {
.open = aaci_pcm_open,
.close = aaci_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = aaci_pcm_capture_hw_params,
+ .hw_params = aaci_pcm_hw_params,
.hw_free = aaci_pcm_hw_free,
.prepare = aaci_pcm_capture_prepare,
.trigger = aaci_pcm_capture_trigger,
@@ -941,12 +909,13 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%016llx, irq %d",
- card->shortname, (unsigned long long)dev->res.start,
- dev->irq[0]);
+ "%s PL%03x rev%u at 0x%08llx, irq %d",
+ card->shortname, amba_part(dev), amba_rev(dev),
+ (unsigned long long)dev->res.start, dev->irq[0]);
aaci = card->private_data;
mutex_init(&aaci->ac97_sem);
+ mutex_init(&aaci->irq_lock);
aaci->card = card;
aaci->dev = dev;
@@ -984,6 +953,10 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
struct aaci_runtime *aacirun = &aaci->playback;
int i;
+ /*
+ * Enable the channel, but don't assign it to any slots, so
+ * it won't empty onto the AC'97 link.
+ */
writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++)
@@ -1002,7 +975,7 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
writel(aaci->maincr, aaci->base + AACI_MAINCR);
/*
- * If we hit 4096, we failed. Go back to the specified
+ * If we hit 4096 entries, we failed. Go back to the specified
* fifo depth.
*/
if (i == 4096)
@@ -1011,7 +984,8 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
return i;
}
-static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id)
+static int __devinit aaci_probe(struct amba_device *dev,
+ const struct amba_id *id)
{
struct aaci *aaci;
int ret, i;
@@ -1067,11 +1041,12 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id)
/*
* Size the FIFOs (must be multiple of 16).
+ * This is the number of entries in the FIFO.
*/
- aaci->fifosize = aaci_size_fifo(aaci);
- if (aaci->fifosize & 15) {
- printk(KERN_WARNING "AACI: fifosize = %d not supported\n",
- aaci->fifosize);
+ aaci->fifo_depth = aaci_size_fifo(aaci);
+ if (aaci->fifo_depth & 15) {
+ printk(KERN_WARNING "AACI: FIFO depth %d not supported\n",
+ aaci->fifo_depth);
ret = -ENODEV;
goto out;
}
@@ -1084,8 +1059,8 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id)
ret = snd_card_register(aaci->card);
if (ret == 0) {
- dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname,
- aaci->fifosize);
+ dev_info(&dev->dev, "%s\n", aaci->card->longname);
+ dev_info(&dev->dev, "FIFO %u entries\n", aaci->fifo_depth);
amba_set_drvdata(dev, aaci->card);
return ret;
}
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h
index 6a4a2eebdda1..5791bd5bd2ab 100644
--- a/sound/arm/aaci.h
+++ b/sound/arm/aaci.h
@@ -210,6 +210,8 @@ struct aaci_runtime {
u32 cr;
struct snd_pcm_substream *substream;
+ unsigned int period; /* byte size of a "period" */
+
/*
* PIO support
*/
@@ -217,15 +219,16 @@ struct aaci_runtime {
void *end;
void *ptr;
int bytes;
- unsigned int period;
- unsigned int fifosz;
+ unsigned int fifo_bytes;
};
struct aaci {
struct amba_device *dev;
struct snd_card *card;
void __iomem *base;
- unsigned int fifosize;
+ unsigned int fifo_depth;
+ unsigned int users;
+ struct mutex irq_lock;
/* AC'97 */
struct mutex ac97_sem;
diff --git a/sound/core/control.c b/sound/core/control.c
index 9ce00ed20fba..a08ad57c49b6 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -279,33 +279,31 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
EXPORT_SYMBOL(snd_ctl_free_one);
-static unsigned int snd_ctl_hole_check(struct snd_card *card,
- unsigned int count)
+static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
+ unsigned int count)
{
struct snd_kcontrol *kctl;
list_for_each_entry(kctl, &card->controls, list) {
- if ((kctl->id.numid <= card->last_numid &&
- kctl->id.numid + kctl->count > card->last_numid) ||
- (kctl->id.numid <= card->last_numid + count - 1 &&
- kctl->id.numid + kctl->count > card->last_numid + count - 1))
- return card->last_numid = kctl->id.numid + kctl->count - 1;
+ if (kctl->id.numid < card->last_numid + 1 + count &&
+ kctl->id.numid + kctl->count > card->last_numid + 1) {
+ card->last_numid = kctl->id.numid + kctl->count - 1;
+ return true;
+ }
}
- return card->last_numid;
+ return false;
}
static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
{
- unsigned int last_numid, iter = 100000;
+ unsigned int iter = 100000;
- last_numid = card->last_numid;
- while (last_numid != snd_ctl_hole_check(card, count)) {
+ while (snd_ctl_remove_numid_conflict(card, count)) {
if (--iter == 0) {
/* this situation is very unlikely */
snd_printk(KERN_ERR "unable to allocate new control numid\n");
return -ENOMEM;
}
- last_numid = card->last_numid;
}
return 0;
}
@@ -466,6 +464,52 @@ error:
}
/**
+ * snd_ctl_activate_id - activate/inactivate the control of the given id
+ * @card: the card instance
+ * @id: the control id to activate/inactivate
+ * @active: non-zero to activate
+ *
+ * Finds the control instance with the given id, and activate or
+ * inactivate the control together with notification, if changed.
+ *
+ * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
+ */
+int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
+ int active)
+{
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int index_offset;
+ int ret;
+
+ down_write(&card->controls_rwsem);
+ kctl = snd_ctl_find_id(card, id);
+ if (kctl == NULL) {
+ ret = -ENOENT;
+ goto unlock;
+ }
+ index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
+ vd = &kctl->vd[index_offset];
+ ret = 0;
+ if (active) {
+ if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+ goto unlock;
+ vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ } else {
+ if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
+ goto unlock;
+ vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ }
+ ret = 1;
+ unlock:
+ up_write(&card->controls_rwsem);
+ if (ret > 0)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
+
+/**
* snd_ctl_rename_id - replace the id of a control on the card
* @card: the card instance
* @src_id: the old id
diff --git a/sound/core/device.c b/sound/core/device.c
index a67dfac08c03..2d1ad4b0cd65 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -225,15 +225,16 @@ int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
{
struct snd_device *dev;
int err;
- unsigned int range_low, range_high;
+ unsigned int range_low, range_high, type;
if (snd_BUG_ON(!card))
return -ENXIO;
- range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
+ range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
__again:
list_for_each_entry(dev, &card->devices, list) {
- if (dev->type >= range_low && dev->type <= range_high) {
+ type = (__force unsigned int)dev->type;
+ if (type >= range_low && type <= range_high) {
if ((err = snd_device_free(card, dev->device_data)) < 0)
return err;
goto __again;
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 9e92441f9b78..16bd9c03679b 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -192,7 +192,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->bytes = 0;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
- dmab->area = snd_malloc_pages(size, (unsigned long)device);
+ dmab->area = snd_malloc_pages(size,
+ (__force gfp_t)(unsigned long)device);
dmab->addr = 0;
break;
#ifdef CONFIG_HAS_DMA
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index 4c1d16827199..13b3f6f49fae 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -114,7 +114,8 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin,
return frames;
}
-static void init_data(struct linear_priv *data, int src_format, int dst_format)
+static void init_data(struct linear_priv *data,
+ snd_pcm_format_t src_format, snd_pcm_format_t dst_format)
{
int src_le, dst_le, src_bytes, dst_bytes;
@@ -140,9 +141,9 @@ static void init_data(struct linear_priv *data, int src_format, int dst_format)
if (snd_pcm_format_signed(src_format) !=
snd_pcm_format_signed(dst_format)) {
if (dst_le)
- data->flip = cpu_to_le32(0x80000000);
+ data->flip = (__force u32)cpu_to_le32(0x80000000);
else
- data->flip = cpu_to_be32(0x80000000);
+ data->flip = (__force u32)cpu_to_be32(0x80000000);
}
}
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 822dd56993ca..d8359cfeca15 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -190,9 +190,10 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
return -EIO;
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
int err;
- if ((err = mixer->get_recsrc(fmixer, &result)) < 0)
+ unsigned int index;
+ if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
return err;
- result = 1 << result;
+ result = 1 << index;
} else {
struct snd_mixer_oss_slot *pslot;
int chn;
@@ -214,6 +215,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
struct snd_mixer_oss *mixer = fmixer->mixer;
struct snd_mixer_oss_slot *pslot;
int chn, active;
+ unsigned int index;
int result = 0;
if (mixer == NULL)
@@ -222,8 +224,8 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr
if (recsrc & ~mixer->oss_recsrc)
recsrc &= ~mixer->oss_recsrc;
mixer->put_recsrc(fmixer, ffz(~recsrc));
- mixer->get_recsrc(fmixer, &result);
- result = 1 << result;
+ mixer->get_recsrc(fmixer, &index);
+ result = 1 << index;
}
for (chn = 0; chn < 31; chn++) {
pslot = &mixer->slots[chn];
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index f7649d4d950b..7915564bd394 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -274,7 +274,7 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin,
return frames;
}
-static void init_data(struct mulaw_priv *data, int format)
+static void init_data(struct mulaw_priv *data, snd_pcm_format_t format)
{
#ifdef SNDRV_LITTLE_ENDIAN
data->cvt_endian = snd_pcm_format_big_endian(format) > 0;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index a2e4eb324699..23c34a02894b 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -41,6 +41,7 @@
#include <sound/info.h>
#include <linux/soundcard.h>
#include <sound/initval.h>
+#include <sound/mixer_oss.h>
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
@@ -60,7 +61,6 @@ MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
-extern int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg);
static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
@@ -656,7 +656,7 @@ snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
#define AFMT_AC3 0x00000400
#define AFMT_VORBIS 0x00000800
-static int snd_pcm_oss_format_from(int format)
+static snd_pcm_format_t snd_pcm_oss_format_from(int format)
{
switch (format) {
case AFMT_MU_LAW: return SNDRV_PCM_FORMAT_MU_LAW;
@@ -680,7 +680,7 @@ static int snd_pcm_oss_format_from(int format)
}
}
-static int snd_pcm_oss_format_to(int format)
+static int snd_pcm_oss_format_to(snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW;
@@ -843,7 +843,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
size_t oss_frame_size;
int err;
int direct;
- int format, sformat, n;
+ snd_pcm_format_t format, sformat;
+ int n;
struct snd_mask sformat_mask;
struct snd_mask mask;
@@ -868,11 +869,11 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask);
if (atomic_read(&substream->mmap_count))
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else {
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
if (!direct)
- snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
+ snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
}
err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
if (err < 0) {
@@ -891,19 +892,22 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
else
sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
- if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {
- for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {
- if (snd_mask_test(&sformat_mask, sformat) &&
+ if ((__force int)sformat < 0 ||
+ !snd_mask_test(&sformat_mask, (__force int)sformat)) {
+ for (sformat = (__force snd_pcm_format_t)0;
+ (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST;
+ sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) {
+ if (snd_mask_test(&sformat_mask, (__force int)sformat) &&
snd_pcm_oss_format_to(sformat) >= 0)
break;
}
- if (sformat > SNDRV_PCM_FORMAT_LAST) {
+ if ((__force int)sformat > (__force int)SNDRV_PCM_FORMAT_LAST) {
snd_printd("Cannot find a format!!!\n");
err = -EINVAL;
goto failure;
}
}
- err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
+ err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
if (err < 0)
goto failure;
@@ -912,9 +916,9 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
} else {
_snd_pcm_hw_params_any(params);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
- SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
+ (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
- snd_pcm_oss_format_from(runtime->oss.format), 0);
+ (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
runtime->oss.channels, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
@@ -1185,10 +1189,10 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
snd_leave_user(fs);
} else {
- ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
}
if (ret != -EPIPE && ret != -ESTRPIPE)
break;
@@ -1230,10 +1234,10 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
if (in_kernel) {
mm_segment_t fs;
fs = snd_enter_user();
- ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
snd_leave_user(fs);
} else {
- ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
+ ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
}
if (ret == -EPIPE) {
if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
@@ -1333,7 +1337,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
struct snd_pcm_plugin_channel *channels;
size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
if (!in_kernel) {
- if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
+ if (copy_from_user(runtime->oss.buffer, (const char __force __user *)buf, bytes))
return -EFAULT;
buf = runtime->oss.buffer;
}
@@ -1429,7 +1433,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_sframes_t frames, frames1;
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
- char __user *final_dst = (char __user *)buf;
+ char __user *final_dst = (char __force __user *)buf;
if (runtime->oss.plugin_first) {
struct snd_pcm_plugin_channel *channels;
size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
@@ -1549,6 +1553,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
{
struct snd_pcm_runtime *runtime;
ssize_t result = 0;
+ snd_pcm_state_t state;
long res;
wait_queue_t wait;
@@ -1570,9 +1575,9 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
result = 0;
set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_lock_irq(substream);
- res = runtime->status->state;
+ state = runtime->status->state;
snd_pcm_stream_unlock_irq(substream);
- if (res != SNDRV_PCM_STATE_RUNNING) {
+ if (state != SNDRV_PCM_STATE_RUNNING) {
set_current_state(TASK_RUNNING);
break;
}
@@ -1658,7 +1663,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
size1);
size1 /= runtime->channels; /* frames */
fs = snd_enter_user();
- snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
+ snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1);
snd_leave_user(fs);
}
} else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 6751daa3bb50..71cc3ddf5c15 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -264,7 +264,7 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
return frames;
}
-static int snd_pcm_plug_formats(struct snd_mask *mask, int format)
+static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format)
{
struct snd_mask formats = *mask;
u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
@@ -276,16 +276,16 @@ static int snd_pcm_plug_formats(struct snd_mask *mask, int format)
SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
- snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
+ snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
if (formats.bits[0] & (u32)linfmts)
formats.bits[0] |= (u32)linfmts;
if (formats.bits[1] & (u32)(linfmts >> 32))
formats.bits[1] |= (u32)(linfmts >> 32);
- return snd_mask_test(&formats, format);
+ return snd_mask_test(&formats, (__force int)format);
}
-static int preferred_formats[] = {
+static snd_pcm_format_t preferred_formats[] = {
SNDRV_PCM_FORMAT_S16_LE,
SNDRV_PCM_FORMAT_S16_BE,
SNDRV_PCM_FORMAT_U16_LE,
@@ -306,24 +306,25 @@ static int preferred_formats[] = {
SNDRV_PCM_FORMAT_U8
};
-int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask)
+snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
+ struct snd_mask *format_mask)
{
int i;
- if (snd_mask_test(format_mask, format))
+ if (snd_mask_test(format_mask, (__force int)format))
return format;
- if (! snd_pcm_plug_formats(format_mask, format))
- return -EINVAL;
+ if (!snd_pcm_plug_formats(format_mask, format))
+ return (__force snd_pcm_format_t)-EINVAL;
if (snd_pcm_format_linear(format)) {
unsigned int width = snd_pcm_format_width(format);
int unsignd = snd_pcm_format_unsigned(format) > 0;
int big = snd_pcm_format_big_endian(format) > 0;
unsigned int badness, best = -1;
- int best_format = -1;
+ snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
- int f = preferred_formats[i];
+ snd_pcm_format_t f = preferred_formats[i];
unsigned int w;
- if (!snd_mask_test(format_mask, f))
+ if (!snd_mask_test(format_mask, (__force int)f))
continue;
w = snd_pcm_format_width(f);
if (w >= width)
@@ -337,17 +338,20 @@ int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask)
best = badness;
}
}
- return best_format >= 0 ? best_format : -EINVAL;
+ if ((__force int)best_format >= 0)
+ return best_format;
+ else
+ return (__force snd_pcm_format_t)-EINVAL;
} else {
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW:
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
- int format1 = preferred_formats[i];
- if (snd_mask_test(format_mask, format1))
+ snd_pcm_format_t format1 = preferred_formats[i];
+ if (snd_mask_test(format_mask, (__force int)format1))
return format1;
}
default:
- return -EINVAL;
+ return (__force snd_pcm_format_t)-EINVAL;
}
}
}
@@ -359,7 +363,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *plug,
struct snd_pcm_plugin_format tmpformat;
struct snd_pcm_plugin_format dstformat;
struct snd_pcm_plugin_format srcformat;
- int src_access, dst_access;
+ snd_pcm_access_t src_access, dst_access;
struct snd_pcm_plugin *plugin = NULL;
int err;
int stream = snd_pcm_plug_stream(plug);
@@ -641,7 +645,7 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
}
int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
- size_t samples, int format)
+ size_t samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
unsigned char *dst;
@@ -688,7 +692,7 @@ int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_area, size_t dst
int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_offset,
const struct snd_pcm_channel_area *dst_area, size_t dst_offset,
- size_t samples, int format)
+ size_t samples, snd_pcm_format_t format)
{
/* FIXME: sub byte resolution and odd dst_offset */
char *src, *dst;
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index b9afab603711..a5035c2369a6 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -46,7 +46,7 @@ struct snd_pcm_plugin_channel {
};
struct snd_pcm_plugin_format {
- int format;
+ snd_pcm_format_t format;
unsigned int rate;
unsigned int channels;
};
@@ -58,7 +58,7 @@ struct snd_pcm_plugin {
struct snd_pcm_plugin_format dst_format; /* destination format */
int src_width; /* sample width in bits */
int dst_width; /* sample width in bits */
- int access;
+ snd_pcm_access_t access;
snd_pcm_sframes_t (*src_frames)(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t dst_frames);
snd_pcm_sframes_t (*dst_frames)(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t src_frames);
snd_pcm_sframes_t (*client_channels)(struct snd_pcm_plugin *plugin,
@@ -125,7 +125,8 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_pcm_hw_params *slave_params);
-int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask);
+snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
+ struct snd_mask *format_mask);
int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin);
@@ -146,12 +147,12 @@ snd_pcm_sframes_t snd_pcm_plugin_client_channels(struct snd_pcm_plugin *plugin,
int snd_pcm_area_silence(const struct snd_pcm_channel_area *dst_channel,
size_t dst_offset,
- size_t samples, int format);
+ size_t samples, snd_pcm_format_t format);
int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
size_t src_offset,
const struct snd_pcm_channel_area *dst_channel,
size_t dst_offset,
- size_t samples, int format);
+ size_t samples, snd_pcm_format_t format);
void *snd_pcm_plug_buf_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t size);
void snd_pcm_plug_buf_unlock(struct snd_pcm_substream *plug, void *ptr);
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index bbe25d8c450a..c8171f5783c8 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -25,7 +25,7 @@
#include "pcm_plugin.h"
static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
- snd_pcm_uframes_t frames, int format)
+ snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
int dst = 0;
for (; dst < ndsts; ++dst) {
@@ -38,7 +38,7 @@ static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
struct snd_pcm_plugin_channel *dst_channel,
- snd_pcm_uframes_t frames, int format)
+ snd_pcm_uframes_t frames, snd_pcm_format_t format)
{
dst_channel->enabled = 1;
snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
@@ -51,7 +51,7 @@ static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
{
int nsrcs, ndsts, dst;
struct snd_pcm_plugin_channel *dvp;
- int format;
+ snd_pcm_format_t format;
if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
return -ENXIO;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 6b4b1287b314..ee9abb2d9001 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -211,9 +211,9 @@ static char *snd_pcm_format_names[] = {
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
- if (format >= ARRAY_SIZE(snd_pcm_format_names))
+ if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
return "Unknown";
- return snd_pcm_format_names[format];
+ return snd_pcm_format_names[(__force unsigned int)format];
}
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
@@ -269,12 +269,12 @@ static const char *snd_pcm_stream_name(int stream)
static const char *snd_pcm_access_name(snd_pcm_access_t access)
{
- return snd_pcm_access_names[access];
+ return snd_pcm_access_names[(__force int)access];
}
static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
{
- return snd_pcm_subformat_names[subformat];
+ return snd_pcm_subformat_names[(__force int)subformat];
}
static const char *snd_pcm_tstamp_mode_name(int mode)
@@ -284,7 +284,7 @@ static const char *snd_pcm_tstamp_mode_name(int mode)
static const char *snd_pcm_state_name(snd_pcm_state_t state)
{
- return snd_pcm_state_names[state];
+ return snd_pcm_state_names[(__force int)state];
}
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 434af3c56d52..88f02e3866e0 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -35,7 +35,10 @@ struct pcm_format_data {
unsigned char silence[8]; /* silence data to fill */
};
-static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
+/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
+#define INT __force int
+
+static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
[SNDRV_PCM_FORMAT_S8] = {
.width = 8, .phys = 8, .le = -1, .signd = 1,
.silence = {},
@@ -215,9 +218,9 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
int snd_pcm_format_signed(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].signd) < 0)
+ if ((val = pcm_formats[(INT)format].signd) < 0)
return -EINVAL;
return val;
}
@@ -266,9 +269,9 @@ EXPORT_SYMBOL(snd_pcm_format_linear);
int snd_pcm_format_little_endian(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].le) < 0)
+ if ((val = pcm_formats[(INT)format].le) < 0)
return -EINVAL;
return val;
}
@@ -304,9 +307,9 @@ EXPORT_SYMBOL(snd_pcm_format_big_endian);
int snd_pcm_format_width(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].width) == 0)
+ if ((val = pcm_formats[(INT)format].width) == 0)
return -EINVAL;
return val;
}
@@ -323,9 +326,9 @@ EXPORT_SYMBOL(snd_pcm_format_width);
int snd_pcm_format_physical_width(snd_pcm_format_t format)
{
int val;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
- if ((val = pcm_formats[format].phys) == 0)
+ if ((val = pcm_formats[(INT)format].phys) == 0)
return -EINVAL;
return val;
}
@@ -358,11 +361,11 @@ EXPORT_SYMBOL(snd_pcm_format_size);
*/
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
{
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return NULL;
- if (! pcm_formats[format].phys)
+ if (! pcm_formats[(INT)format].phys)
return NULL;
- return pcm_formats[format].silence;
+ return pcm_formats[(INT)format].silence;
}
EXPORT_SYMBOL(snd_pcm_format_silence_64);
@@ -382,16 +385,16 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
int width;
unsigned char *dst, *pat;
- if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
+ if ((INT)format < 0 || (INT)format > (INT)SNDRV_PCM_FORMAT_LAST)
return -EINVAL;
if (samples == 0)
return 0;
- width = pcm_formats[format].phys; /* physical width */
- pat = pcm_formats[format].silence;
+ width = pcm_formats[(INT)format].phys; /* physical width */
+ pat = pcm_formats[(INT)format].silence;
if (! width)
return -EINVAL;
/* signed or 1 byte data */
- if (pcm_formats[format].signd == 1 || width <= 8) {
+ if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
unsigned int bytes = samples * width / 8;
memset(data, *pat, bytes);
return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 4be45e7be8ad..ae42b6509ce4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -941,7 +941,7 @@ static struct action_ops snd_pcm_action_stop = {
*
* The state of each stream is then changed to the given state unconditionally.
*/
-int snd_pcm_stop(struct snd_pcm_substream *substream, int state)
+int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 99a485f13648..f2436d33fbf7 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1052,7 +1052,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
} else {
#ifdef CONFIG_COMPAT
if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
- void *ptr = compat_ptr(event.data.raw32.d[1]);
+ void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]);
event.data.ext.ptr = ptr;
}
#endif
@@ -2407,7 +2407,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
if (client == NULL)
return -ENXIO;
fs = snd_enter_user();
- result = snd_seq_do_ioctl(client, cmd, (void __user *)arg);
+ result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg);
snd_leave_user(fs);
return result;
}
@@ -2497,9 +2497,6 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
}
-void snd_seq_info_pool(struct snd_info_buffer *buffer,
- struct snd_seq_pool *pool, char *space);
-
/* exported to seq_info.c */
void snd_seq_info_clients_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 7fb55436287f..7f50c1437675 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -86,7 +86,7 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
char buf[32];
- char __user *curptr = (char __user *)event->data.ext.ptr;
+ char __user *curptr = (char __force __user *)event->data.ext.ptr;
while (len > 0) {
int size = sizeof(buf);
if (len < size)
@@ -157,7 +157,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
if (! in_kernel)
return -EINVAL;
- if (copy_from_user(buf, (void __user *)event->data.ext.ptr, len))
+ if (copy_from_user(buf, (void __force __user *)event->data.ext.ptr, len))
return -EFAULT;
return newlen;
}
@@ -343,7 +343,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
tmp->event = src->event;
src = src->next;
} else if (is_usrptr) {
- if (copy_from_user(&tmp->event, (char __user *)buf, size)) {
+ if (copy_from_user(&tmp->event, (char __force __user *)buf, size)) {
err = -EFAULT;
goto __error;
}
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 63e91431a29f..4a2ec779b8a7 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -24,6 +24,8 @@
#include <sound/seq_kernel.h>
#include <linux/poll.h>
+struct snd_info_buffer;
+
/* container for sequencer event (internal use) */
struct snd_seq_event_cell {
struct snd_seq_event event;
@@ -99,5 +101,7 @@ void snd_sequencer_memory_done(void);
/* polling */
int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, poll_table *wait);
+void snd_seq_info_pool(struct snd_info_buffer *buffer,
+ struct snd_seq_pool *pool, char *space);
#endif
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 3bf7d73ac52e..e12bcd94b6db 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -412,7 +412,7 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
* initialization or termination of devices (see seq_midi.c).
*
* If callback_all option is set, the callback function is invoked
- * at each connnection/disconnection.
+ * at each connection/disconnection.
*/
static int subscribe_port(struct snd_seq_client *client,
diff --git a/sound/core/timer.c b/sound/core/timer.c
index ed016329e911..7c1cbf0a0dc4 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -186,9 +186,8 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
list_for_each_entry(master, &timer->open_list_head, open_list) {
if (slave->slave_class == master->slave_class &&
slave->slave_id == master->slave_id) {
- list_del(&slave->open_list);
- list_add_tail(&slave->open_list,
- &master->slave_list_head);
+ list_move_tail(&slave->open_list,
+ &master->slave_list_head);
spin_lock_irq(&slave_active_lock);
slave->master = master;
slave->timer = master->timer;
@@ -414,8 +413,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri,
unsigned long sticks)
{
- list_del(&timeri->active_list);
- list_add_tail(&timeri->active_list, &timer->active_list_head);
+ list_move_tail(&timeri->active_list, &timer->active_list_head);
if (timer->running) {
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
goto __start_now;
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 3b9b550109cb..a89948ae9e8d 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -18,7 +18,7 @@
* a subset of information returned via ctl info callback
*/
struct link_ctl_info {
- int type; /* value type */
+ snd_ctl_elem_type_t type; /* value type */
int count; /* item count */
int min_val, max_val; /* min, max values */
};
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 12b44b0b6777..a0da7755fcea 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -482,8 +482,9 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
cable->streams[SNDRV_PCM_STREAM_CAPTURE];
unsigned long delta_play = 0, delta_capt = 0;
unsigned int running;
+ unsigned long flags;
- spin_lock(&cable->lock);
+ spin_lock_irqsave(&cable->lock, flags);
running = cable->running ^ cable->pause;
if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
delta_play = jiffies - dpcm_play->last_jiffies;
@@ -495,10 +496,8 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
dpcm_capt->last_jiffies += delta_capt;
}
- if (delta_play == 0 && delta_capt == 0) {
- spin_unlock(&cable->lock);
- return running;
- }
+ if (delta_play == 0 && delta_capt == 0)
+ goto unlock;
if (delta_play > delta_capt) {
loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
@@ -510,14 +509,14 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
delta_capt = delta_play;
}
- if (delta_play == 0 && delta_capt == 0) {
- spin_unlock(&cable->lock);
- return running;
- }
+ if (delta_play == 0 && delta_capt == 0)
+ goto unlock;
+
/* note delta_capt == delta_play at this moment */
loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
- spin_unlock(&cable->lock);
+ unlock:
+ spin_unlock_irqrestore(&cable->lock, flags);
return running;
}
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
new file mode 100644
index 000000000000..e486f48660fb
--- /dev/null
+++ b/sound/firewire/Kconfig
@@ -0,0 +1,25 @@
+menuconfig SND_FIREWIRE
+ bool "FireWire sound devices"
+ depends on FIREWIRE
+ default y
+ help
+ Support for IEEE-1394/FireWire/iLink sound devices.
+
+if SND_FIREWIRE && FIREWIRE
+
+config SND_FIREWIRE_LIB
+ tristate
+ depends on SND_PCM
+
+config SND_FIREWIRE_SPEAKERS
+ tristate "FireWire speakers"
+ select SND_PCM
+ select SND_FIREWIRE_LIB
+ help
+ Say Y here to include support for the Griffin FireWave Surround
+ and the LaCie FireWire Speakers.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-firewire-speakers.
+
+endif # SND_FIREWIRE
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
new file mode 100644
index 000000000000..e5b1634d9ad4
--- /dev/null
+++ b/sound/firewire/Makefile
@@ -0,0 +1,6 @@
+snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
+ fcp.o cmp.o amdtp.o
+snd-firewire-speakers-objs := speakers.o
+
+obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
+obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
new file mode 100644
index 000000000000..b18140ff2b93
--- /dev/null
+++ b/sound/firewire/amdtp.c
@@ -0,0 +1,562 @@
+/*
+ * Audio and Music Data Transmission Protocol (IEC 61883-6) streams
+ * with Common Isochronous Packet (IEC 61883-1) headers
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firewire.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include "amdtp.h"
+
+#define TICKS_PER_CYCLE 3072
+#define CYCLES_PER_SECOND 8000
+#define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
+
+#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */
+
+#define TAG_CIP 1
+
+#define CIP_EOH (1u << 31)
+#define CIP_FMT_AM (0x10 << 24)
+#define AMDTP_FDF_AM824 (0 << 19)
+#define AMDTP_FDF_SFC_SHIFT 16
+
+/* TODO: make these configurable */
+#define INTERRUPT_INTERVAL 16
+#define QUEUE_LENGTH 48
+
+/**
+ * amdtp_out_stream_init - initialize an AMDTP output stream structure
+ * @s: the AMDTP output stream to initialize
+ * @unit: the target of the stream
+ * @flags: the packet transmission method to use
+ */
+int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
+ enum cip_out_flags flags)
+{
+ if (flags != CIP_NONBLOCKING)
+ return -EINVAL;
+
+ s->unit = fw_unit_get(unit);
+ s->flags = flags;
+ s->context = ERR_PTR(-1);
+ mutex_init(&s->mutex);
+ s->packet_index = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(amdtp_out_stream_init);
+
+/**
+ * amdtp_out_stream_destroy - free stream resources
+ * @s: the AMDTP output stream to destroy
+ */
+void amdtp_out_stream_destroy(struct amdtp_out_stream *s)
+{
+ WARN_ON(!IS_ERR(s->context));
+ mutex_destroy(&s->mutex);
+ fw_unit_put(s->unit);
+}
+EXPORT_SYMBOL(amdtp_out_stream_destroy);
+
+/**
+ * amdtp_out_stream_set_rate - set the sample rate
+ * @s: the AMDTP output stream to configure
+ * @rate: the sample rate
+ *
+ * The sample rate must be set before the stream is started, and must not be
+ * changed while the stream is running.
+ */
+void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate)
+{
+ static const struct {
+ unsigned int rate;
+ unsigned int syt_interval;
+ } rate_info[] = {
+ [CIP_SFC_32000] = { 32000, 8, },
+ [CIP_SFC_44100] = { 44100, 8, },
+ [CIP_SFC_48000] = { 48000, 8, },
+ [CIP_SFC_88200] = { 88200, 16, },
+ [CIP_SFC_96000] = { 96000, 16, },
+ [CIP_SFC_176400] = { 176400, 32, },
+ [CIP_SFC_192000] = { 192000, 32, },
+ };
+ unsigned int sfc;
+
+ if (WARN_ON(!IS_ERR(s->context)))
+ return;
+
+ for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc)
+ if (rate_info[sfc].rate == rate) {
+ s->sfc = sfc;
+ s->syt_interval = rate_info[sfc].syt_interval;
+ return;
+ }
+ WARN_ON(1);
+}
+EXPORT_SYMBOL(amdtp_out_stream_set_rate);
+
+/**
+ * amdtp_out_stream_get_max_payload - get the stream's packet size
+ * @s: the AMDTP output stream
+ *
+ * This function must not be called before the stream has been configured
+ * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and
+ * amdtp_out_stream_set_midi().
+ */
+unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s)
+{
+ static const unsigned int max_data_blocks[] = {
+ [CIP_SFC_32000] = 4,
+ [CIP_SFC_44100] = 6,
+ [CIP_SFC_48000] = 6,
+ [CIP_SFC_88200] = 12,
+ [CIP_SFC_96000] = 12,
+ [CIP_SFC_176400] = 23,
+ [CIP_SFC_192000] = 24,
+ };
+
+ s->data_block_quadlets = s->pcm_channels;
+ s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8);
+
+ return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets;
+}
+EXPORT_SYMBOL(amdtp_out_stream_get_max_payload);
+
+static void amdtp_write_s16(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames);
+static void amdtp_write_s32(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames);
+
+/**
+ * amdtp_out_stream_set_pcm_format - set the PCM format
+ * @s: the AMDTP output stream to configure
+ * @format: the format of the ALSA PCM device
+ *
+ * The sample format must be set before the stream is started, and must not be
+ * changed while the stream is running.
+ */
+void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
+ snd_pcm_format_t format)
+{
+ if (WARN_ON(!IS_ERR(s->context)))
+ return;
+
+ switch (format) {
+ default:
+ WARN_ON(1);
+ /* fall through */
+ case SNDRV_PCM_FORMAT_S16:
+ s->transfer_samples = amdtp_write_s16;
+ break;
+ case SNDRV_PCM_FORMAT_S32:
+ s->transfer_samples = amdtp_write_s32;
+ break;
+ }
+}
+EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);
+
+static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
+{
+ unsigned int phase, data_blocks;
+
+ if (!cip_sfc_is_base_44100(s->sfc)) {
+ /* Sample_rate / 8000 is an integer, and precomputed. */
+ data_blocks = s->data_block_state;
+ } else {
+ phase = s->data_block_state;
+
+ /*
+ * This calculates the number of data blocks per packet so that
+ * 1) the overall rate is correct and exactly synchronized to
+ * the bus clock, and
+ * 2) packets with a rounded-up number of blocks occur as early
+ * as possible in the sequence (to prevent underruns of the
+ * device's buffer).
+ */
+ if (s->sfc == CIP_SFC_44100)
+ /* 6 6 5 6 5 6 5 ... */
+ data_blocks = 5 + ((phase & 1) ^
+ (phase == 0 || phase >= 40));
+ else
+ /* 12 11 11 11 11 ... or 23 22 22 22 22 ... */
+ data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
+ if (++phase >= (80 >> (s->sfc >> 1)))
+ phase = 0;
+ s->data_block_state = phase;
+ }
+
+ return data_blocks;
+}
+
+static unsigned int calculate_syt(struct amdtp_out_stream *s,
+ unsigned int cycle)
+{
+ unsigned int syt_offset, phase, index, syt;
+
+ if (s->last_syt_offset < TICKS_PER_CYCLE) {
+ if (!cip_sfc_is_base_44100(s->sfc))
+ syt_offset = s->last_syt_offset + s->syt_offset_state;
+ else {
+ /*
+ * The time, in ticks, of the n'th SYT_INTERVAL sample is:
+ * n * SYT_INTERVAL * 24576000 / sample_rate
+ * Modulo TICKS_PER_CYCLE, the difference between successive
+ * elements is about 1386.23. Rounding the results of this
+ * formula to the SYT precision results in a sequence of
+ * differences that begins with:
+ * 1386 1386 1387 1386 1386 1386 1387 1386 1386 1386 1387 ...
+ * This code generates _exactly_ the same sequence.
+ */
+ phase = s->syt_offset_state;
+ index = phase % 13;
+ syt_offset = s->last_syt_offset;
+ syt_offset += 1386 + ((index && !(index & 3)) ||
+ phase == 146);
+ if (++phase >= 147)
+ phase = 0;
+ s->syt_offset_state = phase;
+ }
+ } else
+ syt_offset = s->last_syt_offset - TICKS_PER_CYCLE;
+ s->last_syt_offset = syt_offset;
+
+ if (syt_offset < TICKS_PER_CYCLE) {
+ syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+ syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
+ syt += syt_offset % TICKS_PER_CYCLE;
+
+ return syt & 0xffff;
+ } else {
+ return 0xffff; /* no info */
+ }
+}
+
+static void amdtp_write_s32(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames)
+{
+ struct snd_pcm_runtime *runtime = pcm->runtime;
+ unsigned int channels, remaining_frames, frame_step, i, c;
+ const u32 *src;
+
+ channels = s->pcm_channels;
+ src = (void *)runtime->dma_area +
+ s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+ frame_step = s->data_block_quadlets - channels;
+
+ for (i = 0; i < frames; ++i) {
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src >> 8) | 0x40000000);
+ src++;
+ buffer++;
+ }
+ buffer += frame_step;
+ if (--remaining_frames == 0)
+ src = (void *)runtime->dma_area;
+ }
+}
+
+static void amdtp_write_s16(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames)
+{
+ struct snd_pcm_runtime *runtime = pcm->runtime;
+ unsigned int channels, remaining_frames, frame_step, i, c;
+ const u16 *src;
+
+ channels = s->pcm_channels;
+ src = (void *)runtime->dma_area +
+ s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
+ frame_step = s->data_block_quadlets - channels;
+
+ for (i = 0; i < frames; ++i) {
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src << 8) | 0x40000000);
+ src++;
+ buffer++;
+ }
+ buffer += frame_step;
+ if (--remaining_frames == 0)
+ src = (void *)runtime->dma_area;
+ }
+}
+
+static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s,
+ __be32 *buffer, unsigned int frames)
+{
+ unsigned int i, c;
+
+ for (i = 0; i < frames; ++i) {
+ for (c = 0; c < s->pcm_channels; ++c)
+ buffer[c] = cpu_to_be32(0x40000000);
+ buffer += s->data_block_quadlets;
+ }
+}
+
+static void amdtp_fill_midi(struct amdtp_out_stream *s,
+ __be32 *buffer, unsigned int frames)
+{
+ unsigned int i;
+
+ for (i = 0; i < frames; ++i)
+ buffer[s->pcm_channels + i * s->data_block_quadlets] =
+ cpu_to_be32(0x80000000);
+}
+
+static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
+{
+ __be32 *buffer;
+ unsigned int index, data_blocks, syt, ptr;
+ struct snd_pcm_substream *pcm;
+ struct fw_iso_packet packet;
+ int err;
+
+ if (s->packet_index < 0)
+ return;
+ index = s->packet_index;
+
+ data_blocks = calculate_data_blocks(s);
+ syt = calculate_syt(s, cycle);
+
+ buffer = s->buffer.packets[index].buffer;
+ buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
+ (s->data_block_quadlets << 16) |
+ s->data_block_counter);
+ buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 |
+ (s->sfc << AMDTP_FDF_SFC_SHIFT) | syt);
+ buffer += 2;
+
+ pcm = ACCESS_ONCE(s->pcm);
+ if (pcm)
+ s->transfer_samples(s, pcm, buffer, data_blocks);
+ else
+ amdtp_fill_pcm_silence(s, buffer, data_blocks);
+ if (s->midi_ports)
+ amdtp_fill_midi(s, buffer, data_blocks);
+
+ s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
+
+ packet.payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
+ packet.interrupt = IS_ALIGNED(index + 1, INTERRUPT_INTERVAL);
+ packet.skip = 0;
+ packet.tag = TAG_CIP;
+ packet.sy = 0;
+ packet.header_length = 0;
+
+ err = fw_iso_context_queue(s->context, &packet, &s->buffer.iso_buffer,
+ s->buffer.packets[index].offset);
+ if (err < 0) {
+ dev_err(&s->unit->device, "queueing error: %d\n", err);
+ s->packet_index = -1;
+ amdtp_out_stream_pcm_abort(s);
+ return;
+ }
+
+ if (++index >= QUEUE_LENGTH)
+ index = 0;
+ s->packet_index = index;
+
+ if (pcm) {
+ ptr = s->pcm_buffer_pointer + data_blocks;
+ if (ptr >= pcm->runtime->buffer_size)
+ ptr -= pcm->runtime->buffer_size;
+ ACCESS_ONCE(s->pcm_buffer_pointer) = ptr;
+
+ s->pcm_period_pointer += data_blocks;
+ if (s->pcm_period_pointer >= pcm->runtime->period_size) {
+ s->pcm_period_pointer -= pcm->runtime->period_size;
+ snd_pcm_period_elapsed(pcm);
+ }
+ }
+}
+
+static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
+ size_t header_length, void *header, void *data)
+{
+ struct amdtp_out_stream *s = data;
+ unsigned int i, packets = header_length / 4;
+
+ /*
+ * Compute the cycle of the last queued packet.
+ * (We need only the four lowest bits for the SYT, so we can ignore
+ * that bits 0-11 must wrap around at 3072.)
+ */
+ cycle += QUEUE_LENGTH - packets;
+
+ for (i = 0; i < packets; ++i)
+ queue_out_packet(s, ++cycle);
+}
+
+static int queue_initial_skip_packets(struct amdtp_out_stream *s)
+{
+ struct fw_iso_packet skip_packet = {
+ .skip = 1,
+ };
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < QUEUE_LENGTH; ++i) {
+ skip_packet.interrupt = IS_ALIGNED(s->packet_index + 1,
+ INTERRUPT_INTERVAL);
+ err = fw_iso_context_queue(s->context, &skip_packet, NULL, 0);
+ if (err < 0)
+ return err;
+ if (++s->packet_index >= QUEUE_LENGTH)
+ s->packet_index = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * amdtp_out_stream_start - start sending packets
+ * @s: the AMDTP output stream to start
+ * @channel: the isochronous channel on the bus
+ * @speed: firewire speed code
+ *
+ * The stream cannot be started until it has been configured with
+ * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and
+ * amdtp_out_stream_set_midi(); and it must be started before any
+ * PCM or MIDI device can be started.
+ */
+int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)
+{
+ static const struct {
+ unsigned int data_block;
+ unsigned int syt_offset;
+ } initial_state[] = {
+ [CIP_SFC_32000] = { 4, 3072 },
+ [CIP_SFC_48000] = { 6, 1024 },
+ [CIP_SFC_96000] = { 12, 1024 },
+ [CIP_SFC_192000] = { 24, 1024 },
+ [CIP_SFC_44100] = { 0, 67 },
+ [CIP_SFC_88200] = { 0, 67 },
+ [CIP_SFC_176400] = { 0, 67 },
+ };
+ int err;
+
+ mutex_lock(&s->mutex);
+
+ if (WARN_ON(!IS_ERR(s->context) ||
+ (!s->pcm_channels && !s->midi_ports))) {
+ err = -EBADFD;
+ goto err_unlock;
+ }
+
+ s->data_block_state = initial_state[s->sfc].data_block;
+ s->syt_offset_state = initial_state[s->sfc].syt_offset;
+ s->last_syt_offset = TICKS_PER_CYCLE;
+
+ err = iso_packets_buffer_init(&s->buffer, s->unit, QUEUE_LENGTH,
+ amdtp_out_stream_get_max_payload(s),
+ DMA_TO_DEVICE);
+ if (err < 0)
+ goto err_unlock;
+
+ s->context = fw_iso_context_create(fw_parent_device(s->unit)->card,
+ FW_ISO_CONTEXT_TRANSMIT,
+ channel, speed, 0,
+ out_packet_callback, s);
+ if (IS_ERR(s->context)) {
+ err = PTR_ERR(s->context);
+ if (err == -EBUSY)
+ dev_err(&s->unit->device,
+ "no free output stream on this controller\n");
+ goto err_buffer;
+ }
+
+ amdtp_out_stream_update(s);
+
+ s->packet_index = 0;
+ s->data_block_counter = 0;
+ err = queue_initial_skip_packets(s);
+ if (err < 0)
+ goto err_context;
+
+ err = fw_iso_context_start(s->context, -1, 0, 0);
+ if (err < 0)
+ goto err_context;
+
+ mutex_unlock(&s->mutex);
+
+ return 0;
+
+err_context:
+ fw_iso_context_destroy(s->context);
+ s->context = ERR_PTR(-1);
+err_buffer:
+ iso_packets_buffer_destroy(&s->buffer, s->unit);
+err_unlock:
+ mutex_unlock(&s->mutex);
+
+ return err;
+}
+EXPORT_SYMBOL(amdtp_out_stream_start);
+
+/**
+ * amdtp_out_stream_update - update the stream after a bus reset
+ * @s: the AMDTP output stream
+ */
+void amdtp_out_stream_update(struct amdtp_out_stream *s)
+{
+ ACCESS_ONCE(s->source_node_id_field) =
+ (fw_parent_device(s->unit)->card->node_id & 0x3f) << 24;
+}
+EXPORT_SYMBOL(amdtp_out_stream_update);
+
+/**
+ * amdtp_out_stream_stop - stop sending packets
+ * @s: the AMDTP output stream to stop
+ *
+ * All PCM and MIDI devices of the stream must be stopped before the stream
+ * itself can be stopped.
+ */
+void amdtp_out_stream_stop(struct amdtp_out_stream *s)
+{
+ mutex_lock(&s->mutex);
+
+ if (IS_ERR(s->context)) {
+ mutex_unlock(&s->mutex);
+ return;
+ }
+
+ fw_iso_context_stop(s->context);
+ fw_iso_context_destroy(s->context);
+ s->context = ERR_PTR(-1);
+ iso_packets_buffer_destroy(&s->buffer, s->unit);
+
+ mutex_unlock(&s->mutex);
+}
+EXPORT_SYMBOL(amdtp_out_stream_stop);
+
+/**
+ * amdtp_out_stream_pcm_abort - abort the running PCM device
+ * @s: the AMDTP stream about to be stopped
+ *
+ * If the isochronous stream needs to be stopped asynchronously, call this
+ * function first to stop the PCM device.
+ */
+void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s)
+{
+ struct snd_pcm_substream *pcm;
+
+ pcm = ACCESS_ONCE(s->pcm);
+ if (pcm) {
+ snd_pcm_stream_lock_irq(pcm);
+ if (snd_pcm_running(pcm))
+ snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irq(pcm);
+ }
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_abort);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
new file mode 100644
index 000000000000..537a9cb83581
--- /dev/null
+++ b/sound/firewire/amdtp.h
@@ -0,0 +1,169 @@
+#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
+#define SOUND_FIREWIRE_AMDTP_H_INCLUDED
+
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include "packets-buffer.h"
+
+/**
+ * enum cip_out_flags - describes details of the streaming protocol
+ * @CIP_NONBLOCKING: In non-blocking mode, each packet contains
+ * sample_rate/8000 samples, with rounding up or down to adjust
+ * for clock skew and left-over fractional samples. This should
+ * be used if supported by the device.
+ */
+enum cip_out_flags {
+ CIP_NONBLOCKING = 0,
+};
+
+/**
+ * enum cip_sfc - a stream's sample rate
+ */
+enum cip_sfc {
+ CIP_SFC_32000 = 0,
+ CIP_SFC_44100 = 1,
+ CIP_SFC_48000 = 2,
+ CIP_SFC_88200 = 3,
+ CIP_SFC_96000 = 4,
+ CIP_SFC_176400 = 5,
+ CIP_SFC_192000 = 6,
+};
+
+#define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \
+ SNDRV_PCM_FMTBIT_S32)
+
+struct fw_unit;
+struct fw_iso_context;
+struct snd_pcm_substream;
+
+struct amdtp_out_stream {
+ struct fw_unit *unit;
+ enum cip_out_flags flags;
+ struct fw_iso_context *context;
+ struct mutex mutex;
+
+ enum cip_sfc sfc;
+ unsigned int data_block_quadlets;
+ unsigned int pcm_channels;
+ unsigned int midi_ports;
+ void (*transfer_samples)(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames);
+
+ unsigned int syt_interval;
+ unsigned int source_node_id_field;
+ struct iso_packets_buffer buffer;
+
+ struct snd_pcm_substream *pcm;
+
+ int packet_index;
+ unsigned int data_block_counter;
+
+ unsigned int data_block_state;
+
+ unsigned int last_syt_offset;
+ unsigned int syt_offset_state;
+
+ unsigned int pcm_buffer_pointer;
+ unsigned int pcm_period_pointer;
+};
+
+int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
+ enum cip_out_flags flags);
+void amdtp_out_stream_destroy(struct amdtp_out_stream *s);
+
+void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate);
+unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s);
+
+int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed);
+void amdtp_out_stream_update(struct amdtp_out_stream *s);
+void amdtp_out_stream_stop(struct amdtp_out_stream *s);
+
+void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
+ snd_pcm_format_t format);
+void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);
+
+/**
+ * amdtp_out_stream_set_pcm - configure format of PCM samples
+ * @s: the AMDTP output stream to be configured
+ * @pcm_channels: the number of PCM samples in each data block, to be encoded
+ * as AM824 multi-bit linear audio
+ *
+ * This function must not be called while the stream is running.
+ */
+static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s,
+ unsigned int pcm_channels)
+{
+ s->pcm_channels = pcm_channels;
+}
+
+/**
+ * amdtp_out_stream_set_midi - configure format of MIDI data
+ * @s: the AMDTP output stream to be configured
+ * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
+ *
+ * This function must not be called while the stream is running.
+ */
+static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s,
+ unsigned int midi_ports)
+{
+ s->midi_ports = midi_ports;
+}
+
+/**
+ * amdtp_out_streaming_error - check for streaming error
+ * @s: the AMDTP output stream
+ *
+ * If this function returns true, the stream's packet queue has stopped due to
+ * an asynchronous error.
+ */
+static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
+{
+ return s->packet_index < 0;
+}
+
+/**
+ * amdtp_out_stream_pcm_prepare - prepare PCM device for running
+ * @s: the AMDTP output stream
+ *
+ * This function should be called from the PCM device's .prepare callback.
+ */
+static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
+{
+ s->pcm_buffer_pointer = 0;
+ s->pcm_period_pointer = 0;
+}
+
+/**
+ * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device
+ * @s: the AMDTP output stream
+ * @pcm: the PCM device to be started, or %NULL to stop the current device
+ *
+ * Call this function on a running isochronous stream to enable the actual
+ * transmission of PCM data. This function should be called from the PCM
+ * device's .trigger callback.
+ */
+static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm)
+{
+ ACCESS_ONCE(s->pcm) = pcm;
+}
+
+/**
+ * amdtp_out_stream_pcm_pointer - get the PCM buffer position
+ * @s: the AMDTP output stream that transports the PCM data
+ *
+ * Returns the current buffer position, in frames.
+ */
+static inline unsigned long
+amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
+{
+ return ACCESS_ONCE(s->pcm_buffer_pointer);
+}
+
+static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
+{
+ return sfc & 1;
+}
+
+#endif
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
new file mode 100644
index 000000000000..4a37f3a6fab9
--- /dev/null
+++ b/sound/firewire/cmp.c
@@ -0,0 +1,308 @@
+/*
+ * Connection Management Procedures (IEC 61883-1) helper functions
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "lib.h"
+#include "iso-resources.h"
+#include "cmp.h"
+
+#define IMPR_SPEED_MASK 0xc0000000
+#define IMPR_SPEED_SHIFT 30
+#define IMPR_XSPEED_MASK 0x00000060
+#define IMPR_XSPEED_SHIFT 5
+#define IMPR_PLUGS_MASK 0x0000001f
+
+#define IPCR_ONLINE 0x80000000
+#define IPCR_BCAST_CONN 0x40000000
+#define IPCR_P2P_CONN_MASK 0x3f000000
+#define IPCR_P2P_CONN_SHIFT 24
+#define IPCR_CHANNEL_MASK 0x003f0000
+#define IPCR_CHANNEL_SHIFT 16
+
+enum bus_reset_handling {
+ ABORT_ON_BUS_RESET,
+ SUCCEED_ON_BUS_RESET,
+};
+
+static __attribute__((format(printf, 2, 3)))
+void cmp_error(struct cmp_connection *c, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ dev_err(&c->resources.unit->device, "%cPCR%u: %pV",
+ 'i', c->pcr_index, &(struct va_format){ fmt, &va });
+ va_end(va);
+}
+
+static int pcr_modify(struct cmp_connection *c,
+ __be32 (*modify)(struct cmp_connection *c, __be32 old),
+ int (*check)(struct cmp_connection *c, __be32 pcr),
+ enum bus_reset_handling bus_reset_handling)
+{
+ struct fw_device *device = fw_parent_device(c->resources.unit);
+ __be32 *buffer = c->resources.buffer;
+ int generation = c->resources.generation;
+ int rcode, errors = 0;
+ __be32 old_arg;
+ int err;
+
+ buffer[0] = c->last_pcr_value;
+ for (;;) {
+ old_arg = buffer[0];
+ buffer[1] = modify(c, buffer[0]);
+
+ rcode = fw_run_transaction(
+ device->card, TCODE_LOCK_COMPARE_SWAP,
+ device->node_id, generation, device->max_speed,
+ CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index),
+ buffer, 8);
+
+ if (rcode == RCODE_COMPLETE) {
+ if (buffer[0] == old_arg) /* success? */
+ break;
+
+ if (check) {
+ err = check(c, buffer[0]);
+ if (err < 0)
+ return err;
+ }
+ } else if (rcode == RCODE_GENERATION)
+ goto bus_reset;
+ else if (rcode_is_permanent_error(rcode) || ++errors >= 3)
+ goto io_error;
+ }
+ c->last_pcr_value = buffer[1];
+
+ return 0;
+
+io_error:
+ cmp_error(c, "transaction failed: %s\n", rcode_string(rcode));
+ return -EIO;
+
+bus_reset:
+ return bus_reset_handling == ABORT_ON_BUS_RESET ? -EAGAIN : 0;
+}
+
+
+/**
+ * cmp_connection_init - initializes a connection manager
+ * @c: the connection manager to initialize
+ * @unit: a unit of the target device
+ * @ipcr_index: the index of the iPCR on the target device
+ */
+int cmp_connection_init(struct cmp_connection *c,
+ struct fw_unit *unit,
+ unsigned int ipcr_index)
+{
+ __be32 impr_be;
+ u32 impr;
+ int err;
+
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ CSR_REGISTER_BASE + CSR_IMPR,
+ &impr_be, 4);
+ if (err < 0)
+ return err;
+ impr = be32_to_cpu(impr_be);
+
+ if (ipcr_index >= (impr & IMPR_PLUGS_MASK))
+ return -EINVAL;
+
+ err = fw_iso_resources_init(&c->resources, unit);
+ if (err < 0)
+ return err;
+
+ c->connected = false;
+ mutex_init(&c->mutex);
+ c->last_pcr_value = cpu_to_be32(0x80000000);
+ c->pcr_index = ipcr_index;
+ c->max_speed = (impr & IMPR_SPEED_MASK) >> IMPR_SPEED_SHIFT;
+ if (c->max_speed == SCODE_BETA)
+ c->max_speed += (impr & IMPR_XSPEED_MASK) >> IMPR_XSPEED_SHIFT;
+
+ return 0;
+}
+EXPORT_SYMBOL(cmp_connection_init);
+
+/**
+ * cmp_connection_destroy - free connection manager resources
+ * @c: the connection manager
+ */
+void cmp_connection_destroy(struct cmp_connection *c)
+{
+ WARN_ON(c->connected);
+ mutex_destroy(&c->mutex);
+ fw_iso_resources_destroy(&c->resources);
+}
+EXPORT_SYMBOL(cmp_connection_destroy);
+
+
+static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr)
+{
+ ipcr &= ~cpu_to_be32(IPCR_BCAST_CONN |
+ IPCR_P2P_CONN_MASK |
+ IPCR_CHANNEL_MASK);
+ ipcr |= cpu_to_be32(1 << IPCR_P2P_CONN_SHIFT);
+ ipcr |= cpu_to_be32(c->resources.channel << IPCR_CHANNEL_SHIFT);
+
+ return ipcr;
+}
+
+static int ipcr_set_check(struct cmp_connection *c, __be32 ipcr)
+{
+ if (ipcr & cpu_to_be32(IPCR_BCAST_CONN |
+ IPCR_P2P_CONN_MASK)) {
+ cmp_error(c, "plug is already in use\n");
+ return -EBUSY;
+ }
+ if (!(ipcr & cpu_to_be32(IPCR_ONLINE))) {
+ cmp_error(c, "plug is not on-line\n");
+ return -ECONNREFUSED;
+ }
+
+ return 0;
+}
+
+/**
+ * cmp_connection_establish - establish a connection to the target
+ * @c: the connection manager
+ * @max_payload_bytes: the amount of data (including CIP headers) per packet
+ *
+ * This function establishes a point-to-point connection from the local
+ * computer to the target by allocating isochronous resources (channel and
+ * bandwidth) and setting the target's input plug control register. When this
+ * function succeeds, the caller is responsible for starting transmitting
+ * packets.
+ */
+int cmp_connection_establish(struct cmp_connection *c,
+ unsigned int max_payload_bytes)
+{
+ int err;
+
+ if (WARN_ON(c->connected))
+ return -EISCONN;
+
+ c->speed = min(c->max_speed,
+ fw_parent_device(c->resources.unit)->max_speed);
+
+ mutex_lock(&c->mutex);
+
+retry_after_bus_reset:
+ err = fw_iso_resources_allocate(&c->resources,
+ max_payload_bytes, c->speed);
+ if (err < 0)
+ goto err_mutex;
+
+ err = pcr_modify(c, ipcr_set_modify, ipcr_set_check,
+ ABORT_ON_BUS_RESET);
+ if (err == -EAGAIN) {
+ fw_iso_resources_free(&c->resources);
+ goto retry_after_bus_reset;
+ }
+ if (err < 0)
+ goto err_resources;
+
+ c->connected = true;
+
+ mutex_unlock(&c->mutex);
+
+ return 0;
+
+err_resources:
+ fw_iso_resources_free(&c->resources);
+err_mutex:
+ mutex_unlock(&c->mutex);
+
+ return err;
+}
+EXPORT_SYMBOL(cmp_connection_establish);
+
+/**
+ * cmp_connection_update - update the connection after a bus reset
+ * @c: the connection manager
+ *
+ * This function must be called from the driver's .update handler to reestablish
+ * any connection that might have been active.
+ *
+ * Returns zero on success, or a negative error code. On an error, the
+ * connection is broken and the caller must stop transmitting iso packets.
+ */
+int cmp_connection_update(struct cmp_connection *c)
+{
+ int err;
+
+ mutex_lock(&c->mutex);
+
+ if (!c->connected) {
+ mutex_unlock(&c->mutex);
+ return 0;
+ }
+
+ err = fw_iso_resources_update(&c->resources);
+ if (err < 0)
+ goto err_unconnect;
+
+ err = pcr_modify(c, ipcr_set_modify, ipcr_set_check,
+ SUCCEED_ON_BUS_RESET);
+ if (err < 0)
+ goto err_resources;
+
+ mutex_unlock(&c->mutex);
+
+ return 0;
+
+err_resources:
+ fw_iso_resources_free(&c->resources);
+err_unconnect:
+ c->connected = false;
+ mutex_unlock(&c->mutex);
+
+ return err;
+}
+EXPORT_SYMBOL(cmp_connection_update);
+
+
+static __be32 ipcr_break_modify(struct cmp_connection *c, __be32 ipcr)
+{
+ return ipcr & ~cpu_to_be32(IPCR_BCAST_CONN | IPCR_P2P_CONN_MASK);
+}
+
+/**
+ * cmp_connection_break - break the connection to the target
+ * @c: the connection manager
+ *
+ * This function deactives the connection in the target's input plug control
+ * register, and frees the isochronous resources of the connection. Before
+ * calling this function, the caller should cease transmitting packets.
+ */
+void cmp_connection_break(struct cmp_connection *c)
+{
+ int err;
+
+ mutex_lock(&c->mutex);
+
+ if (!c->connected) {
+ mutex_unlock(&c->mutex);
+ return;
+ }
+
+ err = pcr_modify(c, ipcr_break_modify, NULL, SUCCEED_ON_BUS_RESET);
+ if (err < 0)
+ cmp_error(c, "plug is still connected\n");
+
+ fw_iso_resources_free(&c->resources);
+
+ c->connected = false;
+
+ mutex_unlock(&c->mutex);
+}
+EXPORT_SYMBOL(cmp_connection_break);
diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h
new file mode 100644
index 000000000000..f47de08feb12
--- /dev/null
+++ b/sound/firewire/cmp.h
@@ -0,0 +1,41 @@
+#ifndef SOUND_FIREWIRE_CMP_H_INCLUDED
+#define SOUND_FIREWIRE_CMP_H_INCLUDED
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include "iso-resources.h"
+
+struct fw_unit;
+
+/**
+ * struct cmp_connection - manages an isochronous connection to a device
+ * @speed: the connection's actual speed
+ *
+ * This structure manages (using CMP) an isochronous stream from the local
+ * computer to a device's input plug (iPCR).
+ *
+ * There is no corresponding oPCR created on the local computer, so it is not
+ * possible to overlay connections on top of this one.
+ */
+struct cmp_connection {
+ int speed;
+ /* private: */
+ bool connected;
+ struct mutex mutex;
+ struct fw_iso_resources resources;
+ __be32 last_pcr_value;
+ unsigned int pcr_index;
+ unsigned int max_speed;
+};
+
+int cmp_connection_init(struct cmp_connection *connection,
+ struct fw_unit *unit,
+ unsigned int ipcr_index);
+void cmp_connection_destroy(struct cmp_connection *connection);
+
+int cmp_connection_establish(struct cmp_connection *connection,
+ unsigned int max_payload);
+int cmp_connection_update(struct cmp_connection *connection);
+void cmp_connection_break(struct cmp_connection *connection);
+
+#endif
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c
new file mode 100644
index 000000000000..ec578b5ad8da
--- /dev/null
+++ b/sound/firewire/fcp.c
@@ -0,0 +1,224 @@
+/*
+ * Function Control Protocol (IEC 61883-1) helper functions
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include "fcp.h"
+#include "lib.h"
+
+#define CTS_AVC 0x00
+
+#define ERROR_RETRIES 3
+#define ERROR_DELAY_MS 5
+#define FCP_TIMEOUT_MS 125
+
+static DEFINE_SPINLOCK(transactions_lock);
+static LIST_HEAD(transactions);
+
+enum fcp_state {
+ STATE_PENDING,
+ STATE_BUS_RESET,
+ STATE_COMPLETE,
+};
+
+struct fcp_transaction {
+ struct list_head list;
+ struct fw_unit *unit;
+ void *response_buffer;
+ unsigned int response_size;
+ unsigned int response_match_bytes;
+ enum fcp_state state;
+ wait_queue_head_t wait;
+};
+
+/**
+ * fcp_avc_transaction - send an AV/C command and wait for its response
+ * @unit: a unit on the target device
+ * @command: a buffer containing the command frame; must be DMA-able
+ * @command_size: the size of @command
+ * @response: a buffer for the response frame
+ * @response_size: the maximum size of @response
+ * @response_match_bytes: a bitmap specifying the bytes used to detect the
+ * correct response frame
+ *
+ * This function sends a FCP command frame to the target and waits for the
+ * corresponding response frame to be returned.
+ *
+ * Because it is possible for multiple FCP transactions to be active at the
+ * same time, the correct response frame is detected by the value of certain
+ * bytes. These bytes must be set in @response before calling this function,
+ * and the corresponding bits must be set in @response_match_bytes.
+ *
+ * @command and @response can point to the same buffer.
+ *
+ * Asynchronous operation (INTERIM, NOTIFY) is not supported at the moment.
+ *
+ * Returns the actual size of the response frame, or a negative error code.
+ */
+int fcp_avc_transaction(struct fw_unit *unit,
+ const void *command, unsigned int command_size,
+ void *response, unsigned int response_size,
+ unsigned int response_match_bytes)
+{
+ struct fcp_transaction t;
+ int tcode, ret, tries = 0;
+
+ t.unit = unit;
+ t.response_buffer = response;
+ t.response_size = response_size;
+ t.response_match_bytes = response_match_bytes;
+ t.state = STATE_PENDING;
+ init_waitqueue_head(&t.wait);
+
+ spin_lock_irq(&transactions_lock);
+ list_add_tail(&t.list, &transactions);
+ spin_unlock_irq(&transactions_lock);
+
+ for (;;) {
+ tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST
+ : TCODE_WRITE_BLOCK_REQUEST;
+ ret = snd_fw_transaction(t.unit, tcode,
+ CSR_REGISTER_BASE + CSR_FCP_COMMAND,
+ (void *)command, command_size);
+ if (ret < 0)
+ break;
+
+ wait_event_timeout(t.wait, t.state != STATE_PENDING,
+ msecs_to_jiffies(FCP_TIMEOUT_MS));
+
+ if (t.state == STATE_COMPLETE) {
+ ret = t.response_size;
+ break;
+ } else if (t.state == STATE_BUS_RESET) {
+ msleep(ERROR_DELAY_MS);
+ } else if (++tries >= ERROR_RETRIES) {
+ dev_err(&t.unit->device, "FCP command timed out\n");
+ ret = -EIO;
+ break;
+ }
+ }
+
+ spin_lock_irq(&transactions_lock);
+ list_del(&t.list);
+ spin_unlock_irq(&transactions_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(fcp_avc_transaction);
+
+/**
+ * fcp_bus_reset - inform the target handler about a bus reset
+ * @unit: the unit that might be used by fcp_avc_transaction()
+ *
+ * This function must be called from the driver's .update handler to inform
+ * the FCP transaction handler that a bus reset has happened. Any pending FCP
+ * transactions are retried.
+ */
+void fcp_bus_reset(struct fw_unit *unit)
+{
+ struct fcp_transaction *t;
+
+ spin_lock_irq(&transactions_lock);
+ list_for_each_entry(t, &transactions, list) {
+ if (t->unit == unit &&
+ t->state == STATE_PENDING) {
+ t->state = STATE_BUS_RESET;
+ wake_up(&t->wait);
+ }
+ }
+ spin_unlock_irq(&transactions_lock);
+}
+EXPORT_SYMBOL(fcp_bus_reset);
+
+/* checks whether the response matches the masked bytes in response_buffer */
+static bool is_matching_response(struct fcp_transaction *transaction,
+ const void *response, size_t length)
+{
+ const u8 *p1, *p2;
+ unsigned int mask, i;
+
+ p1 = response;
+ p2 = transaction->response_buffer;
+ mask = transaction->response_match_bytes;
+
+ for (i = 0; ; ++i) {
+ if ((mask & 1) && p1[i] != p2[i])
+ return false;
+ mask >>= 1;
+ if (!mask)
+ return true;
+ if (--length == 0)
+ return false;
+ }
+}
+
+static void fcp_response(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, unsigned long long offset,
+ void *data, size_t length, void *callback_data)
+{
+ struct fcp_transaction *t;
+ unsigned long flags;
+
+ if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC)
+ return;
+
+ spin_lock_irqsave(&transactions_lock, flags);
+ list_for_each_entry(t, &transactions, list) {
+ struct fw_device *device = fw_parent_device(t->unit);
+ if (device->card != card ||
+ device->generation != generation)
+ continue;
+ smp_rmb(); /* node_id vs. generation */
+ if (device->node_id != source)
+ continue;
+
+ if (t->state == STATE_PENDING &&
+ is_matching_response(t, data, length)) {
+ t->state = STATE_COMPLETE;
+ t->response_size = min((unsigned int)length,
+ t->response_size);
+ memcpy(t->response_buffer, data, t->response_size);
+ wake_up(&t->wait);
+ }
+ }
+ spin_unlock_irqrestore(&transactions_lock, flags);
+}
+
+static struct fw_address_handler response_register_handler = {
+ .length = 0x200,
+ .address_callback = fcp_response,
+};
+
+static int __init fcp_module_init(void)
+{
+ static const struct fw_address_region response_register_region = {
+ .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
+ .end = CSR_REGISTER_BASE + CSR_FCP_END,
+ };
+
+ fw_core_add_address_handler(&response_register_handler,
+ &response_register_region);
+
+ return 0;
+}
+
+static void __exit fcp_module_exit(void)
+{
+ WARN_ON(!list_empty(&transactions));
+ fw_core_remove_address_handler(&response_register_handler);
+}
+
+module_init(fcp_module_init);
+module_exit(fcp_module_exit);
diff --git a/sound/firewire/fcp.h b/sound/firewire/fcp.h
new file mode 100644
index 000000000000..86595688bd91
--- /dev/null
+++ b/sound/firewire/fcp.h
@@ -0,0 +1,12 @@
+#ifndef SOUND_FIREWIRE_FCP_H_INCLUDED
+#define SOUND_FIREWIRE_FCP_H_INCLUDED
+
+struct fw_unit;
+
+int fcp_avc_transaction(struct fw_unit *unit,
+ const void *command, unsigned int command_size,
+ void *response, unsigned int response_size,
+ unsigned int response_match_bytes);
+void fcp_bus_reset(struct fw_unit *unit);
+
+#endif
diff --git a/sound/firewire/iso-resources.c b/sound/firewire/iso-resources.c
new file mode 100644
index 000000000000..775dbd5f3445
--- /dev/null
+++ b/sound/firewire/iso-resources.c
@@ -0,0 +1,232 @@
+/*
+ * isochronous resources helper functions
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "iso-resources.h"
+
+/**
+ * fw_iso_resources_init - initializes a &struct fw_iso_resources
+ * @r: the resource manager to initialize
+ * @unit: the device unit for which the resources will be needed
+ *
+ * If the device does not support all channel numbers, change @r->channels_mask
+ * after calling this function.
+ */
+int fw_iso_resources_init(struct fw_iso_resources *r, struct fw_unit *unit)
+{
+ r->buffer = kmalloc(2 * 4, GFP_KERNEL);
+ if (!r->buffer)
+ return -ENOMEM;
+
+ r->channels_mask = ~0uLL;
+ r->unit = fw_unit_get(unit);
+ mutex_init(&r->mutex);
+ r->allocated = false;
+
+ return 0;
+}
+
+/**
+ * fw_iso_resources_destroy - destroy a resource manager
+ * @r: the resource manager that is no longer needed
+ */
+void fw_iso_resources_destroy(struct fw_iso_resources *r)
+{
+ WARN_ON(r->allocated);
+ kfree(r->buffer);
+ mutex_destroy(&r->mutex);
+ fw_unit_put(r->unit);
+}
+
+static unsigned int packet_bandwidth(unsigned int max_payload_bytes, int speed)
+{
+ unsigned int bytes, s400_bytes;
+
+ /* iso packets have three header quadlets and quadlet-aligned payload */
+ bytes = 3 * 4 + ALIGN(max_payload_bytes, 4);
+
+ /* convert to bandwidth units (quadlets at S1600 = bytes at S400) */
+ if (speed <= SCODE_400)
+ s400_bytes = bytes * (1 << (SCODE_400 - speed));
+ else
+ s400_bytes = DIV_ROUND_UP(bytes, 1 << (speed - SCODE_400));
+
+ return s400_bytes;
+}
+
+static int current_bandwidth_overhead(struct fw_card *card)
+{
+ /*
+ * Under the usual pessimistic assumption (cable length 4.5 m), the
+ * isochronous overhead for N cables is 1.797 µs + N * 0.494 µs, or
+ * 88.3 + N * 24.3 in bandwidth units.
+ *
+ * The calculation below tries to deduce N from the current gap count.
+ * If the gap count has been optimized by measuring the actual packet
+ * transmission time, this derived overhead should be near the actual
+ * overhead as well.
+ */
+ return card->gap_count < 63 ? card->gap_count * 97 / 10 + 89 : 512;
+}
+
+static int wait_isoch_resource_delay_after_bus_reset(struct fw_card *card)
+{
+ for (;;) {
+ s64 delay = (card->reset_jiffies + HZ) - get_jiffies_64();
+ if (delay <= 0)
+ return 0;
+ if (schedule_timeout_interruptible(delay) > 0)
+ return -ERESTARTSYS;
+ }
+}
+
+/**
+ * fw_iso_resources_allocate - allocate isochronous channel and bandwidth
+ * @r: the resource manager
+ * @max_payload_bytes: the amount of data (including CIP headers) per packet
+ * @speed: the speed (e.g., SCODE_400) at which the packets will be sent
+ *
+ * This function allocates one isochronous channel and enough bandwidth for the
+ * specified packet size.
+ *
+ * Returns the channel number that the caller must use for streaming, or
+ * a negative error code. Due to potentionally long delays, this function is
+ * interruptible and can return -ERESTARTSYS. On success, the caller is
+ * responsible for calling fw_iso_resources_update() on bus resets, and
+ * fw_iso_resources_free() when the resources are not longer needed.
+ */
+int fw_iso_resources_allocate(struct fw_iso_resources *r,
+ unsigned int max_payload_bytes, int speed)
+{
+ struct fw_card *card = fw_parent_device(r->unit)->card;
+ int bandwidth, channel, err;
+
+ if (WARN_ON(r->allocated))
+ return -EBADFD;
+
+ r->bandwidth = packet_bandwidth(max_payload_bytes, speed);
+
+retry_after_bus_reset:
+ spin_lock_irq(&card->lock);
+ r->generation = card->generation;
+ r->bandwidth_overhead = current_bandwidth_overhead(card);
+ spin_unlock_irq(&card->lock);
+
+ err = wait_isoch_resource_delay_after_bus_reset(card);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&r->mutex);
+
+ bandwidth = r->bandwidth + r->bandwidth_overhead;
+ fw_iso_resource_manage(card, r->generation, r->channels_mask,
+ &channel, &bandwidth, true, r->buffer);
+ if (channel == -EAGAIN) {
+ mutex_unlock(&r->mutex);
+ goto retry_after_bus_reset;
+ }
+ if (channel >= 0) {
+ r->channel = channel;
+ r->allocated = true;
+ } else {
+ if (channel == -EBUSY)
+ dev_err(&r->unit->device,
+ "isochronous resources exhausted\n");
+ else
+ dev_err(&r->unit->device,
+ "isochronous resource allocation failed\n");
+ }
+
+ mutex_unlock(&r->mutex);
+
+ return channel;
+}
+
+/**
+ * fw_iso_resources_update - update resource allocations after a bus reset
+ * @r: the resource manager
+ *
+ * This function must be called from the driver's .update handler to reallocate
+ * any resources that were allocated before the bus reset. It is safe to call
+ * this function if no resources are currently allocated.
+ *
+ * Returns a negative error code on failure. If this happens, the caller must
+ * stop streaming.
+ */
+int fw_iso_resources_update(struct fw_iso_resources *r)
+{
+ struct fw_card *card = fw_parent_device(r->unit)->card;
+ int bandwidth, channel;
+
+ mutex_lock(&r->mutex);
+
+ if (!r->allocated) {
+ mutex_unlock(&r->mutex);
+ return 0;
+ }
+
+ spin_lock_irq(&card->lock);
+ r->generation = card->generation;
+ r->bandwidth_overhead = current_bandwidth_overhead(card);
+ spin_unlock_irq(&card->lock);
+
+ bandwidth = r->bandwidth + r->bandwidth_overhead;
+
+ fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
+ &channel, &bandwidth, true, r->buffer);
+ /*
+ * When another bus reset happens, pretend that the allocation
+ * succeeded; we will try again for the new generation later.
+ */
+ if (channel < 0 && channel != -EAGAIN) {
+ r->allocated = false;
+ if (channel == -EBUSY)
+ dev_err(&r->unit->device,
+ "isochronous resources exhausted\n");
+ else
+ dev_err(&r->unit->device,
+ "isochronous resource allocation failed\n");
+ }
+
+ mutex_unlock(&r->mutex);
+
+ return channel;
+}
+
+/**
+ * fw_iso_resources_free - frees allocated resources
+ * @r: the resource manager
+ *
+ * This function deallocates the channel and bandwidth, if allocated.
+ */
+void fw_iso_resources_free(struct fw_iso_resources *r)
+{
+ struct fw_card *card = fw_parent_device(r->unit)->card;
+ int bandwidth, channel;
+
+ mutex_lock(&r->mutex);
+
+ if (r->allocated) {
+ bandwidth = r->bandwidth + r->bandwidth_overhead;
+ fw_iso_resource_manage(card, r->generation, 1uLL << r->channel,
+ &channel, &bandwidth, false, r->buffer);
+ if (channel < 0)
+ dev_err(&r->unit->device,
+ "isochronous resource deallocation failed\n");
+
+ r->allocated = false;
+ }
+
+ mutex_unlock(&r->mutex);
+}
diff --git a/sound/firewire/iso-resources.h b/sound/firewire/iso-resources.h
new file mode 100644
index 000000000000..3f0730e4d841
--- /dev/null
+++ b/sound/firewire/iso-resources.h
@@ -0,0 +1,39 @@
+#ifndef SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED
+#define SOUND_FIREWIRE_ISO_RESOURCES_H_INCLUDED
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct fw_unit;
+
+/**
+ * struct fw_iso_resources - manages channel/bandwidth allocation
+ * @channels_mask: if the device does not support all channel numbers, set this
+ * bit mask to something else than the default (all ones)
+ *
+ * This structure manages (de)allocation of isochronous resources (channel and
+ * bandwidth) for one isochronous stream.
+ */
+struct fw_iso_resources {
+ u64 channels_mask;
+ /* private: */
+ struct fw_unit *unit;
+ struct mutex mutex;
+ unsigned int channel;
+ unsigned int bandwidth; /* in bandwidth units, without overhead */
+ unsigned int bandwidth_overhead;
+ int generation; /* in which allocation is valid */
+ bool allocated;
+ __be32 *buffer;
+};
+
+int fw_iso_resources_init(struct fw_iso_resources *r,
+ struct fw_unit *unit);
+void fw_iso_resources_destroy(struct fw_iso_resources *r);
+
+int fw_iso_resources_allocate(struct fw_iso_resources *r,
+ unsigned int max_payload_bytes, int speed);
+int fw_iso_resources_update(struct fw_iso_resources *r);
+void fw_iso_resources_free(struct fw_iso_resources *r);
+
+#endif
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
new file mode 100644
index 000000000000..4750cea2210e
--- /dev/null
+++ b/sound/firewire/lib.c
@@ -0,0 +1,85 @@
+/*
+ * miscellaneous helper functions
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/module.h>
+#include "lib.h"
+
+#define ERROR_RETRY_DELAY_MS 5
+
+/**
+ * rcode_string - convert a firewire result code to a string
+ * @rcode: the result
+ */
+const char *rcode_string(unsigned int rcode)
+{
+ static const char *const names[] = {
+ [RCODE_COMPLETE] = "complete",
+ [RCODE_CONFLICT_ERROR] = "conflict error",
+ [RCODE_DATA_ERROR] = "data error",
+ [RCODE_TYPE_ERROR] = "type error",
+ [RCODE_ADDRESS_ERROR] = "address error",
+ [RCODE_SEND_ERROR] = "send error",
+ [RCODE_CANCELLED] = "cancelled",
+ [RCODE_BUSY] = "busy",
+ [RCODE_GENERATION] = "generation",
+ [RCODE_NO_ACK] = "no ack",
+ };
+
+ if (rcode < ARRAY_SIZE(names) && names[rcode])
+ return names[rcode];
+ else
+ return "unknown";
+}
+EXPORT_SYMBOL(rcode_string);
+
+/**
+ * snd_fw_transaction - send a request and wait for its completion
+ * @unit: the driver's unit on the target device
+ * @tcode: the transaction code
+ * @offset: the address in the target's address space
+ * @buffer: input/output data
+ * @length: length of @buffer
+ *
+ * Submits an asynchronous request to the target device, and waits for the
+ * response. The node ID and the current generation are derived from @unit.
+ * On a bus reset or an error, the transaction is retried a few times.
+ * Returns zero on success, or a negative error code.
+ */
+int snd_fw_transaction(struct fw_unit *unit, int tcode,
+ u64 offset, void *buffer, size_t length)
+{
+ struct fw_device *device = fw_parent_device(unit);
+ int generation, rcode, tries = 0;
+
+ for (;;) {
+ generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ rcode = fw_run_transaction(device->card, tcode,
+ device->node_id, generation,
+ device->max_speed, offset,
+ buffer, length);
+
+ if (rcode == RCODE_COMPLETE)
+ return 0;
+
+ if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
+ dev_err(&unit->device, "transaction failed: %s\n",
+ rcode_string(rcode));
+ return -EIO;
+ }
+
+ msleep(ERROR_RETRY_DELAY_MS);
+ }
+}
+EXPORT_SYMBOL(snd_fw_transaction);
+
+MODULE_DESCRIPTION("FireWire audio helper functions");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
new file mode 100644
index 000000000000..064f3fd9ab06
--- /dev/null
+++ b/sound/firewire/lib.h
@@ -0,0 +1,19 @@
+#ifndef SOUND_FIREWIRE_LIB_H_INCLUDED
+#define SOUND_FIREWIRE_LIB_H_INCLUDED
+
+#include <linux/firewire-constants.h>
+#include <linux/types.h>
+
+struct fw_unit;
+
+int snd_fw_transaction(struct fw_unit *unit, int tcode,
+ u64 offset, void *buffer, size_t length);
+const char *rcode_string(unsigned int rcode);
+
+/* returns true if retrying the transaction would not make sense */
+static inline bool rcode_is_permanent_error(int rcode)
+{
+ return rcode == RCODE_TYPE_ERROR || rcode == RCODE_ADDRESS_ERROR;
+}
+
+#endif
diff --git a/sound/firewire/packets-buffer.c b/sound/firewire/packets-buffer.c
new file mode 100644
index 000000000000..1e20e60ba6a6
--- /dev/null
+++ b/sound/firewire/packets-buffer.c
@@ -0,0 +1,74 @@
+/*
+ * helpers for managing a buffer for many packets
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/firewire.h>
+#include <linux/slab.h>
+#include "packets-buffer.h"
+
+/**
+ * iso_packets_buffer_init - allocates the memory for packets
+ * @b: the buffer structure to initialize
+ * @unit: the device at the other end of the stream
+ * @count: the number of packets
+ * @packet_size: the (maximum) size of a packet, in bytes
+ * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE
+ */
+int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
+ unsigned int count, unsigned int packet_size,
+ enum dma_data_direction direction)
+{
+ unsigned int packets_per_page, pages;
+ unsigned int i, page_index, offset_in_page;
+ void *p;
+ int err;
+
+ b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL);
+ if (!b->packets) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ packet_size = L1_CACHE_ALIGN(packet_size);
+ packets_per_page = PAGE_SIZE / packet_size;
+ if (WARN_ON(!packets_per_page)) {
+ err = -EINVAL;
+ goto error;
+ }
+ pages = DIV_ROUND_UP(count, packets_per_page);
+
+ err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card,
+ pages, direction);
+ if (err < 0)
+ goto err_packets;
+
+ for (i = 0; i < count; ++i) {
+ page_index = i / packets_per_page;
+ p = page_address(b->iso_buffer.pages[page_index]);
+ offset_in_page = (i % packets_per_page) * packet_size;
+ b->packets[i].buffer = p + offset_in_page;
+ b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page;
+ }
+
+ return 0;
+
+err_packets:
+ kfree(b->packets);
+error:
+ return err;
+}
+
+/**
+ * iso_packets_buffer_destroy - frees packet buffer resources
+ * @b: the buffer structure to free
+ * @unit: the device at the other end of the stream
+ */
+void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
+ struct fw_unit *unit)
+{
+ fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
+ kfree(b->packets);
+}
diff --git a/sound/firewire/packets-buffer.h b/sound/firewire/packets-buffer.h
new file mode 100644
index 000000000000..6513c5cb6ea9
--- /dev/null
+++ b/sound/firewire/packets-buffer.h
@@ -0,0 +1,26 @@
+#ifndef SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED
+#define SOUND_FIREWIRE_PACKETS_BUFFER_H_INCLUDED
+
+#include <linux/dma-mapping.h>
+#include <linux/firewire.h>
+
+/**
+ * struct iso_packets_buffer - manages a buffer for many packets
+ * @iso_buffer: the memory containing the packets
+ * @packets: an array, with each element pointing to one packet
+ */
+struct iso_packets_buffer {
+ struct fw_iso_buffer iso_buffer;
+ struct {
+ void *buffer;
+ unsigned int offset;
+ } *packets;
+};
+
+int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
+ unsigned int count, unsigned int packet_size,
+ enum dma_data_direction direction);
+void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
+ struct fw_unit *unit);
+
+#endif
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
new file mode 100644
index 000000000000..0fce9218abb1
--- /dev/null
+++ b/sound/firewire/speakers.c
@@ -0,0 +1,858 @@
+/*
+ * OXFW970-based speakers driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "cmp.h"
+#include "fcp.h"
+#include "amdtp.h"
+#include "lib.h"
+
+#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
+/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
+
+#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
+#define OXFORD_HARDWARE_ID_OXFW970 0x39443841
+#define OXFORD_HARDWARE_ID_OXFW971 0x39373100
+
+#define VENDOR_GRIFFIN 0x001292
+#define VENDOR_LACIE 0x00d04b
+
+#define SPECIFIER_1394TA 0x00a02d
+#define VERSION_AVC 0x010001
+
+struct device_info {
+ const char *driver_name;
+ const char *short_name;
+ const char *long_name;
+ int (*pcm_constraints)(struct snd_pcm_runtime *runtime);
+ unsigned int mixer_channels;
+ u8 mute_fb_id;
+ u8 volume_fb_id;
+};
+
+struct fwspk {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ const struct device_info *device_info;
+ struct snd_pcm_substream *pcm;
+ struct mutex mutex;
+ struct cmp_connection connection;
+ struct amdtp_out_stream stream;
+ bool stream_running;
+ bool mute;
+ s16 volume[6];
+ s16 volume_min;
+ s16 volume_max;
+};
+
+MODULE_DESCRIPTION("FireWire speakers driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ static unsigned int stereo_rates[] = { 48000, 96000 };
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ /* two channels work only at 48/96 kHz */
+ if (snd_interval_max(channels) < 6)
+ return snd_interval_list(rate, 2, stereo_rates, 0);
+ return 0;
+}
+
+static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ static const struct snd_interval all_channels = { .min = 6, .max = 6 };
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* 32/44.1 kHz work only with all six channels */
+ if (snd_interval_max(rate) < 48000)
+ return snd_interval_refine(channels, &all_channels);
+ return 0;
+}
+
+static int firewave_constraints(struct snd_pcm_runtime *runtime)
+{
+ static unsigned int channels_list[] = { 2, 6 };
+ static struct snd_pcm_hw_constraint_list channels_list_constraint = {
+ .count = 2,
+ .list = channels_list,
+ };
+ int err;
+
+ runtime->hw.rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000;
+ runtime->hw.channels_max = 6;
+
+ err = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &channels_list_constraint);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ firewave_rate_constraint, NULL,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ return err;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ firewave_channels_constraint, NULL,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
+{
+ runtime->hw.rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000;
+
+ return 0;
+}
+
+static int fwspk_open(struct snd_pcm_substream *substream)
+{
+ static const struct snd_pcm_hardware hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = AMDTP_OUT_PCM_FORMAT_BITS,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 4 * 1024 * 1024,
+ .period_bytes_min = 1,
+ .period_bytes_max = UINT_MAX,
+ .periods_min = 1,
+ .periods_max = UINT_MAX,
+ };
+ struct fwspk *fwspk = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ runtime->hw = hardware;
+
+ err = fwspk->device_info->pcm_constraints(runtime);
+ if (err < 0)
+ return err;
+ err = snd_pcm_limit_hw_rates(runtime);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ 5000, 8192000);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int fwspk_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static void fwspk_stop_stream(struct fwspk *fwspk)
+{
+ if (fwspk->stream_running) {
+ amdtp_out_stream_stop(&fwspk->stream);
+ cmp_connection_break(&fwspk->connection);
+ fwspk->stream_running = false;
+ }
+}
+
+static int fwspk_set_rate(struct fwspk *fwspk, unsigned int sfc)
+{
+ u8 *buf;
+ int err;
+
+ buf = kmalloc(8, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ buf[1] = 0xff; /* unit */
+ buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
+ buf[3] = 0x00; /* plug 0 */
+ buf[4] = 0x90; /* format: audio */
+ buf[5] = 0x00 | sfc; /* AM824, frequency */
+ buf[6] = 0xff; /* SYT (not used) */
+ buf[7] = 0xff;
+
+ err = fcp_avc_transaction(fwspk->unit, buf, 8, buf, 8,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
+ if (err < 0)
+ goto error;
+ if (err < 6 || buf[0] != 0x09 /* ACCEPTED */) {
+ dev_err(&fwspk->unit->device, "failed to set sample rate\n");
+ err = -EIO;
+ goto error;
+ }
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int fwspk_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct fwspk *fwspk = substream->private_data;
+ int err;
+
+ mutex_lock(&fwspk->mutex);
+ fwspk_stop_stream(fwspk);
+ mutex_unlock(&fwspk->mutex);
+
+ err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ goto error;
+
+ amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params));
+ amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params));
+
+ amdtp_out_stream_set_pcm_format(&fwspk->stream,
+ params_format(hw_params));
+
+ err = fwspk_set_rate(fwspk, fwspk->stream.sfc);
+ if (err < 0)
+ goto err_buffer;
+
+ return 0;
+
+err_buffer:
+ snd_pcm_lib_free_vmalloc_buffer(substream);
+error:
+ return err;
+}
+
+static int fwspk_hw_free(struct snd_pcm_substream *substream)
+{
+ struct fwspk *fwspk = substream->private_data;
+
+ mutex_lock(&fwspk->mutex);
+ fwspk_stop_stream(fwspk);
+ mutex_unlock(&fwspk->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int fwspk_prepare(struct snd_pcm_substream *substream)
+{
+ struct fwspk *fwspk = substream->private_data;
+ int err;
+
+ mutex_lock(&fwspk->mutex);
+
+ if (amdtp_out_streaming_error(&fwspk->stream))
+ fwspk_stop_stream(fwspk);
+
+ if (!fwspk->stream_running) {
+ err = cmp_connection_establish(&fwspk->connection,
+ amdtp_out_stream_get_max_payload(&fwspk->stream));
+ if (err < 0)
+ goto err_mutex;
+
+ err = amdtp_out_stream_start(&fwspk->stream,
+ fwspk->connection.resources.channel,
+ fwspk->connection.speed);
+ if (err < 0)
+ goto err_connection;
+
+ fwspk->stream_running = true;
+ }
+
+ mutex_unlock(&fwspk->mutex);
+
+ amdtp_out_stream_pcm_prepare(&fwspk->stream);
+
+ return 0;
+
+err_connection:
+ cmp_connection_break(&fwspk->connection);
+err_mutex:
+ mutex_unlock(&fwspk->mutex);
+
+ return err;
+}
+
+static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct fwspk *fwspk = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_out_stream_pcm_trigger(&fwspk->stream, pcm);
+ return 0;
+}
+
+static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream)
+{
+ struct fwspk *fwspk = substream->private_data;
+
+ return amdtp_out_stream_pcm_pointer(&fwspk->stream);
+}
+
+static int fwspk_create_pcm(struct fwspk *fwspk)
+{
+ static struct snd_pcm_ops ops = {
+ .open = fwspk_open,
+ .close = fwspk_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = fwspk_hw_params,
+ .hw_free = fwspk_hw_free,
+ .prepare = fwspk_prepare,
+ .trigger = fwspk_trigger,
+ .pointer = fwspk_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = fwspk;
+ strcpy(pcm->name, fwspk->device_info->short_name);
+ fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ fwspk->pcm->ops = &ops;
+ return 0;
+}
+
+enum control_action { CTL_READ, CTL_WRITE };
+enum control_attribute {
+ CTL_MIN = 0x02,
+ CTL_MAX = 0x03,
+ CTL_CURRENT = 0x10,
+};
+
+static int fwspk_mute_command(struct fwspk *fwspk, bool *value,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(11, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */
+ buf[5] = 0x10; /* control attribute: current */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = 0x00; /* audio channel number */
+ buf[8] = 0x01; /* control selector: mute */
+ buf[9] = 0x01; /* control data length */
+ if (action == CTL_READ)
+ buf[10] = 0xff;
+ else
+ buf[10] = *value ? 0x70 : 0x60;
+
+ err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 11) {
+ dev_err(&fwspk->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&fwspk->unit->device, "mute command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = buf[10] == 0x70;
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int fwspk_volume_command(struct fwspk *fwspk, s16 *value,
+ unsigned int channel,
+ enum control_attribute attribute,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(12, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */
+ buf[5] = attribute; /* control attribute */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = channel; /* audio channel number */
+ buf[8] = 0x02; /* control selector: volume */
+ buf[9] = 0x02; /* control data length */
+ if (action == CTL_READ) {
+ buf[10] = 0xff;
+ buf[11] = 0xff;
+ } else {
+ buf[10] = *value >> 8;
+ buf[11] = *value;
+ }
+
+ err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 12) {
+ dev_err(&fwspk->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&fwspk->unit->device, "volume command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = (buf[10] << 8) | buf[11];
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int fwspk_mute_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct fwspk *fwspk = control->private_data;
+
+ value->value.integer.value[0] = !fwspk->mute;
+
+ return 0;
+}
+
+static int fwspk_mute_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct fwspk *fwspk = control->private_data;
+ bool mute;
+ int err;
+
+ mute = !value->value.integer.value[0];
+
+ if (mute == fwspk->mute)
+ return 0;
+
+ err = fwspk_mute_command(fwspk, &mute, CTL_WRITE);
+ if (err < 0)
+ return err;
+ fwspk->mute = mute;
+
+ return 1;
+}
+
+static int fwspk_volume_info(struct snd_kcontrol *control,
+ struct snd_ctl_elem_info *info)
+{
+ struct fwspk *fwspk = control->private_data;
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = fwspk->device_info->mixer_channels;
+ info->value.integer.min = fwspk->volume_min;
+ info->value.integer.max = fwspk->volume_max;
+
+ return 0;
+}
+
+static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
+
+static int fwspk_volume_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct fwspk *fwspk = control->private_data;
+ unsigned int i;
+
+ for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
+ value->value.integer.value[channel_map[i]] = fwspk->volume[i];
+
+ return 0;
+}
+
+static int fwspk_volume_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct fwspk *fwspk = control->private_data;
+ unsigned int i, changed_channels;
+ bool equal_values = true;
+ s16 volume;
+ int err;
+
+ for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
+ if (value->value.integer.value[i] < fwspk->volume_min ||
+ value->value.integer.value[i] > fwspk->volume_max)
+ return -EINVAL;
+ if (value->value.integer.value[i] !=
+ value->value.integer.value[0])
+ equal_values = false;
+ }
+
+ changed_channels = 0;
+ for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
+ if (value->value.integer.value[channel_map[i]] !=
+ fwspk->volume[i])
+ changed_channels |= 1 << (i + 1);
+
+ if (equal_values && changed_channels != 0)
+ changed_channels = 1 << 0;
+
+ for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) {
+ volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
+ if (changed_channels & (1 << i)) {
+ err = fwspk_volume_command(fwspk, &volume, i,
+ CTL_CURRENT, CTL_WRITE);
+ if (err < 0)
+ return err;
+ }
+ if (i > 0)
+ fwspk->volume[i - 1] = volume;
+ }
+
+ return changed_channels != 0;
+}
+
+static int fwspk_create_mixer(struct fwspk *fwspk)
+{
+ static const struct snd_kcontrol_new controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = fwspk_mute_get,
+ .put = fwspk_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = fwspk_volume_info,
+ .get = fwspk_volume_get,
+ .put = fwspk_volume_put,
+ },
+ };
+ unsigned int i, first_ch;
+ int err;
+
+ err = fwspk_volume_command(fwspk, &fwspk->volume_min,
+ 0, CTL_MIN, CTL_READ);
+ if (err < 0)
+ return err;
+ err = fwspk_volume_command(fwspk, &fwspk->volume_max,
+ 0, CTL_MAX, CTL_READ);
+ if (err < 0)
+ return err;
+
+ err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ);
+ if (err < 0)
+ return err;
+
+ first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1;
+ for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
+ err = fwspk_volume_command(fwspk, &fwspk->volume[i],
+ first_ch + i, CTL_CURRENT, CTL_READ);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(controls); ++i) {
+ err = snd_ctl_add(fwspk->card,
+ snd_ctl_new1(&controls[i], fwspk));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static u32 fwspk_read_firmware_version(struct fw_unit *unit)
+{
+ __be32 data;
+ int err;
+
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ OXFORD_FIRMWARE_ID_ADDRESS, &data, 4);
+ return err >= 0 ? be32_to_cpu(data) : 0;
+}
+
+static void fwspk_card_free(struct snd_card *card)
+{
+ struct fwspk *fwspk = card->private_data;
+ struct fw_device *dev = fw_parent_device(fwspk->unit);
+
+ amdtp_out_stream_destroy(&fwspk->stream);
+ cmp_connection_destroy(&fwspk->connection);
+ fw_unit_put(fwspk->unit);
+ fw_device_put(dev);
+ mutex_destroy(&fwspk->mutex);
+}
+
+static const struct device_info *__devinit fwspk_detect(struct fw_device *dev)
+{
+ static const struct device_info griffin_firewave = {
+ .driver_name = "FireWave",
+ .short_name = "FireWave",
+ .long_name = "Griffin FireWave Surround",
+ .pcm_constraints = firewave_constraints,
+ .mixer_channels = 6,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x02,
+ };
+ static const struct device_info lacie_speakers = {
+ .driver_name = "FWSpeakers",
+ .short_name = "FireWire Speakers",
+ .long_name = "LaCie FireWire Speakers",
+ .pcm_constraints = lacie_speakers_constraints,
+ .mixer_channels = 1,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x01,
+ };
+ struct fw_csr_iterator i;
+ int key, value;
+
+ fw_csr_iterator_init(&i, dev->config_rom);
+ while (fw_csr_iterator_next(&i, &key, &value))
+ if (key == CSR_VENDOR)
+ switch (value) {
+ case VENDOR_GRIFFIN:
+ return &griffin_firewave;
+ case VENDOR_LACIE:
+ return &lacie_speakers;
+ }
+
+ return NULL;
+}
+
+static int __devinit fwspk_probe(struct device *unit_dev)
+{
+ struct fw_unit *unit = fw_unit(unit_dev);
+ struct fw_device *fw_dev = fw_parent_device(unit);
+ struct snd_card *card;
+ struct fwspk *fwspk;
+ u32 firmware;
+ int err;
+
+ err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
+ if (err < 0)
+ return err;
+ snd_card_set_dev(card, unit_dev);
+
+ fwspk = card->private_data;
+ fwspk->card = card;
+ mutex_init(&fwspk->mutex);
+ fw_device_get(fw_dev);
+ fwspk->unit = fw_unit_get(unit);
+ fwspk->device_info = fwspk_detect(fw_dev);
+ if (!fwspk->device_info) {
+ err = -ENODEV;
+ goto err_unit;
+ }
+
+ err = cmp_connection_init(&fwspk->connection, unit, 0);
+ if (err < 0)
+ goto err_unit;
+
+ err = amdtp_out_stream_init(&fwspk->stream, unit, CIP_NONBLOCKING);
+ if (err < 0)
+ goto err_connection;
+
+ card->private_free = fwspk_card_free;
+
+ strcpy(card->driver, fwspk->device_info->driver_name);
+ strcpy(card->shortname, fwspk->device_info->short_name);
+ firmware = fwspk_read_firmware_version(unit);
+ snprintf(card->longname, sizeof(card->longname),
+ "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
+ fwspk->device_info->long_name,
+ firmware >> 20, firmware & 0xffff,
+ fw_dev->config_rom[3], fw_dev->config_rom[4],
+ dev_name(&unit->device), 100 << fw_dev->max_speed);
+ strcpy(card->mixername, "OXFW970");
+
+ err = fwspk_create_pcm(fwspk);
+ if (err < 0)
+ goto error;
+
+ err = fwspk_create_mixer(fwspk);
+ if (err < 0)
+ goto error;
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dev_set_drvdata(unit_dev, fwspk);
+
+ return 0;
+
+err_connection:
+ cmp_connection_destroy(&fwspk->connection);
+err_unit:
+ fw_unit_put(fwspk->unit);
+ fw_device_put(fw_dev);
+ mutex_destroy(&fwspk->mutex);
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static int __devexit fwspk_remove(struct device *dev)
+{
+ struct fwspk *fwspk = dev_get_drvdata(dev);
+
+ snd_card_disconnect(fwspk->card);
+
+ mutex_lock(&fwspk->mutex);
+ amdtp_out_stream_pcm_abort(&fwspk->stream);
+ fwspk_stop_stream(fwspk);
+ mutex_unlock(&fwspk->mutex);
+
+ snd_card_free_when_closed(fwspk->card);
+
+ return 0;
+}
+
+static void fwspk_bus_reset(struct fw_unit *unit)
+{
+ struct fwspk *fwspk = dev_get_drvdata(&unit->device);
+
+ fcp_bus_reset(fwspk->unit);
+
+ if (cmp_connection_update(&fwspk->connection) < 0) {
+ mutex_lock(&fwspk->mutex);
+ amdtp_out_stream_pcm_abort(&fwspk->stream);
+ fwspk_stop_stream(fwspk);
+ mutex_unlock(&fwspk->mutex);
+ return;
+ }
+
+ amdtp_out_stream_update(&fwspk->stream);
+}
+
+static const struct ieee1394_device_id fwspk_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_GRIFFIN,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ },
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_LACIE,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table);
+
+static struct fw_driver fwspk_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ .probe = fwspk_probe,
+ .remove = __devexit_p(fwspk_remove),
+ },
+ .update = fwspk_bus_reset,
+ .id_table = fwspk_id_table,
+};
+
+static int __init alsa_fwspk_init(void)
+{
+ return driver_register(&fwspk_driver.driver);
+}
+
+static void __exit alsa_fwspk_exit(void)
+{
+ driver_unregister(&fwspk_driver.driver);
+}
+
+module_init(alsa_fwspk_init);
+module_exit(alsa_fwspk_exit);
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index fcb14a099822..7c7793a0eb25 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -526,31 +526,21 @@ bad:
}
-/* These device names follow the official Linux device list,
- * Documentation/devices.txt. Let us know if there are other
- * common names we should support for compatibility.
- * Only those devices not created by the generic code in sound_core.c are
- * registered here.
- */
-static const struct {
- unsigned short minor;
- char *name;
- umode_t mode;
- int *num;
-} dev_list[] = { /* list of minor devices */
-/* seems to be some confusion here -- this device is not in the device list */
- {SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP,
- &num_audiodevs},
- {SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP,
- &num_audiodevs},
-};
-
static int dmabuf;
static int dmabug;
module_param(dmabuf, int, 0444);
module_param(dmabug, int, 0444);
+/* additional minors for compatibility */
+struct oss_minor_dev {
+ unsigned short minor;
+ unsigned int enabled;
+} dev_list[] = {
+ { SND_DEV_DSP16 },
+ { SND_DEV_AUDIO },
+};
+
static int __init oss_init(void)
{
int err;
@@ -571,18 +561,12 @@ static int __init oss_init(void)
sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_create(sound_class, NULL,
- MKDEV(SOUND_MAJOR, dev_list[i].minor), NULL,
- "%s", dev_list[i].name);
-
- if (!dev_list[i].num)
- continue;
-
- for (j = 1; j < *dev_list[i].num; j++)
- device_create(sound_class, NULL,
- MKDEV(SOUND_MAJOR,
- dev_list[i].minor + (j*0x10)),
- NULL, "%s%d", dev_list[i].name, j);
+ j = 0;
+ do {
+ unsigned short minor = dev_list[i].minor + j * 0x10;
+ if (!register_sound_special(&oss_sound_fops, minor))
+ dev_list[i].enabled = (1 << j);
+ } while (++j < num_audiodevs);
}
if (sound_nblocks >= MAX_MEM_BLOCKS - 1)
@@ -596,11 +580,11 @@ static void __exit oss_cleanup(void)
int i, j;
for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
- device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor));
- if (!dev_list[i].num)
- continue;
- for (j = 1; j < *dev_list[i].num; j++)
- device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)));
+ j = 0;
+ do {
+ if (dev_list[i].enabled & (1 << j))
+ unregister_sound_special(dev_list[i].minor);
+ } while (++j < num_audiodevs);
}
unregister_sound_special(1);
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 9823d59d7ad7..389cd7931668 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -152,10 +152,16 @@ config SND_AZT3328
select SND_MPU401_UART
select SND_PCM
select SND_RAWMIDI
+ select SND_AC97_CODEC
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
+ Supported features: AC97-"conformant" mixer, MPU401/OPL3, analog I/O
+ (16bit/8bit, many sample rates [<= 66.2kHz], NO hardware mixing),
+ Digital Enhanced Game Port, 1.024MHz multimedia sequencer timer,
+ ext. codec (I2S port), onboard amp (4W/4Ohms/ch), suspend/resume.
+
To compile this driver as a module, choose M here: the module
will be called snd-azt3328.
@@ -572,13 +578,13 @@ comment "Don't forget to add built-in firmwares for HDSP driver"
depends on SND_HDSP=y
config SND_HDSPM
- tristate "RME Hammerfall DSP MADI"
+ tristate "RME Hammerfall DSP MADI/RayDAT/AIO"
select SND_HWDEP
select SND_RAWMIDI
select SND_PCM
help
- Say Y here to include support for RME Hammerfall DSP MADI
- soundcards.
+ Say Y here to include support for RME Hammerfall DSP MADI,
+ RayDAT and AIO soundcards.
To compile this driver as a module, choose M here: the module
will be called snd-hdspm.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index cb62d178b3e0..7f4d619f4ddb 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -71,6 +71,12 @@ static const struct ac97_codec_id snd_ac97_codec_id_vendors[] = {
{ 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL, NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL, NULL },
{ 0x414c4700, 0xffffff00, "Realtek", NULL, NULL },
+/*
+ * This is an _inofficial_ Aztech Labs entry
+ * (value might differ from unknown official Aztech ID),
+ * currently used by the AC97 emulation of the almost-AC97 PCI168 card.
+ */
+{ 0x415a5400, 0xffffff00, "Aztech Labs (emulated)", NULL, NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL, NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL, NULL },
@@ -127,6 +133,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x414c4781, 0xffffffff, "ALC658D", NULL, NULL }, /* already patched */
{ 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL },
{ 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL },
+{ 0x415a5401, 0xffffffff, "AZF3328", patch_aztech_azf3328, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL },
@@ -590,9 +597,9 @@ static int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol,
snd_ac97_page_restore(ac97, page_save);
#ifdef CONFIG_SND_AC97_POWER_SAVE
/* check analog mixer power-down */
- if ((val_mask & 0x8000) &&
+ if ((val_mask & AC97_PD_EAPD) &&
(kcontrol->private_value & (1<<30))) {
- if (val & 0x8000)
+ if (val & AC97_PD_EAPD)
ac97->power_up &= ~(1 << (reg>>1));
else
ac97->power_up |= 1 << (reg>>1);
@@ -1035,20 +1042,20 @@ static int snd_ac97_dev_free(struct snd_device *device)
static int snd_ac97_try_volume_mix(struct snd_ac97 * ac97, int reg)
{
- unsigned short val, mask = 0x8000;
+ unsigned short val, mask = AC97_MUTE_MASK_MONO;
if (! snd_ac97_valid_reg(ac97, reg))
return 0;
switch (reg) {
case AC97_MASTER_TONE:
- return ac97->caps & 0x04 ? 1 : 0;
+ return ac97->caps & AC97_BC_BASS_TREBLE ? 1 : 0;
case AC97_HEADPHONE:
- return ac97->caps & 0x10 ? 1 : 0;
+ return ac97->caps & AC97_BC_HEADPHONE ? 1 : 0;
case AC97_REC_GAIN_MIC:
- return ac97->caps & 0x01 ? 1 : 0;
+ return ac97->caps & AC97_BC_DEDICATED_MIC ? 1 : 0;
case AC97_3D_CONTROL:
- if (ac97->caps & 0x7c00) {
+ if (ac97->caps & AC97_BC_3D_TECH_ID_MASK) {
val = snd_ac97_read(ac97, reg);
/* if nonzero - fixed and we can't set it */
return val == 0;
@@ -1104,7 +1111,10 @@ static void check_volume_resolution(struct snd_ac97 *ac97, int reg, unsigned cha
*lo_max = *hi_max = 0;
for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
unsigned short val;
- snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
+ snd_ac97_write(
+ ac97, reg,
+ AC97_MUTE_MASK_STEREO | cbit[i] | (cbit[i] << 8)
+ );
/* Do the read twice due to buffers on some ac97 codecs.
* e.g. The STAC9704 returns exactly what you wrote to the register
* if you read it immediately. This causes the detect routine to fail.
@@ -1139,14 +1149,14 @@ static void snd_ac97_change_volume_params2(struct snd_ac97 * ac97, int reg, int
unsigned short val, val1;
*max = 63;
- val = 0x8080 | (0x20 << shift);
+ val = AC97_MUTE_MASK_STEREO | (0x20 << shift);
snd_ac97_write(ac97, reg, val);
val1 = snd_ac97_read(ac97, reg);
if (val != val1) {
*max = 31;
}
/* reset volume to zero */
- snd_ac97_write_cache(ac97, reg, 0x8080);
+ snd_ac97_write_cache(ac97, reg, AC97_MUTE_MASK_STEREO);
}
static inline int printable(unsigned int x)
@@ -1183,16 +1193,16 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg,
if (! snd_ac97_valid_reg(ac97, reg))
return 0;
- mute_mask = 0x8000;
+ mute_mask = AC97_MUTE_MASK_MONO;
val = snd_ac97_read(ac97, reg);
if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) {
/* check whether both mute bits work */
- val1 = val | 0x8080;
+ val1 = val | AC97_MUTE_MASK_STEREO;
snd_ac97_write(ac97, reg, val1);
if (val1 == snd_ac97_read(ac97, reg))
- mute_mask = 0x8080;
+ mute_mask = AC97_MUTE_MASK_STEREO;
}
- if (mute_mask == 0x8080) {
+ if (mute_mask == AC97_MUTE_MASK_STEREO) {
struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
if (check_amix)
tmp.private_value |= (1 << 30);
@@ -1268,9 +1278,11 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne
err = snd_ctl_add(card, kctl);
if (err < 0)
return err;
- snd_ac97_write_cache(ac97, reg,
- (snd_ac97_read(ac97, reg) & 0x8080) |
- lo_max | (hi_max << 8));
+ snd_ac97_write_cache(
+ ac97, reg,
+ (snd_ac97_read(ac97, reg) & AC97_MUTE_MASK_STEREO)
+ | lo_max | (hi_max << 8)
+ );
return 0;
}
@@ -1332,7 +1344,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
return err;
}
- ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080;
+ ac97->regs[AC97_CENTER_LFE_MASTER] = AC97_MUTE_MASK_STEREO;
/* build center controls */
if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER))
@@ -1410,8 +1422,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
return err;
set_tlv_db_scale(kctl, db_scale_4bit);
- snd_ac97_write_cache(ac97, AC97_PC_BEEP,
- snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
+ snd_ac97_write_cache(
+ ac97,
+ AC97_PC_BEEP,
+ (snd_ac97_read(ac97, AC97_PC_BEEP)
+ | AC97_MUTE_MASK_MONO | 0x001e)
+ );
}
/* build Phone controls */
@@ -1545,7 +1561,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
}
/* build Simulated Stereo Enhancement control */
- if (ac97->caps & 0x0008) {
+ if (ac97->caps & AC97_BC_SIM_STEREO) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0)
return err;
}
@@ -1557,7 +1573,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97)
}
/* build Loudness control */
- if (ac97->caps & 0x0020) {
+ if (ac97->caps & AC97_BC_LOUDNESS) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0)
return err;
}
@@ -2542,8 +2558,8 @@ void snd_ac97_resume(struct snd_ac97 *ac97)
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
/* FIXME: extra delay */
- ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000);
- if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000)
+ ac97->bus->ops->write(ac97, AC97_MASTER, AC97_MUTE_MASK_MONO);
+ if (snd_ac97_read(ac97, AC97_MASTER) != AC97_MUTE_MASK_MONO)
msleep(250);
} else {
end_time = jiffies + msecs_to_jiffies(100);
@@ -2747,12 +2763,12 @@ static int master_mute_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
int rshift = (kcontrol->private_value >> 12) & 0x0f;
unsigned short mask;
if (shift != rshift)
- mask = 0x8080;
+ mask = AC97_MUTE_MASK_STEREO;
else
- mask = 0x8000;
- snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000,
+ mask = AC97_MUTE_MASK_MONO;
+ snd_ac97_update_bits(ac97, AC97_POWERDOWN, AC97_PD_EAPD,
(ac97->regs[AC97_MASTER] & mask) == mask ?
- 0x8000 : 0);
+ AC97_PD_EAPD : 0);
}
return err;
}
@@ -2765,7 +2781,10 @@ static int tune_mute_led(struct snd_ac97 *ac97)
return -ENOENT;
msw->put = master_mute_sw_put;
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
- snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
+ snd_ac97_update_bits(
+ ac97, AC97_POWERDOWN,
+ AC97_PD_EAPD, AC97_PD_EAPD /* mute LED on */
+ );
ac97->scaps |= AC97_SCAP_EAPD_LED;
return 0;
}
@@ -2780,12 +2799,12 @@ static int hp_master_mute_sw_put(struct snd_kcontrol *kcontrol,
int rshift = (kcontrol->private_value >> 12) & 0x0f;
unsigned short mask;
if (shift != rshift)
- mask = 0x8080;
+ mask = AC97_MUTE_MASK_STEREO;
else
- mask = 0x8000;
- snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000,
+ mask = AC97_MUTE_MASK_MONO;
+ snd_ac97_update_bits(ac97, AC97_POWERDOWN, AC97_PD_EAPD,
(ac97->regs[AC97_MASTER] & mask) == mask ?
- 0x8000 : 0);
+ AC97_PD_EAPD : 0);
}
return err;
}
@@ -2801,7 +2820,10 @@ static int tune_hp_mute_led(struct snd_ac97 *ac97)
snd_ac97_remove_ctl(ac97, "External Amplifier", NULL);
snd_ac97_remove_ctl(ac97, "Headphone Playback", "Switch");
snd_ac97_remove_ctl(ac97, "Headphone Playback", "Volume");
- snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */
+ snd_ac97_update_bits(
+ ac97, AC97_POWERDOWN,
+ AC97_PD_EAPD, AC97_PD_EAPD /* mute LED on */
+ );
return 0;
}
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index bf47574ca1f0..200c9a1d48b7 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -27,6 +27,15 @@
#include "ac97_patch.h"
/*
+ * Forward declarations
+ */
+
+static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
+ const char *name);
+static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
+ const unsigned int *tlv, const char **slaves);
+
+/*
* Chip specific initialization
*/
@@ -2940,6 +2949,49 @@ static int patch_alc850(struct snd_ac97 *ac97)
return 0;
}
+static int patch_aztech_azf3328_specific(struct snd_ac97 *ac97)
+{
+ struct snd_kcontrol *kctl_3d_center =
+ snd_ac97_find_mixer_ctl(ac97, "3D Control - Center");
+ struct snd_kcontrol *kctl_3d_depth =
+ snd_ac97_find_mixer_ctl(ac97, "3D Control - Depth");
+
+ /*
+ * 3D register is different from AC97 standard layout
+ * (also do some renaming, to resemble Windows driver naming)
+ */
+ if (kctl_3d_center) {
+ kctl_3d_center->private_value =
+ AC97_SINGLE_VALUE(AC97_3D_CONTROL, 1, 0x07, 0);
+ snd_ac97_rename_vol_ctl(ac97,
+ "3D Control - Center", "3D Control - Width"
+ );
+ }
+ if (kctl_3d_depth)
+ kctl_3d_depth->private_value =
+ AC97_SINGLE_VALUE(AC97_3D_CONTROL, 8, 0x03, 0);
+
+ /* Aztech Windows driver calls the
+ equivalent control "Modem Playback", thus rename it: */
+ snd_ac97_rename_vol_ctl(ac97,
+ "Master Mono Playback", "Modem Playback"
+ );
+ snd_ac97_rename_vol_ctl(ac97,
+ "Headphone Playback", "FM Synth Playback"
+ );
+
+ return 0;
+}
+
+static const struct snd_ac97_build_ops patch_aztech_azf3328_ops = {
+ .build_specific = patch_aztech_azf3328_specific
+};
+
+static int patch_aztech_azf3328(struct snd_ac97 *ac97)
+{
+ ac97->build_ops = &patch_aztech_azf3328_ops;
+ return 0;
+}
/*
* C-Media CM97xx codecs
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index c80b0b863c54..0ac1f98d91a1 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -21,6 +21,7 @@
* would appreciate it if you grant us the right to use those modifications
* for any purpose including commercial applications.
*/
+
/* >0: print Hw params, timer vars. >1: print stream write/copy sizes */
#define REALLY_VERBOSE_LOGGING 0
@@ -36,16 +37,12 @@
#define VPRINTK2(...)
#endif
-#ifndef ASI_STYLE_NAMES
-/* not sure how ALSA style name should look */
-#define ASI_STYLE_NAMES 1
-#endif
-
#include "hpi_internal.h"
#include "hpimsginit.h"
#include "hpioctl.h"
#include <linux/pci.h>
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
@@ -85,11 +82,11 @@ MODULE_PARM_DESC(enable_hpi_hwdep,
/* identify driver */
#ifdef KERNEL_ALSA_BUILD
-static char *build_info = "built using headers from kernel source";
+static char *build_info = "Built using headers from kernel source";
module_param(build_info, charp, S_IRUGO);
MODULE_PARM_DESC(build_info, "built using headers from kernel source");
#else
-static char *build_info = "built within ALSA source";
+static char *build_info = "Built within ALSA source";
module_param(build_info, charp, S_IRUGO);
MODULE_PARM_DESC(build_info, "built within ALSA source");
#endif
@@ -100,13 +97,14 @@ static const int mixer_dump;
#define DEFAULT_SAMPLERATE 44100
static int adapter_fs = DEFAULT_SAMPLERATE;
-static struct hpi_hsubsys *ss; /* handle to HPI audio subsystem */
-
/* defaults */
#define PERIODS_MIN 2
-#define PERIOD_BYTES_MIN 2304
+#define PERIOD_BYTES_MIN 2048
#define BUFFER_BYTES_MAX (512 * 1024)
+/* convert stream to character */
+#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C')
+
/*#define TIMER_MILLISECONDS 20
#define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000)
*/
@@ -152,11 +150,12 @@ struct snd_card_asihpi_pcm {
struct timer_list timer;
unsigned int respawn_timer;
unsigned int hpi_buffer_attached;
- unsigned int pcm_size;
- unsigned int pcm_count;
+ unsigned int buffer_bytes;
+ unsigned int period_bytes;
unsigned int bytes_per_sec;
- unsigned int pcm_irq_pos; /* IRQ position */
- unsigned int pcm_buf_pos; /* position in buffer */
+ unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */
+ unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */
+ unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */
struct snd_pcm_substream *substream;
u32 h_stream;
struct hpi_format format;
@@ -167,7 +166,6 @@ struct snd_card_asihpi_pcm {
/* Functions to allow driver to give a buffer to HPI for busmastering */
static u16 hpi_stream_host_buffer_attach(
- struct hpi_hsubsys *hS,
u32 h_stream, /* handle to outstream. */
u32 size_in_bytes, /* size in bytes of bus mastering buffer */
u32 pci_address
@@ -194,10 +192,7 @@ static u16 hpi_stream_host_buffer_attach(
return hr.error;
}
-static u16 hpi_stream_host_buffer_detach(
- struct hpi_hsubsys *hS,
- u32 h_stream
-)
+static u16 hpi_stream_host_buffer_detach(u32 h_stream)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -218,24 +213,23 @@ static u16 hpi_stream_host_buffer_detach(
return hr.error;
}
-static inline u16 hpi_stream_start(struct hpi_hsubsys *hS, u32 h_stream)
+static inline u16 hpi_stream_start(u32 h_stream)
{
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
- return hpi_outstream_start(hS, h_stream);
+ return hpi_outstream_start(h_stream);
else
- return hpi_instream_start(hS, h_stream);
+ return hpi_instream_start(h_stream);
}
-static inline u16 hpi_stream_stop(struct hpi_hsubsys *hS, u32 h_stream)
+static inline u16 hpi_stream_stop(u32 h_stream)
{
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
- return hpi_outstream_stop(hS, h_stream);
+ return hpi_outstream_stop(h_stream);
else
- return hpi_instream_stop(hS, h_stream);
+ return hpi_instream_stop(h_stream);
}
static inline u16 hpi_stream_get_info_ex(
- struct hpi_hsubsys *hS,
u32 h_stream,
u16 *pw_state,
u32 *pbuffer_size,
@@ -244,42 +238,43 @@ static inline u16 hpi_stream_get_info_ex(
u32 *pauxiliary_data
)
{
+ u16 e;
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
- return hpi_outstream_get_info_ex(hS, h_stream, pw_state,
+ e = hpi_outstream_get_info_ex(h_stream, pw_state,
pbuffer_size, pdata_in_buffer,
psample_count, pauxiliary_data);
else
- return hpi_instream_get_info_ex(hS, h_stream, pw_state,
+ e = hpi_instream_get_info_ex(h_stream, pw_state,
pbuffer_size, pdata_in_buffer,
psample_count, pauxiliary_data);
+ return e;
}
-static inline u16 hpi_stream_group_add(struct hpi_hsubsys *hS,
+static inline u16 hpi_stream_group_add(
u32 h_master,
u32 h_stream)
{
if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM)
- return hpi_outstream_group_add(hS, h_master, h_stream);
+ return hpi_outstream_group_add(h_master, h_stream);
else
- return hpi_instream_group_add(hS, h_master, h_stream);
+ return hpi_instream_group_add(h_master, h_stream);
}
-static inline u16 hpi_stream_group_reset(struct hpi_hsubsys *hS,
- u32 h_stream)
+static inline u16 hpi_stream_group_reset(u32 h_stream)
{
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
- return hpi_outstream_group_reset(hS, h_stream);
+ return hpi_outstream_group_reset(h_stream);
else
- return hpi_instream_group_reset(hS, h_stream);
+ return hpi_instream_group_reset(h_stream);
}
-static inline u16 hpi_stream_group_get_map(struct hpi_hsubsys *hS,
+static inline u16 hpi_stream_group_get_map(
u32 h_stream, u32 *mo, u32 *mi)
{
if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM)
- return hpi_outstream_group_get_map(hS, h_stream, mo, mi);
+ return hpi_outstream_group_get_map(h_stream, mo, mi);
else
- return hpi_instream_group_get_map(hS, h_stream, mo, mi);
+ return hpi_instream_group_get_map(h_stream, mo, mi);
}
static u16 handle_error(u16 err, int line, char *filename)
@@ -299,11 +294,11 @@ static void print_hwparams(struct snd_pcm_hw_params *p)
{
snd_printd("HWPARAMS \n");
snd_printd("samplerate %d \n", params_rate(p));
- snd_printd("channels %d \n", params_channels(p));
- snd_printd("format %d \n", params_format(p));
+ snd_printd("Channels %d \n", params_channels(p));
+ snd_printd("Format %d \n", params_format(p));
snd_printd("subformat %d \n", params_subformat(p));
- snd_printd("buffer bytes %d \n", params_buffer_bytes(p));
- snd_printd("period bytes %d \n", params_period_bytes(p));
+ snd_printd("Buffer bytes %d \n", params_buffer_bytes(p));
+ snd_printd("Period bytes %d \n", params_period_bytes(p));
snd_printd("access %d \n", params_access(p));
snd_printd("period_size %d \n", params_period_size(p));
snd_printd("periods %d \n", params_periods(p));
@@ -335,7 +330,7 @@ static snd_pcm_format_t hpi_to_alsa_formats[] = {
*/
-1
#else
- /* SNDRV_PCM_FORMAT_S24_3LE */ /* { HPI_FORMAT_PCM24_SIGNED 15 */
+ /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
#endif
};
@@ -378,20 +373,20 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
} else {
/* on cards without SRC,
valid rates are determined by sampleclock */
- err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+ err = hpi_mixer_get_control(asihpi->h_mixer,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (err) {
snd_printk(KERN_ERR
- "no local sampleclock, err %d\n", err);
+ "No local sampleclock, err %d\n", err);
}
for (idx = 0; idx < 100; idx++) {
- if (hpi_sample_clock_query_local_rate(ss,
+ if (hpi_sample_clock_query_local_rate(
h_control, idx, &sample_rate)) {
if (!idx)
snd_printk(KERN_ERR
- "local rate query failed\n");
+ "Local rate query failed\n");
break;
}
@@ -480,10 +475,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
format, params_rate(params), 0, 0));
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (hpi_instream_reset(ss, dpcm->h_stream) != 0)
+ if (hpi_instream_reset(dpcm->h_stream) != 0)
return -EINVAL;
- if (hpi_instream_set_format(ss,
+ if (hpi_instream_set_format(
dpcm->h_stream, &dpcm->format) != 0)
return -EINVAL;
}
@@ -491,10 +486,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
dpcm->hpi_buffer_attached = 0;
if (card->support_mmap) {
- err = hpi_stream_host_buffer_attach(ss, dpcm->h_stream,
+ err = hpi_stream_host_buffer_attach(dpcm->h_stream,
params_buffer_bytes(params), runtime->dma_addr);
if (err == 0) {
- snd_printd(KERN_INFO
+ VPRINTK1(KERN_INFO
"stream_host_buffer_attach succeeded %u %lu\n",
params_buffer_bytes(params),
(unsigned long)runtime->dma_addr);
@@ -505,11 +500,11 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
return -ENOMEM;
}
- err = hpi_stream_get_info_ex(ss, dpcm->h_stream, NULL,
+ err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
&dpcm->hpi_buffer_attached,
NULL, NULL, NULL);
- snd_printd(KERN_INFO "stream_host_buffer_attach status 0x%x\n",
+ VPRINTK1(KERN_INFO "stream_host_buffer_attach status 0x%x\n",
dpcm->hpi_buffer_attached);
}
bytes_per_sec = params_rate(params) * params_channels(params);
@@ -520,16 +515,32 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
dpcm->bytes_per_sec = bytes_per_sec;
- dpcm->pcm_size = params_buffer_bytes(params);
- dpcm->pcm_count = params_period_bytes(params);
- snd_printd(KERN_INFO "pcm_size=%d, pcm_count=%d, bps=%d\n",
- dpcm->pcm_size, dpcm->pcm_count, bytes_per_sec);
+ dpcm->buffer_bytes = params_buffer_bytes(params);
+ dpcm->period_bytes = params_period_bytes(params);
+ VPRINTK1(KERN_INFO "buffer_bytes=%d, period_bytes=%d, bps=%d\n",
+ dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec);
- dpcm->pcm_irq_pos = 0;
- dpcm->pcm_buf_pos = 0;
return 0;
}
+static int
+snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+ if (dpcm->hpi_buffer_attached)
+ hpi_stream_host_buffer_detach(dpcm->h_stream);
+
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
+static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
+{
+ struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+ kfree(dpcm);
+}
+
static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
substream)
{
@@ -537,9 +548,9 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
int expiry;
- expiry = (dpcm->pcm_count * HZ / dpcm->bytes_per_sec);
- /* wait longer the first time, for samples to propagate */
- expiry = max(expiry, 20);
+ expiry = HZ / 200;
+ /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
+ expiry = max(expiry, 1); /* don't let it be zero! */
dpcm->timer.expires = jiffies + expiry;
dpcm->respawn_timer = 1;
add_timer(&dpcm->timer);
@@ -562,37 +573,44 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
struct snd_pcm_substream *s;
u16 e;
- snd_printd("trigger %dstream %d\n",
- substream->stream, substream->number);
+ VPRINTK1(KERN_INFO "%c%d trigger\n",
+ SCHR(substream->stream), substream->number);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
snd_pcm_group_for_each_entry(s, substream) {
- struct snd_card_asihpi_pcm *ds;
- ds = s->runtime->private_data;
+ struct snd_pcm_runtime *runtime = s->runtime;
+ struct snd_card_asihpi_pcm *ds = runtime->private_data;
if (snd_pcm_substream_chip(s) != card)
continue;
+ /* don't link Cap and Play */
+ if (substream->stream != s->stream)
+ continue;
+
if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
(card->support_mmap)) {
/* How do I know how much valid data is present
- * in buffer? Just guessing 2 periods, but if
+ * in buffer? Must be at least one period!
+ * Guessing 2 periods, but if
* buffer is bigger it may contain even more
* data??
*/
- unsigned int preload = ds->pcm_count * 2;
- VPRINTK2("preload %d\n", preload);
+ unsigned int preload = ds->period_bytes * 1;
+ VPRINTK2(KERN_INFO "%d preload x%x\n", s->number, preload);
hpi_handle_error(hpi_outstream_write_buf(
- ss, ds->h_stream,
- &s->runtime->dma_area[0],
+ ds->h_stream,
+ &runtime->dma_area[0],
preload,
&ds->format));
+ ds->pcm_buf_host_rw_ofs = preload;
}
if (card->support_grouping) {
- VPRINTK1("\t_group %dstream %d\n", s->stream,
+ VPRINTK1(KERN_INFO "\t%c%d group\n",
+ SCHR(s->stream),
s->number);
- e = hpi_stream_group_add(ss,
+ e = hpi_stream_group_add(
dpcm->h_stream,
ds->h_stream);
if (!e) {
@@ -604,10 +622,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
} else
break;
}
- snd_printd("start\n");
+ VPRINTK1(KERN_INFO "start\n");
/* start the master stream */
snd_card_asihpi_pcm_timer_start(substream);
- hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream));
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
+ !card->support_mmap)
+ hpi_handle_error(hpi_stream_start(dpcm->h_stream));
break;
case SNDRV_PCM_TRIGGER_STOP:
@@ -615,88 +635,73 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) != card)
continue;
+ /* don't link Cap and Play */
+ if (substream->stream != s->stream)
+ continue;
/*? workaround linked streams don't
transition to SETUP 20070706*/
s->runtime->status->state = SNDRV_PCM_STATE_SETUP;
if (card->support_grouping) {
- VPRINTK1("\t_group %dstream %d\n", s->stream,
+ VPRINTK1(KERN_INFO "\t%c%d group\n",
+ SCHR(s->stream),
s->number);
snd_pcm_trigger_done(s, substream);
} else
break;
}
- snd_printd("stop\n");
+ VPRINTK1(KERN_INFO "stop\n");
/* _prepare and _hwparams reset the stream */
- hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream));
+ hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
hpi_handle_error(
- hpi_outstream_reset(ss, dpcm->h_stream));
+ hpi_outstream_reset(dpcm->h_stream));
if (card->support_grouping)
- hpi_handle_error(hpi_stream_group_reset(ss,
- dpcm->h_stream));
+ hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream));
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printd("pause release\n");
- hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream));
+ VPRINTK1(KERN_INFO "pause release\n");
+ hpi_handle_error(hpi_stream_start(dpcm->h_stream));
snd_card_asihpi_pcm_timer_start(substream);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printd("pause\n");
+ VPRINTK1(KERN_INFO "pause\n");
snd_card_asihpi_pcm_timer_stop(substream);
- hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream));
+ hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
break;
default:
- snd_printd("\tINVALID\n");
+ snd_printd(KERN_ERR "\tINVALID\n");
return -EINVAL;
}
return 0;
}
-static int
-snd_card_asihpi_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- if (dpcm->hpi_buffer_attached)
- hpi_stream_host_buffer_detach(ss, dpcm->h_stream);
-
- snd_pcm_lib_free_pages(substream);
- return 0;
-}
-
-static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime)
-{
- struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- kfree(dpcm);
-}
-
/*algorithm outline
Without linking degenerates to getting single stream pos etc
Without mmap 2nd loop degenerates to snd_pcm_period_elapsed
*/
/*
-buf_pos=get_buf_pos(s);
+pcm_buf_dma_ofs=get_buf_pos(s);
for_each_linked_stream(s) {
- buf_pos=get_buf_pos(s);
- min_buf_pos = modulo_min(min_buf_pos, buf_pos, pcm_size)
- new_data = min(new_data, calc_new_data(buf_pos,irq_pos)
+ pcm_buf_dma_ofs=get_buf_pos(s);
+ min_buf_pos = modulo_min(min_buf_pos, pcm_buf_dma_ofs, buffer_bytes)
+ new_data = min(new_data, calc_new_data(pcm_buf_dma_ofs,irq_pos)
}
timer.expires = jiffies + predict_next_period_ready(min_buf_pos);
for_each_linked_stream(s) {
- s->buf_pos = min_buf_pos;
- if (new_data > pcm_count) {
+ s->pcm_buf_dma_ofs = min_buf_pos;
+ if (new_data > period_bytes) {
if (mmap) {
- irq_pos = (irq_pos + pcm_count) % pcm_size;
+ irq_pos = (irq_pos + period_bytes) % buffer_bytes;
if (playback) {
- write(pcm_count);
+ write(period_bytes);
} else {
- read(pcm_count);
+ read(period_bytes);
}
}
snd_pcm_period_elapsed(s);
@@ -724,105 +729,136 @@ static inline unsigned int modulo_min(unsigned int a, unsigned int b,
static void snd_card_asihpi_timer_function(unsigned long data)
{
struct snd_card_asihpi_pcm *dpcm = (struct snd_card_asihpi_pcm *)data;
- struct snd_card_asihpi *card = snd_pcm_substream_chip(dpcm->substream);
+ struct snd_pcm_substream *substream = dpcm->substream;
+ struct snd_card_asihpi *card = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime;
struct snd_pcm_substream *s;
unsigned int newdata = 0;
- unsigned int buf_pos, min_buf_pos = 0;
+ unsigned int pcm_buf_dma_ofs, min_buf_pos = 0;
unsigned int remdata, xfercount, next_jiffies;
int first = 1;
+ int loops = 0;
u16 state;
- u32 buffer_size, data_avail, samples_played, aux;
+ u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
+
+ VPRINTK1(KERN_INFO "%c%d snd_card_asihpi_timer_function\n",
+ SCHR(substream->stream), substream->number);
/* find minimum newdata and buffer pos in group */
- snd_pcm_group_for_each_entry(s, dpcm->substream) {
+ snd_pcm_group_for_each_entry(s, substream) {
struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
runtime = s->runtime;
if (snd_pcm_substream_chip(s) != card)
continue;
- hpi_handle_error(hpi_stream_get_info_ex(ss,
+ /* don't link Cap and Play */
+ if (substream->stream != s->stream)
+ continue;
+
+ hpi_handle_error(hpi_stream_get_info_ex(
ds->h_stream, &state,
- &buffer_size, &data_avail,
- &samples_played, &aux));
+ &buffer_size, &bytes_avail,
+ &samples_played, &on_card_bytes));
/* number of bytes in on-card buffer */
- runtime->delay = aux;
-
- if (state == HPI_STATE_DRAINED) {
- snd_printd(KERN_WARNING "outstream %d drained\n",
- s->number);
- snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
- return;
- }
+ runtime->delay = on_card_bytes;
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- buf_pos = frames_to_bytes(runtime, samples_played);
- } else {
- buf_pos = data_avail + ds->pcm_irq_pos;
- }
+ pcm_buf_dma_ofs = ds->pcm_buf_host_rw_ofs - bytes_avail;
+ if (state == HPI_STATE_STOPPED) {
+ if ((bytes_avail == 0) &&
+ (on_card_bytes < ds->pcm_buf_host_rw_ofs)) {
+ hpi_handle_error(hpi_stream_start(ds->h_stream));
+ VPRINTK1(KERN_INFO "P%d start\n", s->number);
+ }
+ } else if (state == HPI_STATE_DRAINED) {
+ VPRINTK1(KERN_WARNING "P%d drained\n",
+ s->number);
+ /*snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
+ continue; */
+ }
+ } else
+ pcm_buf_dma_ofs = bytes_avail + ds->pcm_buf_host_rw_ofs;
if (first) {
/* can't statically init min when wrap is involved */
- min_buf_pos = buf_pos;
- newdata = (buf_pos - ds->pcm_irq_pos) % ds->pcm_size;
+ min_buf_pos = pcm_buf_dma_ofs;
+ newdata = (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes;
first = 0;
} else {
min_buf_pos =
- modulo_min(min_buf_pos, buf_pos, UINT_MAX+1L);
+ modulo_min(min_buf_pos, pcm_buf_dma_ofs, UINT_MAX+1L);
newdata = min(
- (buf_pos - ds->pcm_irq_pos) % ds->pcm_size,
+ (pcm_buf_dma_ofs - ds->pcm_buf_elapsed_dma_ofs) % ds->buffer_bytes,
newdata);
}
- VPRINTK1("PB timer hw_ptr x%04lX, appl_ptr x%04lX\n",
+ VPRINTK1(KERN_INFO "PB timer hw_ptr x%04lX, appl_ptr x%04lX\n",
(unsigned long)frames_to_bytes(runtime,
runtime->status->hw_ptr),
(unsigned long)frames_to_bytes(runtime,
runtime->control->appl_ptr));
- VPRINTK1("%d S=%d, irq=%04X, pos=x%04X, left=x%04X,"
- " aux=x%04X space=x%04X\n", s->number,
- state, ds->pcm_irq_pos, buf_pos, (int)data_avail,
- (int)aux, buffer_size-data_avail);
+
+ VPRINTK1(KERN_INFO "%d %c%d S=%d, rw=%04X, dma=x%04X, left=x%04X,"
+ " aux=x%04X space=x%04X\n",
+ loops, SCHR(s->stream), s->number,
+ state, ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, (int)bytes_avail,
+ (int)on_card_bytes, buffer_size-bytes_avail);
+ loops++;
}
+ pcm_buf_dma_ofs = min_buf_pos;
- remdata = newdata % dpcm->pcm_count;
- xfercount = newdata - remdata; /* a multiple of pcm_count */
- next_jiffies = ((dpcm->pcm_count-remdata) * HZ / dpcm->bytes_per_sec)+1;
- next_jiffies = max(next_jiffies, 2U * HZ / 1000U);
+ remdata = newdata % dpcm->period_bytes;
+ xfercount = newdata - remdata; /* a multiple of period_bytes */
+ /* come back when on_card_bytes has decreased enough to allow
+ write to happen, or when data has been consumed to make another
+ period
+ */
+ if (xfercount && (on_card_bytes > dpcm->period_bytes))
+ next_jiffies = ((on_card_bytes - dpcm->period_bytes) * HZ / dpcm->bytes_per_sec);
+ else
+ next_jiffies = ((dpcm->period_bytes - remdata) * HZ / dpcm->bytes_per_sec);
+
+ next_jiffies = max(next_jiffies, 1U);
dpcm->timer.expires = jiffies + next_jiffies;
- VPRINTK1("jif %d buf pos x%04X newdata x%04X xc x%04X\n",
- next_jiffies, min_buf_pos, newdata, xfercount);
+ VPRINTK1(KERN_INFO "jif %d buf pos x%04X newdata x%04X xfer x%04X\n",
+ next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
- snd_pcm_group_for_each_entry(s, dpcm->substream) {
+ snd_pcm_group_for_each_entry(s, substream) {
struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
- ds->pcm_buf_pos = min_buf_pos;
- if (xfercount) {
+ /* don't link Cap and Play */
+ if (substream->stream != s->stream)
+ continue;
+
+ ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
+
+ if (xfercount && (on_card_bytes <= ds->period_bytes)) {
if (card->support_mmap) {
- ds->pcm_irq_pos = ds->pcm_irq_pos + xfercount;
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- VPRINTK2("write OS%d x%04x\n",
+ VPRINTK2(KERN_INFO "P%d write x%04x\n",
s->number,
- ds->pcm_count);
+ ds->period_bytes);
hpi_handle_error(
hpi_outstream_write_buf(
- ss, ds->h_stream,
+ ds->h_stream,
&s->runtime->
dma_area[0],
xfercount,
&ds->format));
} else {
- VPRINTK2("read IS%d x%04x\n",
+ VPRINTK2(KERN_INFO "C%d read x%04x\n",
s->number,
- dpcm->pcm_count);
+ xfercount);
hpi_handle_error(
hpi_instream_read_buf(
- ss, ds->h_stream,
+ ds->h_stream,
NULL, xfercount));
}
+ ds->pcm_buf_host_rw_ofs = ds->pcm_buf_host_rw_ofs + xfercount;
} /* else R/W will be handled by read/write callbacks */
+ ds->pcm_buf_elapsed_dma_ofs = pcm_buf_dma_ofs;
snd_pcm_period_elapsed(s);
}
}
@@ -845,12 +881,12 @@ static int snd_card_asihpi_playback_prepare(struct snd_pcm_substream *
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- snd_printd(KERN_INFO "playback prepare %d\n", substream->number);
-
- hpi_handle_error(hpi_outstream_reset(ss, dpcm->h_stream));
- dpcm->pcm_irq_pos = 0;
- dpcm->pcm_buf_pos = 0;
+ VPRINTK1(KERN_INFO "playback prepare %d\n", substream->number);
+ hpi_handle_error(hpi_outstream_reset(dpcm->h_stream));
+ dpcm->pcm_buf_host_rw_ofs = 0;
+ dpcm->pcm_buf_dma_ofs = 0;
+ dpcm->pcm_buf_elapsed_dma_ofs = 0;
return 0;
}
@@ -861,27 +897,8 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
snd_pcm_uframes_t ptr;
- u32 samples_played;
- u16 err;
-
- if (!snd_pcm_stream_linked(substream)) {
- /* NOTE, can use samples played for playback position here and
- * in timer fn because it LAGS the actual read pointer, and is a
- * better representation of actual playout position
- */
- err = hpi_outstream_get_info_ex(ss, dpcm->h_stream, NULL,
- NULL, NULL,
- &samples_played, NULL);
- hpi_handle_error(err);
-
- dpcm->pcm_buf_pos = frames_to_bytes(runtime, samples_played);
- }
- /* else must return most conservative value found in timer func
- * by looping over all streams
- */
-
- ptr = bytes_to_frames(runtime, dpcm->pcm_buf_pos % dpcm->pcm_size);
- VPRINTK2("playback_pointer=%04ld\n", (unsigned long)ptr);
+ ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
+ /* VPRINTK2(KERN_INFO "playback_pointer=x%04lx\n", (unsigned long)ptr); */
return ptr;
}
@@ -898,12 +915,12 @@ static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
/* on cards without SRC, must query at valid rate,
* maybe set by external sync
*/
- err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+ err = hpi_mixer_get_control(asihpi->h_mixer,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (!err)
- err = hpi_sample_clock_get_sample_rate(ss, h_control,
+ err = hpi_sample_clock_get_sample_rate(h_control,
&sample_rate);
for (format = HPI_FORMAT_PCM8_UNSIGNED;
@@ -911,7 +928,7 @@ static void snd_card_asihpi_playback_format(struct snd_card_asihpi *asihpi,
err = hpi_format_create(&hpi_format,
2, format, sample_rate, 128000, 0);
if (!err)
- err = hpi_outstream_query_format(ss, h_stream,
+ err = hpi_outstream_query_format(h_stream,
&hpi_format);
if (!err && (hpi_to_alsa_formats[format] != -1))
pcmhw->formats |=
@@ -942,7 +959,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
return -ENOMEM;
err =
- hpi_outstream_open(ss, card->adapter_index,
+ hpi_outstream_open(card->adapter_index,
substream->number, &dpcm->h_stream);
hpi_handle_error(err);
if (err)
@@ -998,11 +1015,11 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
card->update_interval_frames);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- card->update_interval_frames * 4, UINT_MAX);
+ card->update_interval_frames * 2, UINT_MAX);
snd_pcm_set_sync(substream);
- snd_printd(KERN_INFO "playback open\n");
+ VPRINTK1(KERN_INFO "playback open\n");
return 0;
}
@@ -1012,8 +1029,8 @@ static int snd_card_asihpi_playback_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- hpi_handle_error(hpi_outstream_close(ss, dpcm->h_stream));
- snd_printd(KERN_INFO "playback close\n");
+ hpi_handle_error(hpi_outstream_close(dpcm->h_stream));
+ VPRINTK1(KERN_INFO "playback close\n");
return 0;
}
@@ -1036,9 +1053,11 @@ static int snd_card_asihpi_playback_copy(struct snd_pcm_substream *substream,
VPRINTK2(KERN_DEBUG "playback copy%d %u bytes\n",
substream->number, len);
- hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream,
+ hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
runtime->dma_area, len, &dpcm->format));
+ dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
+
return 0;
}
@@ -1052,10 +1071,10 @@ static int snd_card_asihpi_playback_silence(struct snd_pcm_substream *
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
len = frames_to_bytes(runtime, count);
- snd_printd(KERN_INFO "playback silence %u bytes\n", len);
+ VPRINTK1(KERN_INFO "playback silence %u bytes\n", len);
memset(runtime->dma_area, 0, len);
- hpi_handle_error(hpi_outstream_write_buf(ss, dpcm->h_stream,
+ hpi_handle_error(hpi_outstream_write_buf(dpcm->h_stream,
runtime->dma_area, len, &dpcm->format));
return 0;
}
@@ -1091,13 +1110,13 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- VPRINTK2("capture pointer %d=%d\n",
- substream->number, dpcm->pcm_buf_pos);
- /* NOTE Unlike playback can't use actual dwSamplesPlayed
+ VPRINTK2(KERN_INFO "capture pointer %d=%d\n",
+ substream->number, dpcm->pcm_buf_dma_ofs);
+ /* NOTE Unlike playback can't use actual samples_played
for the capture position, because those samples aren't yet in
the local buffer available for reading.
*/
- return bytes_to_frames(runtime, dpcm->pcm_buf_pos % dpcm->pcm_size);
+ return bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
}
static int snd_card_asihpi_capture_ioctl(struct snd_pcm_substream *substream,
@@ -1111,11 +1130,12 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- hpi_handle_error(hpi_instream_reset(ss, dpcm->h_stream));
- dpcm->pcm_irq_pos = 0;
- dpcm->pcm_buf_pos = 0;
+ hpi_handle_error(hpi_instream_reset(dpcm->h_stream));
+ dpcm->pcm_buf_host_rw_ofs = 0;
+ dpcm->pcm_buf_dma_ofs = 0;
+ dpcm->pcm_buf_elapsed_dma_ofs = 0;
- snd_printd("capture prepare %d\n", substream->number);
+ VPRINTK1("Capture Prepare %d\n", substream->number);
return 0;
}
@@ -1133,12 +1153,12 @@ static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
/* on cards without SRC, must query at valid rate,
maybe set by external sync */
- err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+ err = hpi_mixer_get_control(asihpi->h_mixer,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (!err)
- err = hpi_sample_clock_get_sample_rate(ss, h_control,
+ err = hpi_sample_clock_get_sample_rate(h_control,
&sample_rate);
for (format = HPI_FORMAT_PCM8_UNSIGNED;
@@ -1147,7 +1167,7 @@ static void snd_card_asihpi_capture_format(struct snd_card_asihpi *asihpi,
err = hpi_format_create(&hpi_format, 2, format,
sample_rate, 128000, 0);
if (!err)
- err = hpi_instream_query_format(ss, h_stream,
+ err = hpi_instream_query_format(h_stream,
&hpi_format);
if (!err)
pcmhw->formats |=
@@ -1178,11 +1198,11 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
if (dpcm == NULL)
return -ENOMEM;
- snd_printd("hpi_instream_open adapter %d stream %d\n",
+ VPRINTK1("hpi_instream_open adapter %d stream %d\n",
card->adapter_index, substream->number);
err = hpi_handle_error(
- hpi_instream_open(ss, card->adapter_index,
+ hpi_instream_open(card->adapter_index,
substream->number, &dpcm->h_stream));
if (err)
kfree(dpcm);
@@ -1209,6 +1229,9 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID;
+ if (card->support_grouping)
+ snd_card_asihpi_capture.info |= SNDRV_PCM_INFO_SYNC_START;
+
runtime->hw = snd_card_asihpi_capture;
if (card->support_mmap)
@@ -1231,7 +1254,7 @@ static int snd_card_asihpi_capture_close(struct snd_pcm_substream *substream)
{
struct snd_card_asihpi_pcm *dpcm = substream->runtime->private_data;
- hpi_handle_error(hpi_instream_close(ss, dpcm->h_stream));
+ hpi_handle_error(hpi_instream_close(dpcm->h_stream));
return 0;
}
@@ -1241,18 +1264,17 @@ static int snd_card_asihpi_capture_copy(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
- u32 data_size;
+ u32 len;
- data_size = frames_to_bytes(runtime, count);
+ len = frames_to_bytes(runtime, count);
- VPRINTK2("capture copy%d %d bytes\n", substream->number, data_size);
- hpi_handle_error(hpi_instream_read_buf(ss, dpcm->h_stream,
- runtime->dma_area, data_size));
+ VPRINTK2(KERN_INFO "capture copy%d %d bytes\n", substream->number, len);
+ hpi_handle_error(hpi_instream_read_buf(dpcm->h_stream,
+ runtime->dma_area, len));
- /* Used by capture_pointer */
- dpcm->pcm_irq_pos = dpcm->pcm_irq_pos + data_size;
+ dpcm->pcm_buf_host_rw_ofs = dpcm->pcm_buf_host_rw_ofs + len;
- if (copy_to_user(dst, runtime->dma_area, data_size))
+ if (copy_to_user(dst, runtime->dma_area, len))
return -EFAULT;
return 0;
@@ -1287,7 +1309,7 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
struct snd_pcm *pcm;
int err;
- err = snd_pcm_new(asihpi->card, "asihpi PCM", device,
+ err = snd_pcm_new(asihpi->card, "Asihpi PCM", device,
asihpi->num_outstreams, asihpi->num_instreams,
&pcm);
if (err < 0)
@@ -1307,7 +1329,7 @@ static int __devinit snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi,
pcm->private_data = asihpi;
pcm->info_flags = 0;
- strcpy(pcm->name, "asihpi PCM");
+ strcpy(pcm->name, "Asihpi PCM");
/*? do we want to emulate MMAP for non-BBM cards?
Jack doesn't work with ALSAs MMAP emulation - WHY NOT? */
@@ -1330,8 +1352,7 @@ struct hpi_control {
char name[44]; /* copied to snd_ctl_elem_id.name[44]; */
};
-static char *asihpi_tuner_band_names[] =
-{
+static const char * const asihpi_tuner_band_names[] = {
"invalid",
"AM",
"FM mono",
@@ -1349,70 +1370,36 @@ compile_time_assert(
(HPI_TUNER_BAND_LAST+1)),
assert_tuner_band_names_size);
-#if ASI_STYLE_NAMES
-static char *asihpi_src_names[] =
-{
+static const char * const asihpi_src_names[] = {
"no source",
- "outstream",
- "line_in",
- "aes_in",
- "tuner",
+ "PCM",
+ "Line",
+ "Digital",
+ "Tuner",
"RF",
- "clock",
- "bitstr",
- "mic",
- "cobranet",
- "analog_in",
- "adapter",
+ "Clock",
+ "Bitstream",
+ "Microphone",
+ "Cobranet",
+ "Analog",
+ "Adapter",
};
-#else
-static char *asihpi_src_names[] =
-{
- "no source",
- "PCM playback",
- "line in",
- "digital in",
- "tuner",
- "RF",
- "clock",
- "bitstream",
- "mic",
- "cobranet in",
- "analog in",
- "adapter",
-};
-#endif
compile_time_assert(
(ARRAY_SIZE(asihpi_src_names) ==
(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
assert_src_names_size);
-#if ASI_STYLE_NAMES
-static char *asihpi_dst_names[] =
-{
- "no destination",
- "instream",
- "line_out",
- "aes_out",
- "RF",
- "speaker" ,
- "cobranet",
- "analog_out",
-};
-#else
-static char *asihpi_dst_names[] =
-{
+static const char * const asihpi_dst_names[] = {
"no destination",
- "PCM capture",
- "line out",
- "digital out",
+ "PCM",
+ "Line",
+ "Digital",
"RF",
- "speaker",
- "cobranet out",
- "analog out"
+ "Speaker",
+ "Cobranet Out",
+ "Analog"
};
-#endif
compile_time_assert(
(ARRAY_SIZE(asihpi_dst_names) ==
@@ -1438,30 +1425,45 @@ static void asihpi_ctl_init(struct snd_kcontrol_new *snd_control,
struct hpi_control *hpi_ctl,
char *name)
{
+ char *dir = "";
memset(snd_control, 0, sizeof(*snd_control));
snd_control->name = hpi_ctl->name;
snd_control->private_value = hpi_ctl->h_control;
snd_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
snd_control->index = 0;
+ if (hpi_ctl->dst_node_type + HPI_DESTNODE_NONE == HPI_DESTNODE_ISTREAM)
+ dir = "Capture "; /* On or towards a PCM capture destination*/
+ else if ((hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
+ (!hpi_ctl->dst_node_type))
+ dir = "Capture "; /* On a source node that is not PCM playback */
+ else if (hpi_ctl->src_node_type &&
+ (hpi_ctl->src_node_type + HPI_SOURCENODE_NONE != HPI_SOURCENODE_OSTREAM) &&
+ (hpi_ctl->dst_node_type))
+ dir = "Monitor Playback "; /* Between an input and an output */
+ else
+ dir = "Playback "; /* PCM Playback source, or output node */
+
if (hpi_ctl->src_node_type && hpi_ctl->dst_node_type)
- sprintf(hpi_ctl->name, "%s%d to %s%d %s",
+ sprintf(hpi_ctl->name, "%s%d %s%d %s%s",
asihpi_src_names[hpi_ctl->src_node_type],
hpi_ctl->src_node_index,
asihpi_dst_names[hpi_ctl->dst_node_type],
hpi_ctl->dst_node_index,
- name);
+ dir, name);
else if (hpi_ctl->dst_node_type) {
- sprintf(hpi_ctl->name, "%s%d %s",
+ sprintf(hpi_ctl->name, "%s %d %s%s",
asihpi_dst_names[hpi_ctl->dst_node_type],
hpi_ctl->dst_node_index,
- name);
+ dir, name);
} else {
- sprintf(hpi_ctl->name, "%s%d %s",
+ sprintf(hpi_ctl->name, "%s %d %s%s",
asihpi_src_names[hpi_ctl->src_node_type],
hpi_ctl->src_node_index,
- name);
+ dir, name);
}
+ /* printk(KERN_INFO "Adding %s %d to %d ", hpi_ctl->name,
+ hpi_ctl->wSrcNodeType, hpi_ctl->wDstNodeType); */
}
/*------------------------------------------------------------
@@ -1478,7 +1480,7 @@ static int snd_asihpi_volume_info(struct snd_kcontrol *kcontrol,
short max_gain_mB;
short step_gain_mB;
- err = hpi_volume_query_range(ss, h_control,
+ err = hpi_volume_query_range(h_control,
&min_gain_mB, &max_gain_mB, &step_gain_mB);
if (err) {
max_gain_mB = 0;
@@ -1500,7 +1502,7 @@ static int snd_asihpi_volume_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
short an_gain_mB[HPI_MAX_CHANNELS];
- hpi_handle_error(hpi_volume_get_gain(ss, h_control, an_gain_mB));
+ hpi_handle_error(hpi_volume_get_gain(h_control, an_gain_mB));
ucontrol->value.integer.value[0] = an_gain_mB[0] / VOL_STEP_mB;
ucontrol->value.integer.value[1] = an_gain_mB[1] / VOL_STEP_mB;
@@ -1522,7 +1524,7 @@ static int snd_asihpi_volume_put(struct snd_kcontrol *kcontrol,
asihpi->mixer_volume[addr][1] != right;
*/
change = 1;
- hpi_handle_error(hpi_volume_set_gain(ss, h_control, an_gain_mB));
+ hpi_handle_error(hpi_volume_set_gain(h_control, an_gain_mB));
return change;
}
@@ -1534,7 +1536,7 @@ static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
- asihpi_ctl_init(&snd_control, hpi_ctl, "volume");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Volume");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
snd_control.info = snd_asihpi_volume_info;
@@ -1558,7 +1560,7 @@ static int snd_asihpi_level_info(struct snd_kcontrol *kcontrol,
short step_gain_mB;
err =
- hpi_level_query_range(ss, h_control, &min_gain_mB,
+ hpi_level_query_range(h_control, &min_gain_mB,
&max_gain_mB, &step_gain_mB);
if (err) {
max_gain_mB = 2400;
@@ -1580,7 +1582,7 @@ static int snd_asihpi_level_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
short an_gain_mB[HPI_MAX_CHANNELS];
- hpi_handle_error(hpi_level_get_gain(ss, h_control, an_gain_mB));
+ hpi_handle_error(hpi_level_get_gain(h_control, an_gain_mB));
ucontrol->value.integer.value[0] =
an_gain_mB[0] / HPI_UNITS_PER_dB;
ucontrol->value.integer.value[1] =
@@ -1604,7 +1606,7 @@ static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol,
asihpi->mixer_level[addr][1] != right;
*/
change = 1;
- hpi_handle_error(hpi_level_set_gain(ss, h_control, an_gain_mB));
+ hpi_handle_error(hpi_level_set_gain(h_control, an_gain_mB));
return change;
}
@@ -1617,7 +1619,7 @@ static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
struct snd_kcontrol_new snd_control;
/* can't use 'volume' cos some nodes have volume as well */
- asihpi_ctl_init(&snd_control, hpi_ctl, "level");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Level");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
snd_control.info = snd_asihpi_level_info;
@@ -1633,12 +1635,8 @@ static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi,
------------------------------------------------------------*/
/* AESEBU format */
-static char *asihpi_aesebu_format_names[] =
-{
- "N/A",
- "S/PDIF",
- "AES/EBU",
-};
+static const char * const asihpi_aesebu_format_names[] = {
+ "N/A", "S/PDIF", "AES/EBU" };
static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -1659,12 +1657,12 @@ static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
- u16 (*func)(const struct hpi_hsubsys *, u32, u16 *))
+ u16 (*func)(u32, u16 *))
{
u32 h_control = kcontrol->private_value;
u16 source, err;
- err = func(ss, h_control, &source);
+ err = func(h_control, &source);
/* default to N/A */
ucontrol->value.enumerated.item[0] = 0;
@@ -1681,7 +1679,7 @@ static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol,
- u16 (*func)(const struct hpi_hsubsys *, u32, u16))
+ u16 (*func)(u32, u16))
{
u32 h_control = kcontrol->private_value;
@@ -1693,7 +1691,7 @@ static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] == 2)
source = HPI_AESEBU_FORMAT_AESEBU;
- if (func(ss, h_control, source) != 0)
+ if (func(h_control, source) != 0)
return -EINVAL;
return 1;
@@ -1702,13 +1700,13 @@ static int snd_asihpi_aesebu_format_put(struct snd_kcontrol *kcontrol,
static int snd_asihpi_aesebu_rx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
- HPI_AESEBU__receiver_get_format);
+ hpi_aesebu_receiver_get_format);
}
static int snd_asihpi_aesebu_rx_format_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
- HPI_AESEBU__receiver_set_format);
+ hpi_aesebu_receiver_set_format);
}
static int snd_asihpi_aesebu_rxstatus_info(struct snd_kcontrol *kcontrol,
@@ -1730,8 +1728,8 @@ static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
u16 status;
- hpi_handle_error(HPI_AESEBU__receiver_get_error_status(
- ss, h_control, &status));
+ hpi_handle_error(hpi_aesebu_receiver_get_error_status(
+ h_control, &status));
ucontrol->value.integer.value[0] = status;
return 0;
}
@@ -1742,7 +1740,7 @@ static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
- asihpi_ctl_init(&snd_control, hpi_ctl, "format");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
snd_control.info = snd_asihpi_aesebu_format_info;
snd_control.get = snd_asihpi_aesebu_rx_format_get;
@@ -1752,7 +1750,7 @@ static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
if (ctl_add(card, &snd_control, asihpi) < 0)
return -EINVAL;
- asihpi_ctl_init(&snd_control, hpi_ctl, "status");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Status");
snd_control.access =
SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
snd_control.info = snd_asihpi_aesebu_rxstatus_info;
@@ -1764,13 +1762,13 @@ static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi,
static int snd_asihpi_aesebu_tx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
return snd_asihpi_aesebu_format_get(kcontrol, ucontrol,
- HPI_AESEBU__transmitter_get_format);
+ hpi_aesebu_transmitter_get_format);
}
static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) {
return snd_asihpi_aesebu_format_put(kcontrol, ucontrol,
- HPI_AESEBU__transmitter_set_format);
+ hpi_aesebu_transmitter_set_format);
}
@@ -1780,7 +1778,7 @@ static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
- asihpi_ctl_init(&snd_control, hpi_ctl, "format");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Format");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
snd_control.info = snd_asihpi_aesebu_format_info;
snd_control.get = snd_asihpi_aesebu_tx_format_get;
@@ -1804,7 +1802,7 @@ static int snd_asihpi_tuner_gain_info(struct snd_kcontrol *kcontrol,
u16 gain_range[3];
for (idx = 0; idx < 3; idx++) {
- err = hpi_tuner_query_gain(ss, h_control,
+ err = hpi_tuner_query_gain(h_control,
idx, &gain_range[idx]);
if (err != 0)
return err;
@@ -1827,7 +1825,7 @@ static int snd_asihpi_tuner_gain_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
short gain;
- hpi_handle_error(hpi_tuner_get_gain(ss, h_control, &gain));
+ hpi_handle_error(hpi_tuner_get_gain(h_control, &gain));
ucontrol->value.integer.value[0] = gain / HPI_UNITS_PER_dB;
return 0;
@@ -1843,7 +1841,7 @@ static int snd_asihpi_tuner_gain_put(struct snd_kcontrol *kcontrol,
short gain;
gain = (ucontrol->value.integer.value[0]) * HPI_UNITS_PER_dB;
- hpi_handle_error(hpi_tuner_set_gain(ss, h_control, gain));
+ hpi_handle_error(hpi_tuner_set_gain(h_control, gain));
return 1;
}
@@ -1857,7 +1855,7 @@ static int asihpi_tuner_band_query(struct snd_kcontrol *kcontrol,
u32 i;
for (i = 0; i < len; i++) {
- err = hpi_tuner_query_band(ss,
+ err = hpi_tuner_query_band(
h_control, i, &band_list[i]);
if (err != 0)
break;
@@ -1913,7 +1911,7 @@ static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
HPI_TUNER_BAND_LAST);
- hpi_handle_error(hpi_tuner_get_band(ss, h_control, &band));
+ hpi_handle_error(hpi_tuner_get_band(h_control, &band));
ucontrol->value.enumerated.item[0] = -1;
for (idx = 0; idx < HPI_TUNER_BAND_LAST; idx++)
@@ -1940,7 +1938,7 @@ static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
HPI_TUNER_BAND_LAST);
band = tuner_bands[ucontrol->value.enumerated.item[0]];
- hpi_handle_error(hpi_tuner_set_band(ss, h_control, band));
+ hpi_handle_error(hpi_tuner_set_band(h_control, band));
return 1;
}
@@ -1965,7 +1963,7 @@ static int snd_asihpi_tuner_freq_info(struct snd_kcontrol *kcontrol,
for (band_iter = 0; band_iter < num_bands; band_iter++) {
for (idx = 0; idx < 3; idx++) {
- err = hpi_tuner_query_frequency(ss, h_control,
+ err = hpi_tuner_query_frequency(h_control,
idx, tuner_bands[band_iter],
&temp_freq_range[idx]);
if (err != 0)
@@ -1998,7 +1996,7 @@ static int snd_asihpi_tuner_freq_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
u32 freq;
- hpi_handle_error(hpi_tuner_get_frequency(ss, h_control, &freq));
+ hpi_handle_error(hpi_tuner_get_frequency(h_control, &freq));
ucontrol->value.integer.value[0] = freq;
return 0;
@@ -2011,7 +2009,7 @@ static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol,
u32 freq;
freq = ucontrol->value.integer.value[0];
- hpi_handle_error(hpi_tuner_set_frequency(ss, h_control, freq));
+ hpi_handle_error(hpi_tuner_set_frequency(h_control, freq));
return 1;
}
@@ -2026,8 +2024,8 @@ static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
snd_control.private_value = hpi_ctl->h_control;
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
- if (!hpi_tuner_get_gain(ss, hpi_ctl->h_control, NULL)) {
- asihpi_ctl_init(&snd_control, hpi_ctl, "gain");
+ if (!hpi_tuner_get_gain(hpi_ctl->h_control, NULL)) {
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Gain");
snd_control.info = snd_asihpi_tuner_gain_info;
snd_control.get = snd_asihpi_tuner_gain_get;
snd_control.put = snd_asihpi_tuner_gain_put;
@@ -2036,7 +2034,7 @@ static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
return -EINVAL;
}
- asihpi_ctl_init(&snd_control, hpi_ctl, "band");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Band");
snd_control.info = snd_asihpi_tuner_band_info;
snd_control.get = snd_asihpi_tuner_band_get;
snd_control.put = snd_asihpi_tuner_band_put;
@@ -2044,7 +2042,7 @@ static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi,
if (ctl_add(card, &snd_control, asihpi) < 0)
return -EINVAL;
- asihpi_ctl_init(&snd_control, hpi_ctl, "freq");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Freq");
snd_control.info = snd_asihpi_tuner_freq_info;
snd_control.get = snd_asihpi_tuner_freq_get;
snd_control.put = snd_asihpi_tuner_freq_put;
@@ -2095,7 +2093,7 @@ static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol,
short an_gain_mB[HPI_MAX_CHANNELS], i;
u16 err;
- err = hpi_meter_get_peak(ss, h_control, an_gain_mB);
+ err = hpi_meter_get_peak(h_control, an_gain_mB);
for (i = 0; i < HPI_MAX_CHANNELS; i++) {
if (err) {
@@ -2120,7 +2118,7 @@ static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
- asihpi_ctl_init(&snd_control, hpi_ctl, "meter");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Meter");
snd_control.access =
SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
snd_control.info = snd_asihpi_meter_info;
@@ -2140,7 +2138,7 @@ static int snd_card_asihpi_mux_count_sources(struct snd_kcontrol *snd_control)
struct hpi_control hpi_ctl;
int s, err;
for (s = 0; s < 32; s++) {
- err = hpi_multiplexer_query_source(ss, h_control, s,
+ err = hpi_multiplexer_query_source(h_control, s,
&hpi_ctl.
src_node_type,
&hpi_ctl.
@@ -2168,7 +2166,7 @@ static int snd_asihpi_mux_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items - 1;
err =
- hpi_multiplexer_query_source(ss, h_control,
+ hpi_multiplexer_query_source(h_control,
uinfo->value.enumerated.item,
&src_node_type, &src_node_index);
@@ -2186,11 +2184,11 @@ static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
u16 src_node_type, src_node_index;
int s;
- hpi_handle_error(hpi_multiplexer_get_source(ss, h_control,
+ hpi_handle_error(hpi_multiplexer_get_source(h_control,
&source_type, &source_index));
/* Should cache this search result! */
for (s = 0; s < 256; s++) {
- if (hpi_multiplexer_query_source(ss, h_control, s,
+ if (hpi_multiplexer_query_source(h_control, s,
&src_node_type, &src_node_index))
break;
@@ -2201,7 +2199,7 @@ static int snd_asihpi_mux_get(struct snd_kcontrol *kcontrol,
}
}
snd_printd(KERN_WARNING
- "control %x failed to match mux source %hu %hu\n",
+ "Control %x failed to match mux source %hu %hu\n",
h_control, source_type, source_index);
ucontrol->value.enumerated.item[0] = 0;
return 0;
@@ -2217,12 +2215,12 @@ static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol,
change = 1;
- e = hpi_multiplexer_query_source(ss, h_control,
+ e = hpi_multiplexer_query_source(h_control,
ucontrol->value.enumerated.item[0],
&source_type, &source_index);
if (!e)
hpi_handle_error(
- hpi_multiplexer_set_source(ss, h_control,
+ hpi_multiplexer_set_source(h_control,
source_type, source_index));
return change;
}
@@ -2234,11 +2232,7 @@ static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
-#if ASI_STYLE_NAMES
- asihpi_ctl_init(&snd_control, hpi_ctl, "multiplexer");
-#else
- asihpi_ctl_init(&snd_control, hpi_ctl, "route");
-#endif
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Route");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
snd_control.info = snd_asihpi_mux_info;
snd_control.get = snd_asihpi_mux_get;
@@ -2254,33 +2248,38 @@ static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi,
static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *mode_names[HPI_CHANNEL_MODE_LAST] = {
- "normal", "swap",
- "from_left", "from_right",
- "to_left", "to_right"
+ static const char * const mode_names[HPI_CHANNEL_MODE_LAST + 1] = {
+ "invalid",
+ "Normal", "Swap",
+ "From Left", "From Right",
+ "To Left", "To Right"
};
u32 h_control = kcontrol->private_value;
u16 mode;
int i;
+ u16 mode_map[6];
+ int valid_modes = 0;
/* HPI channel mode values can be from 1 to 6
Some adapters only support a contiguous subset
*/
for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
- if (hpi_channel_mode_query_mode(
- ss, h_control, i, &mode))
- break;
+ if (!hpi_channel_mode_query_mode(
+ h_control, i, &mode)) {
+ mode_map[valid_modes] = mode;
+ valid_modes++;
+ }
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = i;
+ uinfo->value.enumerated.items = valid_modes;
- if (uinfo->value.enumerated.item >= i)
- uinfo->value.enumerated.item = i - 1;
+ if (uinfo->value.enumerated.item >= valid_modes)
+ uinfo->value.enumerated.item = valid_modes - 1;
strcpy(uinfo->value.enumerated.name,
- mode_names[uinfo->value.enumerated.item]);
+ mode_names[mode_map[uinfo->value.enumerated.item]]);
return 0;
}
@@ -2291,7 +2290,7 @@ static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
u16 mode;
- if (hpi_channel_mode_get(ss, h_control, &mode))
+ if (hpi_channel_mode_get(h_control, &mode))
mode = 1;
ucontrol->value.enumerated.item[0] = mode - 1;
@@ -2307,7 +2306,7 @@ static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol,
change = 1;
- hpi_handle_error(hpi_channel_mode_set(ss, h_control,
+ hpi_handle_error(hpi_channel_mode_set(h_control,
ucontrol->value.enumerated.item[0] + 1));
return change;
}
@@ -2319,7 +2318,7 @@ static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
struct snd_card *card = asihpi->card;
struct snd_kcontrol_new snd_control;
- asihpi_ctl_init(&snd_control, hpi_ctl, "channel mode");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Mode");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
snd_control.info = snd_asihpi_cmode_info;
snd_control.get = snd_asihpi_cmode_get;
@@ -2331,15 +2330,12 @@ static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
/*------------------------------------------------------------
Sampleclock source controls
------------------------------------------------------------*/
-
-static char *sampleclock_sources[MAX_CLOCKSOURCES] =
- { "N/A", "local PLL", "AES/EBU sync", "word external", "word header",
- "SMPTE", "AES/EBU in1", "auto", "network", "invalid",
- "prev module",
- "AES/EBU in2", "AES/EBU in3", "AES/EBU in4", "AES/EBU in5",
- "AES/EBU in6", "AES/EBU in7", "AES/EBU in8"};
-
-
+static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
+ "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
+ "SMPTE", "Digital1", "Auto", "Network", "Invalid",
+ "Prev Module",
+ "Digital2", "Digital3", "Digital4", "Digital5",
+ "Digital6", "Digital7", "Digital8"};
static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -2371,11 +2367,11 @@ static int snd_asihpi_clksrc_get(struct snd_kcontrol *kcontrol,
int i;
ucontrol->value.enumerated.item[0] = 0;
- if (hpi_sample_clock_get_source(ss, h_control, &source))
+ if (hpi_sample_clock_get_source(h_control, &source))
source = 0;
if (source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
- if (hpi_sample_clock_get_source_index(ss, h_control, &srcindex))
+ if (hpi_sample_clock_get_source_index(h_control, &srcindex))
srcindex = 0;
for (i = 0; i < clkcache->count; i++)
@@ -2402,11 +2398,11 @@ static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
if (item >= clkcache->count)
item = clkcache->count-1;
- hpi_handle_error(hpi_sample_clock_set_source(ss,
+ hpi_handle_error(hpi_sample_clock_set_source(
h_control, clkcache->s[item].source));
if (clkcache->s[item].source == HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT)
- hpi_handle_error(hpi_sample_clock_set_source_index(ss,
+ hpi_handle_error(hpi_sample_clock_set_source_index(
h_control, clkcache->s[item].index));
return change;
}
@@ -2434,7 +2430,7 @@ static int snd_asihpi_clklocal_get(struct snd_kcontrol *kcontrol,
u32 rate;
u16 e;
- e = hpi_sample_clock_get_local_rate(ss, h_control, &rate);
+ e = hpi_sample_clock_get_local_rate(h_control, &rate);
if (!e)
ucontrol->value.integer.value[0] = rate;
else
@@ -2452,7 +2448,7 @@ static int snd_asihpi_clklocal_put(struct snd_kcontrol *kcontrol,
asihpi->mixer_clkrate[addr][1] != right;
*/
change = 1;
- hpi_handle_error(hpi_sample_clock_set_local_rate(ss, h_control,
+ hpi_handle_error(hpi_sample_clock_set_local_rate(h_control,
ucontrol->value.integer.value[0]));
return change;
}
@@ -2476,7 +2472,7 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
u32 rate;
u16 e;
- e = hpi_sample_clock_get_sample_rate(ss, h_control, &rate);
+ e = hpi_sample_clock_get_sample_rate(h_control, &rate);
if (!e)
ucontrol->value.integer.value[0] = rate;
else
@@ -2501,7 +2497,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
clkcache->has_local = 0;
for (i = 0; i <= HPI_SAMPLECLOCK_SOURCE_LAST; i++) {
- if (hpi_sample_clock_query_source(ss, hSC,
+ if (hpi_sample_clock_query_source(hSC,
i, &source))
break;
clkcache->s[i].source = source;
@@ -2515,7 +2511,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
if (has_aes_in)
/* already will have picked up index 0 above */
for (j = 1; j < 8; j++) {
- if (hpi_sample_clock_query_source_index(ss, hSC,
+ if (hpi_sample_clock_query_source_index(hSC,
j, HPI_SAMPLECLOCK_SOURCE_AESEBU_INPUT,
&source))
break;
@@ -2528,7 +2524,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
}
clkcache->count = i;
- asihpi_ctl_init(&snd_control, hpi_ctl, "source");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Source");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
snd_control.info = snd_asihpi_clksrc_info;
snd_control.get = snd_asihpi_clksrc_get;
@@ -2538,7 +2534,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
if (clkcache->has_local) {
- asihpi_ctl_init(&snd_control, hpi_ctl, "local_rate");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Localrate");
snd_control.access = SNDRV_CTL_ELEM_ACCESS_READWRITE ;
snd_control.info = snd_asihpi_clklocal_info;
snd_control.get = snd_asihpi_clklocal_get;
@@ -2549,7 +2545,7 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
return -EINVAL;
}
- asihpi_ctl_init(&snd_control, hpi_ctl, "rate");
+ asihpi_ctl_init(&snd_control, hpi_ctl, "Rate");
snd_control.access =
SNDRV_CTL_ELEM_ACCESS_VOLATILE | SNDRV_CTL_ELEM_ACCESS_READ;
snd_control.info = snd_asihpi_clkrate_info;
@@ -2571,10 +2567,10 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (snd_BUG_ON(!asihpi))
return -EINVAL;
- strcpy(card->mixername, "asihpi mixer");
+ strcpy(card->mixername, "Asihpi Mixer");
err =
- hpi_mixer_open(ss, asihpi->adapter_index,
+ hpi_mixer_open(asihpi->adapter_index,
&asihpi->h_mixer);
hpi_handle_error(err);
if (err)
@@ -2585,7 +2581,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
for (idx = 0; idx < 2000; idx++) {
err = hpi_mixer_get_control_by_index(
- ss, asihpi->h_mixer,
+ asihpi->h_mixer,
idx,
&hpi_ctl.src_node_type,
&hpi_ctl.src_node_index,
@@ -2597,7 +2593,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (err == HPI_ERROR_CONTROL_DISABLED) {
if (mixer_dump)
snd_printk(KERN_INFO
- "disabled HPI control(%d)\n",
+ "Disabled HPI Control(%d)\n",
idx);
continue;
} else
@@ -2662,7 +2658,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
default:
if (mixer_dump)
snd_printk(KERN_INFO
- "untranslated HPI control"
+ "Untranslated HPI Control"
"(%d) %d %d %d %d %d\n",
idx,
hpi_ctl.control_type,
@@ -2712,14 +2708,14 @@ snd_asihpi_proc_read(struct snd_info_entry *entry,
version & 0x7,
((version >> 13) * 100) + ((version >> 7) & 0x3f));
- err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+ err = hpi_mixer_get_control(asihpi->h_mixer,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (!err) {
- err = hpi_sample_clock_get_sample_rate(ss,
+ err = hpi_sample_clock_get_sample_rate(
h_control, &rate);
- err += hpi_sample_clock_get_source(ss, h_control, &source);
+ err += hpi_sample_clock_get_source(h_control, &source);
if (!err)
snd_iprintf(buffer, "sample_clock=%d_hz, source %s\n",
@@ -2841,15 +2837,17 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
if (err < 0)
return err;
snd_printk(KERN_WARNING
- "**** WARNING **** adapter index %d->ALSA index %d\n",
+ "**** WARNING **** Adapter index %d->ALSA index %d\n",
hpi_card->index, card->number);
}
+ snd_card_set_dev(card, &pci_dev->dev);
+
asihpi = (struct snd_card_asihpi *) card->private_data;
asihpi->card = card;
- asihpi->pci = hpi_card->pci;
+ asihpi->pci = pci_dev;
asihpi->adapter_index = hpi_card->index;
- hpi_handle_error(hpi_adapter_get_info(ss,
+ hpi_handle_error(hpi_adapter_get_info(
asihpi->adapter_index,
&asihpi->num_outstreams,
&asihpi->num_instreams,
@@ -2859,7 +2857,7 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
version = asihpi->version;
snd_printk(KERN_INFO "adapter ID=%4X index=%d num_outstreams=%d "
"num_instreams=%d S/N=%d\n"
- "hw version %c%d DSP code version %03d\n",
+ "Hw Version %c%d DSP code version %03d\n",
asihpi->type, asihpi->adapter_index,
asihpi->num_outstreams,
asihpi->num_instreams, asihpi->serial_number,
@@ -2871,33 +2869,33 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
if (pcm_substreams < asihpi->num_instreams)
pcm_substreams = asihpi->num_instreams;
- err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+ err = hpi_adapter_get_property(asihpi->adapter_index,
HPI_ADAPTER_PROPERTY_CAPS1,
NULL, &asihpi->support_grouping);
if (err)
asihpi->support_grouping = 0;
- err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+ err = hpi_adapter_get_property(asihpi->adapter_index,
HPI_ADAPTER_PROPERTY_CAPS2,
&asihpi->support_mrx, NULL);
if (err)
asihpi->support_mrx = 0;
- err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+ err = hpi_adapter_get_property(asihpi->adapter_index,
HPI_ADAPTER_PROPERTY_INTERVAL,
NULL, &asihpi->update_interval_frames);
if (err)
asihpi->update_interval_frames = 512;
- hpi_handle_error(hpi_instream_open(ss, asihpi->adapter_index,
+ hpi_handle_error(hpi_instream_open(asihpi->adapter_index,
0, &h_stream));
- err = hpi_instream_host_buffer_free(ss, h_stream);
+ err = hpi_instream_host_buffer_free(h_stream);
asihpi->support_mmap = (!err);
- hpi_handle_error(hpi_instream_close(ss, h_stream));
+ hpi_handle_error(hpi_instream_close(h_stream));
- err = hpi_adapter_get_property(ss, asihpi->adapter_index,
+ err = hpi_adapter_get_property(asihpi->adapter_index,
HPI_ADAPTER_PROPERTY_CURCHANNELS,
&asihpi->in_max_chans, &asihpi->out_max_chans);
if (err) {
@@ -2923,13 +2921,13 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev,
goto __nodev;
}
- err = hpi_mixer_get_control(ss, asihpi->h_mixer,
+ err = hpi_mixer_get_control(asihpi->h_mixer,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (!err)
err = hpi_sample_clock_set_local_rate(
- ss, h_control, adapter_fs);
+ h_control, adapter_fs);
snd_asihpi_proc_init(asihpi);
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 23399d02f666..6fc025c448de 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -24,17 +24,10 @@
The HPI is a low-level hardware abstraction layer to all
AudioScience digital audio adapters
-*/
-/*
- You must define one operating system that the HPI is to be compiled under
- HPI_OS_WIN32_USER 32bit Windows
- HPI_OS_DSP_C6000 DSP TI C6000 (automatically set)
- HPI_OS_WDM Windows WDM kernel driver
- HPI_OS_LINUX Linux userspace
- HPI_OS_LINUX_KERNEL Linux kernel (automatically set)
(C) Copyright AudioScience Inc. 1998-2010
-******************************************************************************/
+*/
+
#ifndef _HPI_H_
#define _HPI_H_
/* HPI Version
@@ -50,20 +43,20 @@ i.e 3.05.02 is a development version
#define HPI_VER_RELEASE(v) ((int)(v & 0xFF))
/* Use single digits for versions less that 10 to avoid octal. */
-#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 4, 1)
-#define HPI_VER_STRING "4.04.01"
+#define HPI_VER HPI_VERSION_CONSTRUCTOR(4L, 6, 0)
+#define HPI_VER_STRING "4.06.00"
/* Library version as documented in hpi-api-versions.txt */
#define HPI_LIB_VER HPI_VERSION_CONSTRUCTOR(9, 0, 0)
#include <linux/types.h>
-#define HPI_EXCLUDE_DEPRECATED
+#define HPI_BUILD_EXCLUDE_DEPRECATED
+#define HPI_BUILD_KERNEL_MODE
/******************************************************************************/
-/******************************************************************************/
/******** HPI API DEFINITIONS *****/
/******************************************************************************/
-/******************************************************************************/
+
/*******************************************/
/** Audio format types
\ingroup stream
@@ -174,7 +167,6 @@ The range is +1.0 to -1.0, which corresponds to digital fullscale.
HPI_FORMAT_UNDEFINED = 0xffff
};
-/******************************************* in/out Stream states */
/*******************************************/
/** Stream States
\ingroup stream
@@ -194,7 +186,7 @@ enum HPI_STREAM_STATES {
cards to be ready. */
HPI_STATE_WAIT = 6
};
-/******************************************* mixer source node types */
+/*******************************************/
/** Source node types
\ingroup mixer
*/
@@ -224,7 +216,7 @@ enum HPI_SOURCENODES {
/* AX6 max sourcenode types = 15 */
};
-/******************************************* mixer dest node types */
+/*******************************************/
/** Destination node types
\ingroup mixer
*/
@@ -262,11 +254,11 @@ enum HPI_CONTROLS {
HPI_CONTROL_MUTE = 4, /*mute control - not used at present. */
HPI_CONTROL_MULTIPLEXER = 5, /**< multiplexer control. */
- HPI_CONTROL_AESEBU_TRANSMITTER = 6, /**< AES/EBU transmitter control. */
- HPI_CONTROL_AESEBUTX = HPI_CONTROL_AESEBU_TRANSMITTER,
+ HPI_CONTROL_AESEBU_TRANSMITTER = 6, /**< AES/EBU transmitter control */
+ HPI_CONTROL_AESEBUTX = 6, /* HPI_CONTROL_AESEBU_TRANSMITTER */
HPI_CONTROL_AESEBU_RECEIVER = 7, /**< AES/EBU receiver control. */
- HPI_CONTROL_AESEBURX = HPI_CONTROL_AESEBU_RECEIVER,
+ HPI_CONTROL_AESEBURX = 7, /* HPI_CONTROL_AESEBU_RECEIVER */
HPI_CONTROL_LEVEL = 8, /**< level/trim control - works in d_bu. */
HPI_CONTROL_TUNER = 9, /**< tuner control. */
@@ -281,7 +273,7 @@ enum HPI_CONTROLS {
HPI_CONTROL_SAMPLECLOCK = 17, /**< sample clock control. */
HPI_CONTROL_MICROPHONE = 18, /**< microphone control. */
HPI_CONTROL_PARAMETRIC_EQ = 19, /**< parametric EQ control. */
- HPI_CONTROL_EQUALIZER = HPI_CONTROL_PARAMETRIC_EQ,
+ HPI_CONTROL_EQUALIZER = 19, /*HPI_CONTROL_PARAMETRIC_EQ */
HPI_CONTROL_COMPANDER = 20, /**< compander control. */
HPI_CONTROL_COBRANET = 21, /**< cobranet control. */
@@ -296,10 +288,7 @@ enum HPI_CONTROLS {
/* WARNING types 256 or greater impact bit packing in all AX6 DSP code */
};
-/* Shorthand names that match attribute names */
-
-/******************************************* ADAPTER ATTRIBUTES ****/
-
+/*******************************************/
/** Adapter properties
These are used in HPI_AdapterSetProperty() and HPI_AdapterGetProperty()
\ingroup adapter
@@ -330,12 +319,21 @@ by the driver and is not passed on to the DSP at all.
Indicates the state of the adapter's SSX2 setting. This setting is stored in
non-volatile memory on the adapter. A typical call sequence would be to use
HPI_ADAPTER_PROPERTY_SSX2_SETTING to set SSX2 on the adapter and then to reload
-the driver. The driver would query HPI_ADAPTER_PROPERTY_SSX2_SETTING during startup
-and if SSX2 is set, it would then call HPI_ADAPTER_PROPERTY_ENABLE_SSX2 to enable
-SSX2 stream mapping within the kernel level of the driver.
+the driver. The driver would query HPI_ADAPTER_PROPERTY_SSX2_SETTING during
+startup and if SSX2 is set, it would then call HPI_ADAPTER_PROPERTY_ENABLE_SSX2
+to enable SSX2 stream mapping within the kernel level of the driver.
*/
HPI_ADAPTER_PROPERTY_SSX2_SETTING = 4,
+/** Enables/disables PCI(e) IRQ.
+A setting of 0 indicates that no interrupts are being generated. A DSP boot
+this property is set to 0. Setting to a non-zero value specifies the number
+of frames of audio that should be processed between interrupts. This property
+should be set to multiple of the mixer interval as read back from the
+HPI_ADAPTER_PROPERTY_INTERVAL property.
+*/
+ HPI_ADAPTER_PROPERTY_IRQ_RATE = 5,
+
/** Base number for readonly properties */
HPI_ADAPTER_PROPERTY_READONLYBASE = 256,
@@ -440,21 +438,30 @@ return value is true (1) or false (0). If the current adapter
mode is MONO SSX2 is disabled, even though this property will
return true.
*/
- HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271
+ HPI_ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271,
+/** Readonly supports PCI(e) IRQ.
+Indicates that the adapter in it's current mode supports interrupts
+across the host bus. Note, this does not imply that interrupts are
+enabled. Instead it indicates that they can be enabled.
+*/
+ HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ = 272
};
/** Adapter mode commands
-Used in wQueryOrSet field of HPI_AdapterSetModeEx().
+Used in wQueryOrSet parameter of HPI_AdapterSetModeEx().
\ingroup adapter
*/
enum HPI_ADAPTER_MODE_CMDS {
+ /** Set the mode to the given parameter */
HPI_ADAPTER_MODE_SET = 0,
+ /** Return 0 or error depending whether mode is valid,
+ but don't set the mode */
HPI_ADAPTER_MODE_QUERY = 1
};
/** Adapter Modes
- These are used by HPI_AdapterSetModeEx()
+ These are used by HPI_AdapterSetModeEx()
\warning - more than 16 possible modes breaks
a bitmask in the Windows WAVE DLL
@@ -629,10 +636,13 @@ enum HPI_MIXER_STORE_COMMAND {
HPI_MIXER_STORE_SAVE_SINGLE = 6
};
-/************************************* CONTROL ATTRIBUTE VALUES ****/
+/****************************/
+/* CONTROL ATTRIBUTE VALUES */
+/****************************/
+
/** Used by mixer plugin enable functions
-E.g. HPI_ParametricEQ_SetState()
+E.g. HPI_ParametricEq_SetState()
\ingroup mixer
*/
enum HPI_SWITCH_STATES {
@@ -641,6 +651,7 @@ enum HPI_SWITCH_STATES {
};
/* Volume control special gain values */
+
/** volumes units are 100ths of a dB
\ingroup volume
*/
@@ -650,6 +661,11 @@ enum HPI_SWITCH_STATES {
*/
#define HPI_GAIN_OFF (-100 * HPI_UNITS_PER_dB)
+/** channel mask specifying all channels
+\ingroup volume
+*/
+#define HPI_BITMASK_ALL_CHANNELS (0xFFFFFFFF)
+
/** value returned for no signal
\ingroup meter
*/
@@ -667,7 +683,7 @@ enum HPI_VOLUME_AUTOFADES {
/** The physical encoding format of the AESEBU I/O.
-Used in HPI_AESEBU_Transmitter_SetFormat(), HPI_AESEBU_Receiver_SetFormat()
+Used in HPI_Aesebu_Transmitter_SetFormat(), HPI_Aesebu_Receiver_SetFormat()
along with related Get and Query functions
\ingroup aestx
*/
@@ -680,7 +696,7 @@ enum HPI_AESEBU_FORMATS {
/** AES/EBU error status bits
-Returned by HPI_AESEBU_Receiver_GetErrorStatus()
+Returned by HPI_Aesebu_Receiver_GetErrorStatus()
\ingroup aesrx
*/
enum HPI_AESEBU_ERRORS {
@@ -767,14 +783,6 @@ enum HPI_TUNER_MODE_VALUES {
HPI_TUNER_MODE_RDS_RBDS = 2 /**< RDS - RBDS mode */
};
-/** Tuner Level settings
-\ingroup tuner
-*/
-enum HPI_TUNER_LEVEL {
- HPI_TUNER_LEVEL_AVERAGE = 0,
- HPI_TUNER_LEVEL_RAW = 1
-};
-
/** Tuner Status Bits
These bitfield values are returned by a call to HPI_Tuner_GetStatus().
@@ -783,13 +791,13 @@ Multiple fields are returned from a single call.
*/
enum HPI_TUNER_STATUS_BITS {
HPI_TUNER_VIDEO_COLOR_PRESENT = 0x0001, /**< video color is present. */
- HPI_TUNER_VIDEO_IS_60HZ = 0x0020, /**< 60 hz video detected. */
- HPI_TUNER_VIDEO_HORZ_SYNC_MISSING = 0x0040, /**< video HSYNC is missing. */
- HPI_TUNER_VIDEO_STATUS_VALID = 0x0100, /**< video status is valid. */
- HPI_TUNER_PLL_LOCKED = 0x1000, /**< the tuner's PLL is locked. */
- HPI_TUNER_FM_STEREO = 0x2000, /**< tuner reports back FM stereo. */
- HPI_TUNER_DIGITAL = 0x0200, /**< tuner reports digital programming. */
- HPI_TUNER_MULTIPROGRAM = 0x0400 /**< tuner reports multiple programs. */
+ HPI_TUNER_VIDEO_IS_60HZ = 0x0020, /**< 60 hz video detected. */
+ HPI_TUNER_VIDEO_HORZ_SYNC_MISSING = 0x0040, /**< video HSYNC is missing. */
+ HPI_TUNER_VIDEO_STATUS_VALID = 0x0100, /**< video status is valid. */
+ HPI_TUNER_DIGITAL = 0x0200, /**< tuner reports digital programming. */
+ HPI_TUNER_MULTIPROGRAM = 0x0400, /**< tuner reports multiple programs. */
+ HPI_TUNER_PLL_LOCKED = 0x1000, /**< the tuner's PLL is locked. */
+ HPI_TUNER_FM_STEREO = 0x2000 /**< tuner reports back FM stereo. */
};
/** Channel Modes
@@ -839,7 +847,7 @@ enum HPI_SAMPLECLOCK_SOURCES {
HPI_SAMPLECLOCK_SOURCE_LAST = 10
};
-/** Equalizer filter types. Used by HPI_ParametricEQ_SetBand()
+/** Equalizer filter types. Used by HPI_ParametricEq_SetBand()
\ingroup parmeq
*/
enum HPI_FILTER_TYPE {
@@ -882,7 +890,7 @@ enum HPI_ERROR_CODES {
HPI_ERROR_INVALID_OBJ = 101,
/** Function does not exist. */
HPI_ERROR_INVALID_FUNC = 102,
- /** The specified object (adapter/Stream) does not exist. */
+ /** The specified object does not exist. */
HPI_ERROR_INVALID_OBJ_INDEX = 103,
/** Trying to access an object that has not been opened yet. */
HPI_ERROR_OBJ_NOT_OPEN = 104,
@@ -890,8 +898,7 @@ enum HPI_ERROR_CODES {
HPI_ERROR_OBJ_ALREADY_OPEN = 105,
/** PCI, ISA resource not valid. */
HPI_ERROR_INVALID_RESOURCE = 106,
- /** GetInfo call from SubSysFindAdapters failed. */
- HPI_ERROR_SUBSYSFINDADAPTERS_GETINFO = 107,
+ /* HPI_ERROR_SUBSYSFINDADAPTERS_GETINFO= 107 */
/** Default response was never updated with actual error code. */
HPI_ERROR_INVALID_RESPONSE = 108,
/** wSize field of response was not updated,
@@ -899,38 +906,44 @@ enum HPI_ERROR_CODES {
HPI_ERROR_PROCESSING_MESSAGE = 109,
/** The network did not respond in a timely manner. */
HPI_ERROR_NETWORK_TIMEOUT = 110,
- /** An HPI handle is invalid (uninitialised?). */
+ /* An HPI handle is invalid (uninitialised?). */
HPI_ERROR_INVALID_HANDLE = 111,
/** A function or attribute has not been implemented yet. */
HPI_ERROR_UNIMPLEMENTED = 112,
- /** There are too many clients attempting to access a network resource. */
+ /** There are too many clients attempting
+ to access a network resource. */
HPI_ERROR_NETWORK_TOO_MANY_CLIENTS = 113,
- /** Response buffer passed to HPI_Message was smaller than returned response */
+ /** Response buffer passed to HPI_Message
+ was smaller than returned response.
+ wSpecificError field of hpi response contains the required size.
+ */
HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL = 114,
/** The returned response did not match the sent message */
HPI_ERROR_RESPONSE_MISMATCH = 115,
+ /** A control setting that should have been cached was not. */
+ HPI_ERROR_CONTROL_CACHING = 116,
+ /** A message buffer in the path to the adapter was smaller
+ than the message size.
+ wSpecificError field of hpi response contains the actual size.
+ */
+ HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL = 117,
- /** Too many adapters.*/
- HPI_ERROR_TOO_MANY_ADAPTERS = 200,
+ /* HPI_ERROR_TOO_MANY_ADAPTERS= 200 */
/** Bad adpater. */
HPI_ERROR_BAD_ADAPTER = 201,
/** Adapter number out of range or not set properly. */
HPI_ERROR_BAD_ADAPTER_NUMBER = 202,
/** 2 adapters with the same adapter number. */
- HPI_DUPLICATE_ADAPTER_NUMBER = 203,
- /** DSP code failed to bootload. */
+ HPI_ERROR_DUPLICATE_ADAPTER_NUMBER = 203,
+ /** DSP code failed to bootload. (unused?) */
HPI_ERROR_DSP_BOOTLOAD = 204,
- /** Adapter failed DSP code self test. */
- HPI_ERROR_DSP_SELFTEST = 205,
/** Couldn't find or open the DSP code file. */
HPI_ERROR_DSP_FILE_NOT_FOUND = 206,
/** Internal DSP hardware error. */
HPI_ERROR_DSP_HARDWARE = 207,
- /** Could not allocate memory in DOS. */
- HPI_ERROR_DOS_MEMORY_ALLOC = 208,
/** Could not allocate memory */
HPI_ERROR_MEMORY_ALLOC = 208,
- /** Failed to correctly load/config PLD .*/
+ /** Failed to correctly load/config PLD. (unused) */
HPI_ERROR_PLD_LOAD = 209,
/** Unexpected end of file, block length too big etc. */
HPI_ERROR_DSP_FILE_FORMAT = 210,
@@ -939,8 +952,7 @@ enum HPI_ERROR_CODES {
HPI_ERROR_DSP_FILE_ACCESS_DENIED = 211,
/** First DSP code section header not found in DSP file. */
HPI_ERROR_DSP_FILE_NO_HEADER = 212,
- /** File read operation on DSP code file failed. */
- HPI_ERROR_DSP_FILE_READ_ERROR = 213,
+ /* HPI_ERROR_DSP_FILE_READ_ERROR= 213, */
/** DSP code for adapter family not found. */
HPI_ERROR_DSP_SECTION_NOT_FOUND = 214,
/** Other OS specific error opening DSP file. */
@@ -950,23 +962,21 @@ enum HPI_ERROR_CODES {
/** DSP code section header had size == 0. */
HPI_ERROR_DSP_FILE_NULL_HEADER = 217,
- /** Base number for flash errors. */
- HPI_ERROR_FLASH = 220,
+ /* HPI_ERROR_FLASH = 220, */
/** Flash has bad checksum */
- HPI_ERROR_BAD_CHECKSUM = (HPI_ERROR_FLASH + 1),
- HPI_ERROR_BAD_SEQUENCE = (HPI_ERROR_FLASH + 2),
- HPI_ERROR_FLASH_ERASE = (HPI_ERROR_FLASH + 3),
- HPI_ERROR_FLASH_PROGRAM = (HPI_ERROR_FLASH + 4),
- HPI_ERROR_FLASH_VERIFY = (HPI_ERROR_FLASH + 5),
- HPI_ERROR_FLASH_TYPE = (HPI_ERROR_FLASH + 6),
- HPI_ERROR_FLASH_START = (HPI_ERROR_FLASH + 7),
+ HPI_ERROR_BAD_CHECKSUM = 221,
+ HPI_ERROR_BAD_SEQUENCE = 222,
+ HPI_ERROR_FLASH_ERASE = 223,
+ HPI_ERROR_FLASH_PROGRAM = 224,
+ HPI_ERROR_FLASH_VERIFY = 225,
+ HPI_ERROR_FLASH_TYPE = 226,
+ HPI_ERROR_FLASH_START = 227,
/** Reserved for OEMs. */
HPI_ERROR_RESERVED_1 = 290,
- /** Stream does not exist. */
- HPI_ERROR_INVALID_STREAM = 300,
+ /* HPI_ERROR_INVALID_STREAM = 300 use HPI_ERROR_INVALID_OBJ_INDEX */
/** Invalid compression format. */
HPI_ERROR_INVALID_FORMAT = 301,
/** Invalid format samplerate */
@@ -977,21 +987,19 @@ enum HPI_ERROR_CODES {
HPI_ERROR_INVALID_BITRATE = 304,
/** Invalid datasize used for stream read/write. */
HPI_ERROR_INVALID_DATASIZE = 305,
- /** Stream buffer is full during stream write. */
- HPI_ERROR_BUFFER_FULL = 306,
- /** Stream buffer is empty during stream read. */
- HPI_ERROR_BUFFER_EMPTY = 307,
- /** Invalid datasize used for stream read/write. */
- HPI_ERROR_INVALID_DATA_TRANSFER = 308,
+ /* HPI_ERROR_BUFFER_FULL = 306 use HPI_ERROR_INVALID_DATASIZE */
+ /* HPI_ERROR_BUFFER_EMPTY = 307 use HPI_ERROR_INVALID_DATASIZE */
+ /** Null data pointer used for stream read/write. */
+ HPI_ERROR_INVALID_DATA_POINTER = 308,
/** Packet ordering error for stream read/write. */
HPI_ERROR_INVALID_PACKET_ORDER = 309,
/** Object can't do requested operation in its current
- state, eg set format, change rec mux state while recording.*/
+ state, eg set format, change rec mux state while recording.*/
HPI_ERROR_INVALID_OPERATION = 310,
- /** Where an SRG is shared amongst streams, an incompatible samplerate is one
- that is different to any currently playing or recording stream. */
+ /** Where a SRG is shared amongst streams, an incompatible samplerate
+ is one that is different to any currently active stream. */
HPI_ERROR_INCOMPATIBLE_SAMPLERATE = 311,
/** Adapter mode is illegal.*/
HPI_ERROR_BAD_ADAPTER_MODE = 312,
@@ -1004,6 +1012,8 @@ enum HPI_ERROR_CODES {
HPI_ERROR_NO_INTERADAPTER_GROUPS = 314,
/** Streams on different DSPs cannot be grouped. */
HPI_ERROR_NO_INTERDSP_GROUPS = 315,
+ /** Stream wait cancelled before threshold reached. */
+ HPI_ERROR_WAIT_CANCELLED = 316,
/** Invalid mixer node for this adapter. */
HPI_ERROR_INVALID_NODE = 400,
@@ -1017,6 +1027,7 @@ enum HPI_ERROR_CODES {
HPI_ERROR_CONTROL_DISABLED = 404,
/** I2C transaction failed due to a missing ACK. */
HPI_ERROR_CONTROL_I2C_MISSING_ACK = 405,
+ HPI_ERROR_I2C_MISSING_ACK = 405,
/** Control is busy, or coming out of
reset and cannot be accessed at this time. */
HPI_ERROR_CONTROL_NOT_READY = 407,
@@ -1027,7 +1038,6 @@ enum HPI_ERROR_CODES {
HPI_ERROR_NVMEM_FAIL = 452,
/** I2C */
- HPI_ERROR_I2C_MISSING_ACK = HPI_ERROR_CONTROL_I2C_MISSING_ACK,
HPI_ERROR_I2C_BAD_ADR = 460,
/** Entity errors */
@@ -1035,6 +1045,7 @@ enum HPI_ERROR_CODES {
HPI_ERROR_ENTITY_ITEM_COUNT = 471,
HPI_ERROR_ENTITY_TYPE_INVALID = 472,
HPI_ERROR_ENTITY_ROLE_INVALID = 473,
+ HPI_ERROR_ENTITY_SIZE_MISMATCH = 474,
/* AES18 specific errors were 500..507 */
@@ -1044,11 +1055,18 @@ enum HPI_ERROR_CODES {
/** hpioct32.c can't obtain mutex */
HPI_ERROR_MUTEX_TIMEOUT = 700,
- /** errors from HPI backends have values >= this */
+ /** Backend errors used to be greater than this.
+ \deprecated Now, all backends return only errors defined here in hpi.h
+ */
HPI_ERROR_BACKEND_BASE = 900,
- /** indicates a cached u16 value is invalid. */
- HPI_ERROR_ILLEGAL_CACHE_VALUE = 0xffff
+ /** Communication with DSP failed */
+ HPI_ERROR_DSP_COMMUNICATION = 900
+ /* Note that the dsp communication error is set to this value so that
+ it remains compatible with any software that expects such errors
+ to be backend errors i.e. >= 900.
+ Do not define any new error codes with values > 900.
+ */
};
/** \defgroup maximums HPI maximum values
@@ -1075,7 +1093,7 @@ enum HPI_ERROR_CODES {
/**\}*/
-/* ////////////////////////////////////////////////////////////////////// */
+/**************/
/* STRUCTURES */
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(push, 1)
@@ -1092,7 +1110,7 @@ struct hpi_format {
/**< Stereo/JointStereo/Mono */
u16 mode_legacy;
/**< Legacy ancillary mode or idle bit */
- u16 unused; /**< unused */
+ u16 unused; /**< Unused */
u16 channels; /**< 1,2..., (or ancillary mode or idle bit */
u16 format; /**< HPI_FORMAT_PCM16, _MPEG etc. see #HPI_FORMATS. */
};
@@ -1106,930 +1124,594 @@ struct hpi_anc_frame {
*/
struct hpi_async_event {
u16 event_type; /**< type of event. \sa async_event */
- u16 sequence; /**< sequence number, allows lost event detection */
- u32 state; /**< new state */
- u32 h_object; /**< handle to the object returning the event. */
+ u16 sequence; /**< Sequence number, allows lost event detection */
+ u32 state; /**< New state */
+ u32 h_object; /**< handle to the object returning the event. */
union {
struct {
u16 index; /**< GPIO bit index. */
} gpio;
struct {
u16 node_index; /**< what node is the control on ? */
- u16 node_type; /**< what type of node is the control on ? */
+ u16 node_type; /**< what type of node is the control on ? */
} control;
} u;
};
-/*/////////////////////////////////////////////////////////////////////////// */
-/* Public HPI Entity related definitions */
-
-struct hpi_entity;
-
-enum e_entity_type {
- entity_type_null,
- entity_type_sequence, /* sequence of potentially heterogeneous TLV entities */
-
- entity_type_reference, /* refers to a TLV entity or NULL */
-
- entity_type_int, /* 32 bit */
- entity_type_float, /* ieee754 binary 32 bit encoding */
- entity_type_double,
-
- entity_type_cstring,
- entity_type_octet,
- entity_type_ip4_address,
- entity_type_ip6_address,
- entity_type_mac_address,
-
- LAST_ENTITY_TYPE
-};
-
-enum e_entity_role {
- entity_role_null,
- entity_role_value,
- entity_role_classname,
-
- entity_role_units,
- entity_role_flags,
- entity_role_range,
-
- entity_role_mapping,
- entity_role_enum,
-
- entity_role_instance_of,
- entity_role_depends_on,
- entity_role_member_of_group,
- entity_role_value_constraint,
- entity_role_parameter_port,
-
- entity_role_block,
- entity_role_node_group,
- entity_role_audio_port,
- entity_role_clock_port,
- LAST_ENTITY_ROLE
-};
-
/* skip host side function declarations for
DSP compile and documentation extraction */
-struct hpi_hsubsys {
- int not_really_used;
-};
-
#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(pop)
#endif
-/*////////////////////////////////////////////////////////////////////////// */
+/*****************/
/* HPI FUNCTIONS */
+/*****************/
-/*/////////////////////////// */
-/* DATA and FORMAT and STREAM */
-
+/* Stream */
u16 hpi_stream_estimate_buffer_size(struct hpi_format *pF,
u32 host_polling_rate_in_milli_seconds, u32 *recommended_buffer_size);
-/*/////////// */
-/* SUB SYSTEM */
-struct hpi_hsubsys *hpi_subsys_create(void
- );
-
-void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys);
-
-u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys,
- u32 *pversion);
-
-u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys,
- u32 *pversion_ex);
-
-u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion,
- u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length);
-
-u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys,
- u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length);
-
-u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys,
- int *pn_num_adapters);
-
-u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator,
- u32 *padapter_index, u16 *pw_adapter_type);
-
-u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass);
+/*************/
+/* SubSystem */
+/*************/
-u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys,
- const char *sz_interface);
+u16 hpi_subsys_get_version_ex(u32 *pversion_ex);
-/*///////// */
-/* ADAPTER */
+u16 hpi_subsys_get_num_adapters(int *pn_num_adapters);
-u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index);
+u16 hpi_subsys_get_adapter(int iterator, u32 *padapter_index,
+ u16 *pw_adapter_type);
-u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index);
+/***********/
+/* Adapter */
+/***********/
-u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams,
- u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type);
+u16 hpi_adapter_open(u16 adapter_index);
-u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 module_index, u16 *pw_num_outputs,
- u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number,
- u16 *pw_module_type, u32 *ph_module);
+u16 hpi_adapter_close(u16 adapter_index);
-u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 adapter_mode);
+u16 hpi_adapter_get_info(u16 adapter_index, u16 *pw_num_outstreams,
+ u16 *pw_num_instreams, u16 *pw_version, u32 *pserial_number,
+ u16 *pw_adapter_type);
-u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 adapter_mode, u16 query_or_set);
-
-u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 *padapter_mode);
-
-u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *assert_present, char *psz_assert,
- u16 *pw_line_number);
-
-u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *assert_present, char *psz_assert,
- u32 *pline_number, u16 *pw_assert_on_dsp);
-
-u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 assert_id);
-
-u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 capability, u32 key);
-
-u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index);
-
-u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 dsp_address, char *p_bytes, int *count_bytes);
-
-u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 property, u16 paramter1, u16 paramter2);
-
-u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 property, u16 *pw_paramter1,
- u16 *pw_paramter2);
-
-u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 index, u16 what_to_enumerate,
- u16 property_index, u32 *psetting);
-
-/*////////////// */
-/* NonVol Memory */
-u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_nv_memory, u16 *pw_size_in_bytes);
-
-u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys,
- u32 h_nv_memory, u16 index, u16 *pw_data);
-
-u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys,
- u32 h_nv_memory, u16 index, u16 data);
-
-/*////////////// */
-/* Digital I/O */
-u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits);
-
-u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 bit_index, u16 *pw_bit_data);
-
-u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 aw_all_bit_data[4]
- );
+u16 hpi_adapter_get_module_by_index(u16 adapter_index, u16 module_index,
+ u16 *pw_num_outputs, u16 *pw_num_inputs, u16 *pw_version,
+ u32 *pserial_number, u16 *pw_module_type, u32 *ph_module);
-u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 bit_index, u16 bit_data);
+u16 hpi_adapter_set_mode(u16 adapter_index, u32 adapter_mode);
-u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 aw_all_bit_data[4]
- );
+u16 hpi_adapter_set_mode_ex(u16 adapter_index, u32 adapter_mode,
+ u16 query_or_set);
-/**********************/
-/* Async Event Object */
-/**********************/
-u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 *ph_async);
+u16 hpi_adapter_get_mode(u16 adapter_index, u32 *padapter_mode);
-u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async);
+u16 hpi_adapter_get_assert2(u16 adapter_index, u16 *p_assert_count,
+ char *psz_assert, u32 *p_param1, u32 *p_param2,
+ u32 *p_dsp_string_addr, u16 *p_processor_id);
-u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
- u16 maximum_events, struct hpi_async_event *p_events,
- u16 *pw_number_returned);
+u16 hpi_adapter_test_assert(u16 adapter_index, u16 assert_id);
-u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys,
- u32 h_async, u16 *pw_count);
+u16 hpi_adapter_enable_capability(u16 adapter_index, u16 capability, u32 key);
-u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async,
- u16 maximum_events, struct hpi_async_event *p_events,
- u16 *pw_number_returned);
+u16 hpi_adapter_self_test(u16 adapter_index);
-/*/////////// */
-/* WATCH-DOG */
-u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_watchdog);
+u16 hpi_adapter_debug_read(u16 adapter_index, u32 dsp_address, char *p_bytes,
+ int *count_bytes);
-u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog,
- u32 time_millisec);
+u16 hpi_adapter_set_property(u16 adapter_index, u16 property, u16 paramter1,
+ u16 paramter2);
-u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog);
+u16 hpi_adapter_get_property(u16 adapter_index, u16 property,
+ u16 *pw_paramter1, u16 *pw_paramter2);
-/**************/
-/* OUT STREAM */
-/**************/
-u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u16 outstream_index, u32 *ph_outstream);
+u16 hpi_adapter_enumerate_property(u16 adapter_index, u16 index,
+ u16 what_to_enumerate, u16 property_index, u32 *psetting);
+/*************/
+/* OutStream */
+/*************/
+u16 hpi_outstream_open(u16 adapter_index, u16 outstream_index,
+ u32 *ph_outstream);
-u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+u16 hpi_outstream_close(u32 h_outstream);
-u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play,
- u32 *psamples_played, u32 *pauxiliary_data_to_play);
+u16 hpi_outstream_get_info_ex(u32 h_outstream, u16 *pw_state,
+ u32 *pbuffer_size, u32 *pdata_to_play, u32 *psamples_played,
+ u32 *pauxiliary_data_to_play);
-u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, const u8 *pb_write_buf, u32 bytes_to_write,
- const struct hpi_format *p_format);
+u16 hpi_outstream_write_buf(u32 h_outstream, const u8 *pb_write_buf,
+ u32 bytes_to_write, const struct hpi_format *p_format);
-u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+u16 hpi_outstream_start(u32 h_outstream);
-u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream);
+u16 hpi_outstream_wait_start(u32 h_outstream);
-u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+u16 hpi_outstream_stop(u32 h_outstream);
-u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream);
+u16 hpi_outstream_sinegen(u32 h_outstream);
-u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream);
+u16 hpi_outstream_reset(u32 h_outstream);
-u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_format *p_format);
+u16 hpi_outstream_query_format(u32 h_outstream, struct hpi_format *p_format);
-u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_format *p_format);
+u16 hpi_outstream_set_format(u32 h_outstream, struct hpi_format *p_format);
-u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample);
+u16 hpi_outstream_set_punch_in_out(u32 h_outstream, u32 punch_in_sample,
+ u32 punch_out_sample);
-u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, short velocity);
+u16 hpi_outstream_set_velocity(u32 h_outstream, short velocity);
-u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u16 mode);
+u16 hpi_outstream_ancillary_reset(u32 h_outstream, u16 mode);
-u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 *pframes_available);
+u16 hpi_outstream_ancillary_get_info(u32 h_outstream, u32 *pframes_available);
-u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer,
+u16 hpi_outstream_ancillary_read(u32 h_outstream,
+ struct hpi_anc_frame *p_anc_frame_buffer,
u32 anc_frame_buffer_size_in_bytes,
u32 number_of_ancillary_frames_to_read);
-u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 time_scaleX10000);
+u16 hpi_outstream_set_time_scale(u32 h_outstream, u32 time_scaleX10000);
-u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 size_in_bytes);
+u16 hpi_outstream_host_buffer_allocate(u32 h_outstream, u32 size_in_bytes);
-u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream);
+u16 hpi_outstream_host_buffer_free(u32 h_outstream);
-u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 h_stream);
+u16 hpi_outstream_group_add(u32 h_outstream, u32 h_stream);
-u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map);
+u16 hpi_outstream_group_get_map(u32 h_outstream, u32 *poutstream_map,
+ u32 *pinstream_map);
-u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream);
+u16 hpi_outstream_group_reset(u32 h_outstream);
-/*////////// */
-/* IN_STREAM */
-u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u16 instream_index, u32 *ph_instream);
+/************/
+/* InStream */
+/************/
+u16 hpi_instream_open(u16 adapter_index, u16 instream_index,
+ u32 *ph_instream);
-u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+u16 hpi_instream_close(u32 h_instream);
-u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_format *p_format);
+u16 hpi_instream_query_format(u32 h_instream,
+ const struct hpi_format *p_format);
-u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_format *p_format);
+u16 hpi_instream_set_format(u32 h_instream,
+ const struct hpi_format *p_format);
-u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream,
- u8 *pb_read_buf, u32 bytes_to_read);
+u16 hpi_instream_read_buf(u32 h_instream, u8 *pb_read_buf, u32 bytes_to_read);
-u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+u16 hpi_instream_start(u32 h_instream);
-u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream);
+u16 hpi_instream_wait_start(u32 h_instream);
-u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+u16 hpi_instream_stop(u32 h_instream);
-u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream);
+u16 hpi_instream_reset(u32 h_instream);
-u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded,
- u32 *psamples_recorded, u32 *pauxiliary_data_recorded);
+u16 hpi_instream_get_info_ex(u32 h_instream, u16 *pw_state, u32 *pbuffer_size,
+ u32 *pdata_recorded, u32 *psamples_recorded,
+ u32 *pauxiliary_data_recorded);
-u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment,
- u16 idle_bit);
+u16 hpi_instream_ancillary_reset(u32 h_instream, u16 bytes_per_frame,
+ u16 mode, u16 alignment, u16 idle_bit);
-u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 *pframe_space);
+u16 hpi_instream_ancillary_get_info(u32 h_instream, u32 *pframe_space);
-u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer,
+u16 hpi_instream_ancillary_write(u32 h_instream,
+ const struct hpi_anc_frame *p_anc_frame_buffer,
u32 anc_frame_buffer_size_in_bytes,
u32 number_of_ancillary_frames_to_write);
-u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 size_in_bytes);
+u16 hpi_instream_host_buffer_allocate(u32 h_instream, u32 size_in_bytes);
-u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream);
+u16 hpi_instream_host_buffer_free(u32 h_instream);
-u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 h_stream);
+u16 hpi_instream_group_add(u32 h_instream, u32 h_stream);
-u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 *poutstream_map, u32 *pinstream_map);
+u16 hpi_instream_group_get_map(u32 h_instream, u32 *poutstream_map,
+ u32 *pinstream_map);
-u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream);
+u16 hpi_instream_group_reset(u32 h_instream);
/*********/
-/* MIXER */
+/* Mixer */
/*********/
-u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_mixer);
-
-u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer);
-
-u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
- u16 src_node_type, u16 src_node_type_index, u16 dst_node_type,
- u16 dst_node_type_index, u16 control_type, u32 *ph_control);
-
-u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_mixer, u16 control_index, u16 *pw_src_node_type,
- u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index,
- u16 *pw_control_type, u32 *ph_control);
-
-u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
- enum HPI_MIXER_STORE_COMMAND command, u16 index);
-/*************************/
-/* mixer CONTROLS */
-/*************************/
-/*************************/
-/* volume control */
-/*************************/
-u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB[HPI_MAX_CHANNELS]
+u16 hpi_mixer_open(u16 adapter_index, u32 *ph_mixer);
+
+u16 hpi_mixer_close(u32 h_mixer);
+
+u16 hpi_mixer_get_control(u32 h_mixer, u16 src_node_type,
+ u16 src_node_type_index, u16 dst_node_type, u16 dst_node_type_index,
+ u16 control_type, u32 *ph_control);
+
+u16 hpi_mixer_get_control_by_index(u32 h_mixer, u16 control_index,
+ u16 *pw_src_node_type, u16 *pw_src_node_index, u16 *pw_dst_node_type,
+ u16 *pw_dst_node_index, u16 *pw_control_type, u32 *ph_control);
+
+u16 hpi_mixer_store(u32 h_mixer, enum HPI_MIXER_STORE_COMMAND command,
+ u16 index);
+/************/
+/* Controls */
+/************/
+/******************/
+/* Volume control */
+/******************/
+u16 hpi_volume_set_gain(u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS]
);
-u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+u16 hpi_volume_get_gain(u32 h_control,
short an_gain0_01dB_out[HPI_MAX_CHANNELS]
);
+u16 hpi_volume_set_mute(u32 h_control, u32 mute);
+
+u16 hpi_volume_get_mute(u32 h_control, u32 *mute);
+
#define hpi_volume_get_range hpi_volume_query_range
-u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB);
+u16 hpi_volume_query_range(u32 h_control, short *min_gain_01dB,
+ short *max_gain_01dB, short *step_gain_01dB);
-u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
- const u32 h_volume, u32 *p_channels);
+u16 hpi_volume_query_channels(const u32 h_volume, u32 *p_channels);
-u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+u16 hpi_volume_auto_fade(u32 h_control,
short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms);
-u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS],
- u32 duration_ms, u16 profile);
+u16 hpi_volume_auto_fade_profile(u32 h_control,
+ short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms,
+ u16 profile);
-/*************************/
-/* level control */
-/*************************/
-u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB);
+/*****************/
+/* Level control */
+/*****************/
+u16 hpi_level_query_range(u32 h_control, short *min_gain_01dB,
+ short *max_gain_01dB, short *step_gain_01dB);
-u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB[HPI_MAX_CHANNELS]
+u16 hpi_level_set_gain(u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS]
);
-u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+u16 hpi_level_get_gain(u32 h_control,
short an_gain0_01dB_out[HPI_MAX_CHANNELS]
);
-/*************************/
-/* meter control */
-/*************************/
-u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
- const u32 h_meter, u32 *p_channels);
+/*****************/
+/* Meter control */
+/*****************/
+u16 hpi_meter_query_channels(const u32 h_meter, u32 *p_channels);
-u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+u16 hpi_meter_get_peak(u32 h_control,
short an_peak0_01dB_out[HPI_MAX_CHANNELS]
);
-u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_peak0_01dB_out[HPI_MAX_CHANNELS]
+u16 hpi_meter_get_rms(u32 h_control, short an_peak0_01dB_out[HPI_MAX_CHANNELS]
);
-u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 attack, u16 decay);
+u16 hpi_meter_set_peak_ballistics(u32 h_control, u16 attack, u16 decay);
-u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 attack, u16 decay);
+u16 hpi_meter_set_rms_ballistics(u32 h_control, u16 attack, u16 decay);
-u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *attack, u16 *decay);
+u16 hpi_meter_get_peak_ballistics(u32 h_control, u16 *attack, u16 *decay);
-u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *attack, u16 *decay);
+u16 hpi_meter_get_rms_ballistics(u32 h_control, u16 *attack, u16 *decay);
-/*************************/
-/* channel mode control */
-/*************************/
-u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys,
- const u32 h_mode, const u32 index, u16 *pw_mode);
+/************************/
+/* ChannelMode control */
+/************************/
+u16 hpi_channel_mode_query_mode(const u32 h_mode, const u32 index,
+ u16 *pw_mode);
-u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 mode);
+u16 hpi_channel_mode_set(u32 h_control, u16 mode);
-u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *mode);
+u16 hpi_channel_mode_get(u32 h_control, u16 *mode);
-/*************************/
-/* Tuner control */
-/*************************/
-u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, u16 *pw_band);
+/*****************/
+/* Tuner control */
+/*****************/
+u16 hpi_tuner_query_band(const u32 h_tuner, const u32 index, u16 *pw_band);
-u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 band);
+u16 hpi_tuner_set_band(u32 h_control, u16 band);
-u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_band);
+u16 hpi_tuner_get_band(u32 h_control, u16 *pw_band);
-u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq);
+u16 hpi_tuner_query_frequency(const u32 h_tuner, const u32 index,
+ const u16 band, u32 *pfreq);
-u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 freq_ink_hz);
+u16 hpi_tuner_set_frequency(u32 h_control, u32 freq_ink_hz);
-u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pw_freq_ink_hz);
+u16 hpi_tuner_get_frequency(u32 h_control, u32 *pw_freq_ink_hz);
-u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *pw_level);
+u16 hpi_tuner_get_rf_level(u32 h_control, short *pw_level);
-u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short *pw_level);
+u16 hpi_tuner_get_raw_rf_level(u32 h_control, short *pw_level);
-u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, u16 *pw_gain);
+u16 hpi_tuner_query_gain(const u32 h_tuner, const u32 index, u16 *pw_gain);
-u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short gain);
+u16 hpi_tuner_set_gain(u32 h_control, short gain);
-u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *pn_gain);
+u16 hpi_tuner_get_gain(u32 h_control, short *pn_gain);
-u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_status_mask, u16 *pw_status);
+u16 hpi_tuner_get_status(u32 h_control, u16 *pw_status_mask, u16 *pw_status);
-u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 mode, u32 value);
+u16 hpi_tuner_set_mode(u32 h_control, u32 mode, u32 value);
-u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 mode, u32 *pn_value);
+u16 hpi_tuner_get_mode(u32 h_control, u32 mode, u32 *pn_value);
-u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *p_rds_data);
+u16 hpi_tuner_get_rds(u32 h_control, char *p_rds_data);
-u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis);
+u16 hpi_tuner_query_deemphasis(const u32 h_tuner, const u32 index,
+ const u16 band, u32 *pdeemphasis);
-u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 deemphasis);
-u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pdeemphasis);
+u16 hpi_tuner_set_deemphasis(u32 h_control, u32 deemphasis);
+u16 hpi_tuner_get_deemphasis(u32 h_control, u32 *pdeemphasis);
-u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, u32 *pbitmap_program);
+u16 hpi_tuner_query_program(const u32 h_tuner, u32 *pbitmap_program);
-u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 program);
+u16 hpi_tuner_set_program(u32 h_control, u32 program);
-u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 *pprogram);
+u16 hpi_tuner_get_program(u32 h_control, u32 *pprogram);
-u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_dsp_version, const u32 string_size);
+u16 hpi_tuner_get_hd_radio_dsp_version(u32 h_control, char *psz_dsp_version,
+ const u32 string_size);
-u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_sdk_version, const u32 string_size);
+u16 hpi_tuner_get_hd_radio_sdk_version(u32 h_control, char *psz_sdk_version,
+ const u32 string_size);
-u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pquality);
+u16 hpi_tuner_get_hd_radio_signal_quality(u32 h_control, u32 *pquality);
-u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pblend);
+u16 hpi_tuner_get_hd_radio_signal_blend(u32 h_control, u32 *pblend);
-u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, const u32 blend);
+u16 hpi_tuner_set_hd_radio_signal_blend(u32 h_control, const u32 blend);
-/****************************/
-/* PADs control */
-/****************************/
+/***************/
+/* PAD control */
+/***************/
-u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_string, const u32 string_length);
+u16 hpi_pad_get_channel_name(u32 h_control, char *psz_string,
+ const u32 string_length);
-u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 string_length);
+u16 hpi_pad_get_artist(u32 h_control, char *psz_string,
+ const u32 string_length);
-u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 string_length);
+u16 hpi_pad_get_title(u32 h_control, char *psz_string,
+ const u32 string_length);
-u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 string_length);
+u16 hpi_pad_get_comment(u32 h_control, char *psz_string,
+ const u32 string_length);
-u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *ppTY);
+u16 hpi_pad_get_program_type(u32 h_control, u32 *ppTY);
-u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 *ppI);
+u16 hpi_pad_get_rdsPI(u32 h_control, u32 *ppI);
-u16 HPI_PAD__get_program_type_string(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, const u32 data_type, const u32 pTY, char *psz_string,
- const u32 string_length);
+u16 hpi_pad_get_program_type_string(u32 h_control, const u32 data_type,
+ const u32 pTY, char *psz_string, const u32 string_length);
/****************************/
/* AES/EBU Receiver control */
/****************************/
-u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys,
- const u32 h_aes_rx, const u32 index, u16 *pw_format);
+u16 hpi_aesebu_receiver_query_format(const u32 h_aes_rx, const u32 index,
+ u16 *pw_format);
-u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source);
+u16 hpi_aesebu_receiver_set_format(u32 h_control, u16 source);
-u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_source);
+u16 hpi_aesebu_receiver_get_format(u32 h_control, u16 *pw_source);
-u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate);
+u16 hpi_aesebu_receiver_get_sample_rate(u32 h_control, u32 *psample_rate);
-u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *pw_data);
+u16 hpi_aesebu_receiver_get_user_data(u32 h_control, u16 index, u16 *pw_data);
-u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 *pw_data);
+u16 hpi_aesebu_receiver_get_channel_status(u32 h_control, u16 index,
+ u16 *pw_data);
-u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_error_data);
+u16 hpi_aesebu_receiver_get_error_status(u32 h_control, u16 *pw_error_data);
/*******************************/
/* AES/EBU Transmitter control */
/*******************************/
-u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u32 sample_rate);
+u16 hpi_aesebu_transmitter_set_sample_rate(u32 h_control, u32 sample_rate);
-u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 data);
+u16 hpi_aesebu_transmitter_set_user_data(u32 h_control, u16 index, u16 data);
-u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 data);
+u16 hpi_aesebu_transmitter_set_channel_status(u32 h_control, u16 index,
+ u16 data);
-u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 *pw_data);
+u16 hpi_aesebu_transmitter_get_channel_status(u32 h_control, u16 index,
+ u16 *pw_data);
-u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys,
- const u32 h_aes_tx, const u32 index, u16 *pw_format);
+u16 hpi_aesebu_transmitter_query_format(const u32 h_aes_tx, const u32 index,
+ u16 *pw_format);
-u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 output_format);
+u16 hpi_aesebu_transmitter_set_format(u32 h_control, u16 output_format);
-u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_output_format);
+u16 hpi_aesebu_transmitter_get_format(u32 h_control, u16 *pw_output_format);
/***********************/
-/* multiplexer control */
+/* Multiplexer control */
/***********************/
-u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source_node_type, u16 source_node_index);
-
-u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *source_node_type, u16 *source_node_index);
+u16 hpi_multiplexer_set_source(u32 h_control, u16 source_node_type,
+ u16 source_node_index);
-u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *source_node_type,
+u16 hpi_multiplexer_get_source(u32 h_control, u16 *source_node_type,
u16 *source_node_index);
+u16 hpi_multiplexer_query_source(u32 h_control, u16 index,
+ u16 *source_node_type, u16 *source_node_index);
+
/***************/
-/* VOX control */
+/* Vox control */
/***************/
-u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB);
+u16 hpi_vox_set_threshold(u32 h_control, short an_gain0_01dB);
-u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *an_gain0_01dB);
+u16 hpi_vox_get_threshold(u32 h_control, short *an_gain0_01dB);
/*********************/
/* Bitstream control */
/*********************/
-u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 edge_type);
+u16 hpi_bitstream_set_clock_edge(u32 h_control, u16 edge_type);
-u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 polarity);
+u16 hpi_bitstream_set_data_polarity(u32 h_control, u16 polarity);
-u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity);
+u16 hpi_bitstream_get_activity(u32 h_control, u16 *pw_clk_activity,
+ u16 *pw_data_activity);
/***********************/
/* SampleClock control */
/***********************/
-u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, u16 *pw_source);
+u16 hpi_sample_clock_query_source(const u32 h_clock, const u32 index,
+ u16 *pw_source);
-u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source);
+u16 hpi_sample_clock_set_source(u32 h_control, u16 source);
-u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_source);
+u16 hpi_sample_clock_get_source(u32 h_control, u16 *pw_source);
-u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, const u32 source,
- u16 *pw_source_index);
+u16 hpi_sample_clock_query_source_index(const u32 h_clock, const u32 index,
+ const u32 source, u16 *pw_source_index);
-u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source_index);
+u16 hpi_sample_clock_set_source_index(u32 h_control, u16 source_index);
-u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_source_index);
+u16 hpi_sample_clock_get_source_index(u32 h_control, u16 *pw_source_index);
-u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate);
+u16 hpi_sample_clock_get_sample_rate(u32 h_control, u32 *psample_rate);
-u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, u32 *psource);
+u16 hpi_sample_clock_query_local_rate(const u32 h_clock, const u32 index,
+ u32 *psource);
-u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 sample_rate);
+u16 hpi_sample_clock_set_local_rate(u32 h_control, u32 sample_rate);
-u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate);
+u16 hpi_sample_clock_get_local_rate(u32 h_control, u32 *psample_rate);
-u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 enable);
+u16 hpi_sample_clock_set_auto(u32 h_control, u32 enable);
-u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *penable);
+u16 hpi_sample_clock_get_auto(u32 h_control, u32 *penable);
-u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 lock);
+u16 hpi_sample_clock_set_local_rate_lock(u32 h_control, u32 lock);
-u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *plock);
+u16 hpi_sample_clock_get_local_rate_lock(u32 h_control, u32 *plock);
/***********************/
/* Microphone control */
/***********************/
-u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 on_off);
+u16 hpi_microphone_set_phantom_power(u32 h_control, u16 on_off);
-u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_on_off);
+u16 hpi_microphone_get_phantom_power(u32 h_control, u16 *pw_on_off);
-/*******************************
- Parametric Equalizer control
-*******************************/
-u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_number_of_bands, u16 *pw_enabled);
+/********************************/
+/* Parametric Equalizer control */
+/********************************/
+u16 hpi_parametric_eq_get_info(u32 h_control, u16 *pw_number_of_bands,
+ u16 *pw_enabled);
-u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 on_off);
+u16 hpi_parametric_eq_set_state(u32 h_control, u16 on_off);
-u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100,
- short gain0_01dB);
+u16 hpi_parametric_eq_set_band(u32 h_control, u16 index, u16 type,
+ u32 frequency_hz, short q100, short gain0_01dB);
-u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz,
- short *pnQ100, short *pn_gain0_01dB);
+u16 hpi_parametric_eq_get_band(u32 h_control, u16 index, u16 *pn_type,
+ u32 *pfrequency_hz, short *pnQ100, short *pn_gain0_01dB);
-u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, short coeffs[5]
+u16 hpi_parametric_eq_get_coeffs(u32 h_control, u16 index, short coeffs[5]
);
-/*******************************
- Compressor Expander control
-*******************************/
-
-u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 on);
-
-u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pon);
-
-u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short makeup_gain0_01dB);
-
-u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short *pn_makeup_gain0_01dB);
-
-u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u32 index, u32 attack);
-
-u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u32 index, u32 *pw_attack);
-
-u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 decay);
-
-u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 *pw_decay);
-
-u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, short threshold0_01dB);
-
-u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, short *pn_threshold0_01dB);
-
-u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 ratio100);
-
-u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 *pw_ratio100);
-
-/*******************************
- Cobranet HMI control
-*******************************/
-u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 hmi_address, u32 byte_count, u8 *pb_data);
-
-u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data);
-
-u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pstatus, u32 *preadable_size,
- u32 *pwriteable_size);
-
-/*Read the current IP address
-*/
-u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pi_paddress);
-
-/* Write the current IP address
-*/
-u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 i_paddress);
-
-/* Read the static IP address
-*/
-u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pi_paddress);
+/*******************************/
+/* Compressor Expander control */
+/*******************************/
-/* Write the static IP address
-*/
-u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 i_paddress);
+u16 hpi_compander_set_enable(u32 h_control, u32 on);
-/* Read the MAC address
-*/
-u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs);
+u16 hpi_compander_get_enable(u32 h_control, u32 *pon);
-/*******************************
- Tone Detector control
-*******************************/
-u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys, u32 hC,
- u32 *state);
+u16 hpi_compander_set_makeup_gain(u32 h_control, short makeup_gain0_01dB);
-u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys, u32 hC,
- u32 enable);
+u16 hpi_compander_get_makeup_gain(u32 h_control, short *pn_makeup_gain0_01dB);
-u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys, u32 hC,
- u32 *enable);
+u16 hpi_compander_set_attack_time_constant(u32 h_control, u32 index,
+ u32 attack);
-u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 event_enable);
+u16 hpi_compander_get_attack_time_constant(u32 h_control, u32 index,
+ u32 *pw_attack);
-u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 *event_enable);
+u16 hpi_compander_set_decay_time_constant(u32 h_control, u32 index,
+ u32 decay);
-u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 hC, int threshold);
+u16 hpi_compander_get_decay_time_constant(u32 h_control, u32 index,
+ u32 *pw_decay);
-u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 hC, int *threshold);
+u16 hpi_compander_set_threshold(u32 h_control, u32 index,
+ short threshold0_01dB);
-u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 index, u32 *frequency);
+u16 hpi_compander_get_threshold(u32 h_control, u32 index,
+ short *pn_threshold0_01dB);
-/*******************************
- Silence Detector control
-*******************************/
-u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 *state);
+u16 hpi_compander_set_ratio(u32 h_control, u32 index, u32 ratio100);
-u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 enable);
+u16 hpi_compander_get_ratio(u32 h_control, u32 index, u32 *pw_ratio100);
-u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 *enable);
+/********************/
+/* Cobranet control */
+/********************/
+u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count,
+ u8 *pb_data);
-u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 event_enable);
+u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count,
+ u32 *pbyte_count, u8 *pb_data);
-u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 *event_enable);
+u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
+ u32 *preadable_size, u32 *pwriteable_size);
-u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 delay);
+u16 hpi_cobranet_get_ip_address(u32 h_control, u32 *pdw_ip_address);
-u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
- u32 hC, u32 *delay);
+u16 hpi_cobranet_set_ip_address(u32 h_control, u32 dw_ip_address);
-u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 hC, int threshold);
+u16 hpi_cobranet_get_static_ip_address(u32 h_control, u32 *pdw_ip_address);
-u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 hC, int *threshold);
+u16 hpi_cobranet_set_static_ip_address(u32 h_control, u32 dw_ip_address);
-/*******************************
- Universal control
-*******************************/
-u16 hpi_entity_find_next(struct hpi_entity *container_entity,
- enum e_entity_type type, enum e_entity_role role, int recursive_flag,
- struct hpi_entity **current_match);
+u16 hpi_cobranet_get_macaddress(u32 h_control, u32 *p_mac_msbs,
+ u32 *p_mac_lsbs);
-u16 hpi_entity_copy_value_from(struct hpi_entity *entity,
- enum e_entity_type type, size_t item_count, void *value_dst_p);
+/*************************/
+/* Tone Detector control */
+/*************************/
+u16 hpi_tone_detector_get_state(u32 hC, u32 *state);
-u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type,
- size_t *items, enum e_entity_role *role, void **value);
+u16 hpi_tone_detector_set_enable(u32 hC, u32 enable);
-u16 hpi_entity_alloc_and_pack(const enum e_entity_type type,
- const size_t item_count, const enum e_entity_role role, void *value,
- struct hpi_entity **entity);
+u16 hpi_tone_detector_get_enable(u32 hC, u32 *enable);
-void hpi_entity_free(struct hpi_entity *entity);
+u16 hpi_tone_detector_set_event_enable(u32 hC, u32 event_enable);
-u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity **info);
+u16 hpi_tone_detector_get_event_enable(u32 hC, u32 *event_enable);
-u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity **value);
+u16 hpi_tone_detector_set_threshold(u32 hC, int threshold);
-u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity *value);
+u16 hpi_tone_detector_get_threshold(u32 hC, int *threshold);
-/*/////////// */
-/* DSP CLOCK */
-/*/////////// */
-u16 hpi_clock_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_dsp_clock);
+u16 hpi_tone_detector_get_frequency(u32 hC, u32 index, u32 *frequency);
-u16 hpi_clock_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock,
- u16 hour, u16 minute, u16 second, u16 milli_second);
+/****************************/
+/* Silence Detector control */
+/****************************/
+u16 hpi_silence_detector_get_state(u32 hC, u32 *state);
-u16 hpi_clock_get_time(const struct hpi_hsubsys *ph_subsys, u32 h_clock,
- u16 *pw_hour, u16 *pw_minute, u16 *pw_second, u16 *pw_milli_second);
+u16 hpi_silence_detector_set_enable(u32 hC, u32 enable);
-/*/////////// */
-/* PROFILE */
-/*/////////// */
-u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 profile_index, u32 *ph_profile,
- u16 *pw_max_profiles);
+u16 hpi_silence_detector_get_enable(u32 hC, u32 *enable);
-u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
- u16 index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count,
- u32 *pmax_micro_seconds, u32 *pmin_micro_seconds);
+u16 hpi_silence_detector_set_event_enable(u32 hC, u32 event_enable);
-u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile);
+u16 hpi_silence_detector_get_event_enable(u32 hC, u32 *event_enable);
-u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile);
+u16 hpi_silence_detector_set_delay(u32 hC, u32 delay);
-u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
- u16 index, char *sz_profile_name, u16 profile_name_length);
+u16 hpi_silence_detector_get_delay(u32 hC, u32 *delay);
-u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys,
- u32 h_profile, u32 *putilization);
+u16 hpi_silence_detector_set_threshold(u32 hC, int threshold);
-/*//////////////////// */
-/* UTILITY functions */
+u16 hpi_silence_detector_get_threshold(u32 hC, int *threshold);
+/*********************/
+/* Utility functions */
+/*********************/
u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
u32 sample_rate, u32 bit_rate, u32 attributes);
-/* Until it's verified, this function is for Windows OSs only */
-
-#endif /*_H_HPI_ */
-/*
-///////////////////////////////////////////////////////////////////////////////
-// See CVS for history. Last complete set in rev 1.146
-////////////////////////////////////////////////////////////////////////////////
-*/
+#endif /*_HPI_H_ */
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 1b9bf9395cfe..3e3c2ef6efd8 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -43,16 +43,17 @@
#define HPI_HIF_ERROR_MASK 0x4000
/* HPI6000 specific error codes */
+#define HPI6000_ERROR_BASE 900 /* not actually used anywhere */
-#define HPI6000_ERROR_BASE 900
+/* operational/messaging errors */
#define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901
-#define HPI6000_ERROR_MSG_RESP_SEND_MSG_ACK 902
+
#define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903
#define HPI6000_ERROR_MSG_GET_ADR 904
#define HPI6000_ERROR_RESP_GET_ADR 905
#define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32 906
#define HPI6000_ERROR_MSG_RESP_BLOCKREAD32 907
-#define HPI6000_ERROR_MSG_INVALID_DSP_INDEX 908
+
#define HPI6000_ERROR_CONTROL_CACHE_PARAMS 909
#define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT 911
@@ -62,7 +63,6 @@
#define HPI6000_ERROR_SEND_DATA_CMD 915
#define HPI6000_ERROR_SEND_DATA_WRITE 916
#define HPI6000_ERROR_SEND_DATA_IDLECMD 917
-#define HPI6000_ERROR_SEND_DATA_VERIFY 918
#define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT 921
#define HPI6000_ERROR_GET_DATA_ACK 922
@@ -76,9 +76,8 @@
#define HPI6000_ERROR_MSG_RESP_GETRESPCMD 961
#define HPI6000_ERROR_MSG_RESP_IDLECMD 962
-#define HPI6000_ERROR_MSG_RESP_BLOCKVERIFY32 963
-/* adapter init errors */
+/* Initialisation/bootload errors */
#define HPI6000_ERROR_UNHANDLED_SUBSYS_ID 930
/* can't access PCI2040 */
@@ -210,6 +209,8 @@ static void adapter_get_asserts(struct hpi_adapter_obj *pao,
static short create_adapter_obj(struct hpi_adapter_obj *pao,
u32 *pos_error_code);
+static void delete_adapter_obj(struct hpi_adapter_obj *pao);
+
/* local globals */
static u16 gw_pci_read_asserts; /* used to count PCI2040 errors */
@@ -217,17 +218,7 @@ static u16 gw_pci_write_asserts; /* used to count PCI2040 errors */
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
{
-
switch (phm->function) {
- case HPI_SUBSYS_OPEN:
- case HPI_SUBSYS_CLOSE:
- case HPI_SUBSYS_GET_INFO:
- case HPI_SUBSYS_DRIVER_UNLOAD:
- case HPI_SUBSYS_DRIVER_LOAD:
- case HPI_SUBSYS_FIND_ADAPTERS:
- /* messages that should not get here */
- phr->error = HPI_ERROR_UNIMPLEMENTED;
- break;
case HPI_SUBSYS_CREATE_ADAPTER:
subsys_create_adapter(phm, phr);
break;
@@ -243,7 +234,6 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
static void control_message(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
-
switch (phm->function) {
case HPI_CONTROL_GET_STATE:
if (pao->has_control_cache) {
@@ -251,7 +241,13 @@ static void control_message(struct hpi_adapter_obj *pao,
err = hpi6000_update_control_cache(pao, phm);
if (err) {
- phr->error = err;
+ if (err >= HPI_ERROR_BACKEND_BASE) {
+ phr->error =
+ HPI_ERROR_CONTROL_CACHING;
+ phr->specific_error = err;
+ } else {
+ phr->error = err;
+ }
break;
}
@@ -262,16 +258,15 @@ static void control_message(struct hpi_adapter_obj *pao,
}
hw_message(pao, phm, phr);
break;
- case HPI_CONTROL_GET_INFO:
- hw_message(pao, phm, phr);
- break;
case HPI_CONTROL_SET_STATE:
hw_message(pao, phm, phr);
- hpi_sync_control_cache(((struct hpi_hw_obj *)pao->priv)->
- p_cache, phm, phr);
+ hpi_cmn_control_cache_sync_to_msg(((struct hpi_hw_obj *)pao->
+ priv)->p_cache, phm, phr);
break;
+
+ case HPI_CONTROL_GET_INFO:
default:
- phr->error = HPI_ERROR_INVALID_FUNC;
+ hw_message(pao, phm, phr);
break;
}
}
@@ -280,26 +275,12 @@ static void adapter_message(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
switch (phm->function) {
- case HPI_ADAPTER_GET_INFO:
- hw_message(pao, phm, phr);
- break;
case HPI_ADAPTER_GET_ASSERT:
adapter_get_asserts(pao, phm, phr);
break;
- case HPI_ADAPTER_OPEN:
- case HPI_ADAPTER_CLOSE:
- case HPI_ADAPTER_TEST_ASSERT:
- case HPI_ADAPTER_SELFTEST:
- case HPI_ADAPTER_GET_MODE:
- case HPI_ADAPTER_SET_MODE:
- case HPI_ADAPTER_FIND_OBJECT:
- case HPI_ADAPTER_GET_PROPERTY:
- case HPI_ADAPTER_SET_PROPERTY:
- case HPI_ADAPTER_ENUM_PROPERTY:
- hw_message(pao, phm, phr);
- break;
+
default:
- phr->error = HPI_ERROR_INVALID_FUNC;
+ hw_message(pao, phm, phr);
break;
}
}
@@ -311,7 +292,7 @@ static void outstream_message(struct hpi_adapter_obj *pao,
case HPI_OSTREAM_HOSTBUFFER_ALLOC:
case HPI_OSTREAM_HOSTBUFFER_FREE:
/* Don't let these messages go to the HW function because
- * they're called without allocating the spinlock.
+ * they're called without locking the spinlock.
* For the HPI6000 adapters the HW would return
* HPI_ERROR_INVALID_FUNC anyway.
*/
@@ -331,7 +312,7 @@ static void instream_message(struct hpi_adapter_obj *pao,
case HPI_ISTREAM_HOSTBUFFER_ALLOC:
case HPI_ISTREAM_HOSTBUFFER_FREE:
/* Don't let these messages go to the HW function because
- * they're called without allocating the spinlock.
+ * they're called without locking the spinlock.
* For the HPI6000 adapters the HW would return
* HPI_ERROR_INVALID_FUNC anyway.
*/
@@ -355,7 +336,7 @@ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)
/* subsytem messages get executed by every HPI. */
/* All other messages are ignored unless the adapter index matches */
/* an adapter in the HPI */
- HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->object, phm->function);
+ /*HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); */
/* if Dsp has crashed then do not communicate with it any more */
if (phm->object != HPI_OBJ_SUBSYSTEM) {
@@ -433,21 +414,13 @@ static void subsys_create_adapter(struct hpi_message *phm,
struct hpi_adapter_obj ao;
struct hpi_adapter_obj *pao;
u32 os_error_code;
- short error = 0;
+ u16 err = 0;
u32 dsp_index = 0;
HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n");
memset(&ao, 0, sizeof(ao));
- /* this HPI only creates adapters for TI/PCI2040 based devices */
- if (phm->u.s.resource.bus_type != HPI_BUS_PCI)
- return;
- if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI)
- return;
- if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_PCI2040)
- return;
-
ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
if (!ao.priv) {
HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n");
@@ -456,16 +429,19 @@ static void subsys_create_adapter(struct hpi_message *phm,
}
/* create the adapter object based on the resource information */
- /*? memcpy(&ao.Pci,&phm->u.s.Resource.r.Pci,sizeof(ao.Pci)); */
ao.pci = *phm->u.s.resource.r.pci;
- error = create_adapter_obj(&ao, &os_error_code);
- if (!error)
- error = hpi_add_adapter(&ao);
- if (error) {
+ err = create_adapter_obj(&ao, &os_error_code);
+ if (err) {
+ delete_adapter_obj(&ao);
+ if (err >= HPI_ERROR_BACKEND_BASE) {
+ phr->error = HPI_ERROR_DSP_BOOTLOAD;
+ phr->specific_error = err;
+ } else {
+ phr->error = err;
+ }
+
phr->u.s.data = os_error_code;
- kfree(ao.priv);
- phr->error = error;
return;
}
/* need to update paParentAdapter */
@@ -473,7 +449,7 @@ static void subsys_create_adapter(struct hpi_message *phm,
if (!pao) {
/* We just added this adapter, why can't we find it!? */
HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n");
- phr->error = 950;
+ phr->error = HPI_ERROR_BAD_ADAPTER;
return;
}
@@ -482,9 +458,8 @@ static void subsys_create_adapter(struct hpi_message *phm,
phw->ado[dsp_index].pa_parent_adapter = pao;
}
- phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
+ phr->u.s.adapter_type = ao.adapter_type;
phr->u.s.adapter_index = ao.index;
- phr->u.s.num_adapters++;
phr->error = 0;
}
@@ -492,20 +467,13 @@ static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_response *phr)
{
struct hpi_adapter_obj *pao = NULL;
- struct hpi_hw_obj *phw;
- pao = hpi_find_adapter(phm->adapter_index);
+ pao = hpi_find_adapter(phm->obj_index);
if (!pao)
return;
- phw = (struct hpi_hw_obj *)pao->priv;
-
- if (pao->has_control_cache)
- hpi_free_control_cache(phw->p_cache);
-
+ delete_adapter_obj(pao);
hpi_delete_adapter(pao);
- kfree(phw);
-
phr->error = 0;
}
@@ -519,9 +487,6 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
u32 control_cache_count = 0;
struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
- /* init error reporting */
- pao->dsp_crashed = 0;
-
/* The PCI2040 has the following address map */
/* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */
/* BAR1 - 32K = HPI registers on DSP */
@@ -575,36 +540,36 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
/* get info about the adapter by asking the adapter */
/* send a HPI_ADAPTER_GET_INFO message */
{
- struct hpi_message hM;
- struct hpi_response hR0; /* response from DSP 0 */
- struct hpi_response hR1; /* response from DSP 1 */
+ struct hpi_message hm;
+ struct hpi_response hr0; /* response from DSP 0 */
+ struct hpi_response hr1; /* response from DSP 1 */
u16 error = 0;
HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");
- memset(&hM, 0, sizeof(hM));
- hM.type = HPI_TYPE_MESSAGE;
- hM.size = sizeof(struct hpi_message);
- hM.object = HPI_OBJ_ADAPTER;
- hM.function = HPI_ADAPTER_GET_INFO;
- hM.adapter_index = 0;
- memset(&hR0, 0, sizeof(hR0));
- memset(&hR1, 0, sizeof(hR1));
- hR0.size = sizeof(hR0);
- hR1.size = sizeof(hR1);
-
- error = hpi6000_message_response_sequence(pao, 0, &hM, &hR0);
- if (hR0.error) {
- HPI_DEBUG_LOG(DEBUG, "message error %d\n", hR0.error);
- return hR0.error;
+ memset(&hm, 0, sizeof(hm));
+ hm.type = HPI_TYPE_MESSAGE;
+ hm.size = sizeof(struct hpi_message);
+ hm.object = HPI_OBJ_ADAPTER;
+ hm.function = HPI_ADAPTER_GET_INFO;
+ hm.adapter_index = 0;
+ memset(&hr0, 0, sizeof(hr0));
+ memset(&hr1, 0, sizeof(hr1));
+ hr0.size = sizeof(hr0);
+ hr1.size = sizeof(hr1);
+
+ error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0);
+ if (hr0.error) {
+ HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error);
+ return hr0.error;
}
if (phw->num_dsp == 2) {
- error = hpi6000_message_response_sequence(pao, 1, &hM,
- &hR1);
+ error = hpi6000_message_response_sequence(pao, 1, &hm,
+ &hr1);
if (error)
return error;
}
- pao->adapter_type = hR0.u.a.adapter_type;
- pao->index = hR0.u.a.adapter_index;
+ pao->adapter_type = hr0.u.ax.info.adapter_type;
+ pao->index = hr0.u.ax.info.adapter_index;
}
memset(&phw->control_cache[0], 0,
@@ -618,22 +583,37 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
control_cache_count =
hpi_read_word(&phw->ado[0],
HPI_HIF_ADDR(control_cache_count));
- pao->has_control_cache = 1;
phw->p_cache =
hpi_alloc_control_cache(control_cache_count,
- control_cache_size, (struct hpi_control_cache_info *)
+ control_cache_size, (unsigned char *)
&phw->control_cache[0]
);
- if (!phw->p_cache)
- pao->has_control_cache = 0;
- } else
- pao->has_control_cache = 0;
+ if (phw->p_cache)
+ pao->has_control_cache = 1;
+ }
HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n",
pao->adapter_type, pao->index);
pao->open = 0; /* upon creation the adapter is closed */
- return 0;
+
+ if (phw->p_cache)
+ phw->p_cache->adap_idx = pao->index;
+
+ return hpi_add_adapter(pao);
+}
+
+static void delete_adapter_obj(struct hpi_adapter_obj *pao)
+{
+ struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv;
+
+ if (pao->has_control_cache)
+ hpi_free_control_cache(phw->p_cache);
+
+ /* reset DSPs on adapter */
+ iowrite32(0x0003000F, phw->dw2040_HPICSR + HPI_RESET);
+
+ kfree(phw);
}
/************************************************************************/
@@ -645,11 +625,13 @@ static void adapter_get_asserts(struct hpi_adapter_obj *pao,
#ifndef HIDE_PCI_ASSERTS
/* if we have PCI2040 asserts then collect them */
if ((gw_pci_read_asserts > 0) || (gw_pci_write_asserts > 0)) {
- phr->u.a.serial_number =
+ phr->u.ax.assert.p1 =
gw_pci_read_asserts * 100 + gw_pci_write_asserts;
- phr->u.a.adapter_index = 1; /* assert count */
- phr->u.a.adapter_type = -1; /* "dsp index" */
- strcpy(phr->u.a.sz_adapter_assert, "PCI2040 error");
+ phr->u.ax.assert.p2 = 0;
+ phr->u.ax.assert.count = 1; /* assert count */
+ phr->u.ax.assert.dsp_index = -1; /* "dsp index" */
+ strcpy(phr->u.ax.assert.sz_message, "PCI2040 error");
+ phr->u.ax.assert.dsp_msg_addr = 0;
gw_pci_read_asserts = 0;
gw_pci_write_asserts = 0;
phr->error = 0;
@@ -686,10 +668,10 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
/* NOTE don't use wAdapterType in this routine. It is not setup yet */
- switch (pao->pci.subsys_device_id) {
+ switch (pao->pci.pci_dev->subsystem_device) {
case 0x5100:
case 0x5110: /* ASI5100 revB or higher with C6711D */
- case 0x5200: /* ASI5200 PC_ie version of ASI5100 */
+ case 0x5200: /* ASI5200 PCIe version of ASI5100 */
case 0x6100:
case 0x6200:
boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);
@@ -709,8 +691,9 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
* note that bits 4..15 are read-only and so should always return zero,
* even though we wrote 1 to them
*/
- for (i = 0; i < 1000; i++)
- delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+ hpios_delay_micro_seconds(1000);
+ delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+
if (delay != dw2040_reset) {
HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset,
delay);
@@ -743,8 +726,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
dw2040_reset = dw2040_reset & (~0x00000008);
iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);
/*delay to allow DSP to get going */
- for (i = 0; i < 100; i++)
- delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+ hpios_delay_micro_seconds(100);
/* loop through all DSPs, downloading DSP code */
for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) {
@@ -783,27 +765,27 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
*/
/* bypass PLL */
hpi_write_word(pdo, 0x01B7C100, 0x0000);
- for (i = 0; i < 100; i++)
- delay = ioread32(phw->dw2040_HPICSR +
- HPI_RESET);
+ hpios_delay_micro_seconds(100);
/* ** use default of PLL x7 ** */
/* EMIF = 225/3=75MHz */
hpi_write_word(pdo, 0x01B7C120, 0x8002);
+ hpios_delay_micro_seconds(100);
+
/* peri = 225/2 */
hpi_write_word(pdo, 0x01B7C11C, 0x8001);
+ hpios_delay_micro_seconds(100);
+
/* cpu = 225/1 */
hpi_write_word(pdo, 0x01B7C118, 0x8000);
- /* ~200us delay */
- for (i = 0; i < 2000; i++)
- delay = ioread32(phw->dw2040_HPICSR +
- HPI_RESET);
+
+ /* ~2ms delay */
+ hpios_delay_micro_seconds(2000);
+
/* PLL not bypassed */
hpi_write_word(pdo, 0x01B7C100, 0x0001);
- /* ~200us delay */
- for (i = 0; i < 2000; i++)
- delay = ioread32(phw->dw2040_HPICSR +
- HPI_RESET);
+ /* ~2ms delay */
+ hpios_delay_micro_seconds(2000);
}
/* test r/w to internal DSP memory
@@ -927,9 +909,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
}
/* delay a little to allow SDRAM and DSP to "get going" */
-
- for (i = 0; i < 1000; i++)
- delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+ hpios_delay_micro_seconds(1000);
/* test access to SDRAM */
{
@@ -976,7 +956,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
/* write the DSP code down into the DSPs memory */
/*HpiDspCode_Open(nBootLoadFamily,&DspCode,pdwOsErrorCode); */
- dsp_code.ps_dev = pao->pci.p_os_data;
+ dsp_code.ps_dev = pao->pci.pci_dev;
error = hpi_dsp_code_open(boot_load_family, &dsp_code,
pos_error_code);
@@ -1073,8 +1053,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
/* step 3. Start code by sending interrupt */
iowrite32(0x00030003, pdo->prHPI_control);
- for (i = 0; i < 10000; i++)
- delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);
+ hpios_delay_micro_seconds(10000);
/* wait for a non-zero value in hostcmd -
* indicating initialization is complete
@@ -1101,7 +1080,7 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
* locks up with a bluescreen (NOT GPF or pagefault).
*/
else
- hpios_delay_micro_seconds(1000);
+ hpios_delay_micro_seconds(10000);
}
if (timeout == 0)
return HPI6000_ERROR_INIT_NOACK;
@@ -1132,14 +1111,14 @@ static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
mask = 0xFFFFFF00L;
/* ASI5100 uses AX6 code, */
/* but has no PLD r/w register to test */
- if (HPI_ADAPTER_FAMILY_ASI(pao->pci.
- subsys_device_id) ==
+ if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->
+ subsystem_device) ==
HPI_ADAPTER_FAMILY_ASI(0x5100))
mask = 0x00000000L;
/* ASI5200 uses AX6 code, */
/* but has no PLD r/w register to test */
- if (HPI_ADAPTER_FAMILY_ASI(pao->pci.
- subsys_device_id) ==
+ if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->
+ subsystem_device) ==
HPI_ADAPTER_FAMILY_ASI(0x5200))
mask = 0x00000000L;
break;
@@ -1204,7 +1183,7 @@ static u32 hpi_read_word(struct dsp_obj *pdo, u32 address)
u32 data = 0;
if (hpi_set_address(pdo, address))
- return 0; /*? no way to return error */
+ return 0; /*? No way to return error */
/* take care of errata in revB DSP (2.0.1) */
data = ioread32(pdo->prHPI_data);
@@ -1340,10 +1319,6 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
u32 *p_data;
u16 error = 0;
- /* does the DSP we are referencing exist? */
- if (dsp_index >= phw->num_dsp)
- return HPI6000_ERROR_MSG_INVALID_DSP_INDEX;
-
ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);
if (ack & HPI_HIF_ERROR_MASK) {
pao->dsp_crashed++;
@@ -1351,9 +1326,7 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
}
pao->dsp_crashed = 0;
- /* send the message */
-
- /* get the address and size */
+ /* get the message address and size */
if (phw->message_buffer_address_on_dsp == 0) {
timeout = TIMEOUT;
do {
@@ -1368,10 +1341,9 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
} else
address = phw->message_buffer_address_on_dsp;
- /* dwLength = sizeof(struct hpi_message); */
length = phm->size;
- /* send it */
+ /* send the message */
p_data = (u32 *)phm;
if (hpi6000_dsp_block_write32(pao, dsp_index, address, p_data,
(u16)length / 4))
@@ -1385,7 +1357,7 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
if (ack & HPI_HIF_ERROR_MASK)
return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK;
- /* get the address and size */
+ /* get the response address */
if (phw->response_buffer_address_on_dsp == 0) {
timeout = TIMEOUT;
do {
@@ -1409,7 +1381,7 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
if (!timeout)
length = sizeof(struct hpi_response);
- /* get it */
+ /* get the response */
p_data = (u32 *)phr;
if (hpi6000_dsp_block_read32(pao, dsp_index, address, p_data,
(u16)length / 4))
@@ -1805,17 +1777,11 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
hpios_dsplock_lock(pao);
error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);
- /* maybe an error response */
- if (error) {
- /* something failed in the HPI/DSP interface */
- phr->error = error;
- /* just the header of the response is valid */
- phr->size = sizeof(struct hpi_response_header);
+ if (error) /* something failed in the HPI/DSP interface */
goto err;
- }
- if (phr->error != 0) /* something failed in the DSP */
- goto err;
+ if (phr->error) /* something failed in the DSP */
+ goto out;
switch (phm->function) {
case HPI_OSTREAM_WRITE:
@@ -1827,21 +1793,30 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
error = hpi6000_get_data(pao, dsp_index, phm, phr);
break;
case HPI_ADAPTER_GET_ASSERT:
- phr->u.a.adapter_index = 0; /* dsp 0 default */
+ phr->u.ax.assert.dsp_index = 0; /* dsp 0 default */
if (num_dsp == 2) {
- if (!phr->u.a.adapter_type) {
+ if (!phr->u.ax.assert.count) {
/* no assert from dsp 0, check dsp 1 */
error = hpi6000_message_response_sequence(pao,
1, phm, phr);
- phr->u.a.adapter_index = 1;
+ phr->u.ax.assert.dsp_index = 1;
}
}
}
- if (error)
- phr->error = error;
-
err:
+ if (error) {
+ if (error >= HPI_ERROR_BACKEND_BASE) {
+ phr->error = HPI_ERROR_DSP_COMMUNICATION;
+ phr->specific_error = error;
+ } else {
+ phr->error = error;
+ }
+
+ /* just the header of the response is valid */
+ phr->size = sizeof(struct hpi_response_header);
+ }
+out:
hpios_dsplock_unlock(pao);
return;
}
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 2672f6591ceb..620525bdac59 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -38,27 +38,26 @@
/*****************************************************************************/
/* HPI6205 specific error codes */
-#define HPI6205_ERROR_BASE 1000
-/*#define HPI6205_ERROR_MEM_ALLOC 1001 */
+#define HPI6205_ERROR_BASE 1000 /* not actually used anywhere */
+
+/* operational/messaging errors */
+#define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT 1015
+#define HPI6205_ERROR_MSG_RESP_TIMEOUT 1016
+
+/* initialization/bootload errors */
#define HPI6205_ERROR_6205_NO_IRQ 1002
#define HPI6205_ERROR_6205_INIT_FAILED 1003
-/*#define HPI6205_ERROR_MISSING_DSPCODE 1004 */
-#define HPI6205_ERROR_UNKNOWN_PCI_DEVICE 1005
#define HPI6205_ERROR_6205_REG 1006
#define HPI6205_ERROR_6205_DSPPAGE 1007
-#define HPI6205_ERROR_BAD_DSPINDEX 1008
#define HPI6205_ERROR_C6713_HPIC 1009
#define HPI6205_ERROR_C6713_HPIA 1010
#define HPI6205_ERROR_C6713_PLL 1011
#define HPI6205_ERROR_DSP_INTMEM 1012
#define HPI6205_ERROR_DSP_EXTMEM 1013
#define HPI6205_ERROR_DSP_PLD 1014
-#define HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT 1015
-#define HPI6205_ERROR_MSG_RESP_TIMEOUT 1016
#define HPI6205_ERROR_6205_EEPROM 1017
#define HPI6205_ERROR_DSP_EMIF 1018
-#define hpi6205_error(dsp_index, err) (err)
/*****************************************************************************/
/* for C6205 PCI i/f */
/* Host Status Register (HSR) bitfields */
@@ -128,9 +127,6 @@ struct hpi_hw_obj {
u32 outstream_host_buffer_size[HPI_MAX_STREAMS];
struct consistent_dma_area h_control_cache;
- struct consistent_dma_area h_async_event_buffer;
-/* struct hpi_control_cache_single *pControlCache; */
- struct hpi_async_event *p_async_event_buffer;
struct hpi_control_cache *p_cache;
};
@@ -208,8 +204,8 @@ static void instream_start(struct hpi_adapter_obj *pao,
static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
u32 address);
-static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
- u32 address, u32 data);
+static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
+ int dsp_index, u32 address, u32 data);
static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao,
int dsp_index);
@@ -229,17 +225,7 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index);
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
{
-
switch (phm->function) {
- case HPI_SUBSYS_OPEN:
- case HPI_SUBSYS_CLOSE:
- case HPI_SUBSYS_GET_INFO:
- case HPI_SUBSYS_DRIVER_UNLOAD:
- case HPI_SUBSYS_DRIVER_LOAD:
- case HPI_SUBSYS_FIND_ADAPTERS:
- /* messages that should not get here */
- phr->error = HPI_ERROR_UNIMPLEMENTED;
- break;
case HPI_SUBSYS_CREATE_ADAPTER:
subsys_create_adapter(phm, phr);
break;
@@ -257,15 +243,22 @@ static void control_message(struct hpi_adapter_obj *pao,
{
struct hpi_hw_obj *phw = pao->priv;
+ u16 pending_cache_error = 0;
switch (phm->function) {
case HPI_CONTROL_GET_STATE:
if (pao->has_control_cache) {
- rmb(); /* make sure we see updates DM_aed from DSP */
- if (hpi_check_control_cache(phw->p_cache, phm, phr))
+ rmb(); /* make sure we see updates DMAed from DSP */
+ if (hpi_check_control_cache(phw->p_cache, phm, phr)) {
break;
+ } else if (phm->u.c.attribute == HPI_METER_PEAK) {
+ pending_cache_error =
+ HPI_ERROR_CONTROL_CACHING;
+ }
}
hw_message(pao, phm, phr);
+ if (pending_cache_error && !phr->error)
+ phr->error = pending_cache_error;
break;
case HPI_CONTROL_GET_INFO:
hw_message(pao, phm, phr);
@@ -273,7 +266,8 @@ static void control_message(struct hpi_adapter_obj *pao,
case HPI_CONTROL_SET_STATE:
hw_message(pao, phm, phr);
if (pao->has_control_cache)
- hpi_sync_control_cache(phw->p_cache, phm, phr);
+ hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm,
+ phr);
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
@@ -296,9 +290,9 @@ static void outstream_message(struct hpi_adapter_obj *pao,
{
if (phm->obj_index >= HPI_MAX_STREAMS) {
- phr->error = HPI_ERROR_INVALID_STREAM;
+ phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
HPI_DEBUG_LOG(WARNING,
- "message referencing invalid stream %d "
+ "Message referencing invalid stream %d "
"on adapter index %d\n", phm->obj_index,
phm->adapter_index);
return;
@@ -340,9 +334,9 @@ static void instream_message(struct hpi_adapter_obj *pao,
{
if (phm->obj_index >= HPI_MAX_STREAMS) {
- phr->error = HPI_ERROR_INVALID_STREAM;
+ phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
HPI_DEBUG_LOG(WARNING,
- "message referencing invalid stream %d "
+ "Message referencing invalid stream %d "
"on adapter index %d\n", phm->obj_index,
phm->adapter_index);
return;
@@ -385,8 +379,8 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
* All other messages are ignored unless the adapter index matches
* an adapter in the HPI
*/
- HPI_DEBUG_LOG(DEBUG, "HPI obj=%d, func=%d\n", phm->object,
- phm->function);
+ /* HPI_DEBUG_LOG(DEBUG, "HPI Obj=%d, Func=%d\n", phm->wObject,
+ phm->wFunction); */
/* if Dsp has crashed then do not communicate with it any more */
if (phm->object != HPI_OBJ_SUBSYSTEM) {
@@ -411,8 +405,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
/* Init default response */
if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)
- hpi_init_response(phr, phm->object, phm->function,
- HPI_ERROR_PROCESSING_MESSAGE);
+ phr->error = HPI_ERROR_PROCESSING_MESSAGE;
HPI_DEBUG_LOG(VERBOSE, "start of switch\n");
switch (phm->type) {
@@ -423,9 +416,6 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
break;
case HPI_OBJ_ADAPTER:
- phr->size =
- sizeof(struct hpi_response_header) +
- sizeof(struct hpi_adapter_res);
adapter_message(pao, phm, phr);
break;
@@ -474,14 +464,6 @@ static void subsys_create_adapter(struct hpi_message *phm,
memset(&ao, 0, sizeof(ao));
- /* this HPI only creates adapters for TI/PCI devices */
- if (phm->u.s.resource.bus_type != HPI_BUS_PCI)
- return;
- if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI)
- return;
- if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_DSP6205)
- return;
-
ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);
if (!ao.priv) {
HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n");
@@ -491,18 +473,20 @@ static void subsys_create_adapter(struct hpi_message *phm,
ao.pci = *phm->u.s.resource.r.pci;
err = create_adapter_obj(&ao, &os_error_code);
- if (!err)
- err = hpi_add_adapter(&ao);
if (err) {
- phr->u.s.data = os_error_code;
delete_adapter_obj(&ao);
- phr->error = err;
+ if (err >= HPI_ERROR_BACKEND_BASE) {
+ phr->error = HPI_ERROR_DSP_BOOTLOAD;
+ phr->specific_error = err;
+ } else {
+ phr->error = err;
+ }
+ phr->u.s.data = os_error_code;
return;
}
- phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type;
+ phr->u.s.adapter_type = ao.adapter_type;
phr->u.s.adapter_index = ao.index;
- phr->u.s.num_adapters++;
phr->error = 0;
}
@@ -513,7 +497,7 @@ static void subsys_delete_adapter(struct hpi_message *phm,
struct hpi_adapter_obj *pao;
struct hpi_hw_obj *phw;
- pao = hpi_find_adapter(phm->adapter_index);
+ pao = hpi_find_adapter(phm->obj_index);
if (!pao) {
phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
return;
@@ -526,6 +510,7 @@ static void subsys_delete_adapter(struct hpi_message *phm,
iowrite32(C6205_HDCR_WARMRESET, phw->prHDCR);
delete_adapter_obj(pao);
+ hpi_delete_adapter(pao);
phr->error = 0;
}
@@ -538,10 +523,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
struct hpi_hw_obj *phw = pao->priv;
struct bus_master_interface *interface;
u32 phys_addr;
-#ifndef HPI6205_NO_HSR_POLL
- u32 time_out = HPI6205_TIMEOUT;
- u32 temp1;
-#endif
int i;
u16 err;
@@ -566,7 +547,7 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
if (hpios_locked_mem_alloc(&phw->h_locked_mem,
sizeof(struct bus_master_interface),
- pao->pci.p_os_data))
+ pao->pci.pci_dev))
phw->p_interface_buffer = NULL;
else if (hpios_locked_mem_get_virt_addr(&phw->h_locked_mem,
(void *)&phw->p_interface_buffer))
@@ -591,49 +572,29 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
/* allow boot load even if mem alloc wont work */
if (!phw->p_interface_buffer)
- return hpi6205_error(0, HPI_ERROR_MEMORY_ALLOC);
+ return HPI_ERROR_MEMORY_ALLOC;
interface = phw->p_interface_buffer;
-#ifndef HPI6205_NO_HSR_POLL
- /* wait for first interrupt indicating the DSP init is done */
- time_out = HPI6205_TIMEOUT * 10;
- temp1 = 0;
- while (((temp1 & C6205_HSR_INTSRC) == 0) && --time_out)
- temp1 = ioread32(phw->prHSR);
-
- if (temp1 & C6205_HSR_INTSRC)
- HPI_DEBUG_LOG(INFO,
- "interrupt confirming DSP code running OK\n");
- else {
- HPI_DEBUG_LOG(ERROR,
- "timed out waiting for interrupt "
- "confirming DSP code running\n");
- return hpi6205_error(0, HPI6205_ERROR_6205_NO_IRQ);
- }
-
- /* reset the interrupt */
- iowrite32(C6205_HSR_INTSRC, phw->prHSR);
-#endif
-
/* make sure the DSP has started ok */
if (!wait_dsp_ack(phw, H620_HIF_RESET, HPI6205_TIMEOUT * 10)) {
HPI_DEBUG_LOG(ERROR, "timed out waiting reset state \n");
- return hpi6205_error(0, HPI6205_ERROR_6205_INIT_FAILED);
+ return HPI6205_ERROR_6205_INIT_FAILED;
}
/* Note that *pao, *phw are zeroed after allocation,
* so pointers and flags are NULL by default.
* Allocate bus mastering control cache buffer and tell the DSP about it
*/
if (interface->control_cache.number_of_controls) {
- void *p_control_cache_virtual;
+ u8 *p_control_cache_virtual;
err = hpios_locked_mem_alloc(&phw->h_control_cache,
interface->control_cache.size_in_bytes,
- pao->pci.p_os_data);
+ pao->pci.pci_dev);
if (!err)
err = hpios_locked_mem_get_virt_addr(&phw->
- h_control_cache, &p_control_cache_virtual);
+ h_control_cache,
+ (void *)&p_control_cache_virtual);
if (!err) {
memset(p_control_cache_virtual, 0,
interface->control_cache.size_in_bytes);
@@ -642,7 +603,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
hpi_alloc_control_cache(interface->
control_cache.number_of_controls,
interface->control_cache.size_in_bytes,
- (struct hpi_control_cache_info *)
p_control_cache_virtual);
if (!phw->p_cache)
err = HPI_ERROR_MEMORY_ALLOC;
@@ -662,78 +622,56 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
pao->has_control_cache = 0;
}
}
- /* allocate bus mastering async buffer and tell the DSP about it */
- if (interface->async_buffer.b.size) {
- err = hpios_locked_mem_alloc(&phw->h_async_event_buffer,
- interface->async_buffer.b.size *
- sizeof(struct hpi_async_event), pao->pci.p_os_data);
- if (!err)
- err = hpios_locked_mem_get_virt_addr
- (&phw->h_async_event_buffer, (void *)
- &phw->p_async_event_buffer);
- if (!err)
- memset((void *)phw->p_async_event_buffer, 0,
- interface->async_buffer.b.size *
- sizeof(struct hpi_async_event));
- if (!err) {
- err = hpios_locked_mem_get_phys_addr
- (&phw->h_async_event_buffer, &phys_addr);
- interface->async_buffer.physical_address32 =
- phys_addr;
- }
- if (err) {
- if (hpios_locked_mem_valid(&phw->
- h_async_event_buffer)) {
- hpios_locked_mem_free
- (&phw->h_async_event_buffer);
- phw->p_async_event_buffer = NULL;
- }
- }
- }
send_dsp_command(phw, H620_HIF_IDLE);
{
- struct hpi_message hM;
- struct hpi_response hR;
+ struct hpi_message hm;
+ struct hpi_response hr;
u32 max_streams;
HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
- memset(&hM, 0, sizeof(hM));
- hM.type = HPI_TYPE_MESSAGE;
- hM.size = sizeof(hM);
- hM.object = HPI_OBJ_ADAPTER;
- hM.function = HPI_ADAPTER_GET_INFO;
- hM.adapter_index = 0;
- memset(&hR, 0, sizeof(hR));
- hR.size = sizeof(hR);
-
- err = message_response_sequence(pao, &hM, &hR);
+ memset(&hm, 0, sizeof(hm));
+ hm.type = HPI_TYPE_MESSAGE;
+ hm.size = sizeof(hm);
+ hm.object = HPI_OBJ_ADAPTER;
+ hm.function = HPI_ADAPTER_GET_INFO;
+ hm.adapter_index = 0;
+ memset(&hr, 0, sizeof(hr));
+ hr.size = sizeof(hr);
+
+ err = message_response_sequence(pao, &hm, &hr);
if (err) {
HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
err);
return err;
}
- if (hR.error)
- return hR.error;
+ if (hr.error)
+ return hr.error;
- pao->adapter_type = hR.u.a.adapter_type;
- pao->index = hR.u.a.adapter_index;
+ pao->adapter_type = hr.u.ax.info.adapter_type;
+ pao->index = hr.u.ax.info.adapter_index;
- max_streams = hR.u.a.num_outstreams + hR.u.a.num_instreams;
+ max_streams =
+ hr.u.ax.info.num_outstreams +
+ hr.u.ax.info.num_instreams;
hpios_locked_mem_prepare((max_streams * 6) / 10, max_streams,
- 65536, pao->pci.p_os_data);
+ 65536, pao->pci.pci_dev);
HPI_DEBUG_LOG(VERBOSE,
"got adapter info type %x index %d serial %d\n",
- hR.u.a.adapter_type, hR.u.a.adapter_index,
- hR.u.a.serial_number);
+ hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
+ hr.u.ax.info.serial_number);
}
pao->open = 0; /* upon creation the adapter is closed */
+ if (phw->p_cache)
+ phw->p_cache->adap_idx = pao->index;
+
HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
- return 0;
+
+ return hpi_add_adapter(pao);
}
/** Free memory areas allocated by adapter
@@ -747,11 +685,6 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
phw = pao->priv;
- if (hpios_locked_mem_valid(&phw->h_async_event_buffer)) {
- hpios_locked_mem_free(&phw->h_async_event_buffer);
- phw->p_async_event_buffer = NULL;
- }
-
if (hpios_locked_mem_valid(&phw->h_control_cache)) {
hpios_locked_mem_free(&phw->h_control_cache);
hpi_free_control_cache(phw->p_cache);
@@ -776,13 +709,15 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
phw->outstream_host_buffer_size[i] = 0;
}
- hpios_locked_mem_unprepare(pao->pci.p_os_data);
+ hpios_locked_mem_unprepare(pao->pci.pci_dev);
- hpi_delete_adapter(pao);
kfree(phw);
}
/*****************************************************************************/
+/* Adapter functions */
+
+/*****************************************************************************/
/* OutStream Host buffer functions */
/** Allocate or attach buffer for busmastering
@@ -824,7 +759,7 @@ static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
err = hpios_locked_mem_alloc(&phw->outstream_host_buffers
[phm->obj_index], phm->u.d.u.buffer.buffer_size,
- pao->pci.p_os_data);
+ pao->pci.pci_dev);
if (err) {
phr->error = HPI_ERROR_INVALID_DATASIZE;
@@ -861,7 +796,7 @@ static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
buffer_size - 1)) {
HPI_DEBUG_LOG(ERROR,
- "buffer size must be 2^N not %d\n",
+ "Buffer size must be 2^N not %d\n",
phm->u.d.u.buffer.buffer_size);
phr->error = HPI_ERROR_INVALID_DATASIZE;
return;
@@ -875,6 +810,7 @@ static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
status->dSP_index = 0;
status->host_index = status->dSP_index;
status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
+ status->auxiliary_data_available = 0;
hw_message(pao, phm, phr);
@@ -966,51 +902,6 @@ static void outstream_write(struct hpi_adapter_obj *pao,
hpi_init_response(phr, phm->object, phm->function, 0);
status = &interface->outstream_host_buffer_status[phm->obj_index];
- if (phw->flag_outstream_just_reset[phm->obj_index]) {
- /* First OutStremWrite() call following reset will write data to the
- adapter's buffers, reducing delay before stream can start. The DSP
- takes care of setting the stream data format using format information
- embedded in phm.
- */
- int partial_write = 0;
- unsigned int original_size = 0;
-
- phw->flag_outstream_just_reset[phm->obj_index] = 0;
-
- /* Send the first buffer to the DSP the old way. */
- /* Limit size of first transfer - */
- /* expect that this will not usually be triggered. */
- if (phm->u.d.u.data.data_size > HPI6205_SIZEOF_DATA) {
- partial_write = 1;
- original_size = phm->u.d.u.data.data_size;
- phm->u.d.u.data.data_size = HPI6205_SIZEOF_DATA;
- }
- /* write it */
- phm->function = HPI_OSTREAM_WRITE;
- hw_message(pao, phm, phr);
-
- if (phr->error)
- return;
-
- /* update status information that the DSP would typically
- * update (and will update next time the DSP
- * buffer update task reads data from the host BBM buffer)
- */
- status->auxiliary_data_available = phm->u.d.u.data.data_size;
- status->host_index += phm->u.d.u.data.data_size;
- status->dSP_index += phm->u.d.u.data.data_size;
-
- /* if we did a full write, we can return from here. */
- if (!partial_write)
- return;
-
- /* tweak buffer parameters and let the rest of the */
- /* buffer land in internal BBM buffer */
- phm->u.d.u.data.data_size =
- original_size - HPI6205_SIZEOF_DATA;
- phm->u.d.u.data.pb_data += HPI6205_SIZEOF_DATA;
- }
-
space_available = outstream_get_space_available(status);
if (space_available < phm->u.d.u.data.data_size) {
phr->error = HPI_ERROR_INVALID_DATASIZE;
@@ -1047,6 +938,24 @@ static void outstream_write(struct hpi_adapter_obj *pao,
memcpy(p_bbm_data, p_app_data + l_first_write,
phm->u.d.u.data.data_size - l_first_write);
}
+
+ /*
+ * This version relies on the DSP code triggering an OStream buffer
+ * update immediately following a SET_FORMAT call. The host has
+ * already written data into the BBM buffer, but the DSP won't know
+ * about it until dwHostIndex is adjusted.
+ */
+ if (phw->flag_outstream_just_reset[phm->obj_index]) {
+ /* Format can only change after reset. Must tell DSP. */
+ u16 function = phm->function;
+ phw->flag_outstream_just_reset[phm->obj_index] = 0;
+ phm->function = HPI_OSTREAM_SET_FORMAT;
+ hw_message(pao, phm, phr); /* send the format to the DSP */
+ phm->function = function;
+ if (phr->error)
+ return;
+ }
+
status->host_index += phm->u.d.u.data.data_size;
}
@@ -1132,7 +1041,7 @@ static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
err = hpios_locked_mem_alloc(&phw->instream_host_buffers[phm->
obj_index], phm->u.d.u.buffer.buffer_size,
- pao->pci.p_os_data);
+ pao->pci.pci_dev);
if (err) {
phr->error = HPI_ERROR_INVALID_DATASIZE;
@@ -1163,7 +1072,7 @@ static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
if (phm->u.d.u.buffer.buffer_size & (phm->u.d.u.buffer.
buffer_size - 1)) {
HPI_DEBUG_LOG(ERROR,
- "buffer size must be 2^N not %d\n",
+ "Buffer size must be 2^N not %d\n",
phm->u.d.u.buffer.buffer_size);
phr->error = HPI_ERROR_INVALID_DATASIZE;
return;
@@ -1178,8 +1087,10 @@ static void instream_host_buffer_allocate(struct hpi_adapter_obj *pao,
status->dSP_index = 0;
status->host_index = status->dSP_index;
status->size_in_bytes = phm->u.d.u.buffer.buffer_size;
+ status->auxiliary_data_available = 0;
hw_message(pao, phm, phr);
+
if (phr->error
&& hpios_locked_mem_valid(&phw->
instream_host_buffers[phm->obj_index])) {
@@ -1344,33 +1255,36 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
struct hpi_hw_obj *phw = pao->priv;
struct dsp_code dsp_code;
u16 boot_code_id[HPI6205_MAX_FILES_TO_LOAD];
- u16 firmware_id = pao->pci.subsys_device_id;
u32 temp;
int dsp = 0, i = 0;
u16 err = 0;
boot_code_id[0] = HPI_ADAPTER_ASI(0x6205);
- /* special cases where firmware_id != subsys ID */
- switch (firmware_id) {
+ boot_code_id[1] = pao->pci.pci_dev->subsystem_device;
+ boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(boot_code_id[1]);
+
+ /* fix up cases where bootcode id[1] != subsys id */
+ switch (boot_code_id[1]) {
case HPI_ADAPTER_FAMILY_ASI(0x5000):
- boot_code_id[0] = firmware_id;
- firmware_id = 0;
+ boot_code_id[0] = boot_code_id[1];
+ boot_code_id[1] = 0;
break;
case HPI_ADAPTER_FAMILY_ASI(0x5300):
case HPI_ADAPTER_FAMILY_ASI(0x5400):
case HPI_ADAPTER_FAMILY_ASI(0x6300):
- firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6400);
+ boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6400);
break;
case HPI_ADAPTER_FAMILY_ASI(0x5600):
case HPI_ADAPTER_FAMILY_ASI(0x6500):
- firmware_id = HPI_ADAPTER_FAMILY_ASI(0x6600);
+ boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x6600);
break;
case HPI_ADAPTER_FAMILY_ASI(0x8800):
- firmware_id = HPI_ADAPTER_FAMILY_ASI(0x8900);
+ boot_code_id[1] = HPI_ADAPTER_FAMILY_ASI(0x8900);
+ break;
+ default:
break;
}
- boot_code_id[1] = firmware_id;
/* reset DSP by writing a 1 to the WARMRESET bit */
temp = C6205_HDCR_WARMRESET;
@@ -1381,7 +1295,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
temp = ioread32(phw->prHSR);
if ((temp & (C6205_HSR_CFGERR | C6205_HSR_EEREAD)) !=
C6205_HSR_EEREAD)
- return hpi6205_error(0, HPI6205_ERROR_6205_EEPROM);
+ return HPI6205_ERROR_6205_EEPROM;
temp |= 0x04;
/* disable PINTA interrupt */
iowrite32(temp, phw->prHSR);
@@ -1389,27 +1303,27 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
/* check control register reports PCI boot mode */
temp = ioread32(phw->prHDCR);
if (!(temp & C6205_HDCR_PCIBOOT))
- return hpi6205_error(0, HPI6205_ERROR_6205_REG);
+ return HPI6205_ERROR_6205_REG;
- /* try writing a couple of numbers to the DSP page register */
+ /* try writing a few numbers to the DSP page register */
/* and reading them back. */
- temp = 1;
+ temp = 3;
iowrite32(temp, phw->prDSPP);
if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
- return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+ return HPI6205_ERROR_6205_DSPPAGE;
temp = 2;
iowrite32(temp, phw->prDSPP);
if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
- return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
- temp = 3;
+ return HPI6205_ERROR_6205_DSPPAGE;
+ temp = 1;
iowrite32(temp, phw->prDSPP);
if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
- return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+ return HPI6205_ERROR_6205_DSPPAGE;
/* reset DSP page to the correct number */
temp = 0;
iowrite32(temp, phw->prDSPP);
if ((temp | C6205_DSPP_MAP1) != ioread32(phw->prDSPP))
- return hpi6205_error(0, HPI6205_ERROR_6205_DSPPAGE);
+ return HPI6205_ERROR_6205_DSPPAGE;
phw->dsp_page = 0;
/* release 6713 from reset before 6205 is bootloaded.
@@ -1455,7 +1369,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
return err;
/* write the DSP code down into the DSPs memory */
- dsp_code.ps_dev = pao->pci.p_os_data;
+ dsp_code.ps_dev = pao->pci.pci_dev;
err = hpi_dsp_code_open(boot_code_id[dsp], &dsp_code,
pos_error_code);
if (err)
@@ -1484,10 +1398,8 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
if (err)
break;
for (i = 0; i < (int)length; i++) {
- err = boot_loader_write_mem32(pao, dsp,
- address, *pcode);
- if (err)
- break;
+ boot_loader_write_mem32(pao, dsp, address,
+ *pcode);
/* dummy read every 4 words */
/* for 6205 advisory 1.4.4 */
if (i % 4 == 0)
@@ -1561,7 +1473,7 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
host_mailbox_address_on_dsp = 0x80000000;
while ((physicalPC_iaddress != physicalPC_iaddress_verify)
&& time_out--) {
- err = boot_loader_write_mem32(pao, 0,
+ boot_loader_write_mem32(pao, 0,
host_mailbox_address_on_dsp,
physicalPC_iaddress);
physicalPC_iaddress_verify =
@@ -1631,11 +1543,10 @@ static u32 boot_loader_read_mem32(struct hpi_adapter_obj *pao, int dsp_index,
return data;
}
-static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
- u32 address, u32 data)
+static void boot_loader_write_mem32(struct hpi_adapter_obj *pao,
+ int dsp_index, u32 address, u32 data)
{
struct hpi_hw_obj *phw = pao->priv;
- u16 err = 0;
__iomem u32 *p_data;
/* u32 dwVerifyData=0; */
@@ -1675,15 +1586,11 @@ static u16 boot_loader_write_mem32(struct hpi_adapter_obj *pao, int dsp_index,
/* dummy read every 4 words for 6205 advisory 1.4.4 */
boot_loader_read_mem32(pao, 0, 0);
- } else
- err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
- return err;
+ }
}
static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
{
- u16 err = 0;
-
if (dsp_index == 0) {
u32 setting;
@@ -1711,8 +1618,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
boot_loader_write_mem32(pao, dsp_index, 0x01800008, setting);
if (setting != boot_loader_read_mem32(pao, dsp_index,
0x01800008))
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_EMIF);
+ return HPI6205_ERROR_DSP_EMIF;
/* EMIF CE1 setup - 32 bit async. This is 6713 #1 HPI, */
/* which occupies D15..0. 6713 starts at 27MHz, so need */
@@ -1725,8 +1631,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
boot_loader_write_mem32(pao, dsp_index, 0x01800004, setting);
if (setting != boot_loader_read_mem32(pao, dsp_index,
0x01800004))
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_EMIF);
+ return HPI6205_ERROR_DSP_EMIF;
/* EMIF CE2 setup - 32 bit async. This is 6713 #2 HPI, */
/* which occupies D15..0. 6713 starts at 27MHz, so need */
@@ -1738,8 +1643,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
boot_loader_write_mem32(pao, dsp_index, 0x01800010, setting);
if (setting != boot_loader_read_mem32(pao, dsp_index,
0x01800010))
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_EMIF);
+ return HPI6205_ERROR_DSP_EMIF;
/* EMIF CE3 setup - 32 bit async. */
/* This is the PLD on the ASI5000 cards only */
@@ -1750,8 +1654,7 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
boot_loader_write_mem32(pao, dsp_index, 0x01800014, setting);
if (setting != boot_loader_read_mem32(pao, dsp_index,
0x01800014))
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_EMIF);
+ return HPI6205_ERROR_DSP_EMIF;
/* set EMIF SDRAM control for 2Mx32 SDRAM (512x32x4 bank) */
/* need to use this else DSP code crashes? */
@@ -1775,12 +1678,9 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
read_data =
0xFFF7 & boot_loader_read_mem32(pao, 0, HPICL_ADDR);
if (write_data != read_data) {
- err = hpi6205_error(dsp_index,
- HPI6205_ERROR_C6713_HPIC);
HPI_DEBUG_LOG(ERROR, "HPICL %x %x\n", write_data,
read_data);
-
- return err;
+ return HPI6205_ERROR_C6713_HPIC;
}
/* HPIA - walking ones test */
write_data = 1;
@@ -1798,11 +1698,9 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
HPIAH_ADDR))
<< 16);
if (read_data != write_data) {
- err = hpi6205_error(dsp_index,
- HPI6205_ERROR_C6713_HPIA);
HPI_DEBUG_LOG(ERROR, "HPIA %x %x\n",
write_data, read_data);
- return err;
+ return HPI6205_ERROR_C6713_HPIA;
}
write_data = write_data << 1;
}
@@ -1847,30 +1745,81 @@ static u16 boot_loader_config_emif(struct hpi_adapter_obj *pao, int dsp_index)
/* PLL should not be bypassed! */
if ((boot_loader_read_mem32(pao, dsp_index, 0x01B7C100) & 0xF)
!= 0x0001) {
- err = hpi6205_error(dsp_index,
- HPI6205_ERROR_C6713_PLL);
- return err;
+ return HPI6205_ERROR_C6713_PLL;
}
/* setup C67x EMIF (note this is the only use of
BAR1 via BootLoader_WriteMem32) */
boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_GCTL,
0x000034A8);
+
+ /* EMIF CE0 setup - 2Mx32 Sync DRAM
+ 31..28 Wr setup
+ 27..22 Wr strobe
+ 21..20 Wr hold
+ 19..16 Rd setup
+ 15..14 -
+ 13..8 Rd strobe
+ 7..4 MTYPE 0011 Sync DRAM 32bits
+ 3 Wr hold MSB
+ 2..0 Rd hold
+ */
boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_CE0,
0x00000030);
+
+ /* EMIF SDRAM Extension
+ 0x00
+ 31-21 0000b 0000b 000b
+ 20 WR2RD = 2cycles-1 = 1b
+
+ 19-18 WR2DEAC = 3cycle-1 = 10b
+ 17 WR2WR = 2cycle-1 = 1b
+ 16-15 R2WDQM = 4cycle-1 = 11b
+ 14-12 RD2WR = 6cycles-1 = 101b
+
+ 11-10 RD2DEAC = 4cycle-1 = 11b
+ 9 RD2RD = 2cycle-1 = 1b
+ 8-7 THZP = 3cycle-1 = 10b
+ 6-5 TWR = 2cycle-1 = 01b (tWR = 17ns)
+ 4 TRRD = 2cycle = 0b (tRRD = 14ns)
+ 3-1 TRAS = 5cycle-1 = 100b (Tras=42ns)
+ 1 CAS latency = 3cyc = 1b
+ (for Micron 2M32-7 operating at 100MHz)
+ */
boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMEXT,
0x001BDF29);
+
+ /* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)
+ 31 - 0b -
+ 30 SDBSZ 1b 4 bank
+ 29..28 SDRSZ 00b 11 row address pins
+
+ 27..26 SDCSZ 01b 8 column address pins
+ 25 RFEN 1b refersh enabled
+ 24 INIT 1b init SDRAM!
+
+ 23..20 TRCD 0001b (Trcd/Tcyc)-1 = (20/10)-1 = 1
+
+ 19..16 TRP 0001b (Trp/Tcyc)-1 = (20/10)-1 = 1
+
+ 15..12 TRC 0110b (Trc/Tcyc)-1 = (70/10)-1 = 6
+
+ 11..0 - 0000b 0000b 0000b
+ */
boot_loader_write_mem32(pao, dsp_index, C6713_EMIF_SDRAMCTL,
- 0x47117000);
+ 0x47116000);
+
+ /* SDRAM refresh timing
+ Need 4,096 refresh cycles every 64ms = 15.625us = 1562cycles of 100MHz = 0x61A
+ */
boot_loader_write_mem32(pao, dsp_index,
C6713_EMIF_SDRAMTIMING, 0x00000410);
hpios_delay_micro_seconds(1000);
} else if (dsp_index == 2) {
/* DSP 2 is a C6713 */
+ }
- } else
- err = hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
- return err;
+ return 0;
}
static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
@@ -1896,7 +1845,7 @@ static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
test_addr);
if (data != test_data) {
HPI_DEBUG_LOG(VERBOSE,
- "memtest error details "
+ "Memtest error details "
"%08x %08x %08x %i\n", test_addr,
test_data, data, dsp_index);
return 1; /* error */
@@ -1916,7 +1865,7 @@ static u16 boot_loader_test_memory(struct hpi_adapter_obj *pao, int dsp_index,
data = boot_loader_read_mem32(pao, dsp_index, test_addr);
if (data != test_data) {
HPI_DEBUG_LOG(VERBOSE,
- "memtest error details "
+ "Memtest error details "
"%08x %08x %08x %i\n", test_addr, test_data,
data, dsp_index);
return 1; /* error */
@@ -1946,8 +1895,8 @@ static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
/* 64K data mem */
err = boot_loader_test_memory(pao, dsp_index,
0x80000000, 0x10000);
- } else if ((dsp_index == 1) || (dsp_index == 2)) {
- /* DSP 1&2 are a C6713 */
+ } else if (dsp_index == 1) {
+ /* DSP 1 is a C6713 */
/* 192K internal mem */
err = boot_loader_test_memory(pao, dsp_index, 0x00000000,
0x30000);
@@ -1955,11 +1904,10 @@ static u16 boot_loader_test_internal_memory(struct hpi_adapter_obj *pao,
/* 64K internal mem / L2 cache */
err = boot_loader_test_memory(pao, dsp_index,
0x00030000, 0x10000);
- } else
- return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+ }
if (err)
- return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_INTMEM);
+ return HPI6205_ERROR_DSP_INTMEM;
else
return 0;
}
@@ -1972,24 +1920,23 @@ static u16 boot_loader_test_external_memory(struct hpi_adapter_obj *pao,
if (dsp_index == 0) {
/* only test for SDRAM if an ASI5000 card */
- if (pao->pci.subsys_device_id == 0x5000) {
+ if (pao->pci.pci_dev->subsystem_device == 0x5000) {
/* DSP 0 is always C6205 */
dRAM_start_address = 0x00400000;
dRAM_size = 0x200000;
/*dwDRAMinc=1024; */
} else
return 0;
- } else if ((dsp_index == 1) || (dsp_index == 2)) {
+ } else if (dsp_index == 1) {
/* DSP 1 is a C6713 */
dRAM_start_address = 0x80000000;
dRAM_size = 0x200000;
/*dwDRAMinc=1024; */
- } else
- return hpi6205_error(dsp_index, HPI6205_ERROR_BAD_DSPINDEX);
+ }
if (boot_loader_test_memory(pao, dsp_index, dRAM_start_address,
dRAM_size))
- return hpi6205_error(dsp_index, HPI6205_ERROR_DSP_EXTMEM);
+ return HPI6205_ERROR_DSP_EXTMEM;
return 0;
}
@@ -1998,28 +1945,25 @@ static u16 boot_loader_test_pld(struct hpi_adapter_obj *pao, int dsp_index)
u32 data = 0;
if (dsp_index == 0) {
/* only test for DSP0 PLD on ASI5000 card */
- if (pao->pci.subsys_device_id == 0x5000) {
+ if (pao->pci.pci_dev->subsystem_device == 0x5000) {
/* PLD is located at CE3=0x03000000 */
data = boot_loader_read_mem32(pao, dsp_index,
0x03000008);
if ((data & 0xF) != 0x5)
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_PLD);
+ return HPI6205_ERROR_DSP_PLD;
data = boot_loader_read_mem32(pao, dsp_index,
0x0300000C);
if ((data & 0xF) != 0xA)
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_PLD);
+ return HPI6205_ERROR_DSP_PLD;
}
} else if (dsp_index == 1) {
/* DSP 1 is a C6713 */
- if (pao->pci.subsys_device_id == 0x8700) {
+ if (pao->pci.pci_dev->subsystem_device == 0x8700) {
/* PLD is located at CE1=0x90000000 */
data = boot_loader_read_mem32(pao, dsp_index,
0x90000010);
if ((data & 0xFF) != 0xAA)
- return hpi6205_error(dsp_index,
- HPI6205_ERROR_DSP_PLD);
+ return HPI6205_ERROR_DSP_PLD;
/* 8713 - LED on */
boot_loader_write_mem32(pao, dsp_index, 0x90000000,
0x02);
@@ -2037,14 +1981,11 @@ static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
struct hpi_hw_obj *phw = pao->priv;
u32 data_transferred = 0;
u16 err = 0;
-#ifndef HPI6205_NO_HSR_POLL
- u32 time_out;
-#endif
u32 temp2;
struct bus_master_interface *interface = phw->p_interface_buffer;
if (!p_data)
- return HPI_ERROR_INVALID_DATA_TRANSFER;
+ return HPI_ERROR_INVALID_DATA_POINTER;
data_size &= ~3L; /* round data_size down to nearest 4 bytes */
@@ -2064,14 +2005,10 @@ static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
interface->transfer_size_in_bytes = this_copy;
-#ifdef HPI6205_NO_HSR_POLL
/* DSP must change this back to nOperation */
interface->dsp_ack = H620_HIF_IDLE;
-#endif
-
send_dsp_command(phw, operation);
-#ifdef HPI6205_NO_HSR_POLL
temp2 = wait_dsp_ack(phw, operation, HPI6205_TIMEOUT);
HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
HPI6205_TIMEOUT - temp2, this_copy);
@@ -2079,45 +2016,11 @@ static short hpi6205_transfer_data(struct hpi_adapter_obj *pao, u8 *p_data,
if (!temp2) {
/* timed out */
HPI_DEBUG_LOG(ERROR,
- "timed out waiting for " "state %d got %d\n",
+ "Timed out waiting for " "state %d got %d\n",
operation, interface->dsp_ack);
break;
}
-#else
- /* spin waiting on the result */
- time_out = HPI6205_TIMEOUT;
- temp2 = 0;
- while ((temp2 == 0) && time_out--) {
- /* give 16k bus mastering transfer time to happen */
- /*(16k / 132Mbytes/s = 122usec) */
- hpios_delay_micro_seconds(20);
- temp2 = ioread32(phw->prHSR);
- temp2 &= C6205_HSR_INTSRC;
- }
- HPI_DEBUG_LOG(DEBUG, "spun %d times for data xfer of %d\n",
- HPI6205_TIMEOUT - time_out, this_copy);
- if (temp2 == C6205_HSR_INTSRC) {
- HPI_DEBUG_LOG(VERBOSE,
- "interrupt from HIF <data> OK\n");
- /*
- if(interface->dwDspAck != nOperation) {
- HPI_DEBUG_LOG(DEBUG("interface->dwDspAck=%d,
- expected %d \n",
- interface->dwDspAck,nOperation);
- }
- */
- }
-/* need to handle this differently... */
- else {
- HPI_DEBUG_LOG(ERROR,
- "interrupt from HIF <data> BAD\n");
- err = HPI_ERROR_DSP_HARDWARE;
- }
-
- /* reset the interrupt from the DSP */
- iowrite32(C6205_HSR_INTSRC, phw->prHSR);
-#endif
if (operation == H620_HIF_GET_DATA)
memcpy(&p_data[data_transferred],
(void *)&interface->u.b_data[0], this_copy);
@@ -2174,31 +2077,39 @@ static unsigned int message_count;
static u16 message_response_sequence(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr)
{
-#ifndef HPI6205_NO_HSR_POLL
- u32 temp2;
-#endif
u32 time_out, time_out2;
struct hpi_hw_obj *phw = pao->priv;
struct bus_master_interface *interface = phw->p_interface_buffer;
u16 err = 0;
message_count++;
+ if (phm->size > sizeof(interface->u)) {
+ phr->error = HPI_ERROR_MESSAGE_BUFFER_TOO_SMALL;
+ phr->specific_error = sizeof(interface->u);
+ phr->size = sizeof(struct hpi_response_header);
+ HPI_DEBUG_LOG(ERROR,
+ "message len %d too big for buffer %zd \n", phm->size,
+ sizeof(interface->u));
+ return 0;
+ }
+
/* Assume buffer of type struct bus_master_interface
is allocated "noncacheable" */
if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
HPI_DEBUG_LOG(DEBUG, "timeout waiting for idle\n");
- return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
+ return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
}
- interface->u.message_buffer = *phm;
+
+ memcpy(&interface->u.message_buffer, phm, phm->size);
/* signal we want a response */
send_dsp_command(phw, H620_HIF_GET_RESP);
time_out2 = wait_dsp_ack(phw, H620_HIF_GET_RESP, HPI6205_TIMEOUT);
- if (time_out2 == 0) {
+ if (!time_out2) {
HPI_DEBUG_LOG(ERROR,
- "(%u) timed out waiting for " "GET_RESP state [%x]\n",
+ "(%u) Timed out waiting for " "GET_RESP state [%x]\n",
message_count, interface->dsp_ack);
} else {
HPI_DEBUG_LOG(VERBOSE,
@@ -2208,58 +2119,38 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
/* spin waiting on HIF interrupt flag (end of msg process) */
time_out = HPI6205_TIMEOUT;
-#ifndef HPI6205_NO_HSR_POLL
- temp2 = 0;
- while ((temp2 == 0) && --time_out) {
- temp2 = ioread32(phw->prHSR);
- temp2 &= C6205_HSR_INTSRC;
- hpios_delay_micro_seconds(1);
- }
- if (temp2 == C6205_HSR_INTSRC) {
- rmb(); /* ensure we see latest value for dsp_ack */
- if ((interface->dsp_ack != H620_HIF_GET_RESP)) {
- HPI_DEBUG_LOG(DEBUG,
- "(%u)interface->dsp_ack(0x%x) != "
- "H620_HIF_GET_RESP, t=%u\n", message_count,
- interface->dsp_ack,
- HPI6205_TIMEOUT - time_out);
- } else {
- HPI_DEBUG_LOG(VERBOSE,
- "(%u)int with GET_RESP after %u\n",
- message_count, HPI6205_TIMEOUT - time_out);
+ /* read the result */
+ if (time_out) {
+ if (interface->u.response_buffer.size <= phr->size)
+ memcpy(phr, &interface->u.response_buffer,
+ interface->u.response_buffer.size);
+ else {
+ HPI_DEBUG_LOG(ERROR,
+ "response len %d too big for buffer %d\n",
+ interface->u.response_buffer.size, phr->size);
+ memcpy(phr, &interface->u.response_buffer,
+ sizeof(struct hpi_response_header));
+ phr->error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
+ phr->specific_error =
+ interface->u.response_buffer.size;
+ phr->size = sizeof(struct hpi_response_header);
}
-
- } else {
- /* can we do anything else in response to the error ? */
- HPI_DEBUG_LOG(ERROR,
- "interrupt from HIF module BAD (function %x)\n",
- phm->function);
}
-
- /* reset the interrupt from the DSP */
- iowrite32(C6205_HSR_INTSRC, phw->prHSR);
-#endif
-
- /* read the result */
- if (time_out != 0)
- *phr = interface->u.response_buffer;
-
/* set interface back to idle */
send_dsp_command(phw, H620_HIF_IDLE);
- if ((time_out == 0) || (time_out2 == 0)) {
+ if (!time_out || !time_out2) {
HPI_DEBUG_LOG(DEBUG, "something timed out!\n");
- return hpi6205_error(0, HPI6205_ERROR_MSG_RESP_TIMEOUT);
+ return HPI6205_ERROR_MSG_RESP_TIMEOUT;
}
/* special case for adapter close - */
/* wait for the DSP to indicate it is idle */
if (phm->function == HPI_ADAPTER_CLOSE) {
if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
HPI_DEBUG_LOG(DEBUG,
- "timeout waiting for idle "
+ "Timeout waiting for idle "
"(on adapter_close)\n");
- return hpi6205_error(0,
- HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT);
+ return HPI6205_ERROR_MSG_RESP_IDLE_TIMEOUT;
}
}
err = hpi_validate_response(phm, phr);
@@ -2279,7 +2170,13 @@ static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,
/* maybe an error response */
if (err) {
/* something failed in the HPI/DSP interface */
- phr->error = err;
+ if (err >= HPI_ERROR_BACKEND_BASE) {
+ phr->error = HPI_ERROR_DSP_COMMUNICATION;
+ phr->specific_error = err;
+ } else {
+ phr->error = err;
+ }
+
pao->dsp_crashed++;
/* just the header of the response is valid */
diff --git a/sound/pci/asihpi/hpi6205.h b/sound/pci/asihpi/hpi6205.h
index 1adae0857cda..df2f02c0c7b4 100644
--- a/sound/pci/asihpi/hpi6205.h
+++ b/sound/pci/asihpi/hpi6205.h
@@ -25,9 +25,6 @@ Copyright AudioScience, Inc., 2003
#ifndef _HPI6205_H_
#define _HPI6205_H_
-/* transitional conditional compile shared between host and DSP */
-/* #define HPI6205_NO_HSR_POLL */
-
#include "hpi_internal.h"
/***********************************************************
@@ -78,8 +75,8 @@ struct bus_master_interface {
u32 dsp_ack;
u32 transfer_size_in_bytes;
union {
- struct hpi_message message_buffer;
- struct hpi_response response_buffer;
+ struct hpi_message_header message_buffer;
+ struct hpi_response_header response_buffer;
u8 b_data[HPI6205_SIZEOF_DATA];
} u;
struct controlcache_6205 control_cache;
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index 16f502d459de..af678be0aa15 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -28,7 +28,7 @@ HPI internal definitions
/** maximum number of memory regions mapped to an adapter */
#define HPI_MAX_ADAPTER_MEM_SPACES (2)
-/* Each OS needs its own hpios.h, or specific define as above */
+/* Each OS needs its own hpios.h */
#include "hpios.h"
/* physical memory allocation */
@@ -49,7 +49,7 @@ HpiOs_LockedMem_GetPyhsAddr() will always succed on the returned handle.
*/
u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle,
/**< memory handle */
- u32 size, /**< size in bytes to allocate */
+ u32 size, /**< Size in bytes to allocate */
struct pci_dev *p_os_reference
/**< OS specific data required for memory allocation */
);
@@ -96,41 +96,6 @@ typedef void hpi_handler_func(struct hpi_message *, struct hpi_response *);
#define compile_time_assert(cond, msg) \
typedef char ASSERT_##msg[(cond) ? 1 : -1]
-/*/////////////////////////////////////////////////////////////////////////// */
-/* Private HPI Entity related definitions */
-
-#define STR_SIZE_FIELD_MAX 65535U
-#define STR_TYPE_FIELD_MAX 255U
-#define STR_ROLE_FIELD_MAX 255U
-
-struct hpi_entity_str {
- u16 size;
- u8 type;
- u8 role;
-};
-
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable : 4200)
-#endif
-
-struct hpi_entity {
- struct hpi_entity_str header;
-#if ! defined(HPI_OS_DSP_C6000) || (defined(HPI_OS_DSP_C6000) && (__TI_COMPILER_VERSION__ > 6000008))
- /* DSP C6000 compiler v6.0.8 and lower
- do not support flexible array member */
- u8 value[];
-#else
- /* NOTE! Using sizeof(struct hpi_entity) will give erroneous results */
-#define HPI_INTERNAL_WARN_ABOUT_ENTITY_VALUE
- u8 value[1];
-#endif
-};
-
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-
/******************************************* bus types */
enum HPI_BUSES {
HPI_BUS_ISAPNP = 1,
@@ -139,206 +104,155 @@ enum HPI_BUSES {
HPI_BUS_NET = 4
};
+enum HPI_SUBSYS_OPTIONS {
+ /* 0, 256 are invalid, 1..255 reserved for global options */
+ HPI_SUBSYS_OPT_NET_ENABLE = 257,
+ HPI_SUBSYS_OPT_NET_BROADCAST = 258,
+ HPI_SUBSYS_OPT_NET_UNICAST = 259,
+ HPI_SUBSYS_OPT_NET_ADDR = 260,
+ HPI_SUBSYS_OPT_NET_MASK = 261,
+ HPI_SUBSYS_OPT_NET_ADAPTER_ADDRESS_ADD = 262
+};
+
+/** Volume flags
+*/
+enum HPI_VOLUME_FLAGS {
+ /** Set if the volume control is muted */
+ HPI_VOLUME_FLAG_MUTED = (1 << 0),
+ /** Set if the volume control has a mute function */
+ HPI_VOLUME_FLAG_HAS_MUTE = (1 << 1),
+ /** Set if volume control can do autofading */
+ HPI_VOLUME_FLAG_HAS_AUTOFADE = (1 << 2)
+ /* Note Flags >= (1<<8) are for DSP internal use only */
+};
+
/******************************************* CONTROL ATTRIBUTES ****/
/* (in order of control type ID */
/* This allows for 255 control types, 256 unique attributes each */
-#define HPI_CTL_ATTR(ctl, ai) (HPI_CONTROL_##ctl * 0x100 + ai)
+#define HPI_CTL_ATTR(ctl, ai) ((HPI_CONTROL_##ctl << 8) + ai)
/* Get the sub-index of the attribute for a control type */
-#define HPI_CTL_ATTR_INDEX(i) (i&0xff)
+#define HPI_CTL_ATTR_INDEX(i) (i & 0xff)
/* Extract the control from the control attribute */
-#define HPI_CTL_ATTR_CONTROL(i) (i>>8)
-
-/* Generic control attributes. */
-
-/** Enable a control.
-0=disable, 1=enable
-\note generic to all mixer plugins?
-*/
-#define HPI_GENERIC_ENABLE HPI_CTL_ATTR(GENERIC, 1)
+#define HPI_CTL_ATTR_CONTROL(i) (i >> 8)
/** Enable event generation for a control.
0=disable, 1=enable
\note generic to all controls that can generate events
*/
-#define HPI_GENERIC_EVENT_ENABLE HPI_CTL_ATTR(GENERIC, 2)
-
-/* Volume Control attributes */
-#define HPI_VOLUME_GAIN HPI_CTL_ATTR(VOLUME, 1)
-#define HPI_VOLUME_AUTOFADE HPI_CTL_ATTR(VOLUME, 2)
-
-/** For HPI_ControlQuery() to get the number of channels of a volume control*/
-#define HPI_VOLUME_NUM_CHANNELS HPI_CTL_ATTR(VOLUME, 6)
-#define HPI_VOLUME_RANGE HPI_CTL_ATTR(VOLUME, 10)
-
-/** Level Control attributes */
-#define HPI_LEVEL_GAIN HPI_CTL_ATTR(LEVEL, 1)
-#define HPI_LEVEL_RANGE HPI_CTL_ATTR(LEVEL, 10)
-
-/* Meter Control attributes */
-/** return RMS signal level */
-#define HPI_METER_RMS HPI_CTL_ATTR(METER, 1)
-/** return peak signal level */
-#define HPI_METER_PEAK HPI_CTL_ATTR(METER, 2)
-/** ballistics for ALL rms meters on adapter */
-#define HPI_METER_RMS_BALLISTICS HPI_CTL_ATTR(METER, 3)
-/** ballistics for ALL peak meters on adapter */
-#define HPI_METER_PEAK_BALLISTICS HPI_CTL_ATTR(METER, 4)
-
-/** For HPI_ControlQuery() to get the number of channels of a meter control*/
-#define HPI_METER_NUM_CHANNELS HPI_CTL_ATTR(METER, 5)
-
-/* Multiplexer control attributes */
-#define HPI_MULTIPLEXER_SOURCE HPI_CTL_ATTR(MULTIPLEXER, 1)
-#define HPI_MULTIPLEXER_QUERYSOURCE HPI_CTL_ATTR(MULTIPLEXER, 2)
-
-/** AES/EBU transmitter control attributes */
-/** AESEBU or SPDIF */
-#define HPI_AESEBUTX_FORMAT HPI_CTL_ATTR(AESEBUTX, 1)
-#define HPI_AESEBUTX_SAMPLERATE HPI_CTL_ATTR(AESEBUTX, 3)
-#define HPI_AESEBUTX_CHANNELSTATUS HPI_CTL_ATTR(AESEBUTX, 4)
-#define HPI_AESEBUTX_USERDATA HPI_CTL_ATTR(AESEBUTX, 5)
-
-/** AES/EBU receiver control attributes */
-#define HPI_AESEBURX_FORMAT HPI_CTL_ATTR(AESEBURX, 1)
-#define HPI_AESEBURX_ERRORSTATUS HPI_CTL_ATTR(AESEBURX, 2)
-#define HPI_AESEBURX_SAMPLERATE HPI_CTL_ATTR(AESEBURX, 3)
-#define HPI_AESEBURX_CHANNELSTATUS HPI_CTL_ATTR(AESEBURX, 4)
-#define HPI_AESEBURX_USERDATA HPI_CTL_ATTR(AESEBURX, 5)
-
-/** \defgroup tuner_defs Tuners
-\{
-*/
-/** \defgroup tuner_attrs Tuner control attributes
-\{
-*/
-#define HPI_TUNER_BAND HPI_CTL_ATTR(TUNER, 1)
-#define HPI_TUNER_FREQ HPI_CTL_ATTR(TUNER, 2)
-#define HPI_TUNER_LEVEL HPI_CTL_ATTR(TUNER, 3)
-#define HPI_TUNER_AUDIOMUTE HPI_CTL_ATTR(TUNER, 4)
-/* use TUNER_STATUS instead */
-#define HPI_TUNER_VIDEO_STATUS HPI_CTL_ATTR(TUNER, 5)
-#define HPI_TUNER_GAIN HPI_CTL_ATTR(TUNER, 6)
-#define HPI_TUNER_STATUS HPI_CTL_ATTR(TUNER, 7)
-#define HPI_TUNER_MODE HPI_CTL_ATTR(TUNER, 8)
-/** RDS data. */
-#define HPI_TUNER_RDS HPI_CTL_ATTR(TUNER, 9)
-/** Audio pre-emphasis. */
-#define HPI_TUNER_DEEMPHASIS HPI_CTL_ATTR(TUNER, 10)
-/** HD Radio tuner program control. */
-#define HPI_TUNER_PROGRAM HPI_CTL_ATTR(TUNER, 11)
-/** HD Radio tuner digital signal quality. */
-#define HPI_TUNER_HDRADIO_SIGNAL_QUALITY HPI_CTL_ATTR(TUNER, 12)
-/** HD Radio SDK firmware version. */
-#define HPI_TUNER_HDRADIO_SDK_VERSION HPI_CTL_ATTR(TUNER, 13)
-/** HD Radio DSP firmware version. */
-#define HPI_TUNER_HDRADIO_DSP_VERSION HPI_CTL_ATTR(TUNER, 14)
-/** HD Radio signal blend (force analog, or automatic). */
-#define HPI_TUNER_HDRADIO_BLEND HPI_CTL_ATTR(TUNER, 15)
-
-/** \} */
-
-/** \defgroup pads_attrs Tuner PADs control attributes
-\{
-*/
-/** The text string containing the station/channel combination. */
-#define HPI_PAD_CHANNEL_NAME HPI_CTL_ATTR(PAD, 1)
-/** The text string containing the artist. */
-#define HPI_PAD_ARTIST HPI_CTL_ATTR(PAD, 2)
-/** The text string containing the title. */
-#define HPI_PAD_TITLE HPI_CTL_ATTR(PAD, 3)
-/** The text string containing the comment. */
-#define HPI_PAD_COMMENT HPI_CTL_ATTR(PAD, 4)
-/** The integer containing the PTY code. */
-#define HPI_PAD_PROGRAM_TYPE HPI_CTL_ATTR(PAD, 5)
-/** The integer containing the program identification. */
-#define HPI_PAD_PROGRAM_ID HPI_CTL_ATTR(PAD, 6)
-/** The integer containing whether traffic information is supported.
-Contains either 1 or 0. */
-#define HPI_PAD_TA_SUPPORT HPI_CTL_ATTR(PAD, 7)
-/** The integer containing whether traffic announcement is in progress.
-Contains either 1 or 0. */
-#define HPI_PAD_TA_ACTIVE HPI_CTL_ATTR(PAD, 8)
-/** \} */
-/** \} */
-
-/* VOX control attributes */
-#define HPI_VOX_THRESHOLD HPI_CTL_ATTR(VOX, 1)
-
-/*?? channel mode used hpi_multiplexer_source attribute == 1 */
-#define HPI_CHANNEL_MODE_MODE HPI_CTL_ATTR(CHANNEL_MODE, 1)
-
-/** \defgroup channel_modes Channel Modes
-Used for HPI_ChannelModeSet/Get()
-\{
+
+/** Unique identifiers for every control attribute
*/
-/** Left channel out = left channel in, Right channel out = right channel in. */
-#define HPI_CHANNEL_MODE_NORMAL 1
-/** Left channel out = right channel in, Right channel out = left channel in. */
-#define HPI_CHANNEL_MODE_SWAP 2
-/** Left channel out = left channel in, Right channel out = left channel in. */
-#define HPI_CHANNEL_MODE_LEFT_TO_STEREO 3
-/** Left channel out = right channel in, Right channel out = right channel in.*/
-#define HPI_CHANNEL_MODE_RIGHT_TO_STEREO 4
-/** Left channel out = (left channel in + right channel in)/2,
- Right channel out = mute. */
-#define HPI_CHANNEL_MODE_STEREO_TO_LEFT 5
-/** Left channel out = mute,
- Right channel out = (right channel in + left channel in)/2. */
-#define HPI_CHANNEL_MODE_STEREO_TO_RIGHT 6
-#define HPI_CHANNEL_MODE_LAST 6
-/** \} */
-
-/* Bitstream control set attributes */
-#define HPI_BITSTREAM_DATA_POLARITY HPI_CTL_ATTR(BITSTREAM, 1)
-#define HPI_BITSTREAM_CLOCK_EDGE HPI_CTL_ATTR(BITSTREAM, 2)
-#define HPI_BITSTREAM_CLOCK_SOURCE HPI_CTL_ATTR(BITSTREAM, 3)
+enum HPI_CONTROL_ATTRIBUTES {
+ HPI_GENERIC_ENABLE = HPI_CTL_ATTR(GENERIC, 1),
+ HPI_GENERIC_EVENT_ENABLE = HPI_CTL_ATTR(GENERIC, 2),
+
+ HPI_VOLUME_GAIN = HPI_CTL_ATTR(VOLUME, 1),
+ HPI_VOLUME_AUTOFADE = HPI_CTL_ATTR(VOLUME, 2),
+ HPI_VOLUME_MUTE = HPI_CTL_ATTR(VOLUME, 3),
+ HPI_VOLUME_GAIN_AND_FLAGS = HPI_CTL_ATTR(VOLUME, 4),
+ HPI_VOLUME_NUM_CHANNELS = HPI_CTL_ATTR(VOLUME, 6),
+ HPI_VOLUME_RANGE = HPI_CTL_ATTR(VOLUME, 10),
+
+ HPI_METER_RMS = HPI_CTL_ATTR(METER, 1),
+ HPI_METER_PEAK = HPI_CTL_ATTR(METER, 2),
+ HPI_METER_RMS_BALLISTICS = HPI_CTL_ATTR(METER, 3),
+ HPI_METER_PEAK_BALLISTICS = HPI_CTL_ATTR(METER, 4),
+ HPI_METER_NUM_CHANNELS = HPI_CTL_ATTR(METER, 5),
+
+ HPI_MULTIPLEXER_SOURCE = HPI_CTL_ATTR(MULTIPLEXER, 1),
+ HPI_MULTIPLEXER_QUERYSOURCE = HPI_CTL_ATTR(MULTIPLEXER, 2),
+
+ HPI_AESEBUTX_FORMAT = HPI_CTL_ATTR(AESEBUTX, 1),
+ HPI_AESEBUTX_SAMPLERATE = HPI_CTL_ATTR(AESEBUTX, 3),
+ HPI_AESEBUTX_CHANNELSTATUS = HPI_CTL_ATTR(AESEBUTX, 4),
+ HPI_AESEBUTX_USERDATA = HPI_CTL_ATTR(AESEBUTX, 5),
+
+ HPI_AESEBURX_FORMAT = HPI_CTL_ATTR(AESEBURX, 1),
+ HPI_AESEBURX_ERRORSTATUS = HPI_CTL_ATTR(AESEBURX, 2),
+ HPI_AESEBURX_SAMPLERATE = HPI_CTL_ATTR(AESEBURX, 3),
+ HPI_AESEBURX_CHANNELSTATUS = HPI_CTL_ATTR(AESEBURX, 4),
+ HPI_AESEBURX_USERDATA = HPI_CTL_ATTR(AESEBURX, 5),
+
+ HPI_LEVEL_GAIN = HPI_CTL_ATTR(LEVEL, 1),
+ HPI_LEVEL_RANGE = HPI_CTL_ATTR(LEVEL, 10),
+
+ HPI_TUNER_BAND = HPI_CTL_ATTR(TUNER, 1),
+ HPI_TUNER_FREQ = HPI_CTL_ATTR(TUNER, 2),
+ HPI_TUNER_LEVEL_AVG = HPI_CTL_ATTR(TUNER, 3),
+ HPI_TUNER_LEVEL_RAW = HPI_CTL_ATTR(TUNER, 4),
+ HPI_TUNER_SNR = HPI_CTL_ATTR(TUNER, 5),
+ HPI_TUNER_GAIN = HPI_CTL_ATTR(TUNER, 6),
+ HPI_TUNER_STATUS = HPI_CTL_ATTR(TUNER, 7),
+ HPI_TUNER_MODE = HPI_CTL_ATTR(TUNER, 8),
+ HPI_TUNER_RDS = HPI_CTL_ATTR(TUNER, 9),
+ HPI_TUNER_DEEMPHASIS = HPI_CTL_ATTR(TUNER, 10),
+ HPI_TUNER_PROGRAM = HPI_CTL_ATTR(TUNER, 11),
+ HPI_TUNER_HDRADIO_SIGNAL_QUALITY = HPI_CTL_ATTR(TUNER, 12),
+ HPI_TUNER_HDRADIO_SDK_VERSION = HPI_CTL_ATTR(TUNER, 13),
+ HPI_TUNER_HDRADIO_DSP_VERSION = HPI_CTL_ATTR(TUNER, 14),
+ HPI_TUNER_HDRADIO_BLEND = HPI_CTL_ATTR(TUNER, 15),
+
+ HPI_VOX_THRESHOLD = HPI_CTL_ATTR(VOX, 1),
+
+ HPI_CHANNEL_MODE_MODE = HPI_CTL_ATTR(CHANNEL_MODE, 1),
+
+ HPI_BITSTREAM_DATA_POLARITY = HPI_CTL_ATTR(BITSTREAM, 1),
+ HPI_BITSTREAM_CLOCK_EDGE = HPI_CTL_ATTR(BITSTREAM, 2),
+ HPI_BITSTREAM_CLOCK_SOURCE = HPI_CTL_ATTR(BITSTREAM, 3),
+ HPI_BITSTREAM_ACTIVITY = HPI_CTL_ATTR(BITSTREAM, 4),
+
+ HPI_SAMPLECLOCK_SOURCE = HPI_CTL_ATTR(SAMPLECLOCK, 1),
+ HPI_SAMPLECLOCK_SAMPLERATE = HPI_CTL_ATTR(SAMPLECLOCK, 2),
+ HPI_SAMPLECLOCK_SOURCE_INDEX = HPI_CTL_ATTR(SAMPLECLOCK, 3),
+ HPI_SAMPLECLOCK_LOCAL_SAMPLERATE = HPI_CTL_ATTR(SAMPLECLOCK, 4),
+ HPI_SAMPLECLOCK_AUTO = HPI_CTL_ATTR(SAMPLECLOCK, 5),
+ HPI_SAMPLECLOCK_LOCAL_LOCK = HPI_CTL_ATTR(SAMPLECLOCK, 6),
+
+ HPI_MICROPHONE_PHANTOM_POWER = HPI_CTL_ATTR(MICROPHONE, 1),
+
+ HPI_EQUALIZER_NUM_FILTERS = HPI_CTL_ATTR(EQUALIZER, 1),
+ HPI_EQUALIZER_FILTER = HPI_CTL_ATTR(EQUALIZER, 2),
+ HPI_EQUALIZER_COEFFICIENTS = HPI_CTL_ATTR(EQUALIZER, 3),
+
+ HPI_COMPANDER_PARAMS = HPI_CTL_ATTR(COMPANDER, 1),
+ HPI_COMPANDER_MAKEUPGAIN = HPI_CTL_ATTR(COMPANDER, 2),
+ HPI_COMPANDER_THRESHOLD = HPI_CTL_ATTR(COMPANDER, 3),
+ HPI_COMPANDER_RATIO = HPI_CTL_ATTR(COMPANDER, 4),
+ HPI_COMPANDER_ATTACK = HPI_CTL_ATTR(COMPANDER, 5),
+ HPI_COMPANDER_DECAY = HPI_CTL_ATTR(COMPANDER, 6),
+
+ HPI_COBRANET_SET = HPI_CTL_ATTR(COBRANET, 1),
+ HPI_COBRANET_GET = HPI_CTL_ATTR(COBRANET, 2),
+ HPI_COBRANET_SET_DATA = HPI_CTL_ATTR(COBRANET, 3),
+ HPI_COBRANET_GET_DATA = HPI_CTL_ATTR(COBRANET, 4),
+ HPI_COBRANET_GET_STATUS = HPI_CTL_ATTR(COBRANET, 5),
+ HPI_COBRANET_SEND_PACKET = HPI_CTL_ATTR(COBRANET, 6),
+ HPI_COBRANET_GET_PACKET = HPI_CTL_ATTR(COBRANET, 7),
+
+ HPI_TONEDETECTOR_THRESHOLD = HPI_CTL_ATTR(TONEDETECTOR, 1),
+ HPI_TONEDETECTOR_STATE = HPI_CTL_ATTR(TONEDETECTOR, 2),
+ HPI_TONEDETECTOR_FREQUENCY = HPI_CTL_ATTR(TONEDETECTOR, 3),
+
+ HPI_SILENCEDETECTOR_THRESHOLD = HPI_CTL_ATTR(SILENCEDETECTOR, 1),
+ HPI_SILENCEDETECTOR_STATE = HPI_CTL_ATTR(SILENCEDETECTOR, 2),
+ HPI_SILENCEDETECTOR_DELAY = HPI_CTL_ATTR(SILENCEDETECTOR, 3),
+
+ HPI_PAD_CHANNEL_NAME = HPI_CTL_ATTR(PAD, 1),
+ HPI_PAD_ARTIST = HPI_CTL_ATTR(PAD, 2),
+ HPI_PAD_TITLE = HPI_CTL_ATTR(PAD, 3),
+ HPI_PAD_COMMENT = HPI_CTL_ATTR(PAD, 4),
+ HPI_PAD_PROGRAM_TYPE = HPI_CTL_ATTR(PAD, 5),
+ HPI_PAD_PROGRAM_ID = HPI_CTL_ATTR(PAD, 6),
+ HPI_PAD_TA_SUPPORT = HPI_CTL_ATTR(PAD, 7),
+ HPI_PAD_TA_ACTIVE = HPI_CTL_ATTR(PAD, 8)
+};
#define HPI_POLARITY_POSITIVE 0
#define HPI_POLARITY_NEGATIVE 1
-/* Bitstream control get attributes */
-#define HPI_BITSTREAM_ACTIVITY 1
-
-/* SampleClock control attributes */
-#define HPI_SAMPLECLOCK_SOURCE HPI_CTL_ATTR(SAMPLECLOCK, 1)
-#define HPI_SAMPLECLOCK_SAMPLERATE HPI_CTL_ATTR(SAMPLECLOCK, 2)
-#define HPI_SAMPLECLOCK_SOURCE_INDEX HPI_CTL_ATTR(SAMPLECLOCK, 3)
-#define HPI_SAMPLECLOCK_LOCAL_SAMPLERATE\
- HPI_CTL_ATTR(SAMPLECLOCK, 4)
-#define HPI_SAMPLECLOCK_AUTO HPI_CTL_ATTR(SAMPLECLOCK, 5)
-#define HPI_SAMPLECLOCK_LOCAL_LOCK HPI_CTL_ATTR(SAMPLECLOCK, 6)
-
-/* Microphone control attributes */
-#define HPI_MICROPHONE_PHANTOM_POWER HPI_CTL_ATTR(MICROPHONE, 1)
-
-/** Equalizer control attributes */
-/** Used to get number of filters in an EQ. (Can't set) */
-#define HPI_EQUALIZER_NUM_FILTERS HPI_CTL_ATTR(EQUALIZER, 1)
-/** Set/get the filter by type, freq, Q, gain */
-#define HPI_EQUALIZER_FILTER HPI_CTL_ATTR(EQUALIZER, 2)
-/** Get the biquad coefficients */
-#define HPI_EQUALIZER_COEFFICIENTS HPI_CTL_ATTR(EQUALIZER, 3)
-
-/* Note compander also uses HPI_GENERIC_ENABLE */
-#define HPI_COMPANDER_PARAMS HPI_CTL_ATTR(COMPANDER, 1)
-#define HPI_COMPANDER_MAKEUPGAIN HPI_CTL_ATTR(COMPANDER, 2)
-#define HPI_COMPANDER_THRESHOLD HPI_CTL_ATTR(COMPANDER, 3)
-#define HPI_COMPANDER_RATIO HPI_CTL_ATTR(COMPANDER, 4)
-#define HPI_COMPANDER_ATTACK HPI_CTL_ATTR(COMPANDER, 5)
-#define HPI_COMPANDER_DECAY HPI_CTL_ATTR(COMPANDER, 6)
-
-/* Cobranet control attributes. */
-#define HPI_COBRANET_SET HPI_CTL_ATTR(COBRANET, 1)
-#define HPI_COBRANET_GET HPI_CTL_ATTR(COBRANET, 2)
-#define HPI_COBRANET_SET_DATA HPI_CTL_ATTR(COBRANET, 3)
-#define HPI_COBRANET_GET_DATA HPI_CTL_ATTR(COBRANET, 4)
-#define HPI_COBRANET_GET_STATUS HPI_CTL_ATTR(COBRANET, 5)
-#define HPI_COBRANET_SEND_PACKET HPI_CTL_ATTR(COBRANET, 6)
-#define HPI_COBRANET_GET_PACKET HPI_CTL_ATTR(COBRANET, 7)
-
/*------------------------------------------------------------
Cobranet Chip Bridge - copied from HMI.H
------------------------------------------------------------*/
@@ -395,69 +309,22 @@ Used for HPI_ChannelModeSet/Get()
#define HPI_ETHERNET_UDP_PORT (44600) /*!< UDP messaging port */
-/** Base network time out is set to 100 milli-seconds. */
-#define HPI_ETHERNET_TIMEOUT_MS (100)
-
-/** \defgroup tonedet_attr Tonedetector attributes
-\{
-Used by HPI_ToneDetector_Set() and HPI_ToneDetector_Get()
-*/
-
-/** Set the threshold level of a tonedetector,
-Threshold is a -ve number in units of dB/100,
-*/
-#define HPI_TONEDETECTOR_THRESHOLD HPI_CTL_ATTR(TONEDETECTOR, 1)
-
-/** Get the current state of tonedetection
-The result is a bitmap of detected tones. pairs of bits represent the left
-and right channels, with left channel in LSB.
-The lowest frequency detector state is in the LSB
-*/
-#define HPI_TONEDETECTOR_STATE HPI_CTL_ATTR(TONEDETECTOR, 2)
-
-/** Get the frequency of a tonedetector band.
-*/
-#define HPI_TONEDETECTOR_FREQUENCY HPI_CTL_ATTR(TONEDETECTOR, 3)
-
-/**\}*/
+/** Default network timeout in milli-seconds. */
+#define HPI_ETHERNET_TIMEOUT_MS 500
-/** \defgroup silencedet_attr SilenceDetector attributes
-\{
-*/
-
-/** Get the current state of tonedetection
-The result is a bitmap with 1s for silent channels. Left channel is in LSB
-*/
-#define HPI_SILENCEDETECTOR_STATE \
- HPI_CTL_ATTR(SILENCEDETECTOR, 2)
-
-/** Set the threshold level of a SilenceDetector,
-Threshold is a -ve number in units of dB/100,
-*/
-#define HPI_SILENCEDETECTOR_THRESHOLD \
- HPI_CTL_ATTR(SILENCEDETECTOR, 1)
-
-/** get/set the silence time before the detector triggers
-*/
-#define HPI_SILENCEDETECTOR_DELAY \
- HPI_CTL_ATTR(SILENCEDETECTOR, 3)
-
-/**\}*/
-
-/* Locked memory buffer alloc/free phases */
-/** use one message to allocate or free physical memory */
-#define HPI_BUFFER_CMD_EXTERNAL 0
-/** alloc physical memory */
-#define HPI_BUFFER_CMD_INTERNAL_ALLOC 1
-/** send physical memory address to adapter */
-#define HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER 2
-/** notify adapter to stop using physical buffer */
-#define HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER 3
-/** free physical buffer */
-#define HPI_BUFFER_CMD_INTERNAL_FREE 4
-
-/******************************************* CONTROLX ATTRIBUTES ****/
-/* NOTE: All controlx attributes must be unique, unlike control attributes */
+/** Locked memory buffer alloc/free phases */
+enum HPI_BUFFER_CMDS {
+ /** use one message to allocate or free physical memory */
+ HPI_BUFFER_CMD_EXTERNAL = 0,
+ /** alloc physical memory */
+ HPI_BUFFER_CMD_INTERNAL_ALLOC = 1,
+ /** send physical memory address to adapter */
+ HPI_BUFFER_CMD_INTERNAL_GRANTADAPTER = 2,
+ /** notify adapter to stop using physical buffer */
+ HPI_BUFFER_CMD_INTERNAL_REVOKEADAPTER = 3,
+ /** free physical buffer */
+ HPI_BUFFER_CMD_INTERNAL_FREE = 4
+};
/*****************************************************************************/
/*****************************************************************************/
@@ -482,6 +349,12 @@ Threshold is a -ve number in units of dB/100,
#define HPI_USB_W2K_TAG 0x57495341 /* "ASIW" */
#define HPI_USB_LINUX_TAG 0x4C495341 /* "ASIL" */
+/** Invalid Adapter index
+Used in HPI messages that are not addressed to a specific adapter
+Used in DLL to indicate device not present
+*/
+#define HPI_ADAPTER_INDEX_INVALID 0xFFFF
+
/** First 2 hex digits define the adapter family */
#define HPI_ADAPTER_FAMILY_MASK 0xff00
#define HPI_MODULE_FAMILY_MASK 0xfff0
@@ -490,178 +363,185 @@ Threshold is a -ve number in units of dB/100,
#define HPI_MODULE_FAMILY_ASI(f) (f & HPI_MODULE_FAMILY_MASK)
#define HPI_ADAPTER_ASI(f) (f)
-/******************************************* message types */
-#define HPI_TYPE_MESSAGE 1
-#define HPI_TYPE_RESPONSE 2
-#define HPI_TYPE_DATA 3
-#define HPI_TYPE_SSX2BYPASS_MESSAGE 4
-
-/******************************************* object types */
-#define HPI_OBJ_SUBSYSTEM 1
-#define HPI_OBJ_ADAPTER 2
-#define HPI_OBJ_OSTREAM 3
-#define HPI_OBJ_ISTREAM 4
-#define HPI_OBJ_MIXER 5
-#define HPI_OBJ_NODE 6
-#define HPI_OBJ_CONTROL 7
-#define HPI_OBJ_NVMEMORY 8
-#define HPI_OBJ_GPIO 9
-#define HPI_OBJ_WATCHDOG 10
-#define HPI_OBJ_CLOCK 11
-#define HPI_OBJ_PROFILE 12
-#define HPI_OBJ_CONTROLEX 13
-#define HPI_OBJ_ASYNCEVENT 14
-
-#define HPI_OBJ_MAXINDEX 14
-
-/******************************************* methods/functions */
-
-#define HPI_OBJ_FUNCTION_SPACING 0x100
-#define HPI_MAKE_INDEX(obj, index) (obj * HPI_OBJ_FUNCTION_SPACING + index)
+enum HPI_MESSAGE_TYPES {
+ HPI_TYPE_MESSAGE = 1,
+ HPI_TYPE_RESPONSE = 2,
+ HPI_TYPE_DATA = 3,
+ HPI_TYPE_SSX2BYPASS_MESSAGE = 4
+};
+
+enum HPI_OBJECT_TYPES {
+ HPI_OBJ_SUBSYSTEM = 1,
+ HPI_OBJ_ADAPTER = 2,
+ HPI_OBJ_OSTREAM = 3,
+ HPI_OBJ_ISTREAM = 4,
+ HPI_OBJ_MIXER = 5,
+ HPI_OBJ_NODE = 6,
+ HPI_OBJ_CONTROL = 7,
+ HPI_OBJ_NVMEMORY = 8,
+ HPI_OBJ_GPIO = 9,
+ HPI_OBJ_WATCHDOG = 10,
+ HPI_OBJ_CLOCK = 11,
+ HPI_OBJ_PROFILE = 12,
+ HPI_OBJ_CONTROLEX = 13,
+ HPI_OBJ_ASYNCEVENT = 14
+#define HPI_OBJ_MAXINDEX 14
+};
+
+#define HPI_OBJ_FUNCTION_SPACING 0x100
+#define HPI_FUNC_ID(obj, i) (HPI_OBJ_##obj * HPI_OBJ_FUNCTION_SPACING + i)
+
#define HPI_EXTRACT_INDEX(fn) (fn & 0xff)
-/* SUB-SYSTEM */
-#define HPI_SUBSYS_OPEN HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 1)
-#define HPI_SUBSYS_GET_VERSION HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 2)
-#define HPI_SUBSYS_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 3)
-#define HPI_SUBSYS_FIND_ADAPTERS HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 4)
-#define HPI_SUBSYS_CREATE_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 5)
-#define HPI_SUBSYS_CLOSE HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 6)
-#define HPI_SUBSYS_DELETE_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 7)
-#define HPI_SUBSYS_DRIVER_LOAD HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 8)
-#define HPI_SUBSYS_DRIVER_UNLOAD HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 9)
-#define HPI_SUBSYS_READ_PORT_8 HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 10)
-#define HPI_SUBSYS_WRITE_PORT_8 HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 11)
-#define HPI_SUBSYS_GET_NUM_ADAPTERS HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 12)
-#define HPI_SUBSYS_GET_ADAPTER HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 13)
-#define HPI_SUBSYS_SET_NETWORK_INTERFACE HPI_MAKE_INDEX(HPI_OBJ_SUBSYSTEM, 14)
-#define HPI_SUBSYS_FUNCTION_COUNT 14
-/* ADAPTER */
-#define HPI_ADAPTER_OPEN HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 1)
-#define HPI_ADAPTER_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 2)
-#define HPI_ADAPTER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 3)
-#define HPI_ADAPTER_GET_ASSERT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 4)
-#define HPI_ADAPTER_TEST_ASSERT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 5)
-#define HPI_ADAPTER_SET_MODE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 6)
-#define HPI_ADAPTER_GET_MODE HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 7)
-#define HPI_ADAPTER_ENABLE_CAPABILITY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 8)
-#define HPI_ADAPTER_SELFTEST HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 9)
-#define HPI_ADAPTER_FIND_OBJECT HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 10)
-#define HPI_ADAPTER_QUERY_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 11)
-#define HPI_ADAPTER_START_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 12)
-#define HPI_ADAPTER_PROGRAM_FLASH HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 13)
-#define HPI_ADAPTER_SET_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 14)
-#define HPI_ADAPTER_GET_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 15)
-#define HPI_ADAPTER_ENUM_PROPERTY HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 16)
-#define HPI_ADAPTER_MODULE_INFO HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 17)
-#define HPI_ADAPTER_DEBUG_READ HPI_MAKE_INDEX(HPI_OBJ_ADAPTER, 18)
-#define HPI_ADAPTER_FUNCTION_COUNT 18
-/* OUTPUT STREAM */
-#define HPI_OSTREAM_OPEN HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 1)
-#define HPI_OSTREAM_CLOSE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 2)
-#define HPI_OSTREAM_WRITE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 3)
-#define HPI_OSTREAM_START HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 4)
-#define HPI_OSTREAM_STOP HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 5)
-#define HPI_OSTREAM_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 6)
-#define HPI_OSTREAM_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 7)
-#define HPI_OSTREAM_QUERY_FORMAT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 8)
-#define HPI_OSTREAM_DATA HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 9)
-#define HPI_OSTREAM_SET_VELOCITY HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 10)
-#define HPI_OSTREAM_SET_PUNCHINOUT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 11)
-#define HPI_OSTREAM_SINEGEN HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 12)
-#define HPI_OSTREAM_ANC_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 13)
-#define HPI_OSTREAM_ANC_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 14)
-#define HPI_OSTREAM_ANC_READ HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 15)
-#define HPI_OSTREAM_SET_TIMESCALE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 16)
-#define HPI_OSTREAM_SET_FORMAT HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 17)
-#define HPI_OSTREAM_HOSTBUFFER_ALLOC HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 18)
-#define HPI_OSTREAM_HOSTBUFFER_FREE HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 19)
-#define HPI_OSTREAM_GROUP_ADD HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 20)
-#define HPI_OSTREAM_GROUP_GETMAP HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 21)
-#define HPI_OSTREAM_GROUP_RESET HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 22)
-#define HPI_OSTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 23)
-#define HPI_OSTREAM_WAIT_START HPI_MAKE_INDEX(HPI_OBJ_OSTREAM, 24)
-#define HPI_OSTREAM_FUNCTION_COUNT 24
-/* INPUT STREAM */
-#define HPI_ISTREAM_OPEN HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 1)
-#define HPI_ISTREAM_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 2)
-#define HPI_ISTREAM_SET_FORMAT HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 3)
-#define HPI_ISTREAM_READ HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 4)
-#define HPI_ISTREAM_START HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 5)
-#define HPI_ISTREAM_STOP HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 6)
-#define HPI_ISTREAM_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 7)
-#define HPI_ISTREAM_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 8)
-#define HPI_ISTREAM_QUERY_FORMAT HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 9)
-#define HPI_ISTREAM_ANC_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 10)
-#define HPI_ISTREAM_ANC_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 11)
-#define HPI_ISTREAM_ANC_WRITE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 12)
-#define HPI_ISTREAM_HOSTBUFFER_ALLOC HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 13)
-#define HPI_ISTREAM_HOSTBUFFER_FREE HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 14)
-#define HPI_ISTREAM_GROUP_ADD HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 15)
-#define HPI_ISTREAM_GROUP_GETMAP HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 16)
-#define HPI_ISTREAM_GROUP_RESET HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 17)
-#define HPI_ISTREAM_HOSTBUFFER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 18)
-#define HPI_ISTREAM_WAIT_START HPI_MAKE_INDEX(HPI_OBJ_ISTREAM, 19)
-#define HPI_ISTREAM_FUNCTION_COUNT 19
-/* MIXER */
+enum HPI_FUNCTION_IDS {
+ HPI_SUBSYS_OPEN = HPI_FUNC_ID(SUBSYSTEM, 1),
+ HPI_SUBSYS_GET_VERSION = HPI_FUNC_ID(SUBSYSTEM, 2),
+ HPI_SUBSYS_GET_INFO = HPI_FUNC_ID(SUBSYSTEM, 3),
+ HPI_SUBSYS_FIND_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 4),
+ HPI_SUBSYS_CREATE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 5),
+ HPI_SUBSYS_CLOSE = HPI_FUNC_ID(SUBSYSTEM, 6),
+ HPI_SUBSYS_DELETE_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 7),
+ HPI_SUBSYS_DRIVER_LOAD = HPI_FUNC_ID(SUBSYSTEM, 8),
+ HPI_SUBSYS_DRIVER_UNLOAD = HPI_FUNC_ID(SUBSYSTEM, 9),
+ HPI_SUBSYS_READ_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 10),
+ HPI_SUBSYS_WRITE_PORT_8 = HPI_FUNC_ID(SUBSYSTEM, 11),
+ HPI_SUBSYS_GET_NUM_ADAPTERS = HPI_FUNC_ID(SUBSYSTEM, 12),
+ HPI_SUBSYS_GET_ADAPTER = HPI_FUNC_ID(SUBSYSTEM, 13),
+ HPI_SUBSYS_SET_NETWORK_INTERFACE = HPI_FUNC_ID(SUBSYSTEM, 14),
+ HPI_SUBSYS_OPTION_INFO = HPI_FUNC_ID(SUBSYSTEM, 15),
+ HPI_SUBSYS_OPTION_GET = HPI_FUNC_ID(SUBSYSTEM, 16),
+ HPI_SUBSYS_OPTION_SET = HPI_FUNC_ID(SUBSYSTEM, 17),
+#define HPI_SUBSYS_FUNCTION_COUNT 17
+
+ HPI_ADAPTER_OPEN = HPI_FUNC_ID(ADAPTER, 1),
+ HPI_ADAPTER_CLOSE = HPI_FUNC_ID(ADAPTER, 2),
+ HPI_ADAPTER_GET_INFO = HPI_FUNC_ID(ADAPTER, 3),
+ HPI_ADAPTER_GET_ASSERT = HPI_FUNC_ID(ADAPTER, 4),
+ HPI_ADAPTER_TEST_ASSERT = HPI_FUNC_ID(ADAPTER, 5),
+ HPI_ADAPTER_SET_MODE = HPI_FUNC_ID(ADAPTER, 6),
+ HPI_ADAPTER_GET_MODE = HPI_FUNC_ID(ADAPTER, 7),
+ HPI_ADAPTER_ENABLE_CAPABILITY = HPI_FUNC_ID(ADAPTER, 8),
+ HPI_ADAPTER_SELFTEST = HPI_FUNC_ID(ADAPTER, 9),
+ HPI_ADAPTER_FIND_OBJECT = HPI_FUNC_ID(ADAPTER, 10),
+ HPI_ADAPTER_QUERY_FLASH = HPI_FUNC_ID(ADAPTER, 11),
+ HPI_ADAPTER_START_FLASH = HPI_FUNC_ID(ADAPTER, 12),
+ HPI_ADAPTER_PROGRAM_FLASH = HPI_FUNC_ID(ADAPTER, 13),
+ HPI_ADAPTER_SET_PROPERTY = HPI_FUNC_ID(ADAPTER, 14),
+ HPI_ADAPTER_GET_PROPERTY = HPI_FUNC_ID(ADAPTER, 15),
+ HPI_ADAPTER_ENUM_PROPERTY = HPI_FUNC_ID(ADAPTER, 16),
+ HPI_ADAPTER_MODULE_INFO = HPI_FUNC_ID(ADAPTER, 17),
+ HPI_ADAPTER_DEBUG_READ = HPI_FUNC_ID(ADAPTER, 18),
+ HPI_ADAPTER_IRQ_QUERY_AND_CLEAR = HPI_FUNC_ID(ADAPTER, 19),
+ HPI_ADAPTER_IRQ_CALLBACK = HPI_FUNC_ID(ADAPTER, 20),
+#define HPI_ADAPTER_FUNCTION_COUNT 20
+
+ HPI_OSTREAM_OPEN = HPI_FUNC_ID(OSTREAM, 1),
+ HPI_OSTREAM_CLOSE = HPI_FUNC_ID(OSTREAM, 2),
+ HPI_OSTREAM_WRITE = HPI_FUNC_ID(OSTREAM, 3),
+ HPI_OSTREAM_START = HPI_FUNC_ID(OSTREAM, 4),
+ HPI_OSTREAM_STOP = HPI_FUNC_ID(OSTREAM, 5),
+ HPI_OSTREAM_RESET = HPI_FUNC_ID(OSTREAM, 6),
+ HPI_OSTREAM_GET_INFO = HPI_FUNC_ID(OSTREAM, 7),
+ HPI_OSTREAM_QUERY_FORMAT = HPI_FUNC_ID(OSTREAM, 8),
+ HPI_OSTREAM_DATA = HPI_FUNC_ID(OSTREAM, 9),
+ HPI_OSTREAM_SET_VELOCITY = HPI_FUNC_ID(OSTREAM, 10),
+ HPI_OSTREAM_SET_PUNCHINOUT = HPI_FUNC_ID(OSTREAM, 11),
+ HPI_OSTREAM_SINEGEN = HPI_FUNC_ID(OSTREAM, 12),
+ HPI_OSTREAM_ANC_RESET = HPI_FUNC_ID(OSTREAM, 13),
+ HPI_OSTREAM_ANC_GET_INFO = HPI_FUNC_ID(OSTREAM, 14),
+ HPI_OSTREAM_ANC_READ = HPI_FUNC_ID(OSTREAM, 15),
+ HPI_OSTREAM_SET_TIMESCALE = HPI_FUNC_ID(OSTREAM, 16),
+ HPI_OSTREAM_SET_FORMAT = HPI_FUNC_ID(OSTREAM, 17),
+ HPI_OSTREAM_HOSTBUFFER_ALLOC = HPI_FUNC_ID(OSTREAM, 18),
+ HPI_OSTREAM_HOSTBUFFER_FREE = HPI_FUNC_ID(OSTREAM, 19),
+ HPI_OSTREAM_GROUP_ADD = HPI_FUNC_ID(OSTREAM, 20),
+ HPI_OSTREAM_GROUP_GETMAP = HPI_FUNC_ID(OSTREAM, 21),
+ HPI_OSTREAM_GROUP_RESET = HPI_FUNC_ID(OSTREAM, 22),
+ HPI_OSTREAM_HOSTBUFFER_GET_INFO = HPI_FUNC_ID(OSTREAM, 23),
+ HPI_OSTREAM_WAIT_START = HPI_FUNC_ID(OSTREAM, 24),
+ HPI_OSTREAM_WAIT = HPI_FUNC_ID(OSTREAM, 25),
+#define HPI_OSTREAM_FUNCTION_COUNT 25
+
+ HPI_ISTREAM_OPEN = HPI_FUNC_ID(ISTREAM, 1),
+ HPI_ISTREAM_CLOSE = HPI_FUNC_ID(ISTREAM, 2),
+ HPI_ISTREAM_SET_FORMAT = HPI_FUNC_ID(ISTREAM, 3),
+ HPI_ISTREAM_READ = HPI_FUNC_ID(ISTREAM, 4),
+ HPI_ISTREAM_START = HPI_FUNC_ID(ISTREAM, 5),
+ HPI_ISTREAM_STOP = HPI_FUNC_ID(ISTREAM, 6),
+ HPI_ISTREAM_RESET = HPI_FUNC_ID(ISTREAM, 7),
+ HPI_ISTREAM_GET_INFO = HPI_FUNC_ID(ISTREAM, 8),
+ HPI_ISTREAM_QUERY_FORMAT = HPI_FUNC_ID(ISTREAM, 9),
+ HPI_ISTREAM_ANC_RESET = HPI_FUNC_ID(ISTREAM, 10),
+ HPI_ISTREAM_ANC_GET_INFO = HPI_FUNC_ID(ISTREAM, 11),
+ HPI_ISTREAM_ANC_WRITE = HPI_FUNC_ID(ISTREAM, 12),
+ HPI_ISTREAM_HOSTBUFFER_ALLOC = HPI_FUNC_ID(ISTREAM, 13),
+ HPI_ISTREAM_HOSTBUFFER_FREE = HPI_FUNC_ID(ISTREAM, 14),
+ HPI_ISTREAM_GROUP_ADD = HPI_FUNC_ID(ISTREAM, 15),
+ HPI_ISTREAM_GROUP_GETMAP = HPI_FUNC_ID(ISTREAM, 16),
+ HPI_ISTREAM_GROUP_RESET = HPI_FUNC_ID(ISTREAM, 17),
+ HPI_ISTREAM_HOSTBUFFER_GET_INFO = HPI_FUNC_ID(ISTREAM, 18),
+ HPI_ISTREAM_WAIT_START = HPI_FUNC_ID(ISTREAM, 19),
+ HPI_ISTREAM_WAIT = HPI_FUNC_ID(ISTREAM, 20),
+#define HPI_ISTREAM_FUNCTION_COUNT 20
+
/* NOTE:
GET_NODE_INFO, SET_CONNECTION, GET_CONNECTIONS are not currently used */
-#define HPI_MIXER_OPEN HPI_MAKE_INDEX(HPI_OBJ_MIXER, 1)
-#define HPI_MIXER_CLOSE HPI_MAKE_INDEX(HPI_OBJ_MIXER, 2)
-#define HPI_MIXER_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_MIXER, 3)
-#define HPI_MIXER_GET_NODE_INFO HPI_MAKE_INDEX(HPI_OBJ_MIXER, 4)
-#define HPI_MIXER_GET_CONTROL HPI_MAKE_INDEX(HPI_OBJ_MIXER, 5)
-#define HPI_MIXER_SET_CONNECTION HPI_MAKE_INDEX(HPI_OBJ_MIXER, 6)
-#define HPI_MIXER_GET_CONNECTIONS HPI_MAKE_INDEX(HPI_OBJ_MIXER, 7)
-#define HPI_MIXER_GET_CONTROL_BY_INDEX HPI_MAKE_INDEX(HPI_OBJ_MIXER, 8)
-#define HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX HPI_MAKE_INDEX(HPI_OBJ_MIXER, 9)
-#define HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES HPI_MAKE_INDEX(HPI_OBJ_MIXER, 10)
-#define HPI_MIXER_STORE HPI_MAKE_INDEX(HPI_OBJ_MIXER, 11)
-#define HPI_MIXER_FUNCTION_COUNT 11
-/* MIXER CONTROLS */
-#define HPI_CONTROL_GET_INFO HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 1)
-#define HPI_CONTROL_GET_STATE HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 2)
-#define HPI_CONTROL_SET_STATE HPI_MAKE_INDEX(HPI_OBJ_CONTROL, 3)
+ HPI_MIXER_OPEN = HPI_FUNC_ID(MIXER, 1),
+ HPI_MIXER_CLOSE = HPI_FUNC_ID(MIXER, 2),
+ HPI_MIXER_GET_INFO = HPI_FUNC_ID(MIXER, 3),
+ HPI_MIXER_GET_NODE_INFO = HPI_FUNC_ID(MIXER, 4),
+ HPI_MIXER_GET_CONTROL = HPI_FUNC_ID(MIXER, 5),
+ HPI_MIXER_SET_CONNECTION = HPI_FUNC_ID(MIXER, 6),
+ HPI_MIXER_GET_CONNECTIONS = HPI_FUNC_ID(MIXER, 7),
+ HPI_MIXER_GET_CONTROL_BY_INDEX = HPI_FUNC_ID(MIXER, 8),
+ HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX = HPI_FUNC_ID(MIXER, 9),
+ HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES = HPI_FUNC_ID(MIXER, 10),
+ HPI_MIXER_STORE = HPI_FUNC_ID(MIXER, 11),
+ HPI_MIXER_GET_CACHE_INFO = HPI_FUNC_ID(MIXER, 12),
+#define HPI_MIXER_FUNCTION_COUNT 12
+
+ HPI_CONTROL_GET_INFO = HPI_FUNC_ID(CONTROL, 1),
+ HPI_CONTROL_GET_STATE = HPI_FUNC_ID(CONTROL, 2),
+ HPI_CONTROL_SET_STATE = HPI_FUNC_ID(CONTROL, 3),
#define HPI_CONTROL_FUNCTION_COUNT 3
-/* NONVOL MEMORY */
-#define HPI_NVMEMORY_OPEN HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 1)
-#define HPI_NVMEMORY_READ_BYTE HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 2)
-#define HPI_NVMEMORY_WRITE_BYTE HPI_MAKE_INDEX(HPI_OBJ_NVMEMORY, 3)
+
+ HPI_NVMEMORY_OPEN = HPI_FUNC_ID(NVMEMORY, 1),
+ HPI_NVMEMORY_READ_BYTE = HPI_FUNC_ID(NVMEMORY, 2),
+ HPI_NVMEMORY_WRITE_BYTE = HPI_FUNC_ID(NVMEMORY, 3),
#define HPI_NVMEMORY_FUNCTION_COUNT 3
-/* GPIO */
-#define HPI_GPIO_OPEN HPI_MAKE_INDEX(HPI_OBJ_GPIO, 1)
-#define HPI_GPIO_READ_BIT HPI_MAKE_INDEX(HPI_OBJ_GPIO, 2)
-#define HPI_GPIO_WRITE_BIT HPI_MAKE_INDEX(HPI_OBJ_GPIO, 3)
-#define HPI_GPIO_READ_ALL HPI_MAKE_INDEX(HPI_OBJ_GPIO, 4)
-#define HPI_GPIO_WRITE_STATUS HPI_MAKE_INDEX(HPI_OBJ_GPIO, 5)
+
+ HPI_GPIO_OPEN = HPI_FUNC_ID(GPIO, 1),
+ HPI_GPIO_READ_BIT = HPI_FUNC_ID(GPIO, 2),
+ HPI_GPIO_WRITE_BIT = HPI_FUNC_ID(GPIO, 3),
+ HPI_GPIO_READ_ALL = HPI_FUNC_ID(GPIO, 4),
+ HPI_GPIO_WRITE_STATUS = HPI_FUNC_ID(GPIO, 5),
#define HPI_GPIO_FUNCTION_COUNT 5
-/* ASYNC EVENT */
-#define HPI_ASYNCEVENT_OPEN HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 1)
-#define HPI_ASYNCEVENT_CLOSE HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 2)
-#define HPI_ASYNCEVENT_WAIT HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 3)
-#define HPI_ASYNCEVENT_GETCOUNT HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 4)
-#define HPI_ASYNCEVENT_GET HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 5)
-#define HPI_ASYNCEVENT_SENDEVENTS HPI_MAKE_INDEX(HPI_OBJ_ASYNCEVENT, 6)
+
+ HPI_ASYNCEVENT_OPEN = HPI_FUNC_ID(ASYNCEVENT, 1),
+ HPI_ASYNCEVENT_CLOSE = HPI_FUNC_ID(ASYNCEVENT, 2),
+ HPI_ASYNCEVENT_WAIT = HPI_FUNC_ID(ASYNCEVENT, 3),
+ HPI_ASYNCEVENT_GETCOUNT = HPI_FUNC_ID(ASYNCEVENT, 4),
+ HPI_ASYNCEVENT_GET = HPI_FUNC_ID(ASYNCEVENT, 5),
+ HPI_ASYNCEVENT_SENDEVENTS = HPI_FUNC_ID(ASYNCEVENT, 6),
#define HPI_ASYNCEVENT_FUNCTION_COUNT 6
-/* WATCH-DOG */
-#define HPI_WATCHDOG_OPEN HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 1)
-#define HPI_WATCHDOG_SET_TIME HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 2)
-#define HPI_WATCHDOG_PING HPI_MAKE_INDEX(HPI_OBJ_WATCHDOG, 3)
-/* CLOCK */
-#define HPI_CLOCK_OPEN HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 1)
-#define HPI_CLOCK_SET_TIME HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 2)
-#define HPI_CLOCK_GET_TIME HPI_MAKE_INDEX(HPI_OBJ_CLOCK, 3)
-/* PROFILE */
-#define HPI_PROFILE_OPEN_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 1)
-#define HPI_PROFILE_START_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 2)
-#define HPI_PROFILE_STOP_ALL HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 3)
-#define HPI_PROFILE_GET HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 4)
-#define HPI_PROFILE_GET_IDLECOUNT HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 5)
-#define HPI_PROFILE_GET_NAME HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 6)
-#define HPI_PROFILE_GET_UTILIZATION HPI_MAKE_INDEX(HPI_OBJ_PROFILE, 7)
+
+ HPI_WATCHDOG_OPEN = HPI_FUNC_ID(WATCHDOG, 1),
+ HPI_WATCHDOG_SET_TIME = HPI_FUNC_ID(WATCHDOG, 2),
+ HPI_WATCHDOG_PING = HPI_FUNC_ID(WATCHDOG, 3),
+
+ HPI_CLOCK_OPEN = HPI_FUNC_ID(CLOCK, 1),
+ HPI_CLOCK_SET_TIME = HPI_FUNC_ID(CLOCK, 2),
+ HPI_CLOCK_GET_TIME = HPI_FUNC_ID(CLOCK, 3),
+
+ HPI_PROFILE_OPEN_ALL = HPI_FUNC_ID(PROFILE, 1),
+ HPI_PROFILE_START_ALL = HPI_FUNC_ID(PROFILE, 2),
+ HPI_PROFILE_STOP_ALL = HPI_FUNC_ID(PROFILE, 3),
+ HPI_PROFILE_GET = HPI_FUNC_ID(PROFILE, 4),
+ HPI_PROFILE_GET_IDLECOUNT = HPI_FUNC_ID(PROFILE, 5),
+ HPI_PROFILE_GET_NAME = HPI_FUNC_ID(PROFILE, 6),
+ HPI_PROFILE_GET_UTILIZATION = HPI_FUNC_ID(PROFILE, 7)
#define HPI_PROFILE_FUNCTION_COUNT 7
-/* ////////////////////////////////////////////////////////////////////// */
-/* PRIVATE ATTRIBUTES */
+};
/* ////////////////////////////////////////////////////////////////////// */
/* STRUCTURES */
@@ -672,18 +552,7 @@ Threshold is a -ve number in units of dB/100,
/** PCI bus resource */
struct hpi_pci {
u32 __iomem *ap_mem_base[HPI_MAX_ADAPTER_MEM_SPACES];
- struct pci_dev *p_os_data;
-
-#ifndef HPI64BIT /* keep structure size constant */
- u32 padding[HPI_MAX_ADAPTER_MEM_SPACES + 1];
-#endif
- u16 vendor_id;
- u16 device_id;
- u16 subsys_vendor_id;
- u16 subsys_device_id;
- u16 bus_number;
- u16 device_number;
- u32 interrupt;
+ struct pci_dev *pci_dev;
};
struct hpi_resource {
@@ -702,12 +571,10 @@ struct hpi_resource {
/** Format info used inside struct hpi_message
Not the same as public API struct hpi_format */
struct hpi_msg_format {
- u32 sample_rate;
- /**< 11025, 32000, 44100 ... */
- u32 bit_rate; /**< for MPEG */
- u32 attributes;
- /**< Stereo/JointStereo/Mono */
- u16 channels; /**< 1,2..., (or ancillary mode or idle bit */
+ u32 sample_rate; /**< 11025, 32000, 44100 etc. */
+ u32 bit_rate; /**< for MPEG */
+ u32 attributes; /**< stereo/joint_stereo/mono */
+ u16 channels; /**< 1,2..., (or ancillary mode or idle bit */
u16 format; /**< HPI_FORMAT_PCM16, _MPEG etc. see \ref HPI_FORMATS. */
};
@@ -742,7 +609,7 @@ struct hpi_data_compat32 {
struct hpi_buffer {
/** placehoder for backward compatability (see dwBufferSize) */
struct hpi_msg_format reserved;
- u32 command; /**< HPI_BUFFER_CMD_xxx*/
+ u32 command; /**< HPI_BUFFER_CMD_xxx*/
u32 pci_address; /**< PCI physical address of buffer for DSP DMA */
u32 buffer_size; /**< must line up with data_size of HPI_DATA*/
};
@@ -777,30 +644,25 @@ struct hpi_subsys_msg {
struct hpi_subsys_res {
u32 version;
- u32 data; /* used to return extended version */
- u16 num_adapters; /* number of adapters */
+ u32 data; /* extended version */
+ u16 num_adapters;
u16 adapter_index;
- u16 aw_adapter_list[HPI_MAX_ADAPTERS];
-};
-
-struct hpi_adapter_msg {
- u32 adapter_mode; /* adapter mode */
- u16 assert_id; /* assert number for "test assert" call
- object_index for find object call
- query_or_set for hpi_adapter_set_mode_ex() */
- u16 object_type; /* for adapter find object call */
+ u16 adapter_type;
+ u16 pad16;
};
union hpi_adapterx_msg {
- struct hpi_adapter_msg adapter;
struct {
- u32 offset;
- } query_flash;
+ u32 dsp_address;
+ u32 count_bytes;
+ } debug_read;
struct {
- u32 offset;
- u32 length;
- u32 key;
- } start_flash;
+ u32 adapter_mode;
+ u16 query_or_set;
+ } mode;
+ struct {
+ u16 index;
+ } module_info;
struct {
u32 checksum;
u16 sequence;
@@ -809,28 +671,41 @@ union hpi_adapterx_msg {
u16 unused;
} program_flash;
struct {
+ u16 index;
+ u16 what;
+ u16 property_index;
+ } property_enum;
+ struct {
u16 property;
u16 parameter1;
u16 parameter2;
} property_set;
struct {
- u16 index;
- u16 what;
- u16 property_index;
- } property_enum;
+ u32 offset;
+ } query_flash;
struct {
- u16 index;
- } module_info;
+ u32 pad32;
+ u16 key1;
+ u16 key2;
+ } restart;
struct {
- u32 dsp_address;
- u32 count_bytes;
- } debug_read;
+ u32 offset;
+ u32 length;
+ u32 key;
+ } start_flash;
+ struct {
+ u32 pad32;
+ u16 value;
+ } test_assert;
+ struct {
+ u32 yes;
+ } irq_query;
};
struct hpi_adapter_res {
u32 serial_number;
u16 adapter_type;
- u16 adapter_index; /* is this needed? also used for dsp_index */
+ u16 adapter_index;
u16 num_instreams;
u16 num_outstreams;
u16 num_mixers;
@@ -839,12 +714,18 @@ struct hpi_adapter_res {
};
union hpi_adapterx_res {
- struct hpi_adapter_res adapter;
+ struct hpi_adapter_res info;
struct {
- u32 checksum;
- u32 length;
- u32 version;
- } query_flash;
+ u32 p1;
+ u16 count;
+ u16 dsp_index;
+ u32 p2;
+ u32 dsp_msg_addr;
+ char sz_message[HPI_STRING_LEN];
+ } assert;
+ struct {
+ u32 adapter_mode;
+ } mode;
struct {
u16 sequence;
} program_flash;
@@ -852,6 +733,14 @@ union hpi_adapterx_res {
u16 parameter1;
u16 parameter2;
} property_get;
+ struct {
+ u32 checksum;
+ u32 length;
+ u32 version;
+ } query_flash;
+ struct {
+ u32 yes;
+ } irq_query;
};
struct hpi_stream_msg {
@@ -863,6 +752,7 @@ struct hpi_stream_msg {
u32 time_scale;
struct hpi_buffer buffer;
struct hpi_streamid stream;
+ u32 threshold_bytes;
} u;
};
@@ -911,7 +801,7 @@ struct hpi_stream_res {
struct hpi_mixer_msg {
u16 control_index;
u16 control_type; /* = HPI_CONTROL_METER _VOLUME etc */
- u16 padding1; /* maintain alignment of subsequent fields */
+ u16 padding1; /* Maintain alignment of subsequent fields */
u16 node_type1; /* = HPI_SOURCENODE_LINEIN etc */
u16 node_index1; /* = 0..N */
u16 node_type2;
@@ -949,6 +839,11 @@ union hpi_mixerx_res {
u32 p_data; /* pointer to data array */
u16 more_to_do; /* indicates if there is more to do */
} gcabi;
+ struct {
+ u32 total_controls; /* count of controls in the mixer */
+ u32 cache_controls; /* count of controls in the cac */
+ u32 cache_bytes; /* size of cache */
+ } cache_info;
};
struct hpi_control_msg {
@@ -1000,12 +895,16 @@ union hpi_control_union_res {
u32 band;
u32 frequency;
u32 gain;
- u32 level;
u32 deemphasis;
struct {
u32 data[2];
u32 bLER;
} rds;
+ short s_level;
+ struct {
+ u16 value;
+ u16 mask;
+ } status;
} tuner;
struct {
char sz_data[8];
@@ -1178,11 +1077,11 @@ struct hpi_profile_res_open {
};
struct hpi_profile_res_time {
- u32 micro_seconds;
+ u32 total_tick_count;
u32 call_count;
- u32 max_micro_seconds;
- u32 min_micro_seconds;
- u16 seconds;
+ u32 max_tick_count;
+ u32 ticks_per_millisecond;
+ u16 profile_interval;
};
struct hpi_profile_res_name {
@@ -1218,7 +1117,6 @@ struct hpi_message {
u16 obj_index; /* */
union {
struct hpi_subsys_msg s;
- struct hpi_adapter_msg a;
union hpi_adapterx_msg ax;
struct hpi_stream_msg d;
struct hpi_mixer_msg m;
@@ -1239,7 +1137,7 @@ struct hpi_message {
};
#define HPI_MESSAGE_SIZE_BY_OBJECT { \
- sizeof(struct hpi_message_header) , /* default, no object type 0 */ \
+ sizeof(struct hpi_message_header) , /* Default, no object type 0 */ \
sizeof(struct hpi_message_header) + sizeof(struct hpi_subsys_msg),\
sizeof(struct hpi_message_header) + sizeof(union hpi_adapterx_msg),\
sizeof(struct hpi_message_header) + sizeof(struct hpi_stream_msg),\
@@ -1256,6 +1154,11 @@ struct hpi_message {
sizeof(struct hpi_message_header) + sizeof(struct hpi_async_msg) \
}
+/*
+Note that the wSpecificError error field should be inspected and potentially
+reported whenever HPI_ERROR_DSP_COMMUNICATION or HPI_ERROR_DSP_BOOTLOAD is
+returned in wError.
+*/
struct hpi_response_header {
u16 size;
u8 type; /* HPI_TYPE_RESPONSE */
@@ -1277,7 +1180,6 @@ struct hpi_response {
u16 specific_error; /* adapter specific error */
union {
struct hpi_subsys_res s;
- struct hpi_adapter_res a;
union hpi_adapterx_res ax;
struct hpi_stream_res d;
struct hpi_mixer_res m;
@@ -1297,7 +1199,7 @@ struct hpi_response {
};
#define HPI_RESPONSE_SIZE_BY_OBJECT { \
- sizeof(struct hpi_response_header) ,/* default, no object type 0 */ \
+ sizeof(struct hpi_response_header) ,/* Default, no object type 0 */ \
sizeof(struct hpi_response_header) + sizeof(struct hpi_subsys_res),\
sizeof(struct hpi_response_header) + sizeof(union hpi_adapterx_res),\
sizeof(struct hpi_response_header) + sizeof(struct hpi_stream_res),\
@@ -1314,7 +1216,7 @@ struct hpi_response {
sizeof(struct hpi_response_header) + sizeof(struct hpi_async_res) \
}
-/*********************** version 1 message/response *****************************/
+/*********************** version 1 message/response **************************/
#define HPINET_ETHERNET_DATA_SIZE (1500)
#define HPINET_IP_HDR_SIZE (20)
#define HPINET_IP_DATA_SIZE (HPINET_ETHERNET_DATA_SIZE - HPINET_IP_HDR_SIZE)
@@ -1394,6 +1296,17 @@ struct hpi_res_adapter_program_flash {
sizeof(struct hpi_response_header) - sizeof(u16)];
};
+struct hpi_msg_adapter_debug_read {
+ struct hpi_message_header h;
+ u32 dsp_address;
+ u32 count_bytes;
+};
+
+struct hpi_res_adapter_debug_read {
+ struct hpi_response_header h;
+ u8 bytes[256];
+};
+
#if 1
#define hpi_message_header_v1 hpi_message_header
#define hpi_response_header_v1 hpi_response_header
@@ -1414,23 +1327,10 @@ struct hpi_response_header_v1 {
};
#endif
-/* STRV HPI Packet */
-struct hpi_msg_strv {
- struct hpi_message_header h;
- struct hpi_entity strv;
-};
-
-struct hpi_res_strv {
- struct hpi_response_header h;
- struct hpi_entity strv;
-};
-#define MIN_STRV_PACKET_SIZE sizeof(struct hpi_res_strv)
-
struct hpi_msg_payload_v0 {
struct hpi_message_header h;
union {
struct hpi_subsys_msg s;
- struct hpi_adapter_msg a;
union hpi_adapterx_msg ax;
struct hpi_stream_msg d;
struct hpi_mixer_msg m;
@@ -1451,7 +1351,6 @@ struct hpi_res_payload_v0 {
struct hpi_response_header h;
union {
struct hpi_subsys_res s;
- struct hpi_adapter_res a;
union hpi_adapterx_res ax;
struct hpi_stream_res d;
struct hpi_mixer_res m;
@@ -1471,13 +1370,13 @@ struct hpi_res_payload_v0 {
union hpi_message_buffer_v1 {
struct hpi_message m0; /* version 0 */
struct hpi_message_header_v1 h;
- unsigned char buf[HPI_MAX_PAYLOAD_SIZE];
+ u8 buf[HPI_MAX_PAYLOAD_SIZE];
};
union hpi_response_buffer_v1 {
struct hpi_response r0; /* version 0 */
struct hpi_response_header_v1 h;
- unsigned char buf[HPI_MAX_PAYLOAD_SIZE];
+ u8 buf[HPI_MAX_PAYLOAD_SIZE];
};
compile_time_assert((sizeof(union hpi_message_buffer_v1) <=
@@ -1499,6 +1398,11 @@ struct hpi_control_defn {
/*////////////////////////////////////////////////////////////////////////// */
/* declarations for control caching (internal to HPI<->DSP interaction) */
+/** indicates a cached u16 value is invalid. */
+#define HPI_CACHE_INVALID_UINT16 0xFFFF
+/** indicates a cached short value is invalid. */
+#define HPI_CACHE_INVALID_SHORT -32768
+
/** A compact representation of (part of) a controls state.
Used for efficient transfer of the control state
between DSP and host or across a network
@@ -1512,58 +1416,104 @@ struct hpi_control_cache_info {
u16 control_index;
};
-struct hpi_control_cache_single {
+struct hpi_control_cache_vol {
+ struct hpi_control_cache_info i;
+ short an_log[2];
+ unsigned short flags;
+ char padding[2];
+};
+
+struct hpi_control_cache_meter {
+ struct hpi_control_cache_info i;
+ short an_log_peak[2];
+ short an_logRMS[2];
+};
+
+struct hpi_control_cache_channelmode {
+ struct hpi_control_cache_info i;
+ u16 mode;
+ char temp_padding[6];
+};
+
+struct hpi_control_cache_mux {
+ struct hpi_control_cache_info i;
+ u16 source_node_type;
+ u16 source_node_index;
+ char temp_padding[4];
+};
+
+struct hpi_control_cache_level {
struct hpi_control_cache_info i;
+ short an_log[2];
+ char temp_padding[4];
+};
+
+struct hpi_control_cache_tuner {
+ struct hpi_control_cache_info i;
+ u32 freq_ink_hz;
+ u16 band;
+ short s_level_avg;
+};
+
+struct hpi_control_cache_aes3rx {
+ struct hpi_control_cache_info i;
+ u32 error_status;
+ u32 format;
+};
+
+struct hpi_control_cache_aes3tx {
+ struct hpi_control_cache_info i;
+ u32 format;
+ char temp_padding[4];
+};
+
+struct hpi_control_cache_tonedetector {
+ struct hpi_control_cache_info i;
+ u16 state;
+ char temp_padding[6];
+};
+
+struct hpi_control_cache_silencedetector {
+ struct hpi_control_cache_info i;
+ u32 state;
+ char temp_padding[4];
+};
+
+struct hpi_control_cache_sampleclock {
+ struct hpi_control_cache_info i;
+ u16 source;
+ u16 source_index;
+ u32 sample_rate;
+};
+
+struct hpi_control_cache_microphone {
+ struct hpi_control_cache_info i;
+ u16 phantom_state;
+ char temp_padding[6];
+};
+
+struct hpi_control_cache_generic {
+ struct hpi_control_cache_info i;
+ u32 dw1;
+ u32 dw2;
+};
+
+struct hpi_control_cache_single {
union {
- struct { /* volume */
- short an_log[2];
- } v;
- struct { /* peak meter */
- short an_log_peak[2];
- short an_logRMS[2];
- } p;
- struct { /* channel mode */
- u16 mode;
- } m;
- struct { /* multiplexer */
- u16 source_node_type;
- u16 source_node_index;
- } x;
- struct { /* level/trim */
- short an_log[2];
- } l;
- struct { /* tuner - partial caching.
- some attributes go to the DSP. */
- u32 freq_ink_hz;
- u16 band;
- u16 level;
- } t;
- struct { /* AESEBU rx status */
- u32 error_status;
- u32 source;
- } aes3rx;
- struct { /* AESEBU tx */
- u32 format;
- } aes3tx;
- struct { /* tone detector */
- u16 state;
- } tone;
- struct { /* silence detector */
- u32 state;
- u32 count;
- } silence;
- struct { /* sample clock */
- u16 source;
- u16 source_index;
- u32 sample_rate;
- } clk;
- struct { /* microphone control */
- u16 state;
- } phantom_power;
- struct { /* generic control */
- u32 dw1;
- u32 dw2;
- } g;
+ struct hpi_control_cache_info i;
+ struct hpi_control_cache_vol vol;
+ struct hpi_control_cache_meter meter;
+ struct hpi_control_cache_channelmode mode;
+ struct hpi_control_cache_mux mux;
+ struct hpi_control_cache_level level;
+ struct hpi_control_cache_tuner tuner;
+ struct hpi_control_cache_aes3rx aes3rx;
+ struct hpi_control_cache_aes3tx aes3tx;
+ struct hpi_control_cache_tonedetector tone;
+ struct hpi_control_cache_silencedetector silence;
+ struct hpi_control_cache_sampleclock clk;
+ struct hpi_control_cache_microphone microphone;
+ struct hpi_control_cache_generic generic;
} u;
};
@@ -1580,8 +1530,7 @@ struct hpi_control_cache_pad {
u32 traffic_anouncement;
};
-/*/////////////////////////////////////////////////////////////////////////// */
-/* declarations for 2^N sized FIFO buffer (internal to HPI<->DSP interaction) */
+/* 2^N sized FIFO buffer (internal to HPI<->DSP interaction) */
struct hpi_fifo_buffer {
u32 size;
u32 dSP_index;
@@ -1606,25 +1555,18 @@ u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index,
/*////////////////////////////////////////////////////////////////////////// */
/* main HPI entry point */
-hpi_handler_func hpi_send_recv;
-
-/* UDP message */
-void hpi_send_recvUDP(struct hpi_message *phm, struct hpi_response *phr,
- const unsigned int timeout);
+void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr);
/* used in PnP OS/driver */
-u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys,
- const struct hpi_resource *p_resource, u16 *pw_adapter_index);
+u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
+ u16 *pw_adapter_index);
-u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index);
+u16 hpi_subsys_delete_adapter(u16 adapter_index);
-u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u8 **pp_buffer,
+u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status);
-u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u8 **pp_buffer,
+u16 hpi_instream_host_buffer_get_info(u32 h_instream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status);
u16 hpi_adapter_restart(u16 adapter_index);
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index d67f4d3db911..3e9c5c289764 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -26,6 +26,8 @@
#include "hpi_internal.h"
#include "hpidebug.h"
+#include "hpimsginit.h"
+
#include "hpicmn.h"
struct hpi_adapters_list {
@@ -43,14 +45,24 @@ static struct hpi_adapters_list adapters;
**/
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr)
{
- u16 error = 0;
+ if (phr->type != HPI_TYPE_RESPONSE) {
+ HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type);
+ return HPI_ERROR_INVALID_RESPONSE;
+ }
- if ((phr->type != HPI_TYPE_RESPONSE)
- || (phr->object != phm->object)
- || (phr->function != phm->function))
- error = HPI_ERROR_INVALID_RESPONSE;
+ if (phr->object != phm->object) {
+ HPI_DEBUG_LOG(ERROR, "header object %d invalid\n",
+ phr->object);
+ return HPI_ERROR_INVALID_RESPONSE;
+ }
+
+ if (phr->function != phm->function) {
+ HPI_DEBUG_LOG(ERROR, "header type %d invalid\n",
+ phr->function);
+ return HPI_ERROR_INVALID_RESPONSE;
+ }
- return error;
+ return 0;
}
u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
@@ -66,8 +78,18 @@ u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
}
if (adapters.adapter[pao->index].adapter_type) {
- {
- retval = HPI_DUPLICATE_ADAPTER_NUMBER;
+ int a;
+ for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) {
+ if (!adapters.adapter[a].adapter_type) {
+ HPI_DEBUG_LOG(WARNING,
+ "ASI%X duplicate index %d moved to %d\n",
+ pao->adapter_type, pao->index, a);
+ pao->index = a;
+ break;
+ }
+ }
+ if (a < 0) {
+ retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER;
goto unlock;
}
}
@@ -76,17 +98,22 @@ u16 hpi_add_adapter(struct hpi_adapter_obj *pao)
adapters.gw_num_adapters++;
unlock:
- hpios_alistlock_un_lock(&adapters);
+ hpios_alistlock_unlock(&adapters);
return retval;
}
void hpi_delete_adapter(struct hpi_adapter_obj *pao)
{
- memset(pao, 0, sizeof(struct hpi_adapter_obj));
+ if (!pao->adapter_type) {
+ HPI_DEBUG_LOG(ERROR, "removing null adapter?\n");
+ return;
+ }
hpios_alistlock_lock(&adapters);
- adapters.gw_num_adapters--; /* dec the number of adapters */
- hpios_alistlock_un_lock(&adapters);
+ if (adapters.adapter[pao->index].adapter_type)
+ adapters.gw_num_adapters--;
+ memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0]));
+ hpios_alistlock_unlock(&adapters);
}
/**
@@ -99,7 +126,7 @@ struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
struct hpi_adapter_obj *pao = NULL;
if (adapter_index >= HPI_MAX_ADAPTERS) {
- HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d ",
+ HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n",
adapter_index);
return NULL;
}
@@ -125,51 +152,34 @@ struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index)
* wipe an HPI_ADAPTERS_LIST structure.
*
**/
-static void wipe_adapter_list(void
- )
+static void wipe_adapter_list(void)
{
memset(&adapters, 0, sizeof(adapters));
}
-/**
-* SubSysGetAdapters fills awAdapterList in an struct hpi_response structure
-* with all adapters in the given HPI_ADAPTERS_LIST.
-*
-*/
-static void subsys_get_adapters(struct hpi_response *phr)
+static void subsys_get_adapter(struct hpi_message *phm,
+ struct hpi_response *phr)
{
- /* fill in the response adapter array with the position */
- /* identified by the adapter number/index of the adapters in */
- /* this HPI */
- /* i.e. if we have an A120 with it's jumper set to */
- /* Adapter Number 2 then put an Adapter type A120 in the */
- /* array in position 1 */
- /* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */
-
- /* input: NONE */
- /* output: wNumAdapters */
- /* awAdapter[] */
- /* */
-
- short i;
- struct hpi_adapter_obj *pao = NULL;
+ int count = phm->obj_index;
+ u16 index = 0;
- HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n");
-
- /* for each adapter, place it's type in the position of the array */
- /* corresponding to it's adapter number */
- for (i = 0; i < adapters.gw_num_adapters; i++) {
- pao = &adapters.adapter[i];
- if (phr->u.s.aw_adapter_list[pao->index] != 0) {
- phr->error = HPI_DUPLICATE_ADAPTER_NUMBER;
- phr->specific_error = pao->index;
- return;
+ /* find the nCount'th nonzero adapter in array */
+ for (index = 0; index < HPI_MAX_ADAPTERS; index++) {
+ if (adapters.adapter[index].adapter_type) {
+ if (!count)
+ break;
+ count--;
}
- phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type;
}
- phr->u.s.num_adapters = adapters.gw_num_adapters;
- phr->error = 0; /* the function completed OK; */
+ if (index < HPI_MAX_ADAPTERS) {
+ phr->u.s.adapter_index = adapters.adapter[index].index;
+ phr->u.s.adapter_type = adapters.adapter[index].adapter_type;
+ } else {
+ phr->u.s.adapter_index = 0;
+ phr->u.s.adapter_type = 0;
+ phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
+ }
}
static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
@@ -178,67 +188,98 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
int cached = 0;
if (!pC)
return 0;
- if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count)
- && (pC->cache_size_in_bytes)
- ) {
- u32 *p_master_cache;
- pC->init = 1;
-
- p_master_cache = (u32 *)pC->p_cache;
- HPI_DEBUG_LOG(VERBOSE, "check %d controls\n",
+
+ if (pC->init)
+ return pC->init;
+
+ if (!pC->p_cache)
+ return 0;
+
+ if (pC->control_count && pC->cache_size_in_bytes) {
+ char *p_master_cache;
+ unsigned int byte_count = 0;
+
+ p_master_cache = (char *)pC->p_cache;
+ HPI_DEBUG_LOG(DEBUG, "check %d controls\n",
pC->control_count);
for (i = 0; i < pC->control_count; i++) {
struct hpi_control_cache_info *info =
(struct hpi_control_cache_info *)
- p_master_cache;
+ &p_master_cache[byte_count];
+
+ if (!info->size_in32bit_words) {
+ if (!i) {
+ HPI_DEBUG_LOG(INFO,
+ "adap %d cache not ready?\n",
+ pC->adap_idx);
+ return 0;
+ }
+ /* The cache is invalid.
+ * Minimum valid entry size is
+ * sizeof(struct hpi_control_cache_info)
+ */
+ HPI_DEBUG_LOG(ERROR,
+ "adap %d zero size cache entry %d\n",
+ pC->adap_idx, i);
+ break;
+ }
if (info->control_type) {
- pC->p_info[i] = info;
+ pC->p_info[info->control_index] = info;
cached++;
- } else
- pC->p_info[i] = NULL;
+ } else /* dummy cache entry */
+ pC->p_info[info->control_index] = NULL;
- if (info->size_in32bit_words)
- p_master_cache += info->size_in32bit_words;
- else
- p_master_cache +=
- sizeof(struct
- hpi_control_cache_single) /
- sizeof(u32);
+ byte_count += info->size_in32bit_words * 4;
HPI_DEBUG_LOG(VERBOSE,
- "cached %d, pinfo %p index %d type %d\n",
- cached, pC->p_info[i], info->control_index,
- info->control_type);
+ "cached %d, pinfo %p index %d type %d size %d\n",
+ cached, pC->p_info[info->control_index],
+ info->control_index, info->control_type,
+ info->size_in32bit_words);
+
+ /* quit loop early if whole cache has been scanned.
+ * dwControlCount is the maximum possible entries
+ * but some may be absent from the cache
+ */
+ if (byte_count >= pC->cache_size_in_bytes)
+ break;
+ /* have seen last control index */
+ if (info->control_index == pC->control_count - 1)
+ break;
}
- /*
- We didn't find anything to cache, so try again later !
- */
- if (!cached)
- pC->init = 0;
+
+ if (byte_count != pC->cache_size_in_bytes)
+ HPI_DEBUG_LOG(WARNING,
+ "adap %d bytecount %d != cache size %d\n",
+ pC->adap_idx, byte_count,
+ pC->cache_size_in_bytes);
+ else
+ HPI_DEBUG_LOG(DEBUG,
+ "adap %d cache good, bytecount == cache size = %d\n",
+ pC->adap_idx, byte_count);
+
+ pC->init = (u16)cached;
}
return pC->init;
}
/** Find a control.
*/
-static short find_control(struct hpi_message *phm,
- struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI,
- u16 *pw_control_index)
+static short find_control(u16 control_index,
+ struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI)
{
- *pw_control_index = phm->obj_index;
-
if (!control_cache_alloc_check(p_cache)) {
HPI_DEBUG_LOG(VERBOSE,
- "control_cache_alloc_check() failed. adap%d ci%d\n",
- phm->adapter_index, *pw_control_index);
+ "control_cache_alloc_check() failed %d\n",
+ control_index);
return 0;
}
- *pI = p_cache->p_info[*pw_control_index];
+ *pI = p_cache->p_info[control_index];
if (!*pI) {
- HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n",
- phm->adapter_index, *pw_control_index);
+ HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n",
+ control_index);
return 0;
} else {
HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n",
@@ -247,25 +288,6 @@ static short find_control(struct hpi_message *phm,
return 1;
}
-/** Used by the kernel driver to figure out if a buffer needs mapping.
- */
-short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
- struct hpi_message *phm, void **p, unsigned int *pN)
-{
- *pN = 0;
- *p = NULL;
- if ((phm->function == HPI_CONTROL_GET_STATE)
- && (phm->object == HPI_OBJ_CONTROLEX)
- ) {
- u16 control_index;
- struct hpi_control_cache_info *pI;
-
- if (!find_control(phm, p_cache, &pI, &control_index))
- return 0;
- }
- return 0;
-}
-
/* allow unified treatment of several string fields within struct */
#define HPICMN_PAD_OFS_AND_SIZE(m) {\
offsetof(struct hpi_control_cache_pad, m), \
@@ -290,13 +312,16 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
short found = 1;
- u16 control_index;
struct hpi_control_cache_info *pI;
struct hpi_control_cache_single *pC;
struct hpi_control_cache_pad *p_pad;
- if (!find_control(phm, p_cache, &pI, &control_index))
+ if (!find_control(phm->obj_index, p_cache, &pI)) {
+ HPI_DEBUG_LOG(VERBOSE,
+ "HPICMN find_control() failed for adap %d\n",
+ phm->adapter_index);
return 0;
+ }
phr->error = 0;
@@ -310,55 +335,79 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
case HPI_CONTROL_METER:
if (phm->u.c.attribute == HPI_METER_PEAK) {
- phr->u.c.an_log_value[0] = pC->u.p.an_log_peak[0];
- phr->u.c.an_log_value[1] = pC->u.p.an_log_peak[1];
+ phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0];
+ phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1];
} else if (phm->u.c.attribute == HPI_METER_RMS) {
- phr->u.c.an_log_value[0] = pC->u.p.an_logRMS[0];
- phr->u.c.an_log_value[1] = pC->u.p.an_logRMS[1];
+ if (pC->u.meter.an_logRMS[0] ==
+ HPI_CACHE_INVALID_SHORT) {
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+ phr->u.c.an_log_value[0] = HPI_METER_MINIMUM;
+ phr->u.c.an_log_value[1] = HPI_METER_MINIMUM;
+ } else {
+ phr->u.c.an_log_value[0] =
+ pC->u.meter.an_logRMS[0];
+ phr->u.c.an_log_value[1] =
+ pC->u.meter.an_logRMS[1];
+ }
} else
found = 0;
break;
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
- phr->u.c.an_log_value[0] = pC->u.v.an_log[0];
- phr->u.c.an_log_value[1] = pC->u.v.an_log[1];
- } else
+ phr->u.c.an_log_value[0] = pC->u.vol.an_log[0];
+ phr->u.c.an_log_value[1] = pC->u.vol.an_log[1];
+ } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
+ if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) {
+ if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED)
+ phr->u.c.param1 =
+ HPI_BITMASK_ALL_CHANNELS;
+ else
+ phr->u.c.param1 = 0;
+ } else {
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+ phr->u.c.param1 = 0;
+ }
+ } else {
found = 0;
+ }
break;
case HPI_CONTROL_MULTIPLEXER:
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
- phr->u.c.param1 = pC->u.x.source_node_type;
- phr->u.c.param2 = pC->u.x.source_node_index;
+ phr->u.c.param1 = pC->u.mux.source_node_type;
+ phr->u.c.param2 = pC->u.mux.source_node_index;
} else {
found = 0;
}
break;
case HPI_CONTROL_CHANNEL_MODE:
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
- phr->u.c.param1 = pC->u.m.mode;
+ phr->u.c.param1 = pC->u.mode.mode;
else
found = 0;
break;
case HPI_CONTROL_LEVEL:
if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
- phr->u.c.an_log_value[0] = pC->u.l.an_log[0];
- phr->u.c.an_log_value[1] = pC->u.l.an_log[1];
+ phr->u.c.an_log_value[0] = pC->u.level.an_log[0];
+ phr->u.c.an_log_value[1] = pC->u.level.an_log[1];
} else
found = 0;
break;
case HPI_CONTROL_TUNER:
if (phm->u.c.attribute == HPI_TUNER_FREQ)
- phr->u.c.param1 = pC->u.t.freq_ink_hz;
+ phr->u.c.param1 = pC->u.tuner.freq_ink_hz;
else if (phm->u.c.attribute == HPI_TUNER_BAND)
- phr->u.c.param1 = pC->u.t.band;
- else if ((phm->u.c.attribute == HPI_TUNER_LEVEL)
- && (phm->u.c.param1 == HPI_TUNER_LEVEL_AVERAGE))
- if (pC->u.t.level == HPI_ERROR_ILLEGAL_CACHE_VALUE) {
- phr->u.c.param1 = 0;
+ phr->u.c.param1 = pC->u.tuner.band;
+ else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG)
+ if (pC->u.tuner.s_level_avg ==
+ HPI_CACHE_INVALID_SHORT) {
+ phr->u.cu.tuner.s_level = 0;
phr->error =
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
} else
- phr->u.c.param1 = pC->u.t.level;
+ phr->u.cu.tuner.s_level =
+ pC->u.tuner.s_level_avg;
else
found = 0;
break;
@@ -366,7 +415,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS)
phr->u.c.param1 = pC->u.aes3rx.error_status;
else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
- phr->u.c.param1 = pC->u.aes3rx.source;
+ phr->u.c.param1 = pC->u.aes3rx.format;
else
found = 0;
break;
@@ -385,13 +434,12 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
case HPI_CONTROL_SILENCEDETECTOR:
if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) {
phr->u.c.param1 = pC->u.silence.state;
- phr->u.c.param2 = pC->u.silence.count;
} else
found = 0;
break;
case HPI_CONTROL_MICROPHONE:
if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
- phr->u.c.param1 = pC->u.phantom_power.state;
+ phr->u.c.param1 = pC->u.microphone.phantom_state;
else
found = 0;
break;
@@ -400,7 +448,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
phr->u.c.param1 = pC->u.clk.source;
else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) {
if (pC->u.clk.source_index ==
- HPI_ERROR_ILLEGAL_CACHE_VALUE) {
+ HPI_CACHE_INVALID_UINT16) {
phr->u.c.param1 = 0;
phr->error =
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
@@ -411,60 +459,63 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
else
found = 0;
break;
- case HPI_CONTROL_PAD:
+ case HPI_CONTROL_PAD:{
+ struct hpi_control_cache_pad *p_pad;
+ p_pad = (struct hpi_control_cache_pad *)pI;
- if (!(p_pad->field_valid_flags & (1 <<
- HPI_CTL_ATTR_INDEX(phm->u.c.
- attribute)))) {
- phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
- break;
- }
-
- if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
- phr->u.c.param1 = p_pad->pI;
- else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
- phr->u.c.param1 = p_pad->pTY;
- else {
- unsigned int index =
- HPI_CTL_ATTR_INDEX(phm->u.c.attribute) - 1;
- unsigned int offset = phm->u.c.param1;
- unsigned int pad_string_len, field_size;
- char *pad_string;
- unsigned int tocopy;
-
- HPI_DEBUG_LOG(VERBOSE, "PADS HPI_PADS_ %d\n",
- phm->u.c.attribute);
-
- if (index > ARRAY_SIZE(pad_desc) - 1) {
+ if (!(p_pad->field_valid_flags & (1 <<
+ HPI_CTL_ATTR_INDEX(phm->u.c.
+ attribute)))) {
phr->error =
HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
break;
}
- pad_string = ((char *)p_pad) + pad_desc[index].offset;
- field_size = pad_desc[index].field_size;
- /* Ensure null terminator */
- pad_string[field_size - 1] = 0;
-
- pad_string_len = strlen(pad_string) + 1;
-
- if (offset > pad_string_len) {
- phr->error = HPI_ERROR_INVALID_CONTROL_VALUE;
- break;
+ if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID)
+ phr->u.c.param1 = p_pad->pI;
+ else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE)
+ phr->u.c.param1 = p_pad->pTY;
+ else {
+ unsigned int index =
+ HPI_CTL_ATTR_INDEX(phm->u.c.
+ attribute) - 1;
+ unsigned int offset = phm->u.c.param1;
+ unsigned int pad_string_len, field_size;
+ char *pad_string;
+ unsigned int tocopy;
+
+ if (index > ARRAY_SIZE(pad_desc) - 1) {
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_ATTRIBUTE;
+ break;
+ }
+
+ pad_string =
+ ((char *)p_pad) +
+ pad_desc[index].offset;
+ field_size = pad_desc[index].field_size;
+ /* Ensure null terminator */
+ pad_string[field_size - 1] = 0;
+
+ pad_string_len = strlen(pad_string) + 1;
+
+ if (offset > pad_string_len) {
+ phr->error =
+ HPI_ERROR_INVALID_CONTROL_VALUE;
+ break;
+ }
+
+ tocopy = pad_string_len - offset;
+ if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
+ tocopy = sizeof(phr->u.cu.chars8.
+ sz_data);
+
+ memcpy(phr->u.cu.chars8.sz_data,
+ &pad_string[offset], tocopy);
+
+ phr->u.cu.chars8.remaining_chars =
+ pad_string_len - offset - tocopy;
}
-
- tocopy = pad_string_len - offset;
- if (tocopy > sizeof(phr->u.cu.chars8.sz_data))
- tocopy = sizeof(phr->u.cu.chars8.sz_data);
-
- HPI_DEBUG_LOG(VERBOSE,
- "PADS memcpy(%d), offset %d \n", tocopy,
- offset);
- memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset],
- tocopy);
-
- phr->u.cu.chars8.remaining_chars =
- pad_string_len - offset - tocopy;
}
break;
default:
@@ -472,16 +523,9 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
break;
}
- if (found)
- HPI_DEBUG_LOG(VERBOSE,
- "cached adap %d, ctl %d, type %d, attr %d\n",
- phm->adapter_index, pI->control_index,
- pI->control_type, phm->u.c.attribute);
- else
- HPI_DEBUG_LOG(VERBOSE,
- "uncached adap %d, ctl %d, ctl type %d\n",
- phm->adapter_index, pI->control_index,
- pI->control_type);
+ HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
+ found ? "Cached" : "Uncached", phm->adapter_index,
+ pI->control_index, pI->control_type, phm->u.c.attribute);
if (found)
phr->size =
@@ -497,18 +541,21 @@ Only update if no error.
Volume and Level return the limited values in the response, so use these
Multiplexer does so use sent values
*/
-void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
+void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
- u16 control_index;
struct hpi_control_cache_single *pC;
struct hpi_control_cache_info *pI;
if (phr->error)
return;
- if (!find_control(phm, p_cache, &pI, &control_index))
+ if (!find_control(phm->obj_index, p_cache, &pI)) {
+ HPI_DEBUG_LOG(VERBOSE,
+ "HPICMN find_control() failed for adap %d\n",
+ phm->adapter_index);
return;
+ }
/* pC is the default cached control strucure.
May be cast to something else in the following switch statement.
@@ -518,31 +565,36 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
switch (pI->control_type) {
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
- pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
- pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
+ pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
+ pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
+ } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) {
+ if (phm->u.c.param1)
+ pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED;
+ else
+ pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED;
}
break;
case HPI_CONTROL_MULTIPLEXER:
/* mux does not return its setting on Set command. */
if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) {
- pC->u.x.source_node_type = (u16)phm->u.c.param1;
- pC->u.x.source_node_index = (u16)phm->u.c.param2;
+ pC->u.mux.source_node_type = (u16)phm->u.c.param1;
+ pC->u.mux.source_node_index = (u16)phm->u.c.param2;
}
break;
case HPI_CONTROL_CHANNEL_MODE:
/* mode does not return its setting on Set command. */
if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE)
- pC->u.m.mode = (u16)phm->u.c.param1;
+ pC->u.mode.mode = (u16)phm->u.c.param1;
break;
case HPI_CONTROL_LEVEL:
if (phm->u.c.attribute == HPI_LEVEL_GAIN) {
- pC->u.v.an_log[0] = phr->u.c.an_log_value[0];
- pC->u.v.an_log[1] = phr->u.c.an_log_value[1];
+ pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
+ pC->u.vol.an_log[1] = phr->u.c.an_log_value[1];
}
break;
case HPI_CONTROL_MICROPHONE:
if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER)
- pC->u.phantom_power.state = (u16)phm->u.c.param1;
+ pC->u.microphone.phantom_state = (u16)phm->u.c.param1;
break;
case HPI_CONTROL_AESEBU_TRANSMITTER:
if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT)
@@ -550,7 +602,7 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
break;
case HPI_CONTROL_AESEBU_RECEIVER:
if (phm->u.c.attribute == HPI_AESEBURX_FORMAT)
- pC->u.aes3rx.source = phm->u.c.param1;
+ pC->u.aes3rx.format = phm->u.c.param1;
break;
case HPI_CONTROL_SAMPLECLOCK:
if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE)
@@ -565,59 +617,57 @@ void hpi_sync_control_cache(struct hpi_control_cache *p_cache,
}
}
-struct hpi_control_cache *hpi_alloc_control_cache(const u32
- number_of_controls, const u32 size_in_bytes,
- struct hpi_control_cache_info *pDSP_control_buffer)
+struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
+ const u32 size_in_bytes, u8 *p_dsp_control_buffer)
{
struct hpi_control_cache *p_cache =
kmalloc(sizeof(*p_cache), GFP_KERNEL);
if (!p_cache)
return NULL;
+
p_cache->p_info =
- kmalloc(sizeof(*p_cache->p_info) * number_of_controls,
- GFP_KERNEL);
+ kmalloc(sizeof(*p_cache->p_info) * control_count, GFP_KERNEL);
if (!p_cache->p_info) {
kfree(p_cache);
return NULL;
}
+ memset(p_cache->p_info, 0, sizeof(*p_cache->p_info) * control_count);
p_cache->cache_size_in_bytes = size_in_bytes;
- p_cache->control_count = number_of_controls;
- p_cache->p_cache =
- (struct hpi_control_cache_single *)pDSP_control_buffer;
+ p_cache->control_count = control_count;
+ p_cache->p_cache = p_dsp_control_buffer;
p_cache->init = 0;
return p_cache;
}
void hpi_free_control_cache(struct hpi_control_cache *p_cache)
{
- if (p_cache->init) {
+ if (p_cache) {
kfree(p_cache->p_info);
- p_cache->p_info = NULL;
- p_cache->init = 0;
kfree(p_cache);
}
}
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)
{
+ hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function, 0);
switch (phm->function) {
case HPI_SUBSYS_OPEN:
case HPI_SUBSYS_CLOSE:
case HPI_SUBSYS_DRIVER_UNLOAD:
- phr->error = 0;
break;
case HPI_SUBSYS_DRIVER_LOAD:
wipe_adapter_list();
hpios_alistlock_init(&adapters);
- phr->error = 0;
break;
- case HPI_SUBSYS_GET_INFO:
- subsys_get_adapters(phr);
+ case HPI_SUBSYS_GET_ADAPTER:
+ subsys_get_adapter(phm, phr);
+ break;
+ case HPI_SUBSYS_GET_NUM_ADAPTERS:
+ phr->u.s.num_adapters = adapters.gw_num_adapters;
break;
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_SUBSYS_DELETE_ADAPTER:
- phr->error = 0;
break;
default:
phr->error = HPI_ERROR_INVALID_FUNC;
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h
index 6229022f56cb..590f0b69e655 100644
--- a/sound/pci/asihpi/hpicmn.h
+++ b/sound/pci/asihpi/hpicmn.h
@@ -33,18 +33,19 @@ struct hpi_adapter_obj {
};
struct hpi_control_cache {
- u32 init; /**< indicates whether the
- structures are initialized */
+ /** indicates whether the structures are initialized */
+ u16 init;
+ u16 adap_idx;
u32 control_count;
u32 cache_size_in_bytes;
- struct hpi_control_cache_info
- **p_info; /**< pointer to allocated memory of
- lookup pointers. */
- struct hpi_control_cache_single
- *p_cache; /**< pointer to DSP's control cache. */
+ /** pointer to allocated memory of lookup pointers. */
+ struct hpi_control_cache_info **p_info;
+ /** pointer to DSP's control cache. */
+ u8 *p_cache;
};
struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index);
+
u16 hpi_add_adapter(struct hpi_adapter_obj *pao);
void hpi_delete_adapter(struct hpi_adapter_obj *pao);
@@ -52,13 +53,10 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao);
short hpi_check_control_cache(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
struct hpi_control_cache *hpi_alloc_control_cache(const u32
- number_of_controls, const u32 size_in_bytes,
- struct hpi_control_cache_info
- *pDSP_control_buffer);
+ number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer);
void hpi_free_control_cache(struct hpi_control_cache *p_cache);
-void hpi_sync_control_cache(struct hpi_control_cache *pC,
+void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
+
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
-short hpi_check_buffer_mapping(struct hpi_control_cache *p_cache,
- struct hpi_message *phm, void **p, unsigned int *pN);
diff --git a/sound/pci/asihpi/hpidebug.c b/sound/pci/asihpi/hpidebug.c
index 949836ec913a..b52baf62791e 100644
--- a/sound/pci/asihpi/hpidebug.c
+++ b/sound/pci/asihpi/hpidebug.c
@@ -45,161 +45,14 @@ int hpi_debug_level_get(void)
return hpi_debug_level;
}
-#ifdef HPIOS_DEBUG_PRINT
-/* implies OS has no printf-like function */
-#include <stdarg.h>
-
-void hpi_debug_printf(char *fmt, ...)
-{
- va_list arglist;
- char buffer[128];
-
- va_start(arglist, fmt);
-
- if (buffer[0])
- HPIOS_DEBUG_PRINT(buffer);
- va_end(arglist);
-}
-#endif
-
-struct treenode {
- void *array;
- unsigned int num_elements;
-};
-
-#define make_treenode_from_array(nodename, array) \
-static void *tmp_strarray_##nodename[] = array; \
-static struct treenode nodename = { \
- &tmp_strarray_##nodename, \
- ARRAY_SIZE(tmp_strarray_##nodename) \
-};
-
-#define get_treenode_elem(node_ptr, idx, type) \
- (&(*((type *)(node_ptr)->array)[idx]))
-
-make_treenode_from_array(hpi_control_type_strings, HPI_CONTROL_TYPE_STRINGS)
-
- make_treenode_from_array(hpi_subsys_strings, HPI_SUBSYS_STRINGS)
- make_treenode_from_array(hpi_adapter_strings, HPI_ADAPTER_STRINGS)
- make_treenode_from_array(hpi_istream_strings, HPI_ISTREAM_STRINGS)
- make_treenode_from_array(hpi_ostream_strings, HPI_OSTREAM_STRINGS)
- make_treenode_from_array(hpi_mixer_strings, HPI_MIXER_STRINGS)
- make_treenode_from_array(hpi_node_strings,
- {
- "NODE is invalid object"})
-
- make_treenode_from_array(hpi_control_strings, HPI_CONTROL_STRINGS)
- make_treenode_from_array(hpi_nvmemory_strings, HPI_OBJ_STRINGS)
- make_treenode_from_array(hpi_digitalio_strings, HPI_DIGITALIO_STRINGS)
- make_treenode_from_array(hpi_watchdog_strings, HPI_WATCHDOG_STRINGS)
- make_treenode_from_array(hpi_clock_strings, HPI_CLOCK_STRINGS)
- make_treenode_from_array(hpi_profile_strings, HPI_PROFILE_STRINGS)
- make_treenode_from_array(hpi_asyncevent_strings, HPI_ASYNCEVENT_STRINGS)
-#define HPI_FUNCTION_STRINGS \
-{ \
- &hpi_subsys_strings,\
- &hpi_adapter_strings,\
- &hpi_ostream_strings,\
- &hpi_istream_strings,\
- &hpi_mixer_strings,\
- &hpi_node_strings,\
- &hpi_control_strings,\
- &hpi_nvmemory_strings,\
- &hpi_digitalio_strings,\
- &hpi_watchdog_strings,\
- &hpi_clock_strings,\
- &hpi_profile_strings,\
- &hpi_control_strings, \
- &hpi_asyncevent_strings \
-}
- make_treenode_from_array(hpi_function_strings, HPI_FUNCTION_STRINGS)
-
- compile_time_assert(HPI_OBJ_MAXINDEX == 14, obj_list_doesnt_match);
-
-static char *hpi_function_string(unsigned int function)
-{
- unsigned int object;
- struct treenode *tmp;
-
- object = function / HPI_OBJ_FUNCTION_SPACING;
- function = function - object * HPI_OBJ_FUNCTION_SPACING;
-
- if (object == 0 || object == HPI_OBJ_NODE
- || object > hpi_function_strings.num_elements)
- return "invalid object";
-
- tmp = get_treenode_elem(&hpi_function_strings, object - 1,
- struct treenode *);
-
- if (function == 0 || function > tmp->num_elements)
- return "invalid function";
-
- return get_treenode_elem(tmp, function - 1, char *);
-}
-
void hpi_debug_message(struct hpi_message *phm, char *sz_fileline)
{
if (phm) {
- if ((phm->object <= HPI_OBJ_MAXINDEX) && phm->object) {
- u16 index = 0;
- u16 attrib = 0;
- int is_control = 0;
-
- index = phm->obj_index;
- switch (phm->object) {
- case HPI_OBJ_ADAPTER:
- case HPI_OBJ_PROFILE:
- break;
- case HPI_OBJ_MIXER:
- if (phm->function ==
- HPI_MIXER_GET_CONTROL_BY_INDEX)
- index = phm->u.m.control_index;
- break;
- case HPI_OBJ_OSTREAM:
- case HPI_OBJ_ISTREAM:
- break;
-
- case HPI_OBJ_CONTROLEX:
- case HPI_OBJ_CONTROL:
- if (phm->version == 1)
- attrib = HPI_CTL_ATTR(UNIVERSAL, 1);
- else
- attrib = phm->u.c.attribute;
- is_control = 1;
- break;
- default:
- break;
- }
-
- if (is_control && (attrib & 0xFF00)) {
- int control_type = (attrib & 0xFF00) >> 8;
- int attr_index = HPI_CTL_ATTR_INDEX(attrib);
- /* note the KERN facility level
- is in szFileline already */
- printk("%s adapter %d %s "
- "ctrl_index x%04x %s %d\n",
- sz_fileline, phm->adapter_index,
- hpi_function_string(phm->function),
- index,
- get_treenode_elem
- (&hpi_control_type_strings,
- control_type, char *),
- attr_index);
-
- } else
- printk("%s adapter %d %s "
- "idx x%04x attr x%04x \n",
- sz_fileline, phm->adapter_index,
- hpi_function_string(phm->function),
- index, attrib);
- } else {
- printk("adap=%d, invalid obj=%d, func=0x%x\n",
- phm->adapter_index, phm->object,
- phm->function);
- }
- } else
- printk(KERN_ERR
- "NULL message pointer to hpi_debug_message!\n");
+ printk(KERN_DEBUG "HPI_MSG%d,%d,%d,%d,%d\n", phm->version,
+ phm->adapter_index, phm->obj_index, phm->function,
+ phm->u.c.attribute);
+ }
+
}
void hpi_debug_data(u16 *pdata, u32 len)
diff --git a/sound/pci/asihpi/hpidebug.h b/sound/pci/asihpi/hpidebug.h
index a2f0952a99f0..940f54c3c538 100644
--- a/sound/pci/asihpi/hpidebug.h
+++ b/sound/pci/asihpi/hpidebug.h
@@ -37,7 +37,7 @@ enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */
#define HPI_DEBUG_LEVEL_DEFAULT HPI_DEBUG_LEVEL_NOTICE
/* an OS can define an extra flag string that is appended to
- the start of each message, eg see hpios_linux.h */
+ the start of each message, eg see linux kernel hpios.h */
#ifdef SOURCEFILE_NAME
#define FILE_LINE SOURCEFILE_NAME ":" __stringify(__LINE__) " "
@@ -45,18 +45,11 @@ enum { HPI_DEBUG_LEVEL_ERROR = 0, /* always log errors */
#define FILE_LINE __FILE__ ":" __stringify(__LINE__) " "
#endif
-#if defined(HPI_DEBUG) && defined(_WINDOWS)
-#define HPI_DEBUGBREAK() debug_break()
-#else
-#define HPI_DEBUGBREAK()
-#endif
-
#define HPI_DEBUG_ASSERT(expression) \
do { \
- if (!(expression)) {\
- printk(KERN_ERR FILE_LINE\
- "ASSERT " __stringify(expression));\
- HPI_DEBUGBREAK();\
+ if (!(expression)) { \
+ printk(KERN_ERR FILE_LINE \
+ "ASSERT " __stringify(expression)); \
} \
} while (0)
@@ -78,28 +71,27 @@ void hpi_debug_message(struct hpi_message *phm, char *sz_fileline);
void hpi_debug_data(u16 *pdata, u32 len);
-#define HPI_DEBUG_DATA(pdata, len) \
- do { \
+#define HPI_DEBUG_DATA(pdata, len) \
+ do { \
if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
hpi_debug_data(pdata, len); \
} while (0)
-#define HPI_DEBUG_MESSAGE(level, phm) \
- do { \
- if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
- hpi_debug_message(phm,HPI_DEBUG_FLAG_##level \
- FILE_LINE __stringify(level));\
- } \
+#define HPI_DEBUG_MESSAGE(level, phm) \
+ do { \
+ if (hpi_debug_level >= HPI_DEBUG_LEVEL_##level) { \
+ hpi_debug_message(phm, HPI_DEBUG_FLAG_##level \
+ FILE_LINE __stringify(level)); \
+ } \
} while (0)
-#define HPI_DEBUG_RESPONSE(phr) \
- do { \
- if ((hpi_debug_level >= HPI_DEBUG_LEVEL_DEBUG) && (phr->error))\
- HPI_DEBUG_LOG(ERROR, \
- "HPI response - error# %d\n", \
- phr->error); \
- else if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE) \
- HPI_DEBUG_LOG(VERBOSE, "HPI response OK\n");\
+#define HPI_DEBUG_RESPONSE(phr) \
+ do { \
+ if (((hpi_debug_level >= HPI_DEBUG_LEVEL_DEBUG) && \
+ (phr->error)) ||\
+ (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE)) \
+ printk(KERN_DEBUG "HPI_RES%d,%d,%d\n", \
+ phr->version, phr->error, phr->specific_error); \
} while (0)
#ifndef compile_time_assert
@@ -107,279 +99,4 @@ void hpi_debug_data(u16 *pdata, u32 len);
typedef char msg[(cond) ? 1 : -1]
#endif
- /* check that size is exactly some number */
-#define function_count_check(sym, size) \
- compile_time_assert((sym##_FUNCTION_COUNT) == (size),\
- strings_match_defs_##sym)
-
-/* These strings should be generated using a macro which defines
- the corresponding symbol values. */
-#define HPI_OBJ_STRINGS \
-{ \
- "HPI_OBJ_SUBSYSTEM", \
- "HPI_OBJ_ADAPTER", \
- "HPI_OBJ_OSTREAM", \
- "HPI_OBJ_ISTREAM", \
- "HPI_OBJ_MIXER", \
- "HPI_OBJ_NODE", \
- "HPI_OBJ_CONTROL", \
- "HPI_OBJ_NVMEMORY", \
- "HPI_OBJ_DIGITALIO", \
- "HPI_OBJ_WATCHDOG", \
- "HPI_OBJ_CLOCK", \
- "HPI_OBJ_PROFILE", \
- "HPI_OBJ_CONTROLEX" \
-}
-
-#define HPI_SUBSYS_STRINGS \
-{ \
- "HPI_SUBSYS_OPEN", \
- "HPI_SUBSYS_GET_VERSION", \
- "HPI_SUBSYS_GET_INFO", \
- "HPI_SUBSYS_FIND_ADAPTERS", \
- "HPI_SUBSYS_CREATE_ADAPTER",\
- "HPI_SUBSYS_CLOSE", \
- "HPI_SUBSYS_DELETE_ADAPTER", \
- "HPI_SUBSYS_DRIVER_LOAD", \
- "HPI_SUBSYS_DRIVER_UNLOAD", \
- "HPI_SUBSYS_READ_PORT_8", \
- "HPI_SUBSYS_WRITE_PORT_8", \
- "HPI_SUBSYS_GET_NUM_ADAPTERS",\
- "HPI_SUBSYS_GET_ADAPTER", \
- "HPI_SUBSYS_SET_NETWORK_INTERFACE"\
-}
-function_count_check(HPI_SUBSYS, 14);
-
-#define HPI_ADAPTER_STRINGS \
-{ \
- "HPI_ADAPTER_OPEN", \
- "HPI_ADAPTER_CLOSE", \
- "HPI_ADAPTER_GET_INFO", \
- "HPI_ADAPTER_GET_ASSERT", \
- "HPI_ADAPTER_TEST_ASSERT", \
- "HPI_ADAPTER_SET_MODE", \
- "HPI_ADAPTER_GET_MODE", \
- "HPI_ADAPTER_ENABLE_CAPABILITY",\
- "HPI_ADAPTER_SELFTEST", \
- "HPI_ADAPTER_FIND_OBJECT", \
- "HPI_ADAPTER_QUERY_FLASH", \
- "HPI_ADAPTER_START_FLASH", \
- "HPI_ADAPTER_PROGRAM_FLASH", \
- "HPI_ADAPTER_SET_PROPERTY", \
- "HPI_ADAPTER_GET_PROPERTY", \
- "HPI_ADAPTER_ENUM_PROPERTY", \
- "HPI_ADAPTER_MODULE_INFO", \
- "HPI_ADAPTER_DEBUG_READ" \
-}
-
-function_count_check(HPI_ADAPTER, 18);
-
-#define HPI_OSTREAM_STRINGS \
-{ \
- "HPI_OSTREAM_OPEN", \
- "HPI_OSTREAM_CLOSE", \
- "HPI_OSTREAM_WRITE", \
- "HPI_OSTREAM_START", \
- "HPI_OSTREAM_STOP", \
- "HPI_OSTREAM_RESET", \
- "HPI_OSTREAM_GET_INFO", \
- "HPI_OSTREAM_QUERY_FORMAT", \
- "HPI_OSTREAM_DATA", \
- "HPI_OSTREAM_SET_VELOCITY", \
- "HPI_OSTREAM_SET_PUNCHINOUT", \
- "HPI_OSTREAM_SINEGEN", \
- "HPI_OSTREAM_ANC_RESET", \
- "HPI_OSTREAM_ANC_GET_INFO", \
- "HPI_OSTREAM_ANC_READ", \
- "HPI_OSTREAM_SET_TIMESCALE",\
- "HPI_OSTREAM_SET_FORMAT", \
- "HPI_OSTREAM_HOSTBUFFER_ALLOC", \
- "HPI_OSTREAM_HOSTBUFFER_FREE", \
- "HPI_OSTREAM_GROUP_ADD",\
- "HPI_OSTREAM_GROUP_GETMAP", \
- "HPI_OSTREAM_GROUP_RESET", \
- "HPI_OSTREAM_HOSTBUFFER_GET_INFO", \
- "HPI_OSTREAM_WAIT_START", \
-}
-function_count_check(HPI_OSTREAM, 24);
-
-#define HPI_ISTREAM_STRINGS \
-{ \
- "HPI_ISTREAM_OPEN", \
- "HPI_ISTREAM_CLOSE", \
- "HPI_ISTREAM_SET_FORMAT", \
- "HPI_ISTREAM_READ", \
- "HPI_ISTREAM_START", \
- "HPI_ISTREAM_STOP", \
- "HPI_ISTREAM_RESET", \
- "HPI_ISTREAM_GET_INFO", \
- "HPI_ISTREAM_QUERY_FORMAT", \
- "HPI_ISTREAM_ANC_RESET", \
- "HPI_ISTREAM_ANC_GET_INFO", \
- "HPI_ISTREAM_ANC_WRITE", \
- "HPI_ISTREAM_HOSTBUFFER_ALLOC",\
- "HPI_ISTREAM_HOSTBUFFER_FREE", \
- "HPI_ISTREAM_GROUP_ADD", \
- "HPI_ISTREAM_GROUP_GETMAP", \
- "HPI_ISTREAM_GROUP_RESET", \
- "HPI_ISTREAM_HOSTBUFFER_GET_INFO", \
- "HPI_ISTREAM_WAIT_START", \
-}
-function_count_check(HPI_ISTREAM, 19);
-
-#define HPI_MIXER_STRINGS \
-{ \
- "HPI_MIXER_OPEN", \
- "HPI_MIXER_CLOSE", \
- "HPI_MIXER_GET_INFO", \
- "HPI_MIXER_GET_NODE_INFO", \
- "HPI_MIXER_GET_CONTROL", \
- "HPI_MIXER_SET_CONNECTION", \
- "HPI_MIXER_GET_CONNECTIONS", \
- "HPI_MIXER_GET_CONTROL_BY_INDEX", \
- "HPI_MIXER_GET_CONTROL_ARRAY_BY_INDEX", \
- "HPI_MIXER_GET_CONTROL_MULTIPLE_VALUES", \
- "HPI_MIXER_STORE", \
-}
-function_count_check(HPI_MIXER, 11);
-
-#define HPI_CONTROL_STRINGS \
-{ \
- "HPI_CONTROL_GET_INFO", \
- "HPI_CONTROL_GET_STATE", \
- "HPI_CONTROL_SET_STATE" \
-}
-function_count_check(HPI_CONTROL, 3);
-
-#define HPI_NVMEMORY_STRINGS \
-{ \
- "HPI_NVMEMORY_OPEN", \
- "HPI_NVMEMORY_READ_BYTE", \
- "HPI_NVMEMORY_WRITE_BYTE" \
-}
-function_count_check(HPI_NVMEMORY, 3);
-
-#define HPI_DIGITALIO_STRINGS \
-{ \
- "HPI_GPIO_OPEN", \
- "HPI_GPIO_READ_BIT", \
- "HPI_GPIO_WRITE_BIT", \
- "HPI_GPIO_READ_ALL", \
- "HPI_GPIO_WRITE_STATUS"\
-}
-function_count_check(HPI_GPIO, 5);
-
-#define HPI_WATCHDOG_STRINGS \
-{ \
- "HPI_WATCHDOG_OPEN", \
- "HPI_WATCHDOG_SET_TIME", \
- "HPI_WATCHDOG_PING" \
-}
-
-#define HPI_CLOCK_STRINGS \
-{ \
- "HPI_CLOCK_OPEN", \
- "HPI_CLOCK_SET_TIME", \
- "HPI_CLOCK_GET_TIME" \
-}
-
-#define HPI_PROFILE_STRINGS \
-{ \
- "HPI_PROFILE_OPEN_ALL", \
- "HPI_PROFILE_START_ALL", \
- "HPI_PROFILE_STOP_ALL", \
- "HPI_PROFILE_GET", \
- "HPI_PROFILE_GET_IDLECOUNT", \
- "HPI_PROFILE_GET_NAME", \
- "HPI_PROFILE_GET_UTILIZATION" \
-}
-function_count_check(HPI_PROFILE, 7);
-
-#define HPI_ASYNCEVENT_STRINGS \
-{ \
- "HPI_ASYNCEVENT_OPEN",\
- "HPI_ASYNCEVENT_CLOSE ",\
- "HPI_ASYNCEVENT_WAIT",\
- "HPI_ASYNCEVENT_GETCOUNT",\
- "HPI_ASYNCEVENT_GET",\
- "HPI_ASYNCEVENT_SENDEVENTS"\
-}
-function_count_check(HPI_ASYNCEVENT, 6);
-
-#define HPI_CONTROL_TYPE_STRINGS \
-{ \
- "null control", \
- "HPI_CONTROL_CONNECTION", \
- "HPI_CONTROL_VOLUME", \
- "HPI_CONTROL_METER", \
- "HPI_CONTROL_MUTE", \
- "HPI_CONTROL_MULTIPLEXER", \
- "HPI_CONTROL_AESEBU_TRANSMITTER", \
- "HPI_CONTROL_AESEBU_RECEIVER", \
- "HPI_CONTROL_LEVEL", \
- "HPI_CONTROL_TUNER", \
- "HPI_CONTROL_ONOFFSWITCH", \
- "HPI_CONTROL_VOX", \
- "HPI_CONTROL_AES18_TRANSMITTER", \
- "HPI_CONTROL_AES18_RECEIVER", \
- "HPI_CONTROL_AES18_BLOCKGENERATOR", \
- "HPI_CONTROL_CHANNEL_MODE", \
- "HPI_CONTROL_BITSTREAM", \
- "HPI_CONTROL_SAMPLECLOCK", \
- "HPI_CONTROL_MICROPHONE", \
- "HPI_CONTROL_PARAMETRIC_EQ", \
- "HPI_CONTROL_COMPANDER", \
- "HPI_CONTROL_COBRANET", \
- "HPI_CONTROL_TONE_DETECT", \
- "HPI_CONTROL_SILENCE_DETECT", \
- "HPI_CONTROL_PAD", \
- "HPI_CONTROL_SRC" ,\
- "HPI_CONTROL_UNIVERSAL" \
-}
-
-compile_time_assert((HPI_CONTROL_LAST_INDEX + 1 == 27),
- controltype_strings_match_defs);
-
-#define HPI_SOURCENODE_STRINGS \
-{ \
- "no source", \
- "HPI_SOURCENODE_OSTREAM", \
- "HPI_SOURCENODE_LINEIN", \
- "HPI_SOURCENODE_AESEBU_IN", \
- "HPI_SOURCENODE_TUNER", \
- "HPI_SOURCENODE_RF", \
- "HPI_SOURCENODE_CLOCK_SOURCE", \
- "HPI_SOURCENODE_RAW_BITSTREAM", \
- "HPI_SOURCENODE_MICROPHONE", \
- "HPI_SOURCENODE_COBRANET", \
- "HPI_SOURCENODE_ANALOG", \
- "HPI_SOURCENODE_ADAPTER" \
-}
-
-compile_time_assert((HPI_SOURCENODE_LAST_INDEX - HPI_SOURCENODE_NONE + 1) ==
- (12), sourcenode_strings_match_defs);
-
-#define HPI_DESTNODE_STRINGS \
-{ \
- "no destination", \
- "HPI_DESTNODE_ISTREAM", \
- "HPI_DESTNODE_LINEOUT", \
- "HPI_DESTNODE_AESEBU_OUT", \
- "HPI_DESTNODE_RF", \
- "HPI_DESTNODE_SPEAKER", \
- "HPI_DESTNODE_COBRANET", \
- "HPI_DESTNODE_ANALOG" \
-}
-compile_time_assert((HPI_DESTNODE_LAST_INDEX - HPI_DESTNODE_NONE + 1) == (8),
- destnode_strings_match_defs);
-
-#define HPI_CONTROL_CHANNEL_MODE_STRINGS \
-{ \
- "XXX HPI_CHANNEL_MODE_ERROR XXX", \
- "HPI_CHANNEL_MODE_NORMAL", \
- "HPI_CHANNEL_MODE_SWAP", \
- "HPI_CHANNEL_MODE_LEFT_ONLY", \
- "HPI_CHANNEL_MODE_RIGHT_ONLY" \
-}
-
-#endif /* _HPIDEBUG_H */
+#endif /* _HPIDEBUG_H_ */
diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c
index 9b10d9a5c255..fb311d8c05bf 100644
--- a/sound/pci/asihpi/hpidspcd.c
+++ b/sound/pci/asihpi/hpidspcd.c
@@ -71,47 +71,50 @@ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code,
int err;
sprintf(fw_name, "asihpi/dsp%04x.bin", adapter);
- HPI_DEBUG_LOG(INFO, "requesting firmware for %s\n", fw_name);
err = request_firmware(&ps_firmware, fw_name,
&ps_dsp_code->ps_dev->dev);
+
if (err != 0) {
- HPI_DEBUG_LOG(ERROR, "%d, request_firmware failed for %s\n",
- err, fw_name);
+ dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+ "%d, request_firmware failed for %s\n", err,
+ fw_name);
goto error1;
}
if (ps_firmware->size < sizeof(header)) {
- HPI_DEBUG_LOG(ERROR, "header size too small %s\n", fw_name);
+ dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+ "Header size too small %s\n", fw_name);
goto error2;
}
memcpy(&header, ps_firmware->data, sizeof(header));
if (header.adapter != adapter) {
- HPI_DEBUG_LOG(ERROR, "adapter type incorrect %4x != %4x\n",
- header.adapter, adapter);
+ dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+ "Adapter type incorrect %4x != %4x\n", header.adapter,
+ adapter);
goto error2;
}
if (header.size != ps_firmware->size) {
- HPI_DEBUG_LOG(ERROR, "code size wrong %d != %ld\n",
- header.size, (unsigned long)ps_firmware->size);
+ dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+ "Code size wrong %d != %ld\n", header.size,
+ (unsigned long)ps_firmware->size);
goto error2;
}
- if (header.version / 10000 != HPI_VER_DECIMAL / 10000) {
- HPI_DEBUG_LOG(ERROR,
- "firmware major version mismatch "
- "DSP image %d != driver %d\n", header.version,
+ if (header.version / 100 != HPI_VER_DECIMAL / 100) {
+ dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev,
+ "Incompatible firmware version "
+ "DSP image %d != Driver %d\n", header.version,
HPI_VER_DECIMAL);
goto error2;
}
if (header.version != HPI_VER_DECIMAL) {
- HPI_DEBUG_LOG(WARNING,
- "version mismatch DSP image %d != driver %d\n",
+ dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev,
+ "Firmware: release version mismatch DSP image %d != Driver %d\n",
header.version, HPI_VER_DECIMAL);
- /* goto error2; still allow driver to load */
}
- HPI_DEBUG_LOG(INFO, "dsp code %s opened\n", fw_name);
+ HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name);
ps_dsp_code->ps_firmware = ps_firmware;
ps_dsp_code->block_length = header.size / sizeof(u32);
ps_dsp_code->word_count = sizeof(header) / sizeof(u32);
@@ -148,7 +151,7 @@ void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code)
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code, u32 *pword)
{
if (ps_dsp_code->word_count + 1 > ps_dsp_code->block_length)
- return (HPI_ERROR_DSP_FILE_FORMAT);
+ return HPI_ERROR_DSP_FILE_FORMAT;
*pword = ((u32 *)(ps_dsp_code->ps_firmware->data))[ps_dsp_code->
word_count];
diff --git a/sound/pci/asihpi/hpidspcd.h b/sound/pci/asihpi/hpidspcd.h
index d7c240398225..65f0ca732704 100644
--- a/sound/pci/asihpi/hpidspcd.h
+++ b/sound/pci/asihpi/hpidspcd.h
@@ -87,7 +87,7 @@ void hpi_dsp_code_rewind(struct dsp_code *ps_dsp_code);
*/
short hpi_dsp_code_read_word(struct dsp_code *ps_dsp_code,
/**< DSP code descriptor */
- u32 *pword /**< where to store the read word */
+ u32 *pword /**< Where to store the read word */
);
/** Get a block of dsp code into an internal buffer, and provide a pointer to
diff --git a/sound/pci/asihpi/hpifunc.c b/sound/pci/asihpi/hpifunc.c
index 1e92eb6dd509..c38fc9487560 100644
--- a/sound/pci/asihpi/hpifunc.c
+++ b/sound/pci/asihpi/hpifunc.c
@@ -30,16 +30,25 @@ u32 hpi_indexes_to_handle(const char c_object, const u16 adapter_index,
return handle.w;
}
-void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index,
- u16 *pw_object_index)
+static u16 hpi_handle_indexes(const u32 h, u16 *p1, u16 *p2)
{
union handle_word uhandle;
- uhandle.w = handle;
+ if (!h)
+ return HPI_ERROR_INVALID_HANDLE;
+
+ uhandle.w = h;
+
+ *p1 = (u16)uhandle.h.adapter_index;
+ if (p2)
+ *p2 = (u16)uhandle.h.obj_index;
- if (pw_adapter_index)
- *pw_adapter_index = (u16)uhandle.h.adapter_index;
- if (pw_object_index)
- *pw_object_index = (u16)uhandle.h.obj_index;
+ return 0;
+}
+
+void hpi_handle_to_indexes(const u32 handle, u16 *pw_adapter_index,
+ u16 *pw_object_index)
+{
+ hpi_handle_indexes(handle, pw_adapter_index, pw_object_index);
}
char hpi_handle_object(const u32 handle)
@@ -49,22 +58,6 @@ char hpi_handle_object(const u32 handle)
return (char)uhandle.h.obj_type;
}
-#define u32TOINDEX(h, i1) \
-do {\
- if (h == 0) \
- return HPI_ERROR_INVALID_OBJ; \
- else \
- hpi_handle_to_indexes(h, i1, NULL); \
-} while (0)
-
-#define u32TOINDEXES(h, i1, i2) \
-do {\
- if (h == 0) \
- return HPI_ERROR_INVALID_OBJ; \
- else \
- hpi_handle_to_indexes(h, i1, i2);\
-} while (0)
-
void hpi_format_to_msg(struct hpi_msg_format *pMF,
const struct hpi_format *pF)
{
@@ -94,52 +87,13 @@ void hpi_stream_response_to_legacy(struct hpi_stream_res *pSR)
pSR->u.legacy_stream_info.state = pSR->u.stream_info.state;
}
-static struct hpi_hsubsys gh_subsys;
-
-struct hpi_hsubsys *hpi_subsys_create(void)
+static inline void hpi_send_recvV1(struct hpi_message_header *m,
+ struct hpi_response_header *r)
{
- struct hpi_message hm;
- struct hpi_response hr;
-
- memset(&gh_subsys, 0, sizeof(struct hpi_hsubsys));
-
- {
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_OPEN);
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0)
- return &gh_subsys;
-
- }
- return NULL;
-}
-
-void hpi_subsys_free(const struct hpi_hsubsys *ph_subsys)
-{
- struct hpi_message hm;
- struct hpi_response hr;
-
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_CLOSE);
- hpi_send_recv(&hm, &hr);
-
+ hpi_send_recv((struct hpi_message *)m, (struct hpi_response *)r);
}
-u16 hpi_subsys_get_version(const struct hpi_hsubsys *ph_subsys, u32 *pversion)
-{
- struct hpi_message hm;
- struct hpi_response hr;
-
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_GET_VERSION);
- hpi_send_recv(&hm, &hr);
- *pversion = hr.u.s.version;
- return hr.error;
-}
-
-u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys,
- u32 *pversion_ex)
+u16 hpi_subsys_get_version_ex(u32 *pversion_ex)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -151,51 +105,8 @@ u16 hpi_subsys_get_version_ex(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_subsys_get_info(const struct hpi_hsubsys *ph_subsys, u32 *pversion,
- u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_GET_INFO);
-
- hpi_send_recv(&hm, &hr);
-
- *pversion = hr.u.s.version;
- if (list_length > HPI_MAX_ADAPTERS)
- memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
- HPI_MAX_ADAPTERS);
- else
- memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list, list_length);
- *pw_num_adapters = hr.u.s.num_adapters;
- return hr.error;
-}
-
-u16 hpi_subsys_find_adapters(const struct hpi_hsubsys *ph_subsys,
- u16 *pw_num_adapters, u16 aw_adapter_list[], u16 list_length)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_FIND_ADAPTERS);
-
- hpi_send_recv(&hm, &hr);
-
- if (list_length > HPI_MAX_ADAPTERS) {
- memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
- HPI_MAX_ADAPTERS * sizeof(u16));
- memset(&aw_adapter_list[HPI_MAX_ADAPTERS], 0,
- (list_length - HPI_MAX_ADAPTERS) * sizeof(u16));
- } else
- memcpy(aw_adapter_list, &hr.u.s.aw_adapter_list,
- list_length * sizeof(u16));
- *pw_num_adapters = hr.u.s.num_adapters;
-
- return hr.error;
-}
-
-u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys,
- const struct hpi_resource *p_resource, u16 *pw_adapter_index)
+u16 hpi_subsys_create_adapter(const struct hpi_resource *p_resource,
+ u16 *pw_adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -210,20 +121,18 @@ u16 hpi_subsys_create_adapter(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_subsys_delete_adapter(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index)
+u16 hpi_subsys_delete_adapter(u16 adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
- hm.adapter_index = adapter_index;
+ hm.obj_index = adapter_index;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys,
- int *pn_num_adapters)
+u16 hpi_subsys_get_num_adapters(int *pn_num_adapters)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -234,35 +143,22 @@ u16 hpi_subsys_get_num_adapters(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_subsys_get_adapter(const struct hpi_hsubsys *ph_subsys, int iterator,
- u32 *padapter_index, u16 *pw_adapter_type)
+u16 hpi_subsys_get_adapter(int iterator, u32 *padapter_index,
+ u16 *pw_adapter_type)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_GET_ADAPTER);
- hm.adapter_index = (u16)iterator;
+ hm.obj_index = (u16)iterator;
hpi_send_recv(&hm, &hr);
*padapter_index = (int)hr.u.s.adapter_index;
- *pw_adapter_type = hr.u.s.aw_adapter_list[0];
- return hr.error;
-}
+ *pw_adapter_type = hr.u.s.adapter_type;
-u16 hpi_subsys_set_host_network_interface(const struct hpi_hsubsys *ph_subsys,
- const char *sz_interface)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_SET_NETWORK_INTERFACE);
- if (sz_interface == NULL)
- return HPI_ERROR_INVALID_RESOURCE;
- hm.u.s.resource.r.net_if = sz_interface;
- hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
+u16 hpi_adapter_open(u16 adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -276,7 +172,7 @@ u16 hpi_adapter_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
}
-u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
+u16 hpi_adapter_close(u16 adapter_index)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -289,15 +185,14 @@ u16 hpi_adapter_close(const struct hpi_hsubsys *ph_subsys, u16 adapter_index)
return hr.error;
}
-u16 hpi_adapter_set_mode(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 adapter_mode)
+u16 hpi_adapter_set_mode(u16 adapter_index, u32 adapter_mode)
{
- return hpi_adapter_set_mode_ex(ph_subsys, adapter_index, adapter_mode,
+ return hpi_adapter_set_mode_ex(adapter_index, adapter_mode,
HPI_ADAPTER_MODE_SET);
}
-u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 adapter_mode, u16 query_or_set)
+u16 hpi_adapter_set_mode_ex(u16 adapter_index, u32 adapter_mode,
+ u16 query_or_set)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -305,14 +200,13 @@ u16 hpi_adapter_set_mode_ex(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_SET_MODE);
hm.adapter_index = adapter_index;
- hm.u.a.adapter_mode = adapter_mode;
- hm.u.a.assert_id = query_or_set;
+ hm.u.ax.mode.adapter_mode = adapter_mode;
+ hm.u.ax.mode.query_or_set = query_or_set;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 *padapter_mode)
+u16 hpi_adapter_get_mode(u16 adapter_index, u32 *padapter_mode)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -321,13 +215,13 @@ u16 hpi_adapter_get_mode(const struct hpi_hsubsys *ph_subsys,
hm.adapter_index = adapter_index;
hpi_send_recv(&hm, &hr);
if (padapter_mode)
- *padapter_mode = hr.u.a.serial_number;
+ *padapter_mode = hr.u.ax.mode.adapter_mode;
return hr.error;
}
-u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *pw_num_outstreams, u16 *pw_num_instreams,
- u16 *pw_version, u32 *pserial_number, u16 *pw_adapter_type)
+u16 hpi_adapter_get_info(u16 adapter_index, u16 *pw_num_outstreams,
+ u16 *pw_num_instreams, u16 *pw_version, u32 *pserial_number,
+ u16 *pw_adapter_type)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -337,18 +231,17 @@ u16 hpi_adapter_get_info(const struct hpi_hsubsys *ph_subsys,
hpi_send_recv(&hm, &hr);
- *pw_adapter_type = hr.u.a.adapter_type;
- *pw_num_outstreams = hr.u.a.num_outstreams;
- *pw_num_instreams = hr.u.a.num_instreams;
- *pw_version = hr.u.a.version;
- *pserial_number = hr.u.a.serial_number;
+ *pw_adapter_type = hr.u.ax.info.adapter_type;
+ *pw_num_outstreams = hr.u.ax.info.num_outstreams;
+ *pw_num_instreams = hr.u.ax.info.num_instreams;
+ *pw_version = hr.u.ax.info.version;
+ *pserial_number = hr.u.ax.info.serial_number;
return hr.error;
}
-u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 module_index, u16 *pw_num_outputs,
- u16 *pw_num_inputs, u16 *pw_version, u32 *pserial_number,
- u16 *pw_module_type, u32 *ph_module)
+u16 hpi_adapter_get_module_by_index(u16 adapter_index, u16 module_index,
+ u16 *pw_num_outputs, u16 *pw_num_inputs, u16 *pw_version,
+ u32 *pserial_number, u16 *pw_module_type, u32 *ph_module)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -360,173 +253,18 @@ u16 hpi_adapter_get_module_by_index(const struct hpi_hsubsys *ph_subsys,
hpi_send_recv(&hm, &hr);
- *pw_module_type = hr.u.a.adapter_type;
- *pw_num_outputs = hr.u.a.num_outstreams;
- *pw_num_inputs = hr.u.a.num_instreams;
- *pw_version = hr.u.a.version;
- *pserial_number = hr.u.a.serial_number;
+ *pw_module_type = hr.u.ax.info.adapter_type;
+ *pw_num_outputs = hr.u.ax.info.num_outstreams;
+ *pw_num_inputs = hr.u.ax.info.num_instreams;
+ *pw_version = hr.u.ax.info.version;
+ *pserial_number = hr.u.ax.info.serial_number;
*ph_module = 0;
return hr.error;
}
-u16 hpi_adapter_get_assert(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *assert_present, char *psz_assert,
- u16 *pw_line_number)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_GET_ASSERT);
- hm.adapter_index = adapter_index;
- hpi_send_recv(&hm, &hr);
-
- *assert_present = 0;
-
- if (!hr.error) {
-
- *pw_line_number = (u16)hr.u.a.serial_number;
- if (*pw_line_number) {
-
- int i;
- char *src = (char *)hr.u.a.sz_adapter_assert;
- char *dst = psz_assert;
-
- *assert_present = 1;
-
- for (i = 0; i < HPI_STRING_LEN; i++) {
- char c;
- c = *src++;
- *dst++ = c;
- if (c == 0)
- break;
- }
-
- }
- }
- return hr.error;
-}
-
-u16 hpi_adapter_get_assert_ex(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 *assert_present, char *psz_assert,
- u32 *pline_number, u16 *pw_assert_on_dsp)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_GET_ASSERT);
- hm.adapter_index = adapter_index;
-
- hpi_send_recv(&hm, &hr);
-
- *assert_present = 0;
-
- if (!hr.error) {
-
- *pline_number = hr.u.a.serial_number;
-
- *assert_present = hr.u.a.adapter_type;
-
- *pw_assert_on_dsp = hr.u.a.adapter_index;
-
- if (!*assert_present && *pline_number)
-
- *assert_present = 1;
-
- if (*assert_present) {
-
- int i;
- char *src = (char *)hr.u.a.sz_adapter_assert;
- char *dst = psz_assert;
-
- for (i = 0; i < HPI_STRING_LEN; i++) {
- char c;
- c = *src++;
- *dst++ = c;
- if (c == 0)
- break;
- }
-
- } else {
- *psz_assert = 0;
- }
- }
- return hr.error;
-}
-
-u16 hpi_adapter_test_assert(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 assert_id)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_TEST_ASSERT);
- hm.adapter_index = adapter_index;
- hm.u.a.assert_id = assert_id;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_adapter_enable_capability(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 capability, u32 key)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_ENABLE_CAPABILITY);
- hm.adapter_index = adapter_index;
- hm.u.a.assert_id = capability;
- hm.u.a.adapter_mode = key;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_adapter_self_test(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_SELFTEST);
- hm.adapter_index = adapter_index;
- hpi_send_recv(&hm, &hr);
- return hr.error;
-}
-
-u16 hpi_adapter_debug_read(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 dsp_address, char *p_buffer, int *count_bytes)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
- HPI_ADAPTER_DEBUG_READ);
-
- hr.size = sizeof(hr);
-
- hm.adapter_index = adapter_index;
- hm.u.ax.debug_read.dsp_address = dsp_address;
-
- if (*count_bytes > (int)sizeof(hr.u.bytes))
- *count_bytes = sizeof(hr.u.bytes);
-
- hm.u.ax.debug_read.count_bytes = *count_bytes;
-
- hpi_send_recv(&hm, &hr);
-
- if (!hr.error) {
- *count_bytes = hr.size - 12;
- memcpy(p_buffer, &hr.u.bytes, *count_bytes);
- } else
- *count_bytes = 0;
- return hr.error;
-}
-
-u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 property, u16 parameter1, u16 parameter2)
+u16 hpi_adapter_set_property(u16 adapter_index, u16 property, u16 parameter1,
+ u16 parameter2)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -542,9 +280,8 @@ u16 hpi_adapter_set_property(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 property, u16 *pw_parameter1,
- u16 *pw_parameter2)
+u16 hpi_adapter_get_property(u16 adapter_index, u16 property,
+ u16 *pw_parameter1, u16 *pw_parameter2)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -564,9 +301,8 @@ u16 hpi_adapter_get_property(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 index, u16 what_to_enumerate,
- u16 property_index, u32 *psetting)
+u16 hpi_adapter_enumerate_property(u16 adapter_index, u16 index,
+ u16 what_to_enumerate, u16 property_index, u32 *psetting)
{
return 0;
}
@@ -574,7 +310,7 @@ u16 hpi_adapter_enumerate_property(const struct hpi_hsubsys *ph_subsys,
u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
u32 sample_rate, u32 bit_rate, u32 attributes)
{
- u16 error = 0;
+ u16 err = 0;
struct hpi_msg_format fmt;
switch (channels) {
@@ -586,8 +322,8 @@ u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
case 16:
break;
default:
- error = HPI_ERROR_INVALID_CHANNELS;
- return error;
+ err = HPI_ERROR_INVALID_CHANNELS;
+ return err;
}
fmt.channels = channels;
@@ -610,17 +346,17 @@ u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
case HPI_FORMAT_OEM2:
break;
default:
- error = HPI_ERROR_INVALID_FORMAT;
- return error;
+ err = HPI_ERROR_INVALID_FORMAT;
+ return err;
}
fmt.format = format;
if (sample_rate < 8000L) {
- error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
+ err = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
sample_rate = 8000L;
}
if (sample_rate > 200000L) {
- error = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
+ err = HPI_ERROR_INCOMPATIBLE_SAMPLERATE;
sample_rate = 200000L;
}
fmt.sample_rate = sample_rate;
@@ -651,10 +387,10 @@ u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
if ((channels == 1)
&& (attributes != HPI_MPEG_MODE_DEFAULT)) {
attributes = HPI_MPEG_MODE_DEFAULT;
- error = HPI_ERROR_INVALID_FORMAT;
+ err = HPI_ERROR_INVALID_FORMAT;
} else if (attributes > HPI_MPEG_MODE_DUALCHANNEL) {
attributes = HPI_MPEG_MODE_DEFAULT;
- error = HPI_ERROR_INVALID_FORMAT;
+ err = HPI_ERROR_INVALID_FORMAT;
}
fmt.attributes = attributes;
break;
@@ -663,7 +399,7 @@ u16 hpi_format_create(struct hpi_format *p_format, u16 channels, u16 format,
}
hpi_msg_to_format(p_format, &fmt);
- return error;
+ return err;
}
u16 hpi_stream_estimate_buffer_size(struct hpi_format *p_format,
@@ -712,8 +448,8 @@ u16 hpi_stream_estimate_buffer_size(struct hpi_format *p_format,
return 0;
}
-u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u16 outstream_index, u32 *ph_outstream)
+u16 hpi_outstream_open(u16 adapter_index, u16 outstream_index,
+ u32 *ph_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -733,38 +469,41 @@ u16 hpi_outstream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
return hr.error;
}
-u16 hpi_outstream_close(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+u16 hpi_outstream_close(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_HOSTBUFFER_FREE);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
+
hpi_send_recv(&hm, &hr);
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_GROUP_RESET);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index);
hpi_send_recv(&hm, &hr);
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_CLOSE);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index);
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_to_play,
- u32 *psamples_played, u32 *pauxiliary_data_to_play)
+u16 hpi_outstream_get_info_ex(u32 h_outstream, u16 *pw_state,
+ u32 *pbuffer_size, u32 *pdata_to_play, u32 *psamples_played,
+ u32 *pauxiliary_data_to_play)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_GET_INFO);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
@@ -782,15 +521,15 @@ u16 hpi_outstream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, const u8 *pb_data, u32 bytes_to_write,
- const struct hpi_format *p_format)
+u16 hpi_outstream_write_buf(u32 h_outstream, const u8 *pb_data,
+ u32 bytes_to_write, const struct hpi_format *p_format)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_WRITE);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.pb_data = (u8 *)pb_data;
hm.u.d.u.data.data_size = bytes_to_write;
@@ -801,82 +540,85 @@ u16 hpi_outstream_write_buf(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_start(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+u16 hpi_outstream_start(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_START);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_wait_start(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream)
+u16 hpi_outstream_wait_start(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_WAIT_START);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+u16 hpi_outstream_stop(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_STOP);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_sinegen(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream)
+u16 hpi_outstream_sinegen(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_SINEGEN);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_outstream)
+u16 hpi_outstream_reset(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_RESET);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_format *p_format)
+u16 hpi_outstream_query_format(u32 h_outstream, struct hpi_format *p_format)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_QUERY_FORMAT);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
@@ -885,15 +627,15 @@ u16 hpi_outstream_query_format(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_format *p_format)
+u16 hpi_outstream_set_format(u32 h_outstream, struct hpi_format *p_format)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_SET_FORMAT);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
@@ -902,15 +644,15 @@ u16 hpi_outstream_set_format(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, short velocity)
+u16 hpi_outstream_set_velocity(u32 h_outstream, short velocity)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_SET_VELOCITY);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.velocity = velocity;
hpi_send_recv(&hm, &hr);
@@ -918,15 +660,16 @@ u16 hpi_outstream_set_velocity(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 punch_in_sample, u32 punch_out_sample)
+u16 hpi_outstream_set_punch_in_out(u32 h_outstream, u32 punch_in_sample,
+ u32 punch_out_sample)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_SET_PUNCHINOUT);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.pio.punch_in_sample = punch_in_sample;
hm.u.d.u.pio.punch_out_sample = punch_out_sample;
@@ -936,29 +679,29 @@ u16 hpi_outstream_set_punch_in_out(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u16 mode)
+u16 hpi_outstream_ancillary_reset(u32 h_outstream, u16 mode)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_ANC_RESET);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.format.channels = mode;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 *pframes_available)
+u16 hpi_outstream_ancillary_get_info(u32 h_outstream, u32 *pframes_available)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_ANC_GET_INFO);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (hr.error == 0) {
if (pframes_available)
@@ -969,8 +712,8 @@ u16 hpi_outstream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, struct hpi_anc_frame *p_anc_frame_buffer,
+u16 hpi_outstream_ancillary_read(u32 h_outstream,
+ struct hpi_anc_frame *p_anc_frame_buffer,
u32 anc_frame_buffer_size_in_bytes,
u32 number_of_ancillary_frames_to_read)
{
@@ -979,7 +722,8 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_ANC_READ);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer;
hm.u.d.u.data.data_size =
number_of_ancillary_frames_to_read *
@@ -987,19 +731,19 @@ u16 hpi_outstream_ancillary_read(const struct hpi_hsubsys *ph_subsys,
if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes)
hpi_send_recv(&hm, &hr);
else
- hr.error = HPI_ERROR_INVALID_DATA_TRANSFER;
+ hr.error = HPI_ERROR_INVALID_DATASIZE;
return hr.error;
}
-u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 time_scale)
+u16 hpi_outstream_set_time_scale(u32 h_outstream, u32 time_scale)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_SET_TIMESCALE);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.time_scale = time_scale;
@@ -1008,22 +752,21 @@ u16 hpi_outstream_set_time_scale(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 size_in_bytes)
+u16 hpi_outstream_host_buffer_allocate(u32 h_outstream, u32 size_in_bytes)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_HOSTBUFFER_ALLOC);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.data_size = size_in_bytes;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u8 **pp_buffer,
+u16 hpi_outstream_host_buffer_get_info(u32 h_outstream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status)
{
struct hpi_message hm;
@@ -1031,7 +774,8 @@ u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_HOSTBUFFER_GET_INFO);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (hr.error == 0) {
@@ -1043,21 +787,20 @@ u16 hpi_outstream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream)
+u16 hpi_outstream_host_buffer_free(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_HOSTBUFFER_FREE);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 h_stream)
+u16 hpi_outstream_group_add(u32 h_outstream, u32 h_stream)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -1066,22 +809,22 @@ u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_GROUP_ADD);
- hr.error = 0;
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
+
+ if (hpi_handle_indexes(h_stream, &adapter,
+ &hm.u.d.u.stream.stream_index))
+ return HPI_ERROR_INVALID_HANDLE;
+
c_obj_type = hpi_handle_object(h_stream);
switch (c_obj_type) {
case HPI_OBJ_OSTREAM:
- hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM;
- u32TOINDEXES(h_stream, &adapter,
- &hm.u.d.u.stream.stream_index);
- break;
case HPI_OBJ_ISTREAM:
- hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM;
- u32TOINDEXES(h_stream, &adapter,
- &hm.u.d.u.stream.stream_index);
+ hm.u.d.u.stream.object_type = c_obj_type;
break;
default:
- return HPI_ERROR_INVALID_STREAM;
+ return HPI_ERROR_INVALID_OBJ;
}
if (adapter != hm.adapter_index)
return HPI_ERROR_NO_INTERADAPTER_GROUPS;
@@ -1090,15 +833,16 @@ u16 hpi_outstream_group_add(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream, u32 *poutstream_map, u32 *pinstream_map)
+u16 hpi_outstream_group_get_map(u32 h_outstream, u32 *poutstream_map,
+ u32 *pinstream_map)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_GROUP_GETMAP);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (poutstream_map)
@@ -1109,21 +853,20 @@ u16 hpi_outstream_group_get_map(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_outstream_group_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_outstream)
+u16 hpi_outstream_group_reset(u32 h_outstream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_GROUP_RESET);
- u32TOINDEXES(h_outstream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_outstream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u16 instream_index, u32 *ph_instream)
+u16 hpi_instream_open(u16 adapter_index, u16 instream_index, u32 *ph_instream)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -1145,38 +888,40 @@ u16 hpi_instream_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
return hr.error;
}
-u16 hpi_instream_close(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+u16 hpi_instream_close(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_HOSTBUFFER_FREE);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_GROUP_RESET);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index);
hpi_send_recv(&hm, &hr);
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_CLOSE);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index);
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_format *p_format)
+u16 hpi_instream_query_format(u32 h_instream,
+ const struct hpi_format *p_format)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_QUERY_FORMAT);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
hpi_send_recv(&hm, &hr);
@@ -1184,15 +929,15 @@ u16 hpi_instream_query_format(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_format *p_format)
+u16 hpi_instream_set_format(u32 h_instream, const struct hpi_format *p_format)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_SET_FORMAT);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_format_to_msg(&hm.u.d.u.data.format, p_format);
hpi_send_recv(&hm, &hr);
@@ -1200,15 +945,15 @@ u16 hpi_instream_set_format(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream,
- u8 *pb_data, u32 bytes_to_read)
+u16 hpi_instream_read_buf(u32 h_instream, u8 *pb_data, u32 bytes_to_read)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_READ);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.data_size = bytes_to_read;
hm.u.d.u.data.pb_data = pb_data;
@@ -1217,72 +962,76 @@ u16 hpi_instream_read_buf(const struct hpi_hsubsys *ph_subsys, u32 h_instream,
return hr.error;
}
-u16 hpi_instream_start(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+u16 hpi_instream_start(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_START);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_wait_start(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream)
+u16 hpi_instream_wait_start(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_WAIT_START);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_stop(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+u16 hpi_instream_stop(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_STOP);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_reset(const struct hpi_hsubsys *ph_subsys, u32 h_instream)
+u16 hpi_instream_reset(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_RESET);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u16 *pw_state, u32 *pbuffer_size, u32 *pdata_recorded,
- u32 *psamples_recorded, u32 *pauxiliary_data_recorded)
+u16 hpi_instream_get_info_ex(u32 h_instream, u16 *pw_state, u32 *pbuffer_size,
+ u32 *pdata_recorded, u32 *psamples_recorded,
+ u32 *pauxiliary_data_recorded)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_GET_INFO);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
@@ -1300,15 +1049,15 @@ u16 hpi_instream_get_info_ex(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u16 bytes_per_frame, u16 mode, u16 alignment,
- u16 idle_bit)
+u16 hpi_instream_ancillary_reset(u32 h_instream, u16 bytes_per_frame,
+ u16 mode, u16 alignment, u16 idle_bit)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_ANC_RESET);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.format.attributes = bytes_per_frame;
hm.u.d.u.data.format.format = (mode << 8) | (alignment & 0xff);
hm.u.d.u.data.format.channels = idle_bit;
@@ -1316,14 +1065,14 @@ u16 hpi_instream_ancillary_reset(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 *pframe_space)
+u16 hpi_instream_ancillary_get_info(u32 h_instream, u32 *pframe_space)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_ANC_GET_INFO);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (pframe_space)
*pframe_space =
@@ -1333,8 +1082,8 @@ u16 hpi_instream_ancillary_get_info(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, const struct hpi_anc_frame *p_anc_frame_buffer,
+u16 hpi_instream_ancillary_write(u32 h_instream,
+ const struct hpi_anc_frame *p_anc_frame_buffer,
u32 anc_frame_buffer_size_in_bytes,
u32 number_of_ancillary_frames_to_write)
{
@@ -1343,7 +1092,8 @@ u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_ANC_WRITE);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.pb_data = (u8 *)p_anc_frame_buffer;
hm.u.d.u.data.data_size =
number_of_ancillary_frames_to_write *
@@ -1351,12 +1101,11 @@ u16 hpi_instream_ancillary_write(const struct hpi_hsubsys *ph_subsys,
if (hm.u.d.u.data.data_size <= anc_frame_buffer_size_in_bytes)
hpi_send_recv(&hm, &hr);
else
- hr.error = HPI_ERROR_INVALID_DATA_TRANSFER;
+ hr.error = HPI_ERROR_INVALID_DATASIZE;
return hr.error;
}
-u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 size_in_bytes)
+u16 hpi_instream_host_buffer_allocate(u32 h_instream, u32 size_in_bytes)
{
struct hpi_message hm;
@@ -1364,14 +1113,14 @@ u16 hpi_instream_host_buffer_allocate(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_HOSTBUFFER_ALLOC);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.d.u.data.data_size = size_in_bytes;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u8 **pp_buffer,
+u16 hpi_instream_host_buffer_get_info(u32 h_instream, u8 **pp_buffer,
struct hpi_hostbuffer_status **pp_status)
{
struct hpi_message hm;
@@ -1379,7 +1128,8 @@ u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_HOSTBUFFER_GET_INFO);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (hr.error == 0) {
@@ -1391,8 +1141,7 @@ u16 hpi_instream_host_buffer_get_info(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream)
+u16 hpi_instream_host_buffer_free(u32 h_instream)
{
struct hpi_message hm;
@@ -1400,13 +1149,13 @@ u16 hpi_instream_host_buffer_free(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_HOSTBUFFER_FREE);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 h_stream)
+u16 hpi_instream_group_add(u32 h_instream, u32 h_stream)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -1416,22 +1165,23 @@ u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_GROUP_ADD);
hr.error = 0;
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
+
+ if (hpi_handle_indexes(h_stream, &adapter,
+ &hm.u.d.u.stream.stream_index))
+ return HPI_ERROR_INVALID_HANDLE;
+
c_obj_type = hpi_handle_object(h_stream);
switch (c_obj_type) {
case HPI_OBJ_OSTREAM:
- hm.u.d.u.stream.object_type = HPI_OBJ_OSTREAM;
- u32TOINDEXES(h_stream, &adapter,
- &hm.u.d.u.stream.stream_index);
- break;
case HPI_OBJ_ISTREAM:
- hm.u.d.u.stream.object_type = HPI_OBJ_ISTREAM;
- u32TOINDEXES(h_stream, &adapter,
- &hm.u.d.u.stream.stream_index);
+ hm.u.d.u.stream.object_type = c_obj_type;
break;
default:
- return HPI_ERROR_INVALID_STREAM;
+ return HPI_ERROR_INVALID_OBJ;
}
if (adapter != hm.adapter_index)
@@ -1441,15 +1191,16 @@ u16 hpi_instream_group_add(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream, u32 *poutstream_map, u32 *pinstream_map)
+u16 hpi_instream_group_get_map(u32 h_instream, u32 *poutstream_map,
+ u32 *pinstream_map)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_HOSTBUFFER_FREE);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
if (poutstream_map)
@@ -1460,21 +1211,20 @@ u16 hpi_instream_group_get_map(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_instream_group_reset(const struct hpi_hsubsys *ph_subsys,
- u32 h_instream)
+u16 hpi_instream_group_reset(u32 h_instream)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_GROUP_RESET);
- u32TOINDEXES(h_instream, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_instream, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_mixer)
+u16 hpi_mixer_open(u16 adapter_index, u32 *ph_mixer)
{
struct hpi_message hm;
struct hpi_response hr;
@@ -1492,25 +1242,29 @@ u16 hpi_mixer_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
return hr.error;
}
-u16 hpi_mixer_close(const struct hpi_hsubsys *ph_subsys, u32 h_mixer)
+u16 hpi_mixer_close(u32 h_mixer)
{
struct hpi_message hm;
struct hpi_response hr;
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_CLOSE);
- u32TOINDEX(h_mixer, &hm.adapter_index);
+ if (hpi_handle_indexes(h_mixer, &hm.adapter_index, NULL))
+ return HPI_ERROR_INVALID_HANDLE;
+
hpi_send_recv(&hm, &hr);
return hr.error;
}
-u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
- u16 src_node_type, u16 src_node_type_index, u16 dst_node_type,
- u16 dst_node_type_index, u16 control_type, u32 *ph_control)
+u16 hpi_mixer_get_control(u32 h_mixer, u16 src_node_type,
+ u16 src_node_type_index, u16 dst_node_type, u16 dst_node_type_index,
+ u16 control_type, u32 *ph_control)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER,
HPI_MIXER_GET_CONTROL);
- u32TOINDEX(h_mixer, &hm.adapter_index);
+ if (hpi_handle_indexes(h_mixer, &hm.adapter_index, NULL))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.m.node_type1 = src_node_type;
hm.u.m.node_index1 = src_node_type_index;
hm.u.m.node_type2 = dst_node_type;
@@ -1528,16 +1282,16 @@ u16 hpi_mixer_get_control(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
return hr.error;
}
-u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_mixer, u16 control_index, u16 *pw_src_node_type,
- u16 *pw_src_node_index, u16 *pw_dst_node_type, u16 *pw_dst_node_index,
- u16 *pw_control_type, u32 *ph_control)
+u16 hpi_mixer_get_control_by_index(u32 h_mixer, u16 control_index,
+ u16 *pw_src_node_type, u16 *pw_src_node_index, u16 *pw_dst_node_type,
+ u16 *pw_dst_node_index, u16 *pw_control_type, u32 *ph_control)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER,
HPI_MIXER_GET_CONTROL_BY_INDEX);
- u32TOINDEX(h_mixer, &hm.adapter_index);
+ if (hpi_handle_indexes(h_mixer, &hm.adapter_index, NULL))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.m.control_index = control_index;
hpi_send_recv(&hm, &hr);
@@ -1562,13 +1316,14 @@ u16 hpi_mixer_get_control_by_index(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
- enum HPI_MIXER_STORE_COMMAND command, u16 index)
+u16 hpi_mixer_store(u32 h_mixer, enum HPI_MIXER_STORE_COMMAND command,
+ u16 index)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_MIXER, HPI_MIXER_STORE);
- u32TOINDEX(h_mixer, &hm.adapter_index);
+ if (hpi_handle_indexes(h_mixer, &hm.adapter_index, NULL))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.mx.store.command = command;
hm.u.mx.store.index = index;
hpi_send_recv(&hm, &hr);
@@ -1576,16 +1331,16 @@ u16 hpi_mixer_store(const struct hpi_hsubsys *ph_subsys, u32 h_mixer,
}
static
-u16 hpi_control_param_set(const struct hpi_hsubsys *ph_subsys,
- const u32 h_control, const u16 attrib, const u32 param1,
- const u32 param2)
+u16 hpi_control_param_set(const u32 h_control, const u16 attrib,
+ const u32 param1, const u32 param2)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attrib;
hm.u.c.param1 = param1;
hm.u.c.param2 = param2;
@@ -1601,7 +1356,8 @@ static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attrib;
hm.u.c.an_log_value[0] = sv0;
hm.u.c.an_log_value[1] = sv1;
@@ -1610,16 +1366,16 @@ static u16 hpi_control_log_set2(u32 h_control, u16 attrib, short sv0,
}
static
-u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
- const u32 h_control, const u16 attrib, u32 param1, u32 param2,
- u32 *pparam1, u32 *pparam2)
+u16 hpi_control_param_get(const u32 h_control, const u16 attrib, u32 param1,
+ u32 param2, u32 *pparam1, u32 *pparam2)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attrib;
hm.u.c.param1 = param1;
hm.u.c.param2 = param2;
@@ -1632,19 +1388,20 @@ u16 hpi_control_param_get(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-#define hpi_control_param1_get(s, h, a, p1) \
- hpi_control_param_get(s, h, a, 0, 0, p1, NULL)
-#define hpi_control_param2_get(s, h, a, p1, p2) \
- hpi_control_param_get(s, h, a, 0, 0, p1, p2)
+#define hpi_control_param1_get(h, a, p1) \
+ hpi_control_param_get(h, a, 0, 0, p1, NULL)
+#define hpi_control_param2_get(h, a, p1, p2) \
+ hpi_control_param_get(h, a, 0, 0, p1, p2)
-static u16 hpi_control_log_get2(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 attrib, short *sv0, short *sv1)
+static u16 hpi_control_log_get2(u32 h_control, u16 attrib, short *sv0,
+ short *sv1)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attrib;
hpi_send_recv(&hm, &hr);
@@ -1655,8 +1412,7 @@ static u16 hpi_control_log_get2(const struct hpi_hsubsys *ph_subsys,
}
static
-u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
- const u32 h_control, const u16 attrib, const u32 index,
+u16 hpi_control_query(const u32 h_control, const u16 attrib, const u32 index,
const u32 param, u32 *psetting)
{
struct hpi_message hm;
@@ -1664,7 +1420,8 @@ u16 hpi_control_query(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_INFO);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attrib;
hm.u.c.param1 = index;
@@ -1682,7 +1439,7 @@ static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
unsigned int sub_string_index = 0, j = 0;
char c = 0;
unsigned int n = 0;
- u16 hE = 0;
+ u16 err = 0;
if ((string_length < 1) || (string_length > 256))
return HPI_ERROR_INVALID_CONTROL_VALUE;
@@ -1693,7 +1450,9 @@ static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index,
+ &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = attribute;
hm.u.c.param1 = sub_string_index;
hm.u.c.param2 = 0;
@@ -1705,7 +1464,7 @@ static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
return HPI_ERROR_INVALID_CONTROL_VALUE;
if (hr.error) {
- hE = hr.error;
+ err = hr.error;
break;
}
for (j = 0; j < 8; j++) {
@@ -1714,7 +1473,7 @@ static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
n++;
if (n >= string_length) {
psz_string[string_length - 1] = 0;
- hE = HPI_ERROR_INVALID_CONTROL_VALUE;
+ err = HPI_ERROR_INVALID_CONTROL_VALUE;
break;
}
if (c == 0)
@@ -1730,57 +1489,52 @@ static u16 hpi_control_get_string(const u32 h_control, const u16 attribute,
if (c == 0)
break;
}
- return hE;
+ return err;
}
-u16 HPI_AESEBU__receiver_query_format(const struct hpi_hsubsys *ph_subsys,
- const u32 h_aes_rx, const u32 index, u16 *pw_format)
+u16 hpi_aesebu_receiver_query_format(const u32 h_aes_rx, const u32 index,
+ u16 *pw_format)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_aes_rx, HPI_AESEBURX_FORMAT,
- index, 0, &qr);
+ err = hpi_control_query(h_aes_rx, HPI_AESEBURX_FORMAT, index, 0, &qr);
*pw_format = (u16)qr;
return err;
}
-u16 HPI_AESEBU__receiver_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 format)
+u16 hpi_aesebu_receiver_set_format(u32 h_control, u16 format)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_AESEBURX_FORMAT, format, 0);
+ return hpi_control_param_set(h_control, HPI_AESEBURX_FORMAT, format,
+ 0);
}
-u16 HPI_AESEBU__receiver_get_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_format)
+u16 hpi_aesebu_receiver_get_format(u32 h_control, u16 *pw_format)
{
u16 err;
u32 param;
- err = hpi_control_param1_get(ph_subsys, h_control,
- HPI_AESEBURX_FORMAT, &param);
+ err = hpi_control_param1_get(h_control, HPI_AESEBURX_FORMAT, &param);
if (!err && pw_format)
*pw_format = (u16)param;
return err;
}
-u16 HPI_AESEBU__receiver_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate)
+u16 hpi_aesebu_receiver_get_sample_rate(u32 h_control, u32 *psample_rate)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_AESEBURX_SAMPLERATE, psample_rate);
+ return hpi_control_param1_get(h_control, HPI_AESEBURX_SAMPLERATE,
+ psample_rate);
}
-u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *pw_data)
+u16 hpi_aesebu_receiver_get_user_data(u32 h_control, u16 index, u16 *pw_data)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_AESEBURX_USERDATA;
hm.u.c.param1 = index;
@@ -1791,14 +1545,15 @@ u16 HPI_AESEBU__receiver_get_user_data(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 *pw_data)
+u16 hpi_aesebu_receiver_get_channel_status(u32 h_control, u16 index,
+ u16 *pw_data)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_AESEBURX_CHANNELSTATUS;
hm.u.c.param1 = index;
@@ -1809,101 +1564,93 @@ u16 HPI_AESEBU__receiver_get_channel_status(const struct hpi_hsubsys
return hr.error;
}
-u16 HPI_AESEBU__receiver_get_error_status(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_error_data)
+u16 hpi_aesebu_receiver_get_error_status(u32 h_control, u16 *pw_error_data)
{
u32 error_data = 0;
- u16 error = 0;
+ u16 err = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
- HPI_AESEBURX_ERRORSTATUS, &error_data);
+ err = hpi_control_param1_get(h_control, HPI_AESEBURX_ERRORSTATUS,
+ &error_data);
if (pw_error_data)
*pw_error_data = (u16)error_data;
- return error;
+ return err;
}
-u16 HPI_AESEBU__transmitter_set_sample_rate(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u32 sample_rate)
+u16 hpi_aesebu_transmitter_set_sample_rate(u32 h_control, u32 sample_rate)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_AESEBUTX_SAMPLERATE, sample_rate, 0);
+ return hpi_control_param_set(h_control, HPI_AESEBUTX_SAMPLERATE,
+ sample_rate, 0);
}
-u16 HPI_AESEBU__transmitter_set_user_data(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 data)
+u16 hpi_aesebu_transmitter_set_user_data(u32 h_control, u16 index, u16 data)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_AESEBUTX_USERDATA, index, data);
+ return hpi_control_param_set(h_control, HPI_AESEBUTX_USERDATA, index,
+ data);
}
-u16 HPI_AESEBU__transmitter_set_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 data)
+u16 hpi_aesebu_transmitter_set_channel_status(u32 h_control, u16 index,
+ u16 data)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_AESEBUTX_CHANNELSTATUS, index, data);
+ return hpi_control_param_set(h_control, HPI_AESEBUTX_CHANNELSTATUS,
+ index, data);
}
-u16 HPI_AESEBU__transmitter_get_channel_status(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, u16 index, u16 *pw_data)
+u16 hpi_aesebu_transmitter_get_channel_status(u32 h_control, u16 index,
+ u16 *pw_data)
{
return HPI_ERROR_INVALID_OPERATION;
}
-u16 HPI_AESEBU__transmitter_query_format(const struct hpi_hsubsys *ph_subsys,
- const u32 h_aes_tx, const u32 index, u16 *pw_format)
+u16 hpi_aesebu_transmitter_query_format(const u32 h_aes_tx, const u32 index,
+ u16 *pw_format)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_aes_tx, HPI_AESEBUTX_FORMAT,
- index, 0, &qr);
+ err = hpi_control_query(h_aes_tx, HPI_AESEBUTX_FORMAT, index, 0, &qr);
*pw_format = (u16)qr;
return err;
}
-u16 HPI_AESEBU__transmitter_set_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 output_format)
+u16 hpi_aesebu_transmitter_set_format(u32 h_control, u16 output_format)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_AESEBUTX_FORMAT, output_format, 0);
+ return hpi_control_param_set(h_control, HPI_AESEBUTX_FORMAT,
+ output_format, 0);
}
-u16 HPI_AESEBU__transmitter_get_format(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_output_format)
+u16 hpi_aesebu_transmitter_get_format(u32 h_control, u16 *pw_output_format)
{
u16 err;
u32 param;
- err = hpi_control_param1_get(ph_subsys, h_control,
- HPI_AESEBUTX_FORMAT, &param);
+ err = hpi_control_param1_get(h_control, HPI_AESEBUTX_FORMAT, &param);
if (!err && pw_output_format)
*pw_output_format = (u16)param;
return err;
}
-u16 hpi_bitstream_set_clock_edge(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 edge_type)
+u16 hpi_bitstream_set_clock_edge(u32 h_control, u16 edge_type)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_BITSTREAM_CLOCK_EDGE, edge_type, 0);
+ return hpi_control_param_set(h_control, HPI_BITSTREAM_CLOCK_EDGE,
+ edge_type, 0);
}
-u16 hpi_bitstream_set_data_polarity(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 polarity)
+u16 hpi_bitstream_set_data_polarity(u32 h_control, u16 polarity)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_BITSTREAM_DATA_POLARITY, polarity, 0);
+ return hpi_control_param_set(h_control, HPI_BITSTREAM_DATA_POLARITY,
+ polarity, 0);
}
-u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_clk_activity, u16 *pw_data_activity)
+u16 hpi_bitstream_get_activity(u32 h_control, u16 *pw_clk_activity,
+ u16 *pw_data_activity)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_BITSTREAM_ACTIVITY;
hpi_send_recv(&hm, &hr);
if (pw_clk_activity)
@@ -1913,45 +1660,43 @@ u16 hpi_bitstream_get_activity(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_channel_mode_query_mode(const struct hpi_hsubsys *ph_subsys,
- const u32 h_mode, const u32 index, u16 *pw_mode)
+u16 hpi_channel_mode_query_mode(const u32 h_mode, const u32 index,
+ u16 *pw_mode)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_mode, HPI_CHANNEL_MODE_MODE,
- index, 0, &qr);
+ err = hpi_control_query(h_mode, HPI_CHANNEL_MODE_MODE, index, 0, &qr);
*pw_mode = (u16)qr;
return err;
}
-u16 hpi_channel_mode_set(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 mode)
+u16 hpi_channel_mode_set(u32 h_control, u16 mode)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_CHANNEL_MODE_MODE, mode, 0);
+ return hpi_control_param_set(h_control, HPI_CHANNEL_MODE_MODE, mode,
+ 0);
}
-u16 hpi_channel_mode_get(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *mode)
+u16 hpi_channel_mode_get(u32 h_control, u16 *mode)
{
u32 mode32 = 0;
- u16 error = hpi_control_param1_get(ph_subsys, h_control,
+ u16 err = hpi_control_param1_get(h_control,
HPI_CHANNEL_MODE_MODE, &mode32);
if (mode)
*mode = (u16)mode32;
- return error;
+ return err;
}
-u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 hmi_address, u32 byte_count, u8 *pb_data)
+u16 hpi_cobranet_hmi_write(u32 h_control, u32 hmi_address, u32 byte_count,
+ u8 *pb_data)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.cx.u.cobranet_data.byte_count = byte_count;
hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
@@ -1969,15 +1714,16 @@ u16 hpi_cobranet_hmi_write(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 hmi_address, u32 max_byte_count, u32 *pbyte_count, u8 *pb_data)
+u16 hpi_cobranet_hmi_read(u32 h_control, u32 hmi_address, u32 max_byte_count,
+ u32 *pbyte_count, u8 *pb_data)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.cx.u.cobranet_data.byte_count = max_byte_count;
hm.u.cx.u.cobranet_data.hmi_address = hmi_address;
@@ -2008,16 +1754,16 @@ u16 hpi_cobranet_hmi_read(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pstatus, u32 *preadable_size,
- u32 *pwriteable_size)
+u16 hpi_cobranet_hmi_get_status(u32 h_control, u32 *pstatus,
+ u32 *preadable_size, u32 *pwriteable_size)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROLEX,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.cx.attribute = HPI_COBRANET_GET_STATUS;
@@ -2035,177 +1781,176 @@ u16 hpi_cobranet_hmi_get_status(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_cobranet_getI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pi_paddress)
+u16 hpi_cobranet_get_ip_address(u32 h_control, u32 *pdw_ip_address)
{
u32 byte_count;
u32 iP;
- u16 error;
+ u16 err;
- error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+ err = hpi_cobranet_hmi_read(h_control,
HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, &byte_count,
(u8 *)&iP);
- *pi_paddress =
+ *pdw_ip_address =
((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP &
0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8);
- if (error)
- *pi_paddress = 0;
+ if (err)
+ *pdw_ip_address = 0;
- return error;
+ return err;
}
-u16 hpi_cobranet_setI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 i_paddress)
+u16 hpi_cobranet_set_ip_address(u32 h_control, u32 dw_ip_address)
{
u32 iP;
- u16 error;
+ u16 err;
- iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) <<
- 8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress &
- 0x000000ff) << 8);
+ iP = ((dw_ip_address & 0xff000000) >> 8) | ((dw_ip_address &
+ 0x00ff0000) << 8) | ((dw_ip_address & 0x0000ff00) >>
+ 8) | ((dw_ip_address & 0x000000ff) << 8);
- error = hpi_cobranet_hmi_write(ph_subsys, h_control,
+ err = hpi_cobranet_hmi_write(h_control,
HPI_COBRANET_HMI_cobra_ip_mon_currentIP, 4, (u8 *)&iP);
- return error;
+ return err;
}
-u16 hpi_cobranet_get_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pi_paddress)
+u16 hpi_cobranet_get_static_ip_address(u32 h_control, u32 *pdw_ip_address)
{
u32 byte_count;
u32 iP;
- u16 error;
- error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+ u16 err;
+ err = hpi_cobranet_hmi_read(h_control,
HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, &byte_count,
(u8 *)&iP);
- *pi_paddress =
+ *pdw_ip_address =
((iP & 0xff000000) >> 8) | ((iP & 0x00ff0000) << 8) | ((iP &
0x0000ff00) >> 8) | ((iP & 0x000000ff) << 8);
- if (error)
- *pi_paddress = 0;
+ if (err)
+ *pdw_ip_address = 0;
- return error;
+ return err;
}
-u16 hpi_cobranet_set_staticI_paddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 i_paddress)
+u16 hpi_cobranet_set_static_ip_address(u32 h_control, u32 dw_ip_address)
{
u32 iP;
- u16 error;
+ u16 err;
- iP = ((i_paddress & 0xff000000) >> 8) | ((i_paddress & 0x00ff0000) <<
- 8) | ((i_paddress & 0x0000ff00) >> 8) | ((i_paddress &
- 0x000000ff) << 8);
+ iP = ((dw_ip_address & 0xff000000) >> 8) | ((dw_ip_address &
+ 0x00ff0000) << 8) | ((dw_ip_address & 0x0000ff00) >>
+ 8) | ((dw_ip_address & 0x000000ff) << 8);
- error = hpi_cobranet_hmi_write(ph_subsys, h_control,
+ err = hpi_cobranet_hmi_write(h_control,
HPI_COBRANET_HMI_cobra_ip_mon_staticIP, 4, (u8 *)&iP);
- return error;
+ return err;
}
-u16 hpi_cobranet_getMA_caddress(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pmAC_MS_bs, u32 *pmAC_LS_bs)
+u16 hpi_cobranet_get_macaddress(u32 h_control, u32 *p_mac_msbs,
+ u32 *p_mac_lsbs)
{
u32 byte_count;
- u16 error;
- u32 mAC;
+ u16 err;
+ u32 mac;
- error = hpi_cobranet_hmi_read(ph_subsys, h_control,
+ err = hpi_cobranet_hmi_read(h_control,
HPI_COBRANET_HMI_cobra_if_phy_address, 4, &byte_count,
- (u8 *)&mAC);
- *pmAC_MS_bs =
- ((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC
- & 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8);
- error += hpi_cobranet_hmi_read(ph_subsys, h_control,
- HPI_COBRANET_HMI_cobra_if_phy_address + 1, 4, &byte_count,
- (u8 *)&mAC);
- *pmAC_LS_bs =
- ((mAC & 0xff000000) >> 8) | ((mAC & 0x00ff0000) << 8) | ((mAC
- & 0x0000ff00) >> 8) | ((mAC & 0x000000ff) << 8);
-
- if (error) {
- *pmAC_MS_bs = 0;
- *pmAC_LS_bs = 0;
+ (u8 *)&mac);
+
+ if (!err) {
+ *p_mac_msbs =
+ ((mac & 0xff000000) >> 8) | ((mac & 0x00ff0000) << 8)
+ | ((mac & 0x0000ff00) >> 8) | ((mac & 0x000000ff) <<
+ 8);
+
+ err = hpi_cobranet_hmi_read(h_control,
+ HPI_COBRANET_HMI_cobra_if_phy_address + 1, 4,
+ &byte_count, (u8 *)&mac);
}
- return error;
+ if (!err) {
+ *p_mac_lsbs =
+ ((mac & 0xff000000) >> 8) | ((mac & 0x00ff0000) << 8)
+ | ((mac & 0x0000ff00) >> 8) | ((mac & 0x000000ff) <<
+ 8);
+ } else {
+ *p_mac_msbs = 0;
+ *p_mac_lsbs = 0;
+ }
+
+ return err;
}
-u16 hpi_compander_set_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 enable)
+u16 hpi_compander_set_enable(u32 h_control, u32 enable)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
- enable, 0);
+ return hpi_control_param_set(h_control, HPI_GENERIC_ENABLE, enable,
+ 0);
}
-u16 hpi_compander_get_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *enable)
+u16 hpi_compander_get_enable(u32 h_control, u32 *enable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_GENERIC_ENABLE, enable);
+ return hpi_control_param1_get(h_control, HPI_GENERIC_ENABLE, enable);
}
-u16 hpi_compander_set_makeup_gain(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short makeup_gain0_01dB)
+u16 hpi_compander_set_makeup_gain(u32 h_control, short makeup_gain0_01dB)
{
return hpi_control_log_set2(h_control, HPI_COMPANDER_MAKEUPGAIN,
makeup_gain0_01dB, 0);
}
-u16 hpi_compander_get_makeup_gain(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short *makeup_gain0_01dB)
+u16 hpi_compander_get_makeup_gain(u32 h_control, short *makeup_gain0_01dB)
{
- return hpi_control_log_get2(ph_subsys, h_control,
- HPI_COMPANDER_MAKEUPGAIN, makeup_gain0_01dB, NULL);
+ return hpi_control_log_get2(h_control, HPI_COMPANDER_MAKEUPGAIN,
+ makeup_gain0_01dB, NULL);
}
-u16 hpi_compander_set_attack_time_constant(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, unsigned int index, u32 attack)
+u16 hpi_compander_set_attack_time_constant(u32 h_control, unsigned int index,
+ u32 attack)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_COMPANDER_ATTACK, attack, index);
+ return hpi_control_param_set(h_control, HPI_COMPANDER_ATTACK, attack,
+ index);
}
-u16 hpi_compander_get_attack_time_constant(const struct hpi_hsubsys
- *ph_subsys, u32 h_control, unsigned int index, u32 *attack)
+u16 hpi_compander_get_attack_time_constant(u32 h_control, unsigned int index,
+ u32 *attack)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_COMPANDER_ATTACK, 0, index, attack, NULL);
+ return hpi_control_param_get(h_control, HPI_COMPANDER_ATTACK, 0,
+ index, attack, NULL);
}
-u16 hpi_compander_set_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, unsigned int index, u32 decay)
+u16 hpi_compander_set_decay_time_constant(u32 h_control, unsigned int index,
+ u32 decay)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_COMPANDER_DECAY, decay, index);
+ return hpi_control_param_set(h_control, HPI_COMPANDER_DECAY, decay,
+ index);
}
-u16 hpi_compander_get_decay_time_constant(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, unsigned int index, u32 *decay)
+u16 hpi_compander_get_decay_time_constant(u32 h_control, unsigned int index,
+ u32 *decay)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_COMPANDER_DECAY, 0, index, decay, NULL);
+ return hpi_control_param_get(h_control, HPI_COMPANDER_DECAY, 0, index,
+ decay, NULL);
}
-u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, unsigned int index, short threshold0_01dB)
+u16 hpi_compander_set_threshold(u32 h_control, unsigned int index,
+ short threshold0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_COMPANDER_THRESHOLD;
hm.u.c.param2 = index;
hm.u.c.an_log_value[0] = threshold0_01dB;
@@ -2215,15 +1960,16 @@ u16 hpi_compander_set_threshold(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, unsigned int index, short *threshold0_01dB)
+u16 hpi_compander_get_threshold(u32 h_control, unsigned int index,
+ short *threshold0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_COMPANDER_THRESHOLD;
hm.u.c.param2 = index;
@@ -2233,29 +1979,28 @@ u16 hpi_compander_get_threshold(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_compander_set_ratio(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 ratio100)
+u16 hpi_compander_set_ratio(u32 h_control, u32 index, u32 ratio100)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_COMPANDER_RATIO, ratio100, index);
+ return hpi_control_param_set(h_control, HPI_COMPANDER_RATIO, ratio100,
+ index);
}
-u16 hpi_compander_get_ratio(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 *ratio100)
+u16 hpi_compander_get_ratio(u32 h_control, u32 index, u32 *ratio100)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_COMPANDER_RATIO, 0, index, ratio100, NULL);
+ return hpi_control_param_get(h_control, HPI_COMPANDER_RATIO, 0, index,
+ ratio100, NULL);
}
-u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB)
+u16 hpi_level_query_range(u32 h_control, short *min_gain_01dB,
+ short *max_gain_01dB, short *step_gain_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_LEVEL_RANGE;
hpi_send_recv(&hm, &hr);
@@ -2273,31 +2018,27 @@ u16 hpi_level_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_level_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB[HPI_MAX_CHANNELS]
+u16 hpi_level_set_gain(u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS]
)
{
return hpi_control_log_set2(h_control, HPI_LEVEL_GAIN,
an_gain0_01dB[0], an_gain0_01dB[1]);
}
-u16 hpi_level_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB[HPI_MAX_CHANNELS]
+u16 hpi_level_get_gain(u32 h_control, short an_gain0_01dB[HPI_MAX_CHANNELS]
)
{
- return hpi_control_log_get2(ph_subsys, h_control, HPI_LEVEL_GAIN,
+ return hpi_control_log_get2(h_control, HPI_LEVEL_GAIN,
&an_gain0_01dB[0], &an_gain0_01dB[1]);
}
-u16 hpi_meter_query_channels(const struct hpi_hsubsys *ph_subsys,
- const u32 h_meter, u32 *p_channels)
+u16 hpi_meter_query_channels(const u32 h_meter, u32 *p_channels)
{
- return hpi_control_query(ph_subsys, h_meter, HPI_METER_NUM_CHANNELS,
- 0, 0, p_channels);
+ return hpi_control_query(h_meter, HPI_METER_NUM_CHANNELS, 0, 0,
+ p_channels);
}
-u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_peakdB[HPI_MAX_CHANNELS]
+u16 hpi_meter_get_peak(u32 h_control, short an_peakdB[HPI_MAX_CHANNELS]
)
{
short i = 0;
@@ -2307,7 +2048,8 @@ u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.obj_index = hm.obj_index;
hm.u.c.attribute = HPI_METER_PEAK;
@@ -2322,8 +2064,7 @@ u16 hpi_meter_get_peak(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_rmsdB[HPI_MAX_CHANNELS]
+u16 hpi_meter_get_rms(u32 h_control, short an_rmsdB[HPI_MAX_CHANNELS]
)
{
short i = 0;
@@ -2333,7 +2074,8 @@ u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_METER_RMS;
hpi_send_recv(&hm, &hr);
@@ -2348,22 +2090,20 @@ u16 hpi_meter_get_rms(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_meter_set_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 attack, u16 decay)
+u16 hpi_meter_set_rms_ballistics(u32 h_control, u16 attack, u16 decay)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_METER_RMS_BALLISTICS, attack, decay);
+ return hpi_control_param_set(h_control, HPI_METER_RMS_BALLISTICS,
+ attack, decay);
}
-u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pn_attack, u16 *pn_decay)
+u16 hpi_meter_get_rms_ballistics(u32 h_control, u16 *pn_attack, u16 *pn_decay)
{
u32 attack;
u32 decay;
u16 error;
- error = hpi_control_param2_get(ph_subsys, h_control,
- HPI_METER_RMS_BALLISTICS, &attack, &decay);
+ error = hpi_control_param2_get(h_control, HPI_METER_RMS_BALLISTICS,
+ &attack, &decay);
if (pn_attack)
*pn_attack = (unsigned short)attack;
@@ -2373,22 +2113,21 @@ u16 hpi_meter_get_rms_ballistics(const struct hpi_hsubsys *ph_subsys,
return error;
}
-u16 hpi_meter_set_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 attack, u16 decay)
+u16 hpi_meter_set_peak_ballistics(u32 h_control, u16 attack, u16 decay)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_METER_PEAK_BALLISTICS, attack, decay);
+ return hpi_control_param_set(h_control, HPI_METER_PEAK_BALLISTICS,
+ attack, decay);
}
-u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pn_attack, u16 *pn_decay)
+u16 hpi_meter_get_peak_ballistics(u32 h_control, u16 *pn_attack,
+ u16 *pn_decay)
{
u32 attack;
u32 decay;
u16 error;
- error = hpi_control_param2_get(ph_subsys, h_control,
- HPI_METER_PEAK_BALLISTICS, &attack, &decay);
+ error = hpi_control_param2_get(h_control, HPI_METER_PEAK_BALLISTICS,
+ &attack, &decay);
if (pn_attack)
*pn_attack = (short)attack;
@@ -2398,55 +2137,53 @@ u16 hpi_meter_get_peak_ballistics(const struct hpi_hsubsys *ph_subsys,
return error;
}
-u16 hpi_microphone_set_phantom_power(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 on_off)
+u16 hpi_microphone_set_phantom_power(u32 h_control, u16 on_off)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_MICROPHONE_PHANTOM_POWER, (u32)on_off, 0);
+ return hpi_control_param_set(h_control, HPI_MICROPHONE_PHANTOM_POWER,
+ (u32)on_off, 0);
}
-u16 hpi_microphone_get_phantom_power(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_on_off)
+u16 hpi_microphone_get_phantom_power(u32 h_control, u16 *pw_on_off)
{
u16 error = 0;
u32 on_off = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
+ error = hpi_control_param1_get(h_control,
HPI_MICROPHONE_PHANTOM_POWER, &on_off);
if (pw_on_off)
*pw_on_off = (u16)on_off;
return error;
}
-u16 hpi_multiplexer_set_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source_node_type, u16 source_node_index)
+u16 hpi_multiplexer_set_source(u32 h_control, u16 source_node_type,
+ u16 source_node_index)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_MULTIPLEXER_SOURCE, source_node_type, source_node_index);
+ return hpi_control_param_set(h_control, HPI_MULTIPLEXER_SOURCE,
+ source_node_type, source_node_index);
}
-u16 hpi_multiplexer_get_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *source_node_type, u16 *source_node_index)
+u16 hpi_multiplexer_get_source(u32 h_control, u16 *source_node_type,
+ u16 *source_node_index)
{
u32 node, index;
- u16 error = hpi_control_param2_get(ph_subsys, h_control,
+ u16 err = hpi_control_param2_get(h_control,
HPI_MULTIPLEXER_SOURCE, &node,
&index);
if (source_node_type)
*source_node_type = (u16)node;
if (source_node_index)
*source_node_index = (u16)index;
- return error;
+ return err;
}
-u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *source_node_type,
- u16 *source_node_index)
+u16 hpi_multiplexer_query_source(u32 h_control, u16 index,
+ u16 *source_node_type, u16 *source_node_index)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_MULTIPLEXER_QUERYSOURCE;
hm.u.c.param1 = index;
@@ -2459,15 +2196,15 @@ u16 hpi_multiplexer_query_source(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_number_of_bands, u16 *pw_on_off)
+u16 hpi_parametric_eq_get_info(u32 h_control, u16 *pw_number_of_bands,
+ u16 *pw_on_off)
{
u32 oB = 0;
u32 oO = 0;
u16 error = 0;
- error = hpi_control_param2_get(ph_subsys, h_control,
- HPI_EQUALIZER_NUM_FILTERS, &oO, &oB);
+ error = hpi_control_param2_get(h_control, HPI_EQUALIZER_NUM_FILTERS,
+ &oO, &oB);
if (pw_number_of_bands)
*pw_number_of_bands = (u16)oB;
if (pw_on_off)
@@ -2475,23 +2212,22 @@ u16 hpi_parametricEQ__get_info(const struct hpi_hsubsys *ph_subsys,
return error;
}
-u16 hpi_parametricEQ__set_state(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 on_off)
+u16 hpi_parametric_eq_set_state(u32 h_control, u16 on_off)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_EQUALIZER_NUM_FILTERS, on_off, 0);
+ return hpi_control_param_set(h_control, HPI_EQUALIZER_NUM_FILTERS,
+ on_off, 0);
}
-u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 *pn_type, u32 *pfrequency_hz,
- short *pnQ100, short *pn_gain0_01dB)
+u16 hpi_parametric_eq_get_band(u32 h_control, u16 index, u16 *pn_type,
+ u32 *pfrequency_hz, short *pnQ100, short *pn_gain0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_EQUALIZER_FILTER;
hm.u.c.param2 = index;
@@ -2509,16 +2245,16 @@ u16 hpi_parametricEQ__get_band(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, u16 type, u32 frequency_hz, short q100,
- short gain0_01dB)
+u16 hpi_parametric_eq_set_band(u32 h_control, u16 index, u16 type,
+ u32 frequency_hz, short q100, short gain0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.param1 = frequency_hz;
hm.u.c.param2 = (index & 0xFFFFL) + ((u32)type << 16);
@@ -2531,8 +2267,7 @@ u16 hpi_parametricEQ__set_band(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 index, short coeffs[5]
+u16 hpi_parametric_eq_get_coeffs(u32 h_control, u16 index, short coeffs[5]
)
{
struct hpi_message hm;
@@ -2540,7 +2275,8 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_EQUALIZER_COEFFICIENTS;
hm.u.c.param2 = index;
@@ -2555,444 +2291,388 @@ u16 hpi_parametricEQ__get_coeffs(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_sample_clock_query_source(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, u16 *pw_source)
+u16 hpi_sample_clock_query_source(const u32 h_clock, const u32 index,
+ u16 *pw_source)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_clock, HPI_SAMPLECLOCK_SOURCE,
- index, 0, &qr);
+ err = hpi_control_query(h_clock, HPI_SAMPLECLOCK_SOURCE, index, 0,
+ &qr);
*pw_source = (u16)qr;
return err;
}
-u16 hpi_sample_clock_set_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source)
+u16 hpi_sample_clock_set_source(u32 h_control, u16 source)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SAMPLECLOCK_SOURCE, source, 0);
+ return hpi_control_param_set(h_control, HPI_SAMPLECLOCK_SOURCE,
+ source, 0);
}
-u16 hpi_sample_clock_get_source(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_source)
+u16 hpi_sample_clock_get_source(u32 h_control, u16 *pw_source)
{
- u16 error = 0;
+ u16 err = 0;
u32 source = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
- HPI_SAMPLECLOCK_SOURCE, &source);
- if (!error)
+ err = hpi_control_param1_get(h_control, HPI_SAMPLECLOCK_SOURCE,
+ &source);
+ if (!err)
if (pw_source)
*pw_source = (u16)source;
- return error;
+ return err;
}
-u16 hpi_sample_clock_query_source_index(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, const u32 source,
- u16 *pw_source_index)
+u16 hpi_sample_clock_query_source_index(const u32 h_clock, const u32 index,
+ const u32 source, u16 *pw_source_index)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_clock,
- HPI_SAMPLECLOCK_SOURCE_INDEX, index, source, &qr);
+ err = hpi_control_query(h_clock, HPI_SAMPLECLOCK_SOURCE_INDEX, index,
+ source, &qr);
*pw_source_index = (u16)qr;
return err;
}
-u16 hpi_sample_clock_set_source_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 source_index)
+u16 hpi_sample_clock_set_source_index(u32 h_control, u16 source_index)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SAMPLECLOCK_SOURCE_INDEX, source_index, 0);
+ return hpi_control_param_set(h_control, HPI_SAMPLECLOCK_SOURCE_INDEX,
+ source_index, 0);
}
-u16 hpi_sample_clock_get_source_index(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u16 *pw_source_index)
+u16 hpi_sample_clock_get_source_index(u32 h_control, u16 *pw_source_index)
{
- u16 error = 0;
+ u16 err = 0;
u32 source_index = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
- HPI_SAMPLECLOCK_SOURCE_INDEX, &source_index);
- if (!error)
+ err = hpi_control_param1_get(h_control, HPI_SAMPLECLOCK_SOURCE_INDEX,
+ &source_index);
+ if (!err)
if (pw_source_index)
*pw_source_index = (u16)source_index;
- return error;
+ return err;
}
-u16 hpi_sample_clock_query_local_rate(const struct hpi_hsubsys *ph_subsys,
- const u32 h_clock, const u32 index, u32 *prate)
+u16 hpi_sample_clock_query_local_rate(const u32 h_clock, const u32 index,
+ u32 *prate)
{
u16 err;
- err = hpi_control_query(ph_subsys, h_clock,
- HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, index, 0, prate);
+ err = hpi_control_query(h_clock, HPI_SAMPLECLOCK_LOCAL_SAMPLERATE,
+ index, 0, prate);
return err;
}
-u16 hpi_sample_clock_set_local_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 sample_rate)
+u16 hpi_sample_clock_set_local_rate(u32 h_control, u32 sample_rate)
{
- return hpi_control_param_set(ph_subsys, h_control,
+ return hpi_control_param_set(h_control,
HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, sample_rate, 0);
}
-u16 hpi_sample_clock_get_local_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate)
+u16 hpi_sample_clock_get_local_rate(u32 h_control, u32 *psample_rate)
{
- u16 error = 0;
+ u16 err = 0;
u32 sample_rate = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
+ err = hpi_control_param1_get(h_control,
HPI_SAMPLECLOCK_LOCAL_SAMPLERATE, &sample_rate);
- if (!error)
+ if (!err)
if (psample_rate)
*psample_rate = sample_rate;
- return error;
+ return err;
}
-u16 hpi_sample_clock_get_sample_rate(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *psample_rate)
+u16 hpi_sample_clock_get_sample_rate(u32 h_control, u32 *psample_rate)
{
- u16 error = 0;
+ u16 err = 0;
u32 sample_rate = 0;
- error = hpi_control_param1_get(ph_subsys, h_control,
- HPI_SAMPLECLOCK_SAMPLERATE, &sample_rate);
- if (!error)
+ err = hpi_control_param1_get(h_control, HPI_SAMPLECLOCK_SAMPLERATE,
+ &sample_rate);
+ if (!err)
if (psample_rate)
*psample_rate = sample_rate;
- return error;
+ return err;
}
-u16 hpi_sample_clock_set_auto(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 enable)
+u16 hpi_sample_clock_set_auto(u32 h_control, u32 enable)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SAMPLECLOCK_AUTO, enable, 0);
+ return hpi_control_param_set(h_control, HPI_SAMPLECLOCK_AUTO, enable,
+ 0);
}
-u16 hpi_sample_clock_get_auto(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *penable)
+u16 hpi_sample_clock_get_auto(u32 h_control, u32 *penable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_SAMPLECLOCK_AUTO, penable);
+ return hpi_control_param1_get(h_control, HPI_SAMPLECLOCK_AUTO,
+ penable);
}
-u16 hpi_sample_clock_set_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 lock)
+u16 hpi_sample_clock_set_local_rate_lock(u32 h_control, u32 lock)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SAMPLECLOCK_LOCAL_LOCK, lock, 0);
+ return hpi_control_param_set(h_control, HPI_SAMPLECLOCK_LOCAL_LOCK,
+ lock, 0);
}
-u16 hpi_sample_clock_get_local_rate_lock(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *plock)
+u16 hpi_sample_clock_get_local_rate_lock(u32 h_control, u32 *plock)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_SAMPLECLOCK_LOCAL_LOCK, plock);
+ return hpi_control_param1_get(h_control, HPI_SAMPLECLOCK_LOCAL_LOCK,
+ plock);
}
-u16 hpi_tone_detector_get_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 index, u32 *frequency)
+u16 hpi_tone_detector_get_frequency(u32 h_control, u32 index, u32 *frequency)
{
- return hpi_control_param_get(ph_subsys, h_control,
- HPI_TONEDETECTOR_FREQUENCY, index, 0, frequency, NULL);
+ return hpi_control_param_get(h_control, HPI_TONEDETECTOR_FREQUENCY,
+ index, 0, frequency, NULL);
}
-u16 hpi_tone_detector_get_state(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *state)
+u16 hpi_tone_detector_get_state(u32 h_control, u32 *state)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_TONEDETECTOR_STATE, state);
+ return hpi_control_param1_get(h_control, HPI_TONEDETECTOR_STATE,
+ state);
}
-u16 hpi_tone_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 enable)
+u16 hpi_tone_detector_set_enable(u32 h_control, u32 enable)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
- (u32)enable, 0);
+ return hpi_control_param_set(h_control, HPI_GENERIC_ENABLE, enable,
+ 0);
}
-u16 hpi_tone_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *enable)
+u16 hpi_tone_detector_get_enable(u32 h_control, u32 *enable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_GENERIC_ENABLE, enable);
+ return hpi_control_param1_get(h_control, HPI_GENERIC_ENABLE, enable);
}
-u16 hpi_tone_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 event_enable)
+u16 hpi_tone_detector_set_event_enable(u32 h_control, u32 event_enable)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, (u32)event_enable, 0);
+ return hpi_control_param_set(h_control, HPI_GENERIC_EVENT_ENABLE,
+ (u32)event_enable, 0);
}
-u16 hpi_tone_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *event_enable)
+u16 hpi_tone_detector_get_event_enable(u32 h_control, u32 *event_enable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, event_enable);
+ return hpi_control_param1_get(h_control, HPI_GENERIC_EVENT_ENABLE,
+ event_enable);
}
-u16 hpi_tone_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, int threshold)
+u16 hpi_tone_detector_set_threshold(u32 h_control, int threshold)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_TONEDETECTOR_THRESHOLD, (u32)threshold, 0);
+ return hpi_control_param_set(h_control, HPI_TONEDETECTOR_THRESHOLD,
+ (u32)threshold, 0);
}
-u16 hpi_tone_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, int *threshold)
+u16 hpi_tone_detector_get_threshold(u32 h_control, int *threshold)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_TONEDETECTOR_THRESHOLD, (u32 *)threshold);
+ return hpi_control_param1_get(h_control, HPI_TONEDETECTOR_THRESHOLD,
+ (u32 *)threshold);
}
-u16 hpi_silence_detector_get_state(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *state)
+u16 hpi_silence_detector_get_state(u32 h_control, u32 *state)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_STATE, state);
+ return hpi_control_param1_get(h_control, HPI_SILENCEDETECTOR_STATE,
+ state);
}
-u16 hpi_silence_detector_set_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 enable)
+u16 hpi_silence_detector_set_enable(u32 h_control, u32 enable)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_GENERIC_ENABLE,
- (u32)enable, 0);
+ return hpi_control_param_set(h_control, HPI_GENERIC_ENABLE, enable,
+ 0);
}
-u16 hpi_silence_detector_get_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *enable)
+u16 hpi_silence_detector_get_enable(u32 h_control, u32 *enable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_GENERIC_ENABLE, enable);
+ return hpi_control_param1_get(h_control, HPI_GENERIC_ENABLE, enable);
}
-u16 hpi_silence_detector_set_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 event_enable)
+u16 hpi_silence_detector_set_event_enable(u32 h_control, u32 event_enable)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, event_enable, 0);
+ return hpi_control_param_set(h_control, HPI_GENERIC_EVENT_ENABLE,
+ event_enable, 0);
}
-u16 hpi_silence_detector_get_event_enable(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *event_enable)
+u16 hpi_silence_detector_get_event_enable(u32 h_control, u32 *event_enable)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_GENERIC_EVENT_ENABLE, event_enable);
+ return hpi_control_param1_get(h_control, HPI_GENERIC_EVENT_ENABLE,
+ event_enable);
}
-u16 hpi_silence_detector_set_delay(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 delay)
+u16 hpi_silence_detector_set_delay(u32 h_control, u32 delay)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_DELAY, delay, 0);
+ return hpi_control_param_set(h_control, HPI_SILENCEDETECTOR_DELAY,
+ delay, 0);
}
-u16 hpi_silence_detector_get_delay(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *delay)
+u16 hpi_silence_detector_get_delay(u32 h_control, u32 *delay)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_DELAY, delay);
+ return hpi_control_param1_get(h_control, HPI_SILENCEDETECTOR_DELAY,
+ delay);
}
-u16 hpi_silence_detector_set_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, int threshold)
+u16 hpi_silence_detector_set_threshold(u32 h_control, int threshold)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_SILENCEDETECTOR_THRESHOLD, threshold, 0);
+ return hpi_control_param_set(h_control, HPI_SILENCEDETECTOR_THRESHOLD,
+ threshold, 0);
}
-u16 hpi_silence_detector_get_threshold(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, int *threshold)
+u16 hpi_silence_detector_get_threshold(u32 h_control, int *threshold)
{
- return hpi_control_param1_get(ph_subsys, h_control,
+ return hpi_control_param1_get(h_control,
HPI_SILENCEDETECTOR_THRESHOLD, (u32 *)threshold);
}
-u16 hpi_tuner_query_band(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, u16 *pw_band)
+u16 hpi_tuner_query_band(const u32 h_tuner, const u32 index, u16 *pw_band)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0,
- &qr);
+ err = hpi_control_query(h_tuner, HPI_TUNER_BAND, index, 0, &qr);
*pw_band = (u16)qr;
return err;
}
-u16 hpi_tuner_set_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 band)
+u16 hpi_tuner_set_band(u32 h_control, u16 band)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_BAND,
- band, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_BAND, band, 0);
}
-u16 hpi_tuner_get_band(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_band)
+u16 hpi_tuner_get_band(u32 h_control, u16 *pw_band)
{
u32 band = 0;
u16 error = 0;
- error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_BAND,
- &band);
+ error = hpi_control_param1_get(h_control, HPI_TUNER_BAND, &band);
if (pw_band)
*pw_band = (u16)band;
return error;
}
-u16 hpi_tuner_query_frequency(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, const u16 band, u32 *pfreq)
+u16 hpi_tuner_query_frequency(const u32 h_tuner, const u32 index,
+ const u16 band, u32 *pfreq)
{
- return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_FREQ, index,
- band, pfreq);
+ return hpi_control_query(h_tuner, HPI_TUNER_FREQ, index, band, pfreq);
}
-u16 hpi_tuner_set_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 freq_ink_hz)
+u16 hpi_tuner_set_frequency(u32 h_control, u32 freq_ink_hz)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_FREQ,
- freq_ink_hz, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_FREQ, freq_ink_hz,
+ 0);
}
-u16 hpi_tuner_get_frequency(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pw_freq_ink_hz)
+u16 hpi_tuner_get_frequency(u32 h_control, u32 *pw_freq_ink_hz)
{
- return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_FREQ,
+ return hpi_control_param1_get(h_control, HPI_TUNER_FREQ,
pw_freq_ink_hz);
}
-u16 hpi_tuner_query_gain(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, u16 *pw_gain)
+u16 hpi_tuner_query_gain(const u32 h_tuner, const u32 index, u16 *pw_gain)
{
u32 qr;
u16 err;
- err = hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_BAND, index, 0,
- &qr);
+ err = hpi_control_query(h_tuner, HPI_TUNER_BAND, index, 0, &qr);
*pw_gain = (u16)qr;
return err;
}
-u16 hpi_tuner_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short gain)
+u16 hpi_tuner_set_gain(u32 h_control, short gain)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_GAIN,
- gain, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_GAIN, gain, 0);
}
-u16 hpi_tuner_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *pn_gain)
+u16 hpi_tuner_get_gain(u32 h_control, short *pn_gain)
{
u32 gain = 0;
u16 error = 0;
- error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_GAIN,
- &gain);
+ error = hpi_control_param1_get(h_control, HPI_TUNER_GAIN, &gain);
if (pn_gain)
*pn_gain = (u16)gain;
return error;
}
-u16 hpi_tuner_getRF_level(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *pw_level)
+u16 hpi_tuner_get_rf_level(u32 h_control, short *pw_level)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- hm.u.c.attribute = HPI_TUNER_LEVEL;
- hm.u.c.param1 = HPI_TUNER_LEVEL_AVERAGE;
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
+ hm.u.cu.attribute = HPI_TUNER_LEVEL_AVG;
hpi_send_recv(&hm, &hr);
if (pw_level)
- *pw_level = (short)hr.u.c.param1;
+ *pw_level = hr.u.cu.tuner.s_level;
return hr.error;
}
-u16 hpi_tuner_get_rawRF_level(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short *pw_level)
+u16 hpi_tuner_get_raw_rf_level(u32 h_control, short *pw_level)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
- hm.u.c.attribute = HPI_TUNER_LEVEL;
- hm.u.c.param1 = HPI_TUNER_LEVEL_RAW;
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
+ hm.u.cu.attribute = HPI_TUNER_LEVEL_RAW;
hpi_send_recv(&hm, &hr);
if (pw_level)
- *pw_level = (short)hr.u.c.param1;
+ *pw_level = hr.u.cu.tuner.s_level;
return hr.error;
}
-u16 hpi_tuner_query_deemphasis(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, const u32 index, const u16 band, u32 *pdeemphasis)
+u16 hpi_tuner_query_deemphasis(const u32 h_tuner, const u32 index,
+ const u16 band, u32 *pdeemphasis)
{
- return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_DEEMPHASIS,
- index, band, pdeemphasis);
+ return hpi_control_query(h_tuner, HPI_TUNER_DEEMPHASIS, index, band,
+ pdeemphasis);
}
-u16 hpi_tuner_set_deemphasis(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 deemphasis)
+u16 hpi_tuner_set_deemphasis(u32 h_control, u32 deemphasis)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_TUNER_DEEMPHASIS, deemphasis, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_DEEMPHASIS,
+ deemphasis, 0);
}
-u16 hpi_tuner_get_deemphasis(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pdeemphasis)
+u16 hpi_tuner_get_deemphasis(u32 h_control, u32 *pdeemphasis)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_TUNER_DEEMPHASIS, pdeemphasis);
+ return hpi_control_param1_get(h_control, HPI_TUNER_DEEMPHASIS,
+ pdeemphasis);
}
-u16 hpi_tuner_query_program(const struct hpi_hsubsys *ph_subsys,
- const u32 h_tuner, u32 *pbitmap_program)
+u16 hpi_tuner_query_program(const u32 h_tuner, u32 *pbitmap_program)
{
- return hpi_control_query(ph_subsys, h_tuner, HPI_TUNER_PROGRAM, 0, 0,
+ return hpi_control_query(h_tuner, HPI_TUNER_PROGRAM, 0, 0,
pbitmap_program);
}
-u16 hpi_tuner_set_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 program)
+u16 hpi_tuner_set_program(u32 h_control, u32 program)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_PROGRAM,
- program, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_PROGRAM, program,
+ 0);
}
-u16 hpi_tuner_get_program(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 *pprogram)
+u16 hpi_tuner_get_program(u32 h_control, u32 *pprogram)
{
- return hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_PROGRAM,
- pprogram);
+ return hpi_control_param1_get(h_control, HPI_TUNER_PROGRAM, pprogram);
}
-u16 hpi_tuner_get_hd_radio_dsp_version(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_dsp_version, const u32 string_size)
+u16 hpi_tuner_get_hd_radio_dsp_version(u32 h_control, char *psz_dsp_version,
+ const u32 string_size)
{
return hpi_control_get_string(h_control,
HPI_TUNER_HDRADIO_DSP_VERSION, psz_dsp_version, string_size);
}
-u16 hpi_tuner_get_hd_radio_sdk_version(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_sdk_version, const u32 string_size)
+u16 hpi_tuner_get_hd_radio_sdk_version(u32 h_control, char *psz_sdk_version,
+ const u32 string_size)
{
return hpi_control_get_string(h_control,
HPI_TUNER_HDRADIO_SDK_VERSION, psz_sdk_version, string_size);
}
-u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u16 *pw_status_mask, u16 *pw_status)
+u16 hpi_tuner_get_status(u32 h_control, u16 *pw_status_mask, u16 *pw_status)
{
u32 status = 0;
u16 error = 0;
- error = hpi_control_param1_get(ph_subsys, h_control, HPI_TUNER_STATUS,
- &status);
+ error = hpi_control_param1_get(h_control, HPI_TUNER_STATUS, &status);
if (pw_status) {
if (!error) {
*pw_status_mask = (u16)(status >> 16);
@@ -3005,50 +2685,44 @@ u16 hpi_tuner_get_status(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return error;
}
-u16 hpi_tuner_set_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 mode, u32 value)
+u16 hpi_tuner_set_mode(u32 h_control, u32 mode, u32 value)
{
- return hpi_control_param_set(ph_subsys, h_control, HPI_TUNER_MODE,
- mode, value);
+ return hpi_control_param_set(h_control, HPI_TUNER_MODE, mode, value);
}
-u16 hpi_tuner_get_mode(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 mode, u32 *pn_value)
+u16 hpi_tuner_get_mode(u32 h_control, u32 mode, u32 *pn_value)
{
- return hpi_control_param_get(ph_subsys, h_control, HPI_TUNER_MODE,
- mode, 0, pn_value, NULL);
+ return hpi_control_param_get(h_control, HPI_TUNER_MODE, mode, 0,
+ pn_value, NULL);
}
-u16 hpi_tuner_get_hd_radio_signal_quality(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pquality)
+u16 hpi_tuner_get_hd_radio_signal_quality(u32 h_control, u32 *pquality)
{
- return hpi_control_param1_get(ph_subsys, h_control,
+ return hpi_control_param1_get(h_control,
HPI_TUNER_HDRADIO_SIGNAL_QUALITY, pquality);
}
-u16 hpi_tuner_get_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *pblend)
+u16 hpi_tuner_get_hd_radio_signal_blend(u32 h_control, u32 *pblend)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_TUNER_HDRADIO_BLEND, pblend);
+ return hpi_control_param1_get(h_control, HPI_TUNER_HDRADIO_BLEND,
+ pblend);
}
-u16 hpi_tuner_set_hd_radio_signal_blend(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, const u32 blend)
+u16 hpi_tuner_set_hd_radio_signal_blend(u32 h_control, const u32 blend)
{
- return hpi_control_param_set(ph_subsys, h_control,
- HPI_TUNER_HDRADIO_BLEND, blend, 0);
+ return hpi_control_param_set(h_control, HPI_TUNER_HDRADIO_BLEND,
+ blend, 0);
}
-u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *p_data)
+u16 hpi_tuner_get_rds(u32 h_control, char *p_data)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_TUNER_RDS;
hpi_send_recv(&hm, &hr);
if (p_data) {
@@ -3059,80 +2733,82 @@ u16 hpi_tuner_getRDS(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 HPI_PAD__get_channel_name(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, char *psz_string, const u32 data_length)
+u16 hpi_pad_get_channel_name(u32 h_control, char *psz_string,
+ const u32 data_length)
{
return hpi_control_get_string(h_control, HPI_PAD_CHANNEL_NAME,
psz_string, data_length);
}
-u16 HPI_PAD__get_artist(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 data_length)
+u16 hpi_pad_get_artist(u32 h_control, char *psz_string, const u32 data_length)
{
return hpi_control_get_string(h_control, HPI_PAD_ARTIST, psz_string,
data_length);
}
-u16 HPI_PAD__get_title(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 data_length)
+u16 hpi_pad_get_title(u32 h_control, char *psz_string, const u32 data_length)
{
return hpi_control_get_string(h_control, HPI_PAD_TITLE, psz_string,
data_length);
}
-u16 HPI_PAD__get_comment(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- char *psz_string, const u32 data_length)
+u16 hpi_pad_get_comment(u32 h_control, char *psz_string,
+ const u32 data_length)
{
return hpi_control_get_string(h_control, HPI_PAD_COMMENT, psz_string,
data_length);
}
-u16 HPI_PAD__get_program_type(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, u32 *ppTY)
+u16 hpi_pad_get_program_type(u32 h_control, u32 *ppTY)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_PAD_PROGRAM_TYPE, ppTY);
+ return hpi_control_param1_get(h_control, HPI_PAD_PROGRAM_TYPE, ppTY);
}
-u16 HPI_PAD__get_rdsPI(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- u32 *ppI)
+u16 hpi_pad_get_rdsPI(u32 h_control, u32 *ppI)
{
- return hpi_control_param1_get(ph_subsys, h_control,
- HPI_PAD_PROGRAM_ID, ppI);
+ return hpi_control_param1_get(h_control, HPI_PAD_PROGRAM_ID, ppI);
}
-u16 hpi_volume_query_channels(const struct hpi_hsubsys *ph_subsys,
- const u32 h_volume, u32 *p_channels)
+u16 hpi_volume_query_channels(const u32 h_volume, u32 *p_channels)
{
- return hpi_control_query(ph_subsys, h_volume, HPI_VOLUME_NUM_CHANNELS,
- 0, 0, p_channels);
+ return hpi_control_query(h_volume, HPI_VOLUME_NUM_CHANNELS, 0, 0,
+ p_channels);
}
-u16 hpi_volume_set_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_log_gain[HPI_MAX_CHANNELS]
+u16 hpi_volume_set_gain(u32 h_control, short an_log_gain[HPI_MAX_CHANNELS]
)
{
return hpi_control_log_set2(h_control, HPI_VOLUME_GAIN,
an_log_gain[0], an_log_gain[1]);
}
-u16 hpi_volume_get_gain(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_log_gain[HPI_MAX_CHANNELS]
+u16 hpi_volume_get_gain(u32 h_control, short an_log_gain[HPI_MAX_CHANNELS]
)
{
- return hpi_control_log_get2(ph_subsys, h_control, HPI_VOLUME_GAIN,
+ return hpi_control_log_get2(h_control, HPI_VOLUME_GAIN,
&an_log_gain[0], &an_log_gain[1]);
}
-u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *min_gain_01dB, short *max_gain_01dB, short *step_gain_01dB)
+u16 hpi_volume_set_mute(u32 h_control, u32 mute)
+{
+ return hpi_control_param_set(h_control, HPI_VOLUME_MUTE, mute, 0);
+}
+
+u16 hpi_volume_get_mute(u32 h_control, u32 *mute)
+{
+ return hpi_control_param1_get(h_control, HPI_VOLUME_MUTE, mute);
+}
+
+u16 hpi_volume_query_range(u32 h_control, short *min_gain_01dB,
+ short *max_gain_01dB, short *step_gain_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_VOLUME_RANGE;
hpi_send_recv(&hm, &hr);
@@ -3150,16 +2826,17 @@ u16 hpi_volume_query_range(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
- u32 h_control, short an_stop_gain0_01dB[HPI_MAX_CHANNELS],
- u32 duration_ms, u16 profile)
+u16 hpi_volume_auto_fade_profile(u32 h_control,
+ short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms,
+ u16 profile)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
memcpy(hm.u.c.an_log_value, an_stop_gain0_01dB,
sizeof(short) * HPI_MAX_CHANNELS);
@@ -3173,21 +2850,21 @@ u16 hpi_volume_auto_fade_profile(const struct hpi_hsubsys *ph_subsys,
return hr.error;
}
-u16 hpi_volume_auto_fade(const struct hpi_hsubsys *ph_subsys, u32 h_control,
+u16 hpi_volume_auto_fade(u32 h_control,
short an_stop_gain0_01dB[HPI_MAX_CHANNELS], u32 duration_ms)
{
- return hpi_volume_auto_fade_profile(ph_subsys, h_control,
- an_stop_gain0_01dB, duration_ms, HPI_VOLUME_AUTOFADE_LOG);
+ return hpi_volume_auto_fade_profile(h_control, an_stop_gain0_01dB,
+ duration_ms, HPI_VOLUME_AUTOFADE_LOG);
}
-u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short an_gain0_01dB)
+u16 hpi_vox_set_threshold(u32 h_control, short an_gain0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_SET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_VOX_THRESHOLD;
hm.u.c.an_log_value[0] = an_gain0_01dB;
@@ -3197,14 +2874,14 @@ u16 hpi_vox_set_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
- short *an_gain0_01dB)
+u16 hpi_vox_get_threshold(u32 h_control, short *an_gain0_01dB)
{
struct hpi_message hm;
struct hpi_response hr;
hpi_init_message_response(&hm, &hr, HPI_OBJ_CONTROL,
HPI_CONTROL_GET_STATE);
- u32TOINDEXES(h_control, &hm.adapter_index, &hm.obj_index);
+ if (hpi_handle_indexes(h_control, &hm.adapter_index, &hm.obj_index))
+ return HPI_ERROR_INVALID_HANDLE;
hm.u.c.attribute = HPI_VOX_THRESHOLD;
hpi_send_recv(&hm, &hr);
@@ -3213,728 +2890,3 @@ u16 hpi_vox_get_threshold(const struct hpi_hsubsys *ph_subsys, u32 h_control,
return hr.error;
}
-
-static size_t strv_packet_size = MIN_STRV_PACKET_SIZE;
-
-static size_t entity_type_to_size[LAST_ENTITY_TYPE] = {
- 0,
- sizeof(struct hpi_entity),
- sizeof(void *),
-
- sizeof(int),
- sizeof(float),
- sizeof(double),
-
- sizeof(char),
- sizeof(char),
-
- 4 * sizeof(char),
- 16 * sizeof(char),
- 6 * sizeof(char),
-};
-
-static inline size_t hpi_entity_size(struct hpi_entity *entity_ptr)
-{
- return entity_ptr->header.size;
-}
-
-static inline size_t hpi_entity_header_size(struct hpi_entity *entity_ptr)
-{
- return sizeof(entity_ptr->header);
-}
-
-static inline size_t hpi_entity_value_size(struct hpi_entity *entity_ptr)
-{
- return hpi_entity_size(entity_ptr) -
- hpi_entity_header_size(entity_ptr);
-}
-
-static inline size_t hpi_entity_item_count(struct hpi_entity *entity_ptr)
-{
- return hpi_entity_value_size(entity_ptr) /
- entity_type_to_size[entity_ptr->header.type];
-}
-
-static inline struct hpi_entity *hpi_entity_ptr_to_next(struct hpi_entity
- *entity_ptr)
-{
- return (void *)(((u8 *)entity_ptr) + hpi_entity_size(entity_ptr));
-}
-
-static inline u16 hpi_entity_check_type(const enum e_entity_type t)
-{
- if (t >= 0 && t < STR_TYPE_FIELD_MAX)
- return 0;
- return HPI_ERROR_ENTITY_TYPE_INVALID;
-}
-
-static inline u16 hpi_entity_check_role(const enum e_entity_role r)
-{
- if (r >= 0 && r < STR_ROLE_FIELD_MAX)
- return 0;
- return HPI_ERROR_ENTITY_ROLE_INVALID;
-}
-
-static u16 hpi_entity_get_next(struct hpi_entity *entity, int recursive_flag,
- void *guard_p, struct hpi_entity **next)
-{
- HPI_DEBUG_ASSERT(entity != NULL);
- HPI_DEBUG_ASSERT(next != NULL);
- HPI_DEBUG_ASSERT(hpi_entity_size(entity) != 0);
-
- if (guard_p <= (void *)entity) {
- *next = NULL;
- return 0;
- }
-
- if (recursive_flag && entity->header.type == entity_type_sequence)
- *next = (struct hpi_entity *)entity->value;
- else
- *next = (struct hpi_entity *)hpi_entity_ptr_to_next(entity);
-
- if (guard_p <= (void *)*next) {
- *next = NULL;
- return 0;
- }
-
- HPI_DEBUG_ASSERT(guard_p >= (void *)hpi_entity_ptr_to_next(*next));
- return 0;
-}
-
-u16 hpi_entity_find_next(struct hpi_entity *container_entity,
- enum e_entity_type type, enum e_entity_role role, int recursive_flag,
- struct hpi_entity **current_match)
-{
- struct hpi_entity *tmp = NULL;
- void *guard_p = NULL;
-
- HPI_DEBUG_ASSERT(container_entity != NULL);
- guard_p = hpi_entity_ptr_to_next(container_entity);
-
- if (*current_match != NULL)
- hpi_entity_get_next(*current_match, recursive_flag, guard_p,
- &tmp);
- else
- hpi_entity_get_next(container_entity, 1, guard_p, &tmp);
-
- while (tmp) {
- u16 err;
-
- HPI_DEBUG_ASSERT((void *)tmp >= (void *)container_entity);
-
- if ((!type || tmp->header.type == type) && (!role
- || tmp->header.role == role)) {
- *current_match = tmp;
- return 0;
- }
-
- err = hpi_entity_get_next(tmp, recursive_flag, guard_p,
- current_match);
- if (err)
- return err;
-
- tmp = *current_match;
- }
-
- *current_match = NULL;
- return 0;
-}
-
-void hpi_entity_free(struct hpi_entity *entity)
-{
- kfree(entity);
-}
-
-static u16 hpi_entity_alloc_and_copy(struct hpi_entity *src,
- struct hpi_entity **dst)
-{
- size_t buf_size;
- HPI_DEBUG_ASSERT(dst != NULL);
- HPI_DEBUG_ASSERT(src != NULL);
-
- buf_size = hpi_entity_size(src);
- *dst = kmalloc(buf_size, GFP_KERNEL);
- if (*dst == NULL)
- return HPI_ERROR_MEMORY_ALLOC;
- memcpy(*dst, src, buf_size);
- return 0;
-}
-
-u16 hpi_universal_info(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity **info)
-{
- struct hpi_msg_strv hm;
- struct hpi_res_strv *phr;
- u16 hpi_err;
- int remaining_attempts = 2;
- size_t resp_packet_size = 1024;
-
- *info = NULL;
-
- while (remaining_attempts--) {
- phr = kmalloc(resp_packet_size, GFP_KERNEL);
- HPI_DEBUG_ASSERT(phr != NULL);
-
- hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h,
- (u16)resp_packet_size, HPI_OBJ_CONTROL,
- HPI_CONTROL_GET_INFO);
- u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index);
-
- hm.strv.header.size = sizeof(hm.strv);
- phr->strv.header.size = resp_packet_size - sizeof(phr->h);
-
- hpi_send_recv((struct hpi_message *)&hm.h,
- (struct hpi_response *)&phr->h);
- if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) {
-
- HPI_DEBUG_ASSERT(phr->h.specific_error >
- MIN_STRV_PACKET_SIZE
- && phr->h.specific_error < 1500);
- resp_packet_size = phr->h.specific_error;
- } else {
- remaining_attempts = 0;
- if (!phr->h.error)
- hpi_entity_alloc_and_copy(&phr->strv, info);
- }
-
- hpi_err = phr->h.error;
- kfree(phr);
- }
-
- return hpi_err;
-}
-
-u16 hpi_universal_get(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity **value)
-{
- struct hpi_msg_strv hm;
- struct hpi_res_strv *phr;
- u16 hpi_err;
- int remaining_attempts = 2;
-
- *value = NULL;
-
- while (remaining_attempts--) {
- phr = kmalloc(strv_packet_size, GFP_KERNEL);
- if (!phr)
- return HPI_ERROR_MEMORY_ALLOC;
-
- hpi_init_message_responseV1(&hm.h, (u16)sizeof(hm), &phr->h,
- (u16)strv_packet_size, HPI_OBJ_CONTROL,
- HPI_CONTROL_GET_STATE);
- u32TOINDEXES(hC, &hm.h.adapter_index, &hm.h.obj_index);
-
- hm.strv.header.size = sizeof(hm.strv);
- phr->strv.header.size = strv_packet_size - sizeof(phr->h);
-
- hpi_send_recv((struct hpi_message *)&hm.h,
- (struct hpi_response *)&phr->h);
- if (phr->h.error == HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL) {
-
- HPI_DEBUG_ASSERT(phr->h.specific_error >
- MIN_STRV_PACKET_SIZE
- && phr->h.specific_error < 1000);
- strv_packet_size = phr->h.specific_error;
- } else {
- remaining_attempts = 0;
- if (!phr->h.error)
- hpi_entity_alloc_and_copy(&phr->strv, value);
- }
-
- hpi_err = phr->h.error;
- kfree(phr);
- }
-
- return hpi_err;
-}
-
-u16 hpi_universal_set(const struct hpi_hsubsys *ph_subsys, u32 hC,
- struct hpi_entity *value)
-{
- struct hpi_msg_strv *phm;
- struct hpi_res_strv hr;
-
- phm = kmalloc(sizeof(phm->h) + value->header.size, GFP_KERNEL);
- HPI_DEBUG_ASSERT(phm != NULL);
-
- hpi_init_message_responseV1(&phm->h,
- sizeof(phm->h) + value->header.size, &hr.h, sizeof(hr),
- HPI_OBJ_CONTROL, HPI_CONTROL_SET_STATE);
- u32TOINDEXES(hC, &phm->h.adapter_index, &phm->h.obj_index);
- hr.strv.header.size = sizeof(hr.strv);
-
- memcpy(&phm->strv, value, value->header.size);
- hpi_send_recv((struct hpi_message *)&phm->h,
- (struct hpi_response *)&hr.h);
-
- return hr.h.error;
-}
-
-u16 hpi_entity_alloc_and_pack(const enum e_entity_type type,
- const size_t item_count, const enum e_entity_role role, void *value,
- struct hpi_entity **entity)
-{
- size_t bytes_to_copy, total_size;
- u16 hE = 0;
- *entity = NULL;
-
- hE = hpi_entity_check_type(type);
- if (hE)
- return hE;
-
- HPI_DEBUG_ASSERT(role > entity_role_null && type < LAST_ENTITY_TYPE);
-
- bytes_to_copy = entity_type_to_size[type] * item_count;
- total_size = hpi_entity_header_size(*entity) + bytes_to_copy;
-
- HPI_DEBUG_ASSERT(total_size >= hpi_entity_header_size(*entity)
- && total_size < STR_SIZE_FIELD_MAX);
-
- *entity = kmalloc(total_size, GFP_KERNEL);
- if (*entity == NULL)
- return HPI_ERROR_MEMORY_ALLOC;
- memcpy((*entity)->value, value, bytes_to_copy);
- (*entity)->header.size =
- hpi_entity_header_size(*entity) + bytes_to_copy;
- (*entity)->header.type = type;
- (*entity)->header.role = role;
- return 0;
-}
-
-u16 hpi_entity_copy_value_from(struct hpi_entity *entity,
- enum e_entity_type type, size_t item_count, void *value_dst_p)
-{
- size_t bytes_to_copy;
-
- if (entity->header.type != type)
- return HPI_ERROR_ENTITY_TYPE_MISMATCH;
-
- if (hpi_entity_item_count(entity) != item_count)
- return HPI_ERROR_ENTITY_ITEM_COUNT;
-
- bytes_to_copy = entity_type_to_size[type] * item_count;
- memcpy(value_dst_p, entity->value, bytes_to_copy);
- return 0;
-}
-
-u16 hpi_entity_unpack(struct hpi_entity *entity, enum e_entity_type *type,
- size_t *item_count, enum e_entity_role *role, void **value)
-{
- u16 err = 0;
- HPI_DEBUG_ASSERT(entity != NULL);
-
- if (type)
- *type = entity->header.type;
-
- if (role)
- *role = entity->header.role;
-
- if (value)
- *value = entity->value;
-
- if (item_count != NULL) {
- if (entity->header.type == entity_type_sequence) {
- void *guard_p = hpi_entity_ptr_to_next(entity);
- struct hpi_entity *next = NULL;
- void *contents = entity->value;
-
- *item_count = 0;
- while (contents < guard_p) {
- (*item_count)++;
- err = hpi_entity_get_next(contents, 0,
- guard_p, &next);
- if (next == NULL || err)
- break;
- contents = next;
- }
- } else {
- *item_count = hpi_entity_item_count(entity);
- }
- }
- return err;
-}
-
-u16 hpi_gpio_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_gpio, u16 *pw_number_input_bits, u16 *pw_number_output_bits)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_OPEN);
- hm.adapter_index = adapter_index;
-
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0) {
- *ph_gpio =
- hpi_indexes_to_handle(HPI_OBJ_GPIO, adapter_index, 0);
- if (pw_number_input_bits)
- *pw_number_input_bits = hr.u.l.number_input_bits;
- if (pw_number_output_bits)
- *pw_number_output_bits = hr.u.l.number_output_bits;
- } else
- *ph_gpio = 0;
- return hr.error;
-}
-
-u16 hpi_gpio_read_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 bit_index, u16 *pw_bit_data)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_BIT);
- u32TOINDEX(h_gpio, &hm.adapter_index);
- hm.u.l.bit_index = bit_index;
-
- hpi_send_recv(&hm, &hr);
-
- *pw_bit_data = hr.u.l.bit_data[0];
- return hr.error;
-}
-
-u16 hpi_gpio_read_all_bits(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 aw_all_bit_data[4]
- )
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_READ_ALL);
- u32TOINDEX(h_gpio, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
-
- if (aw_all_bit_data) {
- aw_all_bit_data[0] = hr.u.l.bit_data[0];
- aw_all_bit_data[1] = hr.u.l.bit_data[1];
- aw_all_bit_data[2] = hr.u.l.bit_data[2];
- aw_all_bit_data[3] = hr.u.l.bit_data[3];
- }
- return hr.error;
-}
-
-u16 hpi_gpio_write_bit(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 bit_index, u16 bit_data)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO, HPI_GPIO_WRITE_BIT);
- u32TOINDEX(h_gpio, &hm.adapter_index);
- hm.u.l.bit_index = bit_index;
- hm.u.l.bit_data = bit_data;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_gpio_write_status(const struct hpi_hsubsys *ph_subsys, u32 h_gpio,
- u16 aw_all_bit_data[4]
- )
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_GPIO,
- HPI_GPIO_WRITE_STATUS);
- u32TOINDEX(h_gpio, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
-
- if (aw_all_bit_data) {
- aw_all_bit_data[0] = hr.u.l.bit_data[0];
- aw_all_bit_data[1] = hr.u.l.bit_data[1];
- aw_all_bit_data[2] = hr.u.l.bit_data[2];
- aw_all_bit_data[3] = hr.u.l.bit_data[3];
- }
- return hr.error;
-}
-
-u16 hpi_async_event_open(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u32 *ph_async)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
- HPI_ASYNCEVENT_OPEN);
- hm.adapter_index = adapter_index;
-
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0)
-
- *ph_async =
- hpi_indexes_to_handle(HPI_OBJ_ASYNCEVENT,
- adapter_index, 0);
- else
- *ph_async = 0;
- return hr.error;
-
-}
-
-u16 hpi_async_event_close(const struct hpi_hsubsys *ph_subsys, u32 h_async)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
- HPI_ASYNCEVENT_OPEN);
- u32TOINDEX(h_async, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_async_event_wait(const struct hpi_hsubsys *ph_subsys, u32 h_async,
- u16 maximum_events, struct hpi_async_event *p_events,
- u16 *pw_number_returned)
-{
-
- return 0;
-}
-
-u16 hpi_async_event_get_count(const struct hpi_hsubsys *ph_subsys,
- u32 h_async, u16 *pw_count)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
- HPI_ASYNCEVENT_GETCOUNT);
- u32TOINDEX(h_async, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0)
- if (pw_count)
- *pw_count = hr.u.as.u.count.count;
-
- return hr.error;
-}
-
-u16 hpi_async_event_get(const struct hpi_hsubsys *ph_subsys, u32 h_async,
- u16 maximum_events, struct hpi_async_event *p_events,
- u16 *pw_number_returned)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_ASYNCEVENT,
- HPI_ASYNCEVENT_GET);
- u32TOINDEX(h_async, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
- if (!hr.error) {
- memcpy(p_events, &hr.u.as.u.event,
- sizeof(struct hpi_async_event));
- *pw_number_returned = 1;
- }
-
- return hr.error;
-}
-
-u16 hpi_nv_memory_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_nv_memory, u16 *pw_size_in_bytes)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
- HPI_NVMEMORY_OPEN);
- hm.adapter_index = adapter_index;
-
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0) {
- *ph_nv_memory =
- hpi_indexes_to_handle(HPI_OBJ_NVMEMORY, adapter_index,
- 0);
- if (pw_size_in_bytes)
- *pw_size_in_bytes = hr.u.n.size_in_bytes;
- } else
- *ph_nv_memory = 0;
- return hr.error;
-}
-
-u16 hpi_nv_memory_read_byte(const struct hpi_hsubsys *ph_subsys,
- u32 h_nv_memory, u16 index, u16 *pw_data)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
- HPI_NVMEMORY_READ_BYTE);
- u32TOINDEX(h_nv_memory, &hm.adapter_index);
- hm.u.n.address = index;
-
- hpi_send_recv(&hm, &hr);
-
- *pw_data = hr.u.n.data;
- return hr.error;
-}
-
-u16 hpi_nv_memory_write_byte(const struct hpi_hsubsys *ph_subsys,
- u32 h_nv_memory, u16 index, u16 data)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_NVMEMORY,
- HPI_NVMEMORY_WRITE_BYTE);
- u32TOINDEX(h_nv_memory, &hm.adapter_index);
- hm.u.n.address = index;
- hm.u.n.data = data;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_profile_open_all(const struct hpi_hsubsys *ph_subsys,
- u16 adapter_index, u16 profile_index, u32 *ph_profile,
- u16 *pw_max_profiles)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
- HPI_PROFILE_OPEN_ALL);
- hm.adapter_index = adapter_index;
- hm.obj_index = profile_index;
- hpi_send_recv(&hm, &hr);
-
- *pw_max_profiles = hr.u.p.u.o.max_profiles;
- if (hr.error == 0)
- *ph_profile =
- hpi_indexes_to_handle(HPI_OBJ_PROFILE, adapter_index,
- profile_index);
- else
- *ph_profile = 0;
- return hr.error;
-}
-
-u16 hpi_profile_get(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
- u16 bin_index, u16 *pw_seconds, u32 *pmicro_seconds, u32 *pcall_count,
- u32 *pmax_micro_seconds, u32 *pmin_micro_seconds)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE, HPI_PROFILE_GET);
- u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
- hm.u.p.bin_index = bin_index;
- hpi_send_recv(&hm, &hr);
- if (pw_seconds)
- *pw_seconds = hr.u.p.u.t.seconds;
- if (pmicro_seconds)
- *pmicro_seconds = hr.u.p.u.t.micro_seconds;
- if (pcall_count)
- *pcall_count = hr.u.p.u.t.call_count;
- if (pmax_micro_seconds)
- *pmax_micro_seconds = hr.u.p.u.t.max_micro_seconds;
- if (pmin_micro_seconds)
- *pmin_micro_seconds = hr.u.p.u.t.min_micro_seconds;
- return hr.error;
-}
-
-u16 hpi_profile_get_utilization(const struct hpi_hsubsys *ph_subsys,
- u32 h_profile, u32 *putilization)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
- HPI_PROFILE_GET_UTILIZATION);
- u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
- hpi_send_recv(&hm, &hr);
- if (hr.error) {
- if (putilization)
- *putilization = 0;
- } else {
- if (putilization)
- *putilization = hr.u.p.u.t.call_count;
- }
- return hr.error;
-}
-
-u16 hpi_profile_get_name(const struct hpi_hsubsys *ph_subsys, u32 h_profile,
- u16 bin_index, char *sz_name, u16 name_length)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
- HPI_PROFILE_GET_NAME);
- u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
- hm.u.p.bin_index = bin_index;
- hpi_send_recv(&hm, &hr);
- if (hr.error) {
- if (sz_name)
- strcpy(sz_name, "??");
- } else {
- if (sz_name)
- memcpy(sz_name, (char *)hr.u.p.u.n.sz_name,
- name_length);
- }
- return hr.error;
-}
-
-u16 hpi_profile_start_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
- HPI_PROFILE_START_ALL);
- u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_profile_stop_all(const struct hpi_hsubsys *ph_subsys, u32 h_profile)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_PROFILE,
- HPI_PROFILE_STOP_ALL);
- u32TOINDEXES(h_profile, &hm.adapter_index, &hm.obj_index);
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_watchdog_open(const struct hpi_hsubsys *ph_subsys, u16 adapter_index,
- u32 *ph_watchdog)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
- HPI_WATCHDOG_OPEN);
- hm.adapter_index = adapter_index;
-
- hpi_send_recv(&hm, &hr);
-
- if (hr.error == 0)
- *ph_watchdog =
- hpi_indexes_to_handle(HPI_OBJ_WATCHDOG, adapter_index,
- 0);
- else
- *ph_watchdog = 0;
- return hr.error;
-}
-
-u16 hpi_watchdog_set_time(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog,
- u32 time_millisec)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
- HPI_WATCHDOG_SET_TIME);
- u32TOINDEX(h_watchdog, &hm.adapter_index);
- hm.u.w.time_ms = time_millisec;
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
-
-u16 hpi_watchdog_ping(const struct hpi_hsubsys *ph_subsys, u32 h_watchdog)
-{
- struct hpi_message hm;
- struct hpi_response hr;
- hpi_init_message_response(&hm, &hr, HPI_OBJ_WATCHDOG,
- HPI_WATCHDOG_PING);
- u32TOINDEX(h_watchdog, &hm.adapter_index);
-
- hpi_send_recv(&hm, &hr);
-
- return hr.error;
-}
diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c
index 8e1d099ed7e4..628376ce4a49 100644
--- a/sound/pci/asihpi/hpimsginit.c
+++ b/sound/pci/asihpi/hpimsginit.c
@@ -32,21 +32,6 @@ static u16 res_size[HPI_OBJ_MAXINDEX + 1] = HPI_RESPONSE_SIZE_BY_OBJECT;
static u16 gwSSX2_bypass;
/** \internal
- * Used by ASIO driver to disable SSX2 for a single process
- * \param phSubSys Pointer to HPI subsystem handle.
- * \param wBypass New bypass setting 0 = off, nonzero = on
- * \return Previous bypass setting.
- */
-u16 hpi_subsys_ssx2_bypass(const struct hpi_hsubsys *ph_subsys, u16 bypass)
-{
- u16 old_value = gwSSX2_bypass;
-
- gwSSX2_bypass = bypass;
-
- return old_value;
-}
-
-/** \internal
* initialize the HPI message structure
*/
static void hpi_init_message(struct hpi_message *phm, u16 object,
@@ -65,7 +50,8 @@ static void hpi_init_message(struct hpi_message *phm, u16 object,
phm->object = object;
phm->function = function;
phm->version = 0;
- /* Expect adapter index to be set by caller */
+ phm->adapter_index = HPI_ADAPTER_INDEX_INVALID;
+ /* Expect actual adapter index to be set by caller */
}
/** \internal
diff --git a/sound/pci/asihpi/hpimsginit.h b/sound/pci/asihpi/hpimsginit.h
index 864ad020c9b3..bfd330d78b58 100644
--- a/sound/pci/asihpi/hpimsginit.h
+++ b/sound/pci/asihpi/hpimsginit.h
@@ -21,11 +21,15 @@
(C) Copyright AudioScience Inc. 2007
*******************************************************************************/
/* Initialise response headers, or msg/response pairs.
-Note that it is valid to just init a response e.g. when a lower level is preparing
-a response to a message.
-However, when sending a message, a matching response buffer always must be prepared
+Note that it is valid to just init a response e.g. when a lower level is
+preparing a response to a message.
+However, when sending a message, a matching response buffer must always be
+prepared.
*/
+#ifndef _HPIMSGINIT_H_
+#define _HPIMSGINIT_H_
+
void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
u16 error);
@@ -38,3 +42,5 @@ void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
void hpi_init_message_responseV1(struct hpi_message_header *phm, u16 msg_size,
struct hpi_response_header *phr, u16 res_size, u16 object,
u16 function);
+
+#endif /* _HPIMSGINIT_H_ */
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index f01ab964f602..bcbdf30a6aa0 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -23,6 +23,7 @@ Extended Message Function With Response Cacheing
#define SOURCEFILE_NAME "hpimsgx.c"
#include "hpi_internal.h"
#include "hpimsginit.h"
+#include "hpicmn.h"
#include "hpimsgx.h"
#include "hpidebug.h"
@@ -42,22 +43,24 @@ static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
for (i = 0; asihpi_pci_tbl[i].vendor != 0; i++) {
if (asihpi_pci_tbl[i].vendor != PCI_ANY_ID
- && asihpi_pci_tbl[i].vendor != pci_info->vendor_id)
+ && asihpi_pci_tbl[i].vendor !=
+ pci_info->pci_dev->vendor)
continue;
if (asihpi_pci_tbl[i].device != PCI_ANY_ID
- && asihpi_pci_tbl[i].device != pci_info->device_id)
+ && asihpi_pci_tbl[i].device !=
+ pci_info->pci_dev->device)
continue;
if (asihpi_pci_tbl[i].subvendor != PCI_ANY_ID
&& asihpi_pci_tbl[i].subvendor !=
- pci_info->subsys_vendor_id)
+ pci_info->pci_dev->subsystem_vendor)
continue;
if (asihpi_pci_tbl[i].subdevice != PCI_ANY_ID
&& asihpi_pci_tbl[i].subdevice !=
- pci_info->subsys_device_id)
+ pci_info->pci_dev->subsystem_device)
continue;
- HPI_DEBUG_LOG(DEBUG, " %x,%lu\n", i,
- asihpi_pci_tbl[i].driver_data);
+ /* HPI_DEBUG_LOG(DEBUG, " %x,%lx\n", i,
+ asihpi_pci_tbl[i].driver_data); */
return (hpi_handler_func *) asihpi_pci_tbl[i].driver_data;
}
@@ -67,21 +70,12 @@ static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
static inline void hw_entry_point(struct hpi_message *phm,
struct hpi_response *phr)
{
-
- hpi_handler_func *ep;
-
- if (phm->adapter_index < HPI_MAX_ADAPTERS) {
- ep = (hpi_handler_func *) hpi_entry_points[phm->
- adapter_index];
- if (ep) {
- HPI_DEBUG_MESSAGE(DEBUG, phm);
- ep(phm, phr);
- HPI_DEBUG_RESPONSE(phr);
- return;
- }
- }
- hpi_init_response(phr, phm->object, phm->function,
- HPI_ERROR_PROCESSING_MESSAGE);
+ if ((phm->adapter_index < HPI_MAX_ADAPTERS)
+ && hpi_entry_points[phm->adapter_index])
+ hpi_entry_points[phm->adapter_index] (phm, phr);
+ else
+ hpi_init_response(phr, phm->object, phm->function,
+ HPI_ERROR_PROCESSING_MESSAGE);
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr);
@@ -100,6 +94,7 @@ static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner);
static void HPIMSGX__reset(u16 adapter_index);
+
static u16 HPIMSGX__init(struct hpi_message *phm, struct hpi_response *phr);
static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner);
@@ -153,8 +148,6 @@ static struct hpi_stream_response
static struct hpi_mixer_response rESP_HPI_MIXER_OPEN[HPI_MAX_ADAPTERS];
-static struct hpi_subsys_response gRESP_HPI_SUBSYS_FIND_ADAPTERS;
-
static struct adapter_info aDAPTER_INFO[HPI_MAX_ADAPTERS];
/* use these to keep track of opens from user mode apps/DLLs */
@@ -167,6 +160,11 @@ static struct asi_open_state
static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
+ if (phm->adapter_index != HPI_ADAPTER_INDEX_INVALID)
+ HPI_DEBUG_LOG(WARNING,
+ "suspicious adapter index %d in subsys message 0x%x.\n",
+ phm->adapter_index, phm->function);
+
switch (phm->function) {
case HPI_SUBSYS_GET_VERSION:
hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
@@ -204,85 +202,37 @@ static void subsys_message(struct hpi_message *phm, struct hpi_response *phr,
HPI_SUBSYS_DRIVER_UNLOAD, 0);
return;
- case HPI_SUBSYS_GET_INFO:
- HPI_COMMON(phm, phr);
- break;
-
- case HPI_SUBSYS_FIND_ADAPTERS:
- memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
- sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
- break;
case HPI_SUBSYS_GET_NUM_ADAPTERS:
- memcpy(phr, &gRESP_HPI_SUBSYS_FIND_ADAPTERS,
- sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
- phr->function = HPI_SUBSYS_GET_NUM_ADAPTERS;
- break;
case HPI_SUBSYS_GET_ADAPTER:
- {
- int count = phm->adapter_index;
- int index = 0;
- hpi_init_response(phr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_GET_ADAPTER, 0);
-
- /* This is complicated by the fact that we want to
- * "skip" 0's in the adapter list.
- * First, make sure we are pointing to a
- * non-zero adapter type.
- */
- while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
- s.aw_adapter_list[index] == 0) {
- index++;
- if (index >= HPI_MAX_ADAPTERS)
- break;
- }
- while (count) {
- /* move on to the next adapter */
- index++;
- if (index >= HPI_MAX_ADAPTERS)
- break;
- while (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
- s.aw_adapter_list[index] == 0) {
- index++;
- if (index >= HPI_MAX_ADAPTERS)
- break;
- }
- count--;
- }
+ HPI_COMMON(phm, phr);
+ break;
- if (index < HPI_MAX_ADAPTERS) {
- phr->u.s.adapter_index = (u16)index;
- phr->u.s.aw_adapter_list[0] =
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.
- s.aw_adapter_list[index];
- } else {
- phr->u.s.adapter_index = 0;
- phr->u.s.aw_adapter_list[0] = 0;
- phr->error = HPI_ERROR_BAD_ADAPTER_NUMBER;
- }
- break;
- }
case HPI_SUBSYS_CREATE_ADAPTER:
HPIMSGX__init(phm, phr);
break;
+
case HPI_SUBSYS_DELETE_ADAPTER:
- HPIMSGX__cleanup(phm->adapter_index, h_owner);
+ HPIMSGX__cleanup(phm->obj_index, h_owner);
{
struct hpi_message hm;
struct hpi_response hr;
- /* call to HPI_ADAPTER_CLOSE */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_CLOSE);
- hm.adapter_index = phm->adapter_index;
+ hm.adapter_index = phm->obj_index;
hw_entry_point(&hm, &hr);
}
- hw_entry_point(phm, phr);
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.
- aw_adapter_list[phm->adapter_index]
- = 0;
- hpi_entry_points[phm->adapter_index] = NULL;
+ if ((phm->obj_index < HPI_MAX_ADAPTERS)
+ && hpi_entry_points[phm->obj_index]) {
+ hpi_entry_points[phm->obj_index] (phm, phr);
+ hpi_entry_points[phm->obj_index] = NULL;
+ } else
+ phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
+
break;
default:
- hw_entry_point(phm, phr);
+ /* Must explicitly handle every subsys message in this switch */
+ hpi_init_response(phr, HPI_OBJ_SUBSYSTEM, phm->function,
+ HPI_ERROR_INVALID_FUNC);
break;
}
}
@@ -409,33 +359,7 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
break;
}
HPI_DEBUG_RESPONSE(phr);
-#if 1
- if (phr->error >= HPI_ERROR_BACKEND_BASE) {
- void *ep = NULL;
- char *ep_name;
-
- HPI_DEBUG_MESSAGE(ERROR, phm);
-
- if (phm->adapter_index < HPI_MAX_ADAPTERS)
- ep = hpi_entry_points[phm->adapter_index];
-
- /* Don't need this? Have adapter index in debug info
- Know at driver load time index->backend mapping */
- if (ep == HPI_6000)
- ep_name = "HPI_6000";
- else if (ep == HPI_6205)
- ep_name = "HPI_6205";
- else
- ep_name = "unknown";
-
- HPI_DEBUG_LOG(ERROR, "HPI %s response - error# %d\n", ep_name,
- phr->error);
-
- if (hpi_debug_level >= HPI_DEBUG_LEVEL_VERBOSE)
- hpi_debug_data((u16 *)phm,
- sizeof(*phm) / sizeof(u16));
- }
-#endif
+
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr)
@@ -484,7 +408,7 @@ static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
else {
instream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
@@ -509,7 +433,7 @@ static void instream_open(struct hpi_message *phm, struct hpi_response *phr,
sizeof(rESP_HPI_ISTREAM_OPEN[0][0]));
}
}
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
}
static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
@@ -530,7 +454,7 @@ static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
phm->wAdapterIndex, phm->wObjIndex, hOwner); */
instream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ISTREAM,
HPI_ISTREAM_RESET);
@@ -556,7 +480,7 @@ static void instream_close(struct hpi_message *phm, struct hpi_response *phr,
obj_index].h_owner);
phr->error = HPI_ERROR_OBJ_NOT_OPEN;
}
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
}
static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
@@ -581,7 +505,7 @@ static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
else {
outstream_user_open[phm->adapter_index][phm->
obj_index].open_flag = 1;
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
@@ -606,7 +530,7 @@ static void outstream_open(struct hpi_message *phm, struct hpi_response *phr,
sizeof(rESP_HPI_OSTREAM_OPEN[0][0]));
}
}
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
}
static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
@@ -628,7 +552,7 @@ static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
phm->wAdapterIndex, phm->wObjIndex, hOwner); */
outstream_user_open[phm->adapter_index][phm->
obj_index].h_owner = NULL;
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
/* issue a reset */
hpi_init_message_response(&hm, &hr, HPI_OBJ_OSTREAM,
HPI_OSTREAM_RESET);
@@ -654,7 +578,7 @@ static void outstream_close(struct hpi_message *phm, struct hpi_response *phr,
obj_index].h_owner);
phr->error = HPI_ERROR_OBJ_NOT_OPEN;
}
- hpios_msgxlock_un_lock(&msgx_lock);
+ hpios_msgxlock_unlock(&msgx_lock);
}
static u16 adapter_prepare(u16 adapter)
@@ -683,16 +607,9 @@ static u16 adapter_prepare(u16 adapter)
if (hr.error)
return hr.error;
- aDAPTER_INFO[adapter].num_outstreams = hr.u.a.num_outstreams;
- aDAPTER_INFO[adapter].num_instreams = hr.u.a.num_instreams;
- aDAPTER_INFO[adapter].type = hr.u.a.adapter_type;
-
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list[adapter] =
- hr.u.a.adapter_type;
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters++;
- if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters > HPI_MAX_ADAPTERS)
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters =
- HPI_MAX_ADAPTERS;
+ aDAPTER_INFO[adapter].num_outstreams = hr.u.ax.info.num_outstreams;
+ aDAPTER_INFO[adapter].num_instreams = hr.u.ax.info.num_instreams;
+ aDAPTER_INFO[adapter].type = hr.u.ax.info.adapter_type;
/* call to HPI_OSTREAM_OPEN */
for (i = 0; i < aDAPTER_INFO[adapter].num_outstreams; i++) {
@@ -727,7 +644,7 @@ static u16 adapter_prepare(u16 adapter)
memcpy(&rESP_HPI_MIXER_OPEN[adapter], &hr,
sizeof(rESP_HPI_MIXER_OPEN[0]));
- return gRESP_HPI_SUBSYS_FIND_ADAPTERS.h.error;
+ return 0;
}
static void HPIMSGX__reset(u16 adapter_index)
@@ -737,12 +654,6 @@ static void HPIMSGX__reset(u16 adapter_index)
struct hpi_response hr;
if (adapter_index == HPIMSGX_ALLADAPTERS) {
- /* reset all responses to contain errors */
- hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM,
- HPI_SUBSYS_FIND_ADAPTERS, 0);
- memcpy(&gRESP_HPI_SUBSYS_FIND_ADAPTERS, &hr,
- sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS));
-
for (adapter = 0; adapter < HPI_MAX_ADAPTERS; adapter++) {
hpi_init_response(&hr, HPI_OBJ_ADAPTER,
@@ -783,12 +694,6 @@ static void HPIMSGX__reset(u16 adapter_index)
rESP_HPI_ISTREAM_OPEN[adapter_index][i].h.error =
HPI_ERROR_INVALID_OBJ;
}
- if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.
- s.aw_adapter_list[adapter_index]) {
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.
- s.aw_adapter_list[adapter_index] = 0;
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters--;
- }
}
}
@@ -802,15 +707,9 @@ static u16 HPIMSGX__init(struct hpi_message *phm,
hpi_handler_func *entry_point_func;
struct hpi_response hr;
- if (gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.num_adapters >= HPI_MAX_ADAPTERS)
- return HPI_ERROR_BAD_ADAPTER_NUMBER;
-
/* Init response here so we can pass in previous adapter list */
hpi_init_response(&hr, phm->object, phm->function,
HPI_ERROR_INVALID_OBJ);
- memcpy(hr.u.s.aw_adapter_list,
- gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list,
- sizeof(gRESP_HPI_SUBSYS_FIND_ADAPTERS.s.aw_adapter_list));
entry_point_func =
hpi_lookup_entry_point_function(phm->u.s.resource.r.pci);
@@ -860,7 +759,7 @@ static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner)
struct hpi_response hr;
HPI_DEBUG_LOG(DEBUG,
- "close adapter %d ostream %d\n",
+ "Close adapter %d ostream %d\n",
adapter, i);
hpi_init_message_response(&hm, &hr,
@@ -884,7 +783,7 @@ static void HPIMSGX__cleanup(u16 adapter_index, void *h_owner)
struct hpi_response hr;
HPI_DEBUG_LOG(DEBUG,
- "close adapter %d istream %d\n",
+ "Close adapter %d istream %d\n",
adapter, i);
hpi_init_message_response(&hm, &hr,
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 22dbd91811a4..cd624f13ff8e 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -30,6 +30,7 @@ Common Linux HPI ioctl and module probe/remove functions
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
+#include <linux/pci.h>
#include <linux/stringify.h>
#ifdef MODULE_FIRMWARE
@@ -45,7 +46,7 @@ MODULE_FIRMWARE("asihpi/dsp8900.bin");
static int prealloc_stream_buf;
module_param(prealloc_stream_buf, int, S_IRUGO);
MODULE_PARM_DESC(prealloc_stream_buf,
- "preallocate size for per-adapter stream buffer");
+ "Preallocate size for per-adapter stream buffer");
/* Allow the debug level to be changed after module load.
E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
@@ -121,8 +122,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
/* Read the message and response pointers from user space. */
- if (get_user(puhm, &phpi_ioctl_data->phm) ||
- get_user(puhr, &phpi_ioctl_data->phr)) {
+ if (get_user(puhm, &phpi_ioctl_data->phm)
+ || get_user(puhr, &phpi_ioctl_data->phr)) {
err = -EFAULT;
goto out;
}
@@ -135,7 +136,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (hm->h.size > sizeof(*hm))
hm->h.size = sizeof(*hm);
- /*printk(KERN_INFO "message size %d\n", hm->h.wSize); */
+ /* printk(KERN_INFO "message size %d\n", hm->h.wSize); */
uncopied_bytes = copy_from_user(hm, puhm, hm->h.size);
if (uncopied_bytes) {
@@ -155,8 +156,13 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto out;
}
+ if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) {
+ err = -EINVAL;
+ goto out;
+ }
+
pa = &adapters[hm->h.adapter_index];
- hr->h.size = 0;
+ hr->h.size = res_max_size;
if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
@@ -216,7 +222,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
if (pa->buffer_size < size) {
HPI_DEBUG_LOG(DEBUG,
- "realloc adapter %d stream "
+ "Realloc adapter %d stream "
"buffer from %zd to %d\n",
hm->h.adapter_index,
pa->buffer_size, size);
@@ -259,7 +265,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
copy_from_user(pa->p_buffer, ptr, size);
if (uncopied_bytes)
HPI_DEBUG_LOG(WARNING,
- "missed %d of %d "
+ "Missed %d of %d "
"bytes from user\n", uncopied_bytes,
size);
}
@@ -271,7 +277,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
copy_to_user(ptr, pa->p_buffer, size);
if (uncopied_bytes)
HPI_DEBUG_LOG(WARNING,
- "missed %d of %d " "bytes to user\n",
+ "Missed %d of %d " "bytes to user\n",
uncopied_bytes, size);
}
@@ -290,9 +296,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (hr->h.size > res_max_size) {
HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size,
res_max_size);
- /*HPI_DEBUG_MESSAGE(ERROR, hm); */
- err = -EFAULT;
- goto out;
+ hr->h.error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
+ hr->h.specific_error = hr->h.size;
+ hr->h.size = sizeof(hr->h);
}
uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
@@ -320,18 +326,26 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
memset(&adapter, 0, sizeof(adapter));
- printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n",
- pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor,
+ dev_printk(KERN_DEBUG, &pci_dev->dev,
+ "probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor,
+ pci_dev->device, pci_dev->subsystem_vendor,
pci_dev->subsystem_device, pci_dev->devfn);
+ if (pci_enable_device(pci_dev) < 0) {
+ dev_printk(KERN_ERR, &pci_dev->dev,
+ "pci_enable_device failed, disabling device\n");
+ return -EIO;
+ }
+
+ pci_set_master(pci_dev); /* also sets latency timer if < 16 */
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_CREATE_ADAPTER);
hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER,
HPI_ERROR_PROCESSING_MESSAGE);
- hm.adapter_index = -1; /* an invalid index */
+ hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
- /* fill in HPI_PCI information from kernel provided information */
adapter.pci = pci_dev;
nm = HPI_MAX_ADAPTER_MEM_SPACES;
@@ -359,19 +373,7 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx];
}
- /* could replace Pci with direct pointer to pci_dev for linux
- Instead wrap accessor functions for IDs etc.
- Would it work for windows?
- */
- pci.bus_number = pci_dev->bus->number;
- pci.vendor_id = (u16)pci_dev->vendor;
- pci.device_id = (u16)pci_dev->device;
- pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff);
- pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff);
- pci.device_number = pci_dev->devfn;
- pci.interrupt = pci_dev->irq;
- pci.p_os_data = pci_dev;
-
+ pci.pci_dev = pci_dev;
hm.u.s.resource.bus_type = HPI_BUS_PCI;
hm.u.s.resource.r.pci = &pci;
@@ -392,10 +394,10 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
}
adapter.index = hr.u.s.adapter_index;
- adapter.type = hr.u.s.aw_adapter_list[adapter.index];
+ adapter.type = hr.u.s.adapter_type;
hm.adapter_index = adapter.index;
- err = hpi_adapter_open(NULL, adapter.index);
+ err = hpi_adapter_open(adapter.index);
if (err)
goto err;
@@ -407,8 +409,9 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
mutex_init(&adapters[adapter.index].mutex);
pci_set_drvdata(pci_dev, &adapters[adapter.index]);
- printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n",
- adapter.type, adapter.index);
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "probe succeeded for ASI%04X HPI index %d\n", adapter.type,
+ adapter.index);
return 0;
@@ -439,7 +442,8 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_DELETE_ADAPTER);
- hm.adapter_index = pa->index;
+ hm.obj_index = pa->index;
+ hm.adapter_index = HPI_ADAPTER_INDEX_INVALID;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
/* unmap PCI memory space, mapped during device init. */
@@ -450,20 +454,18 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
}
}
- if (pa->p_buffer) {
- pa->buffer_size = 0;
+ if (pa->p_buffer)
vfree(pa->p_buffer);
- }
pci_set_drvdata(pci_dev, NULL);
- /*
- printk(KERN_INFO "PCI device (%04x:%04x,%04x:%04x,%04x),"
- " HPI index # %d, removed.\n",
- pci_dev->vendor, pci_dev->device,
- pci_dev->subsystem_vendor,
- pci_dev->subsystem_device, pci_dev->devfn,
- pa->index);
- */
+ if (1)
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "remove %04x:%04x,%04x:%04x,%04x," " HPI index %d.\n",
+ pci_dev->vendor, pci_dev->device,
+ pci_dev->subsystem_vendor, pci_dev->subsystem_device,
+ pci_dev->devfn, pa->index);
+
+ memset(pa, 0, sizeof(*pa));
}
void __init asihpi_init(void)
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h
index 370f39b43f85..03273e729f99 100644
--- a/sound/pci/asihpi/hpios.h
+++ b/sound/pci/asihpi/hpios.h
@@ -27,9 +27,7 @@ HPI Operating System Specific macros for Linux Kernel driver
#define HPI_OS_LINUX_KERNEL
#define HPI_OS_DEFINED
-#define HPI_KERNEL_MODE
-
-#define HPI_REASSIGN_DUPLICATE_ADAPTER_IDX
+#define HPI_BUILD_KERNEL_MODE
#include <linux/io.h>
#include <asm/system.h>
@@ -135,20 +133,20 @@ static inline void cond_unlock(struct hpios_spinlock *l)
#define hpios_msgxlock_init(obj) spin_lock_init(&(obj)->lock)
#define hpios_msgxlock_lock(obj) cond_lock(obj)
-#define hpios_msgxlock_un_lock(obj) cond_unlock(obj)
+#define hpios_msgxlock_unlock(obj) cond_unlock(obj)
#define hpios_dsplock_init(obj) spin_lock_init(&(obj)->dsp_lock.lock)
#define hpios_dsplock_lock(obj) cond_lock(&(obj)->dsp_lock)
#define hpios_dsplock_unlock(obj) cond_unlock(&(obj)->dsp_lock)
#ifdef CONFIG_SND_DEBUG
-#define HPI_DEBUG
+#define HPI_BUILD_DEBUG
#endif
#define HPI_ALIST_LOCKING
#define hpios_alistlock_init(obj) spin_lock_init(&((obj)->list_lock.lock))
#define hpios_alistlock_lock(obj) spin_lock(&((obj)->list_lock.lock))
-#define hpios_alistlock_un_lock(obj) spin_unlock(&((obj)->list_lock.lock))
+#define hpios_alistlock_unlock(obj) spin_unlock(&((obj)->list_lock.lock))
struct hpi_adapter {
/* mutex prevents contention for one card
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 49d572a7b235..3119cd97a217 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -522,7 +522,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
atiixp_read(chip, CMD);
mdelay(1);
atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
- if (--timeout) {
+ if (!--timeout) {
snd_printk(KERN_ERR "atiixp: codec reset timeout\n");
break;
}
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 91d7036b6411..2f74c2fdf1ea 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -498,7 +498,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
atiixp_read(chip, CMD);
msleep(1);
atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET);
- if (--timeout) {
+ if (!--timeout) {
snd_printk(KERN_ERR "atiixp-modem: codec reset timeout\n");
break;
}
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index cf46bba563cf..ecb8f4daf408 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -211,7 +211,7 @@ static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma);
//static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma);
static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma);
static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma);
-static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
+static inline int vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma);
#ifndef CHIP_AU8810
@@ -219,7 +219,7 @@ static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma);
-static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma);
+static inline int vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma);
#endif
/* global stuff. */
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 16c0bdfbb164..489150380eac 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1249,7 +1249,7 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
}
}
-static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
+static inline int vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
{
stream_t *dma = &vortex->dma_adb[adbdma];
int temp, page, delta;
@@ -1506,7 +1506,7 @@ static int vortex_wtdma_getcursubuffer(vortex_t * vortex, int wtdma)
POS_SHIFT) & POS_MASK);
}
#endif
-static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma)
+static inline int vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma)
{
stream_t *dma = &vortex->dma_wt[wtdma];
int temp;
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 38602b85874d..278ed8189fca 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -896,7 +896,8 @@ static int __devinit vortex_eq_init(vortex_t * vortex)
if ((kcontrol =
snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
return -ENOMEM;
- strcpy(kcontrol->id.name, EqBandLabels[i]);
+ snprintf(kcontrol->id.name, sizeof(kcontrol->id.name),
+ "%s Playback Volume", EqBandLabels[i]);
kcontrol->private_value = i;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 573594bf3225..5715c4d05573 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1,6 +1,5 @@
-/*
- * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
- * Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de>
+/* azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
+ * Copyright (C) 2002, 2005 - 2011 by Andreas Mohr <andi AT lisas.de>
*
* Framework borrowed from Bart Hartgers's als4000.c.
* Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
@@ -66,6 +65,13 @@
* addresses illegally. So far unfortunately it looks like the very flexible
* ALSA AC97 support is still not enough to easily compensate for such a
* grave layout violation despite all tweaks and quirks mechanisms it offers.
+ * Well, not quite: now ac97 layer is much improved (bus-specific ops!),
+ * thus I was able to implement support - it's actually working quite well.
+ * An interesting item might be Aztech AMR 2800-W, since it's an AC97
+ * modem card which might reveal the Aztech-specific codec ID which
+ * we might want to pretend, too. Dito PCI168's brother, PCI368,
+ * where the advertising datasheet says it's AC97-based and has a
+ * Digital Enhanced Game Port.
* - builtin genuine OPL3 - verified to work fine, 20080506
* - full duplex 16bit playback/record at independent sampling rate
* - MPU401 (+ legacy address support, claimed by one official spec sheet)
@@ -189,6 +195,16 @@
#include <sound/mpu401.h>
#include <sound/opl3.h>
#include <sound/initval.h>
+/*
+ * Config switch, to use ALSA's AC97 layer instead of old custom mixer crap.
+ * If the AC97 compatibility parts we needed to implement locally turn out
+ * to work nicely, then remove the old implementation eventually.
+ */
+#define AZF_USE_AC97_LAYER 1
+
+#ifdef AZF_USE_AC97_LAYER
+#include <sound/ac97_codec.h>
+#endif
#include "azt3328.h"
MODULE_AUTHOR("Andreas Mohr <andi AT lisas.de>");
@@ -328,6 +344,10 @@ struct snd_azf3328 {
/* playback, recording and I2S out codecs */
struct snd_azf3328_codec_data codecs[3];
+#ifdef AZF_USE_AC97_LAYER
+ struct snd_ac97 *ac97;
+#endif
+
struct snd_card *card;
struct snd_rawmidi *rmidi;
@@ -506,7 +526,7 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg)
#define AZF_MUTE_BIT 0x80
static bool
-snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip,
+snd_azf3328_mixer_mute_control(const struct snd_azf3328 *chip,
unsigned reg, bool do_mute
)
{
@@ -521,6 +541,323 @@ snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip,
return (do_mute) ? !updated : updated;
}
+static inline bool
+snd_azf3328_mixer_mute_control_master(const struct snd_azf3328 *chip,
+ bool do_mute
+)
+{
+ return snd_azf3328_mixer_mute_control(
+ chip,
+ IDX_MIXER_PLAY_MASTER,
+ do_mute
+ );
+}
+
+static inline bool
+snd_azf3328_mixer_mute_control_pcm(const struct snd_azf3328 *chip,
+ bool do_mute
+)
+{
+ return snd_azf3328_mixer_mute_control(
+ chip,
+ IDX_MIXER_WAVEOUT,
+ do_mute
+ );
+}
+
+static inline void
+snd_azf3328_mixer_reset(const struct snd_azf3328 *chip)
+{
+ /* reset (close) mixer:
+ * first mute master volume, then reset
+ */
+ snd_azf3328_mixer_mute_control_master(chip, 1);
+ snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
+}
+
+#ifdef AZF_USE_AC97_LAYER
+
+static inline void
+snd_azf3328_mixer_ac97_map_unsupported(unsigned short reg, const char *mode)
+{
+ /* need to add some more or less clever emulation? */
+ printk(KERN_WARNING
+ "azt3328: missing %s emulation for AC97 register 0x%02x!\n",
+ mode, reg);
+}
+
+/*
+ * Need to have _special_ AC97 mixer hardware register index mapper,
+ * to compensate for the issue of a rather AC97-incompatible hardware layout.
+ */
+#define AZF_REG_MASK 0x3f
+#define AZF_AC97_REG_UNSUPPORTED 0x8000
+#define AZF_AC97_REG_REAL_IO_READ 0x4000
+#define AZF_AC97_REG_REAL_IO_WRITE 0x2000
+#define AZF_AC97_REG_REAL_IO_RW \
+ (AZF_AC97_REG_REAL_IO_READ | AZF_AC97_REG_REAL_IO_WRITE)
+#define AZF_AC97_REG_EMU_IO_READ 0x0400
+#define AZF_AC97_REG_EMU_IO_WRITE 0x0200
+#define AZF_AC97_REG_EMU_IO_RW \
+ (AZF_AC97_REG_EMU_IO_READ | AZF_AC97_REG_EMU_IO_WRITE)
+static unsigned short
+snd_azf3328_mixer_ac97_map_reg_idx(unsigned short reg)
+{
+ static const struct {
+ unsigned short azf_reg;
+ } azf_reg_mapper[] = {
+ /* Especially when taking into consideration
+ * mono/stereo-based sequence of azf vs. AC97 control series,
+ * it's quite obvious that azf simply got rid
+ * of the AC97_HEADPHONE control at its intended offset,
+ * thus shifted _all_ controls by one,
+ * and _then_ simply added it as an FMSYNTH control at the end,
+ * to make up for the offset.
+ * This means we'll have to translate indices here as
+ * needed and then do some tiny AC97 patch action
+ * (snd_ac97_rename_vol_ctl() etc.) - that's it.
+ */
+ { /* AC97_RESET */ IDX_MIXER_RESET
+ | AZF_AC97_REG_REAL_IO_WRITE
+ | AZF_AC97_REG_EMU_IO_READ },
+ { /* AC97_MASTER */ IDX_MIXER_PLAY_MASTER },
+ /* note large shift: AC97_HEADPHONE to IDX_MIXER_FMSYNTH! */
+ { /* AC97_HEADPHONE */ IDX_MIXER_FMSYNTH },
+ { /* AC97_MASTER_MONO */ IDX_MIXER_MODEMOUT },
+ { /* AC97_MASTER_TONE */ IDX_MIXER_BASSTREBLE },
+ { /* AC97_PC_BEEP */ IDX_MIXER_PCBEEP },
+ { /* AC97_PHONE */ IDX_MIXER_MODEMIN },
+ { /* AC97_MIC */ IDX_MIXER_MIC },
+ { /* AC97_LINE */ IDX_MIXER_LINEIN },
+ { /* AC97_CD */ IDX_MIXER_CDAUDIO },
+ { /* AC97_VIDEO */ IDX_MIXER_VIDEO },
+ { /* AC97_AUX */ IDX_MIXER_AUX },
+ { /* AC97_PCM */ IDX_MIXER_WAVEOUT },
+ { /* AC97_REC_SEL */ IDX_MIXER_REC_SELECT },
+ { /* AC97_REC_GAIN */ IDX_MIXER_REC_VOLUME },
+ { /* AC97_REC_GAIN_MIC */ AZF_AC97_REG_EMU_IO_RW },
+ { /* AC97_GENERAL_PURPOSE */ IDX_MIXER_ADVCTL2 },
+ { /* AC97_3D_CONTROL */ IDX_MIXER_ADVCTL1 },
+ };
+
+ unsigned short reg_azf = AZF_AC97_REG_UNSUPPORTED;
+
+ /* azf3328 supports the low-numbered and low-spec:ed range
+ of AC97 regs only */
+ if (reg <= AC97_3D_CONTROL) {
+ unsigned short reg_idx = reg / 2;
+ reg_azf = azf_reg_mapper[reg_idx].azf_reg;
+ /* a translation-only entry means it's real read/write: */
+ if (!(reg_azf & ~AZF_REG_MASK))
+ reg_azf |= AZF_AC97_REG_REAL_IO_RW;
+ } else {
+ switch (reg) {
+ case AC97_POWERDOWN:
+ reg_azf = AZF_AC97_REG_EMU_IO_RW;
+ break;
+ case AC97_EXTENDED_ID:
+ reg_azf = AZF_AC97_REG_EMU_IO_READ;
+ break;
+ case AC97_EXTENDED_STATUS:
+ /* I don't know what the h*ll AC97 layer
+ * would consult this _extended_ register for
+ * given a base-AC97-advertised card,
+ * but let's just emulate it anyway :-P
+ */
+ reg_azf = AZF_AC97_REG_EMU_IO_RW;
+ break;
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ reg_azf = AZF_AC97_REG_EMU_IO_READ;
+ break;
+ }
+ }
+ return reg_azf;
+}
+
+static const unsigned short
+azf_emulated_ac97_caps =
+ AC97_BC_DEDICATED_MIC |
+ AC97_BC_BASS_TREBLE |
+ /* Headphone is an FM Synth control here */
+ AC97_BC_HEADPHONE |
+ /* no AC97_BC_LOUDNESS! */
+ /* mask 0x7c00 is
+ vendor-specific 3D enhancement
+ vendor indicator.
+ Since there actually _is_ an
+ entry for Aztech Labs
+ (13), make damn sure
+ to indicate it. */
+ (13 << 10);
+
+static const unsigned short
+azf_emulated_ac97_powerdown =
+ /* pretend everything to be active */
+ AC97_PD_ADC_STATUS |
+ AC97_PD_DAC_STATUS |
+ AC97_PD_MIXER_STATUS |
+ AC97_PD_VREF_STATUS;
+
+/*
+ * Emulated, _inofficial_ vendor ID
+ * (there might be some devices such as the MR 2800-W
+ * which could reveal the real Aztech AC97 ID).
+ * We choose to use "AZT" prefix, and then use 1 to indicate PCI168
+ * (better don't use 0x68 since there's a PCI368 as well).
+ */
+static const unsigned int
+azf_emulated_ac97_vendor_id = 0x415a5401;
+
+static unsigned short
+snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
+{
+ const struct snd_azf3328 *chip = ac97->private_data;
+ unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
+ unsigned short reg_val = 0;
+ bool unsupported = 0;
+
+ snd_azf3328_dbgmixer(
+ "snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
+ reg_ac97
+ );
+ if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
+ unsupported = 1;
+ else {
+ if (reg_azf & AZF_AC97_REG_REAL_IO_READ)
+ reg_val = snd_azf3328_mixer_inw(chip,
+ reg_azf & AZF_REG_MASK);
+ else {
+ /*
+ * Proceed with dummy I/O read,
+ * to ensure compatible timing where this may matter.
+ * (ALSA AC97 layer usually doesn't call I/O functions
+ * due to intelligent I/O caching anyway)
+ * Choose a mixer register that's thoroughly unrelated
+ * to common audio (try to minimize distortion).
+ */
+ snd_azf3328_mixer_inw(chip, IDX_MIXER_SOMETHING30H);
+ }
+
+ if (reg_azf & AZF_AC97_REG_EMU_IO_READ) {
+ switch (reg_ac97) {
+ case AC97_RESET:
+ reg_val |= azf_emulated_ac97_caps;
+ break;
+ case AC97_POWERDOWN:
+ reg_val |= azf_emulated_ac97_powerdown;
+ break;
+ case AC97_EXTENDED_ID:
+ case AC97_EXTENDED_STATUS:
+ /* AFAICS we simply can't support anything: */
+ reg_val |= 0;
+ break;
+ case AC97_VENDOR_ID1:
+ reg_val = azf_emulated_ac97_vendor_id >> 16;
+ break;
+ case AC97_VENDOR_ID2:
+ reg_val = azf_emulated_ac97_vendor_id & 0xffff;
+ break;
+ default:
+ unsupported = 1;
+ break;
+ }
+ }
+ }
+ if (unsupported)
+ snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "read");
+
+ return reg_val;
+}
+
+static void
+snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
+ unsigned short reg_ac97, unsigned short val)
+{
+ const struct snd_azf3328 *chip = ac97->private_data;
+ unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
+ bool unsupported = 0;
+
+ snd_azf3328_dbgmixer(
+ "snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n",
+ reg_ac97, val
+ );
+ if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
+ unsupported = 1;
+ else {
+ if (reg_azf & AZF_AC97_REG_REAL_IO_WRITE)
+ snd_azf3328_mixer_outw(
+ chip,
+ reg_azf & AZF_REG_MASK,
+ val
+ );
+ else
+ if (reg_azf & AZF_AC97_REG_EMU_IO_WRITE) {
+ switch (reg_ac97) {
+ case AC97_REC_GAIN_MIC:
+ case AC97_POWERDOWN:
+ case AC97_EXTENDED_STATUS:
+ /*
+ * Silently swallow these writes.
+ * Since for most registers our card doesn't
+ * actually support a comparable feature,
+ * this is exactly what we should do here.
+ * The AC97 layer's I/O caching probably
+ * automatically takes care of all the rest...
+ * (remembers written values etc.)
+ */
+ break;
+ default:
+ unsupported = 1;
+ break;
+ }
+ }
+ }
+ if (unsupported)
+ snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write");
+}
+
+static int __devinit
+snd_azf3328_mixer_new(struct snd_azf3328 *chip)
+{
+ struct snd_ac97_bus *bus;
+ struct snd_ac97_template ac97;
+ static struct snd_ac97_bus_ops ops = {
+ .write = snd_azf3328_mixer_ac97_write,
+ .read = snd_azf3328_mixer_ac97_read,
+ };
+ int rc;
+
+ memset(&ac97, 0, sizeof(ac97));
+ ac97.scaps = AC97_SCAP_SKIP_MODEM
+ | AC97_SCAP_AUDIO /* we support audio! */
+ | AC97_SCAP_NO_SPDIF;
+ ac97.private_data = chip;
+ ac97.pci = chip->pci;
+
+ /*
+ * ALSA's AC97 layer has terrible init crackling issues,
+ * unfortunately, and since it makes use of AC97_RESET,
+ * there's no use trying to mute Master Playback proactively.
+ */
+
+ rc = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus);
+ if (!rc)
+ rc = snd_ac97_mixer(bus, &ac97, &chip->ac97);
+ /*
+ * Make sure to complain loudly in case of AC97 init failure,
+ * since failure may happen quite often,
+ * due to this card being a very quirky AC97 "lookalike".
+ */
+ if (rc)
+ printk(KERN_ERR "azt3328: AC97 init failed, err %d!\n", rc);
+
+ /* If we return an error here, then snd_card_free() should
+ * free up any ac97 codecs that got created, as well as the bus.
+ */
+ return rc;
+}
+#else /* AZF_USE_AC97_LAYER */
static void
snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip,
unsigned reg,
@@ -945,6 +1282,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip)
snd_azf3328_dbgcallleave();
return 0;
}
+#endif /* AZF_USE_AC97_LAYER */
static int
snd_azf3328_hw_params(struct snd_pcm_substream *substream,
@@ -1233,8 +1571,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
previously_muted =
- snd_azf3328_mixer_set_mute(
- chip, IDX_MIXER_WAVEOUT, 1
+ snd_azf3328_mixer_mute_control_pcm(
+ chip, 1
);
}
@@ -1290,8 +1628,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (is_main_mixer_playback_codec) {
/* now unmute WaveOut */
if (!previously_muted)
- snd_azf3328_mixer_set_mute(
- chip, IDX_MIXER_WAVEOUT, 0
+ snd_azf3328_mixer_mute_control_pcm(
+ chip, 0
);
}
@@ -1315,8 +1653,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (is_main_mixer_playback_codec) {
/* mute WaveOut (avoid clicking during setup) */
previously_muted =
- snd_azf3328_mixer_set_mute(
- chip, IDX_MIXER_WAVEOUT, 1
+ snd_azf3328_mixer_mute_control_pcm(
+ chip, 1
);
}
@@ -1341,8 +1679,8 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (is_main_mixer_playback_codec) {
/* now unmute WaveOut */
if (!previously_muted)
- snd_azf3328_mixer_set_mute(
- chip, IDX_MIXER_WAVEOUT, 0
+ snd_azf3328_mixer_mute_control_pcm(
+ chip, 0
);
}
@@ -2050,11 +2388,7 @@ snd_azf3328_free(struct snd_azf3328 *chip)
if (chip->irq < 0)
goto __end_hw;
- /* reset (close) mixer:
- * first mute master volume, then reset
- */
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
- snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000);
+ snd_azf3328_mixer_reset(chip);
snd_azf3328_timer_stop(chip->timer);
snd_azf3328_gameport_free(chip);
@@ -2407,6 +2741,55 @@ snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
}
}
+static inline void
+snd_azf3328_resume_regs(const u32 *saved_regs,
+ unsigned long io_addr,
+ unsigned count
+)
+{
+ unsigned reg;
+
+ for (reg = 0; reg < count; ++reg) {
+ outl(*saved_regs, io_addr);
+ snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
+ io_addr, *saved_regs, inl(io_addr));
+ ++saved_regs;
+ io_addr += sizeof(*saved_regs);
+ }
+}
+
+static inline void
+snd_azf3328_suspend_ac97(struct snd_azf3328 *chip)
+{
+#ifdef AZF_USE_AC97_LAYER
+ snd_ac97_suspend(chip->ac97);
+#else
+ snd_azf3328_suspend_regs(chip->mixer_io,
+ ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
+
+ /* make sure to disable master volume etc. to prevent looping sound */
+ snd_azf3328_mixer_mute_control_master(chip, 1);
+ snd_azf3328_mixer_mute_control_pcm(chip, 1);
+#endif /* AZF_USE_AC97_LAYER */
+}
+
+static inline void
+snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
+{
+#ifdef AZF_USE_AC97_LAYER
+ snd_ac97_resume(chip->ac97);
+#else
+ snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
+ ARRAY_SIZE(chip->saved_regs_mixer));
+
+ /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
+ and IDX_MIXER_RESET (offset 0x00) get touched at the same time,
+ resulting in a mixer reset condition persisting until _after_
+ master vol was restored. Thus master vol needs an extra restore. */
+ outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2);
+#endif /* AZF_USE_AC97_LAYER */
+}
+
static int
snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
{
@@ -2420,12 +2803,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
- snd_azf3328_suspend_regs(chip->mixer_io,
- ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer);
-
- /* make sure to disable master volume etc. to prevent looping sound */
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1);
- snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1);
+ snd_azf3328_suspend_ac97(chip);
snd_azf3328_suspend_regs(chip->ctrl_io,
ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl);
@@ -2447,23 +2825,6 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
return 0;
}
-static inline void
-snd_azf3328_resume_regs(const u32 *saved_regs,
- unsigned long io_addr,
- unsigned count
-)
-{
- unsigned reg;
-
- for (reg = 0; reg < count; ++reg) {
- outl(*saved_regs, io_addr);
- snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n",
- io_addr, *saved_regs, inl(io_addr));
- ++saved_regs;
- io_addr += sizeof(*saved_regs);
- }
-}
-
static int
snd_azf3328_resume(struct pci_dev *pci)
{
@@ -2487,14 +2848,7 @@ snd_azf3328_resume(struct pci_dev *pci)
snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io,
ARRAY_SIZE(chip->saved_regs_opl3));
- snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io,
- ARRAY_SIZE(chip->saved_regs_mixer));
-
- /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02)
- and IDX_MIXER_RESET (offset 0x00) get touched at the same time,
- resulting in a mixer reset condition persisting until _after_
- master vol was restored. Thus master vol needs an extra restore. */
- outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2);
+ snd_azf3328_resume_ac97(chip);
snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io,
ARRAY_SIZE(chip->saved_regs_ctrl));
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 1bff80cde0a2..b9321544c31c 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -869,7 +869,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
mutex_lock(&atc->atc_mutex);
dao->ops->get_spos(dao, &status);
if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
- status &= ((~IEC958_AES3_CON_FS) << 24);
+ status &= ~(IEC958_AES3_CON_FS << 24);
status |= (iec958_con_fs << 24);
dao->ops->set_spos(dao, status);
dao->ops->commit_write(dao);
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index af56eb949bde..47d9ea97de02 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -176,6 +176,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input)
if (!entry)
return -ENOMEM;
+ dao->ops->clear_left_input(dao);
/* Program master and conjugate resources */
input->ops->master(input);
daio->rscl.ops->master(&daio->rscl);
@@ -204,6 +205,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input)
if (!entry)
return -ENOMEM;
+ dao->ops->clear_right_input(dao);
/* Program master and conjugate resources */
input->ops->master(input);
daio->rscr.ops->master(&daio->rscr);
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index b6b11bfe7574..5364164674e4 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1307,10 +1307,10 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
set_field(&pllctl, PLLCTL_B, 0);
if (48000 == rsr) {
set_field(&pllctl, PLLCTL_FD, 16 - 2);
- set_field(&pllctl, PLLCTL_RD, 1 - 1);
+ set_field(&pllctl, PLLCTL_RD, 1 - 1); /* 3000*16/1 = 48000 */
} else { /* 44100 */
set_field(&pllctl, PLLCTL_FD, 147 - 2);
- set_field(&pllctl, PLLCTL_RD, 10 - 1);
+ set_field(&pllctl, PLLCTL_RD, 10 - 1); /* 3000*147/10 = 44100 */
}
hw_write_20kx(hw, PLL_CTL, pllctl);
mdelay(40);
@@ -1740,6 +1740,10 @@ static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
return data;
}
+#define MIC_BOOST_0DB 0xCF
+#define MIC_BOOST_STEPS_PER_DB 2
+#define MIC_BOOST_20DB (MIC_BOOST_0DB + 20 * MIC_BOOST_STEPS_PER_DB)
+
static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
{
u32 data;
@@ -1751,10 +1755,12 @@ static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
hw_write_20kx(hw, GPIO_DATA, data);
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
MAKE_WM8775_DATA(0x101)); /* Mic-in */
- hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
- MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
- hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
- MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+ hw20k2_i2c_write(hw,
+ MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
+ MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
+ hw20k2_i2c_write(hw,
+ MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
+ MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
break;
case ADC_LINEIN:
data &= ~(0x1 << 14);
@@ -1827,10 +1833,12 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101),
MAKE_WM8775_DATA(0x101)); /* Mic-in */
- hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7),
- MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
- hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7),
- MAKE_WM8775_DATA(0xE7)); /* +12dB boost */
+ hw20k2_i2c_write(hw,
+ MAKE_WM8775_ADDR(WM8775_AADCL, MIC_BOOST_20DB),
+ MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
+ hw20k2_i2c_write(hw,
+ MAKE_WM8775_ADDR(WM8775_AADCR, MIC_BOOST_20DB),
+ MAKE_WM8775_DATA(MIC_BOOST_20DB)); /* +20dB */
} else if (mux == 2) {
/* Configures GPIO data to select Line-in */
data &= ~(0x1 << 14);
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index 15c1e7271ea8..c3519ff42fbb 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -566,19 +566,6 @@ static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
return 0;
}
-static int ct_spdif_default_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF;
-
- ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
- ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
- ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
- ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
-
- return 0;
-}
-
static int ct_spdif_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -586,6 +573,10 @@ static int ct_spdif_get(struct snd_kcontrol *kcontrol,
unsigned int status;
atc->spdif_out_get_status(atc, &status);
+
+ if (status == 0)
+ status = SNDRV_PCM_DEFAULT_CON_SPDIF;
+
ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
@@ -629,7 +620,7 @@ static struct snd_kcontrol_new iec958_default_ctl = {
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
.count = 1,
.info = ct_spdif_info,
- .get = ct_spdif_default_get,
+ .get = ct_spdif_get,
.put = ct_spdif_put,
.private_value = MIXER_IEC958_DEFAULT
};
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c
index 65da6e466f80..b78f3fc3c33c 100644
--- a/sound/pci/ctxfi/ctvmem.c
+++ b/sound/pci/ctxfi/ctvmem.c
@@ -52,8 +52,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
if (entry->size == size) {
/* Move the vm node from unused list to used list directly */
- list_del(&entry->list);
- list_add(&entry->list, &vm->used);
+ list_move(&entry->list, &vm->used);
vm->size -= size;
block = entry;
goto out;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 66c7fb3ced3e..5e619a84da06 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -926,7 +926,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19);
/* Unknown. */
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c);
- /* IRQ Enable: Alll on */
+ /* IRQ Enable: All on */
/* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */
/* IRQ Enable: All off */
snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ae5c5d5e4b7c..2c79e96d0324 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -29,6 +29,7 @@
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/initval.h>
+#include <sound/jack.h>
#include "hda_local.h"
#include "hda_beep.h"
#include <sound/hda_hwdep.h>
@@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
}
EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+/*
+ * Input-jack notification support
+ */
+struct hda_jack_item {
+ hda_nid_t nid;
+ int type;
+ struct snd_jack *jack;
+};
+
+static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
+ int type)
+{
+ switch (type) {
+ case SND_JACK_HEADPHONE:
+ return "Headphone";
+ case SND_JACK_MICROPHONE:
+ return "Mic";
+ case SND_JACK_LINEOUT:
+ return "Line-out";
+ case SND_JACK_HEADSET:
+ return "Headset";
+ default:
+ return "Misc";
+ }
+}
+
+static void hda_free_jack_priv(struct snd_jack *jack)
+{
+ struct hda_jack_item *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+
+int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
+ const char *name)
+{
+ struct hda_jack_item *jack;
+ int err;
+
+ snd_array_init(&codec->jacks, sizeof(*jack), 32);
+ jack = snd_array_new(&codec->jacks);
+ if (!jack)
+ return -ENOMEM;
+
+ jack->nid = nid;
+ jack->type = type;
+ if (!name)
+ name = get_jack_default_name(codec, nid, type);
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0) {
+ jack->nid = 0;
+ return err;
+ }
+ jack->jack->private_data = jack;
+ jack->jack->private_free = hda_free_jack_priv;
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);
+
+void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct hda_jack_item *jacks = codec->jacks.list;
+ int i;
+
+ if (!jacks)
+ return;
+
+ for (i = 0; i < codec->jacks.used; i++, jacks++) {
+ unsigned int pin_ctl;
+ unsigned int present;
+ int type;
+
+ if (jacks->nid != nid)
+ continue;
+ present = snd_hda_jack_detect(codec, nid);
+ type = jacks->type;
+ if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) {
+ pin_ctl = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ type = (pin_ctl & AC_PINCTL_HP_EN) ?
+ SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
+ }
+ snd_jack_report(jacks->jack, present ? type : 0);
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);
+
+/* free jack instances manually when clearing/reconfiguring */
+void snd_hda_input_jack_free(struct hda_codec *codec)
+{
+ if (!codec->bus->shutdown && codec->jacks.list) {
+ struct hda_jack_item *jacks = codec->jacks.list;
+ int i;
+ for (i = 0; i < codec->jacks.used; i++, jacks++) {
+ if (jacks->jack)
+ snd_device_free(codec->bus->card, jacks->jack);
+ }
+ }
+ snd_array_free(&codec->jacks);
+}
+EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
+
MODULE_DESCRIPTION("HDA codec core");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index fdf8d44f8b6b..e46d5420a9f2 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -866,6 +866,11 @@ struct hda_codec {
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);
+
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+ /* jack detection */
+ struct snd_array jacks;
+#endif
};
/* direction */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index fcedad9a5fef..70a9d32f0e96 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1052,9 +1052,12 @@ static void azx_init_pci(struct azx *chip)
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
* Ensuring these bits are 0 clears playback static on some HD Audio
- * codecs
+ * codecs.
+ * The PCI register TCSEL is defined in the Intel manuals.
*/
- update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
+ if (chip->driver_type != AZX_DRIVER_ATI &&
+ chip->driver_type != AZX_DRIVER_ATIHDMI)
+ update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0);
switch (chip->driver_type) {
case AZX_DRIVER_ATI:
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 3ab5e7a303db..ff5e2ac2239a 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);
+/*
+ * Input-jack notification support
+ */
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
+ const char *name);
+void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
+void snd_hda_input_jack_free(struct hda_codec *codec);
+#else /* CONFIG_SND_HDA_INPUT_JACK */
+static inline int snd_hda_input_jack_add(struct hda_codec *codec,
+ hda_nid_t nid, int type,
+ const char *name)
+{
+ return 0;
+}
+static inline void snd_hda_input_jack_report(struct hda_codec *codec,
+ hda_nid_t nid)
+{
+}
+static inline void snd_hda_input_jack_free(struct hda_codec *codec)
+{
+}
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
+
#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 8dabab798689..734c6ee55d8a 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -30,10 +30,10 @@
#include "hda_beep.h"
struct ad198x_spec {
- struct snd_kcontrol_new *mixers[5];
+ struct snd_kcontrol_new *mixers[6];
int num_mixers;
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
- const struct hda_verb *init_verbs[5]; /* initialization verbs
+ const struct hda_verb *init_verbs[6]; /* initialization verbs
* don't forget NULL termination!
*/
unsigned int num_init_verbs;
@@ -331,36 +331,11 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
-static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
-{
- struct ad198x_spec *spec = codec->spec;
- snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
- 0, format);
- return 0;
-}
-
-static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
-{
- struct ad198x_spec *spec = codec->spec;
- snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
- return 0;
-}
-
static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
.substreams = 1,
.channels_min = 2,
.channels_max = 2,
/* NID is set in ad198x_build_pcms */
- .ops = {
- .prepare = ad198x_alt_playback_pcm_prepare,
- .cleanup = ad198x_alt_playback_pcm_cleanup
- },
};
/*
@@ -2239,29 +2214,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
- HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
- HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
- HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
- HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
- HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
- HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
- HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-
{ } /* end */
};
@@ -2545,11 +2497,6 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
};
static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
- /* Front, Surround, CLFE, side DAC; unmute as default */
- {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Headphone; unmute as default */
{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* Port-A front headphon path */
@@ -2558,50 +2505,6 @@ static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
- /* Port-D line-out path */
- {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Port-F surround path */
- {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Port-G CLFE path */
- {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Port-H side path */
- {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
- {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- /* Mono out path */
- {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
- {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
- {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
- {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
- {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
- /* Port-B front mic-in path */
- {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- /* Port-C line-in path */
- {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* Port-E mic-in path */
- {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
- {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
- {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
- {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
- /* Analog CD Input */
- {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
- /* Analog Mix output amp */
- {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
{ }
};
@@ -3316,20 +3219,20 @@ static int patch_ad1988(struct hda_codec *codec)
spec->mixers[0] = ad1988_6stack_mixers1_rev2;
else
spec->mixers[0] = ad1988_6stack_mixers1;
+ spec->mixers[1] = ad1988_6stack_mixers2;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = ad1988_6stack_init_verbs;
if (board_config == AD1988_6STACK_DIG_FP) {
- spec->mixers[1] = ad1988_6stack_fp_mixers;
+ spec->num_mixers++;
+ spec->mixers[2] = ad1988_6stack_fp_mixers;
+ spec->num_init_verbs++;
+ spec->init_verbs[1] = ad1988_6stack_fp_init_verbs;
spec->slave_vols = ad1988_6stack_fp_slave_vols;
spec->slave_sws = ad1988_6stack_fp_slave_sws;
spec->alt_dac_nid = ad1988_alt_dac_nid;
spec->stream_analog_alt_playback =
&ad198x_pcm_analog_alt_playback;
- } else
- spec->mixers[1] = ad1988_6stack_mixers2;
- spec->num_init_verbs = 1;
- if (board_config == AD1988_6STACK_DIG_FP)
- spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
- else
- spec->init_verbs[0] = ad1988_6stack_init_verbs;
+ }
if ((board_config == AD1988_6STACK_DIG) ||
(board_config == AD1988_6STACK_DIG_FP)) {
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 4d5004e693f0..d08cf31596f3 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -49,14 +49,6 @@
#define AUTO_MIC_PORTB (1 << 1)
#define AUTO_MIC_PORTC (1 << 2)
-struct conexant_jack {
-
- hda_nid_t nid;
- int type;
- struct snd_jack *jack;
-
-};
-
struct pin_dac_pair {
hda_nid_t pin;
hda_nid_t dac;
@@ -111,9 +103,6 @@ struct conexant_spec {
unsigned int spdif_route;
- /* jack detection */
- struct snd_array jacks;
-
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct hda_input_mux private_imux;
@@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
&spec->cur_mux[adc_idx]);
}
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void conexant_free_jack_priv(struct snd_jack *jack)
-{
- struct conexant_jack *jacks = jack->private_data;
- jacks->nid = 0;
- jacks->jack = NULL;
-}
-
-static int conexant_add_jack(struct hda_codec *codec,
- hda_nid_t nid, int type)
-{
- struct conexant_spec *spec;
- struct conexant_jack *jack;
- const char *name;
- int i, err;
-
- spec = codec->spec;
- snd_array_init(&spec->jacks, sizeof(*jack), 32);
-
- jack = spec->jacks.list;
- for (i = 0; i < spec->jacks.used; i++, jack++)
- if (jack->nid == nid)
- return 0 ; /* already present */
-
- jack = snd_array_new(&spec->jacks);
- name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
-
- if (!jack)
- return -ENOMEM;
-
- jack->nid = nid;
- jack->type = type;
-
- err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
- if (err < 0)
- return err;
- jack->jack->private_data = jack;
- jack->jack->private_free = conexant_free_jack_priv;
- return 0;
-}
-
-static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
- struct conexant_spec *spec = codec->spec;
- struct conexant_jack *jacks = spec->jacks.list;
-
- if (jacks) {
- int i;
- for (i = 0; i < spec->jacks.used; i++) {
- if (jacks->nid == nid) {
- unsigned int present;
- present = snd_hda_jack_detect(codec, nid);
-
- present = (present) ? jacks->type : 0 ;
-
- snd_jack_report(jacks->jack,
- present);
- }
- jacks++;
- }
- }
-}
-
static int conexant_init_jacks(struct hda_codec *codec)
{
+#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
int i;
@@ -469,15 +396,15 @@ static int conexant_init_jacks(struct hda_codec *codec)
int err = 0;
switch (hv->param ^ AC_USRSP_EN) {
case CONEXANT_HP_EVENT:
- err = conexant_add_jack(codec, hv->nid,
- SND_JACK_HEADPHONE);
- conexant_report_jack(codec, hv->nid);
+ err = snd_hda_input_jack_add(codec, hv->nid,
+ SND_JACK_HEADPHONE, NULL);
+ snd_hda_input_jack_report(codec, hv->nid);
break;
case CXT5051_PORTC_EVENT:
case CONEXANT_MIC_EVENT:
- err = conexant_add_jack(codec, hv->nid,
- SND_JACK_MICROPHONE);
- conexant_report_jack(codec, hv->nid);
+ err = snd_hda_input_jack_add(codec, hv->nid,
+ SND_JACK_MICROPHONE, NULL);
+ snd_hda_input_jack_report(codec, hv->nid);
break;
}
if (err < 0)
@@ -485,19 +412,9 @@ static int conexant_init_jacks(struct hda_codec *codec)
++hv;
}
}
- return 0;
-
-}
-#else
-static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-}
-
-static inline int conexant_init_jacks(struct hda_codec *codec)
-{
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
-#endif
static int conexant_init(struct hda_codec *codec)
{
@@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
- struct conexant_spec *spec = codec->spec;
- if (spec->jacks.list) {
- struct conexant_jack *jacks = spec->jacks.list;
- int i;
- for (i = 0; i < spec->jacks.used; i++, jacks++) {
- if (jacks->jack)
- snd_device_free(codec->bus->card, jacks->jack);
- }
- snd_array_free(&spec->jacks);
- }
-#endif
+ snd_hda_input_jack_free(codec);
snd_hda_detach_beep_device(codec);
kfree(codec->spec);
}
@@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
cxt5051_portc_automic(codec);
break;
}
- conexant_report_jack(codec, nid);
+ snd_hda_input_jack_report(codec, nid);
}
static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
@@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | event);
-#ifdef CONFIG_SND_HDA_INPUT_JACK
- conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
- conexant_report_jack(codec, nid);
-#endif
+ snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
+ snd_hda_input_jack_report(codec, nid);
}
static struct hda_verb cxt5051_ideapad_init_verbs[] = {
@@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cx_auto_hp_automute(codec);
- conexant_report_jack(codec, nid);
+ snd_hda_input_jack_report(codec, nid);
break;
case CONEXANT_MIC_EVENT:
cx_auto_automic(codec);
- conexant_report_jack(codec, nid);
+ snd_hda_input_jack_report(codec, nid);
break;
}
}
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index ec0fa2dd0a27..251773e45f61 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -110,6 +110,12 @@ struct dp_audio_infoframe {
u8 LFEPBL01_LSV36_DM_INH7;
};
+union audio_infoframe {
+ struct hdmi_audio_infoframe hdmi;
+ struct dp_audio_infoframe dp;
+ u8 bytes[0];
+};
+
/*
* CEA speaker placement:
*
@@ -620,8 +626,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
int channels = substream->runtime->channels;
int ca;
int i;
- u8 ai[max(sizeof(struct hdmi_audio_infoframe),
- sizeof(struct dp_audio_infoframe))];
+ union audio_infoframe ai;
ca = hdmi_channel_allocation(codec, nid, channels);
@@ -633,11 +638,10 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
pin_nid = spec->pin[i];
- memset(ai, 0, sizeof(ai));
+ memset(&ai, 0, sizeof(ai));
if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
- struct hdmi_audio_infoframe *hdmi_ai;
+ struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
- hdmi_ai = (struct hdmi_audio_infoframe *)ai;
hdmi_ai->type = 0x84;
hdmi_ai->ver = 0x01;
hdmi_ai->len = 0x0a;
@@ -645,9 +649,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
} else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
- struct dp_audio_infoframe *dp_ai;
+ struct dp_audio_infoframe *dp_ai = &ai.dp;
- dp_ai = (struct dp_audio_infoframe *)ai;
dp_ai->type = 0x84;
dp_ai->len = 0x1b;
dp_ai->ver = 0x11 << 2;
@@ -664,7 +667,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
* sizeof(*dp_ai) to avoid partial match/update problems when
* the user switches between HDMI/DP monitors.
*/
- if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
+ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+ sizeof(ai))) {
snd_printdd("hdmi_setup_audio_infoframe: "
"cvt=%d pin=%d channels=%d\n",
nid, pin_nid,
@@ -672,7 +676,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
hdmi_setup_channel_mapping(codec, pin_nid, ca);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
- ai, sizeof(ai));
+ ai.bytes, sizeof(ai));
hdmi_start_infoframe_trans(codec, pin_nid);
}
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4261bb8eec1d..f1a03f223495 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -282,12 +282,6 @@ struct alc_mic_route {
unsigned char amix_idx;
};
-struct alc_jack {
- hda_nid_t nid;
- int type;
- struct snd_jack *jack;
-};
-
#define MUX_IDX_UNDEF ((unsigned char)-1)
struct alc_customize_define {
@@ -366,9 +360,6 @@ struct alc_spec {
/* PCM information */
struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
- /* jack detection */
- struct snd_array jacks;
-
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct alc_customize_define cdefine;
@@ -394,6 +385,7 @@ struct alc_spec {
/* other flags */
unsigned int no_analog :1; /* digital I/O only */
unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
+ unsigned int single_input_src:1;
int init_amp;
int codec_variant; /* flag for other variants */
@@ -1032,94 +1024,32 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
alc_fix_pll(codec);
}
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void alc_free_jack_priv(struct snd_jack *jack)
-{
- struct alc_jack *jacks = jack->private_data;
- jacks->nid = 0;
- jacks->jack = NULL;
-}
-
-static int alc_add_jack(struct hda_codec *codec,
- hda_nid_t nid, int type)
-{
- struct alc_spec *spec;
- struct alc_jack *jack;
- const char *name;
- int err;
-
- spec = codec->spec;
- snd_array_init(&spec->jacks, sizeof(*jack), 32);
- jack = snd_array_new(&spec->jacks);
- if (!jack)
- return -ENOMEM;
-
- jack->nid = nid;
- jack->type = type;
- name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
-
- err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
- if (err < 0)
- return err;
- jack->jack->private_data = jack;
- jack->jack->private_free = alc_free_jack_priv;
- return 0;
-}
-
-static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
- struct alc_spec *spec = codec->spec;
- struct alc_jack *jacks = spec->jacks.list;
-
- if (jacks) {
- int i;
- for (i = 0; i < spec->jacks.used; i++) {
- if (jacks->nid == nid) {
- unsigned int present;
- present = snd_hda_jack_detect(codec, nid);
-
- present = (present) ? jacks->type : 0;
-
- snd_jack_report(jacks->jack, present);
- }
- jacks++;
- }
- }
-}
-
static int alc_init_jacks(struct hda_codec *codec)
{
+#ifdef CONFIG_SND_HDA_INPUT_JACK
struct alc_spec *spec = codec->spec;
int err;
unsigned int hp_nid = spec->autocfg.hp_pins[0];
unsigned int mic_nid = spec->ext_mic.pin;
if (hp_nid) {
- err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+ err = snd_hda_input_jack_add(codec, hp_nid,
+ SND_JACK_HEADPHONE, NULL);
if (err < 0)
return err;
- alc_report_jack(codec, hp_nid);
+ snd_hda_input_jack_report(codec, hp_nid);
}
if (mic_nid) {
- err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+ err = snd_hda_input_jack_add(codec, mic_nid,
+ SND_JACK_MICROPHONE, NULL);
if (err < 0)
return err;
- alc_report_jack(codec, mic_nid);
+ snd_hda_input_jack_report(codec, mic_nid);
}
-
- return 0;
-}
-#else
-static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
-}
-
-static inline int alc_init_jacks(struct hda_codec *codec)
-{
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
-#endif
static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
{
@@ -1133,7 +1063,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
nid = spec->autocfg.hp_pins[i];
if (!nid)
break;
- alc_report_jack(codec, nid);
+ snd_hda_input_jack_report(codec, nid);
spec->jack_present |= snd_hda_jack_detect(codec, nid);
}
@@ -1240,7 +1170,7 @@ static void alc_mic_automute(struct hda_codec *codec)
AC_VERB_SET_CONNECT_SEL,
alive->mux_idx);
}
- alc_report_jack(codec, spec->ext_mic.pin);
+ snd_hda_input_jack_report(codec, spec->ext_mic.pin);
/* FIXME: analog mixer */
}
@@ -2292,13 +2222,13 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0,
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT),
- HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
- HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
@@ -2309,7 +2239,6 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
{ } /* end */
};
-
static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -3919,6 +3848,8 @@ static struct hda_amp_list alc880_lg_loopbacks[] = {
* Common callbacks
*/
+static void alc_init_special_input_src(struct hda_codec *codec);
+
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -3929,6 +3860,7 @@ static int alc_init(struct hda_codec *codec)
for (i = 0; i < spec->num_init_verbs; i++)
snd_hda_sequence_write(codec, spec->init_verbs[i]);
+ alc_init_special_input_src(codec);
if (spec->init_hook)
spec->init_hook(codec);
@@ -4284,6 +4216,7 @@ static void alc_free(struct hda_codec *codec)
return;
alc_shutup(codec);
+ snd_hda_input_jack_free(codec);
alc_free_kctls(codec);
kfree(spec);
snd_hda_detach_beep_device(codec);
@@ -4702,7 +4635,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
- SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
+ SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
@@ -5151,7 +5084,9 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
switch (cfg->line_out_type) {
case AUTO_PIN_SPEAKER_OUT:
- return "Speaker";
+ if (cfg->line_outs == 1)
+ return "Speaker";
+ break;
case AUTO_PIN_HP_OUT:
return "Headphone";
default:
@@ -5205,16 +5140,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
return err;
} else {
const char *name = pfx;
- if (!name)
+ int index = i;
+ if (!name) {
name = chname[i];
+ index = 0;
+ }
err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
- name, i,
+ name, index,
HDA_COMPOSE_AMP_VAL(nid, 3, 0,
HDA_OUTPUT));
if (err < 0)
return err;
err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
- name, i,
+ name, index,
HDA_COMPOSE_AMP_VAL(nid, 3, 2,
HDA_INPUT));
if (err < 0)
@@ -5585,6 +5523,7 @@ static void fixup_single_adc(struct hda_codec *codec)
spec->capsrc_nids += i;
spec->adc_nids += i;
spec->num_adc_nids = 1;
+ spec->single_input_src = 1;
}
}
@@ -5596,6 +5535,16 @@ static void fixup_dual_adc_switch(struct hda_codec *codec)
init_capsrc_for_pin(codec, spec->int_mic.pin);
}
+/* initialize some special cases for input sources */
+static void alc_init_special_input_src(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ if (spec->dual_adc_switch)
+ fixup_dual_adc_switch(codec);
+ else if (spec->single_input_src)
+ init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
+}
+
static void set_capture_mixer(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -5611,7 +5560,7 @@ static void set_capture_mixer(struct hda_codec *codec)
int mux = 0;
int num_adcs = spec->num_adc_nids;
if (spec->dual_adc_switch)
- fixup_dual_adc_switch(codec);
+ num_adcs = 1;
else if (spec->auto_mic)
fixup_automic_adc(codec);
else if (spec->input_mux) {
@@ -5620,8 +5569,6 @@ static void set_capture_mixer(struct hda_codec *codec)
else if (spec->input_mux->num_items == 1)
fixup_single_adc(codec);
}
- if (spec->dual_adc_switch)
- num_adcs = 1;
spec->cap_mixer = caps[mux][num_adcs - 1];
}
}
@@ -10748,6 +10695,7 @@ static struct alc_config_preset alc882_presets[] = {
*/
enum {
PINFIX_ABIT_AW9D_MAX,
+ PINFIX_LENOVO_Y530,
PINFIX_PB_M5210,
PINFIX_ACER_ASPIRE_7736,
};
@@ -10762,6 +10710,14 @@ static const struct alc_fixup alc882_fixups[] = {
{ }
}
},
+ [PINFIX_LENOVO_Y530] = {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
+ { 0x15, 0x99130112 }, /* rear int speakers */
+ { 0x16, 0x99130111 }, /* subwoofer */
+ { }
+ }
+ },
[PINFIX_PB_M5210] = {
.type = ALC_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -10777,6 +10733,7 @@ static const struct alc_fixup alc882_fixups[] = {
static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
{}
@@ -10829,23 +10786,28 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
hda_nid_t pin, dac;
int i;
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
- pin = spec->autocfg.hp_pins[i];
- if (!pin)
- break;
- dac = spec->multiout.hp_nid;
- if (!dac)
- dac = spec->multiout.dac_nids[0]; /* to front */
- alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+ if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
+ for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+ pin = spec->autocfg.hp_pins[i];
+ if (!pin)
+ break;
+ dac = spec->multiout.hp_nid;
+ if (!dac)
+ dac = spec->multiout.dac_nids[0]; /* to front */
+ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+ }
}
- for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
- pin = spec->autocfg.speaker_pins[i];
- if (!pin)
- break;
- dac = spec->multiout.extra_out_nid[0];
- if (!dac)
- dac = spec->multiout.dac_nids[0]; /* to front */
- alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+
+ if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
+ for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+ pin = spec->autocfg.speaker_pins[i];
+ if (!pin)
+ break;
+ dac = spec->multiout.extra_out_nid[0];
+ if (!dac)
+ dac = spec->multiout.dac_nids[0]; /* to front */
+ alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+ }
}
}
@@ -13796,6 +13758,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
}
#define alc268_auto_init_analog_input alc882_auto_init_analog_input
+#define alc268_auto_init_input_src alc882_auto_init_input_src
/* init callback for auto-configuration model -- overriding the default init */
static void alc268_auto_init(struct hda_codec *codec)
@@ -13805,6 +13768,7 @@ static void alc268_auto_init(struct hda_codec *codec)
alc268_auto_init_hp_out(codec);
alc268_auto_init_mono_speaker_out(codec);
alc268_auto_init_analog_input(codec);
+ alc268_auto_init_input_src(codec);
alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
@@ -14092,7 +14056,6 @@ static int patch_alc268(struct hda_codec *codec)
if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
/* check whether NID 0x07 is valid */
unsigned int wcap = get_wcaps(codec, 0x07);
- int i;
spec->capsrc_nids = alc268_capsrc_nids;
/* get type */
@@ -14112,13 +14075,6 @@ static int patch_alc268(struct hda_codec *codec)
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
add_mixer(spec, alc268_capture_mixer);
}
- /* set default input source */
- for (i = 0; i < spec->num_adc_nids; i++)
- snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
- 0, AC_VERB_SET_CONNECT_SEL,
- i < spec->num_mux_defs ?
- spec->input_mux[i].items[0].index :
- spec->input_mux->items[0].index);
}
spec->vmaster_nid = 0x02;
@@ -14495,7 +14451,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
HDA_AMP_MUTE, bits);
snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
HDA_AMP_MUTE, bits);
- alc_report_jack(codec, nid);
+ snd_hda_input_jack_report(codec, nid);
}
/* unsolicited event for HP jack sensing */
@@ -14807,11 +14763,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
fillup_priv_adc_nids(codec, alc269_adc_candidates,
sizeof(alc269_adc_candidates));
- /* set default input source */
- if (!spec->dual_adc_switch)
- select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
- spec->input_mux->items[0].index);
-
err = alc_auto_add_mic_boost(codec);
if (err < 0)
return err;
@@ -14825,6 +14776,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
#define alc269_auto_init_multi_out alc268_auto_init_multi_out
#define alc269_auto_init_hp_out alc268_auto_init_hp_out
#define alc269_auto_init_analog_input alc882_auto_init_analog_input
+#define alc269_auto_init_input_src alc882_auto_init_input_src
/* init callback for auto-configuration model -- overriding the default init */
@@ -14834,6 +14786,8 @@ static void alc269_auto_init(struct hda_codec *codec)
alc269_auto_init_multi_out(codec);
alc269_auto_init_hp_out(codec);
alc269_auto_init_analog_input(codec);
+ if (!spec->dual_adc_switch)
+ alc269_auto_init_input_src(codec);
alc_auto_init_digital(codec);
if (spec->unsol_event)
alc_inithook(codec);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index bd7b123f6440..05fcd60cc46f 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -180,18 +180,16 @@ struct sigmatel_event {
int data;
};
-struct sigmatel_jack {
- hda_nid_t nid;
- int type;
- struct snd_jack *jack;
-};
-
struct sigmatel_mic_route {
hda_nid_t pin;
signed char mux_idx;
signed char dmux_idx;
};
+#define MAX_PINS_NUM 16
+#define MAX_ADCS_NUM 4
+#define MAX_DMICS_NUM 4
+
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
@@ -229,9 +227,6 @@ struct sigmatel_spec {
hda_nid_t *pwr_nids;
hda_nid_t *dac_list;
- /* jack detection */
- struct snd_array jacks;
-
/* events */
struct snd_array events;
@@ -309,6 +304,17 @@ struct sigmatel_spec {
struct hda_input_mux private_imux;
struct hda_input_mux private_smux;
struct hda_input_mux private_mono_mux;
+
+ /* auto spec */
+ unsigned auto_pin_cnt;
+ hda_nid_t auto_pin_nids[MAX_PINS_NUM];
+ unsigned auto_adc_cnt;
+ hda_nid_t auto_adc_nids[MAX_ADCS_NUM];
+ hda_nid_t auto_mux_nids[MAX_ADCS_NUM];
+ hda_nid_t auto_dmux_nids[MAX_ADCS_NUM];
+ unsigned long auto_capvols[MAX_ADCS_NUM];
+ unsigned auto_dmic_cnt;
+ hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
};
static hda_nid_t stac9200_adc_nids[1] = {
@@ -364,14 +370,6 @@ static unsigned long stac92hd73xx_capvols[] = {
#define STAC92HD83_DAC_COUNT 3
-static hda_nid_t stac92hd83xxx_mux_nids[2] = {
- 0x17, 0x18,
-};
-
-static hda_nid_t stac92hd83xxx_adc_nids[2] = {
- 0x15, 0x16,
-};
-
static hda_nid_t stac92hd83xxx_pwr_nids[4] = {
0xa, 0xb, 0xd, 0xe,
};
@@ -384,25 +382,9 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
0x03, 0x0c, 0x20, 0x40,
};
-#define STAC92HD83XXX_NUM_DMICS 2
-static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
- 0x11, 0x20, 0
-};
-
-#define STAC92HD88XXX_NUM_DMICS STAC92HD83XXX_NUM_DMICS
-#define stac92hd88xxx_dmic_nids stac92hd83xxx_dmic_nids
-
-#define STAC92HD87B_NUM_DMICS 1
-static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
- 0x11, 0
-};
-
-#define STAC92HD83XXX_NUM_CAPS 2
-static unsigned long stac92hd83xxx_capvols[] = {
- HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
- HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_OUTPUT),
+static hda_nid_t stac92hd83xxx_dmic_nids[] = {
+ 0x11, 0x20,
};
-#define stac92hd83xxx_capsws stac92hd83xxx_capvols
static hda_nid_t stac92hd71bxx_pwr_nids[3] = {
0x0a, 0x0d, 0x0f
@@ -581,21 +563,6 @@ static hda_nid_t stac92hd73xx_pin_nids[13] = {
0x14, 0x22, 0x23
};
-static hda_nid_t stac92hd83xxx_pin_nids[10] = {
- 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x1f, 0x20,
-};
-
-static hda_nid_t stac92hd87xxx_pin_nids[6] = {
- 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0f, 0x11,
-};
-
-static hda_nid_t stac92hd88xxx_pin_nids[8] = {
- 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0f, 0x11, 0x1f, 0x20,
-};
-
#define STAC92HD71BXX_NUM_PINS 13
static hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x00,
@@ -757,7 +724,7 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
struct sigmatel_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
const struct hda_input_mux *imux = spec->input_mux;
- unsigned int idx, prev_idx;
+ unsigned int idx, prev_idx, didx;
idx = ucontrol->value.enumerated.item[0];
if (idx >= imux->num_items)
@@ -769,7 +736,8 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0,
AC_VERB_SET_CONNECT_SEL,
imux->items[idx].index);
- if (prev_idx >= spec->num_analog_muxes) {
+ if (prev_idx >= spec->num_analog_muxes &&
+ spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) {
imux = spec->dinput_mux;
/* 0 = analog */
snd_hda_codec_write_cache(codec,
@@ -779,9 +747,13 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
}
} else {
imux = spec->dinput_mux;
+ /* first dimux item is hardcoded to select analog imux,
+ * so lets skip it
+ */
+ didx = idx - spec->num_analog_muxes + 1;
snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0,
AC_VERB_SET_CONNECT_SEL,
- imux->items[idx - 1].index);
+ imux->items[didx].index);
}
spec->cur_mux[adc_idx] = idx;
return 1;
@@ -3419,6 +3391,17 @@ static const char * const stac92xx_dmic_labels[5] = {
"Digital Mic 3", "Digital Mic 4"
};
+static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux,
+ int idx)
+{
+ hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+ int nums;
+ nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+ if (idx >= 0 && idx < nums)
+ return conn[idx];
+ return 0;
+}
+
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid)
{
@@ -3429,6 +3412,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
for (i = 0; i < nums; i++)
if (conn[i] == nid)
return i;
+
+ for (i = 0; i < nums; i++) {
+ unsigned int wid_caps = get_wcaps(codec, conn[i]);
+ unsigned int wid_type = get_wcaps_type(wid_caps);
+
+ if (wid_type != AC_WID_PIN && wid_type != AC_WID_AUD_MIX)
+ if (get_connection_index(codec, conn[i], nid) >= 0)
+ return i;
+ }
return -1;
}
@@ -3501,6 +3493,16 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
type_idx, HDA_OUTPUT);
if (err < 0)
return err;
+ if (!err) {
+ nid = get_connected_node(codec,
+ spec->dmux_nids[0], index);
+ if (nid)
+ err = create_elem_capture_vol(codec,
+ nid, label,
+ type_idx, HDA_INPUT);
+ if (err < 0)
+ return err;
+ }
}
}
@@ -4054,21 +4056,10 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-static void stac92xx_free_jack_priv(struct snd_jack *jack)
-{
- struct sigmatel_jack *jacks = jack->private_data;
- jacks->nid = 0;
- jacks->jack = NULL;
-}
-#endif
-
static int stac92xx_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
- struct sigmatel_spec *spec = codec->spec;
- struct sigmatel_jack *jack;
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf);
char name[32];
@@ -4077,26 +4068,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0;
- snd_array_init(&spec->jacks, sizeof(*jack), 32);
- jack = snd_array_new(&spec->jacks);
- if (!jack)
- return -ENOMEM;
- jack->nid = nid;
- jack->type = type;
-
snprintf(name, sizeof(name), "%s at %s %s Jack",
snd_hda_get_jack_type(def_conf),
snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf));
- err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
- if (err < 0) {
- jack->nid = 0;
+ err = snd_hda_input_jack_add(codec, nid, type, name);
+ if (err < 0)
return err;
- }
- jack->jack->private_data = jack;
- jack->jack->private_free = stac92xx_free_jack_priv;
-#endif
+#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
@@ -4399,23 +4379,6 @@ static int stac92xx_init(struct hda_codec *codec)
return 0;
}
-static void stac92xx_free_jacks(struct hda_codec *codec)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
- /* free jack instances manually when clearing/reconfiguring */
- struct sigmatel_spec *spec = codec->spec;
- if (!codec->bus->shutdown && spec->jacks.list) {
- struct sigmatel_jack *jacks = spec->jacks.list;
- int i;
- for (i = 0; i < spec->jacks.used; i++, jacks++) {
- if (jacks->jack)
- snd_device_free(codec->bus->card, jacks->jack);
- }
- }
- snd_array_free(&spec->jacks);
-#endif
-}
-
static void stac92xx_free_kctls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -4449,7 +4412,7 @@ static void stac92xx_free(struct hda_codec *codec)
return;
stac92xx_shutup(codec);
- stac92xx_free_jacks(codec);
+ snd_hda_input_jack_free(codec);
snd_array_free(&spec->events);
kfree(spec);
@@ -4667,33 +4630,6 @@ static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid));
}
-static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
-{
- struct sigmatel_spec *spec = codec->spec;
- struct sigmatel_jack *jacks = spec->jacks.list;
-
- if (jacks) {
- int i;
- for (i = 0; i < spec->jacks.used; i++) {
- if (jacks->nid == nid) {
- unsigned int pin_ctl =
- snd_hda_codec_read(codec, nid,
- 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0x00);
- int type = jacks->type;
- if (type == (SND_JACK_LINEOUT
- | SND_JACK_HEADPHONE))
- type = (pin_ctl & AC_PINCTL_HP_EN)
- ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
- snd_jack_report(jacks->jack,
- get_pin_presence(codec, nid)
- ? type : 0);
- }
- jacks++;
- }
- }
-}
-
/* get the pin connection (fixed, none, etc) */
static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
{
@@ -4782,7 +4718,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
case STAC_PWR_EVENT:
if (spec->num_pwrs > 0)
stac92xx_pin_sense(codec, event->nid);
- stac92xx_report_jack(codec, event->nid);
+ snd_hda_input_jack_report(codec, event->nid);
switch (codec->subsystem_id) {
case 0x103c308f:
@@ -5378,6 +5314,105 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec)
return 0;
}
+static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ int i;
+
+ spec->auto_pin_nids[spec->auto_pin_cnt] = nid;
+ spec->auto_pin_cnt++;
+
+ if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+ get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) {
+ for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) {
+ if (nid == stac92hd83xxx_dmic_nids[i]) {
+ spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid;
+ spec->auto_dmic_cnt++;
+ }
+ }
+ }
+}
+
+static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ spec->auto_adc_nids[spec->auto_adc_cnt] = nid;
+ spec->auto_adc_cnt++;
+}
+
+static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid)
+{
+ int i, j;
+ struct sigmatel_spec *spec = codec->spec;
+
+ for (i = 0; i < spec->auto_adc_cnt; i++) {
+ if (get_connection_index(codec,
+ spec->auto_adc_nids[i], nid) >= 0) {
+ /* mux and volume for adc_nids[i] */
+ if (!spec->auto_mux_nids[i]) {
+ spec->auto_mux_nids[i] = nid;
+ /* 92hd codecs capture volume is in mux */
+ spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid,
+ 3, 0, HDA_OUTPUT);
+ }
+ for (j = 0; j < spec->auto_dmic_cnt; j++) {
+ if (get_connection_index(codec, nid,
+ spec->auto_dmic_nids[j]) >= 0) {
+ /* dmux for adc_nids[i] */
+ if (!spec->auto_dmux_nids[i])
+ spec->auto_dmux_nids[i] = nid;
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void stac92hd8x_fill_auto_spec(struct hda_codec *codec)
+{
+ hda_nid_t nid, end_nid;
+ unsigned int wid_caps, wid_type;
+ struct sigmatel_spec *spec = codec->spec;
+
+ end_nid = codec->start_nid + codec->num_nodes;
+
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ wid_caps = get_wcaps(codec, nid);
+ wid_type = get_wcaps_type(wid_caps);
+
+ if (wid_type == AC_WID_PIN)
+ stac92hd8x_add_pin(codec, nid);
+
+ if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL))
+ stac92hd8x_add_adc(codec, nid);
+ }
+
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ wid_caps = get_wcaps(codec, nid);
+ wid_type = get_wcaps_type(wid_caps);
+
+ if (wid_type == AC_WID_AUD_SEL)
+ stac92hd8x_add_mux(codec, nid);
+ }
+
+ spec->pin_nids = spec->auto_pin_nids;
+ spec->num_pins = spec->auto_pin_cnt;
+ spec->adc_nids = spec->auto_adc_nids;
+ spec->num_adcs = spec->auto_adc_cnt;
+ spec->capvols = spec->auto_capvols;
+ spec->capsws = spec->auto_capvols;
+ spec->num_caps = spec->auto_adc_cnt;
+ spec->mux_nids = spec->auto_mux_nids;
+ spec->num_muxes = spec->auto_adc_cnt;
+ spec->dmux_nids = spec->auto_dmux_nids;
+ spec->num_dmuxes = spec->auto_adc_cnt;
+ spec->dmic_nids = spec->auto_dmic_nids;
+ spec->num_dmics = spec->auto_dmic_cnt;
+}
+
static int patch_stac92hd83xxx(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -5399,26 +5434,17 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
codec->no_trigger_sense = 1;
codec->spec = spec;
+
+ stac92hd8x_fill_auto_spec(codec);
+
spec->linear_tone_beep = 0;
codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
spec->digbeep_nid = 0x21;
- spec->dmic_nids = stac92hd83xxx_dmic_nids;
- spec->dmux_nids = stac92hd83xxx_mux_nids;
- spec->mux_nids = stac92hd83xxx_mux_nids;
- spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
- spec->adc_nids = stac92hd83xxx_adc_nids;
- spec->num_adcs = ARRAY_SIZE(stac92hd83xxx_adc_nids);
spec->pwr_nids = stac92hd83xxx_pwr_nids;
spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
spec->multiout.dac_nids = spec->dac_nids;
-
spec->init = stac92hd83xxx_core_init;
- spec->num_pins = ARRAY_SIZE(stac92hd83xxx_pin_nids);
- spec->pin_nids = stac92hd83xxx_pin_nids;
- spec->num_caps = STAC92HD83XXX_NUM_CAPS;
- spec->capvols = stac92hd83xxx_capvols;
- spec->capsws = stac92hd83xxx_capsws;
spec->board_config = snd_hda_check_board_config(codec,
STAC_92HD83XXX_MODELS,
@@ -5436,28 +5462,11 @@ again:
case 0x111d76d1:
case 0x111d76d9:
case 0x111d76e5:
- spec->dmic_nids = stac92hd87b_dmic_nids;
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd87b_dmic_nids,
- STAC92HD87B_NUM_DMICS);
- spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids);
- spec->pin_nids = stac92hd87xxx_pin_nids;
- spec->mono_nid = 0;
- spec->num_pwrs = 0;
- break;
case 0x111d7666:
case 0x111d7667:
case 0x111d7668:
case 0x111d7669:
case 0x111d76e3:
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd88xxx_dmic_nids,
- STAC92HD88XXX_NUM_DMICS);
- spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
- spec->pin_nids = stac92hd88xxx_pin_nids;
- spec->mono_nid = 0;
- spec->num_pwrs = 0;
- break;
case 0x111d7604:
case 0x111d76d4:
case 0x111d7605:
@@ -5466,9 +5475,6 @@ again:
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
break;
spec->num_pwrs = 0;
- spec->num_dmics = stac92xx_connected_ports(codec,
- stac92hd83xxx_dmic_nids,
- STAC92HD83XXX_NUM_DMICS);
break;
}
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 13cec1e5ced9..2ae8d29500a8 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -341,9 +341,9 @@ static int snd_intel8x0m_codec_semaphore(struct intel8x0m *chip, unsigned int co
return -EBUSY;
}
-static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,
- unsigned short reg,
- unsigned short val)
+static void snd_intel8x0m_codec_write(struct snd_ac97 *ac97,
+ unsigned short reg,
+ unsigned short val)
{
struct intel8x0m *chip = ac97->private_data;
@@ -354,8 +354,8 @@ static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,
iaputword(chip, reg + ac97->num * 0x80, val);
}
-static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
- unsigned short reg)
+static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
+ unsigned short reg)
{
struct intel8x0m *chip = ac97->private_data;
unsigned short res;
@@ -385,7 +385,7 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
/*
* DMA I/O
*/
-static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ichdev)
+static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *ichdev)
{
int idx;
u32 *bdbar = ichdev->bdbar;
@@ -437,7 +437,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0m *chip, struct ichdev *ic
* Interrupt handler
*/
-static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ichdev)
+static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *ichdev)
{
unsigned long port = ichdev->reg_offset;
int civ, i, step;
@@ -489,7 +489,7 @@ static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ic
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}
-static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
+static irqreturn_t snd_intel8x0m_interrupt(int irq, void *dev_id)
{
struct intel8x0m *chip = dev_id;
struct ichdev *ichdev;
@@ -512,7 +512,7 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
for (i = 0; i < chip->bdbars_count; i++) {
ichdev = &chip->ichd[i];
if (status & ichdev->int_sta_mask)
- snd_intel8x0_update(chip, ichdev);
+ snd_intel8x0m_update(chip, ichdev);
}
/* ack them */
@@ -526,7 +526,7 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
* PCM part
*/
-static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+static int snd_intel8x0m_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct intel8x0m *chip = snd_pcm_substream_chip(substream);
struct ichdev *ichdev = get_ichdev(substream);
@@ -561,18 +561,18 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
return 0;
}
-static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
+static int snd_intel8x0m_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
-static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
+static int snd_intel8x0m_hw_free(struct snd_pcm_substream *substream)
{
return snd_pcm_lib_free_pages(substream);
}
-static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *substream)
+static snd_pcm_uframes_t snd_intel8x0m_pcm_pointer(struct snd_pcm_substream *substream)
{
struct intel8x0m *chip = snd_pcm_substream_chip(substream);
struct ichdev *ichdev = get_ichdev(substream);
@@ -600,7 +600,7 @@ static int snd_intel8x0m_pcm_prepare(struct snd_pcm_substream *substream)
ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
snd_ac97_write(ichdev->ac97, AC97_LINE1_RATE, runtime->rate);
snd_ac97_write(ichdev->ac97, AC97_LINE1_LEVEL, 0);
- snd_intel8x0_setup_periods(chip, ichdev);
+ snd_intel8x0m_setup_periods(chip, ichdev);
return 0;
}
@@ -682,22 +682,22 @@ static struct snd_pcm_ops snd_intel8x0m_playback_ops = {
.open = snd_intel8x0m_playback_open,
.close = snd_intel8x0m_playback_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_intel8x0_hw_params,
- .hw_free = snd_intel8x0_hw_free,
+ .hw_params = snd_intel8x0m_hw_params,
+ .hw_free = snd_intel8x0m_hw_free,
.prepare = snd_intel8x0m_pcm_prepare,
- .trigger = snd_intel8x0_pcm_trigger,
- .pointer = snd_intel8x0_pcm_pointer,
+ .trigger = snd_intel8x0m_pcm_trigger,
+ .pointer = snd_intel8x0m_pcm_pointer,
};
static struct snd_pcm_ops snd_intel8x0m_capture_ops = {
.open = snd_intel8x0m_capture_open,
.close = snd_intel8x0m_capture_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_intel8x0_hw_params,
- .hw_free = snd_intel8x0_hw_free,
+ .hw_params = snd_intel8x0m_hw_params,
+ .hw_free = snd_intel8x0m_hw_free,
.prepare = snd_intel8x0m_pcm_prepare,
- .trigger = snd_intel8x0_pcm_trigger,
- .pointer = snd_intel8x0_pcm_pointer,
+ .trigger = snd_intel8x0m_pcm_trigger,
+ .pointer = snd_intel8x0m_pcm_pointer,
};
@@ -710,7 +710,7 @@ struct ich_pcm_table {
int ac97_idx;
};
-static int __devinit snd_intel8x0_pcm1(struct intel8x0m *chip, int device,
+static int __devinit snd_intel8x0m_pcm1(struct intel8x0m *chip, int device,
struct ich_pcm_table *rec)
{
struct snd_pcm *pcm;
@@ -759,7 +759,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = {
},
};
-static int __devinit snd_intel8x0_pcm(struct intel8x0m *chip)
+static int __devinit snd_intel8x0m_pcm(struct intel8x0m *chip)
{
int i, tblsize, device, err;
struct ich_pcm_table *tbl, *rec;
@@ -791,7 +791,7 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0m *chip)
if (! chip->ichd[rec->ac97_idx].ac97)
continue;
}
- err = snd_intel8x0_pcm1(chip, device, rec);
+ err = snd_intel8x0m_pcm1(chip, device, rec);
if (err < 0)
return err;
device++;
@@ -806,20 +806,20 @@ static int __devinit snd_intel8x0_pcm(struct intel8x0m *chip)
* Mixer part
*/
-static void snd_intel8x0_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
+static void snd_intel8x0m_mixer_free_ac97_bus(struct snd_ac97_bus *bus)
{
struct intel8x0m *chip = bus->private_data;
chip->ac97_bus = NULL;
}
-static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97)
+static void snd_intel8x0m_mixer_free_ac97(struct snd_ac97 *ac97)
{
struct intel8x0m *chip = ac97->private_data;
chip->ac97 = NULL;
}
-static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock)
+static int __devinit snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock)
{
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
@@ -827,22 +827,22 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0m *chip, int ac97_clock)
int err;
unsigned int glob_sta = 0;
static struct snd_ac97_bus_ops ops = {
- .write = snd_intel8x0_codec_write,
- .read = snd_intel8x0_codec_read,
+ .write = snd_intel8x0m_codec_write,
+ .read = snd_intel8x0m_codec_read,
};
chip->in_ac97_init = 1;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
- ac97.private_free = snd_intel8x0_mixer_free_ac97;
+ ac97.private_free = snd_intel8x0m_mixer_free_ac97;
ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
glob_sta = igetdword(chip, ICHREG(GLOB_STA));
if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0)
goto __err;
- pbus->private_free = snd_intel8x0_mixer_free_ac97_bus;
+ pbus->private_free = snd_intel8x0m_mixer_free_ac97_bus;
if (ac97_clock >= 8000 && ac97_clock <= 48000)
pbus->clock = ac97_clock;
chip->ac97_bus = pbus;
@@ -894,7 +894,8 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
/* finish cold or do warm reset */
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
iputdword(chip, ICHREG(GLOB_CNT), cnt);
- end_time = (jiffies + (HZ / 4)) + 1;
+ usleep_range(500, 1000); /* give warm reset some time */
+ end_time = jiffies + HZ / 4;
do {
if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
goto __ok;
@@ -959,7 +960,7 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing)
return 0;
}
-static int snd_intel8x0_chip_init(struct intel8x0m *chip, int probing)
+static int snd_intel8x0m_chip_init(struct intel8x0m *chip, int probing)
{
unsigned int i;
int err;
@@ -980,7 +981,7 @@ static int snd_intel8x0_chip_init(struct intel8x0m *chip, int probing)
return 0;
}
-static int snd_intel8x0_free(struct intel8x0m *chip)
+static int snd_intel8x0m_free(struct intel8x0m *chip)
{
unsigned int i;
@@ -1045,7 +1046,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
return -EIO;
}
pci_set_master(pci);
- if (request_irq(pci->irq, snd_intel8x0_interrupt,
+ if (request_irq(pci->irq, snd_intel8x0m_interrupt,
IRQF_SHARED, card->shortname, chip)) {
printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, "
"disabling device\n", pci->irq);
@@ -1053,7 +1054,7 @@ static int intel8x0m_resume(struct pci_dev *pci)
return -EIO;
}
chip->irq = pci->irq;
- snd_intel8x0_chip_init(chip, 0);
+ snd_intel8x0m_chip_init(chip, 0);
snd_ac97_resume(chip->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -1094,10 +1095,10 @@ static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip)
#endif /* CONFIG_PROC_FS */
-static int snd_intel8x0_dev_free(struct snd_device *device)
+static int snd_intel8x0m_dev_free(struct snd_device *device)
{
struct intel8x0m *chip = device->device_data;
- return snd_intel8x0_free(chip);
+ return snd_intel8x0m_free(chip);
}
struct ich_reg_info {
@@ -1108,7 +1109,7 @@ struct ich_reg_info {
static int __devinit snd_intel8x0m_create(struct snd_card *card,
struct pci_dev *pci,
unsigned long device_type,
- struct intel8x0m ** r_intel8x0)
+ struct intel8x0m **r_intel8x0m)
{
struct intel8x0m *chip;
int err;
@@ -1116,7 +1117,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
unsigned int int_sta_masks;
struct ichdev *ichdev;
static struct snd_device_ops ops = {
- .dev_free = snd_intel8x0_dev_free,
+ .dev_free = snd_intel8x0m_dev_free,
};
static struct ich_reg_info intel_regs[2] = {
{ ICH_MIINT, 0 },
@@ -1124,7 +1125,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
};
struct ich_reg_info *tbl;
- *r_intel8x0 = NULL;
+ *r_intel8x0m = NULL;
if ((err = pci_enable_device(pci)) < 0)
return err;
@@ -1158,7 +1159,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
chip->addr = pci_iomap(pci, 0, 0);
if (!chip->addr) {
snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
- snd_intel8x0_free(chip);
+ snd_intel8x0m_free(chip);
return -EIO;
}
if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */
@@ -1167,15 +1168,15 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
chip->bmaddr = pci_iomap(pci, 1, 0);
if (!chip->bmaddr) {
snd_printk(KERN_ERR "Controller space ioremap problem\n");
- snd_intel8x0_free(chip);
+ snd_intel8x0m_free(chip);
return -EIO;
}
port_inited:
- if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED,
+ if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
card->shortname, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
- snd_intel8x0_free(chip);
+ snd_intel8x0m_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
@@ -1210,7 +1211,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
&chip->bdbars) < 0) {
- snd_intel8x0_free(chip);
+ snd_intel8x0m_free(chip);
return -ENOMEM;
}
/* tables must be aligned to 8 bytes here, but the kernel pages
@@ -1225,19 +1226,19 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card,
chip->int_sta_reg = ICH_REG_GLOB_STA;
chip->int_sta_mask = int_sta_masks;
- if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) {
- snd_intel8x0_free(chip);
+ if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
+ snd_intel8x0m_free(chip);
return err;
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- snd_intel8x0_free(chip);
+ snd_intel8x0m_free(chip);
return err;
}
snd_card_set_dev(card, &pci->dev);
- *r_intel8x0 = chip;
+ *r_intel8x0m = chip;
return 0;
}
@@ -1295,11 +1296,11 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
}
card->private_data = chip;
- if ((err = snd_intel8x0_mixer(chip, ac97_clock)) < 0) {
+ if ((err = snd_intel8x0m_mixer(chip, ac97_clock)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_intel8x0_pcm(chip)) < 0) {
+ if ((err = snd_intel8x0m_pcm(chip)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index f5eadfc0672a..a323eafb9e03 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -8,6 +8,21 @@
* Modified 2006-06-01 for AES32 support by Remy Bruno
* <remy.bruno@trinnov.com>
*
+ * Modified 2009-04-13 for proper metering by Florian Faber
+ * <faber@faberman.de>
+ *
+ * Modified 2009-04-14 for native float support by Florian Faber
+ * <faber@faberman.de>
+ *
+ * Modified 2009-04-26 fixed bug in rms metering by Florian Faber
+ * <faber@faberman.de>
+ *
+ * Modified 2009-04-30 added hw serial number support by Florian Faber
+ *
+ * Modified 2011-01-14 added S/PDIF input on RayDATs by Adrian Knoth
+ *
+ * Modified 2011-01-25 variable period sizes on RayDAT/AIO by Adrian Knoth
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -35,6 +50,7 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/asoundef.h>
#include <sound/rawmidi.h>
@@ -47,15 +63,6 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
-/* Disable precise pointer at start */
-static int precise_ptr[SNDRV_CARDS];
-
-/* Send all playback to line outs */
-static int line_outs_monitor[SNDRV_CARDS];
-
-/* Enable Analog Outs on Channel 63/64 by default */
-static int enable_monitor[SNDRV_CARDS];
-
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for RME HDSPM interface.");
@@ -65,42 +72,39 @@ MODULE_PARM_DESC(id, "ID string for RME HDSPM interface.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
-module_param_array(precise_ptr, bool, NULL, 0444);
-MODULE_PARM_DESC(precise_ptr, "Enable or disable precise pointer.");
-
-module_param_array(line_outs_monitor, bool, NULL, 0444);
-MODULE_PARM_DESC(line_outs_monitor,
- "Send playback streams to analog outs by default.");
-
-module_param_array(enable_monitor, bool, NULL, 0444);
-MODULE_PARM_DESC(enable_monitor,
- "Enable Analog Out on Channel 63/64 by default.");
MODULE_AUTHOR
- ("Winfried Ritsch <ritsch_AT_iem.at>, "
- "Paul Davis <paul@linuxaudiosystems.com>, "
- "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
- "Remy Bruno <remy.bruno@trinnov.com>");
+(
+ "Winfried Ritsch <ritsch_AT_iem.at>, "
+ "Paul Davis <paul@linuxaudiosystems.com>, "
+ "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, "
+ "Remy Bruno <remy.bruno@trinnov.com>, "
+ "Florian Faber <faberman@linuxproaudio.org>, "
+ "Adrian Knoth <adi@drcomp.erfurt.thur.de>"
+);
MODULE_DESCRIPTION("RME HDSPM");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
-/* --- Write registers. ---
+/* --- Write registers. ---
These are defined as byte-offsets from the iobase value. */
+#define HDSPM_WR_SETTINGS 0
+#define HDSPM_outputBufferAddress 32
+#define HDSPM_inputBufferAddress 36
#define HDSPM_controlRegister 64
#define HDSPM_interruptConfirmation 96
#define HDSPM_control2Reg 256 /* not in specs ???????? */
#define HDSPM_freqReg 256 /* for AES32 */
-#define HDSPM_midiDataOut0 352 /* just believe in old code */
-#define HDSPM_midiDataOut1 356
+#define HDSPM_midiDataOut0 352 /* just believe in old code */
+#define HDSPM_midiDataOut1 356
#define HDSPM_eeprom_wr 384 /* for AES32 */
/* DMA enable for 64 channels, only Bit 0 is relevant */
-#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */
+#define HDSPM_outputEnableBase 512 /* 512-767 input DMA */
#define HDSPM_inputEnableBase 768 /* 768-1023 output DMA */
-/* 16 page addresses for each of the 64 channels DMA buffer in and out
+/* 16 page addresses for each of the 64 channels DMA buffer in and out
(each 64k=16*4k) Buffer must be 4k aligned (which is default i386 ????) */
#define HDSPM_pageAddressBufferOut 8192
#define HDSPM_pageAddressBufferIn (HDSPM_pageAddressBufferOut+64*16*4)
@@ -119,22 +123,84 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_statusRegister2 192
#define HDSPM_timecodeRegister 128
+/* AIO, RayDAT */
+#define HDSPM_RD_STATUS_0 0
+#define HDSPM_RD_STATUS_1 64
+#define HDSPM_RD_STATUS_2 128
+#define HDSPM_RD_STATUS_3 192
+
+#define HDSPM_RD_TCO 256
+#define HDSPM_RD_PLL_FREQ 512
+#define HDSPM_WR_TCO 128
+
+#define HDSPM_TCO1_TCO_lock 0x00000001
+#define HDSPM_TCO1_WCK_Input_Range_LSB 0x00000002
+#define HDSPM_TCO1_WCK_Input_Range_MSB 0x00000004
+#define HDSPM_TCO1_LTC_Input_valid 0x00000008
+#define HDSPM_TCO1_WCK_Input_valid 0x00000010
+#define HDSPM_TCO1_Video_Input_Format_NTSC 0x00000020
+#define HDSPM_TCO1_Video_Input_Format_PAL 0x00000040
+
+#define HDSPM_TCO1_set_TC 0x00000100
+#define HDSPM_TCO1_set_drop_frame_flag 0x00000200
+#define HDSPM_TCO1_LTC_Format_LSB 0x00000400
+#define HDSPM_TCO1_LTC_Format_MSB 0x00000800
+
+#define HDSPM_TCO2_TC_run 0x00010000
+#define HDSPM_TCO2_WCK_IO_ratio_LSB 0x00020000
+#define HDSPM_TCO2_WCK_IO_ratio_MSB 0x00040000
+#define HDSPM_TCO2_set_num_drop_frames_LSB 0x00080000
+#define HDSPM_TCO2_set_num_drop_frames_MSB 0x00100000
+#define HDSPM_TCO2_set_jam_sync 0x00200000
+#define HDSPM_TCO2_set_flywheel 0x00400000
+
+#define HDSPM_TCO2_set_01_4 0x01000000
+#define HDSPM_TCO2_set_pull_down 0x02000000
+#define HDSPM_TCO2_set_pull_up 0x04000000
+#define HDSPM_TCO2_set_freq 0x08000000
+#define HDSPM_TCO2_set_term_75R 0x10000000
+#define HDSPM_TCO2_set_input_LSB 0x20000000
+#define HDSPM_TCO2_set_input_MSB 0x40000000
+#define HDSPM_TCO2_set_freq_from_app 0x80000000
+
+
+#define HDSPM_midiDataOut0 352
+#define HDSPM_midiDataOut1 356
+#define HDSPM_midiDataOut2 368
+
#define HDSPM_midiDataIn0 360
#define HDSPM_midiDataIn1 364
+#define HDSPM_midiDataIn2 372
+#define HDSPM_midiDataIn3 376
/* status is data bytes in MIDI-FIFO (0-128) */
-#define HDSPM_midiStatusOut0 384
-#define HDSPM_midiStatusOut1 388
-#define HDSPM_midiStatusIn0 392
-#define HDSPM_midiStatusIn1 396
+#define HDSPM_midiStatusOut0 384
+#define HDSPM_midiStatusOut1 388
+#define HDSPM_midiStatusOut2 400
+
+#define HDSPM_midiStatusIn0 392
+#define HDSPM_midiStatusIn1 396
+#define HDSPM_midiStatusIn2 404
+#define HDSPM_midiStatusIn3 408
/* the meters are regular i/o-mapped registers, but offset
considerably from the rest. the peak registers are reset
- when read; the least-significant 4 bits are full-scale counters;
+ when read; the least-significant 4 bits are full-scale counters;
the actual peak value is in the most-significant 24 bits.
*/
-#define HDSPM_MADI_peakrmsbase 4096 /* 4096-8191 2x64x32Bit Meters */
+
+#define HDSPM_MADI_INPUT_PEAK 4096
+#define HDSPM_MADI_PLAYBACK_PEAK 4352
+#define HDSPM_MADI_OUTPUT_PEAK 4608
+
+#define HDSPM_MADI_INPUT_RMS_L 6144
+#define HDSPM_MADI_PLAYBACK_RMS_L 6400
+#define HDSPM_MADI_OUTPUT_RMS_L 6656
+
+#define HDSPM_MADI_INPUT_RMS_H 7168
+#define HDSPM_MADI_PLAYBACK_RMS_H 7424
+#define HDSPM_MADI_OUTPUT_RMS_H 7680
/* --- Control Register bits --------- */
#define HDSPM_Start (1<<0) /* start engine */
@@ -143,7 +209,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Latency1 (1<<2) /* where n is defined */
#define HDSPM_Latency2 (1<<3) /* by Latency{2,1,0} */
-#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */
+#define HDSPM_ClockModeMaster (1<<4) /* 1=Master, 0=Autosync */
+#define HDSPM_c0Master 0x1 /* Master clock bit in settings
+ register [RayDAT, AIO] */
#define HDSPM_AudioInterruptEnable (1<<5) /* what do you think ? */
@@ -157,7 +225,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
56channelMODE=0 */ /* MADI ONLY*/
#define HDSPM_Emphasis (1<<10) /* Emphasis */ /* AES32 ONLY */
-#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
+#define HDSPM_AutoInp (1<<11) /* Auto Input (takeover) == Safe Mode,
0=off, 1=on */ /* MADI ONLY */
#define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */
@@ -166,22 +234,23 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
*/
#define HDSPM_InputSelect1 (1<<15) /* should be 0 */
-#define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */
-#define HDSPM_SyncRef1 (1<<17) /* for AES32: SyncRefN codes the AES # */
#define HDSPM_SyncRef2 (1<<13)
#define HDSPM_SyncRef3 (1<<25)
#define HDSPM_SMUX (1<<18) /* Frame ??? */ /* MADI ONY */
-#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
+#define HDSPM_clr_tms (1<<19) /* clear track marker, do not use
AES additional bits in
lower 5 Audiodatabits ??? */
#define HDSPM_taxi_reset (1<<20) /* ??? */ /* MADI ONLY ? */
#define HDSPM_WCK48 (1<<20) /* Frame ??? = HDSPM_SMUX */ /* AES32 ONLY */
-#define HDSPM_Midi0InterruptEnable (1<<22)
-#define HDSPM_Midi1InterruptEnable (1<<23)
+#define HDSPM_Midi0InterruptEnable 0x0400000
+#define HDSPM_Midi1InterruptEnable 0x0800000
+#define HDSPM_Midi2InterruptEnable 0x0200000
+#define HDSPM_Midi3InterruptEnable 0x4000000
#define HDSPM_LineOut (1<<24) /* Analog Out on channel 63/64 on=1, mute=0 */
+#define HDSPe_FLOAT_FORMAT 0x2000000
#define HDSPM_DS_DoubleWire (1<<26) /* AES32 ONLY */
#define HDSPM_QS_DoubleWire (1<<27) /* AES32 ONLY */
@@ -198,11 +267,18 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_InputCoaxial (HDSPM_InputSelect0)
#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\
HDSPM_SyncRef2|HDSPM_SyncRef3)
-#define HDSPM_SyncRef_Word 0
-#define HDSPM_SyncRef_MADI (HDSPM_SyncRef0)
-#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */
-#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */
+#define HDSPM_c0_SyncRef0 0x2
+#define HDSPM_c0_SyncRef1 0x4
+#define HDSPM_c0_SyncRef2 0x8
+#define HDSPM_c0_SyncRef3 0x10
+#define HDSPM_c0_SyncRefMask (HDSPM_c0_SyncRef0 | HDSPM_c0_SyncRef1 |\
+ HDSPM_c0_SyncRef2 | HDSPM_c0_SyncRef3)
+
+#define HDSPM_SYNC_FROM_WORD 0 /* Preferred sync reference */
+#define HDSPM_SYNC_FROM_MADI 1 /* choices - used by "pref_sync_ref" */
+#define HDSPM_SYNC_FROM_TCO 2
+#define HDSPM_SYNC_FROM_SYNC_IN 3
#define HDSPM_Frequency32KHz HDSPM_Frequency0
#define HDSPM_Frequency44_1KHz HDSPM_Frequency1
@@ -216,17 +292,6 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\
HDSPM_Frequency0)
-/* --- for internal discrimination */
-#define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */
-#define HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ 1
-#define HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ 2
-#define HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ 3
-#define HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ 4
-#define HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ 5
-#define HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ 6
-#define HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ 7
-#define HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ 8
-#define HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ 9
/* Synccheck Status */
#define HDSPM_SYNC_CHECK_NO_LOCK 0
@@ -236,14 +301,16 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
/* AutoSync References - used by "autosync_ref" control switch */
#define HDSPM_AUTOSYNC_FROM_WORD 0
#define HDSPM_AUTOSYNC_FROM_MADI 1
-#define HDSPM_AUTOSYNC_FROM_NONE 2
+#define HDSPM_AUTOSYNC_FROM_TCO 2
+#define HDSPM_AUTOSYNC_FROM_SYNC_IN 3
+#define HDSPM_AUTOSYNC_FROM_NONE 4
/* Possible sources of MADI input */
#define HDSPM_OPTICAL 0 /* optical */
#define HDSPM_COAXIAL 1 /* BNC */
#define hdspm_encode_latency(x) (((x)<<1) & HDSPM_LatencyMask)
-#define hdspm_decode_latency(x) (((x) & HDSPM_LatencyMask)>>1)
+#define hdspm_decode_latency(x) ((((x) & HDSPM_LatencyMask)>>1))
#define hdspm_encode_in(x) (((x)&0x3)<<14)
#define hdspm_decode_in(x) (((x)>>14)&0x3)
@@ -270,13 +337,21 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1
* (like inp0)
*/
+
#define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */
+#define HDSPM_madiSync (1<<18) /* MADI is in sync */
+
+#define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */
+#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */
+
+#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */
+#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */
#define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
- /* since 64byte accurate last 6 bits
- are not used */
+ /* since 64byte accurate, last 6 bits are not used */
+
+
-#define HDSPM_madiSync (1<<18) /* MADI is in sync */
#define HDSPM_DoubleSpeedStatus (1<<19) /* (input) card in double speed */
#define HDSPM_madiFreq0 (1<<22) /* system freq 0=error */
@@ -287,8 +362,19 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with
* Interrupt
*/
-#define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */
-#define HDSPM_midi1IRQPending (1<<31) /* and aktiv */
+#define HDSPM_tco_detect 0x08000000
+#define HDSPM_tco_lock 0x20000000
+
+#define HDSPM_s2_tco_detect 0x00000040
+#define HDSPM_s2_AEBO_D 0x00000080
+#define HDSPM_s2_AEBI_D 0x00000100
+
+
+#define HDSPM_midi0IRQPending 0x40000000
+#define HDSPM_midi1IRQPending 0x80000000
+#define HDSPM_midi2IRQPending 0x20000000
+#define HDSPM_midi2IRQPendingAES 0x00000020
+#define HDSPM_midi3IRQPending 0x00200000
/* --- status bit helpers */
#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\
@@ -317,7 +403,10 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */
/* missing Bit for 111=128, 1000=176.4, 1001=192 */
-#define HDSPM_SelSyncRef0 (1<<8) /* Sync Source in slave mode */
+#define HDSPM_SyncRef0 0x10000 /* Sync Reference */
+#define HDSPM_SyncRef1 0x20000
+
+#define HDSPM_SelSyncRef0 (1<<8) /* AutoSync Source */
#define HDSPM_SelSyncRef1 (1<<9) /* 000=word, 001=MADI, */
#define HDSPM_SelSyncRef2 (1<<10) /* 111=no valid signal */
@@ -331,11 +420,19 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2)
#define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2)
+#define HDSPM_status1_F_0 0x0400000
+#define HDSPM_status1_F_1 0x0800000
+#define HDSPM_status1_F_2 0x1000000
+#define HDSPM_status1_F_3 0x2000000
+#define HDSPM_status1_freqMask (HDSPM_status1_F_0|HDSPM_status1_F_1|HDSPM_status1_F_2|HDSPM_status1_F_3)
+
#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
HDSPM_SelSyncRef2)
#define HDSPM_SelSyncRef_WORD 0
#define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0)
+#define HDSPM_SelSyncRef_TCO (HDSPM_SelSyncRef1)
+#define HDSPM_SelSyncRef_SyncIn (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1)
#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\
HDSPM_SelSyncRef2)
@@ -345,7 +442,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
/* status */
#define HDSPM_AES32_wcLock 0x0200000
#define HDSPM_AES32_wcFreq_bit 22
-/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
+/* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
HDSPM_bit2freq */
#define HDSPM_AES32_syncref_bit 16
/* (status >> HDSPM_AES32_syncref_bit) & 0xF gives sync source */
@@ -398,28 +495,348 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
#define MADI_DS_CHANNELS 32
#define MADI_QS_CHANNELS 16
+#define RAYDAT_SS_CHANNELS 36
+#define RAYDAT_DS_CHANNELS 20
+#define RAYDAT_QS_CHANNELS 12
+
+#define AIO_IN_SS_CHANNELS 14
+#define AIO_IN_DS_CHANNELS 10
+#define AIO_IN_QS_CHANNELS 8
+#define AIO_OUT_SS_CHANNELS 16
+#define AIO_OUT_DS_CHANNELS 12
+#define AIO_OUT_QS_CHANNELS 10
+
+#define AES32_CHANNELS 16
+
/* the size of a substream (1 mono data stream) */
#define HDSPM_CHANNEL_BUFFER_SAMPLES (16*1024)
#define HDSPM_CHANNEL_BUFFER_BYTES (4*HDSPM_CHANNEL_BUFFER_SAMPLES)
/* the size of the area we need to allocate for DMA transfers. the
size is the same regardless of the number of channels, and
- also the latency to use.
+ also the latency to use.
for one direction !!!
*/
#define HDSPM_DMA_AREA_BYTES (HDSPM_MAX_CHANNELS * HDSPM_CHANNEL_BUFFER_BYTES)
#define HDSPM_DMA_AREA_KILOBYTES (HDSPM_DMA_AREA_BYTES/1024)
/* revisions >= 230 indicate AES32 card */
-#define HDSPM_AESREVISION 230
+#define HDSPM_MADI_REV 210
+#define HDSPM_RAYDAT_REV 211
+#define HDSPM_AIO_REV 212
+#define HDSPM_MADIFACE_REV 213
+#define HDSPM_AES_REV 240
+#define HDSPM_AES32_REV 234
+#define HDSPM_AES32_OLD_REV 233
/* speed factor modes */
#define HDSPM_SPEED_SINGLE 0
#define HDSPM_SPEED_DOUBLE 1
#define HDSPM_SPEED_QUAD 2
+
/* names for speed modes */
static char *hdspm_speed_names[] = { "single", "double", "quad" };
+static char *texts_autosync_aes_tco[] = { "Word Clock",
+ "AES1", "AES2", "AES3", "AES4",
+ "AES5", "AES6", "AES7", "AES8",
+ "TCO" };
+static char *texts_autosync_aes[] = { "Word Clock",
+ "AES1", "AES2", "AES3", "AES4",
+ "AES5", "AES6", "AES7", "AES8" };
+static char *texts_autosync_madi_tco[] = { "Word Clock",
+ "MADI", "TCO", "Sync In" };
+static char *texts_autosync_madi[] = { "Word Clock",
+ "MADI", "Sync In" };
+
+static char *texts_autosync_raydat_tco[] = {
+ "Word Clock",
+ "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
+ "AES", "SPDIF", "TCO", "Sync In"
+};
+static char *texts_autosync_raydat[] = {
+ "Word Clock",
+ "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
+ "AES", "SPDIF", "Sync In"
+};
+static char *texts_autosync_aio_tco[] = {
+ "Word Clock",
+ "ADAT", "AES", "SPDIF", "TCO", "Sync In"
+};
+static char *texts_autosync_aio[] = { "Word Clock",
+ "ADAT", "AES", "SPDIF", "Sync In" };
+
+static char *texts_freq[] = {
+ "No Lock",
+ "32 kHz",
+ "44.1 kHz",
+ "48 kHz",
+ "64 kHz",
+ "88.2 kHz",
+ "96 kHz",
+ "128 kHz",
+ "176.4 kHz",
+ "192 kHz"
+};
+
+static char *texts_ports_madi[] = {
+ "MADI.1", "MADI.2", "MADI.3", "MADI.4", "MADI.5", "MADI.6",
+ "MADI.7", "MADI.8", "MADI.9", "MADI.10", "MADI.11", "MADI.12",
+ "MADI.13", "MADI.14", "MADI.15", "MADI.16", "MADI.17", "MADI.18",
+ "MADI.19", "MADI.20", "MADI.21", "MADI.22", "MADI.23", "MADI.24",
+ "MADI.25", "MADI.26", "MADI.27", "MADI.28", "MADI.29", "MADI.30",
+ "MADI.31", "MADI.32", "MADI.33", "MADI.34", "MADI.35", "MADI.36",
+ "MADI.37", "MADI.38", "MADI.39", "MADI.40", "MADI.41", "MADI.42",
+ "MADI.43", "MADI.44", "MADI.45", "MADI.46", "MADI.47", "MADI.48",
+ "MADI.49", "MADI.50", "MADI.51", "MADI.52", "MADI.53", "MADI.54",
+ "MADI.55", "MADI.56", "MADI.57", "MADI.58", "MADI.59", "MADI.60",
+ "MADI.61", "MADI.62", "MADI.63", "MADI.64",
+};
+
+
+static char *texts_ports_raydat_ss[] = {
+ "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4", "ADAT1.5", "ADAT1.6",
+ "ADAT1.7", "ADAT1.8", "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
+ "ADAT2.5", "ADAT2.6", "ADAT2.7", "ADAT2.8", "ADAT3.1", "ADAT3.2",
+ "ADAT3.3", "ADAT3.4", "ADAT3.5", "ADAT3.6", "ADAT3.7", "ADAT3.8",
+ "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4", "ADAT4.5", "ADAT4.6",
+ "ADAT4.7", "ADAT4.8",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R"
+};
+
+static char *texts_ports_raydat_ds[] = {
+ "ADAT1.1", "ADAT1.2", "ADAT1.3", "ADAT1.4",
+ "ADAT2.1", "ADAT2.2", "ADAT2.3", "ADAT2.4",
+ "ADAT3.1", "ADAT3.2", "ADAT3.3", "ADAT3.4",
+ "ADAT4.1", "ADAT4.2", "ADAT4.3", "ADAT4.4",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R"
+};
+
+static char *texts_ports_raydat_qs[] = {
+ "ADAT1.1", "ADAT1.2",
+ "ADAT2.1", "ADAT2.2",
+ "ADAT3.1", "ADAT3.2",
+ "ADAT4.1", "ADAT4.2",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R"
+};
+
+
+static char *texts_ports_aio_in_ss[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
+ "ADAT.7", "ADAT.8"
+};
+
+static char *texts_ports_aio_out_ss[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
+ "ADAT.7", "ADAT.8",
+ "Phone.L", "Phone.R"
+};
+
+static char *texts_ports_aio_in_ds[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+};
+
+static char *texts_ports_aio_out_ds[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+ "Phone.L", "Phone.R"
+};
+
+static char *texts_ports_aio_in_qs[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+};
+
+static char *texts_ports_aio_out_qs[] = {
+ "Analogue.L", "Analogue.R",
+ "AES.L", "AES.R",
+ "SPDIF.L", "SPDIF.R",
+ "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+ "Phone.L", "Phone.R"
+};
+
+static char *texts_ports_aes32[] = {
+ "AES.1", "AES.2", "AES.3", "AES.4", "AES.5", "AES.6", "AES.7",
+ "AES.8", "AES.9.", "AES.10", "AES.11", "AES.12", "AES.13", "AES.14",
+ "AES.15", "AES.16"
+};
+
+/* These tables map the ALSA channels 1..N to the channels that we
+ need to use in order to find the relevant channel buffer. RME
+ refers to this kind of mapping as between "the ADAT channel and
+ the DMA channel." We index it using the logical audio channel,
+ and the value is the DMA channel (i.e. channel buffer number)
+ where the data for that channel can be read/written from/to.
+*/
+
+static char channel_map_unity_ss[HDSPM_MAX_CHANNELS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static char channel_map_raydat_ss[HDSPM_MAX_CHANNELS] = {
+ 4, 5, 6, 7, 8, 9, 10, 11, /* ADAT 1 */
+ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT 2 */
+ 20, 21, 22, 23, 24, 25, 26, 27, /* ADAT 3 */
+ 28, 29, 30, 31, 32, 33, 34, 35, /* ADAT 4 */
+ 0, 1, /* AES */
+ 2, 3, /* SPDIF */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static char channel_map_raydat_ds[HDSPM_MAX_CHANNELS] = {
+ 4, 5, 6, 7, /* ADAT 1 */
+ 8, 9, 10, 11, /* ADAT 2 */
+ 12, 13, 14, 15, /* ADAT 3 */
+ 16, 17, 18, 19, /* ADAT 4 */
+ 0, 1, /* AES */
+ 2, 3, /* SPDIF */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static char channel_map_raydat_qs[HDSPM_MAX_CHANNELS] = {
+ 4, 5, /* ADAT 1 */
+ 6, 7, /* ADAT 2 */
+ 8, 9, /* ADAT 3 */
+ 10, 11, /* ADAT 4 */
+ 0, 1, /* AES */
+ 2, 3, /* SPDIF */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line in */
+ 8, 9, /* aes in, */
+ 10, 11, /* spdif in */
+ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */
+ -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line out */
+ 8, 9, /* aes out */
+ 10, 11, /* spdif out */
+ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */
+ 6, 7, /* phone out */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line in */
+ 8, 9, /* aes in */
+ 10, 11, /* spdif in */
+ 12, 14, 16, 18, /* adat in */
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line out */
+ 8, 9, /* aes out */
+ 10, 11, /* spdif out */
+ 12, 14, 16, 18, /* adat out */
+ 6, 7, /* phone out */
+ -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line in */
+ 8, 9, /* aes in */
+ 10, 11, /* spdif in */
+ 12, 16, /* adat in */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = {
+ 0, 1, /* line out */
+ 8, 9, /* aes out */
+ 10, 11, /* spdif out */
+ 12, 16, /* adat out */
+ 6, 7, /* phone out */
+ -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+static char channel_map_aes32[HDSPM_MAX_CHANNELS] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+};
+
struct hdspm_midi {
struct hdspm *hdspm;
int id;
@@ -430,6 +847,21 @@ struct hdspm_midi {
struct timer_list timer;
spinlock_t lock;
int pending;
+ int dataIn;
+ int statusIn;
+ int dataOut;
+ int statusOut;
+ int ie;
+ int irq;
+};
+
+struct hdspm_tco {
+ int input;
+ int framerate;
+ int wordclock;
+ int samplerate;
+ int pull;
+ int term; /* 0 = off, 1 = on */
};
struct hdspm {
@@ -441,21 +873,39 @@ struct hdspm {
char *card_name; /* for procinfo */
unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/
- unsigned char is_aes32; /* indicates if card is AES32 */
+ uint8_t io_type;
- int precise_ptr; /* use precise pointers, to be tested */
int monitor_outs; /* set up monitoring outs init flag */
u32 control_register; /* cached value */
u32 control2_register; /* cached value */
+ u32 settings_register;
- struct hdspm_midi midi[2];
+ struct hdspm_midi midi[4];
struct tasklet_struct midi_tasklet;
size_t period_bytes;
- unsigned char ss_channels; /* channels of card in single speed */
- unsigned char ds_channels; /* Double Speed */
- unsigned char qs_channels; /* Quad Speed */
+ unsigned char ss_in_channels;
+ unsigned char ds_in_channels;
+ unsigned char qs_in_channels;
+ unsigned char ss_out_channels;
+ unsigned char ds_out_channels;
+ unsigned char qs_out_channels;
+
+ unsigned char max_channels_in;
+ unsigned char max_channels_out;
+
+ char *channel_map_in;
+ char *channel_map_out;
+
+ char *channel_map_in_ss, *channel_map_in_ds, *channel_map_in_qs;
+ char *channel_map_out_ss, *channel_map_out_ds, *channel_map_out_qs;
+
+ char **port_names_in;
+ char **port_names_out;
+
+ char **port_names_in_ss, **port_names_in_ds, **port_names_in_qs;
+ char **port_names_out_ss, **port_names_out_ds, **port_names_out_qs;
unsigned char *playback_buffer; /* suitably aligned address */
unsigned char *capture_buffer; /* suitably aligned address */
@@ -468,14 +918,13 @@ struct hdspm {
int last_internal_sample_rate;
int system_sample_rate;
- char *channel_map; /* channel map for DS and Quadspeed */
-
int dev; /* Hardware vars... */
int irq;
unsigned long port;
void __iomem *iobase;
int irq_count; /* for debug */
+ int midiPorts;
struct snd_card *card; /* one card */
struct snd_pcm *pcm; /* has one pcm */
@@ -487,28 +936,17 @@ struct hdspm {
struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS];
/* but input to much, so not used */
struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS];
- /* full mixer accessible over mixer ioctl or hwdep-device */
+ /* full mixer accessable over mixer ioctl or hwdep-device */
struct hdspm_mixer *mixer;
-};
+ struct hdspm_tco *tco; /* NULL if no TCO detected */
-/* These tables map the ALSA channels 1..N to the channels that we
- need to use in order to find the relevant channel buffer. RME
- refer to this kind of mapping as between "the ADAT channel and
- the DMA channel." We index it using the logical audio channel,
- and the value is the DMA channel (i.e. channel buffer number)
- where the data for that channel can be read/written from/to.
-*/
+ char **texts_autosync;
+ int texts_autosync_items;
+
+ cycles_t last_interrupt;
-static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63
+ struct hdspm_peak_rms peak_rms;
};
@@ -532,11 +970,11 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card,
static int __devinit snd_hdspm_create_pcm(struct snd_card *card,
struct hdspm * hdspm);
-static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm);
-static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm);
-static int hdspm_autosync_ref(struct hdspm * hdspm);
-static int snd_hdspm_set_defaults(struct hdspm * hdspm);
-static void hdspm_set_sgbuf(struct hdspm * hdspm,
+static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm);
+static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
+static int hdspm_autosync_ref(struct hdspm *hdspm);
+static int snd_hdspm_set_defaults(struct hdspm *hdspm);
+static void hdspm_set_sgbuf(struct hdspm *hdspm,
struct snd_pcm_substream *substream,
unsigned int reg, int channels);
@@ -550,7 +988,7 @@ static inline int HDSPM_bit2freq(int n)
return bit2freq_tab[n];
}
-/* Write/read to/from HDSPM with Addresses in Bytes
+/* Write/read to/from HDSPM with Adresses in Bytes
not words but only 32Bit writes are allowed */
static inline void hdspm_write(struct hdspm * hdspm, unsigned int reg,
@@ -564,8 +1002,8 @@ static inline unsigned int hdspm_read(struct hdspm * hdspm, unsigned int reg)
return readl(hdspm->iobase + reg);
}
-/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader
- mixer is write only on hardware so we have to cache him for read
+/* for each output channel (chan) I have an Input (in) and Playback (pb) Fader
+ mixer is write only on hardware so we have to cache him for read
each fader is a u32, but uses only the first 16 bit */
static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan,
@@ -641,30 +1079,67 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm)
/* check for external sample rate */
static int hdspm_external_sample_rate(struct hdspm *hdspm)
{
- if (hdspm->is_aes32) {
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
- unsigned int timecode =
- hdspm_read(hdspm, HDSPM_timecodeRegister);
+ unsigned int status, status2, timecode;
+ int syncref, rate = 0, rate_bits;
- int syncref = hdspm_autosync_ref(hdspm);
+ switch (hdspm->io_type) {
+ case AES32:
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+ syncref = hdspm_autosync_ref(hdspm);
if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
status & HDSPM_AES32_wcLock)
- return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit)
- & 0xF);
+ return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+
if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
- syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
- status2 & (HDSPM_LockAES >>
- (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
- return HDSPM_bit2freq((timecode >>
- (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
+ syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
+ status2 & (HDSPM_LockAES >>
+ (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
+ return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
return 0;
- } else {
- unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
- unsigned int rate_bits;
- int rate = 0;
+ break;
+
+ case MADIface:
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+
+ if (!(status & HDSPM_madiLock)) {
+ rate = 0; /* no lock */
+ } else {
+ switch (status & (HDSPM_status1_freqMask)) {
+ case HDSPM_status1_F_0*1:
+ rate = 32000; break;
+ case HDSPM_status1_F_0*2:
+ rate = 44100; break;
+ case HDSPM_status1_F_0*3:
+ rate = 48000; break;
+ case HDSPM_status1_F_0*4:
+ rate = 64000; break;
+ case HDSPM_status1_F_0*5:
+ rate = 88200; break;
+ case HDSPM_status1_F_0*6:
+ rate = 96000; break;
+ case HDSPM_status1_F_0*7:
+ rate = 128000; break;
+ case HDSPM_status1_F_0*8:
+ rate = 176400; break;
+ case HDSPM_status1_F_0*9:
+ rate = 192000; break;
+ default:
+ rate = 0; break;
+ }
+ }
+
+ break;
+
+ case MADI:
+ case AIO:
+ case RayDAT:
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ rate = 0;
/* if wordclock has synced freq and wordclock is valid */
if ((status2 & HDSPM_wcLock) != 0 &&
@@ -672,6 +1147,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
rate_bits = status2 & HDSPM_wcFreqMask;
+
switch (rate_bits) {
case HDSPM_wcFreq32:
rate = 32000;
@@ -691,7 +1167,6 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
case HDSPM_wcFreq96:
rate = 96000;
break;
- /* Quadspeed Bit missing ???? */
default:
rate = 0;
break;
@@ -702,10 +1177,10 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
* word has priority to MADI
*/
if (rate != 0 &&
- (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
+ (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD)
return rate;
- /* maby a madi input (which is taken if sel sync is madi) */
+ /* maybe a madi input (which is taken if sel sync is madi) */
if (status & HDSPM_madiLock) {
rate_bits = status & HDSPM_madiFreqMask;
@@ -742,36 +1217,35 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm)
break;
}
}
- return rate;
+ break;
}
+
+ return rate;
}
/* Latency function */
-static inline void hdspm_compute_period_size(struct hdspm * hdspm)
+static inline void hdspm_compute_period_size(struct hdspm *hdspm)
{
- hdspm->period_bytes =
- 1 << ((hdspm_decode_latency(hdspm->control_register) + 8));
+ hdspm->period_bytes = 1 << ((hdspm_decode_latency(hdspm->control_register) + 8));
}
-static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm * hdspm)
+
+static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm *hdspm)
{
int position;
position = hdspm_read(hdspm, HDSPM_statusRegister);
- if (!hdspm->precise_ptr)
- return (position & HDSPM_BufferID) ?
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ position &= HDSPM_BufferPositionMask;
+ position /= 4; /* Bytes per sample */
+ break;
+ default:
+ position = (position & HDSPM_BufferID) ?
(hdspm->period_bytes / 4) : 0;
-
- /* hwpointer comes in bytes and is 64Bytes accurate (by docu since
- PCI Burst)
- i have experimented that it is at most 64 Byte to much for playing
- so substraction of 64 byte should be ok for ALSA, but use it only
- for application where you know what you do since if you come to
- near with record pointer it can be a disaster */
-
- position &= HDSPM_BufferPositionMask;
- position = ((position - 64) % (2 * hdspm->period_bytes)) / 4;
+ }
return position;
}
@@ -805,7 +1279,7 @@ static void hdspm_silence_playback(struct hdspm *hdspm)
}
}
-static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames)
+static int hdspm_set_interrupt_interval(struct hdspm *s, unsigned int frames)
{
int n;
@@ -829,21 +1303,53 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames)
return 0;
}
+static u64 hdspm_calc_dds_value(struct hdspm *hdspm, u64 period)
+{
+ u64 freq_const;
+
+ if (period == 0)
+ return 0;
+
+ switch (hdspm->io_type) {
+ case MADI:
+ case AES32:
+ freq_const = 110069313433624ULL;
+ break;
+ case RayDAT:
+ case AIO:
+ freq_const = 104857600000000ULL;
+ break;
+ case MADIface:
+ freq_const = 131072000000000ULL;
+ }
+
+ return div_u64(freq_const, period);
+}
+
+
static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
{
u64 n;
-
+
if (rate >= 112000)
rate /= 4;
else if (rate >= 56000)
rate /= 2;
- /* RME says n = 104857600000000, but in the windows MADI driver, I see:
-// return 104857600000000 / rate; // 100 MHz
- return 110100480000000 / rate; // 105 MHz
- */
- /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */
- n = 110100480000000ULL; /* Value checked for AES32 and MADI */
+ switch (hdspm->io_type) {
+ case MADIface:
+ n = 131072000000000ULL; /* 125 MHz */
+ break;
+ case MADI:
+ case AES32:
+ n = 110069313433624ULL; /* 105 MHz */
+ break;
+ case RayDAT:
+ case AIO:
+ n = 104857600000000ULL; /* 100 MHz */
+ break;
+ }
+
n = div_u64(n, rate);
/* n should be less than 2^32 for being written to FREQ register */
snd_BUG_ON(n >> 32);
@@ -864,13 +1370,13 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
if (!(hdspm->control_register & HDSPM_ClockModeMaster)) {
- /* SLAVE --- */
+ /* SLAVE --- */
if (called_internally) {
- /* request from ctl or card initialization
- just make a warning an remember setting
- for future master mode switching */
-
+ /* request from ctl or card initialization
+ just make a warning an remember setting
+ for future master mode switching */
+
snd_printk(KERN_WARNING "HDSPM: "
"Warning: device is not running "
"as a clock master.\n");
@@ -907,7 +1413,7 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
Note that a similar but essentially insoluble problem exists for
externally-driven rate changes. All we can do is to flag rate
- changes in the read/write routines.
+ changes in the read/write routines.
*/
if (current_rate <= 48000)
@@ -975,16 +1481,35 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally)
/* For AES32, need to set DDS value in FREQ register
For MADI, also apparently */
hdspm_set_dds_value(hdspm, rate);
-
- if (hdspm->is_aes32 && rate != current_rate)
+
+ if (AES32 == hdspm->io_type && rate != current_rate)
hdspm_write(hdspm, HDSPM_eeprom_wr, 0);
-
- /* For AES32 and for MADI (at least rev 204), channel_map needs to
- * always be channel_map_madi_ss, whatever the sample rate */
- hdspm->channel_map = channel_map_madi_ss;
hdspm->system_sample_rate = rate;
+ if (rate <= 48000) {
+ hdspm->channel_map_in = hdspm->channel_map_in_ss;
+ hdspm->channel_map_out = hdspm->channel_map_out_ss;
+ hdspm->max_channels_in = hdspm->ss_in_channels;
+ hdspm->max_channels_out = hdspm->ss_out_channels;
+ hdspm->port_names_in = hdspm->port_names_in_ss;
+ hdspm->port_names_out = hdspm->port_names_out_ss;
+ } else if (rate <= 96000) {
+ hdspm->channel_map_in = hdspm->channel_map_in_ds;
+ hdspm->channel_map_out = hdspm->channel_map_out_ds;
+ hdspm->max_channels_in = hdspm->ds_in_channels;
+ hdspm->max_channels_out = hdspm->ds_out_channels;
+ hdspm->port_names_in = hdspm->port_names_in_ds;
+ hdspm->port_names_out = hdspm->port_names_out_ds;
+ } else {
+ hdspm->channel_map_in = hdspm->channel_map_in_qs;
+ hdspm->channel_map_out = hdspm->channel_map_out_qs;
+ hdspm->max_channels_in = hdspm->qs_in_channels;
+ hdspm->max_channels_out = hdspm->qs_out_channels;
+ hdspm->port_names_in = hdspm->port_names_in_qs;
+ hdspm->port_names_out = hdspm->port_names_out_qs;
+ }
+
if (not_set != 0)
return -1;
@@ -1019,39 +1544,26 @@ static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm,
int id)
{
/* the hardware already does the relevant bit-mask with 0xff */
- if (id)
- return hdspm_read(hdspm, HDSPM_midiDataIn1);
- else
- return hdspm_read(hdspm, HDSPM_midiDataIn0);
+ return hdspm_read(hdspm, hdspm->midi[id].dataIn);
}
static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id,
int val)
{
/* the hardware already does the relevant bit-mask with 0xff */
- if (id)
- hdspm_write(hdspm, HDSPM_midiDataOut1, val);
- else
- hdspm_write(hdspm, HDSPM_midiDataOut0, val);
+ return hdspm_write(hdspm, hdspm->midi[id].dataOut, val);
}
static inline int snd_hdspm_midi_input_available (struct hdspm *hdspm, int id)
{
- if (id)
- return (hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff);
- else
- return (hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff);
+ return hdspm_read(hdspm, hdspm->midi[id].statusIn) & 0xFF;
}
static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id)
{
int fifo_bytes_used;
- if (id)
- fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1);
- else
- fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0);
- fifo_bytes_used &= 0xff;
+ fifo_bytes_used = hdspm_read(hdspm, hdspm->midi[id].statusOut) & 0xFF;
if (fifo_bytes_used < 128)
return 128 - fifo_bytes_used;
@@ -1074,7 +1586,7 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
unsigned char buf[128];
/* Output is not interrupt driven */
-
+
spin_lock_irqsave (&hmidi->lock, flags);
if (hmidi->output &&
!snd_rawmidi_transmit_empty (hmidi->output)) {
@@ -1083,11 +1595,11 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi)
if (n_pending > 0) {
if (n_pending > (int)sizeof (buf))
n_pending = sizeof (buf);
-
+
to_write = snd_rawmidi_transmit (hmidi->output, buf,
n_pending);
if (to_write > 0) {
- for (i = 0; i < to_write; ++i)
+ for (i = 0; i < to_write; ++i)
snd_hdspm_midi_write_byte (hmidi->hdspm,
hmidi->id,
buf[i]);
@@ -1127,12 +1639,11 @@ static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi)
}
}
hmidi->pending = 0;
- if (hmidi->id)
- hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable;
- else
- hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable;
+
+ hmidi->hdspm->control_register |= hmidi->ie;
hdspm_write(hmidi->hdspm, HDSPM_controlRegister,
hmidi->hdspm->control_register);
+
spin_unlock_irqrestore (&hmidi->lock, flags);
return snd_hdspm_midi_output_write (hmidi);
}
@@ -1143,20 +1654,18 @@ snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
struct hdspm *hdspm;
struct hdspm_midi *hmidi;
unsigned long flags;
- u32 ie;
hmidi = substream->rmidi->private_data;
hdspm = hmidi->hdspm;
- ie = hmidi->id ?
- HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable;
+
spin_lock_irqsave (&hdspm->lock, flags);
if (up) {
- if (!(hdspm->control_register & ie)) {
+ if (!(hdspm->control_register & hmidi->ie)) {
snd_hdspm_flush_midi_input (hdspm, hmidi->id);
- hdspm->control_register |= ie;
+ hdspm->control_register |= hmidi->ie;
}
} else {
- hdspm->control_register &= ~ie;
+ hdspm->control_register &= ~hmidi->ie;
}
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
@@ -1167,14 +1676,14 @@ static void snd_hdspm_midi_output_timer(unsigned long data)
{
struct hdspm_midi *hmidi = (struct hdspm_midi *) data;
unsigned long flags;
-
+
snd_hdspm_midi_output_write(hmidi);
spin_lock_irqsave (&hmidi->lock, flags);
/* this does not bump hmidi->istimer, because the
kernel automatically removed the timer when it
expired, and we are now adding it back, thus
- leaving istimer wherever it was set before.
+ leaving istimer wherever it was set before.
*/
if (hmidi->istimer) {
@@ -1288,22 +1797,103 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card,
hdspm->midi[id].hdspm = hdspm;
spin_lock_init (&hdspm->midi[id].lock);
- sprintf (buf, "%s MIDI %d", card->shortname, id+1);
- err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi);
- if (err < 0)
- return err;
+ if (0 == id) {
+ if (MADIface == hdspm->io_type) {
+ /* MIDI-over-MADI on HDSPe MADIface */
+ hdspm->midi[0].dataIn = HDSPM_midiDataIn2;
+ hdspm->midi[0].statusIn = HDSPM_midiStatusIn2;
+ hdspm->midi[0].dataOut = HDSPM_midiDataOut2;
+ hdspm->midi[0].statusOut = HDSPM_midiStatusOut2;
+ hdspm->midi[0].ie = HDSPM_Midi2InterruptEnable;
+ hdspm->midi[0].irq = HDSPM_midi2IRQPending;
+ } else {
+ hdspm->midi[0].dataIn = HDSPM_midiDataIn0;
+ hdspm->midi[0].statusIn = HDSPM_midiStatusIn0;
+ hdspm->midi[0].dataOut = HDSPM_midiDataOut0;
+ hdspm->midi[0].statusOut = HDSPM_midiStatusOut0;
+ hdspm->midi[0].ie = HDSPM_Midi0InterruptEnable;
+ hdspm->midi[0].irq = HDSPM_midi0IRQPending;
+ }
+ } else if (1 == id) {
+ hdspm->midi[1].dataIn = HDSPM_midiDataIn1;
+ hdspm->midi[1].statusIn = HDSPM_midiStatusIn1;
+ hdspm->midi[1].dataOut = HDSPM_midiDataOut1;
+ hdspm->midi[1].statusOut = HDSPM_midiStatusOut1;
+ hdspm->midi[1].ie = HDSPM_Midi1InterruptEnable;
+ hdspm->midi[1].irq = HDSPM_midi1IRQPending;
+ } else if ((2 == id) && (MADI == hdspm->io_type)) {
+ /* MIDI-over-MADI on HDSPe MADI */
+ hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
+ hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
+ hdspm->midi[2].dataOut = HDSPM_midiDataOut2;
+ hdspm->midi[2].statusOut = HDSPM_midiStatusOut2;
+ hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
+ hdspm->midi[2].irq = HDSPM_midi2IRQPending;
+ } else if (2 == id) {
+ /* TCO MTC, read only */
+ hdspm->midi[2].dataIn = HDSPM_midiDataIn2;
+ hdspm->midi[2].statusIn = HDSPM_midiStatusIn2;
+ hdspm->midi[2].dataOut = -1;
+ hdspm->midi[2].statusOut = -1;
+ hdspm->midi[2].ie = HDSPM_Midi2InterruptEnable;
+ hdspm->midi[2].irq = HDSPM_midi2IRQPendingAES;
+ } else if (3 == id) {
+ /* TCO MTC on HDSPe MADI */
+ hdspm->midi[3].dataIn = HDSPM_midiDataIn3;
+ hdspm->midi[3].statusIn = HDSPM_midiStatusIn3;
+ hdspm->midi[3].dataOut = -1;
+ hdspm->midi[3].statusOut = -1;
+ hdspm->midi[3].ie = HDSPM_Midi3InterruptEnable;
+ hdspm->midi[3].irq = HDSPM_midi3IRQPending;
+ }
- sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1);
- hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
+ if ((id < 2) || ((2 == id) && ((MADI == hdspm->io_type) ||
+ (MADIface == hdspm->io_type)))) {
+ if ((id == 0) && (MADIface == hdspm->io_type)) {
+ sprintf(buf, "%s MIDIoverMADI", card->shortname);
+ } else if ((id == 2) && (MADI == hdspm->io_type)) {
+ sprintf(buf, "%s MIDIoverMADI", card->shortname);
+ } else {
+ sprintf(buf, "%s MIDI %d", card->shortname, id+1);
+ }
+ err = snd_rawmidi_new(card, buf, id, 1, 1,
+ &hdspm->midi[id].rmidi);
+ if (err < 0)
+ return err;
- snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &snd_hdspm_midi_output);
- snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &snd_hdspm_midi_input);
+ sprintf(hdspm->midi[id].rmidi->name, "%s MIDI %d",
+ card->id, id+1);
+ hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
+
+ snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
+ SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &snd_hdspm_midi_output);
+ snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_hdspm_midi_input);
+
+ hdspm->midi[id].rmidi->info_flags |=
+ SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ } else {
+ /* TCO MTC, read only */
+ sprintf(buf, "%s MTC %d", card->shortname, id+1);
+ err = snd_rawmidi_new(card, buf, id, 1, 1,
+ &hdspm->midi[id].rmidi);
+ if (err < 0)
+ return err;
- hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT |
- SNDRV_RAWMIDI_INFO_DUPLEX;
+ sprintf(hdspm->midi[id].rmidi->name,
+ "%s MTC %d", card->id, id+1);
+ hdspm->midi[id].rmidi->private_data = &hdspm->midi[id];
+
+ snd_rawmidi_set_ops(hdspm->midi[id].rmidi,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ &snd_hdspm_midi_input);
+
+ hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+ }
return 0;
}
@@ -1312,12 +1902,15 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card,
static void hdspm_midi_tasklet(unsigned long arg)
{
struct hdspm *hdspm = (struct hdspm *)arg;
-
- if (hdspm->midi[0].pending)
- snd_hdspm_midi_input_read (&hdspm->midi[0]);
- if (hdspm->midi[1].pending)
- snd_hdspm_midi_input_read (&hdspm->midi[1]);
-}
+ int i = 0;
+
+ while (i < hdspm->midiPorts) {
+ if (hdspm->midi[i].pending)
+ snd_hdspm_midi_input_read(&hdspm->midi[i]);
+
+ i++;
+ }
+}
/*-----------------------------------------------------------------------------
@@ -1326,6 +1919,22 @@ static void hdspm_midi_tasklet(unsigned long arg)
/* get the system sample rate which is set */
+
+/**
+ * Calculate the real sample rate from the
+ * current DDS value.
+ **/
+static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
+{
+ unsigned int period, rate;
+
+ period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
+ rate = hdspm_calc_dds_value(hdspm, period);
+
+ return rate;
+}
+
+
#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1340,112 +1949,274 @@ static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol,
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
+ uinfo->value.integer.min = 27000;
+ uinfo->value.integer.max = 207000;
+ uinfo->value.integer.step = 1;
return 0;
}
+
static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *
ucontrol)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] = hdspm->system_sample_rate;
+ ucontrol->value.integer.value[0] = hdspm_get_system_sample_rate(hdspm);
+ return 0;
+}
+
+
+/**
+ * Returns the WordClock sample rate class for the given card.
+ **/
+static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
+{
+ int status;
+
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
+ return (status >> 16) & 0xF;
+ break;
+ default:
+ break;
+ }
+
+
+ return 0;
+}
+
+
+/**
+ * Returns the TCO sample rate class for the given card.
+ **/
+static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
+{
+ int status;
+
+ if (hdspm->tco) {
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
+ return (status >> 20) & 0xF;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Returns the SYNC_IN sample rate class for the given card.
+ **/
+static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
+{
+ int status;
+
+ if (hdspm->tco) {
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
+ return (status >> 12) & 0xF;
+ break;
+ default:
+ break;
+ }
+ }
+
return 0;
}
+
+/**
+ * Returns the sample rate class for input source <idx> for
+ * 'new style' cards like the AIO and RayDAT.
+ **/
+static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
+{
+ int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
+
+ return (status >> (idx*4)) & 0xF;
+}
+
+
+
#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .access = SNDRV_CTL_ELEM_ACCESS_READ, \
- .info = snd_hdspm_info_autosync_sample_rate, \
- .get = snd_hdspm_get_autosync_sample_rate \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .private_value = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ, \
+ .info = snd_hdspm_info_autosync_sample_rate, \
+ .get = snd_hdspm_get_autosync_sample_rate \
}
+
static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "32000", "44100", "48000",
- "64000", "88200", "96000",
- "128000", "176400", "192000",
- "None"
- };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 10;
+
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
+ texts_freq[uinfo->value.enumerated.item]);
return 0;
}
+
static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *
ucontrol)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- switch (hdspm_external_sample_rate(hdspm)) {
- case 32000:
- ucontrol->value.enumerated.item[0] = 0;
- break;
- case 44100:
- ucontrol->value.enumerated.item[0] = 1;
- break;
- case 48000:
- ucontrol->value.enumerated.item[0] = 2;
- break;
- case 64000:
- ucontrol->value.enumerated.item[0] = 3;
- break;
- case 88200:
- ucontrol->value.enumerated.item[0] = 4;
- break;
- case 96000:
- ucontrol->value.enumerated.item[0] = 5;
- break;
- case 128000:
- ucontrol->value.enumerated.item[0] = 6;
- break;
- case 176400:
- ucontrol->value.enumerated.item[0] = 7;
- break;
- case 192000:
- ucontrol->value.enumerated.item[0] = 8;
- break;
+ switch (hdspm->io_type) {
+ case RayDAT:
+ switch (kcontrol->private_value) {
+ case 0:
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_wc_sample_rate(hdspm);
+ break;
+ case 7:
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_tco_sample_rate(hdspm);
+ break;
+ case 8:
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_sync_in_sample_rate(hdspm);
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_s1_sample_rate(hdspm,
+ kcontrol->private_value-1);
+ }
+
+ case AIO:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_wc_sample_rate(hdspm);
+ break;
+ case 4: /* TCO */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_tco_sample_rate(hdspm);
+ break;
+ case 5: /* SYNC_IN */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_sync_in_sample_rate(hdspm);
+ break;
+ default:
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_s1_sample_rate(hdspm,
+ ucontrol->id.index-1);
+ }
+
+ case AES32:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_wc_sample_rate(hdspm);
+ break;
+ case 9: /* TCO */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_tco_sample_rate(hdspm);
+ break;
+ case 10: /* SYNC_IN */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_sync_in_sample_rate(hdspm);
+ break;
+ default: /* AES1 to AES8 */
+ ucontrol->value.enumerated.item[0] =
+ hdspm_get_s1_sample_rate(hdspm,
+ kcontrol->private_value-1);
+ break;
+
+ }
default:
- ucontrol->value.enumerated.item[0] = 9;
+ break;
}
+
return 0;
}
+
#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .access = SNDRV_CTL_ELEM_ACCESS_READ, \
- .info = snd_hdspm_info_system_clock_mode, \
- .get = snd_hdspm_get_system_clock_mode, \
-}
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_system_clock_mode, \
+ .get = snd_hdspm_get_system_clock_mode, \
+ .put = snd_hdspm_put_system_clock_mode, \
+}
+
+
+/**
+ * Returns the system clock mode for the given card.
+ * @returns 0 - master, 1 - slave
+ **/
+static int hdspm_system_clock_mode(struct hdspm *hdspm)
+{
+ switch (hdspm->io_type) {
+ case AIO:
+ case RayDAT:
+ if (hdspm->settings_register & HDSPM_c0Master)
+ return 0;
+ break;
+
+ default:
+ if (hdspm->control_register & HDSPM_ClockModeMaster)
+ return 0;
+ }
+ return 1;
+}
-static int hdspm_system_clock_mode(struct hdspm * hdspm)
+/**
+ * Sets the system clock mode.
+ * @param mode 0 - master, 1 - slave
+ **/
+static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
{
- /* Always reflect the hardware info, rme is never wrong !!!! */
+ switch (hdspm->io_type) {
+ case AIO:
+ case RayDAT:
+ if (0 == mode)
+ hdspm->settings_register |= HDSPM_c0Master;
+ else
+ hdspm->settings_register &= ~HDSPM_c0Master;
- if (hdspm->control_register & HDSPM_ClockModeMaster)
- return 0;
- return 1;
+ hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
+ break;
+
+ default:
+ if (0 == mode)
+ hdspm->control_register |= HDSPM_ClockModeMaster;
+ else
+ hdspm->control_register &= ~HDSPM_ClockModeMaster;
+
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ }
}
+
static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Master", "Slave" };
+ static char *texts[] = { "Master", "AutoSync" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
@@ -1463,96 +2234,83 @@ static int snd_hdspm_get_system_clock_mode(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- ucontrol->value.enumerated.item[0] =
- hdspm_system_clock_mode(hdspm);
+ ucontrol->value.enumerated.item[0] = hdspm_system_clock_mode(hdspm);
return 0;
}
-#define HDSPM_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_hdspm_info_clock_source, \
- .get = snd_hdspm_get_clock_source, \
- .put = snd_hdspm_put_clock_source \
+static int snd_hdspm_put_system_clock_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int val;
+
+ if (!snd_hdspm_use_is_exclusive(hdspm))
+ return -EBUSY;
+
+ val = ucontrol->value.enumerated.item[0];
+ if (val < 0)
+ val = 0;
+ else if (val > 1)
+ val = 1;
+
+ hdspm_set_system_clock_mode(hdspm, val);
+
+ return 0;
}
+
+#define HDSPM_INTERNAL_CLOCK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .info = snd_hdspm_info_clock_source, \
+ .get = snd_hdspm_get_clock_source, \
+ .put = snd_hdspm_put_clock_source \
+}
+
+
static int hdspm_clock_source(struct hdspm * hdspm)
{
- if (hdspm->control_register & HDSPM_ClockModeMaster) {
- switch (hdspm->system_sample_rate) {
- case 32000:
- return 1;
- case 44100:
- return 2;
- case 48000:
- return 3;
- case 64000:
- return 4;
- case 88200:
- return 5;
- case 96000:
- return 6;
- case 128000:
- return 7;
- case 176400:
- return 8;
- case 192000:
- return 9;
- default:
- return 3;
- }
- } else {
- return 0;
+ switch (hdspm->system_sample_rate) {
+ case 32000: return 0;
+ case 44100: return 1;
+ case 48000: return 2;
+ case 64000: return 3;
+ case 88200: return 4;
+ case 96000: return 5;
+ case 128000: return 6;
+ case 176400: return 7;
+ case 192000: return 8;
}
+
+ return -1;
}
static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
{
int rate;
switch (mode) {
-
- case HDSPM_CLOCK_SOURCE_AUTOSYNC:
- if (hdspm_external_sample_rate(hdspm) != 0) {
- hdspm->control_register &= ~HDSPM_ClockModeMaster;
- hdspm_write(hdspm, HDSPM_controlRegister,
- hdspm->control_register);
- return 0;
- }
- return -1;
- case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
- rate = 32000;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
- rate = 44100;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
- rate = 48000;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
- rate = 64000;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
- rate = 88200;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
- rate = 96000;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
- rate = 128000;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
- rate = 176400;
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
- rate = 192000;
- break;
-
+ case 0:
+ rate = 32000; break;
+ case 1:
+ rate = 44100; break;
+ case 2:
+ rate = 48000; break;
+ case 3:
+ rate = 64000; break;
+ case 4:
+ rate = 88200; break;
+ case 5:
+ rate = 96000; break;
+ case 6:
+ rate = 128000; break;
+ case 7:
+ rate = 176400; break;
+ case 8:
+ rate = 192000; break;
default:
- rate = 44100;
+ rate = 48000;
}
- hdspm->control_register |= HDSPM_ClockModeMaster;
- hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
hdspm_set_rate(hdspm, rate, 1);
return 0;
}
@@ -1560,25 +2318,16 @@ static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "AutoSync",
- "Internal 32.0 kHz", "Internal 44.1 kHz",
- "Internal 48.0 kHz",
- "Internal 64.0 kHz", "Internal 88.2 kHz",
- "Internal 96.0 kHz",
- "Internal 128.0 kHz", "Internal 176.4 kHz",
- "Internal 192.0 kHz"
- };
-
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 10;
+ uinfo->value.enumerated.items = 9;
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
uinfo->value.enumerated.item =
uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
+ texts_freq[uinfo->value.enumerated.item+1]);
return 0;
}
@@ -1615,134 +2364,301 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
return change;
}
-#define HDSPM_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .info = snd_hdspm_info_pref_sync_ref, \
- .get = snd_hdspm_get_pref_sync_ref, \
- .put = snd_hdspm_put_pref_sync_ref \
-}
+#define HDSPM_PREF_SYNC_REF(xname, xindex) \
+{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_pref_sync_ref, \
+ .get = snd_hdspm_get_pref_sync_ref, \
+ .put = snd_hdspm_put_pref_sync_ref \
+}
+
+
+/**
+ * Returns the current preferred sync reference setting.
+ * The semantics of the return value are depending on the
+ * card, please see the comments for clarification.
+ **/
static int hdspm_pref_sync_ref(struct hdspm * hdspm)
{
- /* Notice that this looks at the requested sync source,
- not the one actually in use.
- */
- if (hdspm->is_aes32) {
+ switch (hdspm->io_type) {
+ case AES32:
switch (hdspm->control_register & HDSPM_SyncRefMask) {
- /* number gives AES index, except for 0 which
- corresponds to WordClock */
- case 0: return 0;
- case HDSPM_SyncRef0: return 1;
- case HDSPM_SyncRef1: return 2;
- case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3;
- case HDSPM_SyncRef2: return 4;
- case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5;
- case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6;
- case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0: return 7;
- case HDSPM_SyncRef3: return 8;
+ case 0: return 0; /* WC */
+ case HDSPM_SyncRef0: return 1; /* AES 1 */
+ case HDSPM_SyncRef1: return 2; /* AES 2 */
+ case HDSPM_SyncRef1+HDSPM_SyncRef0: return 3; /* AES 3 */
+ case HDSPM_SyncRef2: return 4; /* AES 4 */
+ case HDSPM_SyncRef2+HDSPM_SyncRef0: return 5; /* AES 5 */
+ case HDSPM_SyncRef2+HDSPM_SyncRef1: return 6; /* AES 6 */
+ case HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0:
+ return 7; /* AES 7 */
+ case HDSPM_SyncRef3: return 8; /* AES 8 */
+ case HDSPM_SyncRef3+HDSPM_SyncRef0: return 9; /* TCO */
}
- } else {
- switch (hdspm->control_register & HDSPM_SyncRefMask) {
- case HDSPM_SyncRef_Word:
- return HDSPM_SYNC_FROM_WORD;
- case HDSPM_SyncRef_MADI:
- return HDSPM_SYNC_FROM_MADI;
+ break;
+
+ case MADI:
+ case MADIface:
+ if (hdspm->tco) {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case 0: return 0; /* WC */
+ case HDSPM_SyncRef0: return 1; /* MADI */
+ case HDSPM_SyncRef1: return 2; /* TCO */
+ case HDSPM_SyncRef1+HDSPM_SyncRef0:
+ return 3; /* SYNC_IN */
+ }
+ } else {
+ switch (hdspm->control_register & HDSPM_SyncRefMask) {
+ case 0: return 0; /* WC */
+ case HDSPM_SyncRef0: return 1; /* MADI */
+ case HDSPM_SyncRef1+HDSPM_SyncRef0:
+ return 2; /* SYNC_IN */
+ }
+ }
+ break;
+
+ case RayDAT:
+ if (hdspm->tco) {
+ switch ((hdspm->settings_register &
+ HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
+ case 0: return 0; /* WC */
+ case 3: return 1; /* ADAT 1 */
+ case 4: return 2; /* ADAT 2 */
+ case 5: return 3; /* ADAT 3 */
+ case 6: return 4; /* ADAT 4 */
+ case 1: return 5; /* AES */
+ case 2: return 6; /* SPDIF */
+ case 9: return 7; /* TCO */
+ case 10: return 8; /* SYNC_IN */
+ }
+ } else {
+ switch ((hdspm->settings_register &
+ HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
+ case 0: return 0; /* WC */
+ case 3: return 1; /* ADAT 1 */
+ case 4: return 2; /* ADAT 2 */
+ case 5: return 3; /* ADAT 3 */
+ case 6: return 4; /* ADAT 4 */
+ case 1: return 5; /* AES */
+ case 2: return 6; /* SPDIF */
+ case 10: return 7; /* SYNC_IN */
+ }
}
+
+ break;
+
+ case AIO:
+ if (hdspm->tco) {
+ switch ((hdspm->settings_register &
+ HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
+ case 0: return 0; /* WC */
+ case 3: return 1; /* ADAT */
+ case 1: return 2; /* AES */
+ case 2: return 3; /* SPDIF */
+ case 9: return 4; /* TCO */
+ case 10: return 5; /* SYNC_IN */
+ }
+ } else {
+ switch ((hdspm->settings_register &
+ HDSPM_c0_SyncRefMask) / HDSPM_c0_SyncRef0) {
+ case 0: return 0; /* WC */
+ case 3: return 1; /* ADAT */
+ case 1: return 2; /* AES */
+ case 2: return 3; /* SPDIF */
+ case 10: return 4; /* SYNC_IN */
+ }
+ }
+
+ break;
}
- return HDSPM_SYNC_FROM_WORD;
+ return -1;
}
+
+/**
+ * Set the preferred sync reference to <pref>. The semantics
+ * of <pref> are depending on the card type, see the comments
+ * for clarification.
+ **/
static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
{
- hdspm->control_register &= ~HDSPM_SyncRefMask;
+ int p = 0;
- if (hdspm->is_aes32) {
- switch (pref) {
- case 0:
- hdspm->control_register |= 0;
- break;
- case 1:
- hdspm->control_register |= HDSPM_SyncRef0;
- break;
- case 2:
- hdspm->control_register |= HDSPM_SyncRef1;
- break;
- case 3:
- hdspm->control_register |= HDSPM_SyncRef1+HDSPM_SyncRef0;
- break;
- case 4:
- hdspm->control_register |= HDSPM_SyncRef2;
- break;
- case 5:
- hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef0;
- break;
- case 6:
- hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1;
- break;
- case 7:
- hdspm->control_register |=
- HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
- break;
- case 8:
- hdspm->control_register |= HDSPM_SyncRef3;
- break;
- default:
- return -1;
- }
- } else {
+ switch (hdspm->io_type) {
+ case AES32:
+ hdspm->control_register &= ~HDSPM_SyncRefMask;
switch (pref) {
- case HDSPM_SYNC_FROM_MADI:
- hdspm->control_register |= HDSPM_SyncRef_MADI;
+ case 0: /* WC */
+ break;
+ case 1: /* AES 1 */
+ hdspm->control_register |= HDSPM_SyncRef0;
+ break;
+ case 2: /* AES 2 */
+ hdspm->control_register |= HDSPM_SyncRef1;
+ break;
+ case 3: /* AES 3 */
+ hdspm->control_register |=
+ HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 4: /* AES 4 */
+ hdspm->control_register |= HDSPM_SyncRef2;
+ break;
+ case 5: /* AES 5 */
+ hdspm->control_register |=
+ HDSPM_SyncRef2+HDSPM_SyncRef0;
break;
- case HDSPM_SYNC_FROM_WORD:
- hdspm->control_register |= HDSPM_SyncRef_Word;
+ case 6: /* AES 6 */
+ hdspm->control_register |=
+ HDSPM_SyncRef2+HDSPM_SyncRef1;
+ break;
+ case 7: /* AES 7 */
+ hdspm->control_register |=
+ HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0;
+ break;
+ case 8: /* AES 8 */
+ hdspm->control_register |= HDSPM_SyncRef3;
+ break;
+ case 9: /* TCO */
+ hdspm->control_register |=
+ HDSPM_SyncRef3+HDSPM_SyncRef0;
break;
default:
return -1;
}
+
+ break;
+
+ case MADI:
+ case MADIface:
+ hdspm->control_register &= ~HDSPM_SyncRefMask;
+ if (hdspm->tco) {
+ switch (pref) {
+ case 0: /* WC */
+ break;
+ case 1: /* MADI */
+ hdspm->control_register |= HDSPM_SyncRef0;
+ break;
+ case 2: /* TCO */
+ hdspm->control_register |= HDSPM_SyncRef1;
+ break;
+ case 3: /* SYNC_IN */
+ hdspm->control_register |=
+ HDSPM_SyncRef0+HDSPM_SyncRef1;
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ switch (pref) {
+ case 0: /* WC */
+ break;
+ case 1: /* MADI */
+ hdspm->control_register |= HDSPM_SyncRef0;
+ break;
+ case 2: /* SYNC_IN */
+ hdspm->control_register |=
+ HDSPM_SyncRef0+HDSPM_SyncRef1;
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ break;
+
+ case RayDAT:
+ if (hdspm->tco) {
+ switch (pref) {
+ case 0: p = 0; break; /* WC */
+ case 1: p = 3; break; /* ADAT 1 */
+ case 2: p = 4; break; /* ADAT 2 */
+ case 3: p = 5; break; /* ADAT 3 */
+ case 4: p = 6; break; /* ADAT 4 */
+ case 5: p = 1; break; /* AES */
+ case 6: p = 2; break; /* SPDIF */
+ case 7: p = 9; break; /* TCO */
+ case 8: p = 10; break; /* SYNC_IN */
+ default: return -1;
+ }
+ } else {
+ switch (pref) {
+ case 0: p = 0; break; /* WC */
+ case 1: p = 3; break; /* ADAT 1 */
+ case 2: p = 4; break; /* ADAT 2 */
+ case 3: p = 5; break; /* ADAT 3 */
+ case 4: p = 6; break; /* ADAT 4 */
+ case 5: p = 1; break; /* AES */
+ case 6: p = 2; break; /* SPDIF */
+ case 7: p = 10; break; /* SYNC_IN */
+ default: return -1;
+ }
+ }
+ break;
+
+ case AIO:
+ if (hdspm->tco) {
+ switch (pref) {
+ case 0: p = 0; break; /* WC */
+ case 1: p = 3; break; /* ADAT */
+ case 2: p = 1; break; /* AES */
+ case 3: p = 2; break; /* SPDIF */
+ case 4: p = 9; break; /* TCO */
+ case 5: p = 10; break; /* SYNC_IN */
+ default: return -1;
+ }
+ } else {
+ switch (pref) {
+ case 0: p = 0; break; /* WC */
+ case 1: p = 3; break; /* ADAT */
+ case 2: p = 1; break; /* AES */
+ case 3: p = 2; break; /* SPDIF */
+ case 4: p = 10; break; /* SYNC_IN */
+ default: return -1;
+ }
+ }
+ break;
}
- hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ hdspm->settings_register &= ~HDSPM_c0_SyncRefMask;
+ hdspm->settings_register |= HDSPM_c0_SyncRef0 * p;
+ hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
+ break;
+
+ case MADI:
+ case MADIface:
+ case AES32:
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ }
+
return 0;
}
+
static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- if (hdspm->is_aes32) {
- static char *texts[] = { "Word", "AES1", "AES2", "AES3",
- "AES4", "AES5", "AES6", "AES7", "AES8" };
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
-
- uinfo->value.enumerated.items = 9;
-
- if (uinfo->value.enumerated.item >=
- uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- } else {
- static char *texts[] = { "Word", "MADI" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = hdspm->texts_autosync_items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
- uinfo->value.enumerated.items = 2;
+ strcpy(uinfo->value.enumerated.name,
+ hdspm->texts_autosync[uinfo->value.enumerated.item]);
- if (uinfo->value.enumerated.item >=
- uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- }
return 0;
}
@@ -1750,32 +2666,41 @@ static int snd_hdspm_get_pref_sync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int psf = hdspm_pref_sync_ref(hdspm);
- ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm);
- return 0;
+ if (psf >= 0) {
+ ucontrol->value.enumerated.item[0] = psf;
+ return 0;
+ }
+
+ return -1;
}
static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- int change, max;
- unsigned int val;
-
- max = hdspm->is_aes32 ? 9 : 2;
+ int val, change = 0;
if (!snd_hdspm_use_is_exclusive(hdspm))
return -EBUSY;
- val = ucontrol->value.enumerated.item[0] % max;
+ val = ucontrol->value.enumerated.item[0];
+
+ if (val < 0)
+ val = 0;
+ else if (val >= hdspm->texts_autosync_items)
+ val = hdspm->texts_autosync_items-1;
spin_lock_irq(&hdspm->lock);
- change = (int) val != hdspm_pref_sync_ref(hdspm);
- hdspm_set_pref_sync_ref(hdspm, val);
+ if (val != hdspm_pref_sync_ref(hdspm))
+ change = (0 == hdspm_set_pref_sync_ref(hdspm, val)) ? 1 : 0;
+
spin_unlock_irq(&hdspm->lock);
return change;
}
+
#define HDSPM_AUTOSYNC_REF(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1785,18 +2710,18 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol,
.get = snd_hdspm_get_autosync_ref, \
}
-static int hdspm_autosync_ref(struct hdspm * hdspm)
+static int hdspm_autosync_ref(struct hdspm *hdspm)
{
- if (hdspm->is_aes32) {
+ if (AES32 == hdspm->io_type) {
unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
- unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) &
- 0xF;
+ unsigned int syncref =
+ (status >> HDSPM_AES32_syncref_bit) & 0xF;
if (syncref == 0)
return HDSPM_AES32_AUTOSYNC_FROM_WORD;
if (syncref <= 8)
return syncref;
return HDSPM_AES32_AUTOSYNC_FROM_NONE;
- } else {
+ } else if (MADI == hdspm->io_type) {
/* This looks at the autosync selected sync reference */
unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
@@ -1805,22 +2730,27 @@ static int hdspm_autosync_ref(struct hdspm * hdspm)
return HDSPM_AUTOSYNC_FROM_WORD;
case HDSPM_SelSyncRef_MADI:
return HDSPM_AUTOSYNC_FROM_MADI;
+ case HDSPM_SelSyncRef_TCO:
+ return HDSPM_AUTOSYNC_FROM_TCO;
+ case HDSPM_SelSyncRef_SyncIn:
+ return HDSPM_AUTOSYNC_FROM_SYNC_IN;
case HDSPM_SelSyncRef_NVALID:
return HDSPM_AUTOSYNC_FROM_NONE;
default:
return 0;
}
- return 0;
}
+ return 0;
}
+
static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- if (hdspm->is_aes32) {
+ if (AES32 == hdspm->io_type) {
static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
"AES4", "AES5", "AES6", "AES7", "AES8", "None"};
@@ -1833,14 +2763,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);
- } else {
- static char *texts[] = { "WordClock", "MADI", "None" };
+ } else if (MADI == hdspm->io_type) {
+ static char *texts[] = {"Word Clock", "MADI", "TCO",
+ "Sync In", "None" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
+ uinfo->value.enumerated.items = 5;
if (uinfo->value.enumerated.item >=
- uinfo->value.enumerated.items)
+ uinfo->value.enumerated.items)
uinfo->value.enumerated.item =
uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name,
@@ -1858,6 +2789,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol,
return 0;
}
+
#define HDSPM_LINE_OUT(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1914,6 +2846,7 @@ static int snd_hdspm_put_line_out(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_TX_64(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -1969,6 +2902,7 @@ static int snd_hdspm_put_tx_64(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_C_TMS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2024,6 +2958,7 @@ static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_SAFE_MODE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2079,6 +3014,7 @@ static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_EMPHASIS(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2134,6 +3070,7 @@ static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_DOLBY(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2189,6 +3126,7 @@ static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_PROFESSIONAL(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2315,6 +3253,7 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_DS_WIRE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2386,6 +3325,7 @@ static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol,
return change;
}
+
#define HDSPM_QS_WIRE(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2472,15 +3412,6 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol,
return change;
}
-/* Simple Mixer
- deprecated since to much faders ???
- MIXER interface says output (source, destination, value)
- where source > MAX_channels are playback channels
- on MADICARD
- - playback mixer matrix: [channelout+64] [output] [value]
- - input(thru) mixer matrix: [channelin] [output] [value]
- (better do 2 kontrols for separation ?)
-*/
#define HDSPM_MIXER(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
@@ -2586,7 +3517,7 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol,
/* The simple mixer control(s) provide gain control for the
basic 1:1 mappings of playback streams to output
- streams.
+ streams.
*/
#define HDSPM_PLAYBACK_MIXER \
@@ -2604,7 +3535,7 @@ static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 65536;
+ uinfo->value.integer.max = 64;
uinfo->value.integer.step = 1;
return 0;
}
@@ -2614,28 +3545,17 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol,
{
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
int channel;
- int mapped_channel;
channel = ucontrol->id.index - 1;
if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
return -EINVAL;
- mapped_channel = hdspm->channel_map[channel];
- if (mapped_channel < 0)
- return -EINVAL;
-
spin_lock_irq(&hdspm->lock);
ucontrol->value.integer.value[0] =
- hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel);
+ (hdspm_read_pb_gain(hdspm, channel, channel)*64)/UNITY_GAIN;
spin_unlock_irq(&hdspm->lock);
- /*
- snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, "
- "value %d\n",
- ucontrol->id.index, channel, mapped_channel,
- ucontrol->value.integer.value[0]);
- */
return 0;
}
@@ -2645,7 +3565,6 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
int change;
int channel;
- int mapped_channel;
int gain;
if (!snd_hdspm_use_is_exclusive(hdspm))
@@ -2656,59 +3575,60 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol,
if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
return -EINVAL;
- mapped_channel = hdspm->channel_map[channel];
- if (mapped_channel < 0)
- return -EINVAL;
-
- gain = ucontrol->value.integer.value[0];
+ gain = ucontrol->value.integer.value[0]*UNITY_GAIN/64;
spin_lock_irq(&hdspm->lock);
change =
- gain != hdspm_read_pb_gain(hdspm, mapped_channel,
- mapped_channel);
+ gain != hdspm_read_pb_gain(hdspm, channel,
+ channel);
if (change)
- hdspm_write_pb_gain(hdspm, mapped_channel, mapped_channel,
+ hdspm_write_pb_gain(hdspm, channel, channel,
gain);
spin_unlock_irq(&hdspm->lock);
return change;
}
-#define HDSPM_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
- .info = snd_hdspm_info_sync_check, \
- .get = snd_hdspm_get_wc_sync_check \
+#define HDSPM_SYNC_CHECK(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .private_value = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_sync_check, \
+ .get = snd_hdspm_get_sync_check \
}
+
static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "No Lock", "Lock", "Sync" };
+ static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
+ uinfo->value.enumerated.items = 4;
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
+ uinfo->value.enumerated.items - 1;
strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
+ texts[uinfo->value.enumerated.item]);
return 0;
}
-static int hdspm_wc_sync_check(struct hdspm * hdspm)
+static int hdspm_wc_sync_check(struct hdspm *hdspm)
{
- if (hdspm->is_aes32) {
- int status = hdspm_read(hdspm, HDSPM_statusRegister);
- if (status & HDSPM_AES32_wcLock) {
- /* I don't know how to differenciate sync from lock.
- Doing as if sync for now */
+ int status, status2;
+
+ switch (hdspm->io_type) {
+ case AES32:
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ if (status & HDSPM_wcSync)
return 2;
- }
+ else if (status & HDSPM_wcLock)
+ return 1;
return 0;
- } else {
- int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ break;
+
+ case MADI:
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
if (status2 & HDSPM_wcLock) {
if (status2 & HDSPM_wcSync)
return 2;
@@ -2716,29 +3636,30 @@ static int hdspm_wc_sync_check(struct hdspm * hdspm)
return 1;
}
return 0;
- }
-}
+ break;
-static int snd_hdspm_get_wc_sync_check(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
- ucontrol->value.enumerated.item[0] = hdspm_wc_sync_check(hdspm);
- return 0;
-}
+ if (status & 0x2000000)
+ return 2;
+ else if (status & 0x1000000)
+ return 1;
+ return 0;
+ break;
-#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
- .info = snd_hdspm_info_sync_check, \
- .get = snd_hdspm_get_madisync_sync_check \
+ case MADIface:
+ break;
+ }
+
+
+ return 3;
}
-static int hdspm_madisync_sync_check(struct hdspm * hdspm)
+
+static int hdspm_madi_sync_check(struct hdspm *hdspm)
{
int status = hdspm_read(hdspm, HDSPM_statusRegister);
if (status & HDSPM_madiLock) {
@@ -2750,89 +3671,726 @@ static int hdspm_madisync_sync_check(struct hdspm * hdspm)
return 0;
}
-static int snd_hdspm_get_madisync_sync_check(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *
- ucontrol)
+
+static int hdspm_s1_sync_check(struct hdspm *hdspm, int idx)
{
- struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int status, lock, sync;
+
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
+
+ lock = (status & (0x1<<idx)) ? 1 : 0;
+ sync = (status & (0x100<<idx)) ? 1 : 0;
- ucontrol->value.enumerated.item[0] =
- hdspm_madisync_sync_check(hdspm);
+ if (lock && sync)
+ return 2;
+ else if (lock)
+ return 1;
return 0;
}
-#define HDSPM_AES_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .index = xindex, \
- .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
- .info = snd_hdspm_info_sync_check, \
- .get = snd_hdspm_get_aes_sync_check \
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm)
+{
+ int status, lock = 0, sync = 0;
+
+ switch (hdspm->io_type) {
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_3);
+ lock = (status & 0x400) ? 1 : 0;
+ sync = (status & 0x800) ? 1 : 0;
+ break;
+
+ case MADI:
+ case AES32:
+ status = hdspm_read(hdspm, HDSPM_statusRegister2);
+ lock = (status & HDSPM_syncInLock) ? 1 : 0;
+ sync = (status & HDSPM_syncInSync) ? 1 : 0;
+ break;
+
+ case MADIface:
+ break;
+ }
+
+ if (lock && sync)
+ return 2;
+ else if (lock)
+ return 1;
+
+ return 0;
}
-static int hdspm_aes_sync_check(struct hdspm * hdspm, int idx)
+static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx)
{
- int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- if (status2 & (HDSPM_LockAES >> idx)) {
- /* I don't know how to differenciate sync from lock.
- Doing as if sync for now */
+ int status2, lock, sync;
+ status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ lock = (status2 & (0x0080 >> idx)) ? 1 : 0;
+ sync = (status2 & (0x8000 >> idx)) ? 1 : 0;
+
+ if (sync)
return 2;
+ else if (lock)
+ return 1;
+ return 0;
+}
+
+
+static int hdspm_tco_sync_check(struct hdspm *hdspm)
+{
+ int status;
+
+ if (hdspm->tco) {
+ switch (hdspm->io_type) {
+ case MADI:
+ case AES32:
+ status = hdspm_read(hdspm, HDSPM_statusRegister);
+ if (status & HDSPM_tcoLock) {
+ if (status & HDSPM_tcoSync)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+
+ break;
+
+ case RayDAT:
+ case AIO:
+ status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
+
+ if (status & 0x8000000)
+ return 2; /* Sync */
+ if (status & 0x4000000)
+ return 1; /* Lock */
+ return 0; /* No signal */
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 3; /* N/A */
+}
+
+
+static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+ int val = -1;
+
+ switch (hdspm->io_type) {
+ case RayDAT:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ val = hdspm_wc_sync_check(hdspm); break;
+ case 7: /* TCO */
+ val = hdspm_tco_sync_check(hdspm); break;
+ case 8: /* SYNC IN */
+ val = hdspm_sync_in_sync_check(hdspm); break;
+ default:
+ val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+ }
+
+ case AIO:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ val = hdspm_wc_sync_check(hdspm); break;
+ case 4: /* TCO */
+ val = hdspm_tco_sync_check(hdspm); break;
+ case 5: /* SYNC IN */
+ val = hdspm_sync_in_sync_check(hdspm); break;
+ default:
+ val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+ }
+
+ case MADI:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ val = hdspm_wc_sync_check(hdspm); break;
+ case 1: /* MADI */
+ val = hdspm_madi_sync_check(hdspm); break;
+ case 2: /* TCO */
+ val = hdspm_tco_sync_check(hdspm); break;
+ case 3: /* SYNC_IN */
+ val = hdspm_sync_in_sync_check(hdspm); break;
+ }
+
+ case MADIface:
+ val = hdspm_madi_sync_check(hdspm); /* MADI */
+ break;
+
+ case AES32:
+ switch (kcontrol->private_value) {
+ case 0: /* WC */
+ val = hdspm_wc_sync_check(hdspm); break;
+ case 9: /* TCO */
+ val = hdspm_tco_sync_check(hdspm); break;
+ case 10 /* SYNC IN */:
+ val = hdspm_sync_in_sync_check(hdspm); break;
+ default: /* AES1 to AES8 */
+ val = hdspm_aes_sync_check(hdspm,
+ kcontrol->private_value-1);
+ }
+
}
+
+ if (-1 == val)
+ val = 3;
+
+ ucontrol->value.enumerated.item[0] = val;
return 0;
}
-static int snd_hdspm_get_aes_sync_check(struct snd_kcontrol *kcontrol,
+
+
+/**
+ * TCO controls
+ **/
+static void hdspm_tco_write(struct hdspm *hdspm)
+{
+ unsigned int tc[4] = { 0, 0, 0, 0};
+
+ switch (hdspm->tco->input) {
+ case 0:
+ tc[2] |= HDSPM_TCO2_set_input_MSB;
+ break;
+ case 1:
+ tc[2] |= HDSPM_TCO2_set_input_LSB;
+ break;
+ default:
+ break;
+ }
+
+ switch (hdspm->tco->framerate) {
+ case 1:
+ tc[1] |= HDSPM_TCO1_LTC_Format_LSB;
+ break;
+ case 2:
+ tc[1] |= HDSPM_TCO1_LTC_Format_MSB;
+ break;
+ case 3:
+ tc[1] |= HDSPM_TCO1_LTC_Format_MSB +
+ HDSPM_TCO1_set_drop_frame_flag;
+ break;
+ case 4:
+ tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
+ HDSPM_TCO1_LTC_Format_MSB;
+ break;
+ case 5:
+ tc[1] |= HDSPM_TCO1_LTC_Format_LSB +
+ HDSPM_TCO1_LTC_Format_MSB +
+ HDSPM_TCO1_set_drop_frame_flag;
+ break;
+ default:
+ break;
+ }
+
+ switch (hdspm->tco->wordclock) {
+ case 1:
+ tc[2] |= HDSPM_TCO2_WCK_IO_ratio_LSB;
+ break;
+ case 2:
+ tc[2] |= HDSPM_TCO2_WCK_IO_ratio_MSB;
+ break;
+ default:
+ break;
+ }
+
+ switch (hdspm->tco->samplerate) {
+ case 1:
+ tc[2] |= HDSPM_TCO2_set_freq;
+ break;
+ case 2:
+ tc[2] |= HDSPM_TCO2_set_freq_from_app;
+ break;
+ default:
+ break;
+ }
+
+ switch (hdspm->tco->pull) {
+ case 1:
+ tc[2] |= HDSPM_TCO2_set_pull_up;
+ break;
+ case 2:
+ tc[2] |= HDSPM_TCO2_set_pull_down;
+ break;
+ case 3:
+ tc[2] |= HDSPM_TCO2_set_pull_up + HDSPM_TCO2_set_01_4;
+ break;
+ case 4:
+ tc[2] |= HDSPM_TCO2_set_pull_down + HDSPM_TCO2_set_01_4;
+ break;
+ default:
+ break;
+ }
+
+ if (1 == hdspm->tco->term) {
+ tc[2] |= HDSPM_TCO2_set_term_75R;
+ }
+
+ hdspm_write(hdspm, HDSPM_WR_TCO, tc[0]);
+ hdspm_write(hdspm, HDSPM_WR_TCO+4, tc[1]);
+ hdspm_write(hdspm, HDSPM_WR_TCO+8, tc[2]);
+ hdspm_write(hdspm, HDSPM_WR_TCO+12, tc[3]);
+}
+
+
+#define HDSPM_TCO_SAMPLE_RATE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_sample_rate, \
+ .get = snd_hdspm_get_tco_sample_rate, \
+ .put = snd_hdspm_put_tco_sample_rate \
+}
+
+static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "44.1 kHz", "48 kHz" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_tco_sample_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->tco->samplerate;
+
+ return 0;
+}
+
+static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->samplerate != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->samplerate = ucontrol->value.enumerated.item[0];
+
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#define HDSPM_TCO_PULL(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_pull, \
+ .get = snd_hdspm_get_tco_pull, \
+ .put = snd_hdspm_put_tco_pull \
+}
+
+static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 5;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_tco_pull(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->tco->pull;
+
+ return 0;
+}
+
+static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->pull != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->pull = ucontrol->value.enumerated.item[0];
+
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#define HDSPM_TCO_WCK_CONVERSION(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_wck_conversion, \
+ .get = snd_hdspm_get_tco_wck_conversion, \
+ .put = snd_hdspm_put_tco_wck_conversion \
+}
+
+static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_tco_wck_conversion(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->tco->wordclock;
+
+ return 0;
+}
+
+static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->wordclock != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->wordclock = ucontrol->value.enumerated.item[0];
+
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#define HDSPM_TCO_FRAME_RATE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_frame_rate, \
+ .get = snd_hdspm_get_tco_frame_rate, \
+ .put = snd_hdspm_put_tco_frame_rate \
+}
+
+static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "24 fps", "25 fps", "29.97fps",
+ "29.97 dfps", "30 fps", "30 dfps" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 6;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_tco_frame_rate(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- int offset;
struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
- offset = ucontrol->id.index - 1;
- if (offset < 0 || offset >= 8)
- return -EINVAL;
+ ucontrol->value.enumerated.item[0] = hdspm->tco->framerate;
- ucontrol->value.enumerated.item[0] =
- hdspm_aes_sync_check(hdspm, offset);
return 0;
}
+static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->framerate != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->framerate = ucontrol->value.enumerated.item[0];
-static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
- HDSPM_MIXER("Mixer", 0),
-/* 'Sample Clock Source' complies with the alsa control naming scheme */
- HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+#define HDSPM_TCO_SYNC_SOURCE(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_sync_source, \
+ .get = snd_hdspm_get_tco_sync_source, \
+ .put = snd_hdspm_put_tco_sync_source \
+}
+
+static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[] = { "LTC", "Video", "WCK" };
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item =
+ uinfo->value.enumerated.items - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_hdspm_get_tco_sync_source(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->tco->input;
+
+ return 0;
+}
+
+static int snd_hdspm_put_tco_sync_source(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->input != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->input = ucontrol->value.enumerated.item[0];
+
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#define HDSPM_TCO_WORD_TERM(xname, xindex) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .index = xindex, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+ .info = snd_hdspm_info_tco_word_term, \
+ .get = snd_hdspm_get_tco_word_term, \
+ .put = snd_hdspm_put_tco_word_term \
+}
+
+static int snd_hdspm_info_tco_word_term(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+
+
+static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = hdspm->tco->term;
+
+ return 0;
+}
+
+
+static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+
+ if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) {
+ hdspm->tco->term = ucontrol->value.enumerated.item[0];
+
+ hdspm_tco_write(hdspm);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+static struct snd_kcontrol_new snd_hdspm_controls_madi[] = {
+ HDSPM_MIXER("Mixer", 0),
+ HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
-/* 'External Rate' complies with the alsa control naming scheme */
- HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
- HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
- HDSPM_MADI_SYNC_CHECK("MADI Sync Lock Status", 0),
+ HDSPM_SYNC_CHECK("WC SyncCheck", 0),
+ HDSPM_SYNC_CHECK("MADI SyncCheck", 1),
+ HDSPM_SYNC_CHECK("TCO SyncCHeck", 2),
+ HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3),
HDSPM_LINE_OUT("Line Out", 0),
HDSPM_TX_64("TX 64 channels mode", 0),
HDSPM_C_TMS("Clear Track Marker", 0),
HDSPM_SAFE_MODE("Safe Mode", 0),
- HDSPM_INPUT_SELECT("Input Select", 0),
+ HDSPM_INPUT_SELECT("Input Select", 0)
};
-static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
+static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = {
HDSPM_MIXER("Mixer", 0),
-/* 'Sample Clock Source' complies with the alsa control naming scheme */
- HDSPM_CLOCK_SOURCE("Sample Clock Source", 0),
+ HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
+ HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+ HDSPM_SYNC_CHECK("MADI SyncCheck", 0),
+ HDSPM_TX_64("TX 64 channels mode", 0),
+ HDSPM_C_TMS("Clear Track Marker", 0),
+ HDSPM_SAFE_MODE("Safe Mode", 0)
+};
+static struct snd_kcontrol_new snd_hdspm_controls_aio[] = {
+ HDSPM_MIXER("Mixer", 0),
+ HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
-/* 'External Rate' complies with the alsa control naming scheme */
HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
- HDSPM_WC_SYNC_CHECK("Word Clock Lock Status", 0),
-/* HDSPM_AES_SYNC_CHECK("AES Lock Status", 0),*/ /* created in snd_hdspm_create_controls() */
+ HDSPM_SYNC_CHECK("WC SyncCheck", 0),
+ HDSPM_SYNC_CHECK("AES SyncCheck", 1),
+ HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
+ HDSPM_SYNC_CHECK("ADAT SyncCheck", 3),
+ HDSPM_SYNC_CHECK("TCO SyncCheck", 4),
+ HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 5),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5)
+
+ /*
+ HDSPM_INPUT_SELECT("Input Select", 0),
+ HDSPM_SPDIF_OPTICAL("SPDIF Out Optical", 0),
+ HDSPM_PROFESSIONAL("SPDIF Out Professional", 0);
+ HDSPM_SPDIF_IN("SPDIF In", 0);
+ HDSPM_BREAKOUT_CABLE("Breakout Cable", 0);
+ HDSPM_INPUT_LEVEL("Input Level", 0);
+ HDSPM_OUTPUT_LEVEL("Output Level", 0);
+ HDSPM_PHONES("Phones", 0);
+ */
+};
+
+static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = {
+ HDSPM_MIXER("Mixer", 0),
+ HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
+ HDSPM_SYSTEM_CLOCK_MODE("Clock Mode", 0),
+ HDSPM_PREF_SYNC_REF("Pref Sync Ref", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+ HDSPM_SYNC_CHECK("WC SyncCheck", 0),
+ HDSPM_SYNC_CHECK("AES SyncCheck", 1),
+ HDSPM_SYNC_CHECK("SPDIF SyncCheck", 2),
+ HDSPM_SYNC_CHECK("ADAT1 SyncCheck", 3),
+ HDSPM_SYNC_CHECK("ADAT2 SyncCheck", 4),
+ HDSPM_SYNC_CHECK("ADAT3 SyncCheck", 5),
+ HDSPM_SYNC_CHECK("ADAT4 SyncCheck", 6),
+ HDSPM_SYNC_CHECK("TCO SyncCheck", 7),
+ HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 8),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES Frequency", 1),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT1 Frequency", 3),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT2 Frequency", 4),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8)
+};
+
+static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
+ HDSPM_MIXER("Mixer", 0),
+ HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
+ HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
+ HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
+ HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
+ HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+ HDSPM_SYNC_CHECK("WC Sync Check", 0),
+ HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
+ HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
+ HDSPM_SYNC_CHECK("AES3 Sync Check", 3),
+ HDSPM_SYNC_CHECK("AES4 Sync Check", 4),
+ HDSPM_SYNC_CHECK("AES5 Sync Check", 5),
+ HDSPM_SYNC_CHECK("AES6 Sync Check", 6),
+ HDSPM_SYNC_CHECK("AES7 Sync Check", 7),
+ HDSPM_SYNC_CHECK("AES8 Sync Check", 8),
+ HDSPM_SYNC_CHECK("TCO Sync Check", 9),
+ HDSPM_SYNC_CHECK("SYNC IN Sync Check", 10),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("WC Frequency", 0),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES1 Frequency", 1),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES2 Frequency", 2),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES3 Frequency", 3),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES4 Frequency", 4),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES5 Frequency", 5),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES6 Frequency", 6),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES7 Frequency", 7),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9),
+ HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10),
HDSPM_LINE_OUT("Line Out", 0),
HDSPM_EMPHASIS("Emphasis", 0),
HDSPM_DOLBY("Non Audio", 0),
@@ -2842,6 +4400,19 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
HDSPM_QS_WIRE("Quad Speed Wire Mode", 0),
};
+
+
+/* Control elements for the optional TCO module */
+static struct snd_kcontrol_new snd_hdspm_controls_tco[] = {
+ HDSPM_TCO_SAMPLE_RATE("TCO Sample Rate", 0),
+ HDSPM_TCO_PULL("TCO Pull", 0),
+ HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0),
+ HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0),
+ HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0),
+ HDSPM_TCO_WORD_TERM("TCO Word Term", 0)
+};
+
+
static struct snd_kcontrol_new snd_hdspm_playback_mixer = HDSPM_PLAYBACK_MIXER;
@@ -2849,78 +4420,76 @@ static int hdspm_update_simple_mixer_controls(struct hdspm * hdspm)
{
int i;
- for (i = hdspm->ds_channels; i < hdspm->ss_channels; ++i) {
+ for (i = hdspm->ds_out_channels; i < hdspm->ss_out_channels; ++i) {
if (hdspm->system_sample_rate > 48000) {
hdspm->playback_mixer_ctls[i]->vd[0].access =
- SNDRV_CTL_ELEM_ACCESS_INACTIVE |
- SNDRV_CTL_ELEM_ACCESS_READ |
- SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+ SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE;
} else {
hdspm->playback_mixer_ctls[i]->vd[0].access =
- SNDRV_CTL_ELEM_ACCESS_READWRITE |
- SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+ SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE;
}
snd_ctl_notify(hdspm->card, SNDRV_CTL_EVENT_MASK_VALUE |
- SNDRV_CTL_EVENT_MASK_INFO,
- &hdspm->playback_mixer_ctls[i]->id);
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &hdspm->playback_mixer_ctls[i]->id);
}
return 0;
}
-static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm)
+static int snd_hdspm_create_controls(struct snd_card *card,
+ struct hdspm *hdspm)
{
unsigned int idx, limit;
int err;
struct snd_kcontrol *kctl;
+ struct snd_kcontrol_new *list = NULL;
- /* add control list first */
- if (hdspm->is_aes32) {
- struct snd_kcontrol_new aes_sync_ctl =
- HDSPM_AES_SYNC_CHECK("AES Lock Status", 0);
+ switch (hdspm->io_type) {
+ case MADI:
+ list = snd_hdspm_controls_madi;
+ limit = ARRAY_SIZE(snd_hdspm_controls_madi);
+ break;
+ case MADIface:
+ list = snd_hdspm_controls_madiface;
+ limit = ARRAY_SIZE(snd_hdspm_controls_madiface);
+ break;
+ case AIO:
+ list = snd_hdspm_controls_aio;
+ limit = ARRAY_SIZE(snd_hdspm_controls_aio);
+ break;
+ case RayDAT:
+ list = snd_hdspm_controls_raydat;
+ limit = ARRAY_SIZE(snd_hdspm_controls_raydat);
+ break;
+ case AES32:
+ list = snd_hdspm_controls_aes32;
+ limit = ARRAY_SIZE(snd_hdspm_controls_aes32);
+ break;
+ }
- for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_aes32);
- idx++) {
- err = snd_ctl_add(card,
- snd_ctl_new1(&snd_hdspm_controls_aes32[idx],
- hdspm));
- if (err < 0)
- return err;
- }
- for (idx = 1; idx <= 8; idx++) {
- aes_sync_ctl.index = idx;
- err = snd_ctl_add(card,
- snd_ctl_new1(&aes_sync_ctl, hdspm));
- if (err < 0)
- return err;
- }
- } else {
- for (idx = 0; idx < ARRAY_SIZE(snd_hdspm_controls_madi);
- idx++) {
+ if (NULL != list) {
+ for (idx = 0; idx < limit; idx++) {
err = snd_ctl_add(card,
- snd_ctl_new1(&snd_hdspm_controls_madi[idx],
- hdspm));
+ snd_ctl_new1(&list[idx], hdspm));
if (err < 0)
return err;
}
}
- /* Channel playback mixer as default control
- Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders,
- thats too * big for any alsamixer they are accessible via special
- IOCTL on hwdep and the mixer 2dimensional mixer control
- */
+ /* create simple 1:1 playback mixer controls */
snd_hdspm_playback_mixer.name = "Chn";
- limit = HDSPM_MAX_CHANNELS;
-
- /* The index values are one greater than the channel ID so that
- * alsamixer will display them correctly. We want to use the index
- * for fast lookup of the relevant channel, but if we use it at all,
- * most ALSA software does the wrong thing with it ...
- */
-
+ if (hdspm->system_sample_rate >= 128000) {
+ limit = hdspm->qs_out_channels;
+ } else if (hdspm->system_sample_rate >= 64000) {
+ limit = hdspm->ds_out_channels;
+ } else {
+ limit = hdspm->ss_out_channels;
+ }
for (idx = 0; idx < limit; ++idx) {
snd_hdspm_playback_mixer.index = idx + 1;
kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm);
@@ -2930,11 +4499,24 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm
hdspm->playback_mixer_ctls[idx] = kctl;
}
+
+ if (hdspm->tco) {
+ /* add tco control elements */
+ list = snd_hdspm_controls_tco;
+ limit = ARRAY_SIZE(snd_hdspm_controls_tco);
+ for (idx = 0; idx < limit; idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&list[idx], hdspm));
+ if (err < 0)
+ return err;
+ }
+ }
+
return 0;
}
/*------------------------------------------------------------
- /proc interface
+ /proc interface
------------------------------------------------------------*/
static void
@@ -2942,72 +4524,178 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
- unsigned int status;
- unsigned int status2;
+ unsigned int status, status2, control, freq;
+
char *pref_sync_ref;
char *autosync_ref;
char *system_clock_mode;
- char *clock_source;
char *insel;
- char *syncref;
int x, x2;
+ /* TCO stuff */
+ int a, ltc, frames, seconds, minutes, hours;
+ unsigned int period;
+ u64 freq_const = 0;
+ u32 rate;
+
status = hdspm_read(hdspm, HDSPM_statusRegister);
status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+ control = hdspm->control_register;
+ freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
- hdspm->card_name, hdspm->card->number + 1,
- hdspm->firmware_rev,
- (status2 & HDSPM_version0) |
- (status2 & HDSPM_version1) | (status2 &
- HDSPM_version2));
+ hdspm->card_name, hdspm->card->number + 1,
+ hdspm->firmware_rev,
+ (status2 & HDSPM_version0) |
+ (status2 & HDSPM_version1) | (status2 &
+ HDSPM_version2));
+
+ snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
+ (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
+ (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF);
snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
- hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+ hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
snd_iprintf(buffer, "--- System ---\n");
snd_iprintf(buffer,
- "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
- status & HDSPM_audioIRQPending,
- (status & HDSPM_midi0IRQPending) ? 1 : 0,
- (status & HDSPM_midi1IRQPending) ? 1 : 0,
- hdspm->irq_count);
+ "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+ status & HDSPM_audioIRQPending,
+ (status & HDSPM_midi0IRQPending) ? 1 : 0,
+ (status & HDSPM_midi1IRQPending) ? 1 : 0,
+ hdspm->irq_count);
snd_iprintf(buffer,
- "HW pointer: id = %d, rawptr = %d (%d->%d) "
- "estimated= %ld (bytes)\n",
- ((status & HDSPM_BufferID) ? 1 : 0),
- (status & HDSPM_BufferPositionMask),
- (status & HDSPM_BufferPositionMask) %
- (2 * (int)hdspm->period_bytes),
- ((status & HDSPM_BufferPositionMask) - 64) %
- (2 * (int)hdspm->period_bytes),
- (long) hdspm_hw_pointer(hdspm) * 4);
+ "HW pointer: id = %d, rawptr = %d (%d->%d) "
+ "estimated= %ld (bytes)\n",
+ ((status & HDSPM_BufferID) ? 1 : 0),
+ (status & HDSPM_BufferPositionMask),
+ (status & HDSPM_BufferPositionMask) %
+ (2 * (int)hdspm->period_bytes),
+ ((status & HDSPM_BufferPositionMask) - 64) %
+ (2 * (int)hdspm->period_bytes),
+ (long) hdspm_hw_pointer(hdspm) * 4);
snd_iprintf(buffer,
- "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
- hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
- hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
- hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
- hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+ "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
snd_iprintf(buffer,
- "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
- "status2=0x%x\n",
- hdspm->control_register, hdspm->control2_register,
- status, status2);
+ "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
+ snd_iprintf(buffer,
+ "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
+ "status2=0x%x\n",
+ hdspm->control_register, hdspm->control2_register,
+ status, status2);
+ if (status & HDSPM_tco_detect) {
+ snd_iprintf(buffer, "TCO module detected.\n");
+ a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
+ if (a & HDSPM_TCO1_LTC_Input_valid) {
+ snd_iprintf(buffer, " LTC valid, ");
+ switch (a & (HDSPM_TCO1_LTC_Format_LSB |
+ HDSPM_TCO1_LTC_Format_MSB)) {
+ case 0:
+ snd_iprintf(buffer, "24 fps, ");
+ break;
+ case HDSPM_TCO1_LTC_Format_LSB:
+ snd_iprintf(buffer, "25 fps, ");
+ break;
+ case HDSPM_TCO1_LTC_Format_MSB:
+ snd_iprintf(buffer, "29.97 fps, ");
+ break;
+ default:
+ snd_iprintf(buffer, "30 fps, ");
+ break;
+ }
+ if (a & HDSPM_TCO1_set_drop_frame_flag) {
+ snd_iprintf(buffer, "drop frame\n");
+ } else {
+ snd_iprintf(buffer, "full frame\n");
+ }
+ } else {
+ snd_iprintf(buffer, " no LTC\n");
+ }
+ if (a & HDSPM_TCO1_Video_Input_Format_NTSC) {
+ snd_iprintf(buffer, " Video: NTSC\n");
+ } else if (a & HDSPM_TCO1_Video_Input_Format_PAL) {
+ snd_iprintf(buffer, " Video: PAL\n");
+ } else {
+ snd_iprintf(buffer, " No video\n");
+ }
+ if (a & HDSPM_TCO1_TCO_lock) {
+ snd_iprintf(buffer, " Sync: lock\n");
+ } else {
+ snd_iprintf(buffer, " Sync: no lock\n");
+ }
+
+ switch (hdspm->io_type) {
+ case MADI:
+ case AES32:
+ freq_const = 110069313433624ULL;
+ break;
+ case RayDAT:
+ case AIO:
+ freq_const = 104857600000000ULL;
+ break;
+ case MADIface:
+ break; /* no TCO possible */
+ }
+
+ period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
+ snd_iprintf(buffer, " period: %u\n", period);
+
+
+ /* rate = freq_const/period; */
+ rate = div_u64(freq_const, period);
+
+ if (control & HDSPM_QuadSpeed) {
+ rate *= 4;
+ } else if (control & HDSPM_DoubleSpeed) {
+ rate *= 2;
+ }
+
+ snd_iprintf(buffer, " Frequency: %u Hz\n",
+ (unsigned int) rate);
+
+ ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
+ frames = ltc & 0xF;
+ ltc >>= 4;
+ frames += (ltc & 0x3) * 10;
+ ltc >>= 4;
+ seconds = ltc & 0xF;
+ ltc >>= 4;
+ seconds += (ltc & 0x7) * 10;
+ ltc >>= 4;
+ minutes = ltc & 0xF;
+ ltc >>= 4;
+ minutes += (ltc & 0x7) * 10;
+ ltc >>= 4;
+ hours = ltc & 0xF;
+ ltc >>= 4;
+ hours += (ltc & 0x3) * 10;
+ snd_iprintf(buffer,
+ " LTC In: %02d:%02d:%02d:%02d\n",
+ hours, minutes, seconds, frames);
+
+ } else {
+ snd_iprintf(buffer, "No TCO module detected.\n");
+ }
snd_iprintf(buffer, "--- Settings ---\n");
x = 1 << (6 + hdspm_decode_latency(hdspm->control_register &
- HDSPM_LatencyMask));
+ HDSPM_LatencyMask));
snd_iprintf(buffer,
- "Size (Latency): %d samples (2 periods of %lu bytes)\n",
- x, (unsigned long) hdspm->period_bytes);
+ "Size (Latency): %d samples (2 periods of %lu bytes)\n",
+ x, (unsigned long) hdspm->period_bytes);
- snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n",
- (hdspm->control_register & HDSPM_LineOut) ? "on " : "off",
- (hdspm->precise_ptr) ? "on" : "off");
+ snd_iprintf(buffer, "Line out: %s\n",
+ (hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
switch (hdspm->control_register & HDSPM_InputMask) {
case HDSPM_InputOptical:
@@ -3017,63 +4705,22 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
insel = "Coaxial";
break;
default:
- insel = "Unknown";
- }
-
- switch (hdspm->control_register & HDSPM_SyncRefMask) {
- case HDSPM_SyncRef_Word:
- syncref = "WordClock";
- break;
- case HDSPM_SyncRef_MADI:
- syncref = "MADI";
- break;
- default:
- syncref = "Unknown";
+ insel = "Unkown";
}
- snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel,
- syncref);
snd_iprintf(buffer,
- "ClearTrackMarker = %s, Transmit in %s Channel Mode, "
- "Auto Input %s\n",
- (hdspm->
- control_register & HDSPM_clr_tms) ? "on" : "off",
- (hdspm->
- control_register & HDSPM_TX_64ch) ? "64" : "56",
- (hdspm->
- control_register & HDSPM_AutoInp) ? "on" : "off");
+ "ClearTrackMarker = %s, Transmit in %s Channel Mode, "
+ "Auto Input %s\n",
+ (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off",
+ (hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56",
+ (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off");
+
- switch (hdspm_clock_source(hdspm)) {
- case HDSPM_CLOCK_SOURCE_AUTOSYNC:
- clock_source = "AutoSync";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
- clock_source = "Internal 32 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
- clock_source = "Internal 44.1 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
- clock_source = "Internal 48 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
- clock_source = "Internal 64 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
- clock_source = "Internal 88.2 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
- clock_source = "Internal 96 kHz";
- break;
- default:
- clock_source = "Error";
- }
- snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
if (!(hdspm->control_register & HDSPM_ClockModeMaster))
- system_clock_mode = "Slave";
+ system_clock_mode = "AutoSync";
else
system_clock_mode = "Master";
- snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
+ snd_iprintf(buffer, "AutoSync Reference: %s\n", system_clock_mode);
switch (hdspm_pref_sync_ref(hdspm)) {
case HDSPM_SYNC_FROM_WORD:
@@ -3082,15 +4729,21 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
case HDSPM_SYNC_FROM_MADI:
pref_sync_ref = "MADI Sync";
break;
+ case HDSPM_SYNC_FROM_TCO:
+ pref_sync_ref = "TCO";
+ break;
+ case HDSPM_SYNC_FROM_SYNC_IN:
+ pref_sync_ref = "Sync In";
+ break;
default:
pref_sync_ref = "XXXX Clock";
break;
}
snd_iprintf(buffer, "Preferred Sync Reference: %s\n",
- pref_sync_ref);
+ pref_sync_ref);
snd_iprintf(buffer, "System Clock Frequency: %d\n",
- hdspm->system_sample_rate);
+ hdspm->system_sample_rate);
snd_iprintf(buffer, "--- Status:\n");
@@ -3099,12 +4752,18 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
x2 = status2 & HDSPM_wcSync;
snd_iprintf(buffer, "Inputs MADI=%s, WordClock=%s\n",
- (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") :
- "NoLock",
- (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") :
- "NoLock");
+ (status & HDSPM_madiLock) ? (x ? "Sync" : "Lock") :
+ "NoLock",
+ (status2 & HDSPM_wcLock) ? (x2 ? "Sync" : "Lock") :
+ "NoLock");
switch (hdspm_autosync_ref(hdspm)) {
+ case HDSPM_AUTOSYNC_FROM_SYNC_IN:
+ autosync_ref = "Sync In";
+ break;
+ case HDSPM_AUTOSYNC_FROM_TCO:
+ autosync_ref = "TCO";
+ break;
case HDSPM_AUTOSYNC_FROM_WORD:
autosync_ref = "Word Clock";
break;
@@ -3119,15 +4778,15 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
break;
}
snd_iprintf(buffer,
- "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n",
- autosync_ref, hdspm_external_sample_rate(hdspm),
- (status & HDSPM_madiFreqMask) >> 22,
- (status2 & HDSPM_wcFreqMask) >> 5);
+ "AutoSync: Reference= %s, Freq=%d (MADI = %d, Word = %d)\n",
+ autosync_ref, hdspm_external_sample_rate(hdspm),
+ (status & HDSPM_madiFreqMask) >> 22,
+ (status2 & HDSPM_wcFreqMask) >> 5);
snd_iprintf(buffer, "Input: %s, Mode=%s\n",
- (status & HDSPM_AB_int) ? "Coax" : "Optical",
- (status & HDSPM_RX_64ch) ? "64 channels" :
- "56 channels");
+ (status & HDSPM_AB_int) ? "Coax" : "Optical",
+ (status & HDSPM_RX_64ch) ? "64 channels" :
+ "56 channels");
snd_iprintf(buffer, "\n");
}
@@ -3142,8 +4801,6 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
unsigned int timecode;
int pref_syncref;
char *autosync_ref;
- char *system_clock_mode;
- char *clock_source;
int x;
status = hdspm_read(hdspm, HDSPM_statusRegister);
@@ -3183,24 +4840,27 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
snd_iprintf(buffer,
- "Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, "
- "timecode=0x%x\n",
- hdspm->control_register,
- status, status2, timecode);
+ "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
+ hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
+ hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
+ snd_iprintf(buffer,
+ "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
+ "status2=0x%x\n",
+ hdspm->control_register, hdspm->control2_register,
+ status, status2);
snd_iprintf(buffer, "--- Settings ---\n");
x = 1 << (6 + hdspm_decode_latency(hdspm->control_register &
- HDSPM_LatencyMask));
+ HDSPM_LatencyMask));
snd_iprintf(buffer,
"Size (Latency): %d samples (2 periods of %lu bytes)\n",
x, (unsigned long) hdspm->period_bytes);
- snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n",
+ snd_iprintf(buffer, "Line out: %s\n",
(hdspm->
- control_register & HDSPM_LineOut) ? "on " : "off",
- (hdspm->precise_ptr) ? "on" : "off");
+ control_register & HDSPM_LineOut) ? "on " : "off");
snd_iprintf(buffer,
"ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
@@ -3211,46 +4871,6 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
(hdspm->
control_register & HDSPM_Dolby) ? "on" : "off");
- switch (hdspm_clock_source(hdspm)) {
- case HDSPM_CLOCK_SOURCE_AUTOSYNC:
- clock_source = "AutoSync";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_32KHZ:
- clock_source = "Internal 32 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_44_1KHZ:
- clock_source = "Internal 44.1 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_48KHZ:
- clock_source = "Internal 48 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_64KHZ:
- clock_source = "Internal 64 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_88_2KHZ:
- clock_source = "Internal 88.2 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_96KHZ:
- clock_source = "Internal 96 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_128KHZ:
- clock_source = "Internal 128 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_176_4KHZ:
- clock_source = "Internal 176.4 kHz";
- break;
- case HDSPM_CLOCK_SOURCE_INTERNAL_192KHZ:
- clock_source = "Internal 192 kHz";
- break;
- default:
- clock_source = "Error";
- }
- snd_iprintf(buffer, "Sample Clock Source: %s\n", clock_source);
- if (!(hdspm->control_register & HDSPM_ClockModeMaster))
- system_clock_mode = "Slave";
- else
- system_clock_mode = "Master";
- snd_iprintf(buffer, "System Clock Mode: %s\n", system_clock_mode);
pref_syncref = hdspm_pref_sync_ref(hdspm);
if (pref_syncref == 0)
@@ -3274,38 +4894,108 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
snd_iprintf(buffer, "--- Status:\n");
snd_iprintf(buffer, "Word: %s Frequency: %d\n",
- (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock",
+ (status & HDSPM_AES32_wcLock) ? "Sync " : "No Lock",
HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
for (x = 0; x < 8; x++) {
snd_iprintf(buffer, "AES%d: %s Frequency: %d\n",
x+1,
(status2 & (HDSPM_LockAES >> x)) ?
- "Sync ": "No Lock",
+ "Sync " : "No Lock",
HDSPM_bit2freq((timecode >> (4*x)) & 0xF));
}
switch (hdspm_autosync_ref(hdspm)) {
- case HDSPM_AES32_AUTOSYNC_FROM_NONE: autosync_ref="None"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_WORD: autosync_ref="Word Clock"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES1: autosync_ref="AES1"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES2: autosync_ref="AES2"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES3: autosync_ref="AES3"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES4: autosync_ref="AES4"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES5: autosync_ref="AES5"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES6: autosync_ref="AES6"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES7: autosync_ref="AES7"; break;
- case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref="AES8"; break;
- default: autosync_ref = "---"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_NONE:
+ autosync_ref = "None"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_WORD:
+ autosync_ref = "Word Clock"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES1:
+ autosync_ref = "AES1"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES2:
+ autosync_ref = "AES2"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES3:
+ autosync_ref = "AES3"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES4:
+ autosync_ref = "AES4"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES5:
+ autosync_ref = "AES5"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES6:
+ autosync_ref = "AES6"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES7:
+ autosync_ref = "AES7"; break;
+ case HDSPM_AES32_AUTOSYNC_FROM_AES8:
+ autosync_ref = "AES8"; break;
+ default:
+ autosync_ref = "---"; break;
}
snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
snd_iprintf(buffer, "\n");
}
+static void
+snd_hdspm_proc_read_raydat(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = entry->private_data;
+ unsigned int status1, status2, status3, control, i;
+ unsigned int lock, sync;
+
+ status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */
+ status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */
+ status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */
+
+ control = hdspm->control_register;
+
+ snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1);
+ snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2);
+ snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3);
+
+
+ snd_iprintf(buffer, "\n*** CLOCK MODE\n\n");
+
+ snd_iprintf(buffer, "Clock mode : %s\n",
+ (hdspm_system_clock_mode(hdspm) == 0) ? "master" : "slave");
+ snd_iprintf(buffer, "System frequency: %d Hz\n",
+ hdspm_get_system_sample_rate(hdspm));
+
+ snd_iprintf(buffer, "\n*** INPUT STATUS\n\n");
+
+ lock = 0x1;
+ sync = 0x100;
+
+ for (i = 0; i < 8; i++) {
+ snd_iprintf(buffer, "s1_input %d: Lock %d, Sync %d, Freq %s\n",
+ i,
+ (status1 & lock) ? 1 : 0,
+ (status1 & sync) ? 1 : 0,
+ texts_freq[(status2 >> (i * 4)) & 0xF]);
+
+ lock = lock<<1;
+ sync = sync<<1;
+ }
+
+ snd_iprintf(buffer, "WC input: Lock %d, Sync %d, Freq %s\n",
+ (status1 & 0x1000000) ? 1 : 0,
+ (status1 & 0x2000000) ? 1 : 0,
+ texts_freq[(status1 >> 16) & 0xF]);
+
+ snd_iprintf(buffer, "TCO input: Lock %d, Sync %d, Freq %s\n",
+ (status1 & 0x4000000) ? 1 : 0,
+ (status1 & 0x8000000) ? 1 : 0,
+ texts_freq[(status1 >> 20) & 0xF]);
+
+ snd_iprintf(buffer, "SYNC IN: Lock %d, Sync %d, Freq %s\n",
+ (status3 & 0x400) ? 1 : 0,
+ (status3 & 0x800) ? 1 : 0,
+ texts_freq[(status2 >> 12) & 0xF]);
+
+}
+
#ifdef CONFIG_SND_DEBUG
static void
-snd_hdspm_proc_read_debug(struct snd_info_entry * entry,
+snd_hdspm_proc_read_debug(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
@@ -3322,16 +5012,68 @@ snd_hdspm_proc_read_debug(struct snd_info_entry * entry,
#endif
+static void snd_hdspm_proc_ports_in(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = entry->private_data;
+ int i;
+
+ snd_iprintf(buffer, "# generated by hdspm\n");
+
+ for (i = 0; i < hdspm->max_channels_in; i++) {
+ snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_in[i]);
+ }
+}
-static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
+static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdspm *hdspm = entry->private_data;
+ int i;
+
+ snd_iprintf(buffer, "# generated by hdspm\n");
+
+ for (i = 0; i < hdspm->max_channels_out; i++) {
+ snd_iprintf(buffer, "%d=%s\n", i+1, hdspm->port_names_out[i]);
+ }
+}
+
+
+static void __devinit snd_hdspm_proc_init(struct hdspm *hdspm)
{
struct snd_info_entry *entry;
- if (!snd_card_proc_new(hdspm->card, "hdspm", &entry))
- snd_info_set_text_ops(entry, hdspm,
- hdspm->is_aes32 ?
- snd_hdspm_proc_read_aes32 :
- snd_hdspm_proc_read_madi);
+ if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) {
+ switch (hdspm->io_type) {
+ case AES32:
+ snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_aes32);
+ break;
+ case MADI:
+ snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_madi);
+ break;
+ case MADIface:
+ /* snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_madiface); */
+ break;
+ case RayDAT:
+ snd_info_set_text_ops(entry, hdspm,
+ snd_hdspm_proc_read_raydat);
+ break;
+ case AIO:
+ break;
+ }
+ }
+
+ if (!snd_card_proc_new(hdspm->card, "ports.in", &entry)) {
+ snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_in);
+ }
+
+ if (!snd_card_proc_new(hdspm->card, "ports.out", &entry)) {
+ snd_info_set_text_ops(entry, hdspm, snd_hdspm_proc_ports_out);
+ }
+
#ifdef CONFIG_SND_DEBUG
/* debug file to read all hdspm registers */
if (!snd_card_proc_new(hdspm->card, "debug", &entry))
@@ -3341,47 +5083,48 @@ static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm)
}
/*------------------------------------------------------------
- hdspm intitialize
+ hdspm intitialize
------------------------------------------------------------*/
static int snd_hdspm_set_defaults(struct hdspm * hdspm)
{
- unsigned int i;
-
/* ASSUMPTION: hdspm->lock is either held, or there is no need to
hold it (e.g. during module initialization).
- */
+ */
/* set defaults: */
- if (hdspm->is_aes32)
+ hdspm->settings_register = 0;
+
+ switch (hdspm->io_type) {
+ case MADI:
+ case MADIface:
+ hdspm->control_register =
+ 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
+ break;
+
+ case RayDAT:
+ case AIO:
+ hdspm->settings_register = 0x1 + 0x1000;
+ /* Magic values are: LAT_0, LAT_2, Master, freq1, tx64ch, inp_0,
+ * line_out */
+ hdspm->control_register =
+ 0x2 + 0x8 + 0x10 + 0x80 + 0x400 + 0x4000 + 0x1000000;
+ break;
+
+ case AES32:
hdspm->control_register =
HDSPM_ClockModeMaster | /* Master Cloack Mode on */
- hdspm_encode_latency(7) | /* latency maximum =
- * 8192 samples
- */
+ hdspm_encode_latency(7) | /* latency max=8192samples */
HDSPM_SyncRef0 | /* AES1 is syncclock */
HDSPM_LineOut | /* Analog output in */
HDSPM_Professional; /* Professional mode */
- else
- hdspm->control_register =
- HDSPM_ClockModeMaster | /* Master Cloack Mode on */
- hdspm_encode_latency(7) | /* latency maximum =
- * 8192 samples
- */
- HDSPM_InputCoaxial | /* Input Coax not Optical */
- HDSPM_SyncRef_MADI | /* Madi is syncclock */
- HDSPM_LineOut | /* Analog output in */
- HDSPM_TX_64ch | /* transmit in 64ch mode */
- HDSPM_AutoInp; /* AutoInput chossing (takeover) */
-
- /* ! HDSPM_Frequency0|HDSPM_Frequency1 = 44.1khz */
- /* ! HDSPM_DoubleSpeed HDSPM_QuadSpeed = normal speed */
- /* ! HDSPM_clr_tms = do not clear bits in track marks */
+ break;
+ }
hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
- if (!hdspm->is_aes32) {
+ if (AES32 == hdspm->io_type) {
/* No control2 register for AES32 */
#ifdef SNDRV_BIG_ENDIAN
hdspm->control2_register = HDSPM_BIGENDIAN_MODE;
@@ -3397,57 +5140,59 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
- if (line_outs_monitor[hdspm->dev]) {
-
- snd_printk(KERN_INFO "HDSPM: "
- "sending all playback streams to line outs.\n");
-
- for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) {
- if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN))
- return -EIO;
- }
+ if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) {
+ hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
}
/* set a default rate so that the channel map is set up. */
- hdspm->channel_map = channel_map_madi_ss;
- hdspm_set_rate(hdspm, 44100, 1);
+ hdspm_set_rate(hdspm, 48000, 1);
return 0;
}
/*------------------------------------------------------------
- interrupt
+ interrupt
------------------------------------------------------------*/
static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
{
struct hdspm *hdspm = (struct hdspm *) dev_id;
unsigned int status;
- int audio;
- int midi0;
- int midi1;
- unsigned int midi0status;
- unsigned int midi1status;
- int schedule = 0;
+ int i, audio, midi, schedule = 0;
+ /* cycles_t now; */
status = hdspm_read(hdspm, HDSPM_statusRegister);
audio = status & HDSPM_audioIRQPending;
- midi0 = status & HDSPM_midi0IRQPending;
- midi1 = status & HDSPM_midi1IRQPending;
+ midi = status & (HDSPM_midi0IRQPending | HDSPM_midi1IRQPending |
+ HDSPM_midi2IRQPending | HDSPM_midi3IRQPending);
+
+ /* now = get_cycles(); */
+ /**
+ * LAT_2..LAT_0 period counter (win) counter (mac)
+ * 6 4096 ~256053425 ~514672358
+ * 5 2048 ~128024983 ~257373821
+ * 4 1024 ~64023706 ~128718089
+ * 3 512 ~32005945 ~64385999
+ * 2 256 ~16003039 ~32260176
+ * 1 128 ~7998738 ~16194507
+ * 0 64 ~3998231 ~8191558
+ **/
+ /*
+ snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n",
+ now-hdspm->last_interrupt, status & 0xFFC0);
+ hdspm->last_interrupt = now;
+ */
- if (!audio && !midi0 && !midi1)
+ if (!audio && !midi)
return IRQ_NONE;
hdspm_write(hdspm, HDSPM_interruptConfirmation, 0);
hdspm->irq_count++;
- midi0status = hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xff;
- midi1status = hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xff;
if (audio) {
-
if (hdspm->capture_substream)
snd_pcm_period_elapsed(hdspm->capture_substream);
@@ -3455,118 +5200,44 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
snd_pcm_period_elapsed(hdspm->playback_substream);
}
- if (midi0 && midi0status) {
- /* we disable interrupts for this input until processing
- * is done
- */
- hdspm->control_register &= ~HDSPM_Midi0InterruptEnable;
- hdspm_write(hdspm, HDSPM_controlRegister,
- hdspm->control_register);
- hdspm->midi[0].pending = 1;
- schedule = 1;
- }
- if (midi1 && midi1status) {
- /* we disable interrupts for this input until processing
- * is done
- */
- hdspm->control_register &= ~HDSPM_Midi1InterruptEnable;
- hdspm_write(hdspm, HDSPM_controlRegister,
- hdspm->control_register);
- hdspm->midi[1].pending = 1;
- schedule = 1;
+ if (midi) {
+ i = 0;
+ while (i < hdspm->midiPorts) {
+ if ((hdspm_read(hdspm,
+ hdspm->midi[i].statusIn) & 0xff) &&
+ (status & hdspm->midi[i].irq)) {
+ /* we disable interrupts for this input until
+ * processing is done
+ */
+ hdspm->control_register &= ~hdspm->midi[i].ie;
+ hdspm_write(hdspm, HDSPM_controlRegister,
+ hdspm->control_register);
+ hdspm->midi[i].pending = 1;
+ schedule = 1;
+ }
+
+ i++;
+ }
+
+ if (schedule)
+ tasklet_hi_schedule(&hdspm->midi_tasklet);
}
- if (schedule)
- tasklet_schedule(&hdspm->midi_tasklet);
+
return IRQ_HANDLED;
}
/*------------------------------------------------------------
- pcm interface
+ pcm interface
------------------------------------------------------------*/
-static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream *
- substream)
+static snd_pcm_uframes_t snd_hdspm_hw_pointer(struct snd_pcm_substream
+ *substream)
{
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
return hdspm_hw_pointer(hdspm);
}
-static char *hdspm_channel_buffer_location(struct hdspm * hdspm,
- int stream, int channel)
-{
- int mapped_channel;
-
- if (snd_BUG_ON(channel < 0 || channel >= HDSPM_MAX_CHANNELS))
- return NULL;
-
- mapped_channel = hdspm->channel_map[channel];
- if (mapped_channel < 0)
- return NULL;
-
- if (stream == SNDRV_PCM_STREAM_CAPTURE)
- return hdspm->capture_buffer +
- mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
- else
- return hdspm->playback_buffer +
- mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
-}
-
-
-/* dont know why need it ??? */
-static int snd_hdspm_playback_copy(struct snd_pcm_substream *substream,
- int channel, snd_pcm_uframes_t pos,
- void __user *src, snd_pcm_uframes_t count)
-{
- struct hdspm *hdspm = snd_pcm_substream_chip(substream);
- char *channel_buf;
-
- if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
- return -EINVAL;
-
- channel_buf =
- hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
- channel);
-
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
-
- return copy_from_user(channel_buf + pos * 4, src, count * 4);
-}
-
-static int snd_hdspm_capture_copy(struct snd_pcm_substream *substream,
- int channel, snd_pcm_uframes_t pos,
- void __user *dst, snd_pcm_uframes_t count)
-{
- struct hdspm *hdspm = snd_pcm_substream_chip(substream);
- char *channel_buf;
-
- if (snd_BUG_ON(pos + count > HDSPM_CHANNEL_BUFFER_BYTES / 4))
- return -EINVAL;
-
- channel_buf =
- hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
- channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- return copy_to_user(dst, channel_buf + pos * 4, count * 4);
-}
-
-static int snd_hdspm_hw_silence(struct snd_pcm_substream *substream,
- int channel, snd_pcm_uframes_t pos,
- snd_pcm_uframes_t count)
-{
- struct hdspm *hdspm = snd_pcm_substream_chip(substream);
- char *channel_buf;
-
- channel_buf =
- hdspm_channel_buffer_location(hdspm, substream->pstr->stream,
- channel);
- if (snd_BUG_ON(!channel_buf))
- return -EIO;
- memset(channel_buf + pos * 4, 0, count * 4);
- return 0;
-}
static int snd_hdspm_reset(struct snd_pcm_substream *substream)
{
@@ -3589,7 +5260,7 @@ static int snd_hdspm_reset(struct snd_pcm_substream *substream)
snd_pcm_group_for_each_entry(s, substream) {
if (s == other) {
oruntime->status->hw_ptr =
- runtime->status->hw_ptr;
+ runtime->status->hw_ptr;
break;
}
}
@@ -3621,19 +5292,19 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
/* The other stream is open, and not by the same
task as this one. Make sure that the parameters
that matter are the same.
- */
+ */
if (params_rate(params) != hdspm->system_sample_rate) {
spin_unlock_irq(&hdspm->lock);
_snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_RATE);
+ SNDRV_PCM_HW_PARAM_RATE);
return -EBUSY;
}
if (params_period_size(params) != hdspm->period_bytes / 4) {
spin_unlock_irq(&hdspm->lock);
_snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return -EBUSY;
}
@@ -3646,18 +5317,20 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
spin_lock_irq(&hdspm->lock);
err = hdspm_set_rate(hdspm, params_rate(params), 0);
if (err < 0) {
+ snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err);
spin_unlock_irq(&hdspm->lock);
_snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_RATE);
+ SNDRV_PCM_HW_PARAM_RATE);
return err;
}
spin_unlock_irq(&hdspm->lock);
err = hdspm_set_interrupt_interval(hdspm,
- params_period_size(params));
+ params_period_size(params));
if (err < 0) {
+ snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err);
_snd_pcm_hw_param_setempty(params,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
return err;
}
@@ -3667,10 +5340,13 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
/* malloc all buffer even if not enabled to get sure */
/* Update for MADI rev 204: we need to allocate for all channels,
* otherwise it doesn't work at 96kHz */
+
err =
- snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
- if (err < 0)
+ snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES);
+ if (err < 0) {
+ snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err);
return err;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -3681,7 +5357,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
snd_hdspm_enable_out(hdspm, i, 1);
hdspm->playback_buffer =
- (unsigned char *) substream->runtime->dma_area;
+ (unsigned char *) substream->runtime->dma_area;
snd_printdd("Allocated sample buffer for playback at %p\n",
hdspm->playback_buffer);
} else {
@@ -3692,23 +5368,40 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream,
snd_hdspm_enable_in(hdspm, i, 1);
hdspm->capture_buffer =
- (unsigned char *) substream->runtime->dma_area;
+ (unsigned char *) substream->runtime->dma_area;
snd_printdd("Allocated sample buffer for capture at %p\n",
hdspm->capture_buffer);
}
+
/*
snd_printdd("Allocated sample buffer for %s at 0x%08X\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
"playback" : "capture",
snd_pcm_sgbuf_get_addr(substream, 0));
- */
+ */
/*
- snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- "playback" : "capture",
- params_rate(params), params_channels(params),
- params_buffer_size(params));
- */
+ snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "playback" : "capture",
+ params_rate(params), params_channels(params),
+ params_buffer_size(params));
+ */
+
+
+ /* Switch to native float format if requested */
+ if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
+ if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
+ snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n");
+
+ hdspm->control_register |= HDSPe_FLOAT_FORMAT;
+ } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) {
+ if (hdspm->control_register & HDSPe_FLOAT_FORMAT)
+ snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n");
+
+ hdspm->control_register &= ~HDSPe_FLOAT_FORMAT;
+ }
+ hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+
return 0;
}
@@ -3719,14 +5412,14 @@ static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* params_channels(params) should be enough,
+ /* params_channels(params) should be enough,
but to get sure in case of error */
- for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
+ for (i = 0; i < hdspm->max_channels_out; ++i)
snd_hdspm_enable_out(hdspm, i, 0);
hdspm->playback_buffer = NULL;
} else {
- for (i = 0; i < HDSPM_MAX_CHANNELS; ++i)
+ for (i = 0; i < hdspm->max_channels_in; ++i)
snd_hdspm_enable_in(hdspm, i, 0);
hdspm->capture_buffer = NULL;
@@ -3738,37 +5431,58 @@ static int snd_hdspm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+
static int snd_hdspm_channel_info(struct snd_pcm_substream *substream,
- struct snd_pcm_channel_info * info)
+ struct snd_pcm_channel_info *info)
{
struct hdspm *hdspm = snd_pcm_substream_chip(substream);
- int mapped_channel;
- if (snd_BUG_ON(info->channel >= HDSPM_MAX_CHANNELS))
- return -EINVAL;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) {
+ snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel);
+ return -EINVAL;
+ }
- mapped_channel = hdspm->channel_map[info->channel];
- if (mapped_channel < 0)
- return -EINVAL;
+ if (hdspm->channel_map_out[info->channel] < 0) {
+ snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel);
+ return -EINVAL;
+ }
+
+ info->offset = hdspm->channel_map_out[info->channel] *
+ HDSPM_CHANNEL_BUFFER_BYTES;
+ } else {
+ if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) {
+ snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel);
+ return -EINVAL;
+ }
+
+ if (hdspm->channel_map_in[info->channel] < 0) {
+ snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel);
+ return -EINVAL;
+ }
+
+ info->offset = hdspm->channel_map_in[info->channel] *
+ HDSPM_CHANNEL_BUFFER_BYTES;
+ }
- info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES;
info->first = 0;
info->step = 32;
return 0;
}
+
static int snd_hdspm_ioctl(struct snd_pcm_substream *substream,
- unsigned int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
switch (cmd) {
case SNDRV_PCM_IOCTL1_RESET:
return snd_hdspm_reset(substream);
case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
- {
- struct snd_pcm_channel_info *info = arg;
- return snd_hdspm_channel_info(substream, info);
- }
+ {
+ struct snd_pcm_channel_info *info = arg;
+ return snd_hdspm_channel_info(substream, info);
+ }
default:
break;
}
@@ -3815,19 +5529,19 @@ static int snd_hdspm_trigger(struct snd_pcm_substream *substream, int cmd)
}
if (cmd == SNDRV_PCM_TRIGGER_START) {
if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK))
- && substream->stream ==
- SNDRV_PCM_STREAM_CAPTURE)
+ && substream->stream ==
+ SNDRV_PCM_STREAM_CAPTURE)
hdspm_silence_playback(hdspm);
} else {
if (running &&
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
hdspm_silence_playback(hdspm);
}
} else {
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
hdspm_silence_playback(hdspm);
}
- _ok:
+_ok:
snd_pcm_trigger_done(substream, substream);
if (!hdspm->running && running)
hdspm_start_audio(hdspm);
@@ -3844,8 +5558,18 @@ static int snd_hdspm_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static unsigned int period_sizes[] =
- { 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
+static unsigned int period_sizes_old[] = {
+ 64, 128, 256, 512, 1024, 2048, 4096
+};
+
+static unsigned int period_sizes_new[] = {
+ 32, 64, 128, 256, 512, 1024, 2048, 4096
+};
+
+/* RayDAT and AIO always have a buffer of 16384 samples per channel */
+static unsigned int raydat_aio_buffer_sizes[] = {
+ 16384
+};
static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
.info = (SNDRV_PCM_INFO_MMAP |
@@ -3866,9 +5590,9 @@ static struct snd_pcm_hardware snd_hdspm_playback_subinfo = {
.buffer_bytes_max =
HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
.period_bytes_min = (64 * 4),
- .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
+ .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS,
.periods_min = 2,
- .periods_max = 2,
+ .periods_max = 512,
.fifo_size = 0
};
@@ -3891,20 +5615,66 @@ static struct snd_pcm_hardware snd_hdspm_capture_subinfo = {
.buffer_bytes_max =
HDSPM_CHANNEL_BUFFER_BYTES * HDSPM_MAX_CHANNELS,
.period_bytes_min = (64 * 4),
- .period_bytes_max = (8192 * 4) * HDSPM_MAX_CHANNELS,
+ .period_bytes_max = (4096 * 4) * HDSPM_MAX_CHANNELS,
.periods_min = 2,
- .periods_max = 2,
+ .periods_max = 512,
.fifo_size = 0
};
-static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes = {
- .count = ARRAY_SIZE(period_sizes),
- .list = period_sizes,
+static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_old = {
+ .count = ARRAY_SIZE(period_sizes_old),
+ .list = period_sizes_old,
.mask = 0
};
+static struct snd_pcm_hw_constraint_list hw_constraints_period_sizes_new = {
+ .count = ARRAY_SIZE(period_sizes_new),
+ .list = period_sizes_new,
+ .mask = 0
+};
-static int snd_hdspm_hw_rule_channels_rate(struct snd_pcm_hw_params *params,
+static struct snd_pcm_hw_constraint_list hw_constraints_raydat_io_buffer = {
+ .count = ARRAY_SIZE(raydat_aio_buffer_sizes),
+ .list = raydat_aio_buffer_sizes,
+ .mask = 0
+};
+
+static int snd_hdspm_hw_rule_in_channels_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct hdspm *hdspm = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ if (r->min > 96000 && r->max <= 192000) {
+ struct snd_interval t = {
+ .min = hdspm->qs_in_channels,
+ .max = hdspm->qs_in_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ } else if (r->min > 48000 && r->max <= 96000) {
+ struct snd_interval t = {
+ .min = hdspm->ds_in_channels,
+ .max = hdspm->ds_in_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ } else if (r->max < 64000) {
+ struct snd_interval t = {
+ .min = hdspm->ss_in_channels,
+ .max = hdspm->ss_in_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ }
+
+ return 0;
+}
+
+static int snd_hdspm_hw_rule_out_channels_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule * rule)
{
struct hdspm *hdspm = rule->private;
@@ -3913,25 +5683,33 @@ static int snd_hdspm_hw_rule_channels_rate(struct snd_pcm_hw_params *params,
struct snd_interval *r =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- if (r->min > 48000 && r->max <= 96000) {
+ if (r->min > 96000 && r->max <= 192000) {
struct snd_interval t = {
- .min = hdspm->ds_channels,
- .max = hdspm->ds_channels,
+ .min = hdspm->qs_out_channels,
+ .max = hdspm->qs_out_channels,
+ .integer = 1,
+ };
+ return snd_interval_refine(c, &t);
+ } else if (r->min > 48000 && r->max <= 96000) {
+ struct snd_interval t = {
+ .min = hdspm->ds_out_channels,
+ .max = hdspm->ds_out_channels,
.integer = 1,
};
return snd_interval_refine(c, &t);
} else if (r->max < 64000) {
struct snd_interval t = {
- .min = hdspm->ss_channels,
- .max = hdspm->ss_channels,
+ .min = hdspm->ss_out_channels,
+ .max = hdspm->ss_out_channels,
.integer = 1,
};
return snd_interval_refine(c, &t);
+ } else {
}
return 0;
}
-static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
+static int snd_hdspm_hw_rule_rate_in_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule * rule)
{
struct hdspm *hdspm = rule->private;
@@ -3940,42 +5718,92 @@ static int snd_hdspm_hw_rule_rate_channels(struct snd_pcm_hw_params *params,
struct snd_interval *r =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- if (c->min >= hdspm->ss_channels) {
+ if (c->min >= hdspm->ss_in_channels) {
struct snd_interval t = {
.min = 32000,
.max = 48000,
.integer = 1,
};
return snd_interval_refine(r, &t);
- } else if (c->max <= hdspm->ds_channels) {
+ } else if (c->max <= hdspm->qs_in_channels) {
+ struct snd_interval t = {
+ .min = 128000,
+ .max = 192000,
+ .integer = 1,
+ };
+ return snd_interval_refine(r, &t);
+ } else if (c->max <= hdspm->ds_in_channels) {
struct snd_interval t = {
.min = 64000,
.max = 96000,
.integer = 1,
};
+ return snd_interval_refine(r, &t);
+ }
+ return 0;
+}
+static int snd_hdspm_hw_rule_rate_out_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct hdspm *hdspm = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ if (c->min >= hdspm->ss_out_channels) {
+ struct snd_interval t = {
+ .min = 32000,
+ .max = 48000,
+ .integer = 1,
+ };
+ return snd_interval_refine(r, &t);
+ } else if (c->max <= hdspm->qs_out_channels) {
+ struct snd_interval t = {
+ .min = 128000,
+ .max = 192000,
+ .integer = 1,
+ };
+ return snd_interval_refine(r, &t);
+ } else if (c->max <= hdspm->ds_out_channels) {
+ struct snd_interval t = {
+ .min = 64000,
+ .max = 96000,
+ .integer = 1,
+ };
return snd_interval_refine(r, &t);
}
+
return 0;
}
-static int snd_hdspm_hw_rule_channels(struct snd_pcm_hw_params *params,
+static int snd_hdspm_hw_rule_in_channels(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
unsigned int list[3];
struct hdspm *hdspm = rule->private;
struct snd_interval *c = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- if (hdspm->is_aes32) {
- list[0] = hdspm->qs_channels;
- list[1] = hdspm->ds_channels;
- list[2] = hdspm->ss_channels;
- return snd_interval_list(c, 3, list, 0);
- } else {
- list[0] = hdspm->ds_channels;
- list[1] = hdspm->ss_channels;
- return snd_interval_list(c, 2, list, 0);
- }
+
+ list[0] = hdspm->qs_in_channels;
+ list[1] = hdspm->ds_in_channels;
+ list[2] = hdspm->ss_in_channels;
+ return snd_interval_list(c, 3, list, 0);
+}
+
+static int snd_hdspm_hw_rule_out_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ unsigned int list[3];
+ struct hdspm *hdspm = rule->private;
+ struct snd_interval *c = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ list[0] = hdspm->qs_out_channels;
+ list[1] = hdspm->ds_out_channels;
+ list[2] = hdspm->ss_out_channels;
+ return snd_interval_list(c, 3, list, 0);
}
@@ -3999,6 +5827,7 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
+
runtime->hw = snd_hdspm_playback_subinfo;
if (hdspm->capture_substream == NULL)
@@ -4011,25 +5840,41 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- &hw_constraints_period_sizes);
+ switch (hdspm->io_type) {
+ case AIO:
+ case RayDAT:
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes_new);
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ &hw_constraints_raydat_io_buffer);
- if (hdspm->is_aes32) {
+ break;
+
+ default:
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes_old);
+ }
+
+ if (AES32 == hdspm->io_type) {
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates);
} else {
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- snd_hdspm_hw_rule_channels, hdspm,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- snd_hdspm_hw_rule_channels_rate, hdspm,
- SNDRV_PCM_HW_PARAM_RATE, -1);
-
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- snd_hdspm_hw_rule_rate_channels, hdspm,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ snd_hdspm_hw_rule_rate_out_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
}
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_out_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_out_channels_rate, hdspm,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
return 0;
}
@@ -4066,24 +5911,40 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
spin_unlock_irq(&hdspm->lock);
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
- snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- &hw_constraints_period_sizes);
- if (hdspm->is_aes32) {
+ switch (hdspm->io_type) {
+ case AIO:
+ case RayDAT:
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes_new);
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+ &hw_constraints_raydat_io_buffer);
+ break;
+
+ default:
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+ &hw_constraints_period_sizes_old);
+ }
+
+ if (AES32 == hdspm->io_type) {
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hdspm_hw_constraints_aes32_sample_rates);
} else {
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- snd_hdspm_hw_rule_channels, hdspm,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- snd_hdspm_hw_rule_channels_rate, hdspm,
- SNDRV_PCM_HW_PARAM_RATE, -1);
-
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- snd_hdspm_hw_rule_rate_channels, hdspm,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ snd_hdspm_hw_rule_rate_in_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
}
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_in_channels, hdspm,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ snd_hdspm_hw_rule_in_channels_rate, hdspm,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+
return 0;
}
@@ -4100,32 +5961,129 @@ static int snd_hdspm_capture_release(struct snd_pcm_substream *substream)
return 0;
}
-static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file)
{
+ /* we have nothing to initialize but the call is required */
+ return 0;
+}
+
+static inline int copy_u32_le(void __user *dest, void __iomem *src)
+{
+ u32 val = readl(src);
+ return copy_to_user(dest, &val, 4);
+}
+
+static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+ unsigned int cmd, unsigned long __user arg)
+{
+ void __user *argp = (void __user *)arg;
struct hdspm *hdspm = hw->private_data;
struct hdspm_mixer_ioctl mixer;
- struct hdspm_config_info info;
+ struct hdspm_config info;
+ struct hdspm_status status;
struct hdspm_version hdspm_version;
- struct hdspm_peak_rms_ioctl rms;
+ struct hdspm_peak_rms *levels;
+ struct hdspm_ltc ltc;
+ unsigned int statusregister;
+ long unsigned int s;
+ int i = 0;
switch (cmd) {
case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS:
- if (copy_from_user(&rms, (void __user *)arg, sizeof(rms)))
+ levels = &hdspm->peak_rms;
+ for (i = 0; i < HDSPM_MAX_CHANNELS; i++) {
+ levels->input_peaks[i] =
+ readl(hdspm->iobase +
+ HDSPM_MADI_INPUT_PEAK + i*4);
+ levels->playback_peaks[i] =
+ readl(hdspm->iobase +
+ HDSPM_MADI_PLAYBACK_PEAK + i*4);
+ levels->output_peaks[i] =
+ readl(hdspm->iobase +
+ HDSPM_MADI_OUTPUT_PEAK + i*4);
+
+ levels->input_rms[i] =
+ ((uint64_t) readl(hdspm->iobase +
+ HDSPM_MADI_INPUT_RMS_H + i*4) << 32) |
+ (uint64_t) readl(hdspm->iobase +
+ HDSPM_MADI_INPUT_RMS_L + i*4);
+ levels->playback_rms[i] =
+ ((uint64_t)readl(hdspm->iobase +
+ HDSPM_MADI_PLAYBACK_RMS_H+i*4) << 32) |
+ (uint64_t)readl(hdspm->iobase +
+ HDSPM_MADI_PLAYBACK_RMS_L + i*4);
+ levels->output_rms[i] =
+ ((uint64_t)readl(hdspm->iobase +
+ HDSPM_MADI_OUTPUT_RMS_H + i*4) << 32) |
+ (uint64_t)readl(hdspm->iobase +
+ HDSPM_MADI_OUTPUT_RMS_L + i*4);
+ }
+
+ if (hdspm->system_sample_rate > 96000) {
+ levels->speed = qs;
+ } else if (hdspm->system_sample_rate > 48000) {
+ levels->speed = ds;
+ } else {
+ levels->speed = ss;
+ }
+ levels->status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+
+ s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms));
+ if (0 != s) {
+ /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu
+ [Levels]\n", sizeof(struct hdspm_peak_rms), s);
+ */
return -EFAULT;
- /* maybe there is a chance to memorymap in future
- * so dont touch just copy
- */
- if(copy_to_user_fromio((void __user *)rms.peak,
- hdspm->iobase+HDSPM_MADI_peakrmsbase,
- sizeof(struct hdspm_peak_rms)) != 0 )
+ }
+ break;
+
+ case SNDRV_HDSPM_IOCTL_GET_LTC:
+ ltc.ltc = hdspm_read(hdspm, HDSPM_RD_TCO);
+ i = hdspm_read(hdspm, HDSPM_RD_TCO + 4);
+ if (i & HDSPM_TCO1_LTC_Input_valid) {
+ switch (i & (HDSPM_TCO1_LTC_Format_LSB |
+ HDSPM_TCO1_LTC_Format_MSB)) {
+ case 0:
+ ltc.format = fps_24;
+ break;
+ case HDSPM_TCO1_LTC_Format_LSB:
+ ltc.format = fps_25;
+ break;
+ case HDSPM_TCO1_LTC_Format_MSB:
+ ltc.format = fps_2997;
+ break;
+ default:
+ ltc.format = 30;
+ break;
+ }
+ if (i & HDSPM_TCO1_set_drop_frame_flag) {
+ ltc.frame = drop_frame;
+ } else {
+ ltc.frame = full_frame;
+ }
+ } else {
+ ltc.format = format_invalid;
+ ltc.frame = frame_invalid;
+ }
+ if (i & HDSPM_TCO1_Video_Input_Format_NTSC) {
+ ltc.input_format = ntsc;
+ } else if (i & HDSPM_TCO1_Video_Input_Format_PAL) {
+ ltc.input_format = pal;
+ } else {
+ ltc.input_format = no_video;
+ }
+
+ s = copy_to_user(argp, &ltc, sizeof(struct hdspm_ltc));
+ if (0 != s) {
+ /*
+ snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */
return -EFAULT;
+ }
break;
-
- case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO:
+ case SNDRV_HDSPM_IOCTL_GET_CONFIG:
memset(&info, 0, sizeof(info));
spin_lock_irq(&hdspm->lock);
@@ -4134,7 +6092,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
info.system_sample_rate = hdspm->system_sample_rate;
info.autosync_sample_rate =
- hdspm_external_sample_rate(hdspm);
+ hdspm_external_sample_rate(hdspm);
info.system_clock_mode = hdspm_system_clock_mode(hdspm);
info.clock_source = hdspm_clock_source(hdspm);
info.autosync_ref = hdspm_autosync_ref(hdspm);
@@ -4145,10 +6103,58 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
return -EFAULT;
break;
+ case SNDRV_HDSPM_IOCTL_GET_STATUS:
+ status.card_type = hdspm->io_type;
+
+ status.autosync_source = hdspm_autosync_ref(hdspm);
+
+ status.card_clock = 110069313433624ULL;
+ status.master_period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ);
+
+ switch (hdspm->io_type) {
+ case MADI:
+ case MADIface:
+ status.card_specific.madi.sync_wc =
+ hdspm_wc_sync_check(hdspm);
+ status.card_specific.madi.sync_madi =
+ hdspm_madi_sync_check(hdspm);
+ status.card_specific.madi.sync_tco =
+ hdspm_tco_sync_check(hdspm);
+ status.card_specific.madi.sync_in =
+ hdspm_sync_in_sync_check(hdspm);
+
+ statusregister =
+ hdspm_read(hdspm, HDSPM_statusRegister);
+ status.card_specific.madi.madi_input =
+ (statusregister & HDSPM_AB_int) ? 1 : 0;
+ status.card_specific.madi.channel_format =
+ (statusregister & HDSPM_TX_64ch) ? 1 : 0;
+ /* TODO: Mac driver sets it when f_s>48kHz */
+ status.card_specific.madi.frame_format = 0;
+
+ default:
+ break;
+ }
+
+ if (copy_to_user((void __user *) arg, &status, sizeof(status)))
+ return -EFAULT;
+
+
+ break;
+
case SNDRV_HDSPM_IOCTL_GET_VERSION:
+ hdspm_version.card_type = hdspm->io_type;
+ strncpy(hdspm_version.cardname, hdspm->card_name,
+ sizeof(hdspm_version.cardname));
+ hdspm_version.serial = (hdspm_read(hdspm,
+ HDSPM_midiStatusIn0)>>8) & 0xFFFFFF;
hdspm_version.firmware_rev = hdspm->firmware_rev;
+ hdspm_version.addons = 0;
+ if (hdspm->tco)
+ hdspm_version.addons |= HDSPM_ADDON_TCO;
+
if (copy_to_user((void __user *) arg, &hdspm_version,
- sizeof(hdspm_version)))
+ sizeof(hdspm_version)))
return -EFAULT;
break;
@@ -4156,7 +6162,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer)))
return -EFAULT;
if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer,
- sizeof(struct hdspm_mixer)))
+ sizeof(struct hdspm_mixer)))
return -EFAULT;
break;
@@ -4175,8 +6181,6 @@ static struct snd_pcm_ops snd_hdspm_playback_ops = {
.prepare = snd_hdspm_prepare,
.trigger = snd_hdspm_trigger,
.pointer = snd_hdspm_hw_pointer,
- .copy = snd_hdspm_playback_copy,
- .silence = snd_hdspm_hw_silence,
.page = snd_pcm_sgbuf_ops_page,
};
@@ -4189,7 +6193,6 @@ static struct snd_pcm_ops snd_hdspm_capture_ops = {
.prepare = snd_hdspm_prepare,
.trigger = snd_hdspm_trigger,
.pointer = snd_hdspm_hw_pointer,
- .copy = snd_hdspm_capture_copy,
.page = snd_pcm_sgbuf_ops_page,
};
@@ -4207,16 +6210,18 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card,
hw->private_data = hdspm;
strcpy(hw->name, "HDSPM hwdep interface");
+ hw->ops.open = snd_hdspm_hwdep_dummy_op;
hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
+ hw->ops.release = snd_hdspm_hwdep_dummy_op;
return 0;
}
/*------------------------------------------------------------
- memory interface
+ memory interface
------------------------------------------------------------*/
-static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
+static int __devinit snd_hdspm_preallocate_memory(struct hdspm *hdspm)
{
int err;
struct snd_pcm *pcm;
@@ -4228,7 +6233,7 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
err =
snd_pcm_lib_preallocate_pages_for_all(pcm,
- SNDRV_DMA_TYPE_DEV_SG,
+ SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(hdspm->pci),
wanted,
wanted);
@@ -4242,19 +6247,23 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm)
return 0;
}
-static void hdspm_set_sgbuf(struct hdspm * hdspm,
+
+static void hdspm_set_sgbuf(struct hdspm *hdspm,
struct snd_pcm_substream *substream,
unsigned int reg, int channels)
{
int i;
+
+ /* continuous memory segment */
for (i = 0; i < (channels * 16); i++)
hdspm_write(hdspm, reg + 4 * i,
- snd_pcm_sgbuf_get_addr(substream, 4096 * i));
+ snd_pcm_sgbuf_get_addr(substream, 4096 * i));
}
+
/* ------------- ALSA Devices ---------------------------- */
static int __devinit snd_hdspm_create_pcm(struct snd_card *card,
- struct hdspm * hdspm)
+ struct hdspm *hdspm)
{
struct snd_pcm *pcm;
int err;
@@ -4283,27 +6292,30 @@ static int __devinit snd_hdspm_create_pcm(struct snd_card *card,
static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm)
{
- snd_hdspm_flush_midi_input(hdspm, 0);
- snd_hdspm_flush_midi_input(hdspm, 1);
+ int i;
+
+ for (i = 0; i < hdspm->midiPorts; i++)
+ snd_hdspm_flush_midi_input(hdspm, i);
}
static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card,
struct hdspm * hdspm)
{
- int err;
+ int err, i;
snd_printdd("Create card...\n");
err = snd_hdspm_create_pcm(card, hdspm);
if (err < 0)
return err;
- err = snd_hdspm_create_midi(card, hdspm, 0);
- if (err < 0)
- return err;
-
- err = snd_hdspm_create_midi(card, hdspm, 1);
- if (err < 0)
- return err;
+ i = 0;
+ while (i < hdspm->midiPorts) {
+ err = snd_hdspm_create_midi(card, hdspm, i);
+ if (err < 0) {
+ return err;
+ }
+ i++;
+ }
err = snd_hdspm_create_controls(card, hdspm);
if (err < 0)
@@ -4346,37 +6358,55 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card,
}
static int __devinit snd_hdspm_create(struct snd_card *card,
- struct hdspm *hdspm,
- int precise_ptr, int enable_monitor)
-{
+ struct hdspm *hdspm) {
+
struct pci_dev *pci = hdspm->pci;
int err;
unsigned long io_extent;
hdspm->irq = -1;
-
- spin_lock_init(&hdspm->midi[0].lock);
- spin_lock_init(&hdspm->midi[1].lock);
-
hdspm->card = card;
spin_lock_init(&hdspm->lock);
- tasklet_init(&hdspm->midi_tasklet,
- hdspm_midi_tasklet, (unsigned long) hdspm);
-
pci_read_config_word(hdspm->pci,
- PCI_CLASS_REVISION, &hdspm->firmware_rev);
-
- hdspm->is_aes32 = (hdspm->firmware_rev >= HDSPM_AESREVISION);
+ PCI_CLASS_REVISION, &hdspm->firmware_rev);
strcpy(card->mixername, "Xilinx FPGA");
- if (hdspm->is_aes32) {
- strcpy(card->driver, "HDSPAES32");
- hdspm->card_name = "RME HDSPM AES32";
- } else {
- strcpy(card->driver, "HDSPM");
- hdspm->card_name = "RME HDSPM MADI";
+ strcpy(card->driver, "HDSPM");
+
+ switch (hdspm->firmware_rev) {
+ case HDSPM_MADI_REV:
+ hdspm->io_type = MADI;
+ hdspm->card_name = "RME MADI";
+ hdspm->midiPorts = 3;
+ break;
+ case HDSPM_RAYDAT_REV:
+ hdspm->io_type = RayDAT;
+ hdspm->card_name = "RME RayDAT";
+ hdspm->midiPorts = 2;
+ break;
+ case HDSPM_AIO_REV:
+ hdspm->io_type = AIO;
+ hdspm->card_name = "RME AIO";
+ hdspm->midiPorts = 1;
+ break;
+ case HDSPM_MADIFACE_REV:
+ hdspm->io_type = MADIface;
+ hdspm->card_name = "RME MADIface";
+ hdspm->midiPorts = 1;
+ break;
+ case HDSPM_AES_REV:
+ case HDSPM_AES32_REV:
+ case HDSPM_AES32_OLD_REV:
+ hdspm->io_type = AES32;
+ hdspm->card_name = "RME AES32";
+ hdspm->midiPorts = 2;
+ break;
+ default:
+ snd_printk(KERN_ERR "HDSPM: unknown firmware revision %x\n",
+ hdspm->firmware_rev);
+ return -ENODEV;
}
err = pci_enable_device(pci);
@@ -4393,22 +6423,21 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
io_extent = pci_resource_len(pci, 0);
snd_printdd("grabbed memory region 0x%lx-0x%lx\n",
- hdspm->port, hdspm->port + io_extent - 1);
-
+ hdspm->port, hdspm->port + io_extent - 1);
hdspm->iobase = ioremap_nocache(hdspm->port, io_extent);
if (!hdspm->iobase) {
snd_printk(KERN_ERR "HDSPM: "
- "unable to remap region 0x%lx-0x%lx\n",
- hdspm->port, hdspm->port + io_extent - 1);
+ "unable to remap region 0x%lx-0x%lx\n",
+ hdspm->port, hdspm->port + io_extent - 1);
return -EBUSY;
}
snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n",
- (unsigned long)hdspm->iobase, hdspm->port,
- hdspm->port + io_extent - 1);
+ (unsigned long)hdspm->iobase, hdspm->port,
+ hdspm->port + io_extent - 1);
if (request_irq(pci->irq, snd_hdspm_interrupt,
- IRQF_SHARED, "hdspm", hdspm)) {
+ IRQF_SHARED, "hdspm", hdspm)) {
snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq);
return -EBUSY;
}
@@ -4416,23 +6445,219 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
snd_printdd("use IRQ %d\n", pci->irq);
hdspm->irq = pci->irq;
- hdspm->precise_ptr = precise_ptr;
-
- hdspm->monitor_outs = enable_monitor;
snd_printdd("kmalloc Mixer memory of %zd Bytes\n",
- sizeof(struct hdspm_mixer));
+ sizeof(struct hdspm_mixer));
hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL);
if (!hdspm->mixer) {
snd_printk(KERN_ERR "HDSPM: "
- "unable to kmalloc Mixer memory of %d Bytes\n",
- (int)sizeof(struct hdspm_mixer));
+ "unable to kmalloc Mixer memory of %d Bytes\n",
+ (int)sizeof(struct hdspm_mixer));
return err;
}
- hdspm->ss_channels = MADI_SS_CHANNELS;
- hdspm->ds_channels = MADI_DS_CHANNELS;
- hdspm->qs_channels = MADI_QS_CHANNELS;
+ hdspm->port_names_in = NULL;
+ hdspm->port_names_out = NULL;
+
+ switch (hdspm->io_type) {
+ case AES32:
+ hdspm->ss_in_channels = hdspm->ss_out_channels = AES32_CHANNELS;
+ hdspm->ds_in_channels = hdspm->ds_out_channels = AES32_CHANNELS;
+ hdspm->qs_in_channels = hdspm->qs_out_channels = AES32_CHANNELS;
+
+ hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
+ channel_map_aes32;
+ hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
+ channel_map_aes32;
+ hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
+ channel_map_aes32;
+ hdspm->port_names_in_ss = hdspm->port_names_out_ss =
+ texts_ports_aes32;
+ hdspm->port_names_in_ds = hdspm->port_names_out_ds =
+ texts_ports_aes32;
+ hdspm->port_names_in_qs = hdspm->port_names_out_qs =
+ texts_ports_aes32;
+
+ hdspm->max_channels_out = hdspm->max_channels_in =
+ AES32_CHANNELS;
+ hdspm->port_names_in = hdspm->port_names_out =
+ texts_ports_aes32;
+ hdspm->channel_map_in = hdspm->channel_map_out =
+ channel_map_aes32;
+
+ break;
+
+ case MADI:
+ case MADIface:
+ hdspm->ss_in_channels = hdspm->ss_out_channels =
+ MADI_SS_CHANNELS;
+ hdspm->ds_in_channels = hdspm->ds_out_channels =
+ MADI_DS_CHANNELS;
+ hdspm->qs_in_channels = hdspm->qs_out_channels =
+ MADI_QS_CHANNELS;
+
+ hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
+ channel_map_unity_ss;
+ hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
+ channel_map_unity_ss;
+ hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
+ channel_map_unity_ss;
+
+ hdspm->port_names_in_ss = hdspm->port_names_out_ss =
+ texts_ports_madi;
+ hdspm->port_names_in_ds = hdspm->port_names_out_ds =
+ texts_ports_madi;
+ hdspm->port_names_in_qs = hdspm->port_names_out_qs =
+ texts_ports_madi;
+ break;
+
+ case AIO:
+ if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
+ snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n");
+ }
+
+ hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
+ hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
+ hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
+ hdspm->ss_out_channels = AIO_OUT_SS_CHANNELS;
+ hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
+ hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
+
+ hdspm->channel_map_out_ss = channel_map_aio_out_ss;
+ hdspm->channel_map_out_ds = channel_map_aio_out_ds;
+ hdspm->channel_map_out_qs = channel_map_aio_out_qs;
+
+ hdspm->channel_map_in_ss = channel_map_aio_in_ss;
+ hdspm->channel_map_in_ds = channel_map_aio_in_ds;
+ hdspm->channel_map_in_qs = channel_map_aio_in_qs;
+
+ hdspm->port_names_in_ss = texts_ports_aio_in_ss;
+ hdspm->port_names_out_ss = texts_ports_aio_out_ss;
+ hdspm->port_names_in_ds = texts_ports_aio_in_ds;
+ hdspm->port_names_out_ds = texts_ports_aio_out_ds;
+ hdspm->port_names_in_qs = texts_ports_aio_in_qs;
+ hdspm->port_names_out_qs = texts_ports_aio_out_qs;
+
+ break;
+
+ case RayDAT:
+ hdspm->ss_in_channels = hdspm->ss_out_channels =
+ RAYDAT_SS_CHANNELS;
+ hdspm->ds_in_channels = hdspm->ds_out_channels =
+ RAYDAT_DS_CHANNELS;
+ hdspm->qs_in_channels = hdspm->qs_out_channels =
+ RAYDAT_QS_CHANNELS;
+
+ hdspm->max_channels_in = RAYDAT_SS_CHANNELS;
+ hdspm->max_channels_out = RAYDAT_SS_CHANNELS;
+
+ hdspm->channel_map_in_ss = hdspm->channel_map_out_ss =
+ channel_map_raydat_ss;
+ hdspm->channel_map_in_ds = hdspm->channel_map_out_ds =
+ channel_map_raydat_ds;
+ hdspm->channel_map_in_qs = hdspm->channel_map_out_qs =
+ channel_map_raydat_qs;
+ hdspm->channel_map_in = hdspm->channel_map_out =
+ channel_map_raydat_ss;
+
+ hdspm->port_names_in_ss = hdspm->port_names_out_ss =
+ texts_ports_raydat_ss;
+ hdspm->port_names_in_ds = hdspm->port_names_out_ds =
+ texts_ports_raydat_ds;
+ hdspm->port_names_in_qs = hdspm->port_names_out_qs =
+ texts_ports_raydat_qs;
+
+
+ break;
+
+ }
+
+ /* TCO detection */
+ switch (hdspm->io_type) {
+ case AIO:
+ case RayDAT:
+ if (hdspm_read(hdspm, HDSPM_statusRegister2) &
+ HDSPM_s2_tco_detect) {
+ hdspm->midiPorts++;
+ hdspm->tco = kzalloc(sizeof(struct hdspm_tco),
+ GFP_KERNEL);
+ if (NULL != hdspm->tco) {
+ hdspm_tco_write(hdspm);
+ }
+ snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n");
+ } else {
+ hdspm->tco = NULL;
+ }
+ break;
+
+ case MADI:
+ if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
+ hdspm->midiPorts++;
+ hdspm->tco = kzalloc(sizeof(struct hdspm_tco),
+ GFP_KERNEL);
+ if (NULL != hdspm->tco) {
+ hdspm_tco_write(hdspm);
+ }
+ snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n");
+ } else {
+ hdspm->tco = NULL;
+ }
+ break;
+
+ default:
+ hdspm->tco = NULL;
+ }
+
+ /* texts */
+ switch (hdspm->io_type) {
+ case AES32:
+ if (hdspm->tco) {
+ hdspm->texts_autosync = texts_autosync_aes_tco;
+ hdspm->texts_autosync_items = 10;
+ } else {
+ hdspm->texts_autosync = texts_autosync_aes;
+ hdspm->texts_autosync_items = 9;
+ }
+ break;
+
+ case MADI:
+ if (hdspm->tco) {
+ hdspm->texts_autosync = texts_autosync_madi_tco;
+ hdspm->texts_autosync_items = 4;
+ } else {
+ hdspm->texts_autosync = texts_autosync_madi;
+ hdspm->texts_autosync_items = 3;
+ }
+ break;
+
+ case MADIface:
+
+ break;
+
+ case RayDAT:
+ if (hdspm->tco) {
+ hdspm->texts_autosync = texts_autosync_raydat_tco;
+ hdspm->texts_autosync_items = 9;
+ } else {
+ hdspm->texts_autosync = texts_autosync_raydat;
+ hdspm->texts_autosync_items = 8;
+ }
+ break;
+
+ case AIO:
+ if (hdspm->tco) {
+ hdspm->texts_autosync = texts_autosync_aio_tco;
+ hdspm->texts_autosync_items = 6;
+ } else {
+ hdspm->texts_autosync = texts_autosync_aio;
+ hdspm->texts_autosync_items = 5;
+ }
+ break;
+
+ }
+
+ tasklet_init(&hdspm->midi_tasklet,
+ hdspm_midi_tasklet, (unsigned long) hdspm);
snd_printdd("create alsa devices.\n");
err = snd_hdspm_create_alsa_devices(card, hdspm);
@@ -4444,6 +6669,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card,
return 0;
}
+
static int snd_hdspm_free(struct hdspm * hdspm)
{
@@ -4452,7 +6678,8 @@ static int snd_hdspm_free(struct hdspm * hdspm)
/* stop th audio, and cancel all interrupts */
hdspm->control_register &=
~(HDSPM_Start | HDSPM_AudioInterruptEnable |
- HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable);
+ HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable |
+ HDSPM_Midi2InterruptEnable | HDSPM_Midi3InterruptEnable);
hdspm_write(hdspm, HDSPM_controlRegister,
hdspm->control_register);
}
@@ -4472,6 +6699,7 @@ static int snd_hdspm_free(struct hdspm * hdspm)
return 0;
}
+
static void snd_hdspm_card_free(struct snd_card *card)
{
struct hdspm *hdspm = card->private_data;
@@ -4480,6 +6708,7 @@ static void snd_hdspm_card_free(struct snd_card *card)
snd_hdspm_free(hdspm);
}
+
static int __devinit snd_hdspm_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -4496,7 +6725,7 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci,
}
err = snd_card_create(index[dev], id[dev],
- THIS_MODULE, sizeof(struct hdspm), &card);
+ THIS_MODULE, sizeof(struct hdspm), &card);
if (err < 0)
return err;
@@ -4507,16 +6736,25 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci,
snd_card_set_dev(card, &pci->dev);
- err = snd_hdspm_create(card, hdspm, precise_ptr[dev],
- enable_monitor[dev]);
+ err = snd_hdspm_create(card, hdspm);
if (err < 0) {
snd_card_free(card);
return err;
}
- strcpy(card->shortname, "HDSPM MADI");
- sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name,
- hdspm->port, hdspm->irq);
+ if (hdspm->io_type != MADIface) {
+ sprintf(card->shortname, "%s_%x",
+ hdspm->card_name,
+ (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF);
+ sprintf(card->longname, "%s S/N 0x%x at 0x%lx, irq %d",
+ hdspm->card_name,
+ (hdspm_read(hdspm, HDSPM_midiStatusIn0)>>8) & 0xFFFFFF,
+ hdspm->port, hdspm->irq);
+ } else {
+ sprintf(card->shortname, "%s", hdspm->card_name);
+ sprintf(card->longname, "%s at 0x%lx, irq %d",
+ hdspm->card_name, hdspm->port, hdspm->irq);
+ }
err = snd_card_register(card);
if (err < 0) {
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index b47cfd45b3b9..3ecbd67f88c9 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -1034,7 +1034,11 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip)
if (of_device_is_compatible(sound, "tumbler")) {
chip->model = PMAC_TUMBLER;
chip->can_capture = of_machine_is_compatible("PowerMac4,2")
- || of_machine_is_compatible("PowerBook4,1");
+ || of_machine_is_compatible("PowerBook3,2")
+ || of_machine_is_compatible("PowerBook3,3")
+ || of_machine_is_compatible("PowerBook4,1")
+ || of_machine_is_compatible("PowerBook4,2")
+ || of_machine_is_compatible("PowerBook4,3");
chip->can_duplex = 0;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index a3efc52a34da..8224db5f0434 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -50,10 +50,12 @@ source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
+source "sound/soc/mid-x86/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
+source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
# Supported codecs
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index ce913bf5213c..1ed61c5df2c5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC) += ep93xx/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
obj-$(CONFIG_SND_SOC) += jz4740/
+obj-$(CONFIG_SND_SOC) += mid-x86/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
@@ -17,4 +18,5 @@ obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
+obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index c48b23c1d4fc..d63c1754e05f 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -26,17 +26,24 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS42L51 if I2C
select SND_SOC_CS4270 if I2C
+ select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
select SND_SOC_CX20442
select SND_SOC_DA7210 if I2C
+ select SND_SOC_DFBMCS320
select SND_SOC_JZ4740_CODEC if SOC_JZ4740
+ select SND_SOC_LM4857 if I2C
select SND_SOC_MAX98088 if I2C
+ select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008
+ select SND_SOC_SGTL5000 if I2C
+ select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF
select SND_SOC_SSM2602 if I2C
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER
+ select SND_SOC_TVL320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
@@ -76,6 +83,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
+ select SND_SOC_WM8991 if I2C
select SND_SOC_WM8993 if I2C
select SND_SOC_WM8994 if MFD_WM8994
select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
@@ -155,6 +163,9 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_CS4271
+ tristate
+
config SND_SOC_CX20442
tristate
@@ -167,15 +178,28 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
+config SND_SOC_DFBMCS320
+ tristate
+
config SND_SOC_DMIC
tristate
config SND_SOC_MAX98088
tristate
+config SND_SOC_MAX9850
+ tristate
+
config SND_SOC_PCM3008
tristate
+#Freescale sgtl5000 codec
+config SND_SOC_SGTL5000
+ tristate
+
+config SND_SOC_SN95031
+ tristate
+
config SND_SOC_SPDIF
tristate
@@ -192,6 +216,9 @@ config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
depends on SPI
+config SND_SOC_TVL320AIC32X4
+ tristate
+
config SND_SOC_TLV320AIC3X
tristate
@@ -304,6 +331,9 @@ config SND_SOC_WM8988
config SND_SOC_WM8990
tristate
+config SND_SOC_WM8991
+ tristate
+
config SND_SOC_WM8993
tristate
@@ -326,6 +356,9 @@ config SND_SOC_WM9713
tristate
# Amp
+config SND_SOC_LM4857
+ tristate
+
config SND_SOC_MAX9877
tristate
@@ -337,4 +370,3 @@ config SND_SOC_WM2000
config SND_SOC_WM9090
tristate
-
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 579af9c4f128..379bc55f0723 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -12,19 +12,25 @@ snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
+snd-soc-dfbmcs320-objs := dfbmcs320.o
snd-soc-dmic-objs := dmic.o
snd-soc-l3-objs := l3.o
snd-soc-max98088-objs := max98088.o
+snd-soc-max9850-objs := max9850.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
+snd-soc-sn95031-objs := sn95031.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
@@ -61,6 +67,7 @@ snd-soc-wm8978-objs := wm8978.o
snd-soc-wm8985-objs := wm8985.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm8991-objs := wm8991.o
snd-soc-wm8993-objs := wm8993.o
snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
snd-soc-wm8995-objs := wm8995.o
@@ -72,6 +79,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-jz4740-codec-objs := jz4740.o
# Amp
+snd-soc-lm4857-objs := lm4857.o
snd-soc-max9877-objs := max9877.o
snd-soc-tpa6130a2-objs := tpa6130a2.o
snd-soc-wm2000-objs := wm2000.o
@@ -88,23 +96,29 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
+obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
+obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
-obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
+obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
+obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
@@ -141,6 +155,7 @@ obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o
obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o
@@ -151,6 +166,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
# Amp
+obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index c27f8f59dc66..cbf0b6d400b8 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -294,7 +294,6 @@ static struct spi_driver ak4104_spi_driver = {
static int __init ak4104_init(void)
{
- pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n");
return spi_register_driver(&ak4104_spi_driver);
}
module_init(ak4104_init);
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index f00eba313dfd..4be0570e3f1f 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -116,6 +116,12 @@
#define BCKO_MASK (1 << 3)
#define BCKO_64 BCKO_MASK
+#define DIF_MASK (3 << 0)
+#define DSP (0 << 0)
+#define RIGHT_J (1 << 0)
+#define LEFT_J (2 << 0)
+#define I2S (3 << 0)
+
/* MD_CTL2 */
#define FS0 (1 << 0)
#define FS1 (1 << 1)
@@ -354,6 +360,24 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
snd_soc_update_bits(codec, PW_MGMT2, MS, data);
snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
+ /* format type */
+ data = 0;
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ data = LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ data = I2S;
+ break;
+ /* FIXME
+ * Please add RIGHT_J / DSP support here
+ */
+ default:
+ return -EINVAL;
+ break;
+ }
+ snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data);
+
return 0;
}
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 8b51245f2318..0206a17d7283 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -193,12 +193,12 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
/* The number of MCLK/LRCK ratios supported by the CS4270 */
#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)
-static int cs4270_reg_is_readable(unsigned int reg)
+static int cs4270_reg_is_readable(struct snd_soc_codec *codec, unsigned int reg)
{
return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
}
-static int cs4270_reg_is_volatile(unsigned int reg)
+static int cs4270_reg_is_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
/* Unreadable registers are considered volatile */
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
@@ -719,7 +719,7 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client)
/*
* cs4270_id - I2C device IDs supported by this driver
*/
-static struct i2c_device_id cs4270_id[] = {
+static const struct i2c_device_id cs4270_id[] = {
{"cs4270", 0},
{}
};
@@ -743,8 +743,6 @@ static struct i2c_driver cs4270_i2c_driver = {
static int __init cs4270_init(void)
{
- pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
-
return i2c_add_driver(&cs4270_i2c_driver);
}
module_init(cs4270_init);
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
new file mode 100644
index 000000000000..083aab96ca80
--- /dev/null
+++ b/sound/soc/codecs/cs4271.c
@@ -0,0 +1,667 @@
+/*
+ * CS4271 ASoC codec driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver support CS4271 codec being master or slave, working
+ * in control port mode, connected either via SPI or I2C.
+ * The data format accepted is I2S or left-justified.
+ * DAPM support not implemented.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <sound/cs4271.h>
+
+#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+#define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000
+
+/*
+ * CS4271 registers
+ * High byte represents SPI chip address (0x10) + write command (0)
+ * Low byte - codec register address
+ */
+#define CS4271_MODE1 0x2001 /* Mode Control 1 */
+#define CS4271_DACCTL 0x2002 /* DAC Control */
+#define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */
+#define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */
+#define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */
+#define CS4271_ADCCTL 0x2006 /* ADC Control */
+#define CS4271_MODE2 0x2007 /* Mode Control 2 */
+#define CS4271_CHIPID 0x2008 /* Chip ID */
+
+#define CS4271_FIRSTREG CS4271_MODE1
+#define CS4271_LASTREG CS4271_MODE2
+#define CS4271_NR_REGS ((CS4271_LASTREG & 0xFF) + 1)
+
+/* Bit masks for the CS4271 registers */
+#define CS4271_MODE1_MODE_MASK 0xC0
+#define CS4271_MODE1_MODE_1X 0x00
+#define CS4271_MODE1_MODE_2X 0x80
+#define CS4271_MODE1_MODE_4X 0xC0
+
+#define CS4271_MODE1_DIV_MASK 0x30
+#define CS4271_MODE1_DIV_1 0x00
+#define CS4271_MODE1_DIV_15 0x10
+#define CS4271_MODE1_DIV_2 0x20
+#define CS4271_MODE1_DIV_3 0x30
+
+#define CS4271_MODE1_MASTER 0x08
+
+#define CS4271_MODE1_DAC_DIF_MASK 0x07
+#define CS4271_MODE1_DAC_DIF_LJ 0x00
+#define CS4271_MODE1_DAC_DIF_I2S 0x01
+#define CS4271_MODE1_DAC_DIF_RJ16 0x02
+#define CS4271_MODE1_DAC_DIF_RJ24 0x03
+#define CS4271_MODE1_DAC_DIF_RJ20 0x04
+#define CS4271_MODE1_DAC_DIF_RJ18 0x05
+
+#define CS4271_DACCTL_AMUTE 0x80
+#define CS4271_DACCTL_IF_SLOW 0x40
+
+#define CS4271_DACCTL_DEM_MASK 0x30
+#define CS4271_DACCTL_DEM_DIS 0x00
+#define CS4271_DACCTL_DEM_441 0x10
+#define CS4271_DACCTL_DEM_48 0x20
+#define CS4271_DACCTL_DEM_32 0x30
+
+#define CS4271_DACCTL_SVRU 0x08
+#define CS4271_DACCTL_SRD 0x04
+#define CS4271_DACCTL_INVA 0x02
+#define CS4271_DACCTL_INVB 0x01
+
+#define CS4271_DACVOL_BEQUA 0x40
+#define CS4271_DACVOL_SOFT 0x20
+#define CS4271_DACVOL_ZEROC 0x10
+
+#define CS4271_DACVOL_ATAPI_MASK 0x0F
+#define CS4271_DACVOL_ATAPI_M_M 0x00
+#define CS4271_DACVOL_ATAPI_M_BR 0x01
+#define CS4271_DACVOL_ATAPI_M_BL 0x02
+#define CS4271_DACVOL_ATAPI_M_BLR2 0x03
+#define CS4271_DACVOL_ATAPI_AR_M 0x04
+#define CS4271_DACVOL_ATAPI_AR_BR 0x05
+#define CS4271_DACVOL_ATAPI_AR_BL 0x06
+#define CS4271_DACVOL_ATAPI_AR_BLR2 0x07
+#define CS4271_DACVOL_ATAPI_AL_M 0x08
+#define CS4271_DACVOL_ATAPI_AL_BR 0x09
+#define CS4271_DACVOL_ATAPI_AL_BL 0x0A
+#define CS4271_DACVOL_ATAPI_AL_BLR2 0x0B
+#define CS4271_DACVOL_ATAPI_ALR2_M 0x0C
+#define CS4271_DACVOL_ATAPI_ALR2_BR 0x0D
+#define CS4271_DACVOL_ATAPI_ALR2_BL 0x0E
+#define CS4271_DACVOL_ATAPI_ALR2_BLR2 0x0F
+
+#define CS4271_VOLA_MUTE 0x80
+#define CS4271_VOLA_VOL_MASK 0x7F
+#define CS4271_VOLB_MUTE 0x80
+#define CS4271_VOLB_VOL_MASK 0x7F
+
+#define CS4271_ADCCTL_DITHER16 0x20
+
+#define CS4271_ADCCTL_ADC_DIF_MASK 0x10
+#define CS4271_ADCCTL_ADC_DIF_LJ 0x00
+#define CS4271_ADCCTL_ADC_DIF_I2S 0x10
+
+#define CS4271_ADCCTL_MUTEA 0x08
+#define CS4271_ADCCTL_MUTEB 0x04
+#define CS4271_ADCCTL_HPFDA 0x02
+#define CS4271_ADCCTL_HPFDB 0x01
+
+#define CS4271_MODE2_LOOP 0x10
+#define CS4271_MODE2_MUTECAEQUB 0x08
+#define CS4271_MODE2_FREEZE 0x04
+#define CS4271_MODE2_CPEN 0x02
+#define CS4271_MODE2_PDN 0x01
+
+#define CS4271_CHIPID_PART_MASK 0xF0
+#define CS4271_CHIPID_REV_MASK 0x0F
+
+/*
+ * Default CS4271 power-up configuration
+ * Array contains non-existing in hw register at address 0
+ * Array do not include Chip ID, as codec driver does not use
+ * registers read operations at all
+ */
+static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = {
+ 0,
+ 0,
+ CS4271_DACCTL_AMUTE,
+ CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+struct cs4271_private {
+ /* SND_SOC_I2C or SND_SOC_SPI */
+ enum snd_soc_control_type bus_type;
+ void *control_data;
+ unsigned int mclk;
+ bool master;
+ bool deemph;
+ /* Current sample rate for de-emphasis control */
+ int rate;
+ /* GPIO driving Reset pin, if any */
+ int gpio_nreset;
+ /* GPIO that disable serial bus, if any */
+ int gpio_disable;
+};
+
+/*
+ * @freq is the desired MCLK rate
+ * MCLK rate should (c) be the sample rate, multiplied by one of the
+ * ratios listed in cs4271_mclk_fs_ratios table
+ */
+static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
+ cs4271->mclk = freq;
+ return 0;
+}
+
+static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = 0;
+ int ret;
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs4271->master = 0;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs4271->master = 1;
+ val |= CS4271_MODE1_MASTER;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ val |= CS4271_MODE1_DAC_DIF_LJ;
+ ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+ CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
+ if (ret < 0)
+ return ret;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val |= CS4271_MODE1_DAC_DIF_I2S;
+ ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+ CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ ret = snd_soc_update_bits(codec, CS4271_MODE1,
+ CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int cs4271_deemph[] = {0, 44100, 48000, 32000};
+
+static int cs4271_set_deemph(struct snd_soc_codec *codec)
+{
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+ int val = CS4271_DACCTL_DEM_DIS;
+
+ if (cs4271->deemph) {
+ /* Find closest de-emphasis freq */
+ val = 1;
+ for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++)
+ if (abs(cs4271_deemph[i] - cs4271->rate) <
+ abs(cs4271_deemph[val] - cs4271->rate))
+ val = i;
+ val <<= 4;
+ }
+
+ ret = snd_soc_update_bits(codec, CS4271_DACCTL,
+ CS4271_DACCTL_DEM_MASK, val);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int cs4271_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.enumerated.item[0] = cs4271->deemph;
+ return 0;
+}
+
+static int cs4271_put_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
+ cs4271->deemph = ucontrol->value.enumerated.item[0];
+ return cs4271_set_deemph(codec);
+}
+
+struct cs4271_clk_cfg {
+ bool master; /* codec mode */
+ u8 speed_mode; /* codec speed mode: 1x, 2x, 4x */
+ unsigned short ratio; /* MCLK / sample rate */
+ u8 ratio_mask; /* ratio bit mask for Master mode */
+};
+
+static struct cs4271_clk_cfg cs4271_clk_tab[] = {
+ {1, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1},
+ {1, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_15},
+ {1, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_2},
+ {1, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_3},
+ {1, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1},
+ {1, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_15},
+ {1, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_2},
+ {1, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_3},
+ {1, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1},
+ {1, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_15},
+ {1, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_2},
+ {1, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_3},
+ {0, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_2},
+ {0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2},
+ {0, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_2},
+ {0, CS4271_MODE1_MODE_2X, 512, CS4271_MODE1_DIV_2},
+ {0, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_1},
+ {0, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_2},
+ {0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2},
+};
+
+#define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab)
+
+static int cs4271_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int i, ret;
+ unsigned int ratio, val;
+
+ cs4271->rate = params_rate(params);
+
+ /* Configure DAC */
+ if (cs4271->rate < 50000)
+ val = CS4271_MODE1_MODE_1X;
+ else if (cs4271->rate < 100000)
+ val = CS4271_MODE1_MODE_2X;
+ else
+ val = CS4271_MODE1_MODE_4X;
+
+ ratio = cs4271->mclk / cs4271->rate;
+ for (i = 0; i < CS4171_NR_RATIOS; i++)
+ if ((cs4271_clk_tab[i].master == cs4271->master) &&
+ (cs4271_clk_tab[i].speed_mode == val) &&
+ (cs4271_clk_tab[i].ratio == ratio))
+ break;
+
+ if (i == CS4171_NR_RATIOS) {
+ dev_err(codec->dev, "Invalid sample rate\n");
+ return -EINVAL;
+ }
+
+ val |= cs4271_clk_tab[i].ratio_mask;
+
+ ret = snd_soc_update_bits(codec, CS4271_MODE1,
+ CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ return cs4271_set_deemph(codec);
+}
+
+static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int ret;
+ int val_a = 0;
+ int val_b = 0;
+
+ if (mute) {
+ val_a = CS4271_VOLA_MUTE;
+ val_b = CS4271_VOLB_MUTE;
+ }
+
+ ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* CS4271 controls */
+static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0);
+
+static const struct snd_kcontrol_new cs4271_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB,
+ 0, 0x7F, 1, cs4271_dac_tlv),
+ SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0),
+ SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0),
+ SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0),
+ SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+ cs4271_get_deemph, cs4271_put_deemph),
+ SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0),
+ SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0),
+ SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0),
+ SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0),
+ SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0),
+ SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0),
+ SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1),
+ SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0),
+ SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1),
+ SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB,
+ 7, 1, 1),
+};
+
+static struct snd_soc_dai_ops cs4271_dai_ops = {
+ .hw_params = cs4271_hw_params,
+ .set_sysclk = cs4271_set_dai_sysclk,
+ .set_fmt = cs4271_set_dai_fmt,
+ .digital_mute = cs4271_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs4271_dai = {
+ .name = "cs4271-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = CS4271_PCM_RATES,
+ .formats = CS4271_PCM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = CS4271_PCM_RATES,
+ .formats = CS4271_PCM_FORMATS,
+ },
+ .ops = &cs4271_dai_ops,
+ .symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int cs4271_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
+{
+ int ret;
+ /* Set power-down bit */
+ ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, CS4271_MODE2_PDN);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int cs4271_soc_resume(struct snd_soc_codec *codec)
+{
+ int ret;
+ /* Restore codec state */
+ ret = snd_soc_cache_sync(codec);
+ if (ret < 0)
+ return ret;
+ /* then disable the power-down bit */
+ ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+#else
+#define cs4271_soc_suspend NULL
+#define cs4271_soc_resume NULL
+#endif /* CONFIG_PM */
+
+static int cs4271_probe(struct snd_soc_codec *codec)
+{
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
+ int ret;
+ int gpio_nreset = -EINVAL;
+
+ codec->control_data = cs4271->control_data;
+
+ if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
+ gpio_nreset = cs4271plat->gpio_nreset;
+
+ if (gpio_nreset >= 0)
+ if (gpio_request(gpio_nreset, "CS4271 Reset"))
+ gpio_nreset = -EINVAL;
+ if (gpio_nreset >= 0) {
+ /* Reset codec */
+ gpio_direction_output(gpio_nreset, 0);
+ udelay(1);
+ gpio_set_value(gpio_nreset, 1);
+ /* Give the codec time to wake up */
+ udelay(1);
+ }
+
+ cs4271->gpio_nreset = gpio_nreset;
+
+ /*
+ * In case of I2C, chip address specified in board data.
+ * So cache IO operations use 8 bit codec register address.
+ * In case of SPI, chip address and register address
+ * passed together as 16 bit value.
+ * Anyway, register address is masked with 0xFF inside
+ * soc-cache code.
+ */
+ if (cs4271->bus_type == SND_SOC_SPI)
+ ret = snd_soc_codec_set_cache_io(codec, 16, 8,
+ cs4271->bus_type);
+ else
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8,
+ cs4271->bus_type);
+ if (ret) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_update_bits(codec, CS4271_MODE2, 0,
+ CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+ if (ret < 0)
+ return ret;
+ /* Power-up sequence requires 85 uS */
+ udelay(85);
+
+ return snd_soc_add_controls(codec, cs4271_snd_controls,
+ ARRAY_SIZE(cs4271_snd_controls));
+}
+
+static int cs4271_remove(struct snd_soc_codec *codec)
+{
+ struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+ int gpio_nreset;
+
+ gpio_nreset = cs4271->gpio_nreset;
+
+ if (gpio_is_valid(gpio_nreset)) {
+ /* Set codec to the reset state */
+ gpio_set_value(gpio_nreset, 0);
+ gpio_free(gpio_nreset);
+ }
+
+ return 0;
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
+ .probe = cs4271_probe,
+ .remove = cs4271_remove,
+ .suspend = cs4271_soc_suspend,
+ .resume = cs4271_soc_resume,
+ .reg_cache_default = cs4271_dflt_reg,
+ .reg_cache_size = ARRAY_SIZE(cs4271_dflt_reg),
+ .reg_word_size = sizeof(cs4271_dflt_reg[0]),
+ .compress_type = SND_SOC_FLAT_COMPRESSION,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit cs4271_spi_probe(struct spi_device *spi)
+{
+ struct cs4271_private *cs4271;
+
+ cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL);
+ if (!cs4271)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, cs4271);
+ cs4271->control_data = spi;
+ cs4271->bus_type = SND_SOC_SPI;
+
+ return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
+ &cs4271_dai, 1);
+}
+
+static int __devexit cs4271_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver cs4271_spi_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ },
+ .probe = cs4271_spi_probe,
+ .remove = __devexit_p(cs4271_spi_remove),
+};
+#endif /* defined(CONFIG_SPI_MASTER) */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static const struct i2c_device_id cs4271_i2c_id[] = {
+ {"cs4271", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+
+static int __devinit cs4271_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cs4271_private *cs4271;
+
+ cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL);
+ if (!cs4271)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, cs4271);
+ cs4271->control_data = client;
+ cs4271->bus_type = SND_SOC_I2C;
+
+ return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
+ &cs4271_dai, 1);
+}
+
+static int __devexit cs4271_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static struct i2c_driver cs4271_i2c_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs4271_i2c_id,
+ .probe = cs4271_i2c_probe,
+ .remove = __devexit_p(cs4271_i2c_remove),
+};
+#endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */
+
+/*
+ * We only register our serial bus driver here without
+ * assignment to particular chip. So if any of the below
+ * fails, there is some problem with I2C or SPI subsystem.
+ * In most cases this module will be compiled with support
+ * of only one serial bus.
+ */
+static int __init cs4271_modinit(void)
+{
+ int ret;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&cs4271_i2c_driver);
+ if (ret) {
+ pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
+ return ret;
+ }
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&cs4271_spi_driver);
+ if (ret) {
+ pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+module_init(cs4271_modinit);
+
+static void __exit cs4271_modexit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&cs4271_spi_driver);
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&cs4271_i2c_driver);
+#endif
+}
+module_exit(cs4271_modexit);
+
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/dfbmcs320.c b/sound/soc/codecs/dfbmcs320.c
new file mode 100644
index 000000000000..704bbde65737
--- /dev/null
+++ b/sound/soc/codecs/dfbmcs320.c
@@ -0,0 +1,72 @@
+/*
+ * Driver for the DFBM-CS320 bluetooth module
+ * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver dfbmcs320_dai = {
+ .name = "dfbmcs320-pcm",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320;
+
+static int __devinit dfbmcs320_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320,
+ &dfbmcs320_dai, 1);
+}
+
+static int __devexit dfbmcs320_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver dfmcs320_driver = {
+ .driver = {
+ .name = "dfbmcs320",
+ .owner = THIS_MODULE,
+ },
+ .probe = dfbmcs320_probe,
+ .remove = __devexit_p(dfbmcs320_remove),
+};
+
+static int __init dfbmcs320_init(void)
+{
+ return platform_driver_register(&dfmcs320_driver);
+}
+module_init(dfbmcs320_init);
+
+static void __exit dfbmcs320_exit(void)
+{
+ platform_driver_unregister(&dfmcs320_driver);
+}
+module_exit(dfbmcs320_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
new file mode 100644
index 000000000000..72de47e5d040
--- /dev/null
+++ b/sound/soc/codecs/lm4857.c
@@ -0,0 +1,276 @@
+/*
+ * LM4857 AMP driver
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+struct lm4857 {
+ struct i2c_client *i2c;
+ uint8_t mode;
+};
+
+static const uint8_t lm4857_default_regs[] = {
+ 0x00, 0x00, 0x00, 0x00,
+};
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ uint8_t data;
+ int ret;
+
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret < 0)
+ return ret;
+
+ data = (reg << 6) | value;
+ ret = i2c_master_send(codec->control_data, &data, 1);
+ if (ret != 1) {
+ dev_err(codec->dev, "Failed to write register: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static unsigned int lm4857_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret)
+ return -1;
+
+ return val;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = lm4857->mode;
+
+ return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
+ uint8_t value = ucontrol->value.integer.value[0];
+
+ lm4857->mode = value;
+
+ if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
+ snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6);
+
+ return 1;
+}
+
+static int lm4857_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0);
+ break;
+ default:
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+static const char *lm4857_mode[] = {
+ "Earpiece",
+ "Loudspeaker",
+ "Loudspeaker + Headphone",
+ "Headphone",
+};
+
+static const struct soc_enum lm4857_mode_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode);
+
+static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("IN"),
+
+ SND_SOC_DAPM_OUTPUT("LS"),
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_OUTPUT("EP"),
+};
+
+static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
+
+static const struct snd_kcontrol_new lm4857_controls[] = {
+ SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+ stereo_tlv),
+ SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+ stereo_tlv),
+ SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+ mono_tlv),
+ SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0),
+ SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0),
+ SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL,
+ LM4857_WAKEUP, 1, 0),
+ SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL,
+ LM4857_EPGAIN, 1, 0),
+
+ SOC_ENUM_EXT("Mode", lm4857_mode_enum,
+ lm4857_get_mode, lm4857_set_mode),
+};
+
+/* There is a demux inbetween the the input signal and the output signals.
+ * Currently there is no easy way to model it in ASoC and since it does not make
+ * much of a difference in practice simply connect the input direclty to the
+ * outputs. */
+static const struct snd_soc_dapm_route lm4857_routes[] = {
+ {"LS", NULL, "IN"},
+ {"HP", NULL, "IN"},
+ {"EP", NULL, "IN"},
+};
+
+static int lm4857_probe(struct snd_soc_codec *codec)
+{
+ struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret;
+
+ codec->control_data = lm4857->i2c;
+
+ ret = snd_soc_add_controls(codec, lm4857_controls,
+ ARRAY_SIZE(lm4857_controls));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets,
+ ARRAY_SIZE(lm4857_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, lm4857_routes,
+ ARRAY_SIZE(lm4857_routes));
+ if (ret)
+ return ret;
+
+ snd_soc_dapm_new_widgets(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
+ .write = lm4857_write,
+ .read = lm4857_read,
+ .probe = lm4857_probe,
+ .reg_cache_size = ARRAY_SIZE(lm4857_default_regs),
+ .reg_word_size = sizeof(uint8_t),
+ .reg_cache_default = lm4857_default_regs,
+ .set_bias_level = lm4857_set_bias_level,
+};
+
+static int __devinit lm4857_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct lm4857 *lm4857;
+ int ret;
+
+ lm4857 = kzalloc(sizeof(*lm4857), GFP_KERNEL);
+ if (!lm4857)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, lm4857);
+
+ lm4857->i2c = i2c;
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
+
+ if (ret) {
+ kfree(lm4857);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devexit lm4857_i2c_remove(struct i2c_client *i2c)
+{
+ struct lm4857 *lm4857 = i2c_get_clientdata(i2c);
+
+ snd_soc_unregister_codec(&i2c->dev);
+ kfree(lm4857);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm4857_i2c_id[] = {
+ { "lm4857", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id);
+
+static struct i2c_driver lm4857_i2c_driver = {
+ .driver = {
+ .name = "lm4857",
+ .owner = THIS_MODULE,
+ },
+ .probe = lm4857_i2c_probe,
+ .remove = __devexit_p(lm4857_i2c_remove),
+ .id_table = lm4857_i2c_id,
+};
+
+static int __init lm4857_init(void)
+{
+ return i2c_add_driver(&lm4857_i2c_driver);
+}
+module_init(lm4857_init);
+
+static void __exit lm4857_exit(void)
+{
+ i2c_del_driver(&lm4857_i2c_driver);
+}
+module_exit(lm4857_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("LM4857 amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 89498f9ad2e5..bd0517cb7980 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -608,7 +608,7 @@ static struct {
{ 0xFF, 0x00, 1 }, /* FF */
};
-static int max98088_volatile_register(unsigned int reg)
+static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
return max98088_access[reg].vol;
}
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
new file mode 100644
index 000000000000..208d2ee61855
--- /dev/null
+++ b/sound/soc/codecs/max9850.c
@@ -0,0 +1,389 @@
+/*
+ * max9850.c -- codec driver for max9850
+ *
+ * Copyright (C) 2011 taskit GmbH
+ *
+ * Author: Christian Glindkamp <christian.glindkamp@taskit.de>
+ *
+ * Initial development of this code was funded by
+ * MICRONIC Computer Systeme GmbH, http://www.mcsberlin.de/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "max9850.h"
+
+struct max9850_priv {
+ unsigned int sysclk;
+};
+
+/* max9850 register cache */
+static const u8 max9850_reg[MAX9850_CACHEREGNUM] = {
+ 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* these registers are not used at the moment but provided for the sake of
+ * completeness */
+static int max9850_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case MAX9850_STATUSA:
+ case MAX9850_STATUSB:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static const unsigned int max9850_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
+ 0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0),
+ 0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0),
+ 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0),
+};
+
+static const struct snd_kcontrol_new max9850_controls[] = {
+SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv),
+SOC_SINGLE("Headphone Switch", MAX9850_VOLUME, 7, 1, 1),
+SOC_SINGLE("Mono Switch", MAX9850_GENERAL_PURPOSE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new max9850_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Line In Switch", MAX9850_ENABLE, 1, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget max9850_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("Charge Pump 1", MAX9850_ENABLE, 4, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("Charge Pump 2", MAX9850_ENABLE, 5, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MCLK", MAX9850_ENABLE, 6, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SHDN", MAX9850_ENABLE, 7, 0, NULL, 0),
+SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", MAX9850_ENABLE, 2, 0,
+ &max9850_mixer_controls[0],
+ ARRAY_SIZE(max9850_mixer_controls)),
+SND_SOC_DAPM_PGA("Headphone Output", MAX9850_ENABLE, 3, 0, NULL, 0),
+SND_SOC_DAPM_DAC("DAC", "HiFi Playback", MAX9850_ENABLE, 0, 0),
+SND_SOC_DAPM_OUTPUT("OUTL"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("OUTR"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_INPUT("INL"),
+SND_SOC_DAPM_INPUT("INR"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ /* output mixer */
+ {"Output Mixer", NULL, "DAC"},
+ {"Output Mixer", "Line In Switch", "Line Input"},
+
+ /* outputs */
+ {"Headphone Output", NULL, "Output Mixer"},
+ {"HPL", NULL, "Headphone Output"},
+ {"HPR", NULL, "Headphone Output"},
+ {"OUTL", NULL, "Output Mixer"},
+ {"OUTR", NULL, "Output Mixer"},
+
+ /* inputs */
+ {"Line Input", NULL, "INL"},
+ {"Line Input", NULL, "INR"},
+
+ /* supplies */
+ {"Output Mixer", NULL, "Charge Pump 1"},
+ {"Output Mixer", NULL, "Charge Pump 2"},
+ {"Output Mixer", NULL, "SHDN"},
+ {"DAC", NULL, "MCLK"},
+};
+
+static int max9850_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
+ u64 lrclk_div;
+ u8 sf, da;
+
+ if (!max9850->sysclk)
+ return -EINVAL;
+
+ /* lrclk_div = 2^22 * rate / iclk with iclk = mclk / sf */
+ sf = (snd_soc_read(codec, MAX9850_CLOCK) >> 2) + 1;
+ lrclk_div = (1 << 22);
+ lrclk_div *= params_rate(params);
+ lrclk_div *= sf;
+ do_div(lrclk_div, max9850->sysclk);
+
+ snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
+ snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ da = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ da = 0x2;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ da = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, MAX9850_DIGITAL_AUDIO, 0x3, da);
+
+ return 0;
+}
+
+static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
+
+ /* calculate mclk -> iclk divider */
+ if (freq <= 13000000)
+ snd_soc_write(codec, MAX9850_CLOCK, 0x0);
+ else if (freq <= 26000000)
+ snd_soc_write(codec, MAX9850_CLOCK, 0x4);
+ else if (freq <= 40000000)
+ snd_soc_write(codec, MAX9850_CLOCK, 0x8);
+ else
+ return -EINVAL;
+
+ max9850->sysclk = freq;
+ return 0;
+}
+
+static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u8 da = 0;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ da |= MAX9850_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ da |= MAX9850_DLY;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ da |= MAX9850_RTJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ da |= MAX9850_BCINV | MAX9850_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ da |= MAX9850_BCINV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ da |= MAX9850_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set da */
+ snd_soc_write(codec, MAX9850_DIGITAL_AUDIO, da);
+
+ return 0;
+}
+
+static int max9850_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = snd_soc_cache_sync(codec);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+#define MAX9850_RATES SNDRV_PCM_RATE_8000_48000
+
+#define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max9850_dai_ops = {
+ .hw_params = max9850_hw_params,
+ .set_sysclk = max9850_set_dai_sysclk,
+ .set_fmt = max9850_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver max9850_dai = {
+ .name = "max9850-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX9850_RATES,
+ .formats = MAX9850_FORMATS
+ },
+ .ops = &max9850_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int max9850_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ max9850_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int max9850_resume(struct snd_soc_codec *codec)
+{
+ max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define max9850_suspend NULL
+#define max9850_resume NULL
+#endif
+
+static int max9850_probe(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* enable zero-detect */
+ snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1);
+ /* enable slew-rate control */
+ snd_soc_update_bits(codec, MAX9850_VOLUME, 0x40, 0x40);
+ /* set slew-rate 125ms */
+ snd_soc_update_bits(codec, MAX9850_CHARGE_PUMP, 0xff, 0xc0);
+
+ snd_soc_dapm_new_controls(dapm, max9850_dapm_widgets,
+ ARRAY_SIZE(max9850_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+ snd_soc_add_controls(codec, max9850_controls,
+ ARRAY_SIZE(max9850_controls));
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
+ .probe = max9850_probe,
+ .suspend = max9850_suspend,
+ .resume = max9850_resume,
+ .set_bias_level = max9850_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(max9850_reg),
+ .reg_word_size = sizeof(u8),
+ .reg_cache_default = max9850_reg,
+ .volatile_register = max9850_volatile_register,
+};
+
+static int __devinit max9850_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max9850_priv *max9850;
+ int ret;
+
+ max9850 = kzalloc(sizeof(struct max9850_priv), GFP_KERNEL);
+ if (max9850 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max9850);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_max9850, &max9850_dai, 1);
+ if (ret < 0)
+ kfree(max9850);
+ return ret;
+}
+
+static __devexit int max9850_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id max9850_i2c_id[] = {
+ { "max9850", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max9850_i2c_id);
+
+static struct i2c_driver max9850_i2c_driver = {
+ .driver = {
+ .name = "max9850",
+ .owner = THIS_MODULE,
+ },
+ .probe = max9850_i2c_probe,
+ .remove = __devexit_p(max9850_i2c_remove),
+ .id_table = max9850_i2c_id,
+};
+
+static int __init max9850_init(void)
+{
+ return i2c_add_driver(&max9850_i2c_driver);
+}
+module_init(max9850_init);
+
+static void __exit max9850_exit(void)
+{
+ i2c_del_driver(&max9850_i2c_driver);
+}
+module_exit(max9850_exit);
+
+MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
+MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max9850.h b/sound/soc/codecs/max9850.h
new file mode 100644
index 000000000000..72b1ddb04b0d
--- /dev/null
+++ b/sound/soc/codecs/max9850.h
@@ -0,0 +1,38 @@
+/*
+ * max9850.h -- codec driver for max9850
+ *
+ * Copyright (C) 2011 taskit GmbH
+ * Author: Christian Glindkamp <christian.glindkamp@taskit.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _MAX9850_H
+#define _MAX9850_H
+
+#define MAX9850_STATUSA 0x00
+#define MAX9850_STATUSB 0x01
+#define MAX9850_VOLUME 0x02
+#define MAX9850_GENERAL_PURPOSE 0x03
+#define MAX9850_INTERRUPT 0x04
+#define MAX9850_ENABLE 0x05
+#define MAX9850_CLOCK 0x06
+#define MAX9850_CHARGE_PUMP 0x07
+#define MAX9850_LRCLK_MSB 0x08
+#define MAX9850_LRCLK_LSB 0x09
+#define MAX9850_DIGITAL_AUDIO 0x0a
+
+#define MAX9850_CACHEREGNUM 11
+
+/* MAX9850_DIGITAL_AUDIO */
+#define MAX9850_MASTER (1<<7)
+#define MAX9850_INV (1<<6)
+#define MAX9850_BCINV (1<<5)
+#define MAX9850_DLY (1<<3)
+#define MAX9850_RTJ (1<<2)
+
+#endif
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
new file mode 100644
index 000000000000..1f7217f703ee
--- /dev/null
+++ b/sound/soc/codecs/sgtl5000.c
@@ -0,0 +1,1513 @@
+/*
+ * sgtl5000.c -- SGTL5000 ALSA SoC Audio driver
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "sgtl5000.h"
+
+#define SGTL5000_DAP_REG_OFFSET 0x0100
+#define SGTL5000_MAX_REG_OFFSET 0x013A
+
+/* default value of sgtl5000 registers except DAP */
+static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] = {
+ 0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */
+ 0x0000, /* 0x0002, CHIP_DIG_POWER. */
+ 0x0008, /* 0x0004, CHIP_CKL_CTRL */
+ 0x0010, /* 0x0006, CHIP_I2S_CTRL */
+ 0x0000, /* 0x0008, reserved */
+ 0x0008, /* 0x000A, CHIP_SSS_CTRL */
+ 0x0000, /* 0x000C, reserved */
+ 0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */
+ 0x3c3c, /* 0x0010, CHIP_DAC_VOL */
+ 0x0000, /* 0x0012, reserved */
+ 0x015f, /* 0x0014, CHIP_PAD_STRENGTH */
+ 0x0000, /* 0x0016, reserved */
+ 0x0000, /* 0x0018, reserved */
+ 0x0000, /* 0x001A, reserved */
+ 0x0000, /* 0x001E, reserved */
+ 0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */
+ 0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */
+ 0x0111, /* 0x0024, CHIP_ANN_CTRL */
+ 0x0000, /* 0x0026, CHIP_LINREG_CTRL */
+ 0x0000, /* 0x0028, CHIP_REF_CTRL */
+ 0x0000, /* 0x002A, CHIP_MIC_CTRL */
+ 0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */
+ 0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */
+ 0x7060, /* 0x0030, CHIP_ANA_POWER */
+ 0x5000, /* 0x0032, CHIP_PLL_CTRL */
+ 0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */
+ 0x0000, /* 0x0036, CHIP_ANA_STATUS */
+ 0x0000, /* 0x0038, reserved */
+ 0x0000, /* 0x003A, CHIP_ANA_TEST2 */
+ 0x0000, /* 0x003C, CHIP_SHORT_CTRL */
+ 0x0000, /* reserved */
+};
+
+/* default value of dap registers */
+static const u16 sgtl5000_dap_regs[] = {
+ 0x0000, /* 0x0100, DAP_CONTROL */
+ 0x0000, /* 0x0102, DAP_PEQ */
+ 0x0040, /* 0x0104, DAP_BASS_ENHANCE */
+ 0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */
+ 0x0000, /* 0x0108, DAP_AUDIO_EQ */
+ 0x0040, /* 0x010A, DAP_SGTL_SURROUND */
+ 0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */
+ 0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */
+ 0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */
+ 0x0000, /* 0x0112, reserved */
+ 0x0000, /* 0x0114, reserved */
+ 0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */
+ 0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */
+ 0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */
+ 0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */
+ 0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */
+ 0x8000, /* 0x0120, DAP_MAIN_CHAN */
+ 0x0000, /* 0x0122, DAP_MIX_CHAN */
+ 0x0510, /* 0x0124, DAP_AVC_CTRL */
+ 0x1473, /* 0x0126, DAP_AVC_THRESHOLD */
+ 0x0028, /* 0x0128, DAP_AVC_ATTACK */
+ 0x0050, /* 0x012A, DAP_AVC_DECAY */
+ 0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */
+ 0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */
+ 0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */
+ 0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */
+ 0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */
+ 0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */
+ 0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */
+ 0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */
+};
+
+/* regulator supplies for sgtl5000, VDDD is an optional external supply */
+enum sgtl5000_regulator_supplies {
+ VDDA,
+ VDDIO,
+ VDDD,
+ SGTL5000_SUPPLY_NUM
+};
+
+/* vddd is optional supply */
+static const char *supply_names[SGTL5000_SUPPLY_NUM] = {
+ "VDDA",
+ "VDDIO",
+ "VDDD"
+};
+
+#define LDO_CONSUMER_NAME "VDDD_LDO"
+#define LDO_VOLTAGE 1200000
+
+static struct regulator_consumer_supply ldo_consumer[] = {
+ REGULATOR_SUPPLY(LDO_CONSUMER_NAME, NULL),
+};
+
+static struct regulator_init_data ldo_init_data = {
+ .constraints = {
+ .min_uV = 850000,
+ .max_uV = 1600000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &ldo_consumer[0],
+};
+
+/*
+ * sgtl5000 internal ldo regulator,
+ * enabled when VDDD not provided
+ */
+struct ldo_regulator {
+ struct regulator_desc desc;
+ struct regulator_dev *dev;
+ int voltage;
+ void *codec_data;
+ bool enabled;
+};
+
+/* sgtl5000 private structure in codec */
+struct sgtl5000_priv {
+ int sysclk; /* sysclk rate */
+ int master; /* i2s master or not */
+ int fmt; /* i2s data format */
+ struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM];
+ struct ldo_regulator *ldo;
+};
+
+/*
+ * mic_bias power on/off share the same register bits with
+ * output impedance of mic bias, when power on mic bias, we
+ * need reclaim it to impedance value.
+ * 0x0 = Powered off
+ * 0x1 = 2Kohm
+ * 0x2 = 4Kohm
+ * 0x3 = 8Kohm
+ */
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* change mic bias resistor to 4Kohm */
+ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+ SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ /*
+ * SGTL5000_BIAS_R_8k as mask to clean the two bits
+ * of mic bias and output impedance
+ */
+ snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+ SGTL5000_BIAS_R_8k, 0);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * using codec assist to small pop, hp_powerup or lineout_powerup
+ * should stay setting until vag_powerup is fully ramped down,
+ * vag fully ramped down require 400ms.
+ */
+static int small_pop_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VAG_POWERUP, 0);
+ msleep(400);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* input sources for ADC */
+static const char *adc_mux_text[] = {
+ "MIC_IN", "LINE_IN"
+};
+
+static const struct soc_enum adc_enum =
+SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text);
+
+static const struct snd_kcontrol_new adc_mux =
+SOC_DAPM_ENUM("Capture Mux", adc_enum);
+
+/* input sources for DAC */
+static const char *dac_mux_text[] = {
+ "DAC", "LINE_IN"
+};
+
+static const struct soc_enum dac_enum =
+SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
+
+static const struct snd_kcontrol_new dac_mux =
+SOC_DAPM_ENUM("Headphone Mux", dac_enum);
+
+static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("LINE_IN"),
+ SND_SOC_DAPM_INPUT("MIC_IN"),
+
+ SND_SOC_DAPM_OUTPUT("HP_OUT"),
+ SND_SOC_DAPM_OUTPUT("LINE_OUT"),
+
+ SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+ mic_bias_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0,
+ small_pop_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA_E("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0,
+ small_pop_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
+ SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
+
+ /* aif for i2s input */
+ SND_SOC_DAPM_AIF_IN("AIFIN", "Playback",
+ 0, SGTL5000_CHIP_DIG_POWER,
+ 0, 0),
+
+ /* aif for i2s output */
+ SND_SOC_DAPM_AIF_OUT("AIFOUT", "Capture",
+ 0, SGTL5000_CHIP_DIG_POWER,
+ 1, 0),
+
+ SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
+
+ SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
+};
+
+/* routes for sgtl5000 */
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */
+ {"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */
+
+ {"ADC", NULL, "Capture Mux"}, /* adc_mux --> adc */
+ {"AIFOUT", NULL, "ADC"}, /* adc --> i2s_out */
+
+ {"DAC", NULL, "AIFIN"}, /* i2s-->dac,skip audio mux */
+ {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */
+ {"LO", NULL, "DAC"}, /* dac --> line_out */
+
+ {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
+ {"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */
+
+ {"LINE_OUT", NULL, "LO"},
+ {"HP_OUT", NULL, "HP"},
+};
+
+/* custom function to fetch info of PCM playback volume */
+static int dac_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xfc - 0x3c;
+ return 0;
+}
+
+/*
+ * custom function to get of PCM playback volume
+ *
+ * dac volume register
+ * 15-------------8-7--------------0
+ * | R channel vol | L channel vol |
+ * -------------------------------
+ *
+ * PCM volume with 0.5017 dB steps from 0 to -90 dB
+ *
+ * register values map to dB
+ * 0x3B and less = Reserved
+ * 0x3C = 0 dB
+ * 0x3D = -0.5 dB
+ * 0xF0 = -90 dB
+ * 0xFC and greater = Muted
+ *
+ * register value map to userspace value
+ *
+ * register value 0x3c(0dB) 0xf0(-90dB)0xfc
+ * ------------------------------
+ * userspace value 0xc0 0
+ */
+static int dac_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg;
+ int l;
+ int r;
+
+ reg = snd_soc_read(codec, SGTL5000_CHIP_DAC_VOL);
+
+ /* get left channel volume */
+ l = (reg & SGTL5000_DAC_VOL_LEFT_MASK) >> SGTL5000_DAC_VOL_LEFT_SHIFT;
+
+ /* get right channel volume */
+ r = (reg & SGTL5000_DAC_VOL_RIGHT_MASK) >> SGTL5000_DAC_VOL_RIGHT_SHIFT;
+
+ /* make sure value fall in (0x3c,0xfc) */
+ l = clamp(l, 0x3c, 0xfc);
+ r = clamp(r, 0x3c, 0xfc);
+
+ /* invert it and map to userspace value */
+ l = 0xfc - l;
+ r = 0xfc - r;
+
+ ucontrol->value.integer.value[0] = l;
+ ucontrol->value.integer.value[1] = r;
+
+ return 0;
+}
+
+/*
+ * custom function to put of PCM playback volume
+ *
+ * dac volume register
+ * 15-------------8-7--------------0
+ * | R channel vol | L channel vol |
+ * -------------------------------
+ *
+ * PCM volume with 0.5017 dB steps from 0 to -90 dB
+ *
+ * register values map to dB
+ * 0x3B and less = Reserved
+ * 0x3C = 0 dB
+ * 0x3D = -0.5 dB
+ * 0xF0 = -90 dB
+ * 0xFC and greater = Muted
+ *
+ * userspace value map to register value
+ *
+ * userspace value 0xc0 0
+ * ------------------------------
+ * register value 0x3c(0dB) 0xf0(-90dB)0xfc
+ */
+static int dac_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg;
+ int l;
+ int r;
+
+ l = ucontrol->value.integer.value[0];
+ r = ucontrol->value.integer.value[1];
+
+ /* make sure userspace volume fall in (0, 0xfc-0x3c) */
+ l = clamp(l, 0, 0xfc - 0x3c);
+ r = clamp(r, 0, 0xfc - 0x3c);
+
+ /* invert it, get the value can be set to register */
+ l = 0xfc - l;
+ r = 0xfc - r;
+
+ /* shift to get the register value */
+ reg = l << SGTL5000_DAC_VOL_LEFT_SHIFT |
+ r << SGTL5000_DAC_VOL_RIGHT_SHIFT;
+
+ snd_soc_write(codec, SGTL5000_CHIP_DAC_VOL, reg);
+
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
+
+/* tlv for mic gain, 0db 20db 30db 40db */
+static const unsigned int mic_gain_tlv[] = {
+ TLV_DB_RANGE_HEAD(4),
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
+};
+
+/* tlv for hp volume, -51.5db to 12.0db, step .5db */
+static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0);
+
+static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
+ /* SOC_DOUBLE_S8_TLV with invert */
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = dac_info_volsw,
+ .get = dac_get_volsw,
+ .put = dac_put_volsw,
+ },
+
+ SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0),
+ SOC_SINGLE_TLV("Capture Attenuate Switch (-6dB)",
+ SGTL5000_CHIP_ANA_ADC_CTRL,
+ 8, 2, 0, capture_6db_attenuate),
+ SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0),
+
+ SOC_DOUBLE_TLV("Headphone Playback Volume",
+ SGTL5000_CHIP_ANA_HP_CTRL,
+ 0, 8,
+ 0x7f, 1,
+ headphone_volume),
+ SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL,
+ 5, 1, 0),
+
+ SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
+ 0, 4, 0, mic_gain_tlv),
+};
+
+/* mute the codec used by alsa core */
+static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT;
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
+ adcdac_ctrl, mute ? adcdac_ctrl : 0);
+
+ return 0;
+}
+
+/* set codec format */
+static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ u16 i2sctl = 0;
+
+ sgtl5000->master = 0;
+ /*
+ * i2s clock and frame master setting.
+ * ONLY support:
+ * - clock and frame slave,
+ * - clock and frame master
+ */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ i2sctl |= SGTL5000_I2S_MASTER;
+ sgtl5000->master = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* setting i2s data format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ i2sctl |= SGTL5000_I2S_MODE_PCM;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ i2sctl |= SGTL5000_I2S_MODE_PCM;
+ i2sctl |= SGTL5000_I2S_LRALIGN;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ i2sctl |= SGTL5000_I2S_MODE_RJ;
+ i2sctl |= SGTL5000_I2S_LRPOL;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+ i2sctl |= SGTL5000_I2S_LRALIGN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sgtl5000->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
+ /* Clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ i2sctl |= SGTL5000_I2S_SCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, SGTL5000_CHIP_I2S_CTRL, i2sctl);
+
+ return 0;
+}
+
+/* set codec sysclk */
+static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case SGTL5000_SYSCLK:
+ sgtl5000->sysclk = freq;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * set clock according to i2s frame clock,
+ * sgtl5000 provide 2 clock sources.
+ * 1. sys_mclk. sample freq can only configure to
+ * 1/256, 1/384, 1/512 of sys_mclk.
+ * 2. pll. can derive any audio clocks.
+ *
+ * clock setting rules:
+ * 1. in slave mode, only sys_mclk can use.
+ * 2. as constraint by sys_mclk, sample freq should
+ * set to 32k, 44.1k and above.
+ * 3. using sys_mclk prefer to pll to save power.
+ */
+static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
+{
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ int clk_ctl = 0;
+ int sys_fs; /* sample freq */
+
+ /*
+ * sample freq should be divided by frame clock,
+ * if frame clock lower than 44.1khz, sample feq should set to
+ * 32khz or 44.1khz.
+ */
+ switch (frame_rate) {
+ case 8000:
+ case 16000:
+ sys_fs = 32000;
+ break;
+ case 11025:
+ case 22050:
+ sys_fs = 44100;
+ break;
+ default:
+ sys_fs = frame_rate;
+ break;
+ }
+
+ /* set divided factor of frame clock */
+ switch (sys_fs / frame_rate) {
+ case 4:
+ clk_ctl |= SGTL5000_RATE_MODE_DIV_4 << SGTL5000_RATE_MODE_SHIFT;
+ break;
+ case 2:
+ clk_ctl |= SGTL5000_RATE_MODE_DIV_2 << SGTL5000_RATE_MODE_SHIFT;
+ break;
+ case 1:
+ clk_ctl |= SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set the sys_fs according to frame rate */
+ switch (sys_fs) {
+ case 32000:
+ clk_ctl |= SGTL5000_SYS_FS_32k << SGTL5000_SYS_FS_SHIFT;
+ break;
+ case 44100:
+ clk_ctl |= SGTL5000_SYS_FS_44_1k << SGTL5000_SYS_FS_SHIFT;
+ break;
+ case 48000:
+ clk_ctl |= SGTL5000_SYS_FS_48k << SGTL5000_SYS_FS_SHIFT;
+ break;
+ case 96000:
+ clk_ctl |= SGTL5000_SYS_FS_96k << SGTL5000_SYS_FS_SHIFT;
+ break;
+ default:
+ dev_err(codec->dev, "frame rate %d not supported\n",
+ frame_rate);
+ return -EINVAL;
+ }
+
+ /*
+ * calculate the divider of mclk/sample_freq,
+ * factor of freq =96k can only be 256, since mclk in range (12m,27m)
+ */
+ switch (sgtl5000->sysclk / sys_fs) {
+ case 256:
+ clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
+ SGTL5000_MCLK_FREQ_SHIFT;
+ break;
+ case 384:
+ clk_ctl |= SGTL5000_MCLK_FREQ_384FS <<
+ SGTL5000_MCLK_FREQ_SHIFT;
+ break;
+ case 512:
+ clk_ctl |= SGTL5000_MCLK_FREQ_512FS <<
+ SGTL5000_MCLK_FREQ_SHIFT;
+ break;
+ default:
+ /* if mclk not satisify the divider, use pll */
+ if (sgtl5000->master) {
+ clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
+ SGTL5000_MCLK_FREQ_SHIFT;
+ } else {
+ dev_err(codec->dev,
+ "PLL not supported in slave mode\n");
+ return -EINVAL;
+ }
+ }
+
+ /* if using pll, please check manual 6.4.2 for detail */
+ if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) {
+ u64 out, t;
+ int div2;
+ int pll_ctl;
+ unsigned int in, int_div, frac_div;
+
+ if (sgtl5000->sysclk > 17000000) {
+ div2 = 1;
+ in = sgtl5000->sysclk / 2;
+ } else {
+ div2 = 0;
+ in = sgtl5000->sysclk;
+ }
+ if (sys_fs == 44100)
+ out = 180633600;
+ else
+ out = 196608000;
+ t = do_div(out, in);
+ int_div = out;
+ t *= 2048;
+ do_div(t, in);
+ frac_div = t;
+ pll_ctl = int_div << SGTL5000_PLL_INT_DIV_SHIFT |
+ frac_div << SGTL5000_PLL_FRAC_DIV_SHIFT;
+
+ snd_soc_write(codec, SGTL5000_CHIP_PLL_CTRL, pll_ctl);
+ if (div2)
+ snd_soc_update_bits(codec,
+ SGTL5000_CHIP_CLK_TOP_CTRL,
+ SGTL5000_INPUT_FREQ_DIV2,
+ SGTL5000_INPUT_FREQ_DIV2);
+ else
+ snd_soc_update_bits(codec,
+ SGTL5000_CHIP_CLK_TOP_CTRL,
+ SGTL5000_INPUT_FREQ_DIV2,
+ 0);
+
+ /* power up pll */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
+ SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP);
+ } else {
+ /* power down pll */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
+ 0);
+ }
+
+ /* if using pll, clk_ctrl must be set after pll power up */
+ snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+
+ return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ * input: params_rate, params_fmt
+ */
+static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ int channels = params_channels(params);
+ int i2s_ctl = 0;
+ int stereo;
+ int ret;
+
+ /* sysclk should already set */
+ if (!sgtl5000->sysclk) {
+ dev_err(codec->dev, "%s: set sysclk first!\n", __func__);
+ return -EFAULT;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ stereo = SGTL5000_DAC_STEREO;
+ else
+ stereo = SGTL5000_ADC_STEREO;
+
+ /* set mono to save power */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, stereo,
+ channels == 1 ? 0 : stereo);
+
+ /* set codec clock base on lrclk */
+ ret = sgtl5000_set_clock(codec, params_rate(params));
+ if (ret)
+ return ret;
+
+ /* set i2s data format */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
+ return -EINVAL;
+ i2s_ctl |= SGTL5000_I2S_DLEN_16 << SGTL5000_I2S_DLEN_SHIFT;
+ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_32FS <<
+ SGTL5000_I2S_SCLKFREQ_SHIFT;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ i2s_ctl |= SGTL5000_I2S_DLEN_20 << SGTL5000_I2S_DLEN_SHIFT;
+ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+ SGTL5000_I2S_SCLKFREQ_SHIFT;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ i2s_ctl |= SGTL5000_I2S_DLEN_24 << SGTL5000_I2S_DLEN_SHIFT;
+ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+ SGTL5000_I2S_SCLKFREQ_SHIFT;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
+ return -EINVAL;
+ i2s_ctl |= SGTL5000_I2S_DLEN_32 << SGTL5000_I2S_DLEN_SHIFT;
+ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
+ SGTL5000_I2S_SCLKFREQ_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl);
+
+ return 0;
+}
+
+static int ldo_regulator_is_enabled(struct regulator_dev *dev)
+{
+ struct ldo_regulator *ldo = rdev_get_drvdata(dev);
+
+ return ldo->enabled;
+}
+
+static int ldo_regulator_enable(struct regulator_dev *dev)
+{
+ struct ldo_regulator *ldo = rdev_get_drvdata(dev);
+ struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data;
+ int reg;
+
+ if (ldo_regulator_is_enabled(dev))
+ return 0;
+
+ /* set regulator value firstly */
+ reg = (1600 - ldo->voltage / 1000) / 50;
+ reg = clamp(reg, 0x0, 0xf);
+
+ /* amend the voltage value, unit: uV */
+ ldo->voltage = (1600 - reg * 50) * 1000;
+
+ /* set voltage to register */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
+ (0x1 << 4) - 1, reg);
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_LINEREG_D_POWERUP,
+ SGTL5000_LINEREG_D_POWERUP);
+
+ /* when internal ldo enabled, simple digital power can be disabled */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_LINREG_SIMPLE_POWERUP,
+ 0);
+
+ ldo->enabled = 1;
+ return 0;
+}
+
+static int ldo_regulator_disable(struct regulator_dev *dev)
+{
+ struct ldo_regulator *ldo = rdev_get_drvdata(dev);
+ struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data;
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_LINEREG_D_POWERUP,
+ 0);
+
+ /* clear voltage info */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
+ (0x1 << 4) - 1, 0);
+
+ ldo->enabled = 0;
+
+ return 0;
+}
+
+static int ldo_regulator_get_voltage(struct regulator_dev *dev)
+{
+ struct ldo_regulator *ldo = rdev_get_drvdata(dev);
+
+ return ldo->voltage;
+}
+
+static struct regulator_ops ldo_regulator_ops = {
+ .is_enabled = ldo_regulator_is_enabled,
+ .enable = ldo_regulator_enable,
+ .disable = ldo_regulator_disable,
+ .get_voltage = ldo_regulator_get_voltage,
+};
+
+static int ldo_regulator_register(struct snd_soc_codec *codec,
+ struct regulator_init_data *init_data,
+ int voltage)
+{
+ struct ldo_regulator *ldo;
+
+ ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL);
+
+ if (!ldo) {
+ dev_err(codec->dev, "failed to allocate ldo_regulator\n");
+ return -ENOMEM;
+ }
+
+ ldo->desc.name = kstrdup(dev_name(codec->dev), GFP_KERNEL);
+ if (!ldo->desc.name) {
+ kfree(ldo);
+ dev_err(codec->dev, "failed to allocate decs name memory\n");
+ return -ENOMEM;
+ }
+
+ ldo->desc.type = REGULATOR_VOLTAGE;
+ ldo->desc.owner = THIS_MODULE;
+ ldo->desc.ops = &ldo_regulator_ops;
+ ldo->desc.n_voltages = 1;
+
+ ldo->codec_data = codec;
+ ldo->voltage = voltage;
+
+ ldo->dev = regulator_register(&ldo->desc, codec->dev,
+ init_data, ldo);
+ if (IS_ERR(ldo->dev)) {
+ int ret = PTR_ERR(ldo->dev);
+
+ dev_err(codec->dev, "failed to register regulator\n");
+ kfree(ldo->desc.name);
+ kfree(ldo);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ldo_regulator_remove(struct snd_soc_codec *codec)
+{
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ struct ldo_regulator *ldo = sgtl5000->ldo;
+
+ if (!ldo)
+ return 0;
+
+ regulator_unregister(ldo->dev);
+ kfree(ldo->desc.name);
+ kfree(ldo);
+
+ return 0;
+}
+
+/*
+ * set dac bias
+ * common state changes:
+ * startup:
+ * off --> standby --> prepare --> on
+ * standby --> prepare --> on
+ *
+ * stop:
+ * on --> prepare --> standby
+ */
+static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ int ret;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(
+ ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (ret)
+ return ret;
+ udelay(10);
+ }
+
+ break;
+ case SND_SOC_BIAS_OFF:
+ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+#define SGTL5000_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops sgtl5000_ops = {
+ .hw_params = sgtl5000_pcm_hw_params,
+ .digital_mute = sgtl5000_digital_mute,
+ .set_fmt = sgtl5000_set_dai_fmt,
+ .set_sysclk = sgtl5000_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver sgtl5000_dai = {
+ .name = "sgtl5000",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ /*
+ * only support 8~48K + 96K,
+ * TODO modify hw_param to support more
+ */
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000,
+ .formats = SGTL5000_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000,
+ .formats = SGTL5000_FORMATS,
+ },
+ .ops = &sgtl5000_ops,
+ .symmetric_rates = 1,
+};
+
+static int sgtl5000_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ switch (reg) {
+ case SGTL5000_CHIP_ID:
+ case SGTL5000_CHIP_ADCDAC_CTRL:
+ case SGTL5000_CHIP_ANA_STATUS:
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_SUSPEND
+static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+/*
+ * restore all sgtl5000 registers,
+ * since a big hole between dap and regular registers,
+ * we will restore them respectively.
+ */
+static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
+{
+ u16 *cache = codec->reg_cache;
+ int i;
+ int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1;
+
+ /* restore regular registers */
+ for (i = 0; i < regular_regs; i++) {
+ int reg = i << 1;
+
+ /* this regs depends on the others */
+ if (reg == SGTL5000_CHIP_ANA_POWER ||
+ reg == SGTL5000_CHIP_CLK_CTRL ||
+ reg == SGTL5000_CHIP_LINREG_CTRL ||
+ reg == SGTL5000_CHIP_LINE_OUT_CTRL ||
+ reg == SGTL5000_CHIP_CLK_CTRL)
+ continue;
+
+ snd_soc_write(codec, reg, cache[i]);
+ }
+
+ /* restore dap registers */
+ for (i = SGTL5000_DAP_REG_OFFSET >> 1;
+ i < SGTL5000_MAX_REG_OFFSET >> 1; i++) {
+ int reg = i << 1;
+
+ snd_soc_write(codec, reg, cache[i]);
+ }
+
+ /*
+ * restore power and other regs according
+ * to set_power() and set_clock()
+ */
+ snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
+ cache[SGTL5000_CHIP_LINREG_CTRL >> 1]);
+
+ snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
+ cache[SGTL5000_CHIP_ANA_POWER >> 1]);
+
+ snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
+ cache[SGTL5000_CHIP_CLK_CTRL >> 1]);
+
+ snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
+ cache[SGTL5000_CHIP_REF_CTRL >> 1]);
+
+ snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
+ cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]);
+ return 0;
+}
+
+static int sgtl5000_resume(struct snd_soc_codec *codec)
+{
+ /* Bring the codec back up to standby to enable regulators */
+ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* Restore registers by cached in memory */
+ sgtl5000_restore_regs(codec);
+ return 0;
+}
+#else
+#define sgtl5000_suspend NULL
+#define sgtl5000_resume NULL
+#endif /* CONFIG_SUSPEND */
+
+/*
+ * sgtl5000 has 3 internal power supplies:
+ * 1. VAG, normally set to vdda/2
+ * 2. chargepump, set to different value
+ * according to voltage of vdda and vddio
+ * 3. line out VAG, normally set to vddio/2
+ *
+ * and should be set according to:
+ * 1. vddd provided by external or not
+ * 2. vdda and vddio voltage value. > 3.1v or not
+ * 3. chip revision >=0x11 or not. If >=0x11, not use external vddd.
+ */
+static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
+{
+ int vddd;
+ int vdda;
+ int vddio;
+ u16 ana_pwr;
+ u16 lreg_ctrl;
+ int vag;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer);
+ vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer);
+ vddd = regulator_get_voltage(sgtl5000->supplies[VDDD].consumer);
+
+ vdda = vdda / 1000;
+ vddio = vddio / 1000;
+ vddd = vddd / 1000;
+
+ if (vdda <= 0 || vddio <= 0 || vddd < 0) {
+ dev_err(codec->dev, "regulator voltage not set correctly\n");
+
+ return -EINVAL;
+ }
+
+ /* according to datasheet, maximum voltage of supplies */
+ if (vdda > 3600 || vddio > 3600 || vddd > 1980) {
+ dev_err(codec->dev,
+ "exceed max voltage vdda %dmv vddio %dma vddd %dma\n",
+ vdda, vddio, vddd);
+
+ return -EINVAL;
+ }
+
+ /* reset value */
+ ana_pwr = snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER);
+ ana_pwr |= SGTL5000_DAC_STEREO |
+ SGTL5000_ADC_STEREO |
+ SGTL5000_REFTOP_POWERUP;
+ lreg_ctrl = snd_soc_read(codec, SGTL5000_CHIP_LINREG_CTRL);
+
+ if (vddio < 3100 && vdda < 3100) {
+ /* enable internal oscillator used for charge pump */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_CLK_TOP_CTRL,
+ SGTL5000_INT_OSC_EN,
+ SGTL5000_INT_OSC_EN);
+ /* Enable VDDC charge pump */
+ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
+ } else if (vddio >= 3100 && vdda >= 3100) {
+ /*
+ * if vddio and vddd > 3.1v,
+ * charge pump should be clean before set ana_pwr
+ */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_VDDC_CHRGPMP_POWERUP, 0);
+
+ /* VDDC use VDDIO rail */
+ lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
+ lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO <<
+ SGTL5000_VDDC_MAN_ASSN_SHIFT;
+ }
+
+ snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
+
+ snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr);
+
+ /* set voltage to register */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
+ (0x1 << 4) - 1, 0x8);
+
+ /*
+ * if vddd linear reg has been enabled,
+ * simple digital supply should be clear to get
+ * proper VDDD voltage.
+ */
+ if (ana_pwr & SGTL5000_LINEREG_D_POWERUP)
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_LINREG_SIMPLE_POWERUP,
+ 0);
+ else
+ snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
+ SGTL5000_LINREG_SIMPLE_POWERUP |
+ SGTL5000_STARTUP_POWERUP,
+ 0);
+
+ /*
+ * set ADC/DAC VAG to vdda / 2,
+ * should stay in range (0.8v, 1.575v)
+ */
+ vag = vdda / 2;
+ if (vag <= SGTL5000_ANA_GND_BASE)
+ vag = 0;
+ else if (vag >= SGTL5000_ANA_GND_BASE + SGTL5000_ANA_GND_STP *
+ (SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT))
+ vag = SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT;
+ else
+ vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
+ vag << SGTL5000_ANA_GND_SHIFT,
+ vag << SGTL5000_ANA_GND_SHIFT);
+
+ /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
+ vag = vddio / 2;
+ if (vag <= SGTL5000_LINE_OUT_GND_BASE)
+ vag = 0;
+ else if (vag >= SGTL5000_LINE_OUT_GND_BASE +
+ SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX)
+ vag = SGTL5000_LINE_OUT_GND_MAX;
+ else
+ vag = (vag - SGTL5000_LINE_OUT_GND_BASE) /
+ SGTL5000_LINE_OUT_GND_STP;
+
+ snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
+ vag << SGTL5000_LINE_OUT_GND_SHIFT |
+ SGTL5000_LINE_OUT_CURRENT_360u <<
+ SGTL5000_LINE_OUT_CURRENT_SHIFT,
+ vag << SGTL5000_LINE_OUT_GND_SHIFT |
+ SGTL5000_LINE_OUT_CURRENT_360u <<
+ SGTL5000_LINE_OUT_CURRENT_SHIFT);
+
+ return 0;
+}
+
+static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
+{
+ u16 reg;
+ int ret;
+ int rev;
+ int i;
+ int external_vddd = 0;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)
+ sgtl5000->supplies[i].supply = supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (!ret)
+ external_vddd = 1;
+ else {
+ /* set internal ldo to 1.2v */
+ int voltage = LDO_VOLTAGE;
+
+ ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to register vddd internal supplies: %d\n",
+ ret);
+ return ret;
+ }
+
+ sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
+
+ ret = regulator_bulk_get(codec->dev,
+ ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+
+ if (ret) {
+ ldo_regulator_remove(codec);
+ dev_err(codec->dev,
+ "Failed to request supplies: %d\n", ret);
+
+ return ret;
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (ret)
+ goto err_regulator_free;
+
+ /* wait for all power rails bring up */
+ udelay(10);
+
+ /* read chip information */
+ reg = snd_soc_read(codec, SGTL5000_CHIP_ID);
+ if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
+ SGTL5000_PARTID_PART_ID) {
+ dev_err(codec->dev,
+ "Device with ID register %x is not a sgtl5000\n", reg);
+ ret = -ENODEV;
+ goto err_regulator_disable;
+ }
+
+ rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
+ dev_info(codec->dev, "sgtl5000 revision %d\n", rev);
+
+ /*
+ * workaround for revision 0x11 and later,
+ * roll back to use internal LDO
+ */
+ if (external_vddd && rev >= 0x11) {
+ int voltage = LDO_VOLTAGE;
+ /* disable all regulator first */
+ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ /* free VDDD regulator */
+ regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+
+ ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
+ if (ret)
+ return ret;
+
+ sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
+
+ ret = regulator_bulk_get(codec->dev,
+ ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (ret) {
+ ldo_regulator_remove(codec);
+ dev_err(codec->dev,
+ "Failed to request supplies: %d\n", ret);
+
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (ret)
+ goto err_regulator_free;
+
+ /* wait for all power rails bring up */
+ udelay(10);
+ }
+
+ return 0;
+
+err_regulator_disable:
+ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+err_regulator_free:
+ regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (external_vddd)
+ ldo_regulator_remove(codec);
+ return ret;
+
+}
+
+static int sgtl5000_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ /* setup i2c data ops */
+ ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ ret = sgtl5000_enable_regulators(codec);
+ if (ret)
+ return ret;
+
+ /* power up sgtl5000 */
+ ret = sgtl5000_set_power_regs(codec);
+ if (ret)
+ goto err;
+
+ /* enable small pop, introduce 400ms delay in turning off */
+ snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
+ SGTL5000_SMALL_POP,
+ SGTL5000_SMALL_POP);
+
+ /* disable short cut detector */
+ snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0);
+
+ /*
+ * set i2s as default input of sound switch
+ * TODO: add sound switch to control and dapm widge.
+ */
+ snd_soc_write(codec, SGTL5000_CHIP_SSS_CTRL,
+ SGTL5000_DAC_SEL_I2S_IN << SGTL5000_DAC_SEL_SHIFT);
+ snd_soc_write(codec, SGTL5000_CHIP_DIG_POWER,
+ SGTL5000_ADC_EN | SGTL5000_DAC_EN);
+
+ /* enable dac volume ramp by default */
+ snd_soc_write(codec, SGTL5000_CHIP_ADCDAC_CTRL,
+ SGTL5000_DAC_VOL_RAMP_EN |
+ SGTL5000_DAC_MUTE_RIGHT |
+ SGTL5000_DAC_MUTE_LEFT);
+
+ snd_soc_write(codec, SGTL5000_CHIP_PAD_STRENGTH, 0x015f);
+
+ snd_soc_write(codec, SGTL5000_CHIP_ANA_CTRL,
+ SGTL5000_HP_ZCD_EN |
+ SGTL5000_ADC_ZCD_EN);
+
+ snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0);
+
+ /*
+ * disable DAP
+ * TODO:
+ * Enable DAP in kcontrol and dapm.
+ */
+ snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
+
+ /* leading to standby state */
+ ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (ret)
+ goto err;
+
+ snd_soc_add_controls(codec, sgtl5000_snd_controls,
+ ARRAY_SIZE(sgtl5000_snd_controls));
+
+ snd_soc_dapm_new_controls(&codec->dapm, sgtl5000_dapm_widgets,
+ ARRAY_SIZE(sgtl5000_dapm_widgets));
+
+ snd_soc_dapm_add_routes(&codec->dapm, audio_map,
+ ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_new_widgets(&codec->dapm);
+
+ return 0;
+
+err:
+ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ ldo_regulator_remove(codec);
+
+ return ret;
+}
+
+static int sgtl5000_remove(struct snd_soc_codec *codec)
+{
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+
+ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ ldo_regulator_remove(codec);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver sgtl5000_driver = {
+ .probe = sgtl5000_probe,
+ .remove = sgtl5000_remove,
+ .suspend = sgtl5000_suspend,
+ .resume = sgtl5000_resume,
+ .set_bias_level = sgtl5000_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(sgtl5000_regs),
+ .reg_word_size = sizeof(u16),
+ .reg_cache_step = 2,
+ .reg_cache_default = sgtl5000_regs,
+ .volatile_register = sgtl5000_volatile_register,
+};
+
+static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct sgtl5000_priv *sgtl5000;
+ int ret;
+
+ sgtl5000 = kzalloc(sizeof(struct sgtl5000_priv), GFP_KERNEL);
+ if (!sgtl5000)
+ return -ENOMEM;
+
+ /*
+ * copy DAP default values to default value array.
+ * sgtl5000 register space has a big hole, merge it
+ * at init phase makes life easy.
+ * FIXME: should we drop 'const' of sgtl5000_regs?
+ */
+ memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)),
+ sgtl5000_dap_regs,
+ SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET);
+
+ i2c_set_clientdata(client, sgtl5000);
+
+ ret = snd_soc_register_codec(&client->dev,
+ &sgtl5000_driver, &sgtl5000_dai, 1);
+ if (ret) {
+ dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+ kfree(sgtl5000);
+ return ret;
+ }
+
+ return 0;
+}
+
+static __devexit int sgtl5000_i2c_remove(struct i2c_client *client)
+{
+ struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+
+ kfree(sgtl5000);
+ return 0;
+}
+
+static const struct i2c_device_id sgtl5000_id[] = {
+ {"sgtl5000", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
+
+static struct i2c_driver sgtl5000_i2c_driver = {
+ .driver = {
+ .name = "sgtl5000",
+ .owner = THIS_MODULE,
+ },
+ .probe = sgtl5000_i2c_probe,
+ .remove = __devexit_p(sgtl5000_i2c_remove),
+ .id_table = sgtl5000_id,
+};
+
+static int __init sgtl5000_modinit(void)
+{
+ return i2c_add_driver(&sgtl5000_i2c_driver);
+}
+module_init(sgtl5000_modinit);
+
+static void __exit sgtl5000_exit(void)
+{
+ i2c_del_driver(&sgtl5000_i2c_driver);
+}
+module_exit(sgtl5000_exit);
+
+MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Zeng Zhaoming <zhaoming.zeng@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
new file mode 100644
index 000000000000..eec3ab368f39
--- /dev/null
+++ b/sound/soc/codecs/sgtl5000.h
@@ -0,0 +1,400 @@
+/*
+ * sgtl5000.h - SGTL5000 audio codec interface
+ *
+ * Copyright 2010-2011 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SGTL5000_H
+#define _SGTL5000_H
+
+/*
+ * Register values.
+ */
+#define SGTL5000_CHIP_ID 0x0000
+#define SGTL5000_CHIP_DIG_POWER 0x0002
+#define SGTL5000_CHIP_CLK_CTRL 0x0004
+#define SGTL5000_CHIP_I2S_CTRL 0x0006
+#define SGTL5000_CHIP_SSS_CTRL 0x000a
+#define SGTL5000_CHIP_ADCDAC_CTRL 0x000e
+#define SGTL5000_CHIP_DAC_VOL 0x0010
+#define SGTL5000_CHIP_PAD_STRENGTH 0x0014
+#define SGTL5000_CHIP_ANA_ADC_CTRL 0x0020
+#define SGTL5000_CHIP_ANA_HP_CTRL 0x0022
+#define SGTL5000_CHIP_ANA_CTRL 0x0024
+#define SGTL5000_CHIP_LINREG_CTRL 0x0026
+#define SGTL5000_CHIP_REF_CTRL 0x0028
+#define SGTL5000_CHIP_MIC_CTRL 0x002a
+#define SGTL5000_CHIP_LINE_OUT_CTRL 0x002c
+#define SGTL5000_CHIP_LINE_OUT_VOL 0x002e
+#define SGTL5000_CHIP_ANA_POWER 0x0030
+#define SGTL5000_CHIP_PLL_CTRL 0x0032
+#define SGTL5000_CHIP_CLK_TOP_CTRL 0x0034
+#define SGTL5000_CHIP_ANA_STATUS 0x0036
+#define SGTL5000_CHIP_SHORT_CTRL 0x003c
+#define SGTL5000_CHIP_ANA_TEST2 0x003a
+#define SGTL5000_DAP_CTRL 0x0100
+#define SGTL5000_DAP_PEQ 0x0102
+#define SGTL5000_DAP_BASS_ENHANCE 0x0104
+#define SGTL5000_DAP_BASS_ENHANCE_CTRL 0x0106
+#define SGTL5000_DAP_AUDIO_EQ 0x0108
+#define SGTL5000_DAP_SURROUND 0x010a
+#define SGTL5000_DAP_FLT_COEF_ACCESS 0x010c
+#define SGTL5000_DAP_COEF_WR_B0_MSB 0x010e
+#define SGTL5000_DAP_COEF_WR_B0_LSB 0x0110
+#define SGTL5000_DAP_EQ_BASS_BAND0 0x0116
+#define SGTL5000_DAP_EQ_BASS_BAND1 0x0118
+#define SGTL5000_DAP_EQ_BASS_BAND2 0x011a
+#define SGTL5000_DAP_EQ_BASS_BAND3 0x011c
+#define SGTL5000_DAP_EQ_BASS_BAND4 0x011e
+#define SGTL5000_DAP_MAIN_CHAN 0x0120
+#define SGTL5000_DAP_MIX_CHAN 0x0122
+#define SGTL5000_DAP_AVC_CTRL 0x0124
+#define SGTL5000_DAP_AVC_THRESHOLD 0x0126
+#define SGTL5000_DAP_AVC_ATTACK 0x0128
+#define SGTL5000_DAP_AVC_DECAY 0x012a
+#define SGTL5000_DAP_COEF_WR_B1_MSB 0x012c
+#define SGTL5000_DAP_COEF_WR_B1_LSB 0x012e
+#define SGTL5000_DAP_COEF_WR_B2_MSB 0x0130
+#define SGTL5000_DAP_COEF_WR_B2_LSB 0x0132
+#define SGTL5000_DAP_COEF_WR_A1_MSB 0x0134
+#define SGTL5000_DAP_COEF_WR_A1_LSB 0x0136
+#define SGTL5000_DAP_COEF_WR_A2_MSB 0x0138
+#define SGTL5000_DAP_COEF_WR_A2_LSB 0x013a
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * SGTL5000_CHIP_ID
+ */
+#define SGTL5000_PARTID_MASK 0xff00
+#define SGTL5000_PARTID_SHIFT 8
+#define SGTL5000_PARTID_WIDTH 8
+#define SGTL5000_PARTID_PART_ID 0xa0
+#define SGTL5000_REVID_MASK 0x00ff
+#define SGTL5000_REVID_SHIFT 0
+#define SGTL5000_REVID_WIDTH 8
+
+/*
+ * SGTL5000_CHIP_DIG_POWER
+ */
+#define SGTL5000_ADC_EN 0x0040
+#define SGTL5000_DAC_EN 0x0020
+#define SGTL5000_DAP_POWERUP 0x0010
+#define SGTL5000_I2S_OUT_POWERUP 0x0002
+#define SGTL5000_I2S_IN_POWERUP 0x0001
+
+/*
+ * SGTL5000_CHIP_CLK_CTRL
+ */
+#define SGTL5000_RATE_MODE_MASK 0x0030
+#define SGTL5000_RATE_MODE_SHIFT 4
+#define SGTL5000_RATE_MODE_WIDTH 2
+#define SGTL5000_RATE_MODE_DIV_1 0
+#define SGTL5000_RATE_MODE_DIV_2 1
+#define SGTL5000_RATE_MODE_DIV_4 2
+#define SGTL5000_RATE_MODE_DIV_6 3
+#define SGTL5000_SYS_FS_MASK 0x000c
+#define SGTL5000_SYS_FS_SHIFT 2
+#define SGTL5000_SYS_FS_WIDTH 2
+#define SGTL5000_SYS_FS_32k 0x0
+#define SGTL5000_SYS_FS_44_1k 0x1
+#define SGTL5000_SYS_FS_48k 0x2
+#define SGTL5000_SYS_FS_96k 0x3
+#define SGTL5000_MCLK_FREQ_MASK 0x0003
+#define SGTL5000_MCLK_FREQ_SHIFT 0
+#define SGTL5000_MCLK_FREQ_WIDTH 2
+#define SGTL5000_MCLK_FREQ_256FS 0x0
+#define SGTL5000_MCLK_FREQ_384FS 0x1
+#define SGTL5000_MCLK_FREQ_512FS 0x2
+#define SGTL5000_MCLK_FREQ_PLL 0x3
+
+/*
+ * SGTL5000_CHIP_I2S_CTRL
+ */
+#define SGTL5000_I2S_SCLKFREQ_MASK 0x0100
+#define SGTL5000_I2S_SCLKFREQ_SHIFT 8
+#define SGTL5000_I2S_SCLKFREQ_WIDTH 1
+#define SGTL5000_I2S_SCLKFREQ_64FS 0x0
+#define SGTL5000_I2S_SCLKFREQ_32FS 0x1 /* Not for RJ mode */
+#define SGTL5000_I2S_MASTER 0x0080
+#define SGTL5000_I2S_SCLK_INV 0x0040
+#define SGTL5000_I2S_DLEN_MASK 0x0030
+#define SGTL5000_I2S_DLEN_SHIFT 4
+#define SGTL5000_I2S_DLEN_WIDTH 2
+#define SGTL5000_I2S_DLEN_32 0x0
+#define SGTL5000_I2S_DLEN_24 0x1
+#define SGTL5000_I2S_DLEN_20 0x2
+#define SGTL5000_I2S_DLEN_16 0x3
+#define SGTL5000_I2S_MODE_MASK 0x000c
+#define SGTL5000_I2S_MODE_SHIFT 2
+#define SGTL5000_I2S_MODE_WIDTH 2
+#define SGTL5000_I2S_MODE_I2S_LJ 0x0
+#define SGTL5000_I2S_MODE_RJ 0x1
+#define SGTL5000_I2S_MODE_PCM 0x2
+#define SGTL5000_I2S_LRALIGN 0x0002
+#define SGTL5000_I2S_LRPOL 0x0001 /* set for which mode */
+
+/*
+ * SGTL5000_CHIP_SSS_CTRL
+ */
+#define SGTL5000_DAP_MIX_LRSWAP 0x4000
+#define SGTL5000_DAP_LRSWAP 0x2000
+#define SGTL5000_DAC_LRSWAP 0x1000
+#define SGTL5000_I2S_OUT_LRSWAP 0x0400
+#define SGTL5000_DAP_MIX_SEL_MASK 0x0300
+#define SGTL5000_DAP_MIX_SEL_SHIFT 8
+#define SGTL5000_DAP_MIX_SEL_WIDTH 2
+#define SGTL5000_DAP_MIX_SEL_ADC 0x0
+#define SGTL5000_DAP_MIX_SEL_I2S_IN 0x1
+#define SGTL5000_DAP_SEL_MASK 0x00c0
+#define SGTL5000_DAP_SEL_SHIFT 6
+#define SGTL5000_DAP_SEL_WIDTH 2
+#define SGTL5000_DAP_SEL_ADC 0x0
+#define SGTL5000_DAP_SEL_I2S_IN 0x1
+#define SGTL5000_DAC_SEL_MASK 0x0030
+#define SGTL5000_DAC_SEL_SHIFT 4
+#define SGTL5000_DAC_SEL_WIDTH 2
+#define SGTL5000_DAC_SEL_ADC 0x0
+#define SGTL5000_DAC_SEL_I2S_IN 0x1
+#define SGTL5000_DAC_SEL_DAP 0x3
+#define SGTL5000_I2S_OUT_SEL_MASK 0x0003
+#define SGTL5000_I2S_OUT_SEL_SHIFT 0
+#define SGTL5000_I2S_OUT_SEL_WIDTH 2
+#define SGTL5000_I2S_OUT_SEL_ADC 0x0
+#define SGTL5000_I2S_OUT_SEL_I2S_IN 0x1
+#define SGTL5000_I2S_OUT_SEL_DAP 0x3
+
+/*
+ * SGTL5000_CHIP_ADCDAC_CTRL
+ */
+#define SGTL5000_VOL_BUSY_DAC_RIGHT 0x2000
+#define SGTL5000_VOL_BUSY_DAC_LEFT 0x1000
+#define SGTL5000_DAC_VOL_RAMP_EN 0x0200
+#define SGTL5000_DAC_VOL_RAMP_EXPO 0x0100
+#define SGTL5000_DAC_MUTE_RIGHT 0x0008
+#define SGTL5000_DAC_MUTE_LEFT 0x0004
+#define SGTL5000_ADC_HPF_FREEZE 0x0002
+#define SGTL5000_ADC_HPF_BYPASS 0x0001
+
+/*
+ * SGTL5000_CHIP_DAC_VOL
+ */
+#define SGTL5000_DAC_VOL_RIGHT_MASK 0xff00
+#define SGTL5000_DAC_VOL_RIGHT_SHIFT 8
+#define SGTL5000_DAC_VOL_RIGHT_WIDTH 8
+#define SGTL5000_DAC_VOL_LEFT_MASK 0x00ff
+#define SGTL5000_DAC_VOL_LEFT_SHIFT 0
+#define SGTL5000_DAC_VOL_LEFT_WIDTH 8
+
+/*
+ * SGTL5000_CHIP_PAD_STRENGTH
+ */
+#define SGTL5000_PAD_I2S_LRCLK_MASK 0x0300
+#define SGTL5000_PAD_I2S_LRCLK_SHIFT 8
+#define SGTL5000_PAD_I2S_LRCLK_WIDTH 2
+#define SGTL5000_PAD_I2S_SCLK_MASK 0x00c0
+#define SGTL5000_PAD_I2S_SCLK_SHIFT 6
+#define SGTL5000_PAD_I2S_SCLK_WIDTH 2
+#define SGTL5000_PAD_I2S_DOUT_MASK 0x0030
+#define SGTL5000_PAD_I2S_DOUT_SHIFT 4
+#define SGTL5000_PAD_I2S_DOUT_WIDTH 2
+#define SGTL5000_PAD_I2C_SDA_MASK 0x000c
+#define SGTL5000_PAD_I2C_SDA_SHIFT 2
+#define SGTL5000_PAD_I2C_SDA_WIDTH 2
+#define SGTL5000_PAD_I2C_SCL_MASK 0x0003
+#define SGTL5000_PAD_I2C_SCL_SHIFT 0
+#define SGTL5000_PAD_I2C_SCL_WIDTH 2
+
+/*
+ * SGTL5000_CHIP_ANA_ADC_CTRL
+ */
+#define SGTL5000_ADC_VOL_M6DB 0x0100
+#define SGTL5000_ADC_VOL_RIGHT_MASK 0x00f0
+#define SGTL5000_ADC_VOL_RIGHT_SHIFT 4
+#define SGTL5000_ADC_VOL_RIGHT_WIDTH 4
+#define SGTL5000_ADC_VOL_LEFT_MASK 0x000f
+#define SGTL5000_ADC_VOL_LEFT_SHIFT 0
+#define SGTL5000_ADC_VOL_LEFT_WIDTH 4
+
+/*
+ * SGTL5000_CHIP_ANA_HP_CTRL
+ */
+#define SGTL5000_HP_VOL_RIGHT_MASK 0x7f00
+#define SGTL5000_HP_VOL_RIGHT_SHIFT 8
+#define SGTL5000_HP_VOL_RIGHT_WIDTH 7
+#define SGTL5000_HP_VOL_LEFT_MASK 0x007f
+#define SGTL5000_HP_VOL_LEFT_SHIFT 0
+#define SGTL5000_HP_VOL_LEFT_WIDTH 7
+
+/*
+ * SGTL5000_CHIP_ANA_CTRL
+ */
+#define SGTL5000_LINE_OUT_MUTE 0x0100
+#define SGTL5000_HP_SEL_MASK 0x0040
+#define SGTL5000_HP_SEL_SHIFT 6
+#define SGTL5000_HP_SEL_WIDTH 1
+#define SGTL5000_HP_SEL_DAC 0x0
+#define SGTL5000_HP_SEL_LINE_IN 0x1
+#define SGTL5000_HP_ZCD_EN 0x0020
+#define SGTL5000_HP_MUTE 0x0010
+#define SGTL5000_ADC_SEL_MASK 0x0004
+#define SGTL5000_ADC_SEL_SHIFT 2
+#define SGTL5000_ADC_SEL_WIDTH 1
+#define SGTL5000_ADC_SEL_MIC 0x0
+#define SGTL5000_ADC_SEL_LINE_IN 0x1
+#define SGTL5000_ADC_ZCD_EN 0x0002
+#define SGTL5000_ADC_MUTE 0x0001
+
+/*
+ * SGTL5000_CHIP_LINREG_CTRL
+ */
+#define SGTL5000_VDDC_MAN_ASSN_MASK 0x0040
+#define SGTL5000_VDDC_MAN_ASSN_SHIFT 6
+#define SGTL5000_VDDC_MAN_ASSN_WIDTH 1
+#define SGTL5000_VDDC_MAN_ASSN_VDDA 0x0
+#define SGTL5000_VDDC_MAN_ASSN_VDDIO 0x1
+#define SGTL5000_VDDC_ASSN_OVRD 0x0020
+#define SGTL5000_LINREG_VDDD_MASK 0x000f
+#define SGTL5000_LINREG_VDDD_SHIFT 0
+#define SGTL5000_LINREG_VDDD_WIDTH 4
+
+/*
+ * SGTL5000_CHIP_REF_CTRL
+ */
+#define SGTL5000_ANA_GND_MASK 0x01f0
+#define SGTL5000_ANA_GND_SHIFT 4
+#define SGTL5000_ANA_GND_WIDTH 5
+#define SGTL5000_ANA_GND_BASE 800 /* mv */
+#define SGTL5000_ANA_GND_STP 25 /*mv */
+#define SGTL5000_BIAS_CTRL_MASK 0x000e
+#define SGTL5000_BIAS_CTRL_SHIFT 1
+#define SGTL5000_BIAS_CTRL_WIDTH 3
+#define SGTL5000_SMALL_POP 0x0001
+
+/*
+ * SGTL5000_CHIP_MIC_CTRL
+ */
+#define SGTL5000_BIAS_R_MASK 0x0200
+#define SGTL5000_BIAS_R_SHIFT 8
+#define SGTL5000_BIAS_R_WIDTH 2
+#define SGTL5000_BIAS_R_off 0x0
+#define SGTL5000_BIAS_R_2K 0x1
+#define SGTL5000_BIAS_R_4k 0x2
+#define SGTL5000_BIAS_R_8k 0x3
+#define SGTL5000_BIAS_VOLT_MASK 0x0070
+#define SGTL5000_BIAS_VOLT_SHIFT 4
+#define SGTL5000_BIAS_VOLT_WIDTH 3
+#define SGTL5000_MIC_GAIN_MASK 0x0003
+#define SGTL5000_MIC_GAIN_SHIFT 0
+#define SGTL5000_MIC_GAIN_WIDTH 2
+
+/*
+ * SGTL5000_CHIP_LINE_OUT_CTRL
+ */
+#define SGTL5000_LINE_OUT_CURRENT_MASK 0x0f00
+#define SGTL5000_LINE_OUT_CURRENT_SHIFT 8
+#define SGTL5000_LINE_OUT_CURRENT_WIDTH 4
+#define SGTL5000_LINE_OUT_CURRENT_180u 0x0
+#define SGTL5000_LINE_OUT_CURRENT_270u 0x1
+#define SGTL5000_LINE_OUT_CURRENT_360u 0x3
+#define SGTL5000_LINE_OUT_CURRENT_450u 0x7
+#define SGTL5000_LINE_OUT_CURRENT_540u 0xf
+#define SGTL5000_LINE_OUT_GND_MASK 0x003f
+#define SGTL5000_LINE_OUT_GND_SHIFT 0
+#define SGTL5000_LINE_OUT_GND_WIDTH 6
+#define SGTL5000_LINE_OUT_GND_BASE 800 /* mv */
+#define SGTL5000_LINE_OUT_GND_STP 25
+#define SGTL5000_LINE_OUT_GND_MAX 0x23
+
+/*
+ * SGTL5000_CHIP_LINE_OUT_VOL
+ */
+#define SGTL5000_LINE_OUT_VOL_RIGHT_MASK 0x1f00
+#define SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT 8
+#define SGTL5000_LINE_OUT_VOL_RIGHT_WIDTH 5
+#define SGTL5000_LINE_OUT_VOL_LEFT_MASK 0x001f
+#define SGTL5000_LINE_OUT_VOL_LEFT_SHIFT 0
+#define SGTL5000_LINE_OUT_VOL_LEFT_WIDTH 5
+
+/*
+ * SGTL5000_CHIP_ANA_POWER
+ */
+#define SGTL5000_DAC_STEREO 0x4000
+#define SGTL5000_LINREG_SIMPLE_POWERUP 0x2000
+#define SGTL5000_STARTUP_POWERUP 0x1000
+#define SGTL5000_VDDC_CHRGPMP_POWERUP 0x0800
+#define SGTL5000_PLL_POWERUP 0x0400
+#define SGTL5000_LINEREG_D_POWERUP 0x0200
+#define SGTL5000_VCOAMP_POWERUP 0x0100
+#define SGTL5000_VAG_POWERUP 0x0080
+#define SGTL5000_ADC_STEREO 0x0040
+#define SGTL5000_REFTOP_POWERUP 0x0020
+#define SGTL5000_HP_POWERUP 0x0010
+#define SGTL5000_DAC_POWERUP 0x0008
+#define SGTL5000_CAPLESS_HP_POWERUP 0x0004
+#define SGTL5000_ADC_POWERUP 0x0002
+#define SGTL5000_LINE_OUT_POWERUP 0x0001
+
+/*
+ * SGTL5000_CHIP_PLL_CTRL
+ */
+#define SGTL5000_PLL_INT_DIV_MASK 0xf800
+#define SGTL5000_PLL_INT_DIV_SHIFT 11
+#define SGTL5000_PLL_INT_DIV_WIDTH 5
+#define SGTL5000_PLL_FRAC_DIV_MASK 0x0700
+#define SGTL5000_PLL_FRAC_DIV_SHIFT 0
+#define SGTL5000_PLL_FRAC_DIV_WIDTH 11
+
+/*
+ * SGTL5000_CHIP_CLK_TOP_CTRL
+ */
+#define SGTL5000_INT_OSC_EN 0x0800
+#define SGTL5000_INPUT_FREQ_DIV2 0x0008
+
+/*
+ * SGTL5000_CHIP_ANA_STATUS
+ */
+#define SGTL5000_HP_LRSHORT 0x0200
+#define SGTL5000_CAPLESS_SHORT 0x0100
+#define SGTL5000_PLL_LOCKED 0x0010
+
+/*
+ * SGTL5000_CHIP_SHORT_CTRL
+ */
+#define SGTL5000_LVLADJR_MASK 0x7000
+#define SGTL5000_LVLADJR_SHIFT 12
+#define SGTL5000_LVLADJR_WIDTH 3
+#define SGTL5000_LVLADJL_MASK 0x0700
+#define SGTL5000_LVLADJL_SHIFT 8
+#define SGTL5000_LVLADJL_WIDTH 3
+#define SGTL5000_LVLADJC_MASK 0x0070
+#define SGTL5000_LVLADJC_SHIFT 4
+#define SGTL5000_LVLADJC_WIDTH 3
+#define SGTL5000_LR_SHORT_MOD_MASK 0x000c
+#define SGTL5000_LR_SHORT_MOD_SHIFT 2
+#define SGTL5000_LR_SHORT_MOD_WIDTH 2
+#define SGTL5000_CM_SHORT_MOD_MASK 0x0003
+#define SGTL5000_CM_SHORT_MOD_SHIFT 0
+#define SGTL5000_CM_SHORT_MOD_WIDTH 2
+
+/*
+ *SGTL5000_CHIP_ANA_TEST2
+ */
+#define SGTL5000_MONO_DAC 0x1000
+
+/*
+ * SGTL5000_DAP_CTRL
+ */
+#define SGTL5000_DAP_MIX_EN 0x0010
+#define SGTL5000_DAP_EN 0x0001
+
+#define SGTL5000_SYSCLK 0x00
+#define SGTL5000_LRCLK 0x01
+
+#endif
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
new file mode 100644
index 000000000000..2a30eae1881c
--- /dev/null
+++ b/sound/soc/codecs/sn95031.c
@@ -0,0 +1,949 @@
+/*
+ * sn95031.c - TI sn95031 Codec driver
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.com>
+ * Author: Harsha Priya <priya.harsha@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <asm/intel_scu_ipc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include "sn95031.h"
+
+#define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100)
+#define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+/* adc helper functions */
+
+/* enables mic bias voltage */
+static void sn95031_enable_mic_bias(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0));
+ snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2));
+}
+
+/* Enable/Disable the ADC depending on the argument */
+static void configure_adc(struct snd_soc_codec *sn95031_codec, int val)
+{
+ int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
+
+ if (val) {
+ /* Enable and start the ADC */
+ value |= (SN95031_ADC_ENBL | SN95031_ADC_START);
+ value &= (~SN95031_ADC_NO_LOOP);
+ } else {
+ /* Just stop the ADC */
+ value &= (~SN95031_ADC_START);
+ }
+ snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value);
+}
+
+/*
+ * finds an empty channel for conversion
+ * If the ADC is not enabled then start using 0th channel
+ * itself. Otherwise find an empty channel by looking for a
+ * channel in which the stopbit is set to 1. returns the index
+ * of the first free channel if succeeds or an error code.
+ *
+ * Context: can sleep
+ *
+ */
+static int find_free_channel(struct snd_soc_codec *sn95031_codec)
+{
+ int ret = 0, i, value;
+
+ /* check whether ADC is enabled */
+ value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
+
+ if ((value & SN95031_ADC_ENBL) == 0)
+ return 0;
+
+ /* ADC is already enabled; Looking for an empty channel */
+ for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) {
+ value = snd_soc_read(sn95031_codec,
+ SN95031_ADC_CHNL_START_ADDR + i);
+ if (value & SN95031_STOPBIT_MASK) {
+ ret = i;
+ break;
+ }
+ }
+ return (ret > SN95031_ADC_LOOP_MAX) ? (-EINVAL) : ret;
+}
+
+/* Initialize the ADC for reading micbias values. Can sleep. */
+static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec)
+{
+ int base_addr, chnl_addr;
+ int value;
+ static int channel_index;
+
+ /* Index of the first channel in which the stop bit is set */
+ channel_index = find_free_channel(sn95031_codec);
+ if (channel_index < 0) {
+ pr_err("No free ADC channels");
+ return channel_index;
+ }
+
+ base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index;
+
+ if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) {
+ /* Reset stop bit for channels other than 0 and 12 */
+ value = snd_soc_read(sn95031_codec, base_addr);
+ /* Set the stop bit to zero */
+ snd_soc_write(sn95031_codec, base_addr, value & 0xEF);
+ /* Index of the first free channel */
+ base_addr++;
+ channel_index++;
+ }
+
+ /* Since this is the last channel, set the stop bit
+ to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
+ snd_soc_write(sn95031_codec, base_addr,
+ SN95031_AUDIO_DETECT_CODE | 0x10);
+
+ chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index;
+ pr_debug("mid_initialize : %x", chnl_addr);
+ configure_adc(sn95031_codec, 1);
+ return chnl_addr;
+}
+
+
+/* reads the ADC registers and gets the mic bias value in mV. */
+static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
+{
+ u16 adc_adr = sn95031_initialize_adc(codec);
+ u16 adc_val1, adc_val2;
+ unsigned int mic_bias;
+
+ sn95031_enable_mic_bias(codec);
+
+ /* Enable the sound card for conversion before reading */
+ snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05);
+ /* Re-toggle the RRDATARD bit */
+ snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04);
+
+ /* Read the higher bits of data */
+ msleep(1000);
+ adc_val1 = snd_soc_read(codec, adc_adr);
+ adc_adr++;
+ adc_val2 = snd_soc_read(codec, adc_adr);
+
+ /* Adding lower two bits to the higher bits */
+ mic_bias = (adc_val1 << 2) + (adc_val2 & 3);
+ mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000;
+ pr_debug("mic bias = %dmV\n", mic_bias);
+ return mic_bias;
+}
+EXPORT_SYMBOL_GPL(sn95031_get_mic_bias);
+/*end - adc helper functions */
+
+static inline unsigned int sn95031_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 value = 0;
+ int ret;
+
+ ret = intel_scu_ipc_ioread8(reg, &value);
+ if (ret)
+ pr_err("read of %x failed, err %d\n", reg, ret);
+ return value;
+
+}
+
+static inline int sn95031_write(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ int ret;
+
+ ret = intel_scu_ipc_iowrite8(reg, value);
+ if (ret)
+ pr_err("write of %x failed, err %d\n", reg, ret);
+ return ret;
+}
+
+static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+ pr_debug("vaud_bias powering up pll\n");
+ /* power up the pll */
+ snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5));
+ /* enable pcm 2 */
+ snd_soc_update_bits(codec, SN95031_PCM2C2,
+ BIT(0), BIT(0));
+ }
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ pr_debug("vaud_bias power up rail\n");
+ /* power up the rail */
+ snd_soc_write(codec, SN95031_VAUD,
+ BIT(2)|BIT(1)|BIT(0));
+ msleep(1);
+ } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+ /* turn off pcm */
+ pr_debug("vaud_bias power dn pcm\n");
+ snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0);
+ snd_soc_write(codec, SN95031_AUDPLLCTRL, 0);
+ }
+ break;
+
+
+ case SND_SOC_BIAS_OFF:
+ pr_debug("vaud_bias _OFF doing rail shutdown\n");
+ snd_soc_write(codec, SN95031_VAUD, BIT(3));
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
+ /* power up the rail */
+ snd_soc_write(w->codec, SN95031_VHSP, 0x3D);
+ snd_soc_write(w->codec, SN95031_VHSN, 0x3F);
+ msleep(1);
+ } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
+ snd_soc_write(w->codec, SN95031_VHSP, 0xC4);
+ snd_soc_write(w->codec, SN95031_VHSN, 0x04);
+ }
+ return 0;
+}
+
+static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
+ /* power up the rail */
+ snd_soc_write(w->codec, SN95031_VIHF, 0x27);
+ msleep(1);
+ } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
+ snd_soc_write(w->codec, SN95031_VIHF, 0x24);
+ }
+ return 0;
+}
+
+static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ldo = BIT(5)|BIT(4);
+ clk_dir = BIT(0);
+ data_dir = BIT(7);
+ }
+ /* program DMIC LDO, clock and set clock */
+ snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+ snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
+ snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir);
+ return 0;
+}
+
+static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ldo = BIT(5)|BIT(4);
+ clk_dir = BIT(2);
+ data_dir = BIT(1);
+ }
+ /* program DMIC LDO, clock and set clock */
+ snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+ snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
+ snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir);
+ return 0;
+}
+
+static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ unsigned int ldo = 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ldo = BIT(7)|BIT(6);
+
+ /* program DMIC LDO */
+ snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
+ return 0;
+}
+
+/* mux controls */
+static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
+
+static const struct soc_enum sn95031_micl_enum =
+ SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts);
+
+static const struct snd_kcontrol_new sn95031_micl_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_micl_enum);
+
+static const struct soc_enum sn95031_micr_enum =
+ SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts);
+
+static const struct snd_kcontrol_new sn95031_micr_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_micr_enum);
+
+static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3",
+ "DMIC4", "DMIC5", "DMIC6",
+ "ADC Left", "ADC Right" };
+
+static const struct soc_enum sn95031_input1_enum =
+ SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts);
+
+static const struct snd_kcontrol_new sn95031_input1_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_input1_enum);
+
+static const struct soc_enum sn95031_input2_enum =
+ SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts);
+
+static const struct snd_kcontrol_new sn95031_input2_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_input2_enum);
+
+static const struct soc_enum sn95031_input3_enum =
+ SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts);
+
+static const struct snd_kcontrol_new sn95031_input3_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_input3_enum);
+
+static const struct soc_enum sn95031_input4_enum =
+ SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts);
+
+static const struct snd_kcontrol_new sn95031_input4_mux_control =
+ SOC_DAPM_ENUM("Route", sn95031_input4_enum);
+
+/* capture path controls */
+
+static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"};
+
+/* 0dB to 30dB in 10dB steps */
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0);
+
+static const struct soc_enum sn95031_micmode1_enum =
+ SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text);
+static const struct soc_enum sn95031_micmode2_enum =
+ SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text);
+
+static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"};
+
+static const struct soc_enum sn95031_dmic12_cfg_enum =
+ SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text);
+static const struct soc_enum sn95031_dmic34_cfg_enum =
+ SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text);
+static const struct soc_enum sn95031_dmic56_cfg_enum =
+ SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text);
+
+static const struct snd_kcontrol_new sn95031_snd_controls[] = {
+ SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum),
+ SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum),
+ SOC_ENUM("DMIC12 Capture Route", sn95031_dmic12_cfg_enum),
+ SOC_ENUM("DMIC34 Capture Route", sn95031_dmic34_cfg_enum),
+ SOC_ENUM("DMIC56 Capture Route", sn95031_dmic56_cfg_enum),
+ SOC_SINGLE_TLV("Mic1 Capture Volume", SN95031_MICAMP1,
+ 2, 4, 0, mic_tlv),
+ SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2,
+ 2, 4, 0, mic_tlv),
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
+
+ /* all end points mic, hs etc */
+ SND_SOC_DAPM_OUTPUT("HPOUTL"),
+ SND_SOC_DAPM_OUTPUT("HPOUTR"),
+ SND_SOC_DAPM_OUTPUT("EPOUT"),
+ SND_SOC_DAPM_OUTPUT("IHFOUTL"),
+ SND_SOC_DAPM_OUTPUT("IHFOUTR"),
+ SND_SOC_DAPM_OUTPUT("LINEOUTL"),
+ SND_SOC_DAPM_OUTPUT("LINEOUTR"),
+ SND_SOC_DAPM_OUTPUT("VIB1OUT"),
+ SND_SOC_DAPM_OUTPUT("VIB2OUT"),
+
+ SND_SOC_DAPM_INPUT("AMIC1"), /* headset mic */
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_INPUT("DMIC3"),
+ SND_SOC_DAPM_INPUT("DMIC4"),
+ SND_SOC_DAPM_INPUT("DMIC5"),
+ SND_SOC_DAPM_INPUT("DMIC6"),
+ SND_SOC_DAPM_INPUT("LINEINL"),
+ SND_SOC_DAPM_INPUT("LINEINR"),
+
+ SND_SOC_DAPM_MICBIAS("AMIC1Bias", SN95031_MICBIAS, 2, 0),
+ SND_SOC_DAPM_MICBIAS("AMIC2Bias", SN95031_MICBIAS, 3, 0),
+ SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0),
+ SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0),
+ SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0),
+
+ SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0,
+ sn95031_dmic12_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("DMIC34supply", SN95031_DMICLK, 1, 0,
+ sn95031_dmic34_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("DMIC56supply", SN95031_DMICLK, 2, 0,
+ sn95031_dmic56_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_OUT("PCM_Out", "Capture", 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0,
+ sn95031_vhs_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0,
+ sn95031_vihf_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* playback path driver enables */
+ SND_SOC_DAPM_PGA("Headset Left Playback",
+ SN95031_DRIVEREN, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Right Playback",
+ SN95031_DRIVEREN, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Left Playback",
+ SN95031_DRIVEREN, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Right Playback",
+ SN95031_DRIVEREN, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Vibra1 Playback",
+ SN95031_DRIVEREN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Vibra2 Playback",
+ SN95031_DRIVEREN, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Earpiece Playback",
+ SN95031_DRIVEREN, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Left Playback",
+ SN95031_LOCTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Lineout Right Playback",
+ SN95031_LOCTL, 4, 0, NULL, 0),
+
+ /* playback path filter enable */
+ SND_SOC_DAPM_PGA("Headset Left Filter",
+ SN95031_HSEPRXCTRL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Headset Right Filter",
+ SN95031_HSEPRXCTRL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Left Filter",
+ SN95031_IHFRXCTRL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker Right Filter",
+ SN95031_IHFRXCTRL, 1, 0, NULL, 0),
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("HSDAC Left", "Headset",
+ SN95031_DACCONFIG, 0, 0),
+ SND_SOC_DAPM_DAC("HSDAC Right", "Headset",
+ SN95031_DACCONFIG, 1, 0),
+ SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker",
+ SN95031_DACCONFIG, 2, 0),
+ SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker",
+ SN95031_DACCONFIG, 3, 0),
+ SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1",
+ SN95031_VIB1C5, 1, 0),
+ SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2",
+ SN95031_VIB2C5, 1, 0),
+
+ /* capture widgets */
+ SND_SOC_DAPM_PGA("LineIn Enable Left", SN95031_MICAMP1,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LineIn Enable Right", SN95031_MICAMP2,
+ 7, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("MIC1 Enable", SN95031_MICAMP1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MIC2 Enable", SN95031_MICAMP2, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("TX1 Enable", SN95031_AUDIOTXEN, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("TX2 Enable", SN95031_AUDIOTXEN, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("TX3 Enable", SN95031_AUDIOTXEN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("TX4 Enable", SN95031_AUDIOTXEN, 5, 0, NULL, 0),
+
+ /* ADC have null stream as they will be turned ON by TX path */
+ SND_SOC_DAPM_ADC("ADC Left", NULL,
+ SN95031_ADCCONFIG, 0, 0),
+ SND_SOC_DAPM_ADC("ADC Right", NULL,
+ SN95031_ADCCONFIG, 2, 0),
+
+ SND_SOC_DAPM_MUX("Mic_InputL Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_micl_mux_control),
+ SND_SOC_DAPM_MUX("Mic_InputR Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_micr_mux_control),
+
+ SND_SOC_DAPM_MUX("Txpath1 Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_input1_mux_control),
+ SND_SOC_DAPM_MUX("Txpath2 Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_input2_mux_control),
+ SND_SOC_DAPM_MUX("Txpath3 Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_input3_mux_control),
+ SND_SOC_DAPM_MUX("Txpath4 Capture Route",
+ SND_SOC_NOPM, 0, 0, &sn95031_input4_mux_control),
+
+};
+
+static const struct snd_soc_dapm_route sn95031_audio_map[] = {
+ /* headset and earpiece map */
+ { "HPOUTL", NULL, "Headset Rail"},
+ { "HPOUTR", NULL, "Headset Rail"},
+ { "HPOUTL", NULL, "Headset Left Playback" },
+ { "HPOUTR", NULL, "Headset Right Playback" },
+ { "EPOUT", NULL, "Earpiece Playback" },
+ { "Headset Left Playback", NULL, "Headset Left Filter"},
+ { "Headset Right Playback", NULL, "Headset Right Filter"},
+ { "Earpiece Playback", NULL, "Headset Left Filter"},
+ { "Headset Left Filter", NULL, "HSDAC Left"},
+ { "Headset Right Filter", NULL, "HSDAC Right"},
+
+ /* speaker map */
+ { "IHFOUTL", NULL, "Speaker Rail"},
+ { "IHFOUTR", NULL, "Speaker Rail"},
+ { "IHFOUTL", "NULL", "Speaker Left Playback"},
+ { "IHFOUTR", "NULL", "Speaker Right Playback"},
+ { "Speaker Left Playback", NULL, "Speaker Left Filter"},
+ { "Speaker Right Playback", NULL, "Speaker Right Filter"},
+ { "Speaker Left Filter", NULL, "IHFDAC Left"},
+ { "Speaker Right Filter", NULL, "IHFDAC Right"},
+
+ /* vibra map */
+ { "VIB1OUT", NULL, "Vibra1 Playback"},
+ { "Vibra1 Playback", NULL, "Vibra1 DAC"},
+
+ { "VIB2OUT", NULL, "Vibra2 Playback"},
+ { "Vibra2 Playback", NULL, "Vibra2 DAC"},
+
+ /* lineout */
+ { "LINEOUTL", NULL, "Lineout Left Playback"},
+ { "LINEOUTR", NULL, "Lineout Right Playback"},
+ { "Lineout Left Playback", NULL, "Headset Left Filter"},
+ { "Lineout Left Playback", NULL, "Speaker Left Filter"},
+ { "Lineout Left Playback", NULL, "Vibra1 DAC"},
+ { "Lineout Right Playback", NULL, "Headset Right Filter"},
+ { "Lineout Right Playback", NULL, "Speaker Right Filter"},
+ { "Lineout Right Playback", NULL, "Vibra2 DAC"},
+
+ /* Headset (AMIC1) mic */
+ { "AMIC1Bias", NULL, "AMIC1"},
+ { "MIC1 Enable", NULL, "AMIC1Bias"},
+ { "Mic_InputL Capture Route", "AMIC", "MIC1 Enable"},
+
+ /* AMIC2 */
+ { "AMIC2Bias", NULL, "AMIC2"},
+ { "MIC2 Enable", NULL, "AMIC2Bias"},
+ { "Mic_InputR Capture Route", "AMIC", "MIC2 Enable"},
+
+
+ /* Linein */
+ { "LineIn Enable Left", NULL, "LINEINL"},
+ { "LineIn Enable Right", NULL, "LINEINR"},
+ { "Mic_InputL Capture Route", "LineIn", "LineIn Enable Left"},
+ { "Mic_InputR Capture Route", "LineIn", "LineIn Enable Right"},
+
+ /* ADC connection */
+ { "ADC Left", NULL, "Mic_InputL Capture Route"},
+ { "ADC Right", NULL, "Mic_InputR Capture Route"},
+
+ /*DMIC connections */
+ { "DMIC1", NULL, "DMIC12supply"},
+ { "DMIC2", NULL, "DMIC12supply"},
+ { "DMIC3", NULL, "DMIC34supply"},
+ { "DMIC4", NULL, "DMIC34supply"},
+ { "DMIC5", NULL, "DMIC56supply"},
+ { "DMIC6", NULL, "DMIC56supply"},
+
+ { "DMIC12Bias", NULL, "DMIC1"},
+ { "DMIC12Bias", NULL, "DMIC2"},
+ { "DMIC34Bias", NULL, "DMIC3"},
+ { "DMIC34Bias", NULL, "DMIC4"},
+ { "DMIC56Bias", NULL, "DMIC5"},
+ { "DMIC56Bias", NULL, "DMIC6"},
+
+ /*TX path inputs*/
+ { "Txpath1 Capture Route", "ADC Left", "ADC Left"},
+ { "Txpath2 Capture Route", "ADC Left", "ADC Left"},
+ { "Txpath3 Capture Route", "ADC Left", "ADC Left"},
+ { "Txpath4 Capture Route", "ADC Left", "ADC Left"},
+ { "Txpath1 Capture Route", "ADC Right", "ADC Right"},
+ { "Txpath2 Capture Route", "ADC Right", "ADC Right"},
+ { "Txpath3 Capture Route", "ADC Right", "ADC Right"},
+ { "Txpath4 Capture Route", "ADC Right", "ADC Right"},
+ { "Txpath1 Capture Route", "DMIC1", "DMIC1"},
+ { "Txpath2 Capture Route", "DMIC1", "DMIC1"},
+ { "Txpath3 Capture Route", "DMIC1", "DMIC1"},
+ { "Txpath4 Capture Route", "DMIC1", "DMIC1"},
+ { "Txpath1 Capture Route", "DMIC2", "DMIC2"},
+ { "Txpath2 Capture Route", "DMIC2", "DMIC2"},
+ { "Txpath3 Capture Route", "DMIC2", "DMIC2"},
+ { "Txpath4 Capture Route", "DMIC2", "DMIC2"},
+ { "Txpath1 Capture Route", "DMIC3", "DMIC3"},
+ { "Txpath2 Capture Route", "DMIC3", "DMIC3"},
+ { "Txpath3 Capture Route", "DMIC3", "DMIC3"},
+ { "Txpath4 Capture Route", "DMIC3", "DMIC3"},
+ { "Txpath1 Capture Route", "DMIC4", "DMIC4"},
+ { "Txpath2 Capture Route", "DMIC4", "DMIC4"},
+ { "Txpath3 Capture Route", "DMIC4", "DMIC4"},
+ { "Txpath4 Capture Route", "DMIC4", "DMIC4"},
+ { "Txpath1 Capture Route", "DMIC5", "DMIC5"},
+ { "Txpath2 Capture Route", "DMIC5", "DMIC5"},
+ { "Txpath3 Capture Route", "DMIC5", "DMIC5"},
+ { "Txpath4 Capture Route", "DMIC5", "DMIC5"},
+ { "Txpath1 Capture Route", "DMIC6", "DMIC6"},
+ { "Txpath2 Capture Route", "DMIC6", "DMIC6"},
+ { "Txpath3 Capture Route", "DMIC6", "DMIC6"},
+ { "Txpath4 Capture Route", "DMIC6", "DMIC6"},
+
+ /* tx path */
+ { "TX1 Enable", NULL, "Txpath1 Capture Route"},
+ { "TX2 Enable", NULL, "Txpath2 Capture Route"},
+ { "TX3 Enable", NULL, "Txpath3 Capture Route"},
+ { "TX4 Enable", NULL, "Txpath4 Capture Route"},
+ { "PCM_Out", NULL, "TX1 Enable"},
+ { "PCM_Out", NULL, "TX2 Enable"},
+ { "PCM_Out", NULL, "TX3 Enable"},
+ { "PCM_Out", NULL, "TX4 Enable"},
+
+};
+
+/* speaker and headset mutes, for audio pops and clicks */
+static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec,
+ SN95031_HSLVOLCTRL, BIT(7), (!mute << 7));
+ snd_soc_update_bits(dai->codec,
+ SN95031_HSRVOLCTRL, BIT(7), (!mute << 7));
+ return 0;
+}
+
+static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec,
+ SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7));
+ snd_soc_update_bits(dai->codec,
+ SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7));
+ return 0;
+}
+
+int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ unsigned int format, rate;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ format = BIT(4)|BIT(5);
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ format = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(dai->codec, SN95031_PCM2C2,
+ BIT(4)|BIT(5), format);
+
+ switch (params_rate(params)) {
+ case 48000:
+ pr_debug("RATE_48000\n");
+ rate = 0;
+ break;
+
+ case 44100:
+ pr_debug("RATE_44100\n");
+ rate = BIT(7);
+ break;
+
+ default:
+ pr_err("ERR rate %d\n", params_rate(params));
+ return -EINVAL;
+ }
+ snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate);
+
+ return 0;
+}
+
+/* Codec DAI section */
+static struct snd_soc_dai_ops sn95031_headset_dai_ops = {
+ .digital_mute = sn95031_pcm_hs_mute,
+ .hw_params = sn95031_pcm_hw_params,
+};
+
+static struct snd_soc_dai_ops sn95031_speaker_dai_ops = {
+ .digital_mute = sn95031_pcm_spkr_mute,
+ .hw_params = sn95031_pcm_hw_params,
+};
+
+static struct snd_soc_dai_ops sn95031_vib1_dai_ops = {
+ .hw_params = sn95031_pcm_hw_params,
+};
+
+static struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
+ .hw_params = sn95031_pcm_hw_params,
+};
+
+struct snd_soc_dai_driver sn95031_dais[] = {
+{
+ .name = "SN95031 Headset",
+ .playback = {
+ .stream_name = "Headset",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SN95031_RATES,
+ .formats = SN95031_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 5,
+ .rates = SN95031_RATES,
+ .formats = SN95031_FORMATS,
+ },
+ .ops = &sn95031_headset_dai_ops,
+},
+{ .name = "SN95031 Speaker",
+ .playback = {
+ .stream_name = "Speaker",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SN95031_RATES,
+ .formats = SN95031_FORMATS,
+ },
+ .ops = &sn95031_speaker_dai_ops,
+},
+{ .name = "SN95031 Vibra1",
+ .playback = {
+ .stream_name = "Vibra1",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SN95031_RATES,
+ .formats = SN95031_FORMATS,
+ },
+ .ops = &sn95031_vib1_dai_ops,
+},
+{ .name = "SN95031 Vibra2",
+ .playback = {
+ .stream_name = "Vibra2",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SN95031_RATES,
+ .formats = SN95031_FORMATS,
+ },
+ .ops = &sn95031_vib2_dai_ops,
+},
+};
+
+static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec, SN95031_BTNCTRL2, 0x00);
+}
+
+static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec)
+{
+ snd_soc_write(codec, SN95031_BTNCTRL1, 0x77);
+ snd_soc_write(codec, SN95031_BTNCTRL2, 0x01);
+}
+
+static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack)
+{
+ int micbias = sn95031_get_mic_bias(mfld_jack->codec);
+
+ int jack_type = snd_soc_jack_get_type(mfld_jack, micbias);
+
+ pr_debug("jack type detected = %d\n", jack_type);
+ if (jack_type == SND_JACK_HEADSET)
+ sn95031_enable_jack_btn(mfld_jack->codec);
+ return jack_type;
+}
+
+void sn95031_jack_detection(struct mfld_jack_data *jack_data)
+{
+ unsigned int status;
+ unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET;
+
+ pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id);
+ if (jack_data->intr_id & 0x1) {
+ pr_debug("short_push detected\n");
+ status = SND_JACK_HEADSET | SND_JACK_BTN_0;
+ } else if (jack_data->intr_id & 0x2) {
+ pr_debug("long_push detected\n");
+ status = SND_JACK_HEADSET | SND_JACK_BTN_1;
+ } else if (jack_data->intr_id & 0x4) {
+ pr_debug("headset or headphones inserted\n");
+ status = sn95031_get_headset_state(jack_data->mfld_jack);
+ } else if (jack_data->intr_id & 0x8) {
+ pr_debug("headset or headphones removed\n");
+ status = 0;
+ sn95031_disable_jack_btn(jack_data->mfld_jack->codec);
+ } else {
+ pr_err("unidentified interrupt\n");
+ return;
+ }
+
+ snd_soc_jack_report(jack_data->mfld_jack, status, mask);
+ /*button pressed and released so we send explicit button release */
+ if ((status & SND_JACK_BTN_0) | (status & SND_JACK_BTN_1))
+ snd_soc_jack_report(jack_data->mfld_jack,
+ SND_JACK_HEADSET, mask);
+}
+EXPORT_SYMBOL_GPL(sn95031_jack_detection);
+
+/* codec registration */
+static int sn95031_codec_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ pr_debug("codec_probe called\n");
+
+ codec->dapm.bias_level = SND_SOC_BIAS_OFF;
+ codec->dapm.idle_bias_off = 1;
+
+ /* PCM interface config
+ * This sets the pcm rx slot conguration to max 6 slots
+ * for max 4 dais (2 stereo and 2 mono)
+ */
+ snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10);
+ snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32);
+ snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54);
+ snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10);
+ snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32);
+ /* pcm port setting
+ * This sets the pcm port to slave and clock at 19.2Mhz which
+ * can support 6slots, sampling rate set per stream in hw-params
+ */
+ snd_soc_write(codec, SN95031_PCM1C1, 0x00);
+ snd_soc_write(codec, SN95031_PCM2C1, 0x01);
+ snd_soc_write(codec, SN95031_PCM2C2, 0x0A);
+ snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4));
+ /* vendor vibra workround, the vibras are muted by
+ * custom register so unmute them
+ */
+ snd_soc_write(codec, SN95031_SSR5, 0x80);
+ snd_soc_write(codec, SN95031_SSR6, 0x80);
+ snd_soc_write(codec, SN95031_VIB1C5, 0x00);
+ snd_soc_write(codec, SN95031_VIB2C5, 0x00);
+ /* configure vibras for pcm port */
+ snd_soc_write(codec, SN95031_VIB1C3, 0x00);
+ snd_soc_write(codec, SN95031_VIB2C3, 0x00);
+
+ /* soft mute ramp time */
+ snd_soc_write(codec, SN95031_SOFTMUTE, 0x3);
+ /* fix the initial volume at 1dB,
+ * default in +9dB,
+ * 1dB give optimal swing on DAC, amps
+ */
+ snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08);
+ snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08);
+ snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08);
+ snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08);
+ /* dac mode and lineout workaround */
+ snd_soc_write(codec, SN95031_SSR2, 0x10);
+ snd_soc_write(codec, SN95031_SSR3, 0x40);
+
+ snd_soc_add_controls(codec, sn95031_snd_controls,
+ ARRAY_SIZE(sn95031_snd_controls));
+
+ ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets,
+ ARRAY_SIZE(sn95031_dapm_widgets));
+ if (ret)
+ pr_err("soc_dapm_new_control failed %d", ret);
+ ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map,
+ ARRAY_SIZE(sn95031_audio_map));
+ if (ret)
+ pr_err("soc_dapm_add_routes failed %d", ret);
+
+ return ret;
+}
+
+static int sn95031_codec_remove(struct snd_soc_codec *codec)
+{
+ pr_debug("codec_remove called\n");
+ sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+struct snd_soc_codec_driver sn95031_codec = {
+ .probe = sn95031_codec_probe,
+ .remove = sn95031_codec_remove,
+ .read = sn95031_read,
+ .write = sn95031_write,
+ .set_bias_level = sn95031_set_vaud_bias,
+};
+
+static int __devinit sn95031_device_probe(struct platform_device *pdev)
+{
+ pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev));
+ return snd_soc_register_codec(&pdev->dev, &sn95031_codec,
+ sn95031_dais, ARRAY_SIZE(sn95031_dais));
+}
+
+static int __devexit sn95031_device_remove(struct platform_device *pdev)
+{
+ pr_debug("codec device remove called\n");
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver sn95031_codec_driver = {
+ .driver = {
+ .name = "sn95031",
+ .owner = THIS_MODULE,
+ },
+ .probe = sn95031_device_probe,
+ .remove = sn95031_device_remove,
+};
+
+static int __init sn95031_init(void)
+{
+ pr_debug("driver init called\n");
+ return platform_driver_register(&sn95031_codec_driver);
+}
+module_init(sn95031_init);
+
+static void __exit sn95031_exit(void)
+{
+ pr_debug("driver exit called\n");
+ platform_driver_unregister(&sn95031_codec_driver);
+}
+module_exit(sn95031_exit);
+
+MODULE_DESCRIPTION("ASoC TI SN95031 codec driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sn95031");
diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h
new file mode 100644
index 000000000000..20376d234fb8
--- /dev/null
+++ b/sound/soc/codecs/sn95031.h
@@ -0,0 +1,132 @@
+/*
+ * sn95031.h - TI sn95031 Codec driver
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.com>
+ * Author: Harsha Priya <priya.harsha@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#ifndef _SN95031_H
+#define _SN95031_H
+
+/*register map*/
+#define SN95031_VAUD 0xDB
+#define SN95031_VHSP 0xDC
+#define SN95031_VHSN 0xDD
+#define SN95031_VIHF 0xC9
+
+#define SN95031_AUDPLLCTRL 0x240
+#define SN95031_DMICBUF0123 0x241
+#define SN95031_DMICBUF45 0x242
+#define SN95031_DMICGPO 0x244
+#define SN95031_DMICMUX 0x245
+#define SN95031_DMICLK 0x246
+#define SN95031_MICBIAS 0x247
+#define SN95031_ADCCONFIG 0x248
+#define SN95031_MICAMP1 0x249
+#define SN95031_MICAMP2 0x24A
+#define SN95031_NOISEMUX 0x24B
+#define SN95031_AUDIOMUX12 0x24C
+#define SN95031_AUDIOMUX34 0x24D
+#define SN95031_AUDIOSINC 0x24E
+#define SN95031_AUDIOTXEN 0x24F
+#define SN95031_HSEPRXCTRL 0x250
+#define SN95031_IHFRXCTRL 0x251
+#define SN95031_HSMIXER 0x256
+#define SN95031_DACCONFIG 0x257
+#define SN95031_SOFTMUTE 0x258
+#define SN95031_HSLVOLCTRL 0x259
+#define SN95031_HSRVOLCTRL 0x25A
+#define SN95031_IHFLVOLCTRL 0x25B
+#define SN95031_IHFRVOLCTRL 0x25C
+#define SN95031_DRIVEREN 0x25D
+#define SN95031_LOCTL 0x25E
+#define SN95031_VIB1C1 0x25F
+#define SN95031_VIB1C2 0x260
+#define SN95031_VIB1C3 0x261
+#define SN95031_VIB1SPIPCM1 0x262
+#define SN95031_VIB1SPIPCM2 0x263
+#define SN95031_VIB1C5 0x264
+#define SN95031_VIB2C1 0x265
+#define SN95031_VIB2C2 0x266
+#define SN95031_VIB2C3 0x267
+#define SN95031_VIB2SPIPCM1 0x268
+#define SN95031_VIB2SPIPCM2 0x269
+#define SN95031_VIB2C5 0x26A
+#define SN95031_BTNCTRL1 0x26B
+#define SN95031_BTNCTRL2 0x26C
+#define SN95031_PCM1TXSLOT01 0x26D
+#define SN95031_PCM1TXSLOT23 0x26E
+#define SN95031_PCM1TXSLOT45 0x26F
+#define SN95031_PCM1RXSLOT0_3 0x270
+#define SN95031_PCM1RXSLOT45 0x271
+#define SN95031_PCM2TXSLOT01 0x272
+#define SN95031_PCM2TXSLOT23 0x273
+#define SN95031_PCM2TXSLOT45 0x274
+#define SN95031_PCM2RXSLOT01 0x275
+#define SN95031_PCM2RXSLOT23 0x276
+#define SN95031_PCM2RXSLOT45 0x277
+#define SN95031_PCM1C1 0x278
+#define SN95031_PCM1C2 0x279
+#define SN95031_PCM1C3 0x27A
+#define SN95031_PCM2C1 0x27B
+#define SN95031_PCM2C2 0x27C
+/*end codec register defn*/
+
+/*vendor defn these are not part of avp*/
+#define SN95031_SSR2 0x381
+#define SN95031_SSR3 0x382
+#define SN95031_SSR5 0x384
+#define SN95031_SSR6 0x385
+
+/* ADC registers */
+
+#define SN95031_ADC1CNTL1 0x1C0
+#define SN95031_ADC_ENBL 0x10
+#define SN95031_ADC_START 0x08
+#define SN95031_ADC1CNTL3 0x1C2
+#define SN95031_ADCTHERM_ENBL 0x04
+#define SN95031_ADCRRDATA_ENBL 0x05
+#define SN95031_STOPBIT_MASK 16
+#define SN95031_ADCTHERM_MASK 4
+#define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */
+#define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1)
+#define SN95031_ADC_NO_LOOP 0x07
+#define SN95031_AUDIO_GPIO_CTRL 0x070
+
+/* ADC channel code values */
+#define SN95031_AUDIO_DETECT_CODE 0x06
+
+/* ADC base addresses */
+#define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */
+#define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */
+/* multipier to convert to mV */
+#define SN95031_ADC_ONE_LSB_MULTIPLIER 2346
+
+
+struct mfld_jack_data {
+ int intr_id;
+ int micbias_vol;
+ struct snd_soc_jack *mfld_jack;
+};
+
+extern void sn95031_jack_detection(struct mfld_jack_data *jack_data);
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
new file mode 100644
index 000000000000..e93b9d1ae1dd
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -0,0 +1,794 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4.c
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <sound/tlv320aic32x4.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "tlv320aic32x4.h"
+
+struct aic32x4_rate_divs {
+ u32 mclk;
+ u32 rate;
+ u8 p_val;
+ u8 pll_j;
+ u16 pll_d;
+ u16 dosr;
+ u8 ndac;
+ u8 mdac;
+ u8 aosr;
+ u8 nadc;
+ u8 madc;
+ u8 blck_N;
+};
+
+struct aic32x4_priv {
+ u32 sysclk;
+ s32 master;
+ u8 page_no;
+ void *control_data;
+ u32 power_cfg;
+ u32 micpga_routing;
+ bool swapdacs;
+};
+
+/* 0dB min, 1dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0);
+/* 0dB min, 0.5dB steps */
+static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0);
+
+static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
+ AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5),
+ SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1),
+ SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1),
+ SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
+ AIC32X4_HPRGAIN, 6, 0x01, 1),
+ SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
+ AIC32X4_LORGAIN, 6, 0x01, 1),
+ SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
+ AIC32X4_RMICPGAVOL, 7, 0x01, 1),
+
+ SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
+ SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
+
+ SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL,
+ AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5),
+ SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
+ AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+
+ SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
+
+ SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
+ SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
+ SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
+ 4, 0x07, 0),
+ SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
+ 0, 0x03, 0),
+ SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
+ 6, 0x03, 0),
+ SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
+ 1, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
+ 0, 0x7F, 0),
+ SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
+ 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
+ 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
+ 0, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
+ 0, 0x0F, 0),
+};
+
+static const struct aic32x4_rate_divs aic32x4_divs[] = {
+ /* 8k rate */
+ {AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
+ {AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
+ {AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
+ /* 11.025k rate */
+ {AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
+ {AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
+ /* 16k rate */
+ {AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
+ {AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
+ {AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
+ /* 22.05k rate */
+ {AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
+ {AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
+ {AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
+ /* 32k rate */
+ {AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+ {AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
+ /* 44.1k rate */
+ {AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+ {AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
+ {AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
+ /* 48k rate */
+ {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+ {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
+ {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}
+};
+
+static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
+ SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpr_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0),
+ SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer_controls[] = {
+ SOC_DAPM_SINGLE("IN1_L P Switch", AIC32X4_LMICPGAPIN, 6, 1, 0),
+ SOC_DAPM_SINGLE("IN2_L P Switch", AIC32X4_LMICPGAPIN, 4, 1, 0),
+ SOC_DAPM_SINGLE("IN3_L P Switch", AIC32X4_LMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer_controls[] = {
+ SOC_DAPM_SINGLE("IN1_R P Switch", AIC32X4_RMICPGAPIN, 6, 1, 0),
+ SOC_DAPM_SINGLE("IN2_R P Switch", AIC32X4_RMICPGAPIN, 4, 1, 0),
+ SOC_DAPM_SINGLE("IN3_R P Switch", AIC32X4_RMICPGAPIN, 2, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0),
+ SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
+ &hpl_output_mixer_controls[0],
+ ARRAY_SIZE(hpl_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
+ &lol_output_mixer_controls[0],
+ ARRAY_SIZE(lol_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0),
+ SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
+ &hpr_output_mixer_controls[0],
+ ARRAY_SIZE(hpr_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
+ &lor_output_mixer_controls[0],
+ ARRAY_SIZE(lor_output_mixer_controls)),
+ SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
+ &left_input_mixer_controls[0],
+ ARRAY_SIZE(left_input_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
+ &right_input_mixer_controls[0],
+ ARRAY_SIZE(right_input_mixer_controls)),
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
+ SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0),
+
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("LOL"),
+ SND_SOC_DAPM_OUTPUT("LOR"),
+ SND_SOC_DAPM_INPUT("IN1_L"),
+ SND_SOC_DAPM_INPUT("IN1_R"),
+ SND_SOC_DAPM_INPUT("IN2_L"),
+ SND_SOC_DAPM_INPUT("IN2_R"),
+ SND_SOC_DAPM_INPUT("IN3_L"),
+ SND_SOC_DAPM_INPUT("IN3_R"),
+};
+
+static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
+ /* Left Output */
+ {"HPL Output Mixer", "L_DAC Switch", "Left DAC"},
+ {"HPL Output Mixer", "IN1_L Switch", "IN1_L"},
+
+ {"HPL Power", NULL, "HPL Output Mixer"},
+ {"HPL", NULL, "HPL Power"},
+
+ {"LOL Output Mixer", "L_DAC Switch", "Left DAC"},
+
+ {"LOL Power", NULL, "LOL Output Mixer"},
+ {"LOL", NULL, "LOL Power"},
+
+ /* Right Output */
+ {"HPR Output Mixer", "R_DAC Switch", "Right DAC"},
+ {"HPR Output Mixer", "IN1_R Switch", "IN1_R"},
+
+ {"HPR Power", NULL, "HPR Output Mixer"},
+ {"HPR", NULL, "HPR Power"},
+
+ {"LOR Output Mixer", "R_DAC Switch", "Right DAC"},
+
+ {"LOR Power", NULL, "LOR Output Mixer"},
+ {"LOR", NULL, "LOR Power"},
+
+ /* Left input */
+ {"Left Input Mixer", "IN1_L P Switch", "IN1_L"},
+ {"Left Input Mixer", "IN2_L P Switch", "IN2_L"},
+ {"Left Input Mixer", "IN3_L P Switch", "IN3_L"},
+
+ {"Left ADC", NULL, "Left Input Mixer"},
+
+ /* Right Input */
+ {"Right Input Mixer", "IN1_R P Switch", "IN1_R"},
+ {"Right Input Mixer", "IN2_R P Switch", "IN2_R"},
+ {"Right Input Mixer", "IN3_R P Switch", "IN3_R"},
+
+ {"Right ADC", NULL, "Right Input Mixer"},
+};
+
+static inline int aic32x4_change_page(struct snd_soc_codec *codec,
+ unsigned int new_page)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 data[2];
+ int ret;
+
+ data[0] = 0x00;
+ data[1] = new_page & 0xff;
+
+ ret = codec->hw_write(codec->control_data, data, 2);
+ if (ret == 2) {
+ aic32x4->page_no = new_page;
+ return 0;
+ } else {
+ return ret;
+ }
+}
+
+static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ unsigned int page = reg / 128;
+ unsigned int fixed_reg = reg % 128;
+ u8 data[2];
+ int ret;
+
+ /* A write to AIC32X4_PSEL is really a non-explicit page change */
+ if (reg == AIC32X4_PSEL)
+ return aic32x4_change_page(codec, val);
+
+ if (aic32x4->page_no != page) {
+ ret = aic32x4_change_page(codec, page);
+ if (ret != 0)
+ return ret;
+ }
+
+ data[0] = fixed_reg & 0xff;
+ data[1] = val & 0xff;
+
+ if (codec->hw_write(codec->control_data, data, 2) == 2)
+ return 0;
+ else
+ return -EIO;
+}
+
+static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ unsigned int page = reg / 128;
+ unsigned int fixed_reg = reg % 128;
+ int ret;
+
+ if (aic32x4->page_no != page) {
+ ret = aic32x4_change_page(codec, page);
+ if (ret != 0)
+ return ret;
+ }
+ return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff);
+}
+
+static inline int aic32x4_get_divs(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
+ if ((aic32x4_divs[i].rate == rate)
+ && (aic32x4_divs[i].mclk == mclk)) {
+ return i;
+ }
+ }
+ printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
+ return -EINVAL;
+}
+
+static int aic32x4_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(&codec->dapm, aic32x4_dapm_widgets,
+ ARRAY_SIZE(aic32x4_dapm_widgets));
+
+ snd_soc_dapm_add_routes(&codec->dapm, aic32x4_dapm_routes,
+ ARRAY_SIZE(aic32x4_dapm_routes));
+
+ snd_soc_dapm_new_widgets(&codec->dapm);
+ return 0;
+}
+
+static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+
+ switch (freq) {
+ case AIC32X4_FREQ_12000000:
+ case AIC32X4_FREQ_24000000:
+ case AIC32X4_FREQ_25000000:
+ aic32x4->sysclk = freq;
+ return 0;
+ }
+ printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
+ return -EINVAL;
+}
+
+static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 iface_reg_1;
+ u8 iface_reg_2;
+ u8 iface_reg_3;
+
+ iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1);
+ iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2);
+ iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2);
+ iface_reg_2 = 0;
+ iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3);
+ iface_reg_3 = iface_reg_3 & ~(1 << 3);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aic32x4->master = 1;
+ iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ aic32x4->master = 0;
+ break;
+ default:
+ printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
+ iface_reg_3 |= (1 << 3); /* invert bit clock */
+ iface_reg_2 = 0x01; /* add offset 1 */
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT);
+ iface_reg_3 |= (1 << 3); /* invert bit clock */
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface_reg_1 |=
+ (AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface_reg_1 |=
+ (AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT);
+ break;
+ default:
+ printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1);
+ snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2);
+ snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3);
+ return 0;
+}
+
+static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 data;
+ int i;
+
+ i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
+ if (i < 0) {
+ printk(KERN_ERR "aic32x4: sampling rate not supported\n");
+ return i;
+ }
+
+ /* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */
+ snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN);
+ snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK);
+
+ /* We will fix R value to 1 and will make P & J=K.D as varialble */
+ data = snd_soc_read(codec, AIC32X4_PLLPR);
+ data &= ~(7 << 4);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (data | (aic32x4_divs[i].p_val << 4) | 0x01));
+
+ snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
+
+ snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
+ snd_soc_write(codec, AIC32X4_PLLDLSB,
+ (aic32x4_divs[i].pll_d & 0xff));
+
+ /* NDAC divider value */
+ data = snd_soc_read(codec, AIC32X4_NDAC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac);
+
+ /* MDAC divider value */
+ data = snd_soc_read(codec, AIC32X4_MDAC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac);
+
+ /* DOSR MSB & LSB values */
+ snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
+ snd_soc_write(codec, AIC32X4_DOSRLSB,
+ (aic32x4_divs[i].dosr & 0xff));
+
+ /* NADC divider value */
+ data = snd_soc_read(codec, AIC32X4_NADC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc);
+
+ /* MADC divider value */
+ data = snd_soc_read(codec, AIC32X4_MADC);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc);
+
+ /* AOSR value */
+ snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+
+ /* BCLK N divider */
+ data = snd_soc_read(codec, AIC32X4_BCLKN);
+ data &= ~(0x7f);
+ snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N);
+
+ data = snd_soc_read(codec, AIC32X4_IFACE1);
+ data = data & ~(3 << 4);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT);
+ break;
+ }
+ snd_soc_write(codec, AIC32X4_IFACE1, data);
+
+ return 0;
+}
+
+static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u8 dac_reg;
+
+ dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON;
+ if (mute)
+ snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON);
+ else
+ snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg);
+ return 0;
+}
+
+static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u8 value;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ if (aic32x4->master) {
+ /* Switch on PLL */
+ value = snd_soc_read(codec, AIC32X4_PLLPR);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (value | AIC32X4_PLLEN));
+
+ /* Switch on NDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_NDAC);
+ snd_soc_write(codec, AIC32X4_NDAC,
+ value | AIC32X4_NDACEN);
+
+ /* Switch on MDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_MDAC);
+ snd_soc_write(codec, AIC32X4_MDAC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on NADC Divider */
+ value = snd_soc_read(codec, AIC32X4_NADC);
+ snd_soc_write(codec, AIC32X4_NADC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on MADC Divider */
+ value = snd_soc_read(codec, AIC32X4_MADC);
+ snd_soc_write(codec, AIC32X4_MADC,
+ value | AIC32X4_MDACEN);
+
+ /* Switch on BCLK_N Divider */
+ value = snd_soc_read(codec, AIC32X4_BCLKN);
+ snd_soc_write(codec, AIC32X4_BCLKN,
+ value | AIC32X4_BCLKEN);
+ }
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (aic32x4->master) {
+ /* Switch off PLL */
+ value = snd_soc_read(codec, AIC32X4_PLLPR);
+ snd_soc_write(codec, AIC32X4_PLLPR,
+ (value & ~AIC32X4_PLLEN));
+
+ /* Switch off NDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_NDAC);
+ snd_soc_write(codec, AIC32X4_NDAC,
+ value & ~AIC32X4_NDACEN);
+
+ /* Switch off MDAC Divider */
+ value = snd_soc_read(codec, AIC32X4_MDAC);
+ snd_soc_write(codec, AIC32X4_MDAC,
+ value & ~AIC32X4_MDACEN);
+
+ /* Switch off NADC Divider */
+ value = snd_soc_read(codec, AIC32X4_NADC);
+ snd_soc_write(codec, AIC32X4_NADC,
+ value & ~AIC32X4_NDACEN);
+
+ /* Switch off MADC Divider */
+ value = snd_soc_read(codec, AIC32X4_MADC);
+ snd_soc_write(codec, AIC32X4_MADC,
+ value & ~AIC32X4_MDACEN);
+ value = snd_soc_read(codec, AIC32X4_BCLKN);
+
+ /* Switch off BCLK_N Divider */
+ snd_soc_write(codec, AIC32X4_BCLKN,
+ value & ~AIC32X4_BCLKEN);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+#define AIC32X4_RATES SNDRV_PCM_RATE_8000_48000
+#define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops aic32x4_ops = {
+ .hw_params = aic32x4_hw_params,
+ .digital_mute = aic32x4_mute,
+ .set_fmt = aic32x4_set_dai_fmt,
+ .set_sysclk = aic32x4_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver aic32x4_dai = {
+ .name = "tlv320aic32x4-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC32X4_RATES,
+ .formats = AIC32X4_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC32X4_RATES,
+ .formats = AIC32X4_FORMATS,},
+ .ops = &aic32x4_ops,
+ .symmetric_rates = 1,
+};
+
+static int aic32x4_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int aic32x4_resume(struct snd_soc_codec *codec)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+
+static int aic32x4_probe(struct snd_soc_codec *codec)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
+ u32 tmp_reg;
+
+ codec->hw_write = (hw_write_t) i2c_master_send;
+ codec->control_data = aic32x4->control_data;
+
+ snd_soc_write(codec, AIC32X4_RESET, 0x01);
+
+ /* Power platform configuration */
+ if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
+ snd_soc_write(codec, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
+ AIC32X4_MICBIAS_2075V);
+ }
+ if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) {
+ snd_soc_write(codec, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
+ }
+ if (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) {
+ snd_soc_write(codec, AIC32X4_LDOCTL, AIC32X4_LDOCTLEN);
+ }
+ tmp_reg = snd_soc_read(codec, AIC32X4_CMMODE);
+ if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36) {
+ tmp_reg |= AIC32X4_LDOIN_18_36;
+ }
+ if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED) {
+ tmp_reg |= AIC32X4_LDOIN2HP;
+ }
+ snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg);
+
+ /* Do DACs need to be swapped? */
+ if (aic32x4->swapdacs) {
+ snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN);
+ } else {
+ snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN);
+ }
+
+ /* Mic PGA routing */
+ if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
+ snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
+ }
+ if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
+ snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
+ }
+
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ snd_soc_add_controls(codec, aic32x4_snd_controls,
+ ARRAY_SIZE(aic32x4_snd_controls));
+ aic32x4_add_widgets(codec);
+
+ return 0;
+}
+
+static int aic32x4_remove(struct snd_soc_codec *codec)
+{
+ aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
+ .read = aic32x4_read,
+ .write = aic32x4_write,
+ .probe = aic32x4_probe,
+ .remove = aic32x4_remove,
+ .suspend = aic32x4_suspend,
+ .resume = aic32x4_resume,
+ .set_bias_level = aic32x4_set_bias_level,
+};
+
+static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct aic32x4_pdata *pdata = i2c->dev.platform_data;
+ struct aic32x4_priv *aic32x4;
+ int ret;
+
+ aic32x4 = kzalloc(sizeof(struct aic32x4_priv), GFP_KERNEL);
+ if (aic32x4 == NULL)
+ return -ENOMEM;
+
+ aic32x4->control_data = i2c;
+ i2c_set_clientdata(i2c, aic32x4);
+
+ if (pdata) {
+ aic32x4->power_cfg = pdata->power_cfg;
+ aic32x4->swapdacs = pdata->swapdacs;
+ aic32x4->micpga_routing = pdata->micpga_routing;
+ } else {
+ aic32x4->power_cfg = 0;
+ aic32x4->swapdacs = false;
+ aic32x4->micpga_routing = 0;
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_aic32x4, &aic32x4_dai, 1);
+ if (ret < 0)
+ kfree(aic32x4);
+ return ret;
+}
+
+static __devexit int aic32x4_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id aic32x4_i2c_id[] = {
+ { "tlv320aic32x4", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
+
+static struct i2c_driver aic32x4_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic32x4",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic32x4_i2c_probe,
+ .remove = __devexit_p(aic32x4_i2c_remove),
+ .id_table = aic32x4_i2c_id,
+};
+
+static int __init aic32x4_modinit(void)
+{
+ int ret = 0;
+
+ ret = i2c_add_driver(&aic32x4_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n",
+ ret);
+ }
+ return ret;
+}
+module_init(aic32x4_modinit);
+
+static void __exit aic32x4_exit(void)
+{
+ i2c_del_driver(&aic32x4_i2c_driver);
+}
+module_exit(aic32x4_exit);
+
+MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
new file mode 100644
index 000000000000..aae2b2440398
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -0,0 +1,143 @@
+/*
+ * tlv320aic32x4.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#ifndef _TLV320AIC32X4_H
+#define _TLV320AIC32X4_H
+
+/* tlv320aic32x4 register space (in decimal to match datasheet) */
+
+#define AIC32X4_PAGE1 128
+
+#define AIC32X4_PSEL 0
+#define AIC32X4_RESET 1
+#define AIC32X4_CLKMUX 4
+#define AIC32X4_PLLPR 5
+#define AIC32X4_PLLJ 6
+#define AIC32X4_PLLDMSB 7
+#define AIC32X4_PLLDLSB 8
+#define AIC32X4_NDAC 11
+#define AIC32X4_MDAC 12
+#define AIC32X4_DOSRMSB 13
+#define AIC32X4_DOSRLSB 14
+#define AIC32X4_NADC 18
+#define AIC32X4_MADC 19
+#define AIC32X4_AOSR 20
+#define AIC32X4_CLKMUX2 25
+#define AIC32X4_CLKOUTM 26
+#define AIC32X4_IFACE1 27
+#define AIC32X4_IFACE2 28
+#define AIC32X4_IFACE3 29
+#define AIC32X4_BCLKN 30
+#define AIC32X4_IFACE4 31
+#define AIC32X4_IFACE5 32
+#define AIC32X4_IFACE6 33
+#define AIC32X4_DOUTCTL 53
+#define AIC32X4_DINCTL 54
+#define AIC32X4_DACSPB 60
+#define AIC32X4_ADCSPB 61
+#define AIC32X4_DACSETUP 63
+#define AIC32X4_DACMUTE 64
+#define AIC32X4_LDACVOL 65
+#define AIC32X4_RDACVOL 66
+#define AIC32X4_ADCSETUP 81
+#define AIC32X4_ADCFGA 82
+#define AIC32X4_LADCVOL 83
+#define AIC32X4_RADCVOL 84
+#define AIC32X4_LAGC1 86
+#define AIC32X4_LAGC2 87
+#define AIC32X4_LAGC3 88
+#define AIC32X4_LAGC4 89
+#define AIC32X4_LAGC5 90
+#define AIC32X4_LAGC6 91
+#define AIC32X4_LAGC7 92
+#define AIC32X4_RAGC1 94
+#define AIC32X4_RAGC2 95
+#define AIC32X4_RAGC3 96
+#define AIC32X4_RAGC4 97
+#define AIC32X4_RAGC5 98
+#define AIC32X4_RAGC6 99
+#define AIC32X4_RAGC7 100
+#define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1)
+#define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2)
+#define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9)
+#define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10)
+#define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12)
+#define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13)
+#define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14)
+#define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15)
+#define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16)
+#define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17)
+#define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18)
+#define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19)
+#define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20)
+#define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51)
+#define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52)
+#define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54)
+#define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55)
+#define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57)
+#define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58)
+#define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59)
+#define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60)
+
+#define AIC32X4_FREQ_12000000 12000000
+#define AIC32X4_FREQ_24000000 24000000
+#define AIC32X4_FREQ_25000000 25000000
+
+#define AIC32X4_WORD_LEN_16BITS 0x00
+#define AIC32X4_WORD_LEN_20BITS 0x01
+#define AIC32X4_WORD_LEN_24BITS 0x02
+#define AIC32X4_WORD_LEN_32BITS 0x03
+
+#define AIC32X4_I2S_MODE 0x00
+#define AIC32X4_DSP_MODE 0x01
+#define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02
+#define AIC32X4_LEFT_JUSTIFIED_MODE 0x03
+
+#define AIC32X4_AVDDWEAKDISABLE 0x08
+#define AIC32X4_LDOCTLEN 0x01
+
+#define AIC32X4_LDOIN_18_36 0x01
+#define AIC32X4_LDOIN2HP 0x02
+
+#define AIC32X4_DACSPBLOCK_MASK 0x1f
+#define AIC32X4_ADCSPBLOCK_MASK 0x1f
+
+#define AIC32X4_PLLJ_SHIFT 6
+#define AIC32X4_DOSRMSB_SHIFT 4
+
+#define AIC32X4_PLLCLKIN 0x03
+
+#define AIC32X4_MICBIAS_LDOIN 0x08
+#define AIC32X4_MICBIAS_2075V 0x60
+
+#define AIC32X4_LMICPGANIN_IN2R_10K 0x10
+#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
+
+#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
+#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
+
+#define AIC32X4_BCLKMASTER 0x08
+#define AIC32X4_WCLKMASTER 0x04
+#define AIC32X4_PLLEN (0x01 << 7)
+#define AIC32X4_NDACEN (0x01 << 7)
+#define AIC32X4_MDACEN (0x01 << 7)
+#define AIC32X4_NADCEN (0x01 << 7)
+#define AIC32X4_MADCEN (0x01 << 7)
+#define AIC32X4_BCLKEN (0x01 << 7)
+#define AIC32X4_DACEN (0x03 << 6)
+#define AIC32X4_RDAC2LCHN (0x02 << 2)
+#define AIC32X4_LDAC2RCHN (0x02 << 4)
+#define AIC32X4_LDAC2LCHN (0x01 << 4)
+#define AIC32X4_RDAC2RCHN (0x01 << 2)
+
+#define AIC32X4_SSTEP2WCLK 0x01
+#define AIC32X4_MUTEON 0x0C
+#define AIC32X4_DACMOD2BCLK 0x01
+
+#endif /* _TLV320AIC32X4_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 71d7be8ac488..00b6d87e7bdb 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1615,6 +1615,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
},
{ },
};
+MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id);
static struct i2c_driver tlv320dac33_i2c_driver = {
.driver = {
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 4bbf1b15a493..482fcdb59bfa 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -724,8 +724,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
return 0;
}
-void twl6040_hs_jack_report(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack, int report)
+static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int report)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int status;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 80ddf4fd23db..a3b9cbb20ee9 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -836,24 +836,25 @@ static void wm2000_i2c_shutdown(struct i2c_client *i2c)
}
#ifdef CONFIG_PM
-static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int wm2000_i2c_suspend(struct device *dev)
{
+ struct i2c_client *i2c = to_i2c_client(dev);
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
return wm2000_anc_transition(wm2000, ANC_OFF);
}
-static int wm2000_i2c_resume(struct i2c_client *i2c)
+static int wm2000_i2c_resume(struct device *dev)
{
+ struct i2c_client *i2c = to_i2c_client(dev);
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
return wm2000_anc_set_mode(wm2000);
}
-#else
-#define wm2000_i2c_suspend NULL
-#define wm2000_i2c_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(wm2000_pm, wm2000_i2c_suspend, wm2000_i2c_resume);
+
static const struct i2c_device_id wm2000_i2c_id[] = {
{ "wm2000", 0 },
{ }
@@ -864,11 +865,10 @@ static struct i2c_driver wm2000_i2c_driver = {
.driver = {
.name = "wm2000",
.owner = THIS_MODULE,
+ .pm = &wm2000_pm,
},
.probe = wm2000_i2c_probe,
.remove = __devexit_p(wm2000_i2c_remove),
- .suspend = wm2000_i2c_suspend,
- .resume = wm2000_i2c_resume,
.shutdown = wm2000_i2c_shutdown,
.id_table = wm2000_i2c_id,
};
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 5eb2f501ce32..4fd4d8dca0fc 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -58,7 +58,7 @@ static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = {
0x0000, /* R8 - ZERO_DETECT */
};
-static int wm8523_volatile_register(unsigned int reg)
+static int wm8523_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8523_DEVICE_ID:
@@ -414,7 +414,6 @@ static int wm8523_resume(struct snd_soc_codec *codec)
static int wm8523_probe(struct snd_soc_codec *codec)
{
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = codec->reg_cache;
int ret, i;
codec->hw_write = (hw_write_t)i2c_master_send;
@@ -471,8 +470,9 @@ static int wm8523_probe(struct snd_soc_codec *codec)
}
/* Change some default settings - latch VU and enable ZC */
- reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
- reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
+ snd_soc_update_bits(codec, WM8523_DAC_GAINR,
+ WM8523_DACR_VU, WM8523_DACR_VU);
+ snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 494f2d31d75b..25af901fe813 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -421,7 +421,6 @@ static int wm8741_resume(struct snd_soc_codec *codec)
static int wm8741_probe(struct snd_soc_codec *codec)
{
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = codec->reg_cache;
int ret = 0;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
@@ -437,10 +436,14 @@ static int wm8741_probe(struct snd_soc_codec *codec)
}
/* Change some default settings - latch VU */
- reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
- reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
- reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
- reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+ snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION,
+ WM8741_UPDATELL, WM8741_UPDATELL);
+ snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION,
+ WM8741_UPDATELM, WM8741_UPDATELM);
+ snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+ WM8741_UPDATERL, WM8741_UPDATERL);
+ snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
+ WM8741_UPDATERM, WM8741_UPDATERM);
snd_soc_add_controls(codec, wm8741_snd_controls,
ARRAY_SIZE(wm8741_snd_controls));
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 79b02ae125c5..3f09deea8d9d 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -55,8 +55,10 @@ static int caps_charge = 2000;
module_param(caps_charge, int, 0);
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
- struct snd_soc_dai *dai, unsigned int hifi);
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
+ unsigned int fmt);
+static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
+ unsigned int fmt);
/*
* wm8753 register cache
@@ -87,6 +89,10 @@ struct wm8753_priv {
enum snd_soc_control_type control_type;
unsigned int sysclk;
unsigned int pcmclk;
+
+ unsigned int voice_fmt;
+ unsigned int hifi_fmt;
+
int dai_func;
};
@@ -170,9 +176,9 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- int mode = snd_soc_read(codec, WM8753_IOCTL);
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
- ucontrol->value.integer.value[0] = (mode & 0xc) >> 2;
+ ucontrol->value.integer.value[0] = wm8753->dai_func;
return 0;
}
@@ -180,16 +186,26 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- int mode = snd_soc_read(codec, WM8753_IOCTL);
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ u16 ioctl;
+
+ if (codec->active)
+ return -EBUSY;
+
+ ioctl = snd_soc_read(codec, WM8753_IOCTL);
+
+ wm8753->dai_func = ucontrol->value.integer.value[0];
+
+ if (((ioctl >> 2) & 0x3) == wm8753->dai_func)
+ return 1;
+
+ ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2);
+ snd_soc_write(codec, WM8753_IOCTL, ioctl);
- if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
- return 0;
- mode &= 0xfff3;
- mode |= (ucontrol->value.integer.value[0] << 2);
+ wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt);
+ wm8753_voice_write_dai_fmt(codec, wm8753->voice_fmt);
- wm8753->dai_func = ucontrol->value.integer.value[0];
return 1;
}
@@ -828,10 +844,9 @@ static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/*
* Set's ADC and Voice DAC format.
*/
-static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec;
/* interface format */
@@ -858,13 +873,6 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- wm8753_set_dai_mode(dai->codec, dai, 0);
- return 0;
-}
-
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -905,10 +913,9 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
/*
* Set's PCM dai fmt and BCLK.
*/
-static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 voice, ioctl;
voice = snd_soc_read(codec, WM8753_PCM) & 0x011f;
@@ -999,10 +1006,9 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
/*
* Set's HiFi DAC format.
*/
-static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0;
/* interface format */
@@ -1032,10 +1038,9 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai,
/*
* Set's I2S DAI format.
*/
-static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 ioctl, hifi;
hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f;
@@ -1098,13 +1103,6 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- wm8753_set_dai_mode(dai->codec, dai, 1);
- return 0;
-}
-
/*
* Set PCM DAI bit size and sample rate.
*/
@@ -1147,61 +1145,117 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 clock;
/* set clk source as pcmclk */
clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
snd_soc_write(codec, WM8753_CLOCK, clock);
- if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
- return -EINVAL;
- return wm8753_pcm_set_dai_fmt(codec_dai, fmt);
+ return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
}
-static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
- return -EINVAL;
- return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
+ return wm8753_hdac_set_dai_fmt(codec, fmt);
}
-static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 clock;
/* set clk source as pcmclk */
clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
snd_soc_write(codec, WM8753_CLOCK, clock);
- if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
- return -EINVAL;
- return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
+ return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
}
-static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec *codec,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
u16 clock;
/* set clk source as mclk */
clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb;
snd_soc_write(codec, WM8753_CLOCK, clock | 0x4);
- if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0)
+ if (wm8753_hdac_set_dai_fmt(codec, fmt) < 0)
return -EINVAL;
- if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0)
- return -EINVAL;
- return wm8753_i2s_set_dai_fmt(codec_dai, fmt);
+ return wm8753_vdac_adc_set_dai_fmt(codec, fmt);
}
+static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec,
+ unsigned int fmt)
+{
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ switch (wm8753->dai_func) {
+ case 0:
+ ret = wm8753_mode1h_set_dai_fmt(codec, fmt);
+ break;
+ case 1:
+ ret = wm8753_mode2_set_dai_fmt(codec, fmt);
+ break;
+ case 2:
+ case 3:
+ ret = wm8753_mode3_4_set_dai_fmt(codec, fmt);
+ break;
+ default:
+ break;
+ }
+ if (ret)
+ return ret;
+
+ return wm8753_i2s_set_dai_fmt(codec, fmt);
+}
+
+static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ wm8753->hifi_fmt = fmt;
+
+ return wm8753_hifi_write_dai_fmt(codec, fmt);
+};
+
+static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec,
+ unsigned int fmt)
+{
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ if (wm8753->dai_func != 0)
+ return 0;
+
+ ret = wm8753_mode1v_set_dai_fmt(codec, fmt);
+ if (ret)
+ return ret;
+ ret = wm8753_pcm_set_dai_fmt(codec, fmt);
+ if (ret)
+ return ret;
+
+ return 0;
+};
+
+static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+ wm8753->voice_fmt = fmt;
+
+ return wm8753_voice_write_dai_fmt(codec, fmt);
+};
+
static int wm8753_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
@@ -1268,57 +1322,25 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
* 3. Voice disabled - HIFI over HIFI
* 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
*/
-static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
- .startup = wm8753_i2s_startup,
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = {
.hw_params = wm8753_i2s_hw_params,
.digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode1h_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
-};
-
-static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
- .startup = wm8753_pcm_startup,
- .hw_params = wm8753_pcm_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode1v_set_dai_fmt,
+ .set_fmt = wm8753_hifi_set_dai_fmt,
.set_clkdiv = wm8753_set_dai_clkdiv,
.set_pll = wm8753_set_dai_pll,
.set_sysclk = wm8753_set_dai_sysclk,
};
-static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
- .startup = wm8753_pcm_startup,
+static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = {
.hw_params = wm8753_pcm_hw_params,
.digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode2_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
-};
-
-static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
- .startup = wm8753_i2s_startup,
- .hw_params = wm8753_i2s_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode3_4_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
-};
-
-static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
- .startup = wm8753_i2s_startup,
- .hw_params = wm8753_i2s_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode3_4_set_dai_fmt,
+ .set_fmt = wm8753_voice_set_dai_fmt,
.set_clkdiv = wm8753_set_dai_clkdiv,
.set_pll = wm8753_set_dai_pll,
.set_sysclk = wm8753_set_dai_sysclk,
};
-static struct snd_soc_dai_driver wm8753_all_dai[] = {
+static struct snd_soc_dai_driver wm8753_dai[] = {
/* DAI HiFi mode 1 */
{ .name = "wm8753-hifi",
.playback = {
@@ -1326,14 +1348,16 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = {
.channels_min = 1,
.channels_max = 2,
.rates = WM8753_RATES,
- .formats = WM8753_FORMATS},
+ .formats = WM8753_FORMATS
+ },
.capture = { /* dummy for fast DAI switching */
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8753_RATES,
- .formats = WM8753_FORMATS},
- .ops = &wm8753_dai_ops_hifi_mode1,
+ .formats = WM8753_FORMATS
+ },
+ .ops = &wm8753_dai_ops_hifi_mode,
},
/* DAI Voice mode 1 */
{ .name = "wm8753-voice",
@@ -1342,97 +1366,19 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = {
.channels_min = 1,
.channels_max = 1,
.rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .ops = &wm8753_dai_ops_voice_mode1,
-},
-/* DAI HiFi mode 2 - dummy */
-{ .name = "wm8753-hifi",
-},
-/* DAI Voice mode 2 */
-{ .name = "wm8753-voice",
- .playback = {
- .stream_name = "Voice Playback",
- .channels_min = 1,
- .channels_max = 1,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .ops = &wm8753_dai_ops_voice_mode2,
-},
-/* DAI HiFi mode 3 */
-{ .name = "wm8753-hifi",
- .playback = {
- .stream_name = "HiFi Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .ops = &wm8753_dai_ops_hifi_mode3,
-},
-/* DAI Voice mode 3 - dummy */
-{ .name = "wm8753-voice",
-},
-/* DAI HiFi mode 4 */
-{ .name = "wm8753-hifi",
- .playback = {
- .stream_name = "HiFi Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
+ .formats = WM8753_FORMATS,
+ },
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8753_RATES,
- .formats = WM8753_FORMATS,},
- .ops = &wm8753_dai_ops_hifi_mode4,
-},
-/* DAI Voice mode 4 - dummy */
-{ .name = "wm8753-voice",
-},
-};
-
-static struct snd_soc_dai_driver wm8753_dai[] = {
- {
- .name = "wm8753-aif0",
- },
- {
- .name = "wm8753-aif1",
+ .formats = WM8753_FORMATS,
},
+ .ops = &wm8753_dai_ops_voice_mode,
+},
};
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
- struct snd_soc_dai *dai, unsigned int hifi)
-{
- struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
-
- if (wm8753->dai_func < 4) {
- if (hifi)
- dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
- else
- dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
- }
- snd_soc_write(codec, WM8753_IOCTL, wm8753->dai_func);
-}
-
static void wm8753_work(struct work_struct *work)
{
struct snd_soc_dapm_context *dapm =
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 6dae1b40c9f7..6785688f8806 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -175,7 +175,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static int wm8804_volatile(unsigned int reg)
+static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8804_RST_DEVID1:
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index cd0959926d12..449ea09a193d 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -180,7 +180,7 @@ static const u16 wm8900_reg_defaults[WM8900_MAXREG] = {
/* Remaining registers all zero */
};
-static int wm8900_volatile_register(unsigned int reg)
+static int wm8900_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8900_REG_ID:
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 017d99ceb42e..ae1cadfae84c 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -2,6 +2,7 @@
* wm8903.c -- WM8903 ALSA SoC Audio driver
*
* Copyright 2008 Wolfson Microelectronics
+ * Copyright 2011 NVIDIA, Inc.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
@@ -19,6 +20,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/gpio.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
@@ -213,6 +215,7 @@ static u16 wm8903_reg_defaults[] = {
};
struct wm8903_priv {
+ struct snd_soc_codec *codec;
int sysclk;
int irq;
@@ -220,25 +223,36 @@ struct wm8903_priv {
int fs;
int deemph;
+ int dcs_pending;
+ int dcs_cache[4];
+
/* Reference count */
int class_w_users;
- struct completion wseq;
-
struct snd_soc_jack *mic_jack;
int mic_det;
int mic_short;
int mic_last_report;
int mic_delay;
+
+#ifdef CONFIG_GPIOLIB
+ struct gpio_chip gpio_chip;
+#endif
};
-static int wm8903_volatile_register(unsigned int reg)
+static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8903_SW_RESET_AND_ID:
case WM8903_REVISION_NUMBER:
case WM8903_INTERRUPT_STATUS_1:
case WM8903_WRITE_SEQUENCER_4:
+ case WM8903_POWER_MANAGEMENT_3:
+ case WM8903_POWER_MANAGEMENT_2:
+ case WM8903_DC_SERVO_READBACK_1:
+ case WM8903_DC_SERVO_READBACK_2:
+ case WM8903_DC_SERVO_READBACK_3:
+ case WM8903_DC_SERVO_READBACK_4:
return 1;
default:
@@ -246,50 +260,6 @@ static int wm8903_volatile_register(unsigned int reg)
}
}
-static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
-{
- u16 reg[5];
- struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-
- BUG_ON(start > 48);
-
- /* Enable the sequencer if it's not already on */
- reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0);
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
- reg[0] | WM8903_WSEQ_ENA);
-
- dev_dbg(codec->dev, "Starting sequence at %d\n", start);
-
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
- start | WM8903_WSEQ_START);
-
- /* Wait for it to complete. If we have the interrupt wired up then
- * that will break us out of the poll early.
- */
- do {
- wait_for_completion_timeout(&wm8903->wseq,
- msecs_to_jiffies(10));
-
- reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
- } while (reg[4] & WM8903_WSEQ_BUSY);
-
- dev_dbg(codec->dev, "Sequence complete\n");
-
- /* Disable the sequencer again if we enabled it */
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
-
- return 0;
-}
-
-static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache)
-{
- int i;
-
- /* There really ought to be something better we can do here :/ */
- for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++)
- cache[i] = codec->hw_read(codec, i);
-}
-
static void wm8903_reset(struct snd_soc_codec *codec)
{
snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0);
@@ -297,11 +267,6 @@ static void wm8903_reset(struct snd_soc_codec *codec)
sizeof(wm8903_reg_defaults));
}
-#define WM8903_OUTPUT_SHORT 0x8
-#define WM8903_OUTPUT_OUT 0x4
-#define WM8903_OUTPUT_INT 0x2
-#define WM8903_OUTPUT_IN 0x1
-
static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -311,97 +276,101 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
return 0;
}
-/*
- * Event for headphone and line out amplifier power changes. Special
- * power up/down sequences are required in order to maximise pop/click
- * performance.
- */
-static int wm8903_output_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 val;
- u16 reg;
- u16 dcs_reg;
- u16 dcs_bit;
- int shift;
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
- switch (w->reg) {
- case WM8903_POWER_MANAGEMENT_2:
- reg = WM8903_ANALOGUE_HP_0;
- dcs_bit = 0 + w->shift;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ wm8903->dcs_pending |= 1 << w->shift;
break;
- case WM8903_POWER_MANAGEMENT_3:
- reg = WM8903_ANALOGUE_LINEOUT_0;
- dcs_bit = 2 + w->shift;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, WM8903_DC_SERVO_0,
+ 1 << w->shift, 0);
break;
- default:
- BUG();
- return -EINVAL; /* Spurious warning from some compilers */
}
- switch (w->shift) {
- case 0:
- shift = 0;
- break;
- case 1:
- shift = 4;
- break;
- default:
- BUG();
- return -EINVAL; /* Spurious warning from some compilers */
- }
+ return 0;
+}
- if (event & SND_SOC_DAPM_PRE_PMU) {
- val = snd_soc_read(codec, reg);
+#define WM8903_DCS_MODE_WRITE_STOP 0
+#define WM8903_DCS_MODE_START_STOP 2
- /* Short the output */
- val &= ~(WM8903_OUTPUT_SHORT << shift);
- snd_soc_write(codec, reg, val);
- }
+static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
+ enum snd_soc_dapm_type event, int subseq)
+{
+ struct snd_soc_codec *codec = container_of(dapm,
+ struct snd_soc_codec, dapm);
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+ int dcs_mode = WM8903_DCS_MODE_WRITE_STOP;
+ int i, val;
- if (event & SND_SOC_DAPM_POST_PMU) {
- val = snd_soc_read(codec, reg);
+ /* Complete any pending DC servo starts */
+ if (wm8903->dcs_pending) {
+ dev_dbg(codec->dev, "Starting DC servo for %x\n",
+ wm8903->dcs_pending);
- val |= (WM8903_OUTPUT_IN << shift);
- snd_soc_write(codec, reg, val);
+ /* If we've no cached values then we need to do startup */
+ for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
+ if (!(wm8903->dcs_pending & (1 << i)))
+ continue;
- val |= (WM8903_OUTPUT_INT << shift);
- snd_soc_write(codec, reg, val);
+ if (wm8903->dcs_cache[i]) {
+ dev_dbg(codec->dev,
+ "Restore DC servo %d value %x\n",
+ 3 - i, wm8903->dcs_cache[i]);
+
+ snd_soc_write(codec, WM8903_DC_SERVO_4 + i,
+ wm8903->dcs_cache[i] & 0xff);
+ } else {
+ dev_dbg(codec->dev,
+ "Calibrate DC servo %d\n", 3 - i);
+ dcs_mode = WM8903_DCS_MODE_START_STOP;
+ }
+ }
- /* Turn on the output ENA_OUTP */
- val |= (WM8903_OUTPUT_OUT << shift);
- snd_soc_write(codec, reg, val);
+ /* Don't trust the cache for analogue */
+ if (wm8903->class_w_users)
+ dcs_mode = WM8903_DCS_MODE_START_STOP;
- /* Enable the DC servo */
- dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
- dcs_reg |= dcs_bit;
- snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+ snd_soc_update_bits(codec, WM8903_DC_SERVO_2,
+ WM8903_DCS_MODE_MASK, dcs_mode);
- /* Remove the short */
- val |= (WM8903_OUTPUT_SHORT << shift);
- snd_soc_write(codec, reg, val);
- }
+ snd_soc_update_bits(codec, WM8903_DC_SERVO_0,
+ WM8903_DCS_ENA_MASK, wm8903->dcs_pending);
- if (event & SND_SOC_DAPM_PRE_PMD) {
- val = snd_soc_read(codec, reg);
+ switch (dcs_mode) {
+ case WM8903_DCS_MODE_WRITE_STOP:
+ break;
- /* Short the output */
- val &= ~(WM8903_OUTPUT_SHORT << shift);
- snd_soc_write(codec, reg, val);
+ case WM8903_DCS_MODE_START_STOP:
+ msleep(270);
- /* Disable the DC servo */
- dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0);
- dcs_reg &= ~dcs_bit;
- snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg);
+ /* Cache the measured offsets for digital */
+ if (wm8903->class_w_users)
+ break;
- /* Then disable the intermediate and output stages */
- val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
- WM8903_OUTPUT_IN) << shift);
- snd_soc_write(codec, reg, val);
- }
+ for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) {
+ if (!(wm8903->dcs_pending & (1 << i)))
+ continue;
- return 0;
+ val = snd_soc_read(codec,
+ WM8903_DC_SERVO_READBACK_1 + i);
+ dev_dbg(codec->dev, "DC servo %d: %x\n",
+ 3 - i, val);
+ wm8903->dcs_cache[i] = val;
+ }
+ break;
+
+ default:
+ pr_warn("DCS mode %d delay not set\n", dcs_mode);
+ break;
+ }
+
+ wm8903->dcs_pending = 0;
+ }
}
/*
@@ -667,6 +636,22 @@ static const struct soc_enum lsidetone_enum =
static const struct soc_enum rsidetone_enum =
SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
+static const char *aif_text[] = {
+ "Left", "Right"
+};
+
+static const struct soc_enum lcapture_enum =
+ SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text);
+
+static const struct soc_enum rcapture_enum =
+ SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text);
+
+static const struct soc_enum lplay_enum =
+ SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text);
+
+static const struct soc_enum rplay_enum =
+ SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text);
+
static const struct snd_kcontrol_new wm8903_snd_controls[] = {
/* Input PGAs - No TLV since the scale depends on PGA mode */
@@ -784,6 +769,18 @@ static const struct snd_kcontrol_new lsidetone_mux =
static const struct snd_kcontrol_new rsidetone_mux =
SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
+static const struct snd_kcontrol_new lcapture_mux =
+ SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
+
+static const struct snd_kcontrol_new rcapture_mux =
+ SOC_DAPM_ENUM("Right Capture Mux", rcapture_enum);
+
+static const struct snd_kcontrol_new lplay_mux =
+ SOC_DAPM_ENUM("Left Playback Mux", lplay_enum);
+
+static const struct snd_kcontrol_new rplay_mux =
+ SOC_DAPM_ENUM("Right Playback Mux", rplay_enum);
+
static const struct snd_kcontrol_new left_output_mixer[] = {
SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
@@ -847,14 +844,26 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
-SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
-SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lcapture_mux),
+SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rcapture_mux),
+
+SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
-SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
-SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXL", "Left Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFRXR", "Right Playback", 0, SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Playback Mux", SND_SOC_NOPM, 0, 0, &lplay_mux),
+SND_SOC_DAPM_MUX("Right Playback Mux", SND_SOC_NOPM, 0, 0, &rplay_mux),
+
+SND_SOC_DAPM_DAC("DACL", NULL, WM8903_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_DAC("DACR", NULL, WM8903_POWER_MANAGEMENT_6, 2, 0),
SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0,
left_output_mixer, ARRAY_SIZE(left_output_mixer)),
@@ -866,23 +875,45 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0,
SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
- 1, 0, NULL, 0, wm8903_output_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
- 0, 0, NULL, 0, wm8903_output_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
-
-SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
- NULL, 0, wm8903_output_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
- NULL, 0, wm8903_output_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0,
+ 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0,
+ 0, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0,
+ NULL, 0),
+SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0,
+ NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPL_DCS", 3, SND_SOC_NOPM, 3, 0, wm8903_dcs_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("HPR_DCS", 3, SND_SOC_NOPM, 2, 0, wm8903_dcs_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("LINEOUTL_DCS", 3, SND_SOC_NOPM, 1, 0, wm8903_dcs_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_S("LINEOUTR_DCS", 3, SND_SOC_NOPM, 0, 0, wm8903_dcs_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
NULL, 0),
@@ -892,10 +923,18 @@ SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
};
static const struct snd_soc_dapm_route intercon[] = {
+ { "CLK_DSP", NULL, "CLK_SYS" },
+ { "Mic Bias", NULL, "CLK_SYS" },
+ { "HPL_DCS", NULL, "CLK_SYS" },
+ { "HPR_DCS", NULL, "CLK_SYS" },
+ { "LINEOUTL_DCS", NULL, "CLK_SYS" },
+ { "LINEOUTR_DCS", NULL, "CLK_SYS" },
+
{ "Left Input Mux", "IN1L", "IN1L" },
{ "Left Input Mux", "IN2L", "IN2L" },
{ "Left Input Mux", "IN3L", "IN3L" },
@@ -936,18 +975,36 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "Left Input PGA", NULL, "Left Input Mode Mux" },
{ "Right Input PGA", NULL, "Right Input Mode Mux" },
+ { "Left Capture Mux", "Left", "ADCL" },
+ { "Left Capture Mux", "Right", "ADCR" },
+
+ { "Right Capture Mux", "Left", "ADCL" },
+ { "Right Capture Mux", "Right", "ADCR" },
+
+ { "AIFTXL", NULL, "Left Capture Mux" },
+ { "AIFTXR", NULL, "Right Capture Mux" },
+
{ "ADCL", NULL, "Left Input PGA" },
{ "ADCL", NULL, "CLK_DSP" },
{ "ADCR", NULL, "Right Input PGA" },
{ "ADCR", NULL, "CLK_DSP" },
+ { "Left Playback Mux", "Left", "AIFRXL" },
+ { "Left Playback Mux", "Right", "AIFRXR" },
+
+ { "Right Playback Mux", "Left", "AIFRXL" },
+ { "Right Playback Mux", "Right", "AIFRXR" },
+
{ "DACL Sidetone", "Left", "ADCL" },
{ "DACL Sidetone", "Right", "ADCR" },
{ "DACR Sidetone", "Left", "ADCL" },
{ "DACR Sidetone", "Right", "ADCR" },
+ { "DACL", NULL, "Left Playback Mux" },
{ "DACL", NULL, "DACL Sidetone" },
{ "DACL", NULL, "CLK_DSP" },
+
+ { "DACR", NULL, "Right Playback Mux" },
{ "DACR", NULL, "DACR Sidetone" },
{ "DACR", NULL, "CLK_DSP" },
@@ -980,11 +1037,35 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "Left Speaker PGA", NULL, "Left Speaker Mixer" },
{ "Right Speaker PGA", NULL, "Right Speaker Mixer" },
- { "HPOUTL", NULL, "Left Headphone Output PGA" },
- { "HPOUTR", NULL, "Right Headphone Output PGA" },
+ { "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" },
+ { "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" },
+ { "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" },
+ { "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" },
+
+ { "HPL_DCS", NULL, "DCS Master" },
+ { "HPR_DCS", NULL, "DCS Master" },
+ { "LINEOUTL_DCS", NULL, "DCS Master" },
+ { "LINEOUTR_DCS", NULL, "DCS Master" },
+
+ { "HPL_DCS", NULL, "HPL_ENA_DLY" },
+ { "HPR_DCS", NULL, "HPR_ENA_DLY" },
+ { "LINEOUTL_DCS", NULL, "LINEOUTL_ENA_DLY" },
+ { "LINEOUTR_DCS", NULL, "LINEOUTR_ENA_DLY" },
- { "LINEOUTL", NULL, "Left Line Output PGA" },
- { "LINEOUTR", NULL, "Right Line Output PGA" },
+ { "HPL_ENA_OUTP", NULL, "HPL_DCS" },
+ { "HPR_ENA_OUTP", NULL, "HPR_DCS" },
+ { "LINEOUTL_ENA_OUTP", NULL, "LINEOUTL_DCS" },
+ { "LINEOUTR_ENA_OUTP", NULL, "LINEOUTR_DCS" },
+
+ { "HPL_RMV_SHORT", NULL, "HPL_ENA_OUTP" },
+ { "HPR_RMV_SHORT", NULL, "HPR_ENA_OUTP" },
+ { "LINEOUTL_RMV_SHORT", NULL, "LINEOUTL_ENA_OUTP" },
+ { "LINEOUTR_RMV_SHORT", NULL, "LINEOUTR_ENA_OUTP" },
+
+ { "HPOUTL", NULL, "HPL_RMV_SHORT" },
+ { "HPOUTR", NULL, "HPR_RMV_SHORT" },
+ { "LINEOUTL", NULL, "LINEOUTL_RMV_SHORT" },
+ { "LINEOUTR", NULL, "LINEOUTR_RMV_SHORT" },
{ "LOP", NULL, "Left Speaker PGA" },
{ "LON", NULL, "Left Speaker PGA" },
@@ -1012,29 +1093,71 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
static int wm8903_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg;
-
switch (level) {
case SND_SOC_BIAS_ON:
+ break;
+
case SND_SOC_BIAS_PREPARE:
- reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
- reg &= ~(WM8903_VMID_RES_MASK);
- reg |= WM8903_VMID_RES_50K;
- snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_RES_MASK,
+ WM8903_VMID_RES_50K);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- snd_soc_write(codec, WM8903_CLOCK_RATES_2,
- WM8903_CLK_SYS_ENA);
-
- /* Change DC servo dither level in startup sequence */
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
- snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
-
- wm8903_run_sequence(codec, 0);
- wm8903_sync_reg_cache(codec, codec->reg_cache);
+ snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+ WM8903_POBCTRL | WM8903_ISEL_MASK |
+ WM8903_STARTUP_BIAS_ENA |
+ WM8903_BIAS_ENA,
+ WM8903_POBCTRL |
+ (2 << WM8903_ISEL_SHIFT) |
+ WM8903_STARTUP_BIAS_ENA);
+
+ snd_soc_update_bits(codec,
+ WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
+ WM8903_SPK_DISCHARGE,
+ WM8903_SPK_DISCHARGE);
+
+ msleep(33);
+
+ snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5,
+ WM8903_SPKL_ENA | WM8903_SPKR_ENA,
+ WM8903_SPKL_ENA | WM8903_SPKR_ENA);
+
+ snd_soc_update_bits(codec,
+ WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0,
+ WM8903_SPK_DISCHARGE, 0);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_TIE_ENA |
+ WM8903_BUFIO_ENA |
+ WM8903_VMID_IO_ENA |
+ WM8903_VMID_SOFT_MASK |
+ WM8903_VMID_RES_MASK |
+ WM8903_VMID_BUF_ENA,
+ WM8903_VMID_TIE_ENA |
+ WM8903_BUFIO_ENA |
+ WM8903_VMID_IO_ENA |
+ (2 << WM8903_VMID_SOFT_SHIFT) |
+ WM8903_VMID_RES_250K |
+ WM8903_VMID_BUF_ENA);
+
+ msleep(129);
+
+ snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5,
+ WM8903_SPKL_ENA | WM8903_SPKR_ENA,
+ 0);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_SOFT_MASK, 0);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_RES_MASK,
+ WM8903_VMID_RES_50K);
+
+ snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+ WM8903_BIAS_ENA | WM8903_POBCTRL,
+ WM8903_BIAS_ENA);
/* By default no bypass paths are enabled so
* enable Class W support.
@@ -1047,17 +1170,32 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
WM8903_CP_DYN_V);
}
- reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
- reg &= ~(WM8903_VMID_RES_MASK);
- reg |= WM8903_VMID_RES_250K;
- snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg);
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_RES_MASK,
+ WM8903_VMID_RES_250K);
break;
case SND_SOC_BIAS_OFF:
- wm8903_run_sequence(codec, 32);
- reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2);
- reg &= ~WM8903_CLK_SYS_ENA;
- snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg);
+ snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+ WM8903_BIAS_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_SOFT_MASK,
+ 2 << WM8903_VMID_SOFT_SHIFT);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_BUF_ENA, 0);
+
+ msleep(290);
+
+ snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0,
+ WM8903_VMID_TIE_ENA | WM8903_BUFIO_ENA |
+ WM8903_VMID_IO_ENA | WM8903_VMID_RES_MASK |
+ WM8903_VMID_SOFT_MASK |
+ WM8903_VMID_BUF_ENA, 0);
+
+ snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0,
+ WM8903_STARTUP_BIAS_ENA, 0);
break;
}
@@ -1510,8 +1648,7 @@ static irqreturn_t wm8903_irq(int irq, void *data)
int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
if (int_val & WM8903_WSEQ_BUSY_EINT) {
- dev_dbg(codec->dev, "Write sequencer done\n");
- complete(&wm8903->wseq);
+ dev_warn(codec->dev, "Write sequencer done\n");
}
/*
@@ -1635,6 +1772,120 @@ static int wm8903_resume(struct snd_soc_codec *codec)
return 0;
}
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip)
+{
+ return container_of(chip, struct wm8903_priv, gpio_chip);
+}
+
+static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset >= WM8903_NUM_GPIO)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct snd_soc_codec *codec = wm8903->codec;
+ unsigned int mask, val;
+
+ mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK;
+ val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) |
+ WM8903_GP1_DIR;
+
+ return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
+ mask, val);
+}
+
+static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct snd_soc_codec *codec = wm8903->codec;
+ int reg;
+
+ reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset);
+
+ return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT;
+}
+
+static int wm8903_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct snd_soc_codec *codec = wm8903->codec;
+ unsigned int mask, val;
+
+ mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK;
+ val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) |
+ (value << WM8903_GP2_LVL_SHIFT);
+
+ return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
+ mask, val);
+}
+
+static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct snd_soc_codec *codec = wm8903->codec;
+
+ snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset,
+ WM8903_GP1_LVL_MASK,
+ !!value << WM8903_GP1_LVL_SHIFT);
+}
+
+static struct gpio_chip wm8903_template_chip = {
+ .label = "wm8903",
+ .owner = THIS_MODULE,
+ .request = wm8903_gpio_request,
+ .direction_input = wm8903_gpio_direction_in,
+ .get = wm8903_gpio_get,
+ .direction_output = wm8903_gpio_direction_out,
+ .set = wm8903_gpio_set,
+ .can_sleep = 1,
+};
+
+static void wm8903_init_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+ struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+ int ret;
+
+ wm8903->gpio_chip = wm8903_template_chip;
+ wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO;
+ wm8903->gpio_chip.dev = codec->dev;
+
+ if (pdata && pdata->gpio_base)
+ wm8903->gpio_chip.base = pdata->gpio_base;
+ else
+ wm8903->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&wm8903->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8903_free_gpio(struct snd_soc_codec *codec)
+{
+ struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = gpiochip_remove(&wm8903->gpio_chip);
+ if (ret != 0)
+ dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8903_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8903_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
static int wm8903_probe(struct snd_soc_codec *codec)
{
struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
@@ -1643,7 +1894,7 @@ static int wm8903_probe(struct snd_soc_codec *codec)
int trigger, irq_pol;
u16 val;
- init_completion(&wm8903->wseq);
+ wm8903->codec = codec;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret != 0) {
@@ -1659,19 +1910,33 @@ static int wm8903_probe(struct snd_soc_codec *codec)
}
val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
- dev_info(codec->dev, "WM8903 revision %d\n",
- val & WM8903_CHIP_REV_MASK);
+ dev_info(codec->dev, "WM8903 revision %c\n",
+ (val & WM8903_CHIP_REV_MASK) + 'A');
wm8903_reset(codec);
/* Set up GPIOs and microphone detection */
if (pdata) {
+ bool mic_gpio = false;
+
for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
- if (!pdata->gpio_cfg[i])
+ if (pdata->gpio_cfg[i] == WM8903_GPIO_NO_CONFIG)
continue;
snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
pdata->gpio_cfg[i] & 0xffff);
+
+ val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK)
+ >> WM8903_GP1_FN_SHIFT;
+
+ switch (val) {
+ case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT:
+ case WM8903_GPn_FN_MICBIAS_SHORT_DETECT:
+ mic_gpio = true;
+ break;
+ default:
+ break;
+ }
}
snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
@@ -1682,6 +1947,14 @@ static int wm8903_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
+ /* If microphone detection is enabled by pdata but
+ * detected via IRQ then interrupts can be lost before
+ * the machine driver has set up microphone detection
+ * IRQs as the IRQs are clear on read. The detection
+ * will be enabled when the machine driver configures.
+ */
+ WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA));
+
wm8903->mic_delay = pdata->micdet_delay;
}
@@ -1741,20 +2014,23 @@ static int wm8903_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val);
/* Enable DAC soft mute by default */
- val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
- val |= WM8903_DAC_MUTEMODE;
- snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
+ snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
+ WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE,
+ WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE);
snd_soc_add_controls(codec, wm8903_snd_controls,
ARRAY_SIZE(wm8903_snd_controls));
wm8903_add_widgets(codec);
+ wm8903_init_gpio(codec);
+
return ret;
}
/* power down chip */
static int wm8903_remove(struct snd_soc_codec *codec)
{
+ wm8903_free_gpio(codec);
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1769,6 +2045,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8903_reg_defaults,
.volatile_register = wm8903_volatile_register,
+ .seq_notifier = wm8903_seq_notifier,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -1807,7 +2084,7 @@ MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
static struct i2c_driver wm8903_i2c_driver = {
.driver = {
- .name = "wm8903-codec",
+ .name = "wm8903",
.owner = THIS_MODULE,
},
.probe = wm8903_i2c_probe,
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h
index e3ec2433b215..db949311c0f2 100644
--- a/sound/soc/codecs/wm8903.h
+++ b/sound/soc/codecs/wm8903.h
@@ -75,6 +75,14 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
#define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0 0x41
#define WM8903_DC_SERVO_0 0x43
#define WM8903_DC_SERVO_2 0x45
+#define WM8903_DC_SERVO_4 0x47
+#define WM8903_DC_SERVO_5 0x48
+#define WM8903_DC_SERVO_6 0x49
+#define WM8903_DC_SERVO_7 0x4A
+#define WM8903_DC_SERVO_READBACK_1 0x51
+#define WM8903_DC_SERVO_READBACK_2 0x52
+#define WM8903_DC_SERVO_READBACK_3 0x53
+#define WM8903_DC_SERVO_READBACK_4 0x54
#define WM8903_ANALOGUE_HP_0 0x5A
#define WM8903_ANALOGUE_LINEOUT_0 0x5E
#define WM8903_CHARGE_PUMP_0 0x62
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 9de44a4c05c0..443ae580445c 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -596,7 +596,7 @@ static struct {
{ 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */
};
-static int wm8904_volatile_register(unsigned int reg)
+static int wm8904_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
return wm8904_access[reg].vol;
}
@@ -2436,19 +2436,28 @@ static int wm8904_probe(struct snd_soc_codec *codec)
}
/* Change some default settings - latch VU and enable ZC */
- reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
- reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
- reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
- reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
- reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
- WM8904_HPOUTLZC;
- reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
- WM8904_HPOUTRZC;
- reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
- WM8904_LINEOUTLZC;
- reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
- WM8904_LINEOUTRZC;
- reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
+ snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT,
+ WM8904_ADC_VU, WM8904_ADC_VU);
+ snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT,
+ WM8904_ADC_VU, WM8904_ADC_VU);
+ snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT,
+ WM8904_DAC_VU, WM8904_DAC_VU);
+ snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT,
+ WM8904_DAC_VU, WM8904_DAC_VU);
+ snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT,
+ WM8904_HPOUT_VU | WM8904_HPOUTLZC,
+ WM8904_HPOUT_VU | WM8904_HPOUTLZC);
+ snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT,
+ WM8904_HPOUT_VU | WM8904_HPOUTRZC,
+ WM8904_HPOUT_VU | WM8904_HPOUTRZC);
+ snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT,
+ WM8904_LINEOUT_VU | WM8904_LINEOUTLZC,
+ WM8904_LINEOUT_VU | WM8904_LINEOUTLZC);
+ snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT,
+ WM8904_LINEOUT_VU | WM8904_LINEOUTRZC,
+ WM8904_LINEOUT_VU | WM8904_LINEOUTRZC);
+ snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0,
+ WM8904_SR_MODE, 0);
/* Apply configuration from the platform data. */
if (wm8904->pdata) {
@@ -2469,10 +2478,12 @@ static int wm8904_probe(struct snd_soc_codec *codec)
/* Set Class W by default - this will be managed by the Class
* G widget at runtime where bypass paths are available.
*/
- reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
+ snd_soc_update_bits(codec, WM8904_CLASS_W_0,
+ WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR);
/* Use normal bias source */
- reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
+ snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
+ WM8904_POBCTRL, 0);
wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 7167dfc96aa7..5e0214d6293e 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -934,16 +934,27 @@ static int wm8955_probe(struct snd_soc_codec *codec)
}
/* Change some default settings - latch VU and enable ZC */
- reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
- reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
- reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
- reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
- reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
- reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
- reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
+ snd_soc_update_bits(codec, WM8955_LEFT_DAC_VOLUME,
+ WM8955_LDVU, WM8955_LDVU);
+ snd_soc_update_bits(codec, WM8955_RIGHT_DAC_VOLUME,
+ WM8955_RDVU, WM8955_RDVU);
+ snd_soc_update_bits(codec, WM8955_LOUT1_VOLUME,
+ WM8955_LO1VU | WM8955_LO1ZC,
+ WM8955_LO1VU | WM8955_LO1ZC);
+ snd_soc_update_bits(codec, WM8955_ROUT1_VOLUME,
+ WM8955_RO1VU | WM8955_RO1ZC,
+ WM8955_RO1VU | WM8955_RO1ZC);
+ snd_soc_update_bits(codec, WM8955_LOUT2_VOLUME,
+ WM8955_LO2VU | WM8955_LO2ZC,
+ WM8955_LO2VU | WM8955_LO2ZC);
+ snd_soc_update_bits(codec, WM8955_ROUT2_VOLUME,
+ WM8955_RO2VU | WM8955_RO2ZC,
+ WM8955_RO2VU | WM8955_RO2ZC);
+ snd_soc_update_bits(codec, WM8955_MONOOUT_VOLUME,
+ WM8955_MOZC, WM8955_MOZC);
/* Also enable adaptive bass boost by default */
- reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
+ snd_soc_update_bits(codec, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB);
/* Set platform data values */
if (pdata) {
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 55252e7d02c9..cdee8103d09b 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -291,7 +291,7 @@ struct wm8961_priv {
int sysclk;
};
-static int wm8961_volatile_register(unsigned int reg)
+static int wm8961_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8961_SOFTWARE_RESET:
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index b9cb1fcf8c92..3b71dd65c966 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1938,7 +1938,7 @@ static const struct wm8962_reg_access {
[21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
};
-static int wm8962_volatile_register(unsigned int reg)
+static int wm8962_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
if (wm8962_reg_access[reg].vol)
return 1;
@@ -1946,7 +1946,7 @@ static int wm8962_volatile_register(unsigned int reg)
return 0;
}
-static int wm8962_readable_register(unsigned int reg)
+static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int reg)
{
if (wm8962_reg_access[reg].read)
return 1;
@@ -3635,7 +3635,7 @@ static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
struct snd_soc_codec *codec = wm8962->codec;
snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
- WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+ WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT);
}
static int wm8962_gpio_direction_out(struct gpio_chip *chip,
@@ -3822,16 +3822,26 @@ static int wm8962_probe(struct snd_soc_codec *codec)
}
/* Latch volume update bits */
- reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
- reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
- reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
- reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;
- reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
- reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
- reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
- reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
- reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
- reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+ snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
+ WM8962_IN_VU, WM8962_IN_VU);
+ snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME,
+ WM8962_IN_VU, WM8962_IN_VU);
+ snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME,
+ WM8962_ADC_VU, WM8962_ADC_VU);
+ snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME,
+ WM8962_ADC_VU, WM8962_ADC_VU);
+ snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME,
+ WM8962_DAC_VU, WM8962_DAC_VU);
+ snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME,
+ WM8962_DAC_VU, WM8962_DAC_VU);
+ snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME,
+ WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+ snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME,
+ WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+ snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME,
+ WM8962_HPOUT_VU, WM8962_HPOUT_VU);
+ snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME,
+ WM8962_HPOUT_VU, WM8962_HPOUT_VU);
wm8962_add_widgets(codec);
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 8dfb0a0da673..85e3e630e763 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -93,6 +93,7 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0);
static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1);
+static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0);
static const struct snd_kcontrol_new wm8978_snd_controls[] = {
@@ -144,8 +145,8 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = {
SOC_SINGLE("DAC Playback Limiter Threshold",
WM8978_DAC_LIMITER_2, 4, 7, 0),
- SOC_SINGLE("DAC Playback Limiter Boost",
- WM8978_DAC_LIMITER_2, 0, 12, 0),
+ SOC_SINGLE_TLV("DAC Playback Limiter Volume",
+ WM8978_DAC_LIMITER_2, 0, 12, 0, limiter_tlv),
SOC_ENUM("ALC Enable Switch", alc1),
SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0),
@@ -967,7 +968,7 @@ static int wm8978_probe(struct snd_soc_codec *codec)
* written.
*/
for (i = 0; i < ARRAY_SIZE(update_reg); i++)
- ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100;
+ snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100);
/* Reset the codec */
ret = snd_soc_write(codec, WM8978_RESET, 0);
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
new file mode 100644
index 000000000000..28fdfd66661d
--- /dev/null
+++ b/sound/soc/codecs/wm8991.c
@@ -0,0 +1,1427 @@
+/*
+ * wm8991.c -- WM8991 ALSA Soc Audio driver
+ *
+ * Copyright 2007-2010 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <asm/div64.h>
+
+#include "wm8991.h"
+
+struct wm8991_priv {
+ enum snd_soc_control_type control_type;
+ unsigned int pcmclk;
+};
+
+static const u16 wm8991_reg_defs[] = {
+ 0x8991, /* R0 - Reset */
+ 0x0000, /* R1 - Power Management (1) */
+ 0x6000, /* R2 - Power Management (2) */
+ 0x0000, /* R3 - Power Management (3) */
+ 0x4050, /* R4 - Audio Interface (1) */
+ 0x4000, /* R5 - Audio Interface (2) */
+ 0x01C8, /* R6 - Clocking (1) */
+ 0x0000, /* R7 - Clocking (2) */
+ 0x0040, /* R8 - Audio Interface (3) */
+ 0x0040, /* R9 - Audio Interface (4) */
+ 0x0004, /* R10 - DAC CTRL */
+ 0x00C0, /* R11 - Left DAC Digital Volume */
+ 0x00C0, /* R12 - Right DAC Digital Volume */
+ 0x0000, /* R13 - Digital Side Tone */
+ 0x0100, /* R14 - ADC CTRL */
+ 0x00C0, /* R15 - Left ADC Digital Volume */
+ 0x00C0, /* R16 - Right ADC Digital Volume */
+ 0x0000, /* R17 */
+ 0x0000, /* R18 - GPIO CTRL 1 */
+ 0x1000, /* R19 - GPIO1 & GPIO2 */
+ 0x1010, /* R20 - GPIO3 & GPIO4 */
+ 0x1010, /* R21 - GPIO5 & GPIO6 */
+ 0x8000, /* R22 - GPIOCTRL 2 */
+ 0x0800, /* R23 - GPIO_POL */
+ 0x008B, /* R24 - Left Line Input 1&2 Volume */
+ 0x008B, /* R25 - Left Line Input 3&4 Volume */
+ 0x008B, /* R26 - Right Line Input 1&2 Volume */
+ 0x008B, /* R27 - Right Line Input 3&4 Volume */
+ 0x0000, /* R28 - Left Output Volume */
+ 0x0000, /* R29 - Right Output Volume */
+ 0x0066, /* R30 - Line Outputs Volume */
+ 0x0022, /* R31 - Out3/4 Volume */
+ 0x0079, /* R32 - Left OPGA Volume */
+ 0x0079, /* R33 - Right OPGA Volume */
+ 0x0003, /* R34 - Speaker Volume */
+ 0x0003, /* R35 - ClassD1 */
+ 0x0000, /* R36 */
+ 0x0100, /* R37 - ClassD3 */
+ 0x0000, /* R38 */
+ 0x0000, /* R39 - Input Mixer1 */
+ 0x0000, /* R40 - Input Mixer2 */
+ 0x0000, /* R41 - Input Mixer3 */
+ 0x0000, /* R42 - Input Mixer4 */
+ 0x0000, /* R43 - Input Mixer5 */
+ 0x0000, /* R44 - Input Mixer6 */
+ 0x0000, /* R45 - Output Mixer1 */
+ 0x0000, /* R46 - Output Mixer2 */
+ 0x0000, /* R47 - Output Mixer3 */
+ 0x0000, /* R48 - Output Mixer4 */
+ 0x0000, /* R49 - Output Mixer5 */
+ 0x0000, /* R50 - Output Mixer6 */
+ 0x0180, /* R51 - Out3/4 Mixer */
+ 0x0000, /* R52 - Line Mixer1 */
+ 0x0000, /* R53 - Line Mixer2 */
+ 0x0000, /* R54 - Speaker Mixer */
+ 0x0000, /* R55 - Additional Control */
+ 0x0000, /* R56 - AntiPOP1 */
+ 0x0000, /* R57 - AntiPOP2 */
+ 0x0000, /* R58 - MICBIAS */
+ 0x0000, /* R59 */
+ 0x0008, /* R60 - PLL1 */
+ 0x0031, /* R61 - PLL2 */
+ 0x0026, /* R62 - PLL3 */
+};
+
+#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0)
+
+static const unsigned int rec_mix_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 7, TLV_DB_LINEAR_ITEM(-1500, 600),
+};
+
+static const unsigned int in_pga_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 0x1F, TLV_DB_LINEAR_ITEM(-1650, 3000),
+};
+
+static const unsigned int out_mix_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 7, TLV_DB_LINEAR_ITEM(0, -2100),
+};
+
+static const unsigned int out_pga_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 127, TLV_DB_LINEAR_ITEM(-7300, 600),
+};
+
+static const unsigned int out_omix_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 7, TLV_DB_LINEAR_ITEM(-600, 0),
+};
+
+static const unsigned int out_dac_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 255, TLV_DB_LINEAR_ITEM(-7163, 0),
+};
+
+static const unsigned int in_adc_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 255, TLV_DB_LINEAR_ITEM(-7163, 1763),
+};
+
+static const unsigned int out_sidetone_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 31, TLV_DB_LINEAR_ITEM(-3600, 0),
+};
+
+static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int ret;
+ u16 val;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ /* now hit the volume update bits (always bit 8) */
+ val = snd_soc_read(codec, reg);
+ return snd_soc_write(codec, reg, val | 0x0100);
+}
+
+static const char *wm8991_digital_sidetone[] =
+{"None", "Left ADC", "Right ADC", "Reserved"};
+
+static const struct soc_enum wm8991_left_digital_sidetone_enum =
+ SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADC_TO_DACL_SHIFT,
+ WM8991_ADC_TO_DACL_MASK,
+ wm8991_digital_sidetone);
+
+static const struct soc_enum wm8991_right_digital_sidetone_enum =
+ SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADC_TO_DACR_SHIFT,
+ WM8991_ADC_TO_DACR_MASK,
+ wm8991_digital_sidetone);
+
+static const char *wm8991_adcmode[] =
+{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static const struct soc_enum wm8991_right_adcmode_enum =
+ SOC_ENUM_SINGLE(WM8991_ADC_CTRL,
+ WM8991_ADC_HPF_CUT_SHIFT,
+ WM8991_ADC_HPF_CUT_MASK,
+ wm8991_adcmode);
+
+static const struct snd_kcontrol_new wm8991_snd_controls[] = {
+ /* INMIXL */
+ SOC_SINGLE("LIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L12MNBST_BIT, 1, 0),
+ SOC_SINGLE("LIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L34MNBST_BIT, 1, 0),
+ /* INMIXR */
+ SOC_SINGLE("RIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R12MNBST_BIT, 1, 0),
+ SOC_SINGLE("RIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R34MNBST_BIT, 1, 0),
+
+ /* LOMIX */
+ SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER3,
+ WM8991_LLI3LOVOL_SHIFT, WM8991_LLI3LOVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
+ WM8991_LR12LOVOL_SHIFT, WM8991_LR12LOVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
+ WM8991_LL12LOVOL_SHIFT, WM8991_LL12LOVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER5,
+ WM8991_LRI3LOVOL_SHIFT, WM8991_LRI3LOVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
+ WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
+ WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),
+
+ /* ROMIX */
+ SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER4,
+ WM8991_RRI3ROVOL_SHIFT, WM8991_RRI3ROVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
+ WM8991_RL12ROVOL_SHIFT, WM8991_RL12ROVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
+ WM8991_RR12ROVOL_SHIFT, WM8991_RR12ROVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER6,
+ WM8991_RLI3ROVOL_SHIFT, WM8991_RLI3ROVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
+ WM8991_RLBROVOL_SHIFT, WM8991_RLBROVOL_MASK, 1, out_mix_tlv),
+ SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
+ WM8991_RRBROVOL_SHIFT, WM8991_RRBROVOL_MASK, 1, out_mix_tlv),
+
+ /* LOUT */
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8991_LEFT_OUTPUT_VOLUME,
+ WM8991_LOUTVOL_SHIFT, WM8991_LOUTVOL_MASK, 0, out_pga_tlv),
+ SOC_SINGLE("LOUT ZC", WM8991_LEFT_OUTPUT_VOLUME, WM8991_LOZC_BIT, 1, 0),
+
+ /* ROUT */
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8991_RIGHT_OUTPUT_VOLUME,
+ WM8991_ROUTVOL_SHIFT, WM8991_ROUTVOL_MASK, 0, out_pga_tlv),
+ SOC_SINGLE("ROUT ZC", WM8991_RIGHT_OUTPUT_VOLUME, WM8991_ROZC_BIT, 1, 0),
+
+ /* LOPGA */
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8991_LEFT_OPGA_VOLUME,
+ WM8991_LOPGAVOL_SHIFT, WM8991_LOPGAVOL_MASK, 0, out_pga_tlv),
+ SOC_SINGLE("LOPGA ZC Switch", WM8991_LEFT_OPGA_VOLUME,
+ WM8991_LOPGAZC_BIT, 1, 0),
+
+ /* ROPGA */
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8991_RIGHT_OPGA_VOLUME,
+ WM8991_ROPGAVOL_SHIFT, WM8991_ROPGAVOL_MASK, 0, out_pga_tlv),
+ SOC_SINGLE("ROPGA ZC Switch", WM8991_RIGHT_OPGA_VOLUME,
+ WM8991_ROPGAZC_BIT, 1, 0),
+
+ SOC_SINGLE("LON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_LONMUTE_BIT, 1, 0),
+ SOC_SINGLE("LOP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_LOPMUTE_BIT, 1, 0),
+ SOC_SINGLE("LOP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_LOATTN_BIT, 1, 0),
+ SOC_SINGLE("RON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_RONMUTE_BIT, 1, 0),
+ SOC_SINGLE("ROP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_ROPMUTE_BIT, 1, 0),
+ SOC_SINGLE("ROP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
+ WM8991_ROATTN_BIT, 1, 0),
+
+ SOC_SINGLE("OUT3 Mute Switch", WM8991_OUT3_4_VOLUME,
+ WM8991_OUT3MUTE_BIT, 1, 0),
+ SOC_SINGLE("OUT3 Attenuation Switch", WM8991_OUT3_4_VOLUME,
+ WM8991_OUT3ATTN_BIT, 1, 0),
+
+ SOC_SINGLE("OUT4 Mute Switch", WM8991_OUT3_4_VOLUME,
+ WM8991_OUT4MUTE_BIT, 1, 0),
+ SOC_SINGLE("OUT4 Attenuation Switch", WM8991_OUT3_4_VOLUME,
+ WM8991_OUT4ATTN_BIT, 1, 0),
+
+ SOC_SINGLE("Speaker Mode Switch", WM8991_CLASSD1,
+ WM8991_CDMODE_BIT, 1, 0),
+
+ SOC_SINGLE("Speaker Output Attenuation Volume", WM8991_SPEAKER_VOLUME,
+ WM8991_SPKVOL_SHIFT, WM8991_SPKVOL_MASK, 0),
+ SOC_SINGLE("Speaker DC Boost Volume", WM8991_CLASSD3,
+ WM8991_DCGAIN_SHIFT, WM8991_DCGAIN_MASK, 0),
+ SOC_SINGLE("Speaker AC Boost Volume", WM8991_CLASSD3,
+ WM8991_ACGAIN_SHIFT, WM8991_ACGAIN_MASK, 0),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+ WM8991_LEFT_DAC_DIGITAL_VOLUME,
+ WM8991_DACL_VOL_SHIFT,
+ WM8991_DACL_VOL_MASK,
+ 0,
+ out_dac_tlv),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+ WM8991_RIGHT_DAC_DIGITAL_VOLUME,
+ WM8991_DACR_VOL_SHIFT,
+ WM8991_DACR_VOL_MASK,
+ 0,
+ out_dac_tlv),
+
+ SOC_ENUM("Left Digital Sidetone", wm8991_left_digital_sidetone_enum),
+ SOC_ENUM("Right Digital Sidetone", wm8991_right_digital_sidetone_enum),
+
+ SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADCL_DAC_SVOL_SHIFT, WM8991_ADCL_DAC_SVOL_MASK, 0,
+ out_sidetone_tlv),
+ SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
+ WM8991_ADCR_DAC_SVOL_SHIFT, WM8991_ADCR_DAC_SVOL_MASK, 0,
+ out_sidetone_tlv),
+
+ SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8991_ADC_CTRL,
+ WM8991_ADC_HPF_ENA_BIT, 1, 0),
+
+ SOC_ENUM("ADC HPF Mode", wm8991_right_adcmode_enum),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+ WM8991_LEFT_ADC_DIGITAL_VOLUME,
+ WM8991_ADCL_VOL_SHIFT,
+ WM8991_ADCL_VOL_MASK,
+ 0,
+ in_adc_tlv),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+ WM8991_RIGHT_ADC_DIGITAL_VOLUME,
+ WM8991_ADCR_VOL_SHIFT,
+ WM8991_ADCR_VOL_MASK,
+ 0,
+ in_adc_tlv),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+ WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8991_LIN12VOL_SHIFT,
+ WM8991_LIN12VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+ SOC_SINGLE("LIN12 ZC Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8991_LI12ZC_BIT, 1, 0),
+
+ SOC_SINGLE("LIN12 Mute Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8991_LI12MUTE_BIT, 1, 0),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+ WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8991_LIN34VOL_SHIFT,
+ WM8991_LIN34VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+ SOC_SINGLE("LIN34 ZC Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8991_LI34ZC_BIT, 1, 0),
+
+ SOC_SINGLE("LIN34 Mute Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8991_LI34MUTE_BIT, 1, 0),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+ WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8991_RIN12VOL_SHIFT,
+ WM8991_RIN12VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+ SOC_SINGLE("RIN12 ZC Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8991_RI12ZC_BIT, 1, 0),
+
+ SOC_SINGLE("RIN12 Mute Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8991_RI12MUTE_BIT, 1, 0),
+
+ SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+ WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8991_RIN34VOL_SHIFT,
+ WM8991_RIN34VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+ SOC_SINGLE("RIN34 ZC Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8991_RI34ZC_BIT, 1, 0),
+
+ SOC_SINGLE("RIN34 Mute Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8991_RI34MUTE_BIT, 1, 0),
+};
+
+/*
+ * _DAPM_ Controls
+ */
+static int inmixer_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ u16 reg, fakepower;
+
+ reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2);
+ fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS);
+
+ if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) |
+ (1 << WM8991_AINLMUX_PWR_BIT)))
+ reg |= WM8991_AINL_ENA;
+ else
+ reg &= ~WM8991_AINL_ENA;
+
+ if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) |
+ (1 << WM8991_AINRMUX_PWR_BIT)))
+ reg |= WM8991_AINR_ENA;
+ else
+ reg &= ~WM8991_AINL_ENA;
+
+ snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
+ return 0;
+}
+
+static int outmixer_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ u32 reg_shift = kcontrol->private_value & 0xfff;
+ int ret = 0;
+ u16 reg;
+
+ switch (reg_shift) {
+ case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
+ reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1);
+ if (reg & WM8991_LDLO) {
+ printk(KERN_WARNING
+ "Cannot set as Output Mixer 1 LDLO Set\n");
+ ret = -1;
+ }
+ break;
+
+ case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
+ reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2);
+ if (reg & WM8991_RDRO) {
+ printk(KERN_WARNING
+ "Cannot set as Output Mixer 2 RDRO Set\n");
+ ret = -1;
+ }
+ break;
+
+ case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
+ reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+ if (reg & WM8991_LDSPK) {
+ printk(KERN_WARNING
+ "Cannot set as Speaker Mixer LDSPK Set\n");
+ ret = -1;
+ }
+ break;
+
+ case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
+ reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+ if (reg & WM8991_RDSPK) {
+ printk(KERN_WARNING
+ "Cannot set as Speaker Mixer RDSPK Set\n");
+ ret = -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/* INMIX dB values */
+static const unsigned int in_mix_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
+};
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = {
+ SOC_DAPM_SINGLE("LIN1 Switch", WM8991_INPUT_MIXER2, WM8991_LMN1_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LIN2 Switch", WM8991_INPUT_MIXER2, WM8991_LMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8991_dapm_lin34_pga_controls[] = {
+ SOC_DAPM_SINGLE("LIN3 Switch", WM8991_INPUT_MIXER2, WM8991_LMN3_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LIN4 Switch", WM8991_INPUT_MIXER2, WM8991_LMP4_BIT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8991_dapm_rin12_pga_controls[] = {
+ SOC_DAPM_SINGLE("RIN1 Switch", WM8991_INPUT_MIXER2, WM8991_RMN1_BIT, 1, 0),
+ SOC_DAPM_SINGLE("RIN2 Switch", WM8991_INPUT_MIXER2, WM8991_RMP2_BIT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8991_dapm_rin34_pga_controls[] = {
+ SOC_DAPM_SINGLE("RIN3 Switch", WM8991_INPUT_MIXER2, WM8991_RMN3_BIT, 1, 0),
+ SOC_DAPM_SINGLE("RIN4 Switch", WM8991_INPUT_MIXER2, WM8991_RMP4_BIT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8991_dapm_inmixl_controls[] = {
+ SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8991_INPUT_MIXER3,
+ WM8991_LDBVOL_SHIFT, WM8991_LDBVOL_MASK, 0, in_mix_tlv),
+ SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8991_INPUT_MIXER5, WM8991_LI2BVOL_SHIFT,
+ 7, 0, in_mix_tlv),
+ SOC_DAPM_SINGLE("LINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
+ 1, 0),
+ SOC_DAPM_SINGLE("LINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
+ 1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
+ SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8991_INPUT_MIXER4,
+ WM8991_RDBVOL_SHIFT, WM8991_RDBVOL_MASK, 0, in_mix_tlv),
+ SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8991_INPUT_MIXER6, WM8991_RI2BVOL_SHIFT,
+ 7, 0, in_mix_tlv),
+ SOC_DAPM_SINGLE("RINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
+ 1, 0),
+ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
+ 1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8991_ainlmux[] =
+{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static const struct soc_enum wm8991_ainlmux_enum =
+ SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
+ ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux);
+
+static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
+ SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8991_ainrmux[] =
+{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static const struct soc_enum wm8991_ainrmux_enum =
+ SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
+ ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux);
+
+static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
+ SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = {
+ SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT,
+ WM8991_LR4BVOL_MASK, 0, in_mix_tlv),
+ SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT,
+ WM8991_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = {
+ SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LRBLO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LLBLO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LRI3LO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LLI3LO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LR12LO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LL12LO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8991_OUTPUT_MIXER1,
+ WM8991_LDLO_BIT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8991_dapm_romix_controls[] = {
+ SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RLBRO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RRBRO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RLI3RO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RRI3RO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RL12RO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RR12RO_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8991_OUTPUT_MIXER2,
+ WM8991_RDRO_BIT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lonmix_controls[] = {
+ SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
+ WM8991_LLOPGALON_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER1,
+ WM8991_LROPGALON_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8991_LINE_MIXER1,
+ WM8991_LOPLON_BIT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8991_dapm_lopmix_controls[] = {
+ SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER1,
+ WM8991_LR12LOP_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER1,
+ WM8991_LL12LOP_BIT, 1, 0),
+ SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
+ WM8991_LLOPGALOP_BIT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8991_dapm_ronmix_controls[] = {
+ SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
+ WM8991_RROPGARON_BIT, 1, 0),
+ SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER2,
+ WM8991_RLOPGARON_BIT, 1, 0),
+ SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8991_LINE_MIXER2,
+ WM8991_ROPRON_BIT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8991_dapm_ropmix_controls[] = {
+ SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER2,
+ WM8991_RL12ROP_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER2,
+ WM8991_RR12ROP_BIT, 1, 0),
+ SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
+ WM8991_RROPGAROP_BIT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8991_dapm_out3mix_controls[] = {
+ SOC_DAPM_SINGLE("OUT3MIX LIN4RXN Bypass Switch", WM8991_OUT3_4_MIXER,
+ WM8991_LI4O3_BIT, 1, 0),
+ SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8991_OUT3_4_MIXER,
+ WM8991_LPGAO3_BIT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8991_dapm_out4mix_controls[] = {
+ SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8991_OUT3_4_MIXER,
+ WM8991_RPGAO4_BIT, 1, 0),
+ SOC_DAPM_SINGLE("OUT4MIX RIN4RXP Bypass Switch", WM8991_OUT3_4_MIXER,
+ WM8991_RI4O4_BIT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8991_dapm_spkmix_controls[] = {
+ SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
+ WM8991_LI2SPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8991_SPEAKER_MIXER,
+ WM8991_LB2SPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8991_SPEAKER_MIXER,
+ WM8991_LOPGASPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8991_SPEAKER_MIXER,
+ WM8991_LDSPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8991_SPEAKER_MIXER,
+ WM8991_RDSPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8991_SPEAKER_MIXER,
+ WM8991_ROPGASPK_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8991_SPEAKER_MIXER,
+ WM8991_RL12ROP_BIT, 1, 0),
+ SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
+ WM8991_RI2SPK_BIT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
+ /* Input Side */
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("LIN1"),
+ SND_SOC_DAPM_INPUT("LIN2"),
+ SND_SOC_DAPM_INPUT("LIN3"),
+ SND_SOC_DAPM_INPUT("LIN4RXN"),
+ SND_SOC_DAPM_INPUT("RIN3"),
+ SND_SOC_DAPM_INPUT("RIN4RXP"),
+ SND_SOC_DAPM_INPUT("RIN1"),
+ SND_SOC_DAPM_INPUT("RIN2"),
+ SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+ /* DACs */
+ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
+ WM8991_ADCL_ENA_BIT, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8991_POWER_MANAGEMENT_2,
+ WM8991_ADCR_ENA_BIT, 0),
+
+ /* Input PGAs */
+ SND_SOC_DAPM_MIXER("LIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN12_ENA_BIT,
+ 0, &wm8991_dapm_lin12_pga_controls[0],
+ ARRAY_SIZE(wm8991_dapm_lin12_pga_controls)),
+ SND_SOC_DAPM_MIXER("LIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN34_ENA_BIT,
+ 0, &wm8991_dapm_lin34_pga_controls[0],
+ ARRAY_SIZE(wm8991_dapm_lin34_pga_controls)),
+ SND_SOC_DAPM_MIXER("RIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN12_ENA_BIT,
+ 0, &wm8991_dapm_rin12_pga_controls[0],
+ ARRAY_SIZE(wm8991_dapm_rin12_pga_controls)),
+ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN34_ENA_BIT,
+ 0, &wm8991_dapm_rin34_pga_controls[0],
+ ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),
+
+ /* INMIXL */
+ SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0,
+ &wm8991_dapm_inmixl_controls[0],
+ ARRAY_SIZE(wm8991_dapm_inmixl_controls),
+ inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* AINLMUX */
+ SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0,
+ &wm8991_dapm_ainlmux_controls, inmixer_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* INMIXR */
+ SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0,
+ &wm8991_dapm_inmixr_controls[0],
+ ARRAY_SIZE(wm8991_dapm_inmixr_controls),
+ inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* AINRMUX */
+ SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0,
+ &wm8991_dapm_ainrmux_controls, inmixer_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Output Side */
+ /* DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8991_POWER_MANAGEMENT_3,
+ WM8991_DACL_ENA_BIT, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8991_POWER_MANAGEMENT_3,
+ WM8991_DACR_ENA_BIT, 0),
+
+ /* LOMIX */
+ SND_SOC_DAPM_MIXER_E("LOMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOMIX_ENA_BIT,
+ 0, &wm8991_dapm_lomix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_lomix_controls),
+ outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+ /* LONMIX */
+ SND_SOC_DAPM_MIXER("LONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LON_ENA_BIT, 0,
+ &wm8991_dapm_lonmix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_lonmix_controls)),
+
+ /* LOPMIX */
+ SND_SOC_DAPM_MIXER("LOPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOP_ENA_BIT, 0,
+ &wm8991_dapm_lopmix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_lopmix_controls)),
+
+ /* OUT3MIX */
+ SND_SOC_DAPM_MIXER("OUT3MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT3_ENA_BIT, 0,
+ &wm8991_dapm_out3mix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_out3mix_controls)),
+
+ /* SPKMIX */
+ SND_SOC_DAPM_MIXER_E("SPKMIX", WM8991_POWER_MANAGEMENT_1, WM8991_SPK_ENA_BIT, 0,
+ &wm8991_dapm_spkmix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_spkmix_controls), outmixer_event,
+ SND_SOC_DAPM_PRE_REG),
+
+ /* OUT4MIX */
+ SND_SOC_DAPM_MIXER("OUT4MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT4_ENA_BIT, 0,
+ &wm8991_dapm_out4mix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_out4mix_controls)),
+
+ /* ROPMIX */
+ SND_SOC_DAPM_MIXER("ROPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROP_ENA_BIT, 0,
+ &wm8991_dapm_ropmix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_ropmix_controls)),
+
+ /* RONMIX */
+ SND_SOC_DAPM_MIXER("RONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_RON_ENA_BIT, 0,
+ &wm8991_dapm_ronmix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_ronmix_controls)),
+
+ /* ROMIX */
+ SND_SOC_DAPM_MIXER_E("ROMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROMIX_ENA_BIT,
+ 0, &wm8991_dapm_romix_controls[0],
+ ARRAY_SIZE(wm8991_dapm_romix_controls),
+ outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+ /* LOUT PGA */
+ SND_SOC_DAPM_PGA("LOUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_LOUT_ENA_BIT, 0,
+ NULL, 0),
+
+ /* ROUT PGA */
+ SND_SOC_DAPM_PGA("ROUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_ROUT_ENA_BIT, 0,
+ NULL, 0),
+
+ /* LOPGA */
+ SND_SOC_DAPM_PGA("LOPGA", WM8991_POWER_MANAGEMENT_3, WM8991_LOPGA_ENA_BIT, 0,
+ NULL, 0),
+
+ /* ROPGA */
+ SND_SOC_DAPM_PGA("ROPGA", WM8991_POWER_MANAGEMENT_3, WM8991_ROPGA_ENA_BIT, 0,
+ NULL, 0),
+
+ /* MICBIAS */
+ SND_SOC_DAPM_MICBIAS("MICBIAS", WM8991_POWER_MANAGEMENT_1,
+ WM8991_MICBIAS_ENA_BIT, 0),
+
+ SND_SOC_DAPM_OUTPUT("LON"),
+ SND_SOC_DAPM_OUTPUT("LOP"),
+ SND_SOC_DAPM_OUTPUT("OUT3"),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("SPKN"),
+ SND_SOC_DAPM_OUTPUT("SPKP"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+ SND_SOC_DAPM_OUTPUT("OUT4"),
+ SND_SOC_DAPM_OUTPUT("ROP"),
+ SND_SOC_DAPM_OUTPUT("RON"),
+ SND_SOC_DAPM_OUTPUT("OUT"),
+
+ SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Make DACs turn on when playing even if not mixed into any outputs */
+ {"Internal DAC Sink", NULL, "Left DAC"},
+ {"Internal DAC Sink", NULL, "Right DAC"},
+
+ /* Make ADCs turn on when recording even if not mixed from any inputs */
+ {"Left ADC", NULL, "Internal ADC Source"},
+ {"Right ADC", NULL, "Internal ADC Source"},
+
+ /* Input Side */
+ /* LIN12 PGA */
+ {"LIN12 PGA", "LIN1 Switch", "LIN1"},
+ {"LIN12 PGA", "LIN2 Switch", "LIN2"},
+ /* LIN34 PGA */
+ {"LIN34 PGA", "LIN3 Switch", "LIN3"},
+ {"LIN34 PGA", "LIN4 Switch", "LIN4RXN"},
+ /* INMIXL */
+ {"INMIXL", "Record Left Volume", "LOMIX"},
+ {"INMIXL", "LIN2 Volume", "LIN2"},
+ {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+ {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+ /* AINLMUX */
+ {"AINLMUX", "INMIXL Mix", "INMIXL"},
+ {"AINLMUX", "DIFFINL Mix", "LIN12 PGA"},
+ {"AINLMUX", "DIFFINL Mix", "LIN34 PGA"},
+ {"AINLMUX", "RXVOICE Mix", "LIN4RXN"},
+ {"AINLMUX", "RXVOICE Mix", "RIN4RXP"},
+ /* ADC */
+ {"Left ADC", NULL, "AINLMUX"},
+
+ /* RIN12 PGA */
+ {"RIN12 PGA", "RIN1 Switch", "RIN1"},
+ {"RIN12 PGA", "RIN2 Switch", "RIN2"},
+ /* RIN34 PGA */
+ {"RIN34 PGA", "RIN3 Switch", "RIN3"},
+ {"RIN34 PGA", "RIN4 Switch", "RIN4RXP"},
+ /* INMIXL */
+ {"INMIXR", "Record Right Volume", "ROMIX"},
+ {"INMIXR", "RIN2 Volume", "RIN2"},
+ {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+ {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+ /* AINRMUX */
+ {"AINRMUX", "INMIXR Mix", "INMIXR"},
+ {"AINRMUX", "DIFFINR Mix", "RIN12 PGA"},
+ {"AINRMUX", "DIFFINR Mix", "RIN34 PGA"},
+ {"AINRMUX", "RXVOICE Mix", "LIN4RXN"},
+ {"AINRMUX", "RXVOICE Mix", "RIN4RXP"},
+ /* ADC */
+ {"Right ADC", NULL, "AINRMUX"},
+
+ /* LOMIX */
+ {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+ {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+ {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+ {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+ {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"},
+ {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"},
+ {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+ /* ROMIX */
+ {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+ {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+ {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+ {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+ {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"},
+ {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"},
+ {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+ /* SPKMIX */
+ {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+ {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+ {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"},
+ {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"},
+ {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+ {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+ {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+ {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+ /* LONMIX */
+ {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+ {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+ {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+ /* LOPMIX */
+ {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+ {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+ {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+ /* OUT3MIX */
+ {"OUT3MIX", "OUT3MIX LIN4RXN Bypass Switch", "LIN4RXN"},
+ {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+ /* OUT4MIX */
+ {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+ {"OUT4MIX", "OUT4MIX RIN4RXP Bypass Switch", "RIN4RXP"},
+
+ /* RONMIX */
+ {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+ {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+ {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+ /* ROPMIX */
+ {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+ {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+ {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+ /* Out Mixer PGAs */
+ {"LOPGA", NULL, "LOMIX"},
+ {"ROPGA", NULL, "ROMIX"},
+
+ {"LOUT PGA", NULL, "LOMIX"},
+ {"ROUT PGA", NULL, "ROMIX"},
+
+ /* Output Pins */
+ {"LON", NULL, "LONMIX"},
+ {"LOP", NULL, "LOPMIX"},
+ {"OUT", NULL, "OUT3MIX"},
+ {"LOUT", NULL, "LOUT PGA"},
+ {"SPKN", NULL, "SPKMIX"},
+ {"ROUT", NULL, "ROUT PGA"},
+ {"OUT4", NULL, "OUT4MIX"},
+ {"ROP", NULL, "ROPMIX"},
+ {"RON", NULL, "RONMIX"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+ u32 div2;
+ u32 n;
+ u32 k;
+};
+
+/* The size in bits of the pll divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_PLL_SIZE ((1 << 16) * 10)
+
+static void pll_factors(struct _pll_div *pll_div, unsigned int target,
+ unsigned int source)
+{
+ u64 Kpart;
+ unsigned int K, Ndiv, Nmod;
+
+
+ Ndiv = target / source;
+ if (Ndiv < 6) {
+ source >>= 1;
+ pll_div->div2 = 1;
+ Ndiv = target / source;
+ } else
+ pll_div->div2 = 0;
+
+ if ((Ndiv < 6) || (Ndiv > 12))
+ printk(KERN_WARNING
+ "WM8991 N value outwith recommended range! N = %d\n", Ndiv);
+
+ pll_div->n = Ndiv;
+ Nmod = target % source;
+ Kpart = FIXED_PLL_SIZE * (long long)Nmod;
+
+ do_div(Kpart, source);
+
+ K = Kpart & 0xFFFFFFFF;
+
+ /* Check if we need to round */
+ if ((K % 10) >= 5)
+ K += 5;
+
+ /* Move down to proper range now rounding is done */
+ K /= 10;
+
+ pll_div->k = K;
+}
+
+static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai,
+ int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
+{
+ u16 reg;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct _pll_div pll_div;
+
+ if (freq_in && freq_out) {
+ pll_factors(&pll_div, freq_out * 4, freq_in);
+
+ /* Turn on PLL */
+ reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
+ reg |= WM8991_PLL_ENA;
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);
+
+ /* sysclk comes from PLL */
+ reg = snd_soc_read(codec, WM8991_CLOCKING_2);
+ snd_soc_write(codec, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC);
+
+ /* set up N , fractional mode and pre-divisor if neccessary */
+ snd_soc_write(codec, WM8991_PLL1, pll_div.n | WM8991_SDM |
+ (pll_div.div2 ? WM8991_PRESCALE : 0));
+ snd_soc_write(codec, WM8991_PLL2, (u8)(pll_div.k>>8));
+ snd_soc_write(codec, WM8991_PLL3, (u8)(pll_div.k & 0xFF));
+ } else {
+ /* Turn on PLL */
+ reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
+ reg &= ~WM8991_PLL_ENA;
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);
+ }
+ return 0;
+}
+
+/*
+ * Set's ADC and Voice DAC format.
+ */
+static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 audio1, audio3;
+
+ audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);
+ audio3 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_3);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ audio3 &= ~WM8991_AIF_MSTR1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ audio3 |= WM8991_AIF_MSTR1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ audio1 &= ~WM8991_AIF_FMT_MASK;
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ audio1 |= WM8991_AIF_TMF_I2S;
+ audio1 &= ~WM8991_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ audio1 |= WM8991_AIF_TMF_RIGHTJ;
+ audio1 &= ~WM8991_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ audio1 |= WM8991_AIF_TMF_LEFTJ;
+ audio1 &= ~WM8991_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ audio1 |= WM8991_AIF_TMF_DSP;
+ audio1 &= ~WM8991_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ audio1 |= WM8991_AIF_TMF_DSP | WM8991_AIF_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
+ snd_soc_write(codec, WM8991_AUDIO_INTERFACE_3, audio3);
+ return 0;
+}
+
+static int wm8991_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+ int div_id, int div)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 reg;
+
+ switch (div_id) {
+ case WM8991_MCLK_DIV:
+ reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+ ~WM8991_MCLK_DIV_MASK;
+ snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+ break;
+ case WM8991_DACCLK_DIV:
+ reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+ ~WM8991_DAC_CLKDIV_MASK;
+ snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+ break;
+ case WM8991_ADCCLK_DIV:
+ reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
+ ~WM8991_ADC_CLKDIV_MASK;
+ snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
+ break;
+ case WM8991_BCLK_DIV:
+ reg = snd_soc_read(codec, WM8991_CLOCKING_1) &
+ ~WM8991_BCLK_DIV_MASK;
+ snd_soc_write(codec, WM8991_CLOCKING_1, reg | div);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8991_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);
+
+ audio1 &= ~WM8991_AIF_WL_MASK;
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ audio1 |= WM8991_AIF_WL_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ audio1 |= WM8991_AIF_WL_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ audio1 |= WM8991_AIF_WL_32BITS;
+ break;
+ }
+
+ snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
+ return 0;
+}
+
+static int wm8991_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 val;
+
+ val = snd_soc_read(codec, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE;
+ if (mute)
+ snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+ else
+ snd_soc_write(codec, WM8991_DAC_CTRL, val);
+ return 0;
+}
+
+static int wm8991_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ u16 val;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID=2*50k */
+ val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
+ ~WM8991_VMID_MODE_MASK;
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x2);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_cache_sync(codec);
+ /* Enable all output discharge bits */
+ snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+ WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
+ WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
+ WM8991_DIS_ROUT);
+
+ /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+ WM8991_BUFDCOPEN | WM8991_POBCTRL |
+ WM8991_VMIDTOG);
+
+ /* Delay to allow output caps to discharge */
+ msleep(300);
+
+ /* Disable VMIDTOG */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+ WM8991_BUFDCOPEN | WM8991_POBCTRL);
+
+ /* disable all output discharge bits */
+ snd_soc_write(codec, WM8991_ANTIPOP1, 0);
+
+ /* Enable outputs */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1b00);
+
+ msleep(50);
+
+ /* Enable VMID at 2x50k */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f02);
+
+ msleep(100);
+
+ /* Enable VREF */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+
+ msleep(600);
+
+ /* Enable BUFIOEN */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+ WM8991_BUFDCOPEN | WM8991_POBCTRL |
+ WM8991_BUFIOEN);
+
+ /* Disable outputs */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x3);
+
+ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_BUFIOEN);
+ }
+
+ /* VMID=2*250k */
+ val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
+ ~WM8991_VMID_MODE_MASK;
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x4);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ /* Enable POBCTRL and SOFT_ST */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+ WM8991_POBCTRL | WM8991_BUFIOEN);
+
+ /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+ snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
+ WM8991_BUFDCOPEN | WM8991_POBCTRL |
+ WM8991_BUFIOEN);
+
+ /* mute DAC */
+ val = snd_soc_read(codec, WM8991_DAC_CTRL);
+ snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
+
+ /* Enable any disabled outputs */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);
+
+ /* Disable VMID */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f01);
+
+ msleep(300);
+
+ /* Enable all output discharge bits */
+ snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
+ WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
+ WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
+ WM8991_DIS_ROUT);
+
+ /* Disable VREF */
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x0);
+
+ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+ snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
+ codec->cache_sync = 1;
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static int wm8991_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+ wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8991_resume(struct snd_soc_codec *codec)
+{
+ wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+
+/* power down chip */
+static int wm8991_remove(struct snd_soc_codec *codec)
+{
+ wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int wm8991_probe(struct snd_soc_codec *codec)
+{
+ struct wm8991_priv *wm8991;
+ int ret;
+ unsigned int reg;
+
+ wm8991 = snd_soc_codec_get_drvdata(codec);
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+ return ret;
+ }
+
+ ret = wm8991_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
+ }
+
+ wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ reg = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_4);
+ snd_soc_write(codec, WM8991_AUDIO_INTERFACE_4, reg | WM8991_ALRCGPIO1);
+
+ reg = snd_soc_read(codec, WM8991_GPIO1_GPIO2) &
+ ~WM8991_GPIO1_SEL_MASK;
+ snd_soc_write(codec, WM8991_GPIO1_GPIO2, reg | 1);
+
+ reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1);
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, reg | WM8991_VREF_ENA|
+ WM8991_VMID_MODE_MASK);
+
+ reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
+ snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg | WM8991_OPCLK_ENA);
+
+ snd_soc_write(codec, WM8991_DAC_CTRL, 0);
+ snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+ snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+ snd_soc_add_controls(codec, wm8991_snd_controls,
+ ARRAY_SIZE(wm8991_snd_controls));
+
+ snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
+ ARRAY_SIZE(wm8991_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm, audio_map,
+ ARRAY_SIZE(audio_map));
+ return 0;
+}
+
+#define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8991_ops = {
+ .hw_params = wm8991_hw_params,
+ .digital_mute = wm8991_mute,
+ .set_fmt = wm8991_set_dai_fmt,
+ .set_clkdiv = wm8991_set_dai_clkdiv,
+ .set_pll = wm8991_set_dai_pll
+};
+
+/*
+ * The WM8991 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+static struct snd_soc_dai_driver wm8991_dai = {
+ /* ADC/DAC on primary */
+ .name = "wm8991",
+ .id = 1,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = WM8991_FORMATS
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = WM8991_FORMATS
+ },
+ .ops = &wm8991_ops
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
+ .probe = wm8991_probe,
+ .remove = wm8991_remove,
+ .suspend = wm8991_suspend,
+ .resume = wm8991_resume,
+ .set_bias_level = wm8991_set_bias_level,
+ .reg_cache_size = WM8991_MAX_REGISTER + 1,
+ .reg_word_size = sizeof(u16),
+ .reg_cache_default = wm8991_reg_defs
+};
+
+static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8991_priv *wm8991;
+ int ret;
+
+ wm8991 = kzalloc(sizeof *wm8991, GFP_KERNEL);
+ if (!wm8991)
+ return -ENOMEM;
+
+ wm8991->control_type = SND_SOC_I2C;
+ i2c_set_clientdata(i2c, wm8991);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_wm8991, &wm8991_dai, 1);
+ if (ret < 0)
+ kfree(wm8991);
+ return ret;
+}
+
+static __devexit int wm8991_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id wm8991_i2c_id[] = {
+ { "wm8991", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id);
+
+static struct i2c_driver wm8991_i2c_driver = {
+ .driver = {
+ .name = "wm8991",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8991_i2c_probe,
+ .remove = __devexit_p(wm8991_i2c_remove),
+ .id_table = wm8991_i2c_id,
+};
+
+static int __init wm8991_modinit(void)
+{
+ int ret;
+ ret = i2c_add_driver(&wm8991_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n",
+ ret);
+ }
+ return 0;
+}
+module_init(wm8991_modinit);
+
+static void __exit wm8991_exit(void)
+{
+ i2c_del_driver(&wm8991_i2c_driver);
+}
+module_exit(wm8991_exit);
+
+MODULE_DESCRIPTION("ASoC WM8991 driver");
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h
new file mode 100644
index 000000000000..8a942efd18a5
--- /dev/null
+++ b/sound/soc/codecs/wm8991.h
@@ -0,0 +1,833 @@
+/*
+ * wm8991.h -- audio driver for WM8991
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _WM8991_H
+#define _WM8991_H
+
+/*
+ * Register values.
+ */
+#define WM8991_RESET 0x00
+#define WM8991_POWER_MANAGEMENT_1 0x01
+#define WM8991_POWER_MANAGEMENT_2 0x02
+#define WM8991_POWER_MANAGEMENT_3 0x03
+#define WM8991_AUDIO_INTERFACE_1 0x04
+#define WM8991_AUDIO_INTERFACE_2 0x05
+#define WM8991_CLOCKING_1 0x06
+#define WM8991_CLOCKING_2 0x07
+#define WM8991_AUDIO_INTERFACE_3 0x08
+#define WM8991_AUDIO_INTERFACE_4 0x09
+#define WM8991_DAC_CTRL 0x0A
+#define WM8991_LEFT_DAC_DIGITAL_VOLUME 0x0B
+#define WM8991_RIGHT_DAC_DIGITAL_VOLUME 0x0C
+#define WM8991_DIGITAL_SIDE_TONE 0x0D
+#define WM8991_ADC_CTRL 0x0E
+#define WM8991_LEFT_ADC_DIGITAL_VOLUME 0x0F
+#define WM8991_RIGHT_ADC_DIGITAL_VOLUME 0x10
+#define WM8991_GPIO_CTRL_1 0x12
+#define WM8991_GPIO1_GPIO2 0x13
+#define WM8991_GPIO3_GPIO4 0x14
+#define WM8991_GPIO5_GPIO6 0x15
+#define WM8991_GPIOCTRL_2 0x16
+#define WM8991_GPIO_POL 0x17
+#define WM8991_LEFT_LINE_INPUT_1_2_VOLUME 0x18
+#define WM8991_LEFT_LINE_INPUT_3_4_VOLUME 0x19
+#define WM8991_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
+#define WM8991_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
+#define WM8991_LEFT_OUTPUT_VOLUME 0x1C
+#define WM8991_RIGHT_OUTPUT_VOLUME 0x1D
+#define WM8991_LINE_OUTPUTS_VOLUME 0x1E
+#define WM8991_OUT3_4_VOLUME 0x1F
+#define WM8991_LEFT_OPGA_VOLUME 0x20
+#define WM8991_RIGHT_OPGA_VOLUME 0x21
+#define WM8991_SPEAKER_VOLUME 0x22
+#define WM8991_CLASSD1 0x23
+#define WM8991_CLASSD3 0x25
+#define WM8991_INPUT_MIXER1 0x27
+#define WM8991_INPUT_MIXER2 0x28
+#define WM8991_INPUT_MIXER3 0x29
+#define WM8991_INPUT_MIXER4 0x2A
+#define WM8991_INPUT_MIXER5 0x2B
+#define WM8991_INPUT_MIXER6 0x2C
+#define WM8991_OUTPUT_MIXER1 0x2D
+#define WM8991_OUTPUT_MIXER2 0x2E
+#define WM8991_OUTPUT_MIXER3 0x2F
+#define WM8991_OUTPUT_MIXER4 0x30
+#define WM8991_OUTPUT_MIXER5 0x31
+#define WM8991_OUTPUT_MIXER6 0x32
+#define WM8991_OUT3_4_MIXER 0x33
+#define WM8991_LINE_MIXER1 0x34
+#define WM8991_LINE_MIXER2 0x35
+#define WM8991_SPEAKER_MIXER 0x36
+#define WM8991_ADDITIONAL_CONTROL 0x37
+#define WM8991_ANTIPOP1 0x38
+#define WM8991_ANTIPOP2 0x39
+#define WM8991_MICBIAS 0x3A
+#define WM8991_PLL1 0x3C
+#define WM8991_PLL2 0x3D
+#define WM8991_PLL3 0x3E
+#define WM8991_INTDRIVBITS 0x3F
+
+#define WM8991_REGISTER_COUNT 60
+#define WM8991_MAX_REGISTER 0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset
+ */
+#define WM8991_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8991_SPK_ENA 0x1000 /* SPK_ENA */
+#define WM8991_SPK_ENA_BIT 12
+#define WM8991_OUT3_ENA 0x0800 /* OUT3_ENA */
+#define WM8991_OUT3_ENA_BIT 11
+#define WM8991_OUT4_ENA 0x0400 /* OUT4_ENA */
+#define WM8991_OUT4_ENA_BIT 10
+#define WM8991_LOUT_ENA 0x0200 /* LOUT_ENA */
+#define WM8991_LOUT_ENA_BIT 9
+#define WM8991_ROUT_ENA 0x0100 /* ROUT_ENA */
+#define WM8991_ROUT_ENA_BIT 8
+#define WM8991_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */
+#define WM8991_MICBIAS_ENA_BIT 4
+#define WM8991_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */
+#define WM8991_VREF_ENA 0x0001 /* VREF_ENA */
+#define WM8991_VREF_ENA_BIT 0
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8991_PLL_ENA 0x8000 /* PLL_ENA */
+#define WM8991_PLL_ENA_BIT 15
+#define WM8991_TSHUT_ENA 0x4000 /* TSHUT_ENA */
+#define WM8991_TSHUT_ENA_BIT 14
+#define WM8991_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
+#define WM8991_TSHUT_OPDIS_BIT 13
+#define WM8991_OPCLK_ENA 0x0800 /* OPCLK_ENA */
+#define WM8991_OPCLK_ENA_BIT 11
+#define WM8991_AINL_ENA 0x0200 /* AINL_ENA */
+#define WM8991_AINL_ENA_BIT 9
+#define WM8991_AINR_ENA 0x0100 /* AINR_ENA */
+#define WM8991_AINR_ENA_BIT 8
+#define WM8991_LIN34_ENA 0x0080 /* LIN34_ENA */
+#define WM8991_LIN34_ENA_BIT 7
+#define WM8991_LIN12_ENA 0x0040 /* LIN12_ENA */
+#define WM8991_LIN12_ENA_BIT 6
+#define WM8991_RIN34_ENA 0x0020 /* RIN34_ENA */
+#define WM8991_RIN34_ENA_BIT 5
+#define WM8991_RIN12_ENA 0x0010 /* RIN12_ENA */
+#define WM8991_RIN12_ENA_BIT 4
+#define WM8991_ADCL_ENA 0x0002 /* ADCL_ENA */
+#define WM8991_ADCL_ENA_BIT 1
+#define WM8991_ADCR_ENA 0x0001 /* ADCR_ENA */
+#define WM8991_ADCR_ENA_BIT 0
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8991_LON_ENA 0x2000 /* LON_ENA */
+#define WM8991_LON_ENA_BIT 13
+#define WM8991_LOP_ENA 0x1000 /* LOP_ENA */
+#define WM8991_LOP_ENA_BIT 12
+#define WM8991_RON_ENA 0x0800 /* RON_ENA */
+#define WM8991_RON_ENA_BIT 11
+#define WM8991_ROP_ENA 0x0400 /* ROP_ENA */
+#define WM8991_ROP_ENA_BIT 10
+#define WM8991_LOPGA_ENA 0x0080 /* LOPGA_ENA */
+#define WM8991_LOPGA_ENA_BIT 7
+#define WM8991_ROPGA_ENA 0x0040 /* ROPGA_ENA */
+#define WM8991_ROPGA_ENA_BIT 6
+#define WM8991_LOMIX_ENA 0x0020 /* LOMIX_ENA */
+#define WM8991_LOMIX_ENA_BIT 5
+#define WM8991_ROMIX_ENA 0x0010 /* ROMIX_ENA */
+#define WM8991_ROMIX_ENA_BIT 4
+#define WM8991_DACL_ENA 0x0002 /* DACL_ENA */
+#define WM8991_DACL_ENA_BIT 1
+#define WM8991_DACR_ENA 0x0001 /* DACR_ENA */
+#define WM8991_DACR_ENA_BIT 0
+
+/*
+ * R4 (0x04) - Audio Interface (1)
+ */
+#define WM8991_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */
+#define WM8991_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */
+#define WM8991_AIFADC_TDM 0x2000 /* AIFADC_TDM */
+#define WM8991_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */
+#define WM8991_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */
+#define WM8991_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */
+#define WM8991_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */
+#define WM8991_AIF_WL_16BITS (0 << 5)
+#define WM8991_AIF_WL_20BITS (1 << 5)
+#define WM8991_AIF_WL_24BITS (2 << 5)
+#define WM8991_AIF_WL_32BITS (3 << 5)
+#define WM8991_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */
+#define WM8991_AIF_TMF_RIGHTJ (0 << 3)
+#define WM8991_AIF_TMF_LEFTJ (1 << 3)
+#define WM8991_AIF_TMF_I2S (2 << 3)
+#define WM8991_AIF_TMF_DSP (3 << 3)
+
+/*
+ * R5 (0x05) - Audio Interface (2)
+ */
+#define WM8991_DACL_SRC 0x8000 /* DACL_SRC */
+#define WM8991_DACR_SRC 0x4000 /* DACR_SRC */
+#define WM8991_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
+#define WM8991_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
+#define WM8991_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */
+#define WM8991_DAC_COMP 0x0010 /* DAC_COMP */
+#define WM8991_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
+#define WM8991_ADC_COMP 0x0004 /* ADC_COMP */
+#define WM8991_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
+#define WM8991_LOOPBACK 0x0001 /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clocking (1)
+ */
+#define WM8991_TOCLK_RATE 0x8000 /* TOCLK_RATE */
+#define WM8991_TOCLK_ENA 0x4000 /* TOCLK_ENA */
+#define WM8991_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */
+#define WM8991_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */
+#define WM8991_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */
+#define WM8991_BCLK_DIV_1 (0x0 << 1)
+#define WM8991_BCLK_DIV_1_5 (0x1 << 1)
+#define WM8991_BCLK_DIV_2 (0x2 << 1)
+#define WM8991_BCLK_DIV_3 (0x3 << 1)
+#define WM8991_BCLK_DIV_4 (0x4 << 1)
+#define WM8991_BCLK_DIV_5_5 (0x5 << 1)
+#define WM8991_BCLK_DIV_6 (0x6 << 1)
+#define WM8991_BCLK_DIV_8 (0x7 << 1)
+#define WM8991_BCLK_DIV_11 (0x8 << 1)
+#define WM8991_BCLK_DIV_12 (0x9 << 1)
+#define WM8991_BCLK_DIV_16 (0xA << 1)
+#define WM8991_BCLK_DIV_22 (0xB << 1)
+#define WM8991_BCLK_DIV_24 (0xC << 1)
+#define WM8991_BCLK_DIV_32 (0xD << 1)
+#define WM8991_BCLK_DIV_44 (0xE << 1)
+#define WM8991_BCLK_DIV_48 (0xF << 1)
+
+/*
+ * R7 (0x07) - Clocking (2)
+ */
+#define WM8991_MCLK_SRC 0x8000 /* MCLK_SRC */
+#define WM8991_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
+#define WM8991_CLK_FORCE 0x2000 /* CLK_FORCE */
+#define WM8991_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */
+#define WM8991_MCLK_DIV_1 (0 << 11)
+#define WM8991_MCLK_DIV_2 ( 2 << 11)
+#define WM8991_MCLK_INV 0x0400 /* MCLK_INV */
+#define WM8991_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV - [7:5] */
+#define WM8991_ADC_CLKDIV_1 (0 << 5)
+#define WM8991_ADC_CLKDIV_1_5 (1 << 5)
+#define WM8991_ADC_CLKDIV_2 (2 << 5)
+#define WM8991_ADC_CLKDIV_3 (3 << 5)
+#define WM8991_ADC_CLKDIV_4 (4 << 5)
+#define WM8991_ADC_CLKDIV_5_5 (5 << 5)
+#define WM8991_ADC_CLKDIV_6 (6 << 5)
+#define WM8991_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */
+#define WM8991_DAC_CLKDIV_1 (0 << 2)
+#define WM8991_DAC_CLKDIV_1_5 (1 << 2)
+#define WM8991_DAC_CLKDIV_2 (2 << 2)
+#define WM8991_DAC_CLKDIV_3 (3 << 2)
+#define WM8991_DAC_CLKDIV_4 (4 << 2)
+#define WM8991_DAC_CLKDIV_5_5 (5 << 2)
+#define WM8991_DAC_CLKDIV_6 (6 << 2)
+
+/*
+ * R8 (0x08) - Audio Interface (3)
+ */
+#define WM8991_AIF_MSTR1 0x8000 /* AIF_MSTR1 */
+#define WM8991_AIF_MSTR2 0x4000 /* AIF_MSTR2 */
+#define WM8991_AIF_SEL 0x2000 /* AIF_SEL */
+#define WM8991_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */
+#define WM8991_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE - [10:0] */
+
+/*
+ * R9 (0x09) - Audio Interface (4)
+ */
+#define WM8991_ALRCGPIO1 0x8000 /* ALRCGPIO1 */
+#define WM8991_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */
+#define WM8991_AIF_TRIS 0x2000 /* AIF_TRIS */
+#define WM8991_DACLRC_DIR 0x0800 /* DACLRC_DIR */
+#define WM8991_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - DAC CTRL
+ */
+#define WM8991_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */
+#define WM8991_DAC_MONO 0x0200 /* DAC_MONO */
+#define WM8991_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */
+#define WM8991_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */
+#define WM8991_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */
+#define WM8991_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */
+#define WM8991_DAC_MUTE 0x0004 /* DAC_MUTE */
+#define WM8991_DACL_DATINV 0x0002 /* DACL_DATINV */
+#define WM8991_DACR_DATINV 0x0001 /* DACR_DATINV */
+
+/*
+ * R11 (0x0B) - Left DAC Digital Volume
+ */
+#define WM8991_DAC_VU 0x0100 /* DAC_VU */
+#define WM8991_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
+#define WM8991_DACL_VOL_SHIFT 0
+/*
+ * R12 (0x0C) - Right DAC Digital Volume
+ */
+#define WM8991_DAC_VU 0x0100 /* DAC_VU */
+#define WM8991_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
+#define WM8991_DACR_VOL_SHIFT 0
+/*
+ * R13 (0x0D) - Digital Side Tone
+ */
+#define WM8991_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL - [12:9] */
+#define WM8991_ADCL_DAC_SVOL_SHIFT 9
+#define WM8991_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL - [8:5] */
+#define WM8991_ADCR_DAC_SVOL_SHIFT 5
+#define WM8991_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */
+#define WM8991_ADC_TO_DACL_SHIFT 2
+#define WM8991_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */
+#define WM8991_ADC_TO_DACR_SHIFT 0
+
+/*
+ * R14 (0x0E) - ADC CTRL
+ */
+#define WM8991_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */
+#define WM8991_ADC_HPF_ENA_BIT 8
+#define WM8991_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */
+#define WM8991_ADC_HPF_CUT_SHIFT 5
+#define WM8991_ADCL_DATINV 0x0002 /* ADCL_DATINV */
+#define WM8991_ADCL_DATINV_BIT 1
+#define WM8991_ADCR_DATINV 0x0001 /* ADCR_DATINV */
+#define WM8991_ADCR_DATINV_BIT 0
+
+/*
+ * R15 (0x0F) - Left ADC Digital Volume
+ */
+#define WM8991_ADC_VU 0x0100 /* ADC_VU */
+#define WM8991_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
+#define WM8991_ADCL_VOL_SHIFT 0
+
+/*
+ * R16 (0x10) - Right ADC Digital Volume
+ */
+#define WM8991_ADC_VU 0x0100 /* ADC_VU */
+#define WM8991_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
+#define WM8991_ADCR_VOL_SHIFT 0
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8991_IRQ 0x1000 /* IRQ */
+#define WM8991_TEMPOK 0x0800 /* TEMPOK */
+#define WM8991_MICSHRT 0x0400 /* MICSHRT */
+#define WM8991_MICDET 0x0200 /* MICDET */
+#define WM8991_PLL_LCK 0x0100 /* PLL_LCK */
+#define WM8991_GPI8_STATUS 0x0080 /* GPI8_STATUS */
+#define WM8991_GPI7_STATUS 0x0040 /* GPI7_STATUS */
+#define WM8991_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */
+#define WM8991_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */
+#define WM8991_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */
+#define WM8991_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */
+#define WM8991_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */
+#define WM8991_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8991_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */
+#define WM8991_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */
+#define WM8991_GPIO2_PU 0x2000 /* GPIO2_PU */
+#define WM8991_GPIO2_PD 0x1000 /* GPIO2_PD */
+#define WM8991_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */
+#define WM8991_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */
+#define WM8991_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */
+#define WM8991_GPIO1_PU 0x0020 /* GPIO1_PU */
+#define WM8991_GPIO1_PD 0x0010 /* GPIO1_PD */
+#define WM8991_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8991_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */
+#define WM8991_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */
+#define WM8991_GPIO4_PU 0x2000 /* GPIO4_PU */
+#define WM8991_GPIO4_PD 0x1000 /* GPIO4_PD */
+#define WM8991_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */
+#define WM8991_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */
+#define WM8991_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */
+#define WM8991_GPIO3_PU 0x0020 /* GPIO3_PU */
+#define WM8991_GPIO3_PD 0x0010 /* GPIO3_PD */
+#define WM8991_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8991_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */
+#define WM8991_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */
+#define WM8991_GPIO6_PU 0x2000 /* GPIO6_PU */
+#define WM8991_GPIO6_PD 0x1000 /* GPIO6_PD */
+#define WM8991_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */
+#define WM8991_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */
+#define WM8991_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */
+#define WM8991_GPIO5_PU 0x0020 /* GPIO5_PU */
+#define WM8991_GPIO5_PD 0x0010 /* GPIO5_PD */
+#define WM8991_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8991_RD_3W_ENA 0x8000 /* RD_3W_ENA */
+#define WM8991_MODE_3W4W 0x4000 /* MODE_3W4W */
+#define WM8991_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */
+#define WM8991_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */
+#define WM8991_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */
+#define WM8991_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */
+#define WM8991_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */
+#define WM8991_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */
+#define WM8991_GPI8_ENA 0x0010 /* GPI8_ENA */
+#define WM8991_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */
+#define WM8991_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */
+#define WM8991_GPI7_ENA 0x0001 /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8991_IRQ_INV 0x1000 /* IRQ_INV */
+#define WM8991_TEMPOK_POL 0x0800 /* TEMPOK_POL */
+#define WM8991_MICSHRT_POL 0x0400 /* MICSHRT_POL */
+#define WM8991_MICDET_POL 0x0200 /* MICDET_POL */
+#define WM8991_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */
+#define WM8991_GPI8_POL 0x0080 /* GPI8_POL */
+#define WM8991_GPI7_POL 0x0040 /* GPI7_POL */
+#define WM8991_GPIO6_POL 0x0020 /* GPIO6_POL */
+#define WM8991_GPIO5_POL 0x0010 /* GPIO5_POL */
+#define WM8991_GPIO4_POL 0x0008 /* GPIO4_POL */
+#define WM8991_GPIO3_POL 0x0004 /* GPIO3_POL */
+#define WM8991_GPIO2_POL 0x0002 /* GPIO2_POL */
+#define WM8991_GPIO1_POL 0x0001 /* GPIO1_POL */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8991_IPVU 0x0100 /* IPVU */
+#define WM8991_LI12MUTE 0x0080 /* LI12MUTE */
+#define WM8991_LI12MUTE_BIT 7
+#define WM8991_LI12ZC 0x0040 /* LI12ZC */
+#define WM8991_LI12ZC_BIT 6
+#define WM8991_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */
+#define WM8991_LIN12VOL_SHIFT 0
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8991_IPVU 0x0100 /* IPVU */
+#define WM8991_LI34MUTE 0x0080 /* LI34MUTE */
+#define WM8991_LI34MUTE_BIT 7
+#define WM8991_LI34ZC 0x0040 /* LI34ZC */
+#define WM8991_LI34ZC_BIT 6
+#define WM8991_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */
+#define WM8991_LIN34VOL_SHIFT 0
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8991_IPVU 0x0100 /* IPVU */
+#define WM8991_RI12MUTE 0x0080 /* RI12MUTE */
+#define WM8991_RI12MUTE_BIT 7
+#define WM8991_RI12ZC 0x0040 /* RI12ZC */
+#define WM8991_RI12ZC_BIT 6
+#define WM8991_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */
+#define WM8991_RIN12VOL_SHIFT 0
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8991_IPVU 0x0100 /* IPVU */
+#define WM8991_RI34MUTE 0x0080 /* RI34MUTE */
+#define WM8991_RI34MUTE_BIT 7
+#define WM8991_RI34ZC 0x0040 /* RI34ZC */
+#define WM8991_RI34ZC_BIT 6
+#define WM8991_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */
+#define WM8991_RIN34VOL_SHIFT 0
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8991_OPVU 0x0100 /* OPVU */
+#define WM8991_LOZC 0x0080 /* LOZC */
+#define WM8991_LOZC_BIT 7
+#define WM8991_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */
+#define WM8991_LOUTVOL_SHIFT 0
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8991_OPVU 0x0100 /* OPVU */
+#define WM8991_ROZC 0x0080 /* ROZC */
+#define WM8991_ROZC_BIT 7
+#define WM8991_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */
+#define WM8991_ROUTVOL_SHIFT 0
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8991_LONMUTE 0x0040 /* LONMUTE */
+#define WM8991_LONMUTE_BIT 6
+#define WM8991_LOPMUTE 0x0020 /* LOPMUTE */
+#define WM8991_LOPMUTE_BIT 5
+#define WM8991_LOATTN 0x0010 /* LOATTN */
+#define WM8991_LOATTN_BIT 4
+#define WM8991_RONMUTE 0x0004 /* RONMUTE */
+#define WM8991_RONMUTE_BIT 2
+#define WM8991_ROPMUTE 0x0002 /* ROPMUTE */
+#define WM8991_ROPMUTE_BIT 1
+#define WM8991_ROATTN 0x0001 /* ROATTN */
+#define WM8991_ROATTN_BIT 0
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8991_OUT3MUTE 0x0020 /* OUT3MUTE */
+#define WM8991_OUT3MUTE_BIT 5
+#define WM8991_OUT3ATTN 0x0010 /* OUT3ATTN */
+#define WM8991_OUT3ATTN_BIT 4
+#define WM8991_OUT4MUTE 0x0002 /* OUT4MUTE */
+#define WM8991_OUT4MUTE_BIT 1
+#define WM8991_OUT4ATTN 0x0001 /* OUT4ATTN */
+#define WM8991_OUT4ATTN_BIT 0
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8991_OPVU 0x0100 /* OPVU */
+#define WM8991_LOPGAZC 0x0080 /* LOPGAZC */
+#define WM8991_LOPGAZC_BIT 7
+#define WM8991_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */
+#define WM8991_LOPGAVOL_SHIFT 0
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8991_OPVU 0x0100 /* OPVU */
+#define WM8991_ROPGAZC 0x0080 /* ROPGAZC */
+#define WM8991_ROPGAZC_BIT 7
+#define WM8991_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */
+#define WM8991_ROPGAVOL_SHIFT 0
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8991_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */
+#define WM8991_SPKVOL_SHIFT 0
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8991_CDMODE 0x0100 /* CDMODE */
+#define WM8991_CDMODE_BIT 8
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8991_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */
+#define WM8991_DCGAIN_SHIFT 3
+#define WM8991_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */
+#define WM8991_ACGAIN_SHIFT 0
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8991_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */
+#define WM8991_AINLMODE_SHIFT 2
+#define WM8991_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */
+#define WM8991_AINRMODE_SHIFT 0
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8991_LMP4 0x0080 /* LMP4 */
+#define WM8991_LMP4_BIT 7 /* LMP4 */
+#define WM8991_LMN3 0x0040 /* LMN3 */
+#define WM8991_LMN3_BIT 6 /* LMN3 */
+#define WM8991_LMP2 0x0020 /* LMP2 */
+#define WM8991_LMP2_BIT 5 /* LMP2 */
+#define WM8991_LMN1 0x0010 /* LMN1 */
+#define WM8991_LMN1_BIT 4 /* LMN1 */
+#define WM8991_RMP4 0x0008 /* RMP4 */
+#define WM8991_RMP4_BIT 3 /* RMP4 */
+#define WM8991_RMN3 0x0004 /* RMN3 */
+#define WM8991_RMN3_BIT 2 /* RMN3 */
+#define WM8991_RMP2 0x0002 /* RMP2 */
+#define WM8991_RMP2_BIT 1 /* RMP2 */
+#define WM8991_RMN1 0x0001 /* RMN1 */
+#define WM8991_RMN1_BIT 0 /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8991_L34MNB 0x0100 /* L34MNB */
+#define WM8991_L34MNB_BIT 8
+#define WM8991_L34MNBST 0x0080 /* L34MNBST */
+#define WM8991_L34MNBST_BIT 7
+#define WM8991_L12MNB 0x0020 /* L12MNB */
+#define WM8991_L12MNB_BIT 5
+#define WM8991_L12MNBST 0x0010 /* L12MNBST */
+#define WM8991_L12MNBST_BIT 4
+#define WM8991_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */
+#define WM8991_LDBVOL_SHIFT 0
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8991_R34MNB 0x0100 /* R34MNB */
+#define WM8991_R34MNB_BIT 8
+#define WM8991_R34MNBST 0x0080 /* R34MNBST */
+#define WM8991_R34MNBST_BIT 7
+#define WM8991_R12MNB 0x0020 /* R12MNB */
+#define WM8991_R12MNB_BIT 5
+#define WM8991_R12MNBST 0x0010 /* R12MNBST */
+#define WM8991_R12MNBST_BIT 4
+#define WM8991_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */
+#define WM8991_RDBVOL_SHIFT 0
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8991_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */
+#define WM8991_LI2BVOL_SHIFT 6
+#define WM8991_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */
+#define WM8991_LR4BVOL_SHIFT 3
+#define WM8991_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */
+#define WM8991_LL4BVOL_SHIFT 0
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8991_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */
+#define WM8991_RI2BVOL_SHIFT 6
+#define WM8991_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */
+#define WM8991_RL4BVOL_SHIFT 3
+#define WM8991_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */
+#define WM8991_RR4BVOL_SHIFT 0
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8991_LRBLO 0x0080 /* LRBLO */
+#define WM8991_LRBLO_BIT 7
+#define WM8991_LLBLO 0x0040 /* LLBLO */
+#define WM8991_LLBLO_BIT 6
+#define WM8991_LRI3LO 0x0020 /* LRI3LO */
+#define WM8991_LRI3LO_BIT 5
+#define WM8991_LLI3LO 0x0010 /* LLI3LO */
+#define WM8991_LLI3LO_BIT 4
+#define WM8991_LR12LO 0x0008 /* LR12LO */
+#define WM8991_LR12LO_BIT 3
+#define WM8991_LL12LO 0x0004 /* LL12LO */
+#define WM8991_LL12LO_BIT 2
+#define WM8991_LDLO 0x0001 /* LDLO */
+#define WM8991_LDLO_BIT 0
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8991_RLBRO 0x0080 /* RLBRO */
+#define WM8991_RLBRO_BIT 7
+#define WM8991_RRBRO 0x0040 /* RRBRO */
+#define WM8991_RRBRO_BIT 6
+#define WM8991_RLI3RO 0x0020 /* RLI3RO */
+#define WM8991_RLI3RO_BIT 5
+#define WM8991_RRI3RO 0x0010 /* RRI3RO */
+#define WM8991_RRI3RO_BIT 4
+#define WM8991_RL12RO 0x0008 /* RL12RO */
+#define WM8991_RL12RO_BIT 3
+#define WM8991_RR12RO 0x0004 /* RR12RO */
+#define WM8991_RR12RO_BIT 2
+#define WM8991_RDRO 0x0001 /* RDRO */
+#define WM8991_RDRO_BIT 0
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8991_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */
+#define WM8991_LLI3LOVOL_SHIFT 6
+#define WM8991_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */
+#define WM8991_LR12LOVOL_SHIFT 3
+#define WM8991_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */
+#define WM8991_LL12LOVOL_SHIFT 0
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8991_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */
+#define WM8991_RRI3ROVOL_SHIFT 6
+#define WM8991_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */
+#define WM8991_RL12ROVOL_SHIFT 3
+#define WM8991_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */
+#define WM8991_RR12ROVOL_SHIFT 0
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8991_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */
+#define WM8991_LRI3LOVOL_SHIFT 6
+#define WM8991_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */
+#define WM8991_LRBLOVOL_SHIFT 3
+#define WM8991_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */
+#define WM8991_LLBLOVOL_SHIFT 0
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8991_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */
+#define WM8991_RLI3ROVOL_SHIFT 6
+#define WM8991_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */
+#define WM8991_RLBROVOL_SHIFT 3
+#define WM8991_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */
+#define WM8991_RRBROVOL_SHIFT 0
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8991_VSEL_MASK 0x0180 /* VSEL - [8:7] */
+#define WM8991_LI4O3 0x0020 /* LI4O3 */
+#define WM8991_LI4O3_BIT 5
+#define WM8991_LPGAO3 0x0010 /* LPGAO3 */
+#define WM8991_LPGAO3_BIT 4
+#define WM8991_RI4O4 0x0002 /* RI4O4 */
+#define WM8991_RI4O4_BIT 1
+#define WM8991_RPGAO4 0x0001 /* RPGAO4 */
+#define WM8991_RPGAO4_BIT 0
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8991_LLOPGALON 0x0040 /* LLOPGALON */
+#define WM8991_LLOPGALON_BIT 6
+#define WM8991_LROPGALON 0x0020 /* LROPGALON */
+#define WM8991_LROPGALON_BIT 5
+#define WM8991_LOPLON 0x0010 /* LOPLON */
+#define WM8991_LOPLON_BIT 4
+#define WM8991_LR12LOP 0x0004 /* LR12LOP */
+#define WM8991_LR12LOP_BIT 2
+#define WM8991_LL12LOP 0x0002 /* LL12LOP */
+#define WM8991_LL12LOP_BIT 1
+#define WM8991_LLOPGALOP 0x0001 /* LLOPGALOP */
+#define WM8991_LLOPGALOP_BIT 0
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8991_RROPGARON 0x0040 /* RROPGARON */
+#define WM8991_RROPGARON_BIT 6
+#define WM8991_RLOPGARON 0x0020 /* RLOPGARON */
+#define WM8991_RLOPGARON_BIT 5
+#define WM8991_ROPRON 0x0010 /* ROPRON */
+#define WM8991_ROPRON_BIT 4
+#define WM8991_RL12ROP 0x0004 /* RL12ROP */
+#define WM8991_RL12ROP_BIT 2
+#define WM8991_RR12ROP 0x0002 /* RR12ROP */
+#define WM8991_RR12ROP_BIT 1
+#define WM8991_RROPGAROP 0x0001 /* RROPGAROP */
+#define WM8991_RROPGAROP_BIT 0
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8991_LB2SPK 0x0080 /* LB2SPK */
+#define WM8991_LB2SPK_BIT 7
+#define WM8991_RB2SPK 0x0040 /* RB2SPK */
+#define WM8991_RB2SPK_BIT 6
+#define WM8991_LI2SPK 0x0020 /* LI2SPK */
+#define WM8991_LI2SPK_BIT 5
+#define WM8991_RI2SPK 0x0010 /* RI2SPK */
+#define WM8991_RI2SPK_BIT 4
+#define WM8991_LOPGASPK 0x0008 /* LOPGASPK */
+#define WM8991_LOPGASPK_BIT 3
+#define WM8991_ROPGASPK 0x0004 /* ROPGASPK */
+#define WM8991_ROPGASPK_BIT 2
+#define WM8991_LDSPK 0x0002 /* LDSPK */
+#define WM8991_LDSPK_BIT 1
+#define WM8991_RDSPK 0x0001 /* RDSPK */
+#define WM8991_RDSPK_BIT 0
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8991_VROI 0x0001 /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8991_DIS_LLINE 0x0020 /* DIS_LLINE */
+#define WM8991_DIS_RLINE 0x0010 /* DIS_RLINE */
+#define WM8991_DIS_OUT3 0x0008 /* DIS_OUT3 */
+#define WM8991_DIS_OUT4 0x0004 /* DIS_OUT4 */
+#define WM8991_DIS_LOUT 0x0002 /* DIS_LOUT */
+#define WM8991_DIS_ROUT 0x0001 /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8991_SOFTST 0x0040 /* SOFTST */
+#define WM8991_BUFIOEN 0x0008 /* BUFIOEN */
+#define WM8991_BUFDCOPEN 0x0004 /* BUFDCOPEN */
+#define WM8991_POBCTRL 0x0002 /* POBCTRL */
+#define WM8991_VMIDTOG 0x0001 /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8991_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */
+#define WM8991_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */
+#define WM8991_MCD 0x0004 /* MCD */
+#define WM8991_MBSEL 0x0001 /* MBSEL */
+
+/*
+ * R60 (0x3C) - PLL1
+ */
+#define WM8991_SDM 0x0080 /* SDM */
+#define WM8991_PRESCALE 0x0040 /* PRESCALE */
+#define WM8991_PLLN_MASK 0x000F /* PLLN - [3:0] */
+
+/*
+ * R61 (0x3D) - PLL2
+ */
+#define WM8991_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */
+
+/*
+ * R62 (0x3E) - PLL3
+ */
+#define WM8991_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
+
+/*
+ * R63 (0x3F) - Internal Driver Bits
+ */
+#define WM8991_INMIXL_PWR_BIT 0
+#define WM8991_AINLMUX_PWR_BIT 1
+#define WM8991_INMIXR_PWR_BIT 2
+#define WM8991_AINRMUX_PWR_BIT 3
+
+#define WM8991_MCLK_DIV 0
+#define WM8991_DACCLK_DIV 1
+#define WM8991_ADCCLK_DIV 2
+#define WM8991_BCLK_DIV 3
+
+#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\
+ tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+#endif /* _WM8991_H */
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 18c0d9ce7c32..379fa22c5b6c 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -242,7 +242,7 @@ struct wm8993_priv {
int fll_src;
};
-static int wm8993_volatile(unsigned int reg)
+static int wm8993_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8993_SOFTWARE_RESET:
diff --git a/sound/soc/codecs/wm8994-tables.c b/sound/soc/codecs/wm8994-tables.c
index 68e9b024dd48..a87adbd05ee1 100644
--- a/sound/soc/codecs/wm8994-tables.c
+++ b/sound/soc/codecs/wm8994-tables.c
@@ -62,8 +62,8 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
{ 0x00FF, 0x00FF }, /* R58 - MICBIAS */
{ 0x000F, 0x000F }, /* R59 - LDO 1 */
{ 0x0007, 0x0007 }, /* R60 - LDO 2 */
- { 0x0000, 0x0000 }, /* R61 */
- { 0x0000, 0x0000 }, /* R62 */
+ { 0xFFFF, 0xFFFF }, /* R61 */
+ { 0xFFFF, 0xFFFF }, /* R62 */
{ 0x0000, 0x0000 }, /* R63 */
{ 0x0000, 0x0000 }, /* R64 */
{ 0x0000, 0x0000 }, /* R65 */
@@ -209,9 +209,9 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
{ 0x0000, 0x0000 }, /* R205 */
{ 0x0000, 0x0000 }, /* R206 */
{ 0x0000, 0x0000 }, /* R207 */
- { 0x0000, 0x0000 }, /* R208 */
- { 0x0000, 0x0000 }, /* R209 */
- { 0x0000, 0x0000 }, /* R210 */
+ { 0xFFFF, 0xFFFF }, /* R208 */
+ { 0xFFFF, 0xFFFF }, /* R209 */
+ { 0xFFFF, 0xFFFF }, /* R210 */
{ 0x0000, 0x0000 }, /* R211 */
{ 0x0000, 0x0000 }, /* R212 */
{ 0x0000, 0x0000 }, /* R213 */
@@ -1573,7 +1573,7 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
{ 0x03C3, 0x03C3 }, /* R1569 - Sidetone */
};
-const __devinitdata u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
+const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
0x8994, /* R0 - Software Reset */
0x0000, /* R1 - Power Management (1) */
0x6000, /* R2 - Power Management (2) */
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index c6c958ee5d59..3dc64c8b6a5c 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -102,8 +102,7 @@ struct wm8994_priv {
wm8958_micdet_cb jack_cb;
void *jack_cb_data;
- bool jack_is_mic;
- bool jack_is_video;
+ int micdet_irq;
int revision;
struct wm8994_pdata *pdata;
@@ -115,7 +114,7 @@ struct wm8994_priv {
unsigned int aif2clk_disable:1;
};
-static int wm8994_readable(unsigned int reg)
+static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM8994_GPIO_1:
@@ -142,7 +141,7 @@ static int wm8994_readable(unsigned int reg)
return wm8994_access_masks[reg].readable != 0;
}
-static int wm8994_volatile(unsigned int reg)
+static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
if (reg >= WM8994_CACHE_SIZE)
return 1;
@@ -170,7 +169,7 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
BUG_ON(reg > WM8994_MAX_REGISTER);
- if (!wm8994_volatile(reg)) {
+ if (!wm8994_volatile(codec, reg)) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret != 0)
dev_err(codec->dev, "Cache write to %x failed: %d\n",
@@ -188,7 +187,7 @@ static unsigned int wm8994_read(struct snd_soc_codec *codec,
BUG_ON(reg > WM8994_MAX_REGISTER);
- if (!wm8994_volatile(reg) && wm8994_readable(reg) &&
+ if (!wm8994_volatile(codec, reg) && wm8994_readable(codec, reg) &&
reg < codec->driver->reg_cache_size) {
ret = snd_soc_cache_read(codec, reg, &val);
if (ret >= 0)
@@ -529,7 +528,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
+ struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -1103,6 +1102,13 @@ static int adc_mux_ev(struct snd_soc_dapm_widget *w,
return 0;
}
+static int micbias_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ late_enable_ev(w, kcontrol, event);
+ return 0;
+}
+
static int dac_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1440,6 +1446,10 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"),
SND_SOC_DAPM_INPUT("DMIC2DAT"),
SND_SOC_DAPM_INPUT("Clock"),
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0),
+SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev,
+ SND_SOC_DAPM_PRE_PMU),
+
SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -1755,6 +1765,8 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
{ "AIF2DACDAT", NULL, "AIF1DACDAT" },
{ "AIF1ADCDAT", NULL, "AIF2ADCDAT" },
{ "AIF2ADCDAT", NULL, "AIF1ADCDAT" },
+ { "MICBIAS", NULL, "CLK_SYS" },
+ { "MICBIAS", NULL, "MICBIAS Supply" },
};
static const struct snd_soc_dapm_route wm8994_intercon[] = {
@@ -2883,6 +2895,13 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
else
snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
ARRAY_SIZE(wm8994_eq_controls));
+
+ for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
+ if (pdata->micbias[i]) {
+ snd_soc_write(codec, WM8958_MICBIAS1 + i,
+ pdata->micbias[i] & 0xffff);
+ }
+ }
}
/**
@@ -2993,46 +3012,18 @@ static void wm8958_default_micdet(u16 status, void *data)
int report = 0;
/* If nothing present then clear our statuses */
- if (!(status & WM8958_MICD_STS)) {
- wm8994->jack_is_video = false;
- wm8994->jack_is_mic = false;
+ if (!(status & WM8958_MICD_STS))
goto done;
- }
- /* Assume anything over 475 ohms is a microphone and remember
- * that we've seen one (since buttons override it) */
- if (status & 0x600)
- wm8994->jack_is_mic = true;
- if (wm8994->jack_is_mic)
- report |= SND_JACK_MICROPHONE;
-
- /* Video has an impedence of approximately 75 ohms; assume
- * this isn't used as a button and remember it since buttons
- * override it. */
- if (status & 0x40)
- wm8994->jack_is_video = true;
- if (wm8994->jack_is_video)
- report |= SND_JACK_VIDEOOUT;
+ report = SND_JACK_MICROPHONE;
/* Everything else is buttons; just assign slots */
- if (status & 0x4)
+ if (status & 0x1c0)
report |= SND_JACK_BTN_0;
- if (status & 0x8)
- report |= SND_JACK_BTN_1;
- if (status & 0x10)
- report |= SND_JACK_BTN_2;
- if (status & 0x20)
- report |= SND_JACK_BTN_3;
- if (status & 0x80)
- report |= SND_JACK_BTN_4;
- if (status & 0x100)
- report |= SND_JACK_BTN_5;
done:
snd_soc_jack_report(wm8994->micdet[0].jack, report,
- SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
- SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5 |
- SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT);
+ SND_JACK_BTN_0 | SND_JACK_MICROPHONE);
}
/**
@@ -3131,13 +3122,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->pdata = dev_get_platdata(codec->dev->parent);
wm8994->codec = codec;
+ if (wm8994->pdata && wm8994->pdata->micdet_irq)
+ wm8994->micdet_irq = wm8994->pdata->micdet_irq;
+ else if (wm8994->pdata && wm8994->pdata->irq_base)
+ wm8994->micdet_irq = wm8994->pdata->irq_base +
+ WM8994_IRQ_MIC1_DET;
+
pm_runtime_enable(codec->dev);
pm_runtime_resume(codec->dev);
/* Read our current status back from the chip - we don't want to
* reset as this may interfere with the GPIO or LDO operation. */
for (i = 0; i < WM8994_CACHE_SIZE; i++) {
- if (!wm8994_readable(i) || wm8994_volatile(i))
+ if (!wm8994_readable(codec, i) || wm8994_volatile(codec, i))
continue;
ret = wm8994_reg_read(codec->control_data, i);
@@ -3179,14 +3176,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
switch (control->type) {
case WM8994:
- ret = wm8994_request_irq(codec->control_data,
- WM8994_IRQ_MIC1_DET,
- wm8994_mic_irq, "Mic 1 detect",
- wm8994);
- if (ret != 0)
- dev_warn(codec->dev,
- "Failed to request Mic1 detect IRQ: %d\n",
- ret);
+ if (wm8994->micdet_irq) {
+ ret = request_threaded_irq(wm8994->micdet_irq, NULL,
+ wm8994_mic_irq,
+ IRQF_TRIGGER_RISING,
+ "Mic1 detect",
+ wm8994);
+ if (ret != 0)
+ dev_warn(codec->dev,
+ "Failed to request Mic1 detect IRQ: %d\n",
+ ret);
+ }
ret = wm8994_request_irq(codec->control_data,
WM8994_IRQ_MIC1_SHRT,
@@ -3217,15 +3217,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break;
case WM8958:
- ret = wm8994_request_irq(codec->control_data,
- WM8994_IRQ_MIC1_DET,
- wm8958_mic_irq, "Mic detect",
- wm8994);
- if (ret != 0)
- dev_warn(codec->dev,
- "Failed to request Mic detect IRQ: %d\n",
- ret);
- break;
+ if (wm8994->micdet_irq) {
+ ret = request_threaded_irq(wm8994->micdet_irq, NULL,
+ wm8958_mic_irq,
+ IRQF_TRIGGER_RISING,
+ "Mic detect",
+ wm8994);
+ if (ret != 0)
+ dev_warn(codec->dev,
+ "Failed to request Mic detect IRQ: %d\n",
+ ret);
+ }
}
/* Remember if AIFnLRCLK is configured as a GPIO. This should be
@@ -3369,7 +3371,8 @@ err_irq:
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
- wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
+ if (wm8994->micdet_irq)
+ free_irq(wm8994->micdet_irq, wm8994);
err:
kfree(wm8994);
return ret;
@@ -3386,8 +3389,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
switch (control->type) {
case WM8994:
- wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
- wm8994);
+ if (wm8994->micdet_irq)
+ free_irq(wm8994->micdet_irq, wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
wm8994);
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
@@ -3397,8 +3400,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
break;
case WM8958:
- wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
- wm8994);
+ if (wm8994->micdet_irq)
+ free_irq(wm8994->micdet_irq, wm8994);
break;
}
kfree(wm8994->retune_mobile_texts);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 0c355bfc88f1..999b8851226b 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -43,6 +43,6 @@ struct wm8994_access_mask {
};
extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
-extern const __devinitdata u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
+extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
#endif
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 608c84c5aa8e..67eaaecbb42e 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -19,6 +19,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -30,6 +31,18 @@
#include "wm8995.h"
+#define WM8995_NUM_SUPPLIES 8
+static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
+ "DCVDD",
+ "DBVDD1",
+ "DBVDD2",
+ "DBVDD3",
+ "AVDD1",
+ "AVDD2",
+ "CPVDD",
+ "MICVDD"
+};
+
static const u16 wm8995_reg_defs[WM8995_MAX_REGISTER + 1] = {
[0] = 0x8995, [5] = 0x0100, [16] = 0x000b, [17] = 0x000b,
[24] = 0x02c0, [25] = 0x02c0, [26] = 0x02c0, [27] = 0x02c0,
@@ -126,8 +139,37 @@ struct wm8995_priv {
int mclk[2];
int aifclk[2];
struct fll_config fll[2], fll_suspend[2];
+ struct regulator_bulk_data supplies[WM8995_NUM_SUPPLIES];
+ struct notifier_block disable_nb[WM8995_NUM_SUPPLIES];
+ struct snd_soc_codec *codec;
};
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8995_REGULATOR_EVENT(n) \
+static int wm8995_regulator_event_##n(struct notifier_block *nb, \
+ unsigned long event, void *data) \
+{ \
+ struct wm8995_priv *wm8995 = container_of(nb, struct wm8995_priv, \
+ disable_nb[n]); \
+ if (event & REGULATOR_EVENT_DISABLE) { \
+ wm8995->codec->cache_sync = 1; \
+ } \
+ return 0; \
+}
+
+WM8995_REGULATOR_EVENT(0)
+WM8995_REGULATOR_EVENT(1)
+WM8995_REGULATOR_EVENT(2)
+WM8995_REGULATOR_EVENT(3)
+WM8995_REGULATOR_EVENT(4)
+WM8995_REGULATOR_EVENT(5)
+WM8995_REGULATOR_EVENT(6)
+WM8995_REGULATOR_EVENT(7)
+
static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
static const DECLARE_TLV_DB_SCALE(in1lr_pga_tlv, -1650, 150, 0);
static const DECLARE_TLV_DB_SCALE(in1l_boost_tlv, 0, 600, 0);
@@ -909,7 +951,7 @@ static const struct snd_soc_dapm_route wm8995_intercon[] = {
{ "SPK2R", NULL, "SPK2R Driver" }
};
-static int wm8995_volatile(unsigned int reg)
+static int wm8995_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
/* out of bounds registers are generally considered
* volatile to support register banks that are partially
@@ -1483,6 +1525,11 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
+ wm8995->supplies);
+ if (ret)
+ return ret;
+
ret = snd_soc_cache_sync(codec);
if (ret) {
dev_err(codec->dev,
@@ -1492,12 +1539,13 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
WM8995_BG_ENA_MASK, WM8995_BG_ENA);
-
}
break;
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
WM8995_BG_ENA_MASK, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies),
+ wm8995->supplies);
break;
}
@@ -1536,10 +1584,12 @@ static int wm8995_remove(struct snd_soc_codec *codec)
static int wm8995_probe(struct snd_soc_codec *codec)
{
struct wm8995_priv *wm8995;
+ int i;
int ret;
codec->dapm.idle_bias_off = 1;
wm8995 = snd_soc_codec_get_drvdata(codec);
+ wm8995->codec = codec;
ret = snd_soc_codec_set_cache_io(codec, 16, 16, wm8995->control_type);
if (ret < 0) {
@@ -1547,21 +1597,58 @@ static int wm8995_probe(struct snd_soc_codec *codec)
return ret;
}
+ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++)
+ wm8995->supplies[i].supply = wm8995_supply_names[i];
+
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8995->supplies),
+ wm8995->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ wm8995->disable_nb[0].notifier_call = wm8995_regulator_event_0;
+ wm8995->disable_nb[1].notifier_call = wm8995_regulator_event_1;
+ wm8995->disable_nb[2].notifier_call = wm8995_regulator_event_2;
+ wm8995->disable_nb[3].notifier_call = wm8995_regulator_event_3;
+ wm8995->disable_nb[4].notifier_call = wm8995_regulator_event_4;
+ wm8995->disable_nb[5].notifier_call = wm8995_regulator_event_5;
+ wm8995->disable_nb[6].notifier_call = wm8995_regulator_event_6;
+ wm8995->disable_nb[7].notifier_call = wm8995_regulator_event_7;
+
+ /* This should really be moved into the regulator core */
+ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) {
+ ret = regulator_register_notifier(wm8995->supplies[i].consumer,
+ &wm8995->disable_nb[i]);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to register regulator notifier: %d\n",
+ ret);
+ }
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies),
+ wm8995->supplies);
+ if (ret) {
+ dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+ goto err_reg_get;
+ }
+
ret = snd_soc_read(codec, WM8995_SOFTWARE_RESET);
if (ret < 0) {
dev_err(codec->dev, "Failed to read device ID: %d\n", ret);
- return ret;
+ goto err_reg_enable;
}
if (ret != 0x8995) {
dev_err(codec->dev, "Invalid device ID: %#x\n", ret);
- return -EINVAL;
+ goto err_reg_enable;
}
ret = snd_soc_write(codec, WM8995_SOFTWARE_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
- return ret;
+ goto err_reg_enable;
}
wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1596,6 +1683,12 @@ static int wm8995_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(wm8995_intercon));
return 0;
+
+err_reg_enable:
+ regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
+err_reg_get:
+ regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
+ return ret;
}
#define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index cce704c275c6..55cdf2982020 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -167,10 +167,10 @@ struct wm9081_priv {
int fll_fref;
int fll_fout;
int tdm_width;
- struct wm9081_retune_mobile_config *retune;
+ struct wm9081_pdata pdata;
};
-static int wm9081_volatile_register(unsigned int reg)
+static int wm9081_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM9081_SOFTWARE_RESET:
@@ -389,27 +389,6 @@ SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0),
SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0),
};
-static int speaker_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- reg |= WM9081_SPK_ENA;
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- reg &= ~WM9081_SPK_ENA;
- break;
- }
-
- snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg);
-
- return 0;
-}
-
struct _fll_div {
u16 fll_fratio;
u16 fll_outdiv;
@@ -747,9 +726,8 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
-SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0,
- speaker_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_OUTPUT("SPKN"),
@@ -762,7 +740,7 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
};
-static const struct snd_soc_dapm_route audio_paths[] = {
+static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
{ "DAC", NULL, "CLK_SYS" },
{ "DAC", NULL, "CLK_DSP" },
@@ -780,8 +758,10 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Speaker PGA", NULL, "TOCLK" },
{ "Speaker PGA", NULL, "CLK_SYS" },
- { "SPKN", NULL, "Speaker PGA" },
- { "SPKP", NULL, "Speaker PGA" },
+ { "Speaker", NULL, "Speaker PGA" },
+
+ { "SPKN", NULL, "Speaker" },
+ { "SPKP", NULL, "Speaker" },
};
static int wm9081_set_bias_level(struct snd_soc_codec *codec,
@@ -1082,21 +1062,22 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
aif4 |= wm9081->bclk / wm9081->fs;
/* Apply a ReTune Mobile configuration if it's in use */
- if (wm9081->retune) {
- struct wm9081_retune_mobile_config *retune = wm9081->retune;
+ if (wm9081->pdata.num_retune_configs) {
+ struct wm9081_pdata *pdata = &wm9081->pdata;
struct wm9081_retune_mobile_setting *s;
int eq1;
best = 0;
- best_val = abs(retune->configs[0].rate - wm9081->fs);
- for (i = 0; i < retune->num_configs; i++) {
- cur_val = abs(retune->configs[i].rate - wm9081->fs);
+ best_val = abs(pdata->retune_configs[0].rate - wm9081->fs);
+ for (i = 0; i < pdata->num_retune_configs; i++) {
+ cur_val = abs(pdata->retune_configs[i].rate -
+ wm9081->fs);
if (cur_val < best_val) {
best_val = cur_val;
best = i;
}
}
- s = &retune->configs[best];
+ s = &pdata->retune_configs[best];
dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n",
s->name, s->rate);
@@ -1139,10 +1120,9 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
return 0;
}
-static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
+static int wm9081_set_sysclk(struct snd_soc_codec *codec,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = codec_dai->codec;
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
switch (clk_id) {
@@ -1207,7 +1187,6 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
static struct snd_soc_dai_ops wm9081_dai_ops = {
.hw_params = wm9081_hw_params,
- .set_sysclk = wm9081_set_sysclk,
.set_fmt = wm9081_set_dai_fmt,
.digital_mute = wm9081_digital_mute,
.set_tdm_slot = wm9081_set_tdm_slot,
@@ -1231,7 +1210,6 @@ static struct snd_soc_dai_driver wm9081_dai = {
static int wm9081_probe(struct snd_soc_codec *codec)
{
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
u16 reg;
@@ -1255,6 +1233,14 @@ static int wm9081_probe(struct snd_soc_codec *codec)
return ret;
}
+ reg = 0;
+ if (wm9081->pdata.irq_high)
+ reg |= WM9081_IRQ_POL;
+ if (!wm9081->pdata.irq_cmos)
+ reg |= WM9081_IRQ_OP_CTRL;
+ snd_soc_update_bits(codec, WM9081_INTERRUPT_CONTROL,
+ WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg);
+
wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Enable zero cross by default */
@@ -1266,17 +1252,13 @@ static int wm9081_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, wm9081_snd_controls,
ARRAY_SIZE(wm9081_snd_controls));
- if (!wm9081->retune) {
+ if (!wm9081->pdata.num_retune_configs) {
dev_dbg(codec->dev,
"No ReTune Mobile data, using normal EQ\n");
snd_soc_add_controls(codec, wm9081_eq_controls,
ARRAY_SIZE(wm9081_eq_controls));
}
- snd_soc_dapm_new_controls(dapm, wm9081_dapm_widgets,
- ARRAY_SIZE(wm9081_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
-
return ret;
}
@@ -1320,11 +1302,19 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
.remove = wm9081_remove,
.suspend = wm9081_suspend,
.resume = wm9081_resume,
+
+ .set_sysclk = wm9081_set_sysclk,
.set_bias_level = wm9081_set_bias_level,
+
.reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm9081_reg_defaults,
.volatile_register = wm9081_volatile_register,
+
+ .dapm_widgets = wm9081_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets),
+ .dapm_routes = wm9081_audio_paths,
+ .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths),
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@@ -1343,8 +1333,8 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
wm9081->control_data = i2c;
if (dev_get_platdata(&i2c->dev))
- memcpy(&wm9081->retune, dev_get_platdata(&i2c->dev),
- sizeof(wm9081->retune));
+ memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
+ sizeof(wm9081->pdata));
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm9081, &wm9081_dai, 1);
@@ -1368,7 +1358,7 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
static struct i2c_driver wm9081_i2c_driver = {
.driver = {
- .name = "wm9081-codec",
+ .name = "wm9081",
.owner = THIS_MODULE,
},
.probe = wm9081_i2c_probe,
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index a788c4297046..4de12203e611 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -144,7 +144,7 @@ struct wm9090_priv {
void *control_data;
};
-static int wm9090_volatile(unsigned int reg)
+static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg)
{
switch (reg) {
case WM9090_SOFTWARE_RESET:
@@ -518,7 +518,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
for (i = 1; i < codec->driver->reg_cache_size; i++) {
if (reg_cache[i] == wm9090_reg_defaults[i])
continue;
- if (wm9090_volatile(i))
+ if (wm9090_volatile(codec, i))
continue;
ret = snd_soc_write(codec, i, reg_cache[i]);
@@ -551,7 +551,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
static int wm9090_probe(struct snd_soc_codec *codec)
{
struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
- u16 *reg_cache = codec->reg_cache;
int ret;
codec->control_data = wm9090->control_data;
@@ -576,22 +575,30 @@ static int wm9090_probe(struct snd_soc_codec *codec)
/* Configure some defaults; they will be written out when we
* bring the bias up.
*/
- reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
- | WM9090_IN1A_ZC;
- reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
- | WM9090_IN1B_ZC;
- reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
- | WM9090_IN2A_ZC;
- reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
- | WM9090_IN2B_ZC;
- reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
- WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
- reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
- WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
- reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
- WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
-
- reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+ snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_A_VOLUME,
+ WM9090_IN1_VU | WM9090_IN1A_ZC,
+ WM9090_IN1_VU | WM9090_IN1A_ZC);
+ snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_B_VOLUME,
+ WM9090_IN1_VU | WM9090_IN1B_ZC,
+ WM9090_IN1_VU | WM9090_IN1B_ZC);
+ snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_A_VOLUME,
+ WM9090_IN2_VU | WM9090_IN2A_ZC,
+ WM9090_IN2_VU | WM9090_IN2A_ZC);
+ snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_B_VOLUME,
+ WM9090_IN2_VU | WM9090_IN2B_ZC,
+ WM9090_IN2_VU | WM9090_IN2B_ZC);
+ snd_soc_update_bits(codec, WM9090_SPEAKER_VOLUME_LEFT,
+ WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC,
+ WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC);
+ snd_soc_update_bits(codec, WM9090_LEFT_OUTPUT_VOLUME,
+ WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC,
+ WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC);
+ snd_soc_update_bits(codec, WM9090_RIGHT_OUTPUT_VOLUME,
+ WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC,
+ WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC);
+
+ snd_soc_update_bits(codec, WM9090_CLOCKING_1,
+ WM9090_TOCLK_ENA, WM9090_TOCLK_ENA);
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 516892706063..7b6b3c18e299 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -82,7 +82,8 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
} while (reg & op && count < 400);
if (reg & op)
- dev_err(codec->dev, "Timed out waiting for DC Servo\n");
+ dev_err(codec->dev, "Timed out waiting for DC Servo %x\n",
+ op);
}
/*
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 9e0e565e6ed9..d0d60b8a54d4 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -658,7 +658,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
return -ENODEV;
}
- ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ ioarea = request_mem_region(mem->start, resource_size(mem),
pdev->name);
if (!ioarea) {
dev_err(&pdev->dev, "McBSP region already claimed\n");
@@ -694,20 +694,25 @@ static int davinci_i2s_probe(struct platform_device *pdev)
}
clk_enable(dev->clk);
- dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (!dev->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_release_clk;
+ }
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
- (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG);
+ (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG);
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
- (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG);
+ (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG);
/* first TX, then RX */
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
- goto err_free_mem;
+ goto err_iounmap;
}
dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
@@ -715,7 +720,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
- goto err_free_mem;
+ goto err_iounmap;
}
dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
dev->dev = &pdev->dev;
@@ -724,14 +729,19 @@ static int davinci_i2s_probe(struct platform_device *pdev)
ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
if (ret != 0)
- goto err_free_mem;
+ goto err_iounmap;
return 0;
+err_iounmap:
+ iounmap(dev->base);
+err_release_clk:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
err_free_mem:
kfree(dev);
err_release_region:
- release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ release_mem_region(mem->start, resource_size(mem));
return ret;
}
@@ -747,7 +757,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
dev->clk = NULL;
kfree(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ release_mem_region(mem->start, resource_size(mem));
return 0;
}
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index fb55d2c5d704..a5af834c8ef5 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -868,7 +868,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
}
ioarea = request_mem_region(mem->start,
- (mem->end - mem->start) + 1, pdev->name);
+ resource_size(mem), pdev->name);
if (!ioarea) {
dev_err(&pdev->dev, "Audio region already claimed\n");
ret = -EBUSY;
@@ -885,7 +885,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
clk_enable(dev->clk);
dev->clk_active = 1;
- dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+ dev->base = ioremap(mem->start, resource_size(mem));
+ if (!dev->base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_release_clk;
+ }
+
dev->op_mode = pdata->op_mode;
dev->tdm_slots = pdata->tdm_slots;
dev->num_serializer = pdata->num_serializer;
@@ -899,14 +905,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_data->asp_chan_q = pdata->asp_chan_q;
dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
- io_v2p(dev->base));
+ mem->start);
/* first TX, then RX */
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENODEV;
- goto err_release_region;
+ goto err_iounmap;
}
dma_data->channel = res->start;
@@ -915,13 +921,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
dma_data->asp_chan_q = pdata->asp_chan_q;
dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
- io_v2p(dev->base));
+ mem->start);
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENODEV;
- goto err_release_region;
+ goto err_iounmap;
}
dma_data->channel = res->start;
@@ -929,11 +935,16 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
if (ret != 0)
- goto err_release_region;
+ goto err_iounmap;
return 0;
+err_iounmap:
+ iounmap(dev->base);
+err_release_clk:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
err_release_region:
- release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ release_mem_region(mem->start, resource_size(mem));
err_release_data:
kfree(dev);
@@ -951,7 +962,7 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
dev->clk = NULL;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ release_mem_region(mem->start, resource_size(mem));
kfree(dev);
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index 57429041189c..91a28de94109 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -30,3 +30,12 @@ config SND_EP93XX_SOC_SIMONE
help
Say Y or M here if you want to add support for AC97 audio on the
Simplemachines Sim.One board.
+
+config SND_EP93XX_SOC_EDB93XX
+ tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
+ depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
+ select SND_EP93XX_SOC_I2S
+ select SND_SOC_CS4271
+ help
+ Say Y or M here if you want to add support for I2S audio on the
+ Cirrus Logic EDB93xx boards.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 8e7977fb6b7d..5514146cbdf0 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o
# EP93XX Machine Support
snd-soc-snappercl15-objs := snappercl15.o
snd-soc-simone-objs := simone.o
+snd-soc-edb93xx-objs := edb93xx.o
obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o
+obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o
diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/ep93xx/edb93xx.c
new file mode 100644
index 000000000000..d3aa15119d26
--- /dev/null
+++ b/sound/soc/ep93xx/edb93xx.c
@@ -0,0 +1,142 @@
+/*
+ * SoC audio for EDB93xx
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver support CS4271 codec being master or slave, working
+ * in control port mode, connected either via SPI or I2C.
+ * The data format accepted is I2S or left-justified.
+ * DAPM support not implemented.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include "ep93xx-pcm.h"
+
+#define edb93xx_has_audio() (machine_is_edb9301() || \
+ machine_is_edb9302() || \
+ machine_is_edb9302a() || \
+ machine_is_edb9307a() || \
+ machine_is_edb9315a())
+
+static int edb93xx_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int err;
+ unsigned int mclk_rate;
+ unsigned int rate = params_rate(params);
+
+ /*
+ * According to CS4271 datasheet we use MCLK/LRCK=256 for
+ * rates below 50kHz and 128 for higher sample rates
+ */
+ if (rate < 50000)
+ mclk_rate = rate * 64 * 4;
+ else
+ mclk_rate = rate * 64 * 2;
+
+ err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (err)
+ return err;
+
+ err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_IF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (err)
+ return err;
+
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
+ SND_SOC_CLOCK_IN);
+ if (err)
+ return err;
+
+ return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
+ SND_SOC_CLOCK_OUT);
+}
+
+static struct snd_soc_ops edb93xx_ops = {
+ .hw_params = edb93xx_hw_params,
+};
+
+static struct snd_soc_dai_link edb93xx_dai = {
+ .name = "CS4271",
+ .stream_name = "CS4271 HiFi",
+ .platform_name = "ep93xx-pcm-audio",
+ .cpu_dai_name = "ep93xx-i2s",
+ .codec_name = "spi0.0",
+ .codec_dai_name = "cs4271-hifi",
+ .ops = &edb93xx_ops,
+};
+
+static struct snd_soc_card snd_soc_edb93xx = {
+ .name = "EDB93XX",
+ .dai_link = &edb93xx_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *edb93xx_snd_device;
+
+static int __init edb93xx_init(void)
+{
+ int ret;
+
+ if (!edb93xx_has_audio())
+ return -ENODEV;
+
+ ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
+ EP93XX_SYSCON_I2SCLKDIV_ORIDE |
+ EP93XX_SYSCON_I2SCLKDIV_SPOL);
+ if (ret)
+ return ret;
+
+ edb93xx_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!edb93xx_snd_device) {
+ ret = -ENOMEM;
+ goto free_i2s;
+ }
+
+ platform_set_drvdata(edb93xx_snd_device, &snd_soc_edb93xx);
+ ret = platform_device_add(edb93xx_snd_device);
+ if (ret)
+ goto device_put;
+
+ return 0;
+
+device_put:
+ platform_device_put(edb93xx_snd_device);
+free_i2s:
+ ep93xx_i2s_release();
+ return ret;
+}
+module_init(edb93xx_init);
+
+static void __exit edb93xx_exit(void)
+{
+ platform_device_unregister(edb93xx_snd_device);
+ ep93xx_i2s_release();
+}
+module_exit(edb93xx_exit);
+
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_DESCRIPTION("ALSA SoC EDB93xx");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index 68a0bae1208a..104e95cda0ad 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -253,7 +253,6 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
unsigned v = 0;
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index fff579a1c134..042f4e93746f 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -242,7 +242,7 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
unsigned word_len, div, sdiv, lrdiv;
- int found = 0, err;
+ int err;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -275,15 +275,14 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
* the codec uses.
*/
div = clk_get_rate(info->mclk) / params_rate(params);
- for (sdiv = 2; sdiv <= 4; sdiv += 2)
- for (lrdiv = 64; lrdiv <= 128; lrdiv <<= 1)
- if (sdiv * lrdiv == div) {
- found = 1;
- goto out;
- }
-out:
- if (!found)
- return -EINVAL;
+ sdiv = 4;
+ if (div > (256 + 512) / 2) {
+ lrdiv = 128;
+ } else {
+ lrdiv = 64;
+ if (div < (128 + 256) / 2)
+ sdiv = 2;
+ }
err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
if (err)
@@ -314,10 +313,12 @@ static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
- return;
+ return 0;
ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
+
+ return 0;
}
static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
@@ -325,10 +326,12 @@ static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
- return;
+ return 0;
ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+
+ return 0;
}
#else
#define ep93xx_i2s_suspend NULL
@@ -352,13 +355,13 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.playback = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
+ .rates = SNDRV_PCM_RATE_8000_192000,
.formats = EP93XX_I2S_FORMATS,
},
.capture = {
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
+ .rates = SNDRV_PCM_RATE_8000_192000,
.formats = EP93XX_I2S_FORMATS,
},
.ops = &ep93xx_i2s_dai_ops,
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
index 06670776f649..a456e491155f 100644
--- a/sound/soc/ep93xx/ep93xx-pcm.c
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -35,9 +35,9 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER),
- .rates = SNDRV_PCM_RATE_8000_96000,
+ .rates = SNDRV_PCM_RATE_8000_192000,
.rate_min = SNDRV_PCM_RATE_8000,
- .rate_max = SNDRV_PCM_RATE_96000,
+ .rate_max = SNDRV_PCM_RATE_192000,
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE |
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 7d7847a1e66b..c16c6b2eff95 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -53,9 +53,8 @@ struct mpc8610_hpcd_data {
*
* Here we program the DMACR and PMUXCR registers.
*/
-static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_probe(struct snd_soc_card *card)
{
- struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
container_of(card, struct mpc8610_hpcd_data, card);
struct ccsr_guts_86xx __iomem *guts;
@@ -138,9 +137,8 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
* This function is called to remove the sound device for one SSI. We
* de-program the DMACR and PMUXCR register.
*/
-static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card)
{
- struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct mpc8610_hpcd_data *machine_data =
container_of(card, struct mpc8610_hpcd_data, card);
struct ccsr_guts_86xx __iomem *guts;
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 026b756961e0..66e0b68af147 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -85,9 +85,8 @@ struct machine_data {
*
* Here we program the DMACR and PMUXCR registers.
*/
-static int p1022_ds_machine_probe(struct platform_device *sound_device)
+static int p1022_ds_machine_probe(struct snd_soc_card *card)
{
- struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct machine_data *mdata =
container_of(card, struct machine_data, card);
struct ccsr_guts_85xx __iomem *guts;
@@ -160,9 +159,8 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream)
* This function is called to remove the sound device for one SSI. We
* de-program the DMACR and PMUXCR register.
*/
-static int p1022_ds_machine_remove(struct platform_device *sound_device)
+static int p1022_ds_machine_remove(struct snd_soc_card *card)
{
- struct snd_soc_card *card = platform_get_drvdata(sound_device);
struct machine_data *mdata =
container_of(card, struct machine_data, card);
struct ccsr_guts_85xx __iomem *guts;
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 642270a635ea..d8f130d39dd9 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -30,6 +30,16 @@ config SND_MXC_SOC_WM1133_EV1
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
+config SND_SOC_MX27VIS_AIC32X4
+ tristate "SoC audio support for Visstrim M10 boards"
+ depends on MACH_IMX27_VISSTRIM_M10
+ select SND_SOC_TVL320AIC32X4
+ select SND_MXC_SOC_SSI
+ select SND_MXC_SOC_MX2
+ help
+ Say Y if you want to add support for SoC audio on Visstrim SM10
+ board with TLV320AIC32X4 codec.
+
config SND_SOC_PHYCORE_AC97
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
@@ -44,7 +54,8 @@ config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
depends on MACH_EUKREA_MBIMX27_BASEBOARD \
|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
- || MACH_EUKREA_MBIMXSD35_BASEBOARD
+ || MACH_EUKREA_MBIMXSD35_BASEBOARD \
+ || MACH_EUKREA_MBIMXSD51_BASEBOARD
select SND_SOC_TLV320AIC23
select SND_MXC_SOC_SSI
select SND_MXC_SOC_FIQ
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index b67fc02a4ecc..d6d609ba7e24 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -10,8 +10,10 @@ obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
# i.MX Machine Support
snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
index 1e9bccae4e80..75fb4b83548b 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -98,7 +98,8 @@ static int __init eukrea_tlv320_init(void)
int ret;
if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd()
- && !machine_is_eukrea_cpuimx35sd())
+ && !machine_is_eukrea_cpuimx35sd()
+ && !machine_is_eukrea_cpuimx51sd())
/* return happy. We might run on a totally different machine */
return 0;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 30894ea7f333..bc92ec620004 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -108,7 +108,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_DSP_B:
/* data on rising edge of bclk, frame high with data */
- strcr |= SSI_STCR_TFSL;
+ strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0;
break;
case SND_SOC_DAIFMT_DSP_A:
/* data on rising edge of bclk, frame high 1clk before data */
@@ -656,6 +656,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+ ssi->dma_params_tx.burstsize = 4;
+ ssi->dma_params_rx.burstsize = 4;
+
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
if (res)
ssi->dma_params_tx.dma = res->start;
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c
new file mode 100644
index 000000000000..054110b91d42
--- /dev/null
+++ b/sound/soc/imx/mx27vis-aic32x4.c
@@ -0,0 +1,137 @@
+/*
+ * mx27vis-aic32x4.c
+ *
+ * Copyright 2011 Vista Silicon S.L.
+ *
+ * Author: Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+#include <mach/audmux.h>
+
+#include "../codecs/tlv320aic32x4.h"
+#include "imx-ssi.h"
+
+static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret;
+ u32 dai_format;
+
+ dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ /* set codec DAI configuration */
+ snd_soc_dai_set_fmt(codec_dai, dai_format);
+
+ /* set cpu DAI configuration */
+ snd_soc_dai_set_fmt(cpu_dai, dai_format);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ 25000000, SND_SOC_CLOCK_OUT);
+ if (ret) {
+ pr_err("%s: failed setting codec sysclk\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops mx27vis_aic32x4_snd_ops = {
+ .hw_params = mx27vis_aic32x4_hw_params,
+};
+
+static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
+ .name = "tlv320aic32x4",
+ .stream_name = "TLV320AIC32X4",
+ .codec_dai_name = "tlv320aic32x4-hifi",
+ .platform_name = "imx-pcm-audio.0",
+ .codec_name = "tlv320aic32x4.0-0018",
+ .cpu_dai_name = "imx-ssi.0",
+ .ops = &mx27vis_aic32x4_snd_ops,
+};
+
+static struct snd_soc_card mx27vis_aic32x4 = {
+ .name = "visstrim_m10-audio",
+ .dai_link = &mx27vis_aic32x4_dai,
+ .num_links = 1,
+};
+
+static struct platform_device *mx27vis_aic32x4_snd_device;
+
+static int __init mx27vis_aic32x4_init(void)
+{
+ int ret;
+
+ mx27vis_aic32x4_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!mx27vis_aic32x4_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(mx27vis_aic32x4_snd_device, &mx27vis_aic32x4);
+ ret = platform_device_add(mx27vis_aic32x4_snd_device);
+
+ if (ret) {
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+ platform_device_put(mx27vis_aic32x4_snd_device);
+ }
+
+ /* Connect SSI0 as clock slave to SSI1 external pins */
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_TFSDIR |
+ MXC_AUDMUX_V1_PCR_TCLKDIR |
+ MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1)
+ );
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+ );
+
+ return ret;
+}
+
+static void __exit mx27vis_aic32x4_exit(void)
+{
+ platform_device_unregister(mx27vis_aic32x4_snd_device);
+}
+
+module_init(mx27vis_aic32x4_init);
+module_exit(mx27vis_aic32x4_exit);
+
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/mid-x86/Kconfig b/sound/soc/mid-x86/Kconfig
new file mode 100644
index 000000000000..29350428f1c2
--- /dev/null
+++ b/sound/soc/mid-x86/Kconfig
@@ -0,0 +1,14 @@
+config SND_MFLD_MACHINE
+ tristate "SOC Machine Audio driver for Intel Medfield MID platform"
+ depends on INTEL_SCU_IPC
+ depends on SND_INTEL_SST
+ select SND_SOC_SN95031
+ select SND_SST_PLATFORM
+ help
+ This adds support for ASoC machine driver for Intel(R) MID Medfield platform
+ used as alsa device in audio substem in Intel(R) MID devices
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SST_PLATFORM
+ tristate
diff --git a/sound/soc/mid-x86/Makefile b/sound/soc/mid-x86/Makefile
new file mode 100644
index 000000000000..639883339465
--- /dev/null
+++ b/sound/soc/mid-x86/Makefile
@@ -0,0 +1,5 @@
+snd-soc-sst-platform-objs := sst_platform.o
+snd-soc-mfld-machine-objs := mfld_machine.o
+
+obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o
+obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c
new file mode 100644
index 000000000000..429aa1be2cff
--- /dev/null
+++ b/sound/soc/mid-x86/mfld_machine.c
@@ -0,0 +1,452 @@
+/*
+ * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.com>
+ * Author: Harsha Priya <priya.harsha@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/sn95031.h"
+
+#define MID_MONO 1
+#define MID_STEREO 2
+#define MID_MAX_CAP 5
+#define MFLD_JACK_INSERT 0x04
+
+enum soc_mic_bias_zones {
+ MFLD_MV_START = 0,
+ /* mic bias volutage range for Headphones*/
+ MFLD_MV_HP = 400,
+ /* mic bias volutage range for American Headset*/
+ MFLD_MV_AM_HS = 650,
+ /* mic bias volutage range for Headset*/
+ MFLD_MV_HS = 2000,
+ MFLD_MV_UNDEFINED,
+};
+
+static unsigned int hs_switch;
+static unsigned int lo_dac;
+
+struct mfld_mc_private {
+ struct platform_device *socdev;
+ void __iomem *int_base;
+ struct snd_soc_codec *codec;
+ u8 interrupt_status;
+};
+
+struct snd_soc_jack mfld_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin mfld_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "AMIC1",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+/* jack detection voltage zones */
+static struct snd_soc_jack_zone mfld_zones[] = {
+ {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE},
+ {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET},
+};
+
+/* sound card controls */
+static const char *headset_switch_text[] = {"Earpiece", "Headset"};
+
+static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"};
+
+static const struct soc_enum headset_enum =
+ SOC_ENUM_SINGLE_EXT(2, headset_switch_text);
+
+static const struct soc_enum lo_enum =
+ SOC_ENUM_SINGLE_EXT(4, lo_text);
+
+static int headset_get_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = hs_switch;
+ return 0;
+}
+
+static int headset_set_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (ucontrol->value.integer.value[0] == hs_switch)
+ return 0;
+
+ if (ucontrol->value.integer.value[0]) {
+ pr_debug("hs_set HS path\n");
+ snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
+ snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+ } else {
+ pr_debug("hs_set EP path\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
+ snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+ }
+ snd_soc_dapm_sync(&codec->dapm);
+ hs_switch = ucontrol->value.integer.value[0];
+
+ return 0;
+}
+
+static void lo_enable_out_pins(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL");
+ snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR");
+ snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL");
+ snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR");
+ snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT");
+ snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT");
+ if (hs_switch) {
+ snd_soc_dapm_enable_pin(&codec->dapm, "Headphones");
+ snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+ } else {
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
+ snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT");
+ }
+}
+
+static int lo_get_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = lo_dac;
+ return 0;
+}
+
+static int lo_set_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (ucontrol->value.integer.value[0] == lo_dac)
+ return 0;
+
+ /* we dont want to work with last state of lineout so just enable all
+ * pins and then disable pins not required
+ */
+ lo_enable_out_pins(codec);
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ pr_debug("set vibra path\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT");
+ snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT");
+ snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0);
+ break;
+
+ case 1:
+ pr_debug("set hs path\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "Headphones");
+ snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT");
+ snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22);
+ break;
+
+ case 2:
+ pr_debug("set spkr path\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL");
+ snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR");
+ snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44);
+ break;
+
+ case 3:
+ pr_debug("set null path\n");
+ snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL");
+ snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR");
+ snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66);
+ break;
+ }
+ snd_soc_dapm_sync(&codec->dapm);
+ lo_dac = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static const struct snd_kcontrol_new mfld_snd_controls[] = {
+ SOC_ENUM_EXT("Playback Switch", headset_enum,
+ headset_get_switch, headset_set_switch),
+ SOC_ENUM_EXT("Lineout Mux", lo_enum,
+ lo_get_switch, lo_set_switch),
+};
+
+static const struct snd_soc_dapm_widget mfld_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route mfld_map[] = {
+ {"Headphones", NULL, "HPOUTR"},
+ {"Headphones", NULL, "HPOUTL"},
+ {"Mic", NULL, "AMIC1"},
+};
+
+static void mfld_jack_check(unsigned int intr_status)
+{
+ struct mfld_jack_data jack_data;
+
+ jack_data.mfld_jack = &mfld_jack;
+ jack_data.intr_id = intr_status;
+
+ sn95031_jack_detection(&jack_data);
+ /* TODO: add american headset detection post gpiolib support */
+}
+
+static int mfld_init(struct snd_soc_pcm_runtime *runtime)
+{
+ struct snd_soc_codec *codec = runtime->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret_val;
+
+ /* Add jack sense widgets */
+ snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
+
+ /* Set up the map */
+ snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
+
+ /* always connected */
+ snd_soc_dapm_enable_pin(dapm, "Headphones");
+ snd_soc_dapm_enable_pin(dapm, "Mic");
+ snd_soc_dapm_sync(dapm);
+
+ ret_val = snd_soc_add_controls(codec, mfld_snd_controls,
+ ARRAY_SIZE(mfld_snd_controls));
+ if (ret_val) {
+ pr_err("soc_add_controls failed %d", ret_val);
+ return ret_val;
+ }
+ /* default is earpiece pin, userspace sets it explcitly */
+ snd_soc_dapm_disable_pin(dapm, "Headphones");
+ /* default is lineout NC, userspace sets it explcitly */
+ snd_soc_dapm_disable_pin(dapm, "LINEOUTL");
+ snd_soc_dapm_disable_pin(dapm, "LINEOUTR");
+ lo_dac = 3;
+ hs_switch = 0;
+ /* we dont use linein in this so set to NC */
+ snd_soc_dapm_disable_pin(dapm, "LINEINL");
+ snd_soc_dapm_disable_pin(dapm, "LINEINR");
+ snd_soc_dapm_sync(dapm);
+
+ /* Headset and button jack detection */
+ ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1, &mfld_jack);
+ if (ret_val) {
+ pr_err("jack creation failed\n");
+ return ret_val;
+ }
+
+ ret_val = snd_soc_jack_add_pins(&mfld_jack,
+ ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins);
+ if (ret_val) {
+ pr_err("adding jack pins failed\n");
+ return ret_val;
+ }
+ ret_val = snd_soc_jack_add_zones(&mfld_jack,
+ ARRAY_SIZE(mfld_zones), mfld_zones);
+ if (ret_val) {
+ pr_err("adding jack zones failed\n");
+ return ret_val;
+ }
+
+ /* we want to check if anything is inserted at boot,
+ * so send a fake event to codec and it will read adc
+ * to find if anything is there or not */
+ mfld_jack_check(MFLD_JACK_INSERT);
+ return ret_val;
+}
+
+struct snd_soc_dai_link mfld_msic_dailink[] = {
+ {
+ .name = "Medfield Headset",
+ .stream_name = "Headset",
+ .cpu_dai_name = "Headset-cpu-dai",
+ .codec_dai_name = "SN95031 Headset",
+ .codec_name = "sn95031",
+ .platform_name = "sst-platform",
+ .init = mfld_init,
+ },
+ {
+ .name = "Medfield Speaker",
+ .stream_name = "Speaker",
+ .cpu_dai_name = "Speaker-cpu-dai",
+ .codec_dai_name = "SN95031 Speaker",
+ .codec_name = "sn95031",
+ .platform_name = "sst-platform",
+ .init = NULL,
+ },
+ {
+ .name = "Medfield Vibra",
+ .stream_name = "Vibra1",
+ .cpu_dai_name = "Vibra1-cpu-dai",
+ .codec_dai_name = "SN95031 Vibra1",
+ .codec_name = "sn95031",
+ .platform_name = "sst-platform",
+ .init = NULL,
+ },
+ {
+ .name = "Medfield Haptics",
+ .stream_name = "Vibra2",
+ .cpu_dai_name = "Vibra2-cpu-dai",
+ .codec_dai_name = "SN95031 Vibra2",
+ .codec_name = "sn95031",
+ .platform_name = "sst-platform",
+ .init = NULL,
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_mfld = {
+ .name = "medfield_audio",
+ .dai_link = mfld_msic_dailink,
+ .num_links = ARRAY_SIZE(mfld_msic_dailink),
+};
+
+static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
+{
+ struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev;
+
+ memcpy_fromio(&mc_private->interrupt_status,
+ ((void *)(mc_private->int_base)),
+ sizeof(u8));
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t snd_mfld_jack_detection(int irq, void *data)
+{
+ struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data;
+
+ if (mfld_jack.codec == NULL)
+ return IRQ_HANDLED;
+ mfld_jack_check(mc_drv_ctx->interrupt_status);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit snd_mfld_mc_probe(struct platform_device *pdev)
+{
+ int ret_val = 0, irq;
+ struct mfld_mc_private *mc_drv_ctx;
+ struct resource *irq_mem;
+
+ pr_debug("snd_mfld_mc_probe called\n");
+
+ /* retrive the irq number */
+ irq = platform_get_irq(pdev, 0);
+
+ /* audio interrupt base of SRAM location where
+ * interrupts are stored by System FW */
+ mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC);
+ if (!mc_drv_ctx) {
+ pr_err("allocation failed\n");
+ return -ENOMEM;
+ }
+
+ irq_mem = platform_get_resource_byname(
+ pdev, IORESOURCE_MEM, "IRQ_BASE");
+ if (!irq_mem) {
+ pr_err("no mem resource given\n");
+ ret_val = -ENODEV;
+ goto unalloc;
+ }
+ mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start,
+ resource_size(irq_mem));
+ if (!mc_drv_ctx->int_base) {
+ pr_err("Mapping of cache failed\n");
+ ret_val = -ENOMEM;
+ goto unalloc;
+ }
+ /* register for interrupt */
+ ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler,
+ snd_mfld_jack_detection,
+ IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx);
+ if (ret_val) {
+ pr_err("cannot register IRQ\n");
+ goto unalloc;
+ }
+ /* register the soc card */
+ snd_soc_card_mfld.dev = &pdev->dev;
+ ret_val = snd_soc_register_card(&snd_soc_card_mfld);
+ if (ret_val) {
+ pr_debug("snd_soc_register_card failed %d\n", ret_val);
+ goto freeirq;
+ }
+ platform_set_drvdata(pdev, mc_drv_ctx);
+ pr_debug("successfully exited probe\n");
+ return ret_val;
+
+freeirq:
+ free_irq(irq, mc_drv_ctx);
+unalloc:
+ kfree(mc_drv_ctx);
+ return ret_val;
+}
+
+static int __devexit snd_mfld_mc_remove(struct platform_device *pdev)
+{
+ struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev);
+
+ pr_debug("snd_mfld_mc_remove called\n");
+ free_irq(platform_get_irq(pdev, 0), mc_drv_ctx);
+ snd_soc_unregister_card(&snd_soc_card_mfld);
+ kfree(mc_drv_ctx);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver snd_mfld_mc_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "msic_audio",
+ },
+ .probe = snd_mfld_mc_probe,
+ .remove = __devexit_p(snd_mfld_mc_remove),
+};
+
+static int __init snd_mfld_driver_init(void)
+{
+ pr_debug("snd_mfld_driver_init called\n");
+ return platform_driver_register(&snd_mfld_mc_driver);
+}
+module_init(snd_mfld_driver_init);
+
+static void __exit snd_mfld_driver_exit(void)
+{
+ pr_debug("snd_mfld_driver_exit called\n");
+ platform_driver_unregister(&snd_mfld_mc_driver);
+}
+module_exit(snd_mfld_driver_exit);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:msic-audio");
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c
new file mode 100644
index 000000000000..ee2c22475a76
--- /dev/null
+++ b/sound/soc/mid-x86/sst_platform.c
@@ -0,0 +1,474 @@
+/*
+ * sst_platform.c - Intel MID Platform driver
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.com>
+ * Author: Harsha Priya <priya.harsha@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h"
+#include "../../../drivers/staging/intel_sst/intel_sst.h"
+#include "sst_platform.h"
+
+static struct snd_pcm_hardware sst_platform_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_DOUBLE |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_MMAP|
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
+ SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
+ SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
+ .rates = (SNDRV_PCM_RATE_8000|
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000),
+ .rate_min = SST_MIN_RATE,
+ .rate_max = SST_MAX_RATE,
+ .channels_min = SST_MIN_CHANNEL,
+ .channels_max = SST_MAX_CHANNEL,
+ .buffer_bytes_max = SST_MAX_BUFFER,
+ .period_bytes_min = SST_MIN_PERIOD_BYTES,
+ .period_bytes_max = SST_MAX_PERIOD_BYTES,
+ .periods_min = SST_MIN_PERIODS,
+ .periods_max = SST_MAX_PERIODS,
+ .fifo_size = SST_FIFO_SIZE,
+};
+
+/* MFLD - MSIC */
+struct snd_soc_dai_driver sst_platform_dai[] = {
+{
+ .name = "Headset-cpu-dai",
+ .id = 0,
+ .playback = {
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 5,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "Speaker-cpu-dai",
+ .id = 1,
+ .playback = {
+ .channels_min = SST_MONO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "Vibra1-cpu-dai",
+ .id = 2,
+ .playback = {
+ .channels_min = SST_MONO,
+ .channels_max = SST_MONO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+{
+ .name = "Vibra2-cpu-dai",
+ .id = 3,
+ .playback = {
+ .channels_min = SST_MONO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ },
+},
+};
+
+/* helper functions */
+static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
+ int state)
+{
+ spin_lock(&stream->status_lock);
+ stream->stream_status = state;
+ spin_unlock(&stream->status_lock);
+}
+
+static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
+{
+ int state;
+
+ spin_lock(&stream->status_lock);
+ state = stream->stream_status;
+ spin_unlock(&stream->status_lock);
+ return state;
+}
+
+static void sst_fill_pcm_params(struct snd_pcm_substream *substream,
+ struct snd_sst_stream_params *param)
+{
+
+ param->uc.pcm_params.codec = SST_CODEC_TYPE_PCM;
+ param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
+ param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
+ param->uc.pcm_params.reserved = 0;
+ param->uc.pcm_params.sfreq = substream->runtime->rate;
+ param->uc.pcm_params.ring_buffer_size =
+ snd_pcm_lib_buffer_bytes(substream);
+ param->uc.pcm_params.period_count = substream->runtime->period_size;
+ param->uc.pcm_params.ring_buffer_addr =
+ virt_to_phys(substream->dma_buffer.area);
+ pr_debug("period_cnt = %d\n", param->uc.pcm_params.period_count);
+ pr_debug("sfreq= %d, wd_sz = %d\n",
+ param->uc.pcm_params.sfreq, param->uc.pcm_params.pcm_wd_sz);
+}
+
+static int sst_platform_alloc_stream(struct snd_pcm_substream *substream)
+{
+ struct sst_runtime_stream *stream =
+ substream->runtime->private_data;
+ struct snd_sst_stream_params param = {{{0,},},};
+ struct snd_sst_params str_params = {0};
+ int ret_val;
+
+ /* set codec params and inform SST driver the same */
+ sst_fill_pcm_params(substream, &param);
+ substream->runtime->dma_area = substream->dma_buffer.area;
+ str_params.sparams = param;
+ str_params.codec = param.uc.pcm_params.codec;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ str_params.ops = STREAM_OPS_PLAYBACK;
+ str_params.device_type = substream->pcm->device + 1;
+ pr_debug("Playbck stream,Device %d\n",
+ substream->pcm->device);
+ } else {
+ str_params.ops = STREAM_OPS_CAPTURE;
+ str_params.device_type = SND_SST_DEVICE_CAPTURE;
+ pr_debug("Capture stream,Device %d\n",
+ substream->pcm->device);
+ }
+ ret_val = stream->sstdrv_ops->pcm_control->open(&str_params);
+ pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val);
+ if (ret_val < 0)
+ return ret_val;
+
+ stream->stream_info.str_id = ret_val;
+ pr_debug("str id : %d\n", stream->stream_info.str_id);
+ return ret_val;
+}
+
+static void sst_period_elapsed(void *mad_substream)
+{
+ struct snd_pcm_substream *substream = mad_substream;
+ struct sst_runtime_stream *stream;
+ int status;
+
+ if (!substream || !substream->runtime)
+ return;
+ stream = substream->runtime->private_data;
+ if (!stream)
+ return;
+ status = sst_get_stream_status(stream);
+ if (status != SST_PLATFORM_RUNNING)
+ return;
+ snd_pcm_period_elapsed(substream);
+}
+
+static int sst_platform_init_stream(struct snd_pcm_substream *substream)
+{
+ struct sst_runtime_stream *stream =
+ substream->runtime->private_data;
+ int ret_val;
+
+ pr_debug("setting buffer ptr param\n");
+ sst_set_stream_status(stream, SST_PLATFORM_INIT);
+ stream->stream_info.period_elapsed = sst_period_elapsed;
+ stream->stream_info.mad_substream = substream;
+ stream->stream_info.buffer_ptr = 0;
+ stream->stream_info.sfreq = substream->runtime->rate;
+ ret_val = stream->sstdrv_ops->pcm_control->device_control(
+ SST_SND_STREAM_INIT, &stream->stream_info);
+ if (ret_val)
+ pr_err("control_set ret error %d\n", ret_val);
+ return ret_val;
+
+}
+/* end -- helper functions */
+
+static int sst_platform_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct sst_runtime_stream *stream;
+ int ret_val = 0;
+
+ pr_debug("sst_platform_open called\n");
+ runtime = substream->runtime;
+ runtime->hw = sst_platform_pcm_hw;
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+ if (!stream)
+ return -ENOMEM;
+ spin_lock_init(&stream->status_lock);
+ stream->stream_info.str_id = 0;
+ sst_set_stream_status(stream, SST_PLATFORM_INIT);
+ stream->stream_info.mad_substream = substream;
+ /* allocate memory for SST API set */
+ stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops),
+ GFP_KERNEL);
+ if (!stream->sstdrv_ops) {
+ pr_err("sst: mem allocation for ops fail\n");
+ kfree(stream);
+ return -ENOMEM;
+ }
+ stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
+ /* registering with SST driver to get access to SST APIs to use */
+ ret_val = register_sst_card(stream->sstdrv_ops);
+ if (ret_val) {
+ pr_err("sst: sst card registration failed\n");
+ return ret_val;
+ }
+ runtime->private_data = stream;
+ return snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+}
+
+static int sst_platform_close(struct snd_pcm_substream *substream)
+{
+ struct sst_runtime_stream *stream;
+ int ret_val = 0, str_id;
+
+ pr_debug("sst_platform_close called\n");
+ stream = substream->runtime->private_data;
+ str_id = stream->stream_info.str_id;
+ if (str_id)
+ ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
+ kfree(stream->sstdrv_ops);
+ kfree(stream);
+ return ret_val;
+}
+
+static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct sst_runtime_stream *stream;
+ int ret_val = 0, str_id;
+
+ pr_debug("sst_platform_pcm_prepare called\n");
+ stream = substream->runtime->private_data;
+ str_id = stream->stream_info.str_id;
+ if (stream->stream_info.str_id) {
+ ret_val = stream->sstdrv_ops->pcm_control->device_control(
+ SST_SND_DROP, &str_id);
+ return ret_val;
+ }
+
+ ret_val = sst_platform_alloc_stream(substream);
+ if (ret_val < 0)
+ return ret_val;
+ snprintf(substream->pcm->id, sizeof(substream->pcm->id),
+ "%d", stream->stream_info.str_id);
+
+ ret_val = sst_platform_init_stream(substream);
+ if (ret_val)
+ return ret_val;
+ substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+ return ret_val;
+}
+
+static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ int ret_val = 0, str_id;
+ struct sst_runtime_stream *stream;
+ int str_cmd, status;
+
+ pr_debug("sst_platform_pcm_trigger called\n");
+ stream = substream->runtime->private_data;
+ str_id = stream->stream_info.str_id;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pr_debug("sst: Trigger Start\n");
+ str_cmd = SST_SND_START;
+ status = SST_PLATFORM_RUNNING;
+ stream->stream_info.mad_substream = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("sst: in stop\n");
+ str_cmd = SST_SND_DROP;
+ status = SST_PLATFORM_DROPPED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("sst: in pause\n");
+ str_cmd = SST_SND_PAUSE;
+ status = SST_PLATFORM_PAUSED;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("sst: in pause release\n");
+ str_cmd = SST_SND_RESUME;
+ status = SST_PLATFORM_RUNNING;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret_val = stream->sstdrv_ops->pcm_control->device_control(str_cmd,
+ &str_id);
+ if (!ret_val)
+ sst_set_stream_status(stream, status);
+
+ return ret_val;
+}
+
+
+static snd_pcm_uframes_t sst_platform_pcm_pointer
+ (struct snd_pcm_substream *substream)
+{
+ struct sst_runtime_stream *stream;
+ int ret_val, status;
+ struct pcm_stream_info *str_info;
+
+ stream = substream->runtime->private_data;
+ status = sst_get_stream_status(stream);
+ if (status == SST_PLATFORM_INIT)
+ return 0;
+ str_info = &stream->stream_info;
+ ret_val = stream->sstdrv_ops->pcm_control->device_control(
+ SST_SND_BUFFER_POINTER, str_info);
+ if (ret_val) {
+ pr_err("sst: error code = %d\n", ret_val);
+ return ret_val;
+ }
+ return stream->stream_info.buffer_ptr;
+}
+
+static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ memset(substream->runtime->dma_area, 0, params_buffer_bytes(params));
+
+ return 0;
+}
+
+static struct snd_pcm_ops sst_platform_ops = {
+ .open = sst_platform_open,
+ .close = sst_platform_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .prepare = sst_platform_pcm_prepare,
+ .trigger = sst_platform_pcm_trigger,
+ .pointer = sst_platform_pcm_pointer,
+ .hw_params = sst_platform_pcm_hw_params,
+};
+
+static void sst_pcm_free(struct snd_pcm *pcm)
+{
+ pr_debug("sst_pcm_free called\n");
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int retval = 0;
+
+ pr_debug("sst_pcm_new called\n");
+ if (dai->driver->playback.channels_min ||
+ dai->driver->capture.channels_min) {
+ retval = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ SST_MIN_BUFFER, SST_MAX_BUFFER);
+ if (retval) {
+ pr_err("dma buffer allocationf fail\n");
+ return retval;
+ }
+ }
+ return retval;
+}
+struct snd_soc_platform_driver sst_soc_platform_drv = {
+ .ops = &sst_platform_ops,
+ .pcm_new = sst_pcm_new,
+ .pcm_free = sst_pcm_free,
+};
+
+static int sst_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pr_debug("sst_platform_probe called\n");
+ ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
+ if (ret) {
+ pr_err("registering soc platform failed\n");
+ return ret;
+ }
+
+ ret = snd_soc_register_dais(&pdev->dev,
+ sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
+ if (ret) {
+ pr_err("registering cpu dais failed\n");
+ snd_soc_unregister_platform(&pdev->dev);
+ }
+ return ret;
+}
+
+static int sst_platform_remove(struct platform_device *pdev)
+{
+
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
+ snd_soc_unregister_platform(&pdev->dev);
+ pr_debug("sst_platform_remove sucess\n");
+ return 0;
+}
+
+static struct platform_driver sst_platform_driver = {
+ .driver = {
+ .name = "sst-platform",
+ .owner = THIS_MODULE,
+ },
+ .probe = sst_platform_probe,
+ .remove = sst_platform_remove,
+};
+
+static int __init sst_soc_platform_init(void)
+{
+ pr_debug("sst_soc_platform_init called\n");
+ return platform_driver_register(&sst_platform_driver);
+}
+module_init(sst_soc_platform_init);
+
+static void __exit sst_soc_platform_exit(void)
+{
+ platform_driver_unregister(&sst_platform_driver);
+ pr_debug("sst_soc_platform_exit sucess\n");
+}
+module_exit(sst_soc_platform_exit);
+
+MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sst-platform");
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h
new file mode 100644
index 000000000000..df370286694f
--- /dev/null
+++ b/sound/soc/mid-x86/sst_platform.h
@@ -0,0 +1,63 @@
+/*
+ * sst_platform.h - Intel MID Platform driver header file
+ *
+ * Copyright (C) 2010 Intel Corp
+ * Author: Vinod Koul <vinod.koul@intel.com>
+ * Author: Harsha Priya <priya.harsha@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *
+ */
+
+#ifndef __SST_PLATFORMDRV_H__
+#define __SST_PLATFORMDRV_H__
+
+#define SST_MONO 1
+#define SST_STEREO 2
+#define SST_MAX_CAP 5
+
+#define SST_MIN_RATE 8000
+#define SST_MAX_RATE 48000
+#define SST_MIN_CHANNEL 1
+#define SST_MAX_CHANNEL 5
+#define SST_MAX_BUFFER (800*1024)
+#define SST_MIN_BUFFER (800*1024)
+#define SST_MIN_PERIOD_BYTES 32
+#define SST_MAX_PERIOD_BYTES SST_MAX_BUFFER
+#define SST_MIN_PERIODS 2
+#define SST_MAX_PERIODS (1024*2)
+#define SST_FIFO_SIZE 0
+#define SST_CARD_NAMES "intel_mid_card"
+#define MSIC_VENDOR_ID 3
+
+struct sst_runtime_stream {
+ int stream_status;
+ struct pcm_stream_info stream_info;
+ struct intel_sst_card_ops *sstdrv_ops;
+ spinlock_t status_lock;
+};
+
+enum sst_drv_status {
+ SST_PLATFORM_INIT = 1,
+ SST_PLATFORM_STARTED,
+ SST_PLATFORM_RUNNING,
+ SST_PLATFORM_PAUSED,
+ SST_PLATFORM_DROPPED,
+};
+
+#endif
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index a088db6d5091..b5922984eac6 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -24,6 +24,7 @@ config SND_OMAP_SOC_RX51
select OMAP_MCBSP
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
+ select SND_SOC_TPA6130A2
help
Say Y if you want to add support for SoC audio on Nokia RX-51
hardware. This is also known as Nokia N900 product.
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index d203f4da18a0..2175f09e57b6 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -69,110 +69,6 @@ static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
*/
static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
-static const int omap1_dma_reqs[][2] = {
- { OMAP_DMA_MCBSP1_TX, OMAP_DMA_MCBSP1_RX },
- { OMAP_DMA_MCBSP2_TX, OMAP_DMA_MCBSP2_RX },
- { OMAP_DMA_MCBSP3_TX, OMAP_DMA_MCBSP3_RX },
-};
-static const unsigned long omap1_mcbsp_port[][2] = {
- { OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
- OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
- { OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
- OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
- { OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DXR1,
- OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DRR1 },
-};
-#else
-static const int omap1_dma_reqs[][2] = {};
-static const unsigned long omap1_mcbsp_port[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-static const int omap24xx_dma_reqs[][2] = {
- { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
- { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
- { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
- { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
- { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
-#endif
-};
-#else
-static const int omap24xx_dma_reqs[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4)
-static const int omap44xx_dma_reqs[][2] = {
- { OMAP44XX_DMA_MCBSP1_TX, OMAP44XX_DMA_MCBSP1_RX },
- { OMAP44XX_DMA_MCBSP2_TX, OMAP44XX_DMA_MCBSP2_RX },
- { OMAP44XX_DMA_MCBSP3_TX, OMAP44XX_DMA_MCBSP3_RX },
- { OMAP44XX_DMA_MCBSP4_TX, OMAP44XX_DMA_MCBSP4_RX },
-};
-#else
-static const int omap44xx_dma_reqs[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2420)
-static const unsigned long omap2420_mcbsp_port[][2] = {
- { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
- OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
- { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
- OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
-};
-#else
-static const unsigned long omap2420_mcbsp_port[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2430)
-static const unsigned long omap2430_mcbsp_port[][2] = {
- { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
- OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
- OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
- OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
- OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
- OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
-};
-#else
-static const unsigned long omap2430_mcbsp_port[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3)
-static const unsigned long omap34xx_mcbsp_port[][2] = {
- { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
- OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
- OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
- OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
- OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
- OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
-};
-#else
-static const unsigned long omap34xx_mcbsp_port[][2] = {};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4)
-static const unsigned long omap44xx_mcbsp_port[][2] = {
- { OMAP44XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
- OMAP44XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP44XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
- OMAP44XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP44XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
- OMAP44XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
- { OMAP44XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
- OMAP44XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
-};
-#else
-static const unsigned long omap44xx_mcbsp_port[][2] = {};
-#endif
-
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -346,24 +242,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
unsigned int format, div, framesize, master;
dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
- if (cpu_class_is_omap1()) {
- dma = omap1_dma_reqs[bus_id][substream->stream];
- port = omap1_mcbsp_port[bus_id][substream->stream];
- } else if (cpu_is_omap2420()) {
- dma = omap24xx_dma_reqs[bus_id][substream->stream];
- port = omap2420_mcbsp_port[bus_id][substream->stream];
- } else if (cpu_is_omap2430()) {
- dma = omap24xx_dma_reqs[bus_id][substream->stream];
- port = omap2430_mcbsp_port[bus_id][substream->stream];
- } else if (cpu_is_omap343x()) {
- dma = omap24xx_dma_reqs[bus_id][substream->stream];
- port = omap34xx_mcbsp_port[bus_id][substream->stream];
- } else if (cpu_is_omap44xx()) {
- dma = omap44xx_dma_reqs[bus_id][substream->stream];
- port = omap44xx_mcbsp_port[bus_id][substream->stream];
- } else {
- return -ENODEV;
- }
+
+ dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
+ port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);
+
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
index 110c106611d3..37dc7211ed3f 100644
--- a/sound/soc/omap/omap-mcbsp.h
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -43,7 +43,7 @@ enum omap_mcbsp_div {
OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
};
-#if defined(CONFIG_ARCH_OMAP2420)
+#if defined(CONFIG_SOC_OMAP2420)
#define NUM_LINKS 2
#endif
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
@@ -54,7 +54,7 @@ enum omap_mcbsp_div {
#undef NUM_LINKS
#define NUM_LINKS 4
#endif
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_OMAP2430)
#undef NUM_LINKS
#define NUM_LINKS 5
#endif
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 09fb0df8d416..d0986220eff9 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -31,6 +31,7 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <plat/mcbsp.h>
+#include "../codecs/tpa6130a2.h"
#include <asm/mach-types.h>
@@ -39,6 +40,7 @@
#define RX51_TVOUT_SEL_GPIO 40
#define RX51_JACK_DETECT_GPIO 177
+#define RX51_ECI_SW_GPIO 182
/*
* REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
* gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -47,7 +49,9 @@
enum {
RX51_JACK_DISABLED,
- RX51_JACK_TVOUT, /* tv-out */
+ RX51_JACK_TVOUT, /* tv-out with stereo output */
+ RX51_JACK_HP, /* headphone: stereo output, no mic */
+ RX51_JACK_HS, /* headset: stereo output with mic */
};
static int rx51_spk_func;
@@ -57,6 +61,19 @@ static int rx51_jack_func;
static void rx51_ext_control(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int hp = 0, hs = 0, tvout = 0;
+
+ switch (rx51_jack_func) {
+ case RX51_JACK_TVOUT:
+ tvout = 1;
+ hp = 1;
+ break;
+ case RX51_JACK_HS:
+ hs = 1;
+ case RX51_JACK_HP:
+ hp = 1;
+ break;
+ }
if (rx51_spk_func)
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
@@ -66,9 +83,16 @@ static void rx51_ext_control(struct snd_soc_codec *codec)
snd_soc_dapm_enable_pin(dapm, "DMic");
else
snd_soc_dapm_disable_pin(dapm, "DMic");
+ if (hp)
+ snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+ if (hs)
+ snd_soc_dapm_enable_pin(dapm, "HS Mic");
+ else
+ snd_soc_dapm_disable_pin(dapm, "HS Mic");
- gpio_set_value(RX51_TVOUT_SEL_GPIO,
- rx51_jack_func == RX51_JACK_TVOUT);
+ gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout);
snd_soc_dapm_sync(dapm);
}
@@ -153,6 +177,19 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rx51_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->dapm->codec;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ tpa6130a2_stereo_enable(codec, 1);
+ else
+ tpa6130a2_stereo_enable(codec, 0);
+
+ return 0;
+}
+
static int rx51_get_input(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -203,7 +240,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
{
.gpio = RX51_JACK_DETECT_GPIO,
.name = "avdet-gpio",
- .report = SND_JACK_VIDEOOUT,
+ .report = SND_JACK_HEADSET,
.invert = 1,
.debounce_time = 200,
},
@@ -212,19 +249,38 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
SND_SOC_DAPM_MIC("DMic", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event),
+ SND_SOC_DAPM_MIC("HS Mic", NULL),
+ SND_SOC_DAPM_LINE("FM Transmitter", NULL),
+};
+
+static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = {
+ SND_SOC_DAPM_SPK("Earphone", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
{"Ext Spk", NULL, "HPLOUT"},
{"Ext Spk", NULL, "HPROUT"},
+ {"Headphone Jack", NULL, "LLOUT"},
+ {"Headphone Jack", NULL, "RLOUT"},
+ {"FM Transmitter", NULL, "LLOUT"},
+ {"FM Transmitter", NULL, "RLOUT"},
{"DMic Rate 64", NULL, "Mic Bias 2V"},
{"Mic Bias 2V", NULL, "DMic"},
};
+static const struct snd_soc_dapm_route audio_mapb[] = {
+ {"b LINE2R", NULL, "MONO_LOUT"},
+ {"Earphone", NULL, "b HPLOUT"},
+
+ {"LINE1L", NULL, "b Mic Bias 2.5V"},
+ {"b Mic Bias 2.5V", NULL, "HS Mic"}
+};
+
static const char *spk_function[] = {"Off", "On"};
static const char *input_function[] = {"ADC", "Digital Mic"};
-static const char *jack_function[] = {"Off", "TV-OUT"};
+static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"};
static const struct soc_enum rx51_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
@@ -239,6 +295,11 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
rx51_get_input, rx51_set_input),
SOC_ENUM_EXT("Jack Function", rx51_enum[2],
rx51_get_jack, rx51_set_jack),
+ SOC_DAPM_PIN_SWITCH("FM Transmitter"),
+};
+
+static const struct snd_kcontrol_new aic34_rx51_controlsb[] = {
+ SOC_DAPM_PIN_SWITCH("Earphone"),
};
static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
@@ -265,11 +326,21 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
/* Set up RX-51 specific audio path audio_map */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ err = tpa6130a2_add_controls(codec);
+ if (err < 0)
+ return err;
+ snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42);
+
+ err = omap_mcbsp_st_add_controls(codec, 1);
+ if (err < 0)
+ return err;
+
snd_soc_dapm_sync(dapm);
/* AV jack detection */
err = snd_soc_jack_new(codec, "AV Jack",
- SND_JACK_VIDEOOUT, &rx51_av_jack);
+ SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
+ &rx51_av_jack);
if (err)
return err;
err = snd_soc_jack_add_gpios(&rx51_av_jack,
@@ -279,6 +350,24 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
return err;
}
+static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm)
+{
+ int err;
+
+ err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb,
+ ARRAY_SIZE(aic34_rx51_controlsb));
+ if (err < 0)
+ return err;
+
+ err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb,
+ ARRAY_SIZE(aic34_dapm_widgetsb));
+ if (err < 0)
+ return 0;
+
+ return snd_soc_dapm_add_routes(dapm, audio_mapb,
+ ARRAY_SIZE(audio_mapb));
+}
+
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link rx51_dai[] = {
{
@@ -293,11 +382,30 @@ static struct snd_soc_dai_link rx51_dai[] = {
},
};
+struct snd_soc_aux_dev rx51_aux_dev[] = {
+ {
+ .name = "TLV320AIC34b",
+ .codec_name = "tlv320aic3x-codec.2-0019",
+ .init = rx51_aic34b_init,
+ },
+};
+
+static struct snd_soc_codec_conf rx51_codec_conf[] = {
+ {
+ .dev_name = "tlv320aic3x-codec.2-0019",
+ .name_prefix = "b",
+ },
+};
+
/* Audio card */
static struct snd_soc_card rx51_sound_card = {
.name = "RX-51",
.dai_link = rx51_dai,
.num_links = ARRAY_SIZE(rx51_dai),
+ .aux_dev = rx51_aux_dev,
+ .num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
+ .codec_conf = rx51_codec_conf,
+ .num_configs = ARRAY_SIZE(rx51_codec_conf),
};
static struct platform_device *rx51_snd_device;
@@ -309,10 +417,14 @@ static int __init rx51_soc_init(void)
if (!machine_is_nokia_rx51())
return -ENODEV;
- err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
+ err = gpio_request_one(RX51_TVOUT_SEL_GPIO,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel");
if (err)
goto err_gpio_tvout_sel;
- gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
+ err = gpio_request_one(RX51_ECI_SW_GPIO,
+ GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw");
+ if (err)
+ goto err_gpio_eci_sw;
rx51_snd_device = platform_device_alloc("soc-audio", -1);
if (!rx51_snd_device) {
@@ -330,6 +442,8 @@ static int __init rx51_soc_init(void)
err2:
platform_device_put(rx51_snd_device);
err1:
+ gpio_free(RX51_ECI_SW_GPIO);
+err_gpio_eci_sw:
gpio_free(RX51_TVOUT_SEL_GPIO);
err_gpio_tvout_sel:
@@ -342,6 +456,7 @@ static void __exit rx51_soc_exit(void)
rx51_av_jack_gpios);
platform_device_unregister(rx51_snd_device);
+ gpio_free(RX51_ECI_SW_GPIO);
gpio_free(RX51_TVOUT_SEL_GPIO);
}
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index 0fd60f423036..2afabaf59491 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = {
.hw_params = raumfeld_cs4270_hw_params,
};
-static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state)
+static int raumfeld_line_suspend(struct snd_soc_card *card)
{
raumfeld_enable_audio(false);
return 0;
}
-static int raumfeld_line_resume(struct platform_device *pdev)
+static int raumfeld_line_resume(struct snd_soc_card *card)
{
raumfeld_enable_audio(true);
return 0;
@@ -229,19 +229,19 @@ static struct snd_soc_dai_link raumfeld_dai[] = {
{
.name = "ak4104",
.stream_name = "Playback",
- .cpu_dai_name = "pxa-ssp-dai.1",
- .codec_dai_name = "ak4104-hifi",
- .platform_name = "pxa-pcm-audio",
+ .cpu_dai_name = "pxa-ssp-dai.1",
+ .codec_dai_name = "ak4104-hifi",
+ .platform_name = "pxa-pcm-audio",
.ops = &raumfeld_ak4104_ops,
- .codec_name = "ak4104-codec.0",
+ .codec_name = "ak4104-codec.0",
},
{
.name = "CS4270",
.stream_name = "CS4270",
- .cpu_dai_name = "pxa-ssp-dai.0",
- .platform_name = "pxa-pcm-audio",
- .codec_dai_name = "cs4270-hifi",
- .codec_name = "cs4270-codec.0-0048",
+ .cpu_dai_name = "pxa-ssp-dai.0",
+ .platform_name = "pxa-pcm-audio",
+ .codec_dai_name = "cs4270-hifi",
+ .codec_name = "cs4270-codec.0-0048",
.ops = &raumfeld_cs4270_ops,
},};
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index 4b6e5d608b42..9a2351366957 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -237,7 +237,7 @@ static struct snd_soc_dai_link tosa_dai[] = {
},
};
-static int tosa_probe(struct platform_device *dev)
+static int tosa_probe(struct snd_soc_card *card)
{
int ret;
@@ -251,7 +251,7 @@ static int tosa_probe(struct platform_device *dev)
return ret;
}
-static int tosa_remove(struct platform_device *dev)
+static int tosa_remove(struct snd_soc_card *card)
{
gpio_free(TOSA_GPIO_L_MUTE);
return 0;
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index 3ceaef68e01d..d69d9fc32233 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -95,6 +95,11 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
.pin = "Headphone Jack",
.mask = SND_JACK_HEADPHONE,
},
+ {
+ .pin = "Ext Spk",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1
+ },
};
/* Headset jack detection gpios */
@@ -147,7 +152,7 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_disable_pin(dapm, "LINPUT3");
snd_soc_dapm_disable_pin(dapm, "RINPUT3");
snd_soc_dapm_disable_pin(dapm, "OUT3");
- snd_soc_dapm_disable_pin(dapm, "MONO");
+ snd_soc_dapm_disable_pin(dapm, "MONO1");
/* Add z2 specific widgets */
snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index 25bba108fea3..ac577263b3e3 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -189,7 +189,7 @@ static struct snd_soc_dai_link zylonite_dai[] = {
},
};
-static int zylonite_probe(struct platform_device *pdev)
+static int zylonite_probe(struct snd_soc_card *card)
{
int ret;
@@ -216,7 +216,7 @@ static int zylonite_probe(struct platform_device *pdev)
return 0;
}
-static int zylonite_remove(struct platform_device *pdev)
+static int zylonite_remove(struct snd_soc_card *card)
{
if (clk_pout) {
clk_disable(pout);
@@ -226,8 +226,7 @@ static int zylonite_remove(struct platform_device *pdev)
return 0;
}
-static int zylonite_suspend_post(struct platform_device *pdev,
- pm_message_t state)
+static int zylonite_suspend_post(struct snd_soc_card *card)
{
if (clk_pout)
clk_disable(pout);
@@ -235,7 +234,7 @@ static int zylonite_suspend_post(struct platform_device *pdev,
return 0;
}
-static int zylonite_resume_pre(struct platform_device *pdev)
+static int zylonite_resume_pre(struct snd_soc_card *card)
{
int ret = 0;
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index a6a6b5fa2f2f..a3fdfb631469 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
- depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PV310
+ depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_EXYNOS4
select S3C64XX_DMA if ARCH_S3C64XX
select S3C2410_DMA if ARCH_S3C2410
help
@@ -35,23 +35,16 @@ config SND_SAMSUNG_I2S
tristate
config SND_SOC_SAMSUNG_NEO1973_WM8753
- tristate "SoC I2S Audio support for NEO1973 - WM8753"
- depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01
+ tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
+ depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
select SND_S3C24XX_I2S
select SND_SOC_WM8753
+ select SND_SOC_LM4857 if MACH_NEO1973_GTA01
+ select SND_SOC_DFBMCS320
help
- Say Y if you want to add support for SoC audio on smdk2440
- with the WM8753.
+ Say Y here to enable audio support for the Openmoko Neo1973
+ Smartphones.
-config SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753
- tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
- depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
- select SND_S3C24XX_I2S
- select SND_SOC_WM8753
- help
- This driver provides audio support for the Openmoko Neo FreeRunner
- smartphone.
-
config SND_SOC_SAMSUNG_JIVE_WM8750
tristate "SoC I2S Audio support for Jive"
depends on SND_SOC_SAMSUNG && MACH_JIVE
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 705d4e8a6724..294dec05c26d 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
-snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
@@ -38,7 +37,6 @@ snd-soc-smdk-spdif-objs := smdk_spdif.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
-obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 4770a9550341..f97110e72e85 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -12,24 +12,24 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
-#include <linux/module.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <sound/soc.h>
-#include <plat/regs-ac97.h>
#include <mach/dma.h>
+#include <plat/regs-ac97.h>
#include <plat/audio.h>
#include "dma.h"
-#include "ac97.h"
#define AC_CMD_ADDR(x) (x << 16)
#define AC_CMD_DATA(x) (x & 0xffff)
+#define S3C_AC97_DAI_PCM 0
+#define S3C_AC97_DAI_MIC 1
+
struct s3c_ac97_info {
struct clk *ac97_clk;
void __iomem *regs;
diff --git a/sound/soc/samsung/ac97.h b/sound/soc/samsung/ac97.h
deleted file mode 100644
index 0d0e1b511457..000000000000
--- a/sound/soc/samsung/ac97.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* sound/soc/samsung/ac97.h
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- * Evolved from s3c2443-ac97.h
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar@samsung.com>
- * Credits: Graeme Gregory, Sean Choi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S3C_AC97_H_
-#define __S3C_AC97_H_
-
-#define S3C_AC97_DAI_PCM 0
-#define S3C_AC97_DAI_MIC 1
-
-#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 21240198c5d6..5cb3b880f0d5 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -14,17 +14,11 @@
* option) any later version.
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <mach/hardware.h>
@@ -32,6 +26,9 @@
#include "dma.h"
+#define ST_RUNNING (1<<0)
+#define ST_OPENED (1<<1)
+
static const struct snd_pcm_hardware dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -313,7 +310,7 @@ dma_pointer(struct snd_pcm_substream *substream)
/* we seem to be getting the odd error from the pcm library due
* to out-of-bounds pointers. this is maybe due to the dma engine
* not having loaded the new values for the channel before being
- * callled... (todo - fix )
+ * called... (todo - fix )
*/
if (res >= snd_pcm_lib_buffer_bytes(substream)) {
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index f8cd2b4223af..c50659269a40 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -12,9 +12,6 @@
#ifndef _S3C_AUDIO_H
#define _S3C_AUDIO_H
-#define ST_RUNNING (1<<0)
-#define ST_OPENED (1<<1)
-
struct s3c_dma_params {
struct s3c2410_dma_client *client; /* stream identifier */
int channel; /* Channel ID */
@@ -22,9 +19,4 @@ struct s3c_dma_params {
int dma_size; /* Size of the DMA transfer */
};
-#define S3C24XX_DAI_I2S 0
-
-/* platform data */
-extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
-
#endif
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
index 34dd9ef1b9c0..f6b3a3ce5919 100644
--- a/sound/soc/samsung/goni_wm8994.c
+++ b/sound/soc/samsung/goni_wm8994.c
@@ -11,21 +11,13 @@
*
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
#include <sound/soc.h>
#include <sound/jack.h>
+
#include <asm/mach-types.h>
#include <mach/gpio.h>
-#include <mach/regs-clock.h>
-#include <linux/mfd/wm8994/core.h>
-#include <linux/mfd/wm8994/registers.h>
#include "../codecs/wm8994.h"
-#include "dma.h"
-#include "i2s.h"
#define MACHINE_NAME 0
#define CPU_VOICE_DAI 1
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index c45f7ce14d61..241f55d00660 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -13,25 +13,16 @@
*
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
#include <linux/gpio.h>
#include <sound/soc.h>
-#include <sound/uda1380.h>
#include <sound/jack.h>
#include <plat/regs-iis.h>
-
#include <mach/h1940-latch.h>
-
#include <asm/mach-types.h>
-#include "dma.h"
#include "s3c24xx-i2s.h"
-#include "../codecs/uda1380.h"
static unsigned int rates[] = {
11025,
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index d00ac3a7102c..ffa09b3b2caa 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -15,9 +15,8 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <plat/audio.h>
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
index 08802520e014..3b53ad54bc33 100644
--- a/sound/soc/samsung/jive_wm8750.c
+++ b/sound/soc/samsung/jive_wm8750.c
@@ -11,22 +11,11 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include "dma.h"
#include "s3c2412-i2s.h"
-
#include "../codecs/wm8750.h"
static const struct snd_soc_dapm_route audio_map[] = {
diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h
deleted file mode 100644
index 0cf5b7011d6f..000000000000
--- a/sound/soc/samsung/lm4857.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * lm4857.h -- ALSA Soc Audio Layer
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Revision history
- * 18th Jun 2007 Initial version.
- */
-
-#ifndef LM4857_H_
-#define LM4857_H_
-
-/* The register offsets in the cache array */
-#define LM4857_MVOL 0
-#define LM4857_LVOL 1
-#define LM4857_RVOL 2
-#define LM4857_CTRL 3
-
-/* the shifts required to set these bits */
-#define LM4857_3D 5
-#define LM4857_WAKEUP 5
-#define LM4857_EPGAIN 4
-
-#endif /*LM4857_H_*/
-
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
index a2bb34def740..bd91c19a6c08 100644
--- a/sound/soc/samsung/ln2440sbc_alc650.c
+++ b/sound/soc/samsung/ln2440sbc_alc650.c
@@ -16,15 +16,8 @@
*
*/
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
-#include "dma.h"
-#include "ac97.h"
-
static struct snd_soc_card ln2440sbc;
static struct snd_soc_dai_link ln2440sbc_dai[] = {
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c
deleted file mode 100644
index 0d0ae2b9eef6..000000000000
--- a/sound/soc/samsung/neo1973_gta02_wm8753.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02)
- *
- * Copyright 2007 Openmoko Inc
- * Author: Graeme Gregory <graeme@openmoko.org>
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory <linux@wolfsonmicro.com>
- * Copyright 2009 Wolfson Microelectronics
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-
-#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-#include <asm/io.h>
-#include <mach/gta02.h>
-#include "../codecs/wm8753.h"
-#include "dma.h"
-#include "s3c24xx-i2s.h"
-
-static struct snd_soc_card neo1973_gta02;
-
-static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 0, bclk = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- pll_out = 12288000;
- break;
- case 48000:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 12288000;
- break;
- case 96000:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 12288000;
- break;
- case 11025:
- bclk = WM8753_BCLK_DIV_16;
- pll_out = 11289600;
- break;
- case 22050:
- bclk = WM8753_BCLK_DIV_8;
- pll_out = 11289600;
- break;
- case 44100:
- bclk = WM8753_BCLK_DIV_4;
- pll_out = 11289600;
- break;
- case 88200:
- bclk = WM8753_BCLK_DIV_2;
- pll_out = 11289600;
- break;
- }
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set MCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_32FS);
- if (ret < 0)
- return ret;
-
- /* set codec BCLK division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai,
- WM8753_BCLKDIV, bclk);
- if (ret < 0)
- return ret;
-
- /* set prescaler division for sample rate */
- ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(4, 4));
- if (ret < 0)
- return ret;
-
- /* codec PLL input is PCLK/4 */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
- iis_clkrate / 4, pll_out);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
-}
-
-/*
- * Neo1973 WM8753 HiFi DAI opserations.
- */
-static struct snd_soc_ops neo1973_gta02_hifi_ops = {
- .hw_params = neo1973_gta02_hifi_hw_params,
- .hw_free = neo1973_gta02_hifi_hw_free,
-};
-
-static int neo1973_gta02_voice_hw_params(
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int pcmdiv = 0;
- int ret = 0;
- unsigned long iis_clkrate;
-
- iis_clkrate = s3c24xx_i2s_get_clockrate();
-
- if (params_rate(params) != 8000)
- return -EINVAL;
- if (params_channels(params) != 1)
- return -EINVAL;
-
- pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
-
- /* todo: gg check mode (DSP_B) against CSR datasheet */
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- /* set the codec system clock for DAC and ADC */
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
- 12288000, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- /* set codec PCM division for sample rate */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
- pcmdiv);
- if (ret < 0)
- return ret;
-
- /* configure and enable PLL for 12.288MHz output */
- ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
- iis_clkrate / 4, 12288000);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
- /* disable the PLL */
- return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
-}
-
-static struct snd_soc_ops neo1973_gta02_voice_ops = {
- .hw_params = neo1973_gta02_voice_hw_params,
- .hw_free = neo1973_gta02_voice_hw_free,
-};
-
-#define LM4853_AMP 1
-#define LM4853_SPK 2
-
-static u8 lm4853_state;
-
-/* This has no effect, it exists only to maintain compatibility with
- * existing ALSA state files.
- */
-static int lm4853_set_state(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int val = ucontrol->value.integer.value[0];
-
- if (val)
- lm4853_state |= LM4853_AMP;
- else
- lm4853_state &= ~LM4853_AMP;
-
- return 0;
-}
-
-static int lm4853_get_state(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
-
- return 0;
-}
-
-static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int val = ucontrol->value.integer.value[0];
-
- if (val) {
- lm4853_state |= LM4853_SPK;
- gpio_set_value(GTA02_GPIO_HP_IN, 0);
- } else {
- lm4853_state &= ~LM4853_SPK;
- gpio_set_value(GTA02_GPIO_HP_IN, 1);
- }
-
- return 0;
-}
-
-static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
-
- return 0;
-}
-
-static int lm4853_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k,
- int event)
-{
- gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
-
- return 0;
-}
-
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
- SND_SOC_DAPM_LINE("GSM Line Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line In", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Handset Mic", NULL),
- SND_SOC_DAPM_SPK("Handset Spk", NULL),
-};
-
-
-/* example machine audio_mapnections */
-static const struct snd_soc_dapm_route audio_map[] = {
-
- /* Connections to the lm4853 amp */
- {"Stereo Out", NULL, "LOUT1"},
- {"Stereo Out", NULL, "ROUT1"},
-
- /* Connections to the GSM Module */
- {"GSM Line Out", NULL, "MONO1"},
- {"GSM Line Out", NULL, "MONO2"},
- {"RXP", NULL, "GSM Line In"},
- {"RXN", NULL, "GSM Line In"},
-
- /* Connections to Headset */
- {"MIC1", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Headset Mic"},
-
- /* Call Mic */
- {"MIC2", NULL, "Mic Bias"},
- {"MIC2N", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Handset Mic"},
-
- /* Call Speaker */
- {"Handset Spk", NULL, "LOUT2"},
- {"Handset Spk", NULL, "ROUT2"},
-
- /* Connect the ALC pins */
- {"ACIN", NULL, "ACOP"},
-};
-
-static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
- SOC_DAPM_PIN_SWITCH("Stereo Out"),
- SOC_DAPM_PIN_SWITCH("GSM Line Out"),
- SOC_DAPM_PIN_SWITCH("GSM Line In"),
- SOC_DAPM_PIN_SWITCH("Headset Mic"),
- SOC_DAPM_PIN_SWITCH("Handset Mic"),
- SOC_DAPM_PIN_SWITCH("Handset Spk"),
-
- /* This has no effect, it exists only to maintain compatibility with
- * existing ALSA state files.
- */
- SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
- lm4853_get_state,
- lm4853_set_state),
- SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
- lm4853_get_spk,
- lm4853_set_spk),
-};
-
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 GTA02.
- */
-static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_codec *codec = rtd->codec;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
-
- /* set up NC codec pins */
- snd_soc_dapm_nc_pin(dapm, "OUT3");
- snd_soc_dapm_nc_pin(dapm, "OUT4");
- snd_soc_dapm_nc_pin(dapm, "LINE1");
- snd_soc_dapm_nc_pin(dapm, "LINE2");
-
- /* Add neo1973 gta02 specific widgets */
- snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
- ARRAY_SIZE(wm8753_dapm_widgets));
-
- /* add neo1973 gta02 specific controls */
- err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
- ARRAY_SIZE(wm8753_neo1973_gta02_controls));
-
- if (err < 0)
- return err;
-
- /* set up neo1973 gta02 specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- /* set endpoints to default off mode */
- snd_soc_dapm_disable_pin(dapm, "Stereo Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Handset Mic");
- snd_soc_dapm_disable_pin(dapm, "Handset Spk");
-
- /* allow audio paths from the GSM modem to run during suspend */
- snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
- snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
- snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
- snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
- snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
-
- snd_soc_dapm_sync(dapm);
-
- return 0;
-}
-
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai_driver bt_dai = {
- .name = "bluetooth-dai",
- .playback = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_dai_link neo1973_gta02_dai[] = {
-{ /* Hifi Playback - for similatious use with voice below */
- .name = "WM8753",
- .stream_name = "WM8753 HiFi",
- .cpu_dai_name = "s3c24xx-iis",
- .codec_dai_name = "wm8753-hifi",
- .init = neo1973_gta02_wm8753_init,
- .platform_name = "samsung-audio",
- .codec_name = "wm8753-codec.0-001a",
- .ops = &neo1973_gta02_hifi_ops,
-},
-{ /* Voice via BT */
- .name = "Bluetooth",
- .stream_name = "Voice",
- .cpu_dai_name = "bluetooth-dai",
- .codec_dai_name = "wm8753-voice",
- .ops = &neo1973_gta02_voice_ops,
- .codec_name = "wm8753-codec.0-001a",
- .platform_name = "samsung-audio",
-},
-};
-
-static struct snd_soc_card neo1973_gta02 = {
- .name = "neo1973-gta02",
- .dai_link = neo1973_gta02_dai,
- .num_links = ARRAY_SIZE(neo1973_gta02_dai),
-};
-
-static struct platform_device *neo1973_gta02_snd_device;
-
-static int __init neo1973_gta02_init(void)
-{
- int ret;
-
- if (!machine_is_neo1973_gta02()) {
- printk(KERN_INFO
- "Only GTA02 is supported by this ASoC driver\n");
- return -ENODEV;
- }
-
- neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
- if (!neo1973_gta02_snd_device)
- return -ENOMEM;
-
- /* register bluetooth DAI here */
- ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai);
- if (ret)
- goto err_put_device;
-
- platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
- ret = platform_device_add(neo1973_gta02_snd_device);
-
- if (ret)
- goto err_unregister_dai;
-
- /* Initialise GPIOs used by amp */
- ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
- if (ret) {
- pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
- goto err_del_device;
- }
-
- ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
- if (ret) {
- pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
- goto err_free_gpio_hp_in;
- }
-
- ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
- if (ret) {
- pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
- goto err_free_gpio_hp_in;
- }
-
- ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
- if (ret) {
- pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
- goto err_free_gpio_amp_shut;
- }
-
- return 0;
-
-err_free_gpio_amp_shut:
- gpio_free(GTA02_GPIO_AMP_SHUT);
-err_free_gpio_hp_in:
- gpio_free(GTA02_GPIO_HP_IN);
-err_del_device:
- platform_device_del(neo1973_gta02_snd_device);
-err_unregister_dai:
- snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
-err_put_device:
- platform_device_put(neo1973_gta02_snd_device);
- return ret;
-}
-module_init(neo1973_gta02_init);
-
-static void __exit neo1973_gta02_exit(void)
-{
- snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
- platform_device_unregister(neo1973_gta02_snd_device);
- gpio_free(GTA02_GPIO_HP_IN);
- gpio_free(GTA02_GPIO_AMP_SHUT);
-}
-module_exit(neo1973_gta02_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index d20815d5ab2e..78bfdb3f5d7e 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -1,57 +1,32 @@
/*
- * neo1973_wm8753.c -- SoC audio for Neo1973
+ * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices
*
+ * Copyright 2007 Openmoko Inc
+ * Author: Graeme Gregory <graeme@openmoko.org>
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ * Copyright 2009 Wolfson Microelectronics
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
- *
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
+#include <linux/gpio.h>
+
#include <sound/soc.h>
-#include <sound/tlv.h>
#include <asm/mach-types.h>
-#include <asm/hardware/scoop.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <linux/io.h>
-#include <mach/spi-gpio.h>
-
#include <plat/regs-iis.h>
+#include <mach/gta02.h>
#include "../codecs/wm8753.h"
-#include "lm4857.h"
-#include "dma.h"
#include "s3c24xx-i2s.h"
-/* define the scenarios */
-#define NEO_AUDIO_OFF 0
-#define NEO_GSM_CALL_AUDIO_HANDSET 1
-#define NEO_GSM_CALL_AUDIO_HEADSET 2
-#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
-#define NEO_STEREO_TO_SPEAKERS 4
-#define NEO_STEREO_TO_HEADPHONES 5
-#define NEO_CAPTURE_HANDSET 6
-#define NEO_CAPTURE_HEADSET 7
-#define NEO_CAPTURE_BLUETOOTH 8
-
-static struct snd_soc_card neo1973;
-static struct i2c_client *i2c;
-
static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -62,8 +37,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
int ret = 0;
unsigned long iis_clkrate;
- pr_debug("Entered %s\n", __func__);
-
iis_clkrate = s3c24xx_i2s_get_clockrate();
switch (params_rate(params)) {
@@ -148,8 +121,6 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- pr_debug("Entered %s\n", __func__);
-
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
}
@@ -171,8 +142,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
int ret = 0;
unsigned long iis_clkrate;
- pr_debug("Entered %s\n", __func__);
-
iis_clkrate = s3c24xx_i2s_get_clockrate();
if (params_rate(params) != 8000)
@@ -214,8 +183,6 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- pr_debug("Entered %s\n", __func__);
-
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
}
@@ -225,335 +192,232 @@ static struct snd_soc_ops neo1973_voice_ops = {
.hw_free = neo1973_voice_hw_free,
};
-static int neo1973_scenario;
-
-static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = neo1973_scenario;
- return 0;
-}
-
-static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- pr_debug("Entered %s\n", __func__);
-
- switch (neo1973_scenario) {
- case NEO_AUDIO_OFF:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_HANDSET:
- snd_soc_dapm_enable_pin(dapm, "Audio Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_HEADSET:
- snd_soc_dapm_enable_pin(dapm, "Audio Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line In");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_GSM_CALL_AUDIO_BLUETOOTH:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_enable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_STEREO_TO_SPEAKERS:
- snd_soc_dapm_enable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_STEREO_TO_HEADPHONES:
- snd_soc_dapm_enable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_CAPTURE_HANDSET:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_enable_pin(dapm, "Call Mic");
- break;
- case NEO_CAPTURE_HEADSET:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_enable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- case NEO_CAPTURE_BLUETOOTH:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- break;
- default:
- snd_soc_dapm_disable_pin(dapm, "Audio Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
- snd_soc_dapm_disable_pin(dapm, "GSM Line In");
- snd_soc_dapm_disable_pin(dapm, "Headset Mic");
- snd_soc_dapm_disable_pin(dapm, "Call Mic");
- }
+/* Shared routes and controls */
- snd_soc_dapm_sync(dapm);
+static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+};
- return 0;
-}
+static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+ {"GSM Line Out", NULL, "MONO2"},
+ {"RXP", NULL, "GSM Line In"},
+ {"RXN", NULL, "GSM Line In"},
-static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ /* Connections to Headset */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
- pr_debug("Entered %s\n", __func__);
+ /* Call Mic */
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC2N", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Handset Mic"},
- if (neo1973_scenario == ucontrol->value.integer.value[0])
- return 0;
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+};
- neo1973_scenario = ucontrol->value.integer.value[0];
- set_scenario_endpoints(codec, neo1973_scenario);
- return 1;
-}
+static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
+ SOC_DAPM_PIN_SWITCH("GSM Line Out"),
+ SOC_DAPM_PIN_SWITCH("GSM Line In"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Handset Mic"),
+};
-static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+/* GTA02 specific routes and controlls */
-static void lm4857_write_regs(void)
-{
- pr_debug("Entered %s\n", __func__);
+#ifdef CONFIG_MACH_NEO1973_GTA02
- if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
- printk(KERN_ERR "lm4857: i2c write failed\n");
-}
+static int gta02_speaker_enabled;
-static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int reg = mc->reg;
- int shift = mc->shift;
- int mask = mc->max;
+ gta02_speaker_enabled = ucontrol->value.integer.value[0];
- pr_debug("Entered %s\n", __func__);
+ gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled);
- ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
return 0;
}
-static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int reg = mc->reg;
- int shift = mc->shift;
- int mask = mc->max;
-
- if (((lm4857_regs[reg] >> shift) & mask) ==
- ucontrol->value.integer.value[0])
- return 0;
-
- lm4857_regs[reg] &= ~(mask << shift);
- lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
- lm4857_write_regs();
- return 1;
+ ucontrol->value.integer.value[0] = gta02_speaker_enabled;
+ return 0;
}
-static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int lm4853_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
{
- u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
-
- pr_debug("Entered %s\n", __func__);
-
- if (value)
- value -= 5;
+ gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
- ucontrol->value.integer.value[0] = value;
return 0;
}
-static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 value = ucontrol->value.integer.value[0];
-
- pr_debug("Entered %s\n", __func__);
-
- if (value)
- value += 5;
-
- if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
- return 0;
-
- lm4857_regs[LM4857_CTRL] &= 0xF0;
- lm4857_regs[LM4857_CTRL] |= value;
- lm4857_write_regs();
- return 1;
-}
+static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
+ /* Connections to the amp */
+ {"Stereo Out", NULL, "LOUT1"},
+ {"Stereo Out", NULL, "ROUT1"},
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
- SND_SOC_DAPM_LINE("Audio Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line Out", NULL),
- SND_SOC_DAPM_LINE("GSM Line In", NULL),
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
- SND_SOC_DAPM_MIC("Call Mic", NULL),
+ /* Call Speaker */
+ {"Handset Spk", NULL, "LOUT2"},
+ {"Handset Spk", NULL, "ROUT2"},
};
+static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Handset Spk"),
+ SOC_DAPM_PIN_SWITCH("Stereo Out"),
-static const struct snd_soc_dapm_route dapm_routes[] = {
-
- /* Connections to the lm4857 amp */
- {"Audio Out", NULL, "LOUT1"},
- {"Audio Out", NULL, "ROUT1"},
-
- /* Connections to the GSM Module */
- {"GSM Line Out", NULL, "MONO1"},
- {"GSM Line Out", NULL, "MONO2"},
- {"RXP", NULL, "GSM Line In"},
- {"RXN", NULL, "GSM Line In"},
+ SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
+ lm4853_get_spk,
+ lm4853_set_spk),
+};
- /* Connections to Headset */
- {"MIC1", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Headset Mic"},
+static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Handset Spk", NULL),
+ SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
+};
- /* Call Mic */
- {"MIC2", NULL, "Mic Bias"},
- {"MIC2N", NULL, "Mic Bias"},
- {"Mic Bias", NULL, "Call Mic"},
+static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret;
- /* Connect the ALC pins */
- {"ACIN", NULL, "ACOP"},
-};
+ ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets,
+ ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets));
+ if (ret)
+ return ret;
-static const char *lm4857_mode[] = {
- "Off",
- "Call Speaker",
- "Stereo Speakers",
- "Stereo Speakers + Headphones",
- "Headphones"
-};
+ ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes,
+ ARRAY_SIZE(neo1973_gta02_routes));
+ if (ret)
+ return ret;
-static const struct soc_enum lm4857_mode_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
-};
+ ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls,
+ ARRAY_SIZE(neo1973_gta02_wm8753_controls));
+ if (ret)
+ return ret;
-static const char *neo_scenarios[] = {
- "Off",
- "GSM Handset",
- "GSM Headset",
- "GSM Bluetooth",
- "Speakers",
- "Headphones",
- "Capture Handset",
- "Capture Headset",
- "Capture Bluetooth"
-};
+ snd_soc_dapm_disable_pin(dapm, "Stereo Out");
+ snd_soc_dapm_disable_pin(dapm, "Handset Spk");
+ snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
-static const struct soc_enum neo_scenario_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
-};
+ return 0;
+}
-static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
-static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
-
-static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
- SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, stereo_tlv),
- SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, stereo_tlv),
- SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
- lm4857_get_reg, lm4857_set_reg, mono_tlv),
- SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
- lm4857_get_mode, lm4857_set_mode),
- SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
- neo1973_get_scenario, neo1973_set_scenario),
- SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
- SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
- lm4857_get_reg, lm4857_set_reg),
-};
+#else
+static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; }
+#endif
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 II. It is missing logic to detect hp/mic insertions and logic
- * to re-route the audio in such an event.
- */
static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int err;
-
- pr_debug("Entered %s\n", __func__);
+ int ret;
/* set up NC codec pins */
- snd_soc_dapm_nc_pin(dapm, "LOUT2");
- snd_soc_dapm_nc_pin(dapm, "ROUT2");
+ if (machine_is_neo1973_gta01()) {
+ snd_soc_dapm_nc_pin(dapm, "LOUT2");
+ snd_soc_dapm_nc_pin(dapm, "ROUT2");
+ }
snd_soc_dapm_nc_pin(dapm, "OUT3");
snd_soc_dapm_nc_pin(dapm, "OUT4");
snd_soc_dapm_nc_pin(dapm, "LINE1");
snd_soc_dapm_nc_pin(dapm, "LINE2");
/* Add neo1973 specific widgets */
- snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
- ARRAY_SIZE(wm8753_dapm_widgets));
-
- /* set endpoints to default mode */
- set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+ ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets,
+ ARRAY_SIZE(neo1973_wm8753_dapm_widgets));
+ if (ret)
+ return ret;
/* add neo1973 specific controls */
- err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
- ARRAY_SIZE(8753_neo1973_controls));
- if (err < 0)
- return err;
+ ret = snd_soc_add_controls(codec, neo1973_wm8753_controls,
+ ARRAY_SIZE(neo1973_wm8753_controls));
+ if (ret)
+ return ret;
/* set up neo1973 specific audio routes */
- err = snd_soc_dapm_add_routes(dapm, dapm_routes,
- ARRAY_SIZE(dapm_routes));
+ ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
+ ARRAY_SIZE(neo1973_wm8753_routes));
+ if (ret)
+ return ret;
+
+ /* set endpoints to default off mode */
+ snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+ snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+ snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+ snd_soc_dapm_disable_pin(dapm, "Handset Mic");
+
+ /* allow audio paths from the GSM modem to run during suspend */
+ snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
+ snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
+ snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+
+ if (machine_is_neo1973_gta02()) {
+ ret = neo1973_gta02_wm8753_init(codec);
+ if (ret)
+ return ret;
+ }
snd_soc_dapm_sync(dapm);
+
return 0;
}
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai bt_dai = {
- .name = "bluetooth-dai",
- .playback = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 1,
- .channels_max = 1,
- .rates = SNDRV_PCM_RATE_8000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+/* GTA01 specific controlls */
+
+#ifdef CONFIG_MACH_NEO1973_GTA01
+
+static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = {
+ {"Amp IN", NULL, "ROUT1"},
+ {"Amp IN", NULL, "LOUT1"},
+
+ {"Handset Spk", NULL, "Amp EP"},
+ {"Stereo Out", NULL, "Amp LS"},
+ {"Headphone", NULL, "Amp HP"},
+};
+
+static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Handset Spk", NULL),
+ SND_SOC_DAPM_SPK("Stereo Out", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
};
+static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm)
+{
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets,
+ ARRAY_SIZE(neo1973_lm4857_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes,
+ ARRAY_SIZE(neo1973_lm4857_routes));
+ if (ret)
+ return ret;
+
+ snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
+ snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
+ snd_soc_dapm_ignore_suspend(dapm, "Headphone");
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+#else
+static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; };
+#endif
+
static struct snd_soc_dai_link neo1973_dai[] = {
{ /* Hifi Playback - for similatious use with voice below */
.name = "WM8753",
@@ -569,90 +433,49 @@ static struct snd_soc_dai_link neo1973_dai[] = {
.name = "Bluetooth",
.stream_name = "Voice",
.platform_name = "samsung-audio",
- .cpu_dai_name = "bluetooth-dai",
+ .cpu_dai_name = "dfbmcs320-pcm",
.codec_dai_name = "wm8753-voice",
.codec_name = "wm8753-codec.0-001a",
.ops = &neo1973_voice_ops,
},
};
-static struct snd_soc_card neo1973 = {
- .name = "neo1973",
- .dai_link = neo1973_dai,
- .num_links = ARRAY_SIZE(neo1973_dai),
+static struct snd_soc_aux_dev neo1973_aux_devs[] = {
+ {
+ .name = "dfbmcs320",
+ .codec_name = "dfbmcs320.0",
+ },
+ {
+ .name = "lm4857",
+ .codec_name = "lm4857.0-007c",
+ .init = neo1973_lm4857_init,
+ },
};
-static int lm4857_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- pr_debug("Entered %s\n", __func__);
-
- i2c = client;
-
- lm4857_write_regs();
- return 0;
-}
-
-static int lm4857_i2c_remove(struct i2c_client *client)
-{
- pr_debug("Entered %s\n", __func__);
-
- i2c = NULL;
-
- return 0;
-}
-
-static u8 lm4857_state;
-
-static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
-{
- pr_debug("Entered %s\n", __func__);
-
- dev_dbg(&dev->dev, "lm4857_suspend\n");
- lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
- if (lm4857_state) {
- lm4857_regs[LM4857_CTRL] &= 0xf0;
- lm4857_write_regs();
- }
- return 0;
-}
-
-static int lm4857_resume(struct i2c_client *dev)
-{
- pr_debug("Entered %s\n", __func__);
-
- if (lm4857_state) {
- lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
- lm4857_write_regs();
- }
- return 0;
-}
-
-static void lm4857_shutdown(struct i2c_client *dev)
-{
- pr_debug("Entered %s\n", __func__);
-
- dev_dbg(&dev->dev, "lm4857_shutdown\n");
- lm4857_regs[LM4857_CTRL] &= 0xf0;
- lm4857_write_regs();
-}
+static struct snd_soc_codec_conf neo1973_codec_conf[] = {
+ {
+ .dev_name = "lm4857.0-007c",
+ .name_prefix = "Amp",
+ },
+};
-static const struct i2c_device_id lm4857_i2c_id[] = {
- { "neo1973_lm4857", 0 },
- { }
+#ifdef CONFIG_MACH_NEO1973_GTA02
+static const struct gpio neo1973_gta02_gpios[] = {
+ { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
+ { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
};
+#else
+static const struct gpio neo1973_gta02_gpios[] = {};
+#endif
-static struct i2c_driver lm4857_i2c_driver = {
- .driver = {
- .name = "LM4857 I2C Amp",
- .owner = THIS_MODULE,
- },
- .suspend = lm4857_suspend,
- .resume = lm4857_resume,
- .shutdown = lm4857_shutdown,
- .probe = lm4857_i2c_probe,
- .remove = lm4857_i2c_remove,
- .id_table = lm4857_i2c_id,
+static struct snd_soc_card neo1973 = {
+ .name = "neo1973",
+ .dai_link = neo1973_dai,
+ .num_links = ARRAY_SIZE(neo1973_dai),
+ .aux_dev = neo1973_aux_devs,
+ .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs),
+ .codec_conf = neo1973_codec_conf,
+ .num_configs = ARRAY_SIZE(neo1973_codec_conf),
};
static struct platform_device *neo1973_snd_device;
@@ -661,46 +484,56 @@ static int __init neo1973_init(void)
{
int ret;
- pr_debug("Entered %s\n", __func__);
-
- if (!machine_is_neo1973_gta01()) {
- printk(KERN_INFO
- "Only GTA01 hardware supported by ASoC driver\n");
+ if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02())
return -ENODEV;
+
+ if (machine_is_neo1973_gta02()) {
+ neo1973.name = "neo1973gta02";
+ neo1973.num_aux_devs = 1;
+
+ ret = gpio_request_array(neo1973_gta02_gpios,
+ ARRAY_SIZE(neo1973_gta02_gpios));
+ if (ret)
+ return ret;
}
neo1973_snd_device = platform_device_alloc("soc-audio", -1);
- if (!neo1973_snd_device)
- return -ENOMEM;
+ if (!neo1973_snd_device) {
+ ret = -ENOMEM;
+ goto err_gpio_free;
+ }
platform_set_drvdata(neo1973_snd_device, &neo1973);
ret = platform_device_add(neo1973_snd_device);
- if (ret) {
- platform_device_put(neo1973_snd_device);
- return ret;
- }
-
- ret = i2c_add_driver(&lm4857_i2c_driver);
+ if (ret)
+ goto err_put_device;
- if (ret != 0)
- platform_device_unregister(neo1973_snd_device);
+ return 0;
+err_put_device:
+ platform_device_put(neo1973_snd_device);
+err_gpio_free:
+ if (machine_is_neo1973_gta02()) {
+ gpio_free_array(neo1973_gta02_gpios,
+ ARRAY_SIZE(neo1973_gta02_gpios));
+ }
return ret;
}
+module_init(neo1973_init);
static void __exit neo1973_exit(void)
{
- pr_debug("Entered %s\n", __func__);
-
- i2c_del_driver(&lm4857_i2c_driver);
platform_device_unregister(neo1973_snd_device);
-}
-module_init(neo1973_init);
+ if (machine_is_neo1973_gta02()) {
+ gpio_free_array(neo1973_gta02_gpios,
+ ARRAY_SIZE(neo1973_gta02_gpios));
+ }
+}
module_exit(neo1973_exit);
/* Module information */
MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 48d0b750406b..38aac7d57a59 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -11,20 +11,11 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
#include <linux/io.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <plat/audio.h>
#include <plat/dma.h>
@@ -32,6 +23,113 @@
#include "dma.h"
#include "pcm.h"
+/*Register Offsets */
+#define S3C_PCM_CTL 0x00
+#define S3C_PCM_CLKCTL 0x04
+#define S3C_PCM_TXFIFO 0x08
+#define S3C_PCM_RXFIFO 0x0C
+#define S3C_PCM_IRQCTL 0x10
+#define S3C_PCM_IRQSTAT 0x14
+#define S3C_PCM_FIFOSTAT 0x18
+#define S3C_PCM_CLRINT 0x20
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK 0x3f
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT 13
+#define S3C_PCM_CTL_RXDIPSTICK_MASK 0x3f
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT 7
+#define S3C_PCM_CTL_TXDMA_EN (0x1 << 6)
+#define S3C_PCM_CTL_RXDMA_EN (0x1 << 5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1 << 4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1 << 3)
+#define S3C_PCM_CTL_TXFIFO_EN (0x1 << 2)
+#define S3C_PCM_CTL_RXFIFO_EN (0x1 << 1)
+#define S3C_PCM_CTL_ENABLE (0x1 << 0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN (0x1 << 19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1 << 18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK 0x1ff
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK 0x1ff
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT 9
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT 0
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID (0x1 << 16)
+#define S3C_PCM_TXFIFO_DATA_MSK (0xffff << 0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID (0x1 << 16)
+#define S3C_PCM_RXFIFO_DATA_MSK (0xffff << 0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN (0x1 << 14)
+#define S3C_PCM_IRQCTL_WRDEN (0x1 << 12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1 << 11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1 << 10)
+#define S3C_PCM_IRQCTL_TXFULLEN (0x1 << 9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1 << 8)
+#define S3C_PCM_IRQCTL_TXSTARVEN (0x1 << 7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1 << 6)
+#define S3C_PCM_IRQCTL_RXEMPTEN (0x1 << 5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1 << 4)
+#define S3C_PCM_IRQCTL_RXFULLEN (0x1 << 3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1 << 2)
+#define S3C_PCM_IRQCTL_RXSTARVEN (0x1 << 1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1 << 0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND (0x1 << 13)
+#define S3C_PCM_IRQSTAT_WRD_XFER (0x1 << 12)
+#define S3C_PCM_IRQSTAT_TXEMPTY (0x1 << 11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1 << 10)
+#define S3C_PCM_IRQSTAT_TXFULL (0x1 << 9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1 << 8)
+#define S3C_PCM_IRQSTAT_TXSTARV (0x1 << 7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1 << 6)
+#define S3C_PCM_IRQSTAT_RXEMPT (0x1 << 5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1 << 4)
+#define S3C_PCM_IRQSTAT_RXFULL (0x1 << 3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1 << 2)
+#define S3C_PCM_IRQSTAT_RXSTARV (0x1 << 1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1 << 0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f << 14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1 << 13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1 << 12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1 << 11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1 << 10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f << 4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1 << 3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1 << 2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1 << 1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1 << 0)
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+ spinlock_t lock;
+ struct device *dev;
+ void __iomem *regs;
+
+ unsigned int sclk_per_fs;
+
+ /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+ unsigned int idleclk;
+
+ struct clk *pclk;
+ struct clk *cclk;
+
+ struct s3c_dma_params *dma_playback;
+ struct s3c_dma_params *dma_capture;
+};
+
static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
.name = "PCM Stereo out"
};
diff --git a/sound/soc/samsung/pcm.h b/sound/soc/samsung/pcm.h
index 03393dcf852d..726baf814613 100644
--- a/sound/soc/samsung/pcm.h
+++ b/sound/soc/samsung/pcm.h
@@ -9,116 +9,9 @@
#ifndef __S3C_PCM_H
#define __S3C_PCM_H __FILE__
-/*Register Offsets */
-#define S3C_PCM_CTL (0x00)
-#define S3C_PCM_CLKCTL (0x04)
-#define S3C_PCM_TXFIFO (0x08)
-#define S3C_PCM_RXFIFO (0x0C)
-#define S3C_PCM_IRQCTL (0x10)
-#define S3C_PCM_IRQSTAT (0x14)
-#define S3C_PCM_FIFOSTAT (0x18)
-#define S3C_PCM_CLRINT (0x20)
-
-/* PCM_CTL Bit-Fields */
-#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f)
-#define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7)
-#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
-#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
-#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
-#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
-#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
-#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
-#define S3C_PCM_CTL_ENABLE (0x1<<0)
-
-/* PCM_CLKCTL Bit-Fields */
-#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
-#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
-#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
-#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
-#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
-
-/* PCM_TXFIFO Bit-Fields */
-#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_RXFIFO Bit-Fields */
-#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
-#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
-
-/* PCM_IRQCTL Bit-Fields */
-#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
-#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
-#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
-#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
-#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
-#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
-#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
-#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
-#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
-#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
-#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
-#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
-#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
-#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
-
-/* PCM_IRQSTAT Bit-Fields */
-#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
-#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
-#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
-#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
-#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
-#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
-#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
-#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
-#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
-#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
-#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
-#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
-#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
-#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
-
-/* PCM_FIFOSTAT Bit-Fields */
-#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
-#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
-#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
-#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
-#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
-#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
-
#define S3C_PCM_CLKSRC_PCLK 0
#define S3C_PCM_CLKSRC_MUX 1
#define S3C_PCM_SCLK_PER_FS 0
-/**
- * struct s3c_pcm_info - S3C PCM Controller information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- */
-struct s3c_pcm_info {
- spinlock_t lock;
- struct device *dev;
- void __iomem *regs;
-
- unsigned int sclk_per_fs;
-
- /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
- unsigned int idleclk;
-
- struct clk *pclk;
- struct clk *cclk;
-
- struct s3c_dma_params *dma_playback;
- struct s3c_dma_params *dma_capture;
-};
-
#endif /* __S3C_PCM_H */
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index f40027445dda..1e574a5d440d 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -17,26 +17,15 @@
*
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
#include <linux/gpio.h>
-#include <linux/clk.h>
#include <sound/soc.h>
-#include <sound/uda1380.h>
#include <sound/jack.h>
#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-
#include <asm/mach-types.h>
-#include "dma.h"
#include "s3c24xx-i2s.h"
-#include "../codecs/uda1380.h"
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
static int rx1950_startup(struct snd_pcm_substream *substream);
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index 094f36e41e83..52074a2b0696 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -20,9 +20,8 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <mach/dma.h>
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 7ea837867124..841ab14c1100 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -16,21 +16,13 @@
* option) any later version.
*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/clk.h>
-#include <linux/kernel.h>
#include <linux/io.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
-#include <mach/hardware.h>
+#include <sound/pcm_params.h>
#include <mach/regs-gpio.h>
#include <mach/dma.h>
@@ -39,8 +31,6 @@
#include "regs-i2s-v2.h"
#include "s3c2412-i2s.h"
-#define S3C2412_I2S_DEBUG 0
-
static struct s3c2410_dma_client s3c2412_dma_client_out = {
.name = "I2S PCM Stereo out"
};
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 13e41ed8e22b..63d8849d80bd 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -14,28 +14,16 @@
* option) any later version.
*/
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
#include <linux/delay.h>
#include <linux/clk.h>
-#include <linux/jiffies.h>
#include <linux/io.h>
#include <linux/gpio.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
-#include <mach/hardware.h>
#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-
-#include <asm/dma.h>
#include <mach/dma.h>
-
#include <plat/regs-iis.h>
#include "dma.h"
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
index a434032d1832..349566f0686b 100644
--- a/sound/soc/samsung/s3c24xx_simtec.c
+++ b/sound/soc/samsung/s3c24xx_simtec.c
@@ -7,20 +7,13 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/clk.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
#include <plat/audio-simtec.h>
-#include "dma.h"
#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
index 08fcaaa66907..ce6aef604179 100644
--- a/sound/soc/samsung/s3c24xx_simtec_hermes.c
+++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c
@@ -7,18 +7,8 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
-#include <plat/audio-simtec.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
static const struct snd_soc_dapm_widget dapm_widgets[] = {
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
index 116e3e670167..a7ef7db54687 100644
--- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
@@ -7,22 +7,10 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
-#include <plat/audio-simtec.h>
-
-#include "dma.h"
-#include "s3c24xx-i2s.h"
#include "s3c24xx_simtec.h"
-#include "../codecs/tlv320aic23.h"
-
/* supported machines:
*
* Machine Connections AMP
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
index 2c09e93dd566..3cb700751078 100644
--- a/sound/soc/samsung/s3c24xx_uda134x.c
+++ b/sound/soc/samsung/s3c24xx_uda134x.c
@@ -11,22 +11,15 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
#include <linux/clk.h>
-#include <linux/mutex.h>
#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
+
#include <sound/soc.h>
#include <sound/s3c24xx_uda134x.h>
-#include <sound/uda134x.h>
#include <plat/regs-iis.h>
-#include "dma.h"
#include "s3c24xx-i2s.h"
-#include "../codecs/uda134x.h"
-
/* #define ENFORCE_RATES 1 */
/*
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 61e2b5219d42..0a2c4f223038 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -13,20 +13,14 @@
*
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <asm/mach-types.h>
-#include "dma.h"
#include "i2s.h"
-
#include "../codecs/wm8750.h"
/*
diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c
index 3be7e7e92d6e..3a0dbfc793f0 100644
--- a/sound/soc/samsung/smdk2443_wm9710.c
+++ b/sound/soc/samsung/smdk2443_wm9710.c
@@ -12,15 +12,8 @@
*
*/
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
#include <sound/soc.h>
-#include "dma.h"
-#include "ac97.h"
-
static struct snd_soc_card smdk2443;
static struct snd_soc_dai_link smdk2443_dai[] = {
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index b5c3fad01bb8..e8ac961c6ba1 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -10,15 +10,10 @@
*
*/
-#include <linux/module.h>
-#include <linux/device.h>
#include <linux/clk.h>
-#include <plat/devs.h>
-
#include <sound/soc.h>
-#include "dma.h"
#include "spdif.h"
/* Audio clock settings are belonged to board specific part. Every
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
index b2cff1a44aed..8aacf23d6f3a 100644
--- a/sound/soc/samsung/smdk_wm8580.c
+++ b/sound/soc/samsung/smdk_wm8580.c
@@ -10,17 +10,12 @@
* option) any later version.
*/
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <asm/mach-types.h>
#include "../codecs/wm8580.h"
-#include "dma.h"
#include "i2s.h"
/*
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
index ae5fed6f772f..fffe3c1dd1bd 100644
--- a/sound/soc/samsung/smdk_wm9713.c
+++ b/sound/soc/samsung/smdk_wm9713.c
@@ -11,13 +11,8 @@
*
*/
-#include <linux/module.h>
-#include <linux/device.h>
#include <sound/soc.h>
-#include "dma.h"
-#include "ac97.h"
-
static struct snd_soc_card smdk;
/*
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index f0816404ea3e..28c491dacf7a 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -13,9 +13,8 @@
#include <linux/clk.h>
#include <linux/io.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <plat/audio.h>
#include <mach/dma.h>
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index a14820ac9665..d6f4703b3c07 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -18,18 +18,26 @@ struct fsi_ak4642_data {
const char *cpu_dai;
const char *codec;
const char *platform;
+ int id;
};
static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = rtd->codec_dai;
+ struct snd_soc_dai *codec = rtd->codec_dai;
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
int ret;
- ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM);
+ ret = snd_soc_dai_set_fmt(codec, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0);
+ ret = snd_soc_dai_set_sysclk(codec, 0, 11289600, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_LEFT_J |
+ SND_SOC_DAIFMT_CBS_CFS);
return ret;
}
@@ -60,7 +68,7 @@ static int fsi_ak4642_probe(struct platform_device *pdev)
pdata = (struct fsi_ak4642_data *)id_entry->driver_data;
- fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A);
+ fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
if (!fsi_snd_device)
goto out;
@@ -93,6 +101,7 @@ static struct fsi_ak4642_data fsi_a_ak4642 = {
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
+ .id = FSI_PORT_A,
};
static struct fsi_ak4642_data fsi_b_ak4642 = {
@@ -101,6 +110,7 @@ static struct fsi_ak4642_data fsi_b_ak4642 = {
.cpu_dai = "fsib-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
+ .id = FSI_PORT_B,
};
static struct fsi_ak4642_data fsi_a_ak4643 = {
@@ -109,6 +119,7 @@ static struct fsi_ak4642_data fsi_a_ak4643 = {
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi.0",
+ .id = FSI_PORT_A,
};
static struct fsi_ak4642_data fsi_b_ak4643 = {
@@ -117,6 +128,7 @@ static struct fsi_ak4642_data fsi_b_ak4643 = {
.cpu_dai = "fsib-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi.0",
+ .id = FSI_PORT_B,
};
static struct fsi_ak4642_data fsi2_a_ak4642 = {
@@ -125,6 +137,7 @@ static struct fsi_ak4642_data fsi2_a_ak4642 = {
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
+ .id = FSI_PORT_A,
};
static struct fsi_ak4642_data fsi2_b_ak4642 = {
@@ -133,6 +146,7 @@ static struct fsi_ak4642_data fsi2_b_ak4642 = {
.cpu_dai = "fsib-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi2",
+ .id = FSI_PORT_B,
};
static struct fsi_ak4642_data fsi2_a_ak4643 = {
@@ -141,6 +155,7 @@ static struct fsi_ak4642_data fsi2_a_ak4643 = {
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
+ .id = FSI_PORT_A,
};
static struct fsi_ak4642_data fsi2_b_ak4643 = {
@@ -149,6 +164,7 @@ static struct fsi_ak4642_data fsi2_b_ak4643 = {
.cpu_dai = "fsib-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
+ .id = FSI_PORT_B,
};
static struct platform_device_id fsi_id_table[] = {
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index e8df9da92f71..dbafd7ac5590 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -15,11 +15,20 @@
static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_dai *dai = rtd->codec_dai;
+ struct snd_soc_dai *codec = rtd->codec_dai;
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
+ int ret;
- return snd_soc_dai_set_fmt(dai,
+ ret = snd_soc_dai_set_fmt(codec,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_CBS_CFS);
+
+ return ret;
}
static struct snd_soc_dai_link fsi_da7210_dai = {
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
index a52dd8ec71d3..9719985eb82d 100644
--- a/sound/soc/sh/fsi-hdmi.c
+++ b/sound/soc/sh/fsi-hdmi.c
@@ -12,31 +12,59 @@
#include <linux/platform_device.h>
#include <sound/sh_fsi.h>
+struct fsi_hdmi_data {
+ const char *cpu_dai;
+ const char *card;
+ int id;
+};
+
+static int fsi_hdmi_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBM_CFM);
+
+ return ret;
+}
+
static struct snd_soc_dai_link fsi_dai_link = {
.name = "HDMI",
.stream_name = "HDMI",
- .cpu_dai_name = "fsib-dai", /* fsi B */
.codec_dai_name = "sh_mobile_hdmi-hifi",
.platform_name = "sh_fsi2",
.codec_name = "sh-mobile-hdmi",
+ .init = fsi_hdmi_dai_init,
};
static struct snd_soc_card fsi_soc_card = {
- .name = "FSI (SH MOBILE HDMI)",
.dai_link = &fsi_dai_link,
.num_links = 1,
};
static struct platform_device *fsi_snd_device;
-static int __init fsi_hdmi_init(void)
+static int fsi_hdmi_probe(struct platform_device *pdev)
{
int ret = -ENOMEM;
+ const struct platform_device_id *id_entry;
+ struct fsi_hdmi_data *pdata;
+
+ id_entry = pdev->id_entry;
+ if (!id_entry) {
+ dev_err(&pdev->dev, "unknown fsi hdmi\n");
+ return -ENODEV;
+ }
- fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
+ pdata = (struct fsi_hdmi_data *)id_entry->driver_data;
+
+ fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
if (!fsi_snd_device)
goto out;
+ fsi_dai_link.cpu_dai_name = pdata->cpu_dai;
+ fsi_soc_card.name = pdata->card;
+
platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
ret = platform_device_add(fsi_snd_device);
@@ -47,9 +75,48 @@ out:
return ret;
}
-static void __exit fsi_hdmi_exit(void)
+static int fsi_hdmi_remove(struct platform_device *pdev)
{
platform_device_unregister(fsi_snd_device);
+ return 0;
+}
+
+static struct fsi_hdmi_data fsi2_a_hdmi = {
+ .cpu_dai = "fsia-dai",
+ .card = "FSI2A (SH MOBILE HDMI)",
+ .id = FSI_PORT_A,
+};
+
+static struct fsi_hdmi_data fsi2_b_hdmi = {
+ .cpu_dai = "fsib-dai",
+ .card = "FSI2B (SH MOBILE HDMI)",
+ .id = FSI_PORT_B,
+};
+
+static struct platform_device_id fsi_id_table[] = {
+ /* FSI 2 */
+ { "sh_fsi2_a_hdmi", (kernel_ulong_t)&fsi2_a_hdmi },
+ { "sh_fsi2_b_hdmi", (kernel_ulong_t)&fsi2_b_hdmi },
+ {},
+};
+
+static struct platform_driver fsi_hdmi = {
+ .driver = {
+ .name = "fsi-hdmi-audio",
+ },
+ .probe = fsi_hdmi_probe,
+ .remove = fsi_hdmi_remove,
+ .id_table = fsi_id_table,
+};
+
+static int __init fsi_hdmi_init(void)
+{
+ return platform_driver_register(&fsi_hdmi);
+}
+
+static void __exit fsi_hdmi_exit(void)
+{
+ platform_driver_unregister(&fsi_hdmi);
}
module_init(fsi_hdmi_init);
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 2b06402801ef..0c9997e2d8c0 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -78,6 +78,8 @@
/* CKG1 */
#define ACKMD_MASK 0x00007000
#define BPFMD_MASK 0x00000700
+#define DIMD (1 << 4)
+#define DOMD (1 << 0)
/* A/B MST_CTLR */
#define BP (1 << 4) /* Fix the signal of Biphase output */
@@ -111,6 +113,8 @@
#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable);
+
/*
* FSI driver use below type name for variable
*
@@ -128,7 +132,6 @@ struct fsi_stream {
struct snd_pcm_substream *substream;
int fifo_max_num;
- int chan_num;
int buff_offset;
int buff_len;
@@ -143,6 +146,7 @@ struct fsi_priv {
void __iomem *base;
struct fsi_master *master;
+ int chan_num;
struct fsi_stream playback;
struct fsi_stream capture;
@@ -252,9 +256,8 @@ static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
return rtd->cpu_dai;
}
-static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
+static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai)
{
- struct snd_soc_dai *dai = fsi_get_dai(substream);
struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
if (dai->id == 0)
@@ -263,11 +266,27 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
return &master->fsib;
}
+static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
+{
+ return fsi_get_priv_frm_dai(fsi_get_dai(substream));
+}
+
+static set_rate_func fsi_get_info_set_rate(struct fsi_master *master)
+{
+ if (!master->info)
+ return NULL;
+
+ return master->info->set_rate;
+}
+
static u32 fsi_get_info_flags(struct fsi_priv *fsi)
{
int is_porta = fsi_is_port_a(fsi);
struct fsi_master *master = fsi_get_master(fsi);
+ if (!master->info)
+ return 0;
+
return is_porta ? master->info->porta_flags :
master->info->portb_flags;
}
@@ -288,21 +307,6 @@ static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
return is_play ? &fsi->playback : &fsi->capture;
}
-static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
-{
- u32 mode;
- u32 flags = fsi_get_info_flags(fsi);
-
- mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE;
-
- /* return
- * 1 : master mode
- * 0 : slave mode
- */
-
- return (mode & flags) != mode;
-}
-
static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
{
int is_porta = fsi_is_port_a(fsi);
@@ -357,7 +361,6 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
{
u32 status;
- struct fsi_stream *io = fsi_get_stream(fsi, is_play);
int data_num;
status = is_play ?
@@ -365,7 +368,7 @@ static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
fsi_reg_read(fsi, DIFF_ST);
data_num = 0x1ff & (status >> 8);
- data_num *= io->chan_num;
+ data_num *= fsi->chan_num;
return data_num;
}
@@ -387,7 +390,7 @@ static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
struct snd_pcm_substream *substream = io->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
- return frames_to_bytes(runtime, 1) / io->chan_num;
+ return frames_to_bytes(runtime, 1) / fsi->chan_num;
}
static void fsi_count_fifo_err(struct fsi_priv *fsi)
@@ -580,10 +583,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
* 7 channels: 32 ( 32 x 7 = 224)
* 8 channels: 32 ( 32 x 8 = 256)
*/
- for (i = 1; i < io->chan_num; i <<= 1)
+ for (i = 1; i < fsi->chan_num; i <<= 1)
io->fifo_max_num >>= 1;
dev_dbg(dai->dev, "%d channel %d store\n",
- io->chan_num, io->fifo_max_num);
+ fsi->chan_num, io->fifo_max_num);
/*
* set interrupt generation factor
@@ -659,7 +662,7 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
* data_num_max : number of FSI fifo free space
* data_num : number of ALSA residue data
*/
- data_num_max = io->fifo_max_num * io->chan_num;
+ data_num_max = io->fifo_max_num * fsi->chan_num;
data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
data_num = data_residue_num;
@@ -754,25 +757,12 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- struct fsi_master *master = fsi_get_master(fsi);
- struct fsi_stream *io;
u32 flags = fsi_get_info_flags(fsi);
- u32 fmt;
u32 data;
int is_play = fsi_is_play(substream);
- int is_master;
-
- io = fsi_get_stream(fsi, is_play);
pm_runtime_get_sync(dai->dev);
- /* CKG1 */
- data = is_play ? (1 << 0) : (1 << 4);
- is_master = fsi_is_master_mode(fsi, is_play);
- if (is_master)
- fsi_reg_mask_set(fsi, CKG1, data, data);
- else
- fsi_reg_mask_set(fsi, CKG1, data, 0);
/* clock inversion (CKG2) */
data = 0;
@@ -787,54 +777,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
fsi_reg_write(fsi, CKG2, data);
- /* do fmt, di fmt */
- data = 0;
- fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
- switch (fmt) {
- case SH_FSI_FMT_MONO:
- data = CR_MONO;
- io->chan_num = 1;
- break;
- case SH_FSI_FMT_MONO_DELAY:
- data = CR_MONO_D;
- io->chan_num = 1;
- break;
- case SH_FSI_FMT_PCM:
- data = CR_PCM;
- io->chan_num = 2;
- break;
- case SH_FSI_FMT_I2S:
- data = CR_I2S;
- io->chan_num = 2;
- break;
- case SH_FSI_FMT_TDM:
- io->chan_num = is_play ?
- SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM | (io->chan_num - 1);
- break;
- case SH_FSI_FMT_TDM_DELAY:
- io->chan_num = is_play ?
- SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
- data = CR_TDM_D | (io->chan_num - 1);
- break;
- case SH_FSI_FMT_SPDIF:
- if (master->core->ver < 2) {
- dev_err(dai->dev, "This FSI can not use SPDIF\n");
- return -EINVAL;
- }
- data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
- io->chan_num = 2;
- fsi_spdif_clk_ctrl(fsi, 1);
- fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
- break;
- default:
- dev_err(dai->dev, "unknown format.\n");
- return -EINVAL;
- }
- is_play ?
- fsi_reg_write(fsi, DO_FMT, data) :
- fsi_reg_write(fsi, DI_FMT, data);
-
/* irq clear */
fsi_irq_disable(fsi, is_play);
fsi_irq_clear_status(fsi);
@@ -851,12 +793,12 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
struct fsi_priv *fsi = fsi_get_priv(substream);
int is_play = fsi_is_play(substream);
struct fsi_master *master = fsi_get_master(fsi);
- int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
+ set_rate_func set_rate;
fsi_irq_disable(fsi, is_play);
fsi_clk_ctrl(fsi, 0);
- set_rate = master->info->set_rate;
+ set_rate = fsi_get_info_set_rate(master);
if (set_rate && fsi->rate)
set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
fsi->rate = 0;
@@ -889,18 +831,100 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
+{
+ u32 data = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ data = CR_I2S;
+ fsi->chan_num = 2;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ data = CR_PCM;
+ fsi->chan_num = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fsi_reg_write(fsi, DO_FMT, data);
+ fsi_reg_write(fsi, DI_FMT, data);
+
+ return 0;
+}
+
+static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
+{
+ struct fsi_master *master = fsi_get_master(fsi);
+ u32 data = 0;
+
+ if (master->core->ver < 2)
+ return -EINVAL;
+
+ data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
+ fsi->chan_num = 2;
+ fsi_spdif_clk_ctrl(fsi, 1);
+ fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+
+ fsi_reg_write(fsi, DO_FMT, data);
+ fsi_reg_write(fsi, DI_FMT, data);
+
+ return 0;
+}
+
+static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+ u32 flags = fsi_get_info_flags(fsi);
+ u32 data = 0;
+ int ret;
+
+ pm_runtime_get_sync(dai->dev);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ data = DIMD | DOMD;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ ret = -EINVAL;
+ goto set_fmt_exit;
+ }
+ fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
+
+ /* set format */
+ switch (flags & SH_FSI_FMT_MASK) {
+ case SH_FSI_FMT_DAI:
+ ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ break;
+ case SH_FSI_FMT_SPDIF:
+ ret = fsi_set_fmt_spdif(fsi);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+set_fmt_exit:
+ pm_runtime_put_sync(dai->dev);
+
+ return ret;
+}
+
static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct fsi_priv *fsi = fsi_get_priv(substream);
struct fsi_master *master = fsi_get_master(fsi);
- int (*set_rate)(struct device *dev, int is_porta, int rate, int enable);
+ set_rate_func set_rate;
int fsi_ver = master->core->ver;
long rate = params_rate(params);
int ret;
- set_rate = master->info->set_rate;
+ set_rate = fsi_get_info_set_rate(master);
if (!set_rate)
return 0;
@@ -975,6 +999,7 @@ static struct snd_soc_dai_ops fsi_dai_ops = {
.startup = fsi_dai_startup,
.shutdown = fsi_dai_shutdown,
.trigger = fsi_dai_trigger,
+ .set_fmt = fsi_dai_set_fmt,
.hw_params = fsi_dai_hw_params,
};
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 8c2a21a978ac..5d76da43b14c 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -18,6 +18,8 @@
#include <linux/bitmap.h>
#include <linux/rbtree.h>
+#include <trace/events/asoc.h>
+
static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
unsigned int reg)
{
@@ -25,7 +27,8 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -49,7 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = value & 0x00ff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -106,7 +110,8 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -130,7 +135,8 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = value & 0x00ff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -191,7 +197,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
data[1] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -216,7 +223,8 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
reg &= 0xff;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -271,7 +279,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
data[2] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -295,7 +304,8 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -450,7 +460,8 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
reg &= 0xff;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -476,7 +487,8 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
reg &= 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -568,7 +580,8 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
unsigned int val;
if (reg >= codec->driver->reg_cache_size ||
- snd_soc_codec_volatile_register(codec, reg)) {
+ snd_soc_codec_volatile_register(codec, reg) ||
+ codec->cache_bypass) {
if (codec->cache_only)
return -1;
@@ -595,7 +608,8 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
data[3] = value & 0xff;
if (!snd_soc_codec_volatile_register(codec, reg) &&
- reg < codec->driver->reg_cache_size) {
+ reg < codec->driver->reg_cache_size &&
+ !codec->cache_bypass) {
ret = snd_soc_cache_write(codec, reg, value);
if (ret < 0)
return -1;
@@ -761,6 +775,49 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
+static bool snd_soc_set_cache_val(void *base, unsigned int idx,
+ unsigned int val, unsigned int word_size)
+{
+ switch (word_size) {
+ case 1: {
+ u8 *cache = base;
+ if (cache[idx] == val)
+ return true;
+ cache[idx] = val;
+ break;
+ }
+ case 2: {
+ u16 *cache = base;
+ if (cache[idx] == val)
+ return true;
+ cache[idx] = val;
+ break;
+ }
+ default:
+ BUG();
+ }
+ return false;
+}
+
+static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
+ unsigned int word_size)
+{
+ switch (word_size) {
+ case 1: {
+ const u8 *cache = base;
+ return cache[idx];
+ }
+ case 2: {
+ const u16 *cache = base;
+ return cache[idx];
+ }
+ default:
+ BUG();
+ }
+ /* unreachable */
+ return -1;
+}
+
struct snd_soc_rbtree_node {
struct rb_node node;
unsigned int reg;
@@ -835,7 +892,9 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
ret = snd_soc_cache_read(codec, rbnode->reg, &val);
if (ret)
return ret;
+ codec->cache_bypass = 1;
ret = snd_soc_write(codec, rbnode->reg, val);
+ codec->cache_bypass = 0;
if (ret)
return ret;
dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
@@ -924,7 +983,12 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
{
+ struct snd_soc_rbtree_node *rbtree_node;
struct snd_soc_rbtree_ctx *rbtree_ctx;
+ unsigned int val;
+ unsigned int word_size;
+ int i;
+ int ret;
codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
if (!codec->reg_cache)
@@ -936,53 +1000,25 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
if (!codec->reg_def_copy)
return 0;
-/*
- * populate the rbtree with the initialized registers. All other
- * registers will be inserted into the tree when they are first written.
- *
- * The reasoning behind this, is that we need to step through and
- * dereference the cache in u8/u16 increments without sacrificing
- * portability. This could also be done using memcpy() but that would
- * be slightly more cryptic.
- */
-#define snd_soc_rbtree_populate(cache) \
-({ \
- int ret, i; \
- struct snd_soc_rbtree_node *rbtree_node; \
- \
- ret = 0; \
- cache = codec->reg_def_copy; \
- for (i = 0; i < codec->driver->reg_cache_size; ++i) { \
- if (!cache[i]) \
- continue; \
- rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); \
- if (!rbtree_node) { \
- ret = -ENOMEM; \
- snd_soc_cache_exit(codec); \
- break; \
- } \
- rbtree_node->reg = i; \
- rbtree_node->value = cache[i]; \
- rbtree_node->defval = cache[i]; \
- snd_soc_rbtree_insert(&rbtree_ctx->root, \
- rbtree_node); \
- } \
- ret; \
-})
-
- switch (codec->driver->reg_word_size) {
- case 1: {
- const u8 *cache;
-
- return snd_soc_rbtree_populate(cache);
- }
- case 2: {
- const u16 *cache;
-
- return snd_soc_rbtree_populate(cache);
- }
- default:
- BUG();
+ /*
+ * populate the rbtree with the initialized registers. All other
+ * registers will be inserted when they are first modified.
+ */
+ word_size = codec->driver->reg_word_size;
+ for (i = 0; i < codec->driver->reg_cache_size; ++i) {
+ val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
+ if (!val)
+ continue;
+ rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
+ if (!rbtree_node) {
+ ret = -ENOMEM;
+ snd_soc_cache_exit(codec);
+ break;
+ }
+ rbtree_node->reg = i;
+ rbtree_node->value = val;
+ rbtree_node->defval = val;
+ snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
}
return 0;
@@ -1080,34 +1116,28 @@ static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
unsigned int reg)
{
const struct snd_soc_codec_driver *codec_drv;
- size_t reg_size;
codec_drv = codec->driver;
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
return (reg * codec_drv->reg_word_size) /
- DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
+ DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
}
static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
unsigned int reg)
{
const struct snd_soc_codec_driver *codec_drv;
- size_t reg_size;
codec_drv = codec->driver;
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
- return reg % (DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()) /
+ return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) /
codec_drv->reg_word_size);
}
static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
{
const struct snd_soc_codec_driver *codec_drv;
- size_t reg_size;
codec_drv = codec->driver;
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
- return DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
+ return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count());
}
static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
@@ -1122,7 +1152,9 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
ret = snd_soc_cache_read(codec, i, &val);
if (ret)
return ret;
+ codec->cache_bypass = 1;
ret = snd_soc_write(codec, i, val);
+ codec->cache_bypass = 0;
if (ret)
return ret;
dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
@@ -1165,29 +1197,10 @@ static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
}
/* write the new value to the cache */
- switch (codec->driver->reg_word_size) {
- case 1: {
- u8 *cache;
- cache = lzo_block->dst;
- if (cache[blkpos] == value) {
- kfree(lzo_block->dst);
- goto out;
- }
- cache[blkpos] = value;
- }
- break;
- case 2: {
- u16 *cache;
- cache = lzo_block->dst;
- if (cache[blkpos] == value) {
- kfree(lzo_block->dst);
- goto out;
- }
- cache[blkpos] = value;
- }
- break;
- default:
- BUG();
+ if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value,
+ codec->driver->reg_word_size)) {
+ kfree(lzo_block->dst);
+ goto out;
}
/* prepare the source to be the decompressed block */
@@ -1241,25 +1254,10 @@ static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
/* decompress the block */
ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
- if (ret >= 0) {
+ if (ret >= 0)
/* fetch the value from the cache */
- switch (codec->driver->reg_word_size) {
- case 1: {
- u8 *cache;
- cache = lzo_block->dst;
- *value = cache[blkpos];
- }
- break;
- case 2: {
- u16 *cache;
- cache = lzo_block->dst;
- *value = cache[blkpos];
- }
- break;
- default:
- BUG();
- }
- }
+ *value = snd_soc_get_cache_val(lzo_block->dst, blkpos,
+ codec->driver->reg_word_size);
kfree(lzo_block->dst);
/* restore the pointer and length of the compressed block */
@@ -1301,7 +1299,7 @@ static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
{
struct snd_soc_lzo_ctx **lzo_blocks;
- size_t reg_size, bmp_size;
+ size_t bmp_size;
const struct snd_soc_codec_driver *codec_drv;
int ret, tofree, i, blksize, blkcount;
const char *p, *end;
@@ -1309,7 +1307,6 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
ret = 0;
codec_drv = codec->driver;
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
/*
* If we have not been given a default register cache
@@ -1321,8 +1318,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
tofree = 1;
if (!codec->reg_def_copy) {
- codec->reg_def_copy = kzalloc(reg_size,
- GFP_KERNEL);
+ codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL);
if (!codec->reg_def_copy)
return -ENOMEM;
}
@@ -1370,7 +1366,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
blksize = snd_soc_lzo_get_blksize(codec);
p = codec->reg_def_copy;
- end = codec->reg_def_copy + reg_size;
+ end = codec->reg_def_copy + codec->reg_size;
/* compress the register map and fill the lzo blocks */
for (i = 0; i < blkcount; ++i, p += blksize) {
lzo_blocks[i]->src = p;
@@ -1414,28 +1410,10 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
ret = snd_soc_cache_read(codec, i, &val);
if (ret)
return ret;
- if (codec_drv->reg_cache_default) {
- switch (codec_drv->reg_word_size) {
- case 1: {
- const u8 *cache;
-
- cache = codec_drv->reg_cache_default;
- if (cache[i] == val)
- continue;
- }
- break;
- case 2: {
- const u16 *cache;
-
- cache = codec_drv->reg_cache_default;
- if (cache[i] == val)
- continue;
- }
- break;
- default:
- BUG();
- }
- }
+ if (codec->reg_def_copy)
+ if (snd_soc_get_cache_val(codec->reg_def_copy,
+ i, codec_drv->reg_word_size) == val)
+ continue;
ret = snd_soc_write(codec, i, val);
if (ret)
return ret;
@@ -1448,50 +1426,16 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
- switch (codec->driver->reg_word_size) {
- case 1: {
- u8 *cache;
-
- cache = codec->reg_cache;
- cache[reg] = value;
- }
- break;
- case 2: {
- u16 *cache;
-
- cache = codec->reg_cache;
- cache[reg] = value;
- }
- break;
- default:
- BUG();
- }
-
+ snd_soc_set_cache_val(codec->reg_cache, reg, value,
+ codec->driver->reg_word_size);
return 0;
}
static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value)
{
- switch (codec->driver->reg_word_size) {
- case 1: {
- u8 *cache;
-
- cache = codec->reg_cache;
- *value = cache[reg];
- }
- break;
- case 2: {
- u16 *cache;
-
- cache = codec->reg_cache;
- *value = cache[reg];
- }
- break;
- default:
- BUG();
- }
-
+ *value = snd_soc_get_cache_val(codec->reg_cache, reg,
+ codec->driver->reg_word_size);
return 0;
}
@@ -1507,24 +1451,14 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
{
const struct snd_soc_codec_driver *codec_drv;
- size_t reg_size;
codec_drv = codec->driver;
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
- /*
- * for flat compression, we don't need to keep a copy of the
- * original defaults register cache as it will definitely not
- * be marked as __devinitconst
- */
- kfree(codec->reg_def_copy);
- codec->reg_def_copy = NULL;
-
- if (codec_drv->reg_cache_default)
- codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
- reg_size, GFP_KERNEL);
+ if (codec->reg_def_copy)
+ codec->reg_cache = kmemdup(codec->reg_def_copy,
+ codec->reg_size, GFP_KERNEL);
else
- codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
+ codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
if (!codec->reg_cache)
return -ENOMEM;
@@ -1669,21 +1603,77 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write);
int snd_soc_cache_sync(struct snd_soc_codec *codec)
{
int ret;
+ const char *name;
if (!codec->cache_sync) {
return 0;
}
- if (codec->cache_ops && codec->cache_ops->sync) {
- if (codec->cache_ops->name)
- dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
- codec->cache_ops->name, codec->name);
- ret = codec->cache_ops->sync(codec);
- if (!ret)
- codec->cache_sync = 0;
- return ret;
- }
+ if (!codec->cache_ops || !codec->cache_ops->sync)
+ return -EINVAL;
- return -EINVAL;
+ if (codec->cache_ops->name)
+ name = codec->cache_ops->name;
+ else
+ name = "unknown";
+
+ if (codec->cache_ops->name)
+ dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
+ codec->cache_ops->name, codec->name);
+ trace_snd_soc_cache_sync(codec, name, "start");
+ ret = codec->cache_ops->sync(codec);
+ if (!ret)
+ codec->cache_sync = 0;
+ trace_snd_soc_cache_sync(codec, name, "end");
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
+
+static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ const struct snd_soc_codec_driver *codec_drv;
+ unsigned int min, max, index;
+
+ codec_drv = codec->driver;
+ min = 0;
+ max = codec_drv->reg_access_size - 1;
+ do {
+ index = (min + max) / 2;
+ if (codec_drv->reg_access_default[index].reg == reg)
+ return index;
+ if (codec_drv->reg_access_default[index].reg < reg)
+ min = index + 1;
+ else
+ max = index;
+ } while (min <= max);
+ return -1;
+}
+
+int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ int index;
+
+ if (reg >= codec->driver->reg_cache_size)
+ return 1;
+ index = snd_soc_get_reg_access_index(codec, reg);
+ if (index < 0)
+ return 0;
+ return codec->driver->reg_access_default[index].vol;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
+
+int snd_soc_default_readable_register(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ int index;
+
+ if (reg >= codec->driver->reg_cache_size)
+ return 1;
+ index = snd_soc_get_reg_access_index(codec, reg);
+ if (index < 0)
+ return 0;
+ return codec->driver->reg_access_default[index].read;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c3f6f1e72790..17efacdb248a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -48,7 +48,8 @@ static DEFINE_MUTEX(pcm_mutex);
static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
#ifdef CONFIG_DEBUG_FS
-static struct dentry *debugfs_root;
+struct dentry *snd_soc_debugfs_root;
+EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
#endif
static DEFINE_MUTEX(client_mutex);
@@ -57,8 +58,6 @@ static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);
-static int snd_soc_register_card(struct snd_soc_card *card);
-static int snd_soc_unregister_card(struct snd_soc_card *card);
static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
/*
@@ -70,10 +69,73 @@ static int pmdown_time = 5000;
module_param(pmdown_time, int, 0);
MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
+/* returns the minimum number of bytes needed to represent
+ * a particular given value */
+static int min_bytes_needed(unsigned long val)
+{
+ int c = 0;
+ int i;
+
+ for (i = (sizeof val * 8) - 1; i >= 0; --i, ++c)
+ if (val & (1UL << i))
+ break;
+ c = (sizeof val * 8) - c;
+ if (!c || (c % 8))
+ c = (c + 8) / 8;
+ else
+ c /= 8;
+ return c;
+}
+
+/* fill buf which is 'len' bytes with a formatted
+ * string of the form 'reg: value\n' */
+static int format_register_str(struct snd_soc_codec *codec,
+ unsigned int reg, char *buf, size_t len)
+{
+ int wordsize = codec->driver->reg_word_size * 2;
+ int regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
+ int ret;
+ char tmpbuf[len + 1];
+ char regbuf[regsize + 1];
+
+ /* since tmpbuf is allocated on the stack, warn the callers if they
+ * try to abuse this function */
+ WARN_ON(len > 63);
+
+ /* +2 for ': ' and + 1 for '\n' */
+ if (wordsize + regsize + 2 + 1 != len)
+ return -EINVAL;
+
+ ret = snd_soc_read(codec , reg);
+ if (ret < 0) {
+ memset(regbuf, 'X', regsize);
+ regbuf[regsize] = '\0';
+ } else {
+ snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
+ }
+
+ /* prepare the buffer */
+ snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf);
+ /* copy it back to the caller without the '\0' */
+ memcpy(buf, tmpbuf, len);
+
+ return 0;
+}
+
/* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
+ size_t count, loff_t pos)
{
- int ret, i, step = 1, count = 0;
+ int i, step = 1;
+ int wordsize, regsize;
+ int len;
+ size_t total = 0;
+ loff_t p = 0;
+
+ wordsize = codec->driver->reg_word_size * 2;
+ regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
+
+ len = wordsize + regsize + 2 + 1;
if (!codec->driver->reg_cache_size)
return 0;
@@ -81,55 +143,37 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
if (codec->driver->reg_cache_step)
step = codec->driver->reg_cache_step;
- count += sprintf(buf, "%s registers\n", codec->name);
for (i = 0; i < codec->driver->reg_cache_size; i += step) {
- if (codec->driver->readable_register && !codec->driver->readable_register(i))
+ if (codec->readable_register && !codec->readable_register(codec, i))
continue;
-
- count += sprintf(buf + count, "%2x: ", i);
- if (count >= PAGE_SIZE - 1)
- break;
-
if (codec->driver->display_register) {
count += codec->driver->display_register(codec, buf + count,
PAGE_SIZE - count, i);
} else {
- /* If the read fails it's almost certainly due to
- * the register being volatile and the device being
- * powered off.
- */
- ret = snd_soc_read(codec, i);
- if (ret >= 0)
- count += snprintf(buf + count,
- PAGE_SIZE - count,
- "%4x", ret);
- else
- count += snprintf(buf + count,
- PAGE_SIZE - count,
- "<no data: %d>", ret);
+ /* only support larger than PAGE_SIZE bytes debugfs
+ * entries for the default case */
+ if (p >= pos) {
+ if (total + len >= count - 1)
+ break;
+ format_register_str(codec, i, buf + total, len);
+ total += len;
+ }
+ p += len;
}
-
- if (count >= PAGE_SIZE - 1)
- break;
-
- count += snprintf(buf + count, PAGE_SIZE - count, "\n");
- if (count >= PAGE_SIZE - 1)
- break;
}
- /* Truncate count; min() would cause a warning */
- if (count >= PAGE_SIZE)
- count = PAGE_SIZE - 1;
+ total = min(total, count - 1);
- return count;
+ return total;
}
+
static ssize_t codec_reg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_soc_pcm_runtime *rtd =
container_of(dev, struct snd_soc_pcm_runtime, dev);
- return soc_codec_reg_show(rtd->codec, buf);
+ return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
}
static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -168,16 +212,28 @@ static int codec_reg_open_file(struct inode *inode, struct file *file)
}
static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
ssize_t ret;
struct snd_soc_codec *codec = file->private_data;
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ char *buf;
+
+ if (*ppos < 0 || !count)
+ return -EINVAL;
+
+ buf = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = soc_codec_reg_show(codec, buf);
- if (ret >= 0)
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ ret = soc_codec_reg_show(codec, buf, count, *ppos);
+ if (ret >= 0) {
+ if (copy_to_user(user_buf, buf, ret)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+ *ppos += ret;
+ }
+
kfree(buf);
return ret;
}
@@ -209,6 +265,10 @@ static ssize_t codec_reg_write_file(struct file *file,
start++;
if (strict_strtoul(start, 16, &value))
return -EINVAL;
+
+ /* Userspace has been fiddling around behind the kernel's back */
+ add_taint(TAINT_USER);
+
snd_soc_write(codec, reg, value);
return buf_size;
}
@@ -232,6 +292,11 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
return;
}
+ debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root,
+ &codec->cache_sync);
+ debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root,
+ &codec->cache_only);
+
codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
codec->debugfs_codec_root,
codec, &codec_reg_fops);
@@ -356,7 +421,7 @@ static const struct file_operations platform_list_fops = {
static void soc_init_card_debugfs(struct snd_soc_card *card)
{
card->debugfs_card_root = debugfs_create_dir(card->name,
- debugfs_root);
+ snd_soc_debugfs_root);
if (!card->debugfs_card_root) {
dev_warn(card->dev,
"ASoC: Failed to create codec debugfs directory\n");
@@ -435,20 +500,30 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
- rtd->dai_link->symmetric_rates) {
- dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
- rtd->rate);
+ if (!codec_dai->driver->symmetric_rates &&
+ !cpu_dai->driver->symmetric_rates &&
+ !rtd->dai_link->symmetric_rates)
+ return 0;
- ret = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- rtd->rate,
- rtd->rate);
- if (ret < 0) {
- dev_err(&rtd->dev,
- "Unable to apply rate symmetry constraint: %d\n", ret);
- return ret;
- }
+ /* This can happen if multiple streams are starting simultaneously -
+ * the second can need to get its constraints before the first has
+ * picked a rate. Complain and allow the application to carry on.
+ */
+ if (!rtd->rate) {
+ dev_warn(&rtd->dev,
+ "Not enforcing symmetric_rates due to race\n");
+ return 0;
+ }
+
+ dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate);
+
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ rtd->rate, rtd->rate);
+ if (ret < 0) {
+ dev_err(&rtd->dev,
+ "Unable to apply rate symmetry constraint: %d\n", ret);
+ return ret;
}
return 0;
@@ -962,12 +1037,11 @@ static struct snd_pcm_ops soc_pcm_ops = {
.pointer = soc_pcm_pointer,
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* powers down audio subsystem for suspend */
-static int soc_suspend(struct device *dev)
+int snd_soc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = dev_get_drvdata(dev);
struct snd_soc_codec *codec;
int i;
@@ -1008,7 +1082,7 @@ static int soc_suspend(struct device *dev)
}
if (card->suspend_pre)
- card->suspend_pre(pdev, PMSG_SUSPEND);
+ card->suspend_pre(card);
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
@@ -1075,10 +1149,11 @@ static int soc_suspend(struct device *dev)
}
if (card->suspend_post)
- card->suspend_post(pdev, PMSG_SUSPEND);
+ card->suspend_post(card);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_suspend);
/* deferred resume work, so resume can complete before we finished
* setting our codec back up, which can be very slow on I2C
@@ -1087,7 +1162,6 @@ static void soc_resume_deferred(struct work_struct *work)
{
struct snd_soc_card *card =
container_of(work, struct snd_soc_card, deferred_resume_work);
- struct platform_device *pdev = to_platform_device(card->dev);
struct snd_soc_codec *codec;
int i;
@@ -1101,7 +1175,7 @@ static void soc_resume_deferred(struct work_struct *work)
snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
if (card->resume_pre)
- card->resume_pre(pdev);
+ card->resume_pre(card);
/* resume AC97 DAIs */
for (i = 0; i < card->num_rtd; i++) {
@@ -1176,7 +1250,7 @@ static void soc_resume_deferred(struct work_struct *work)
}
if (card->resume_post)
- card->resume_post(pdev);
+ card->resume_post(card);
dev_dbg(card->dev, "resume work completed\n");
@@ -1185,10 +1259,9 @@ static void soc_resume_deferred(struct work_struct *work)
}
/* powers up audio subsystem after a suspend */
-static int soc_resume(struct device *dev)
+int snd_soc_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = dev_get_drvdata(dev);
int i;
/* AC97 devices might have other drivers hanging off them so
@@ -1210,9 +1283,10 @@ static int soc_resume(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_resume);
#else
-#define soc_suspend NULL
-#define soc_resume NULL
+#define snd_soc_suspend NULL
+#define snd_soc_resume NULL
#endif
static struct snd_soc_dai_ops null_dai_ops = {
@@ -1400,31 +1474,44 @@ static int soc_probe_codec(struct snd_soc_card *card,
struct snd_soc_codec *codec)
{
int ret = 0;
+ const struct snd_soc_codec_driver *driver = codec->driver;
codec->card = card;
codec->dapm.card = card;
soc_set_name_prefix(card, codec);
- if (codec->driver->probe) {
- ret = codec->driver->probe(codec);
+ if (!try_module_get(codec->dev->driver->owner))
+ return -ENODEV;
+
+ if (driver->probe) {
+ ret = driver->probe(codec);
if (ret < 0) {
dev_err(codec->dev,
"asoc: failed to probe CODEC %s: %d\n",
codec->name, ret);
- return ret;
+ goto err_probe;
}
}
+ if (driver->dapm_widgets)
+ snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets,
+ driver->num_dapm_widgets);
+ if (driver->dapm_routes)
+ snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes,
+ driver->num_dapm_routes);
+
soc_init_codec_debugfs(codec);
/* mark codec as probed and add to card codec list */
- if (!try_module_get(codec->dev->driver->owner))
- return -ENODEV;
-
codec->probed = 1;
list_add(&codec->card_list, &card->codec_dev_list);
list_add(&codec->dapm.list, &card->dapm_list);
+ return 0;
+
+err_probe:
+ module_put(codec->dev->driver->owner);
+
return ret;
}
@@ -1468,7 +1555,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
/* Make sure all DAPM widgets are instantiated */
snd_soc_dapm_new_widgets(&codec->dapm);
- snd_soc_dapm_sync(&codec->dapm);
/* register the rtd device */
rtd->codec = codec;
@@ -1543,19 +1629,19 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
/* probe the platform */
if (!platform->probed) {
+ if (!try_module_get(platform->dev->driver->owner))
+ return -ENODEV;
+
if (platform->driver->probe) {
ret = platform->driver->probe(platform);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to probe platform %s\n",
platform->name);
+ module_put(platform->dev->driver->owner);
return ret;
}
}
/* mark platform as probed and add to card platform list */
-
- if (!try_module_get(platform->dev->driver->owner))
- return -ENODEV;
-
platform->probed = 1;
list_add(&platform->card_list, &card->platform_dev_list);
}
@@ -1713,7 +1799,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
static void snd_soc_instantiate_card(struct snd_soc_card *card)
{
- struct platform_device *pdev = to_platform_device(card->dev);
struct snd_soc_codec *codec;
struct snd_soc_codec_conf *codec_conf;
enum snd_soc_compress_type compress_type;
@@ -1740,6 +1825,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
list_for_each_entry(codec, &codec_list, list) {
if (codec->cache_init)
continue;
+ /* by default we don't override the compress_type */
+ compress_type = 0;
/* check to see if we need to override the compress_type */
for (i = 0; i < card->num_configs; ++i) {
codec_conf = &card->codec_conf[i];
@@ -1750,18 +1837,6 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
break;
}
}
- if (i == card->num_configs) {
- /* no need to override the compress_type so
- * go ahead and do the standard thing */
- ret = snd_soc_init_codec_cache(codec, 0);
- if (ret < 0) {
- mutex_unlock(&card->mutex);
- return;
- }
- continue;
- }
- /* override the compress_type with the one supplied in
- * the machine driver */
ret = snd_soc_init_codec_cache(codec, compress_type);
if (ret < 0) {
mutex_unlock(&card->mutex);
@@ -1780,14 +1855,19 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
card->snd_card->dev = card->dev;
-#ifdef CONFIG_PM
+ card->dapm.bias_level = SND_SOC_BIAS_OFF;
+ card->dapm.dev = card->dev;
+ card->dapm.card = card;
+ list_add(&card->dapm.list, &card->dapm_list);
+
+#ifdef CONFIG_PM_SLEEP
/* deferred resume work */
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
#endif
/* initialise the sound card only once */
if (card->probe) {
- ret = card->probe(pdev);
+ ret = card->probe(card);
if (ret < 0)
goto card_probe_error;
}
@@ -1810,11 +1890,37 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
+ if (card->dapm_widgets)
+ snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
+ card->num_dapm_widgets);
+ if (card->dapm_routes)
+ snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
+ card->num_dapm_routes);
+
+#ifdef CONFIG_DEBUG_FS
+ card->dapm.debugfs_dapm = debugfs_create_dir("dapm",
+ card->debugfs_card_root);
+ if (!card->dapm.debugfs_dapm)
+ printk(KERN_WARNING
+ "Failed to create card DAPM debugfs directory\n");
+
+ snd_soc_dapm_debugfs_init(&card->dapm);
+#endif
+
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
"%s", card->name);
+ if (card->late_probe) {
+ ret = card->late_probe(card);
+ if (ret < 0) {
+ dev_err(card->dev, "%s late_probe() failed: %d\n",
+ card->name, ret);
+ goto probe_aux_dev_err;
+ }
+ }
+
ret = snd_card_register(card->snd_card);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
@@ -1848,7 +1954,7 @@ probe_dai_err:
card_probe_error:
if (card->remove)
- card->remove(pdev);
+ card->remove(card);
snd_card_free(card->snd_card);
@@ -1872,16 +1978,15 @@ static int soc_probe(struct platform_device *pdev)
struct snd_soc_card *card = platform_get_drvdata(pdev);
int ret = 0;
+ /*
+ * no card, so machine driver should be registering card
+ * we should not be here in that case so ret error
+ */
+ if (!card)
+ return -EINVAL;
+
/* Bodge while we unpick instantiation */
card->dev = &pdev->dev;
- INIT_LIST_HEAD(&card->dai_dev_list);
- INIT_LIST_HEAD(&card->codec_dev_list);
- INIT_LIST_HEAD(&card->platform_dev_list);
- INIT_LIST_HEAD(&card->widgets);
- INIT_LIST_HEAD(&card->paths);
- INIT_LIST_HEAD(&card->dapm_list);
-
- soc_init_card_debugfs(card);
ret = snd_soc_register_card(card);
if (ret != 0) {
@@ -1892,45 +1997,48 @@ static int soc_probe(struct platform_device *pdev)
return 0;
}
-/* removes a socdev */
-static int soc_remove(struct platform_device *pdev)
+static int soc_cleanup_card_resources(struct snd_soc_card *card)
{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
int i;
- if (card->instantiated) {
+ /* make sure any delayed work runs */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+ flush_delayed_work_sync(&rtd->delayed_work);
+ }
- /* make sure any delayed work runs */
- for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
- flush_delayed_work_sync(&rtd->delayed_work);
- }
+ /* remove auxiliary devices */
+ for (i = 0; i < card->num_aux_devs; i++)
+ soc_remove_aux_dev(card, i);
- /* remove auxiliary devices */
- for (i = 0; i < card->num_aux_devs; i++)
- soc_remove_aux_dev(card, i);
+ /* remove and free each DAI */
+ for (i = 0; i < card->num_rtd; i++)
+ soc_remove_dai_link(card, i);
- /* remove and free each DAI */
- for (i = 0; i < card->num_rtd; i++)
- soc_remove_dai_link(card, i);
+ soc_cleanup_card_debugfs(card);
- soc_cleanup_card_debugfs(card);
+ /* remove the card */
+ if (card->remove)
+ card->remove(card);
+
+ kfree(card->rtd);
+ snd_card_free(card->snd_card);
+ return 0;
- /* remove the card */
- if (card->remove)
- card->remove(pdev);
+}
+
+/* removes a socdev */
+static int soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
- kfree(card->rtd);
- snd_card_free(card->snd_card);
- }
snd_soc_unregister_card(card);
return 0;
}
-static int soc_poweroff(struct device *dev)
+int snd_soc_poweroff(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = dev_get_drvdata(dev);
int i;
if (!card->instantiated)
@@ -1947,11 +2055,12 @@ static int soc_poweroff(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_poweroff);
-static const struct dev_pm_ops soc_pm_ops = {
- .suspend = soc_suspend,
- .resume = soc_resume,
- .poweroff = soc_poweroff,
+const struct dev_pm_ops snd_soc_pm_ops = {
+ .suspend = snd_soc_suspend,
+ .resume = snd_soc_resume,
+ .poweroff = snd_soc_poweroff,
};
/* ASoC platform driver */
@@ -1959,7 +2068,7 @@ static struct platform_driver soc_driver = {
.driver = {
.name = "soc-audio",
.owner = THIS_MODULE,
- .pm = &soc_pm_ops,
+ .pm = &snd_soc_pm_ops,
},
.probe = soc_probe,
.remove = soc_remove,
@@ -2029,10 +2138,11 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
*
* Boolean function indiciating if a CODEC register is volatile.
*/
-int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
+int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
+ unsigned int reg)
{
- if (codec->driver->volatile_register)
- return codec->driver->volatile_register(reg);
+ if (codec->volatile_register)
+ return codec->volatile_register(codec, reg);
else
return 0;
}
@@ -2129,19 +2239,27 @@ EXPORT_SYMBOL_GPL(snd_soc_write);
*
* Writes new register value.
*
- * Returns 1 for change else 0.
+ * Returns 1 for change, 0 for no change, or negative error code.
*/
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned int mask, unsigned int value)
{
int change;
unsigned int old, new;
+ int ret;
- old = snd_soc_read(codec, reg);
+ ret = snd_soc_read(codec, reg);
+ if (ret < 0)
+ return ret;
+
+ old = ret;
new = (old & ~mask) | value;
change = old != new;
- if (change)
- snd_soc_write(codec, reg, new);
+ if (change) {
+ ret = snd_soc_write(codec, reg, new);
+ if (ret < 0)
+ return ret;
+ }
return change;
}
@@ -2226,22 +2344,45 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
* @_template: control template
* @data: control private data
* @long_name: control long name
+ * @prefix: control name prefix
*
* Create a new mixer control from a template control.
*
* Returns 0 for success, else error.
*/
struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
- void *data, char *long_name)
+ void *data, char *long_name,
+ const char *prefix)
{
struct snd_kcontrol_new template;
+ struct snd_kcontrol *kcontrol;
+ char *name = NULL;
+ int name_len;
memcpy(&template, _template, sizeof(template));
- if (long_name)
- template.name = long_name;
template.index = 0;
- return snd_ctl_new1(&template, data);
+ if (!long_name)
+ long_name = template.name;
+
+ if (prefix) {
+ name_len = strlen(long_name) + strlen(prefix) + 2;
+ name = kmalloc(name_len, GFP_ATOMIC);
+ if (!name)
+ return NULL;
+
+ snprintf(name, name_len, "%s %s", prefix, long_name);
+
+ template.name = name;
+ } else {
+ template.name = long_name;
+ }
+
+ kcontrol = snd_ctl_new1(&template, data);
+
+ kfree(name);
+
+ return kcontrol;
}
EXPORT_SYMBOL_GPL(snd_soc_cnew);
@@ -2260,22 +2401,16 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
const struct snd_kcontrol_new *controls, int num_controls)
{
struct snd_card *card = codec->card->snd_card;
- char prefixed_name[44], *name;
int err, i;
for (i = 0; i < num_controls; i++) {
const struct snd_kcontrol_new *control = &controls[i];
- if (codec->name_prefix) {
- snprintf(prefixed_name, sizeof(prefixed_name), "%s %s",
- codec->name_prefix, control->name);
- name = prefixed_name;
- } else {
- name = control->name;
- }
- err = snd_ctl_add(card, snd_soc_cnew(control, codec, name));
+ err = snd_ctl_add(card, snd_soc_cnew(control, codec,
+ control->name,
+ codec->name_prefix));
if (err < 0) {
dev_err(codec->dev, "%s: Failed to add %s: %d\n",
- codec->name, name, err);
+ codec->name, control->name, err);
return err;
}
}
@@ -2956,12 +3091,34 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
{
if (dai->driver && dai->driver->ops->set_sysclk)
return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
+ else if (dai->codec && dai->codec->driver->set_sysclk)
+ return dai->codec->driver->set_sysclk(dai->codec, clk_id,
+ freq, dir);
else
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
/**
+ * snd_soc_codec_set_sysclk - configure CODEC system or master clock.
+ * @codec: CODEC
+ * @clk_id: DAI specific clock ID
+ * @freq: new clock frequency in Hz
+ * @dir: new clock direction - input/output.
+ *
+ * Configures the CODEC master (MCLK) or system (SYSCLK) clocking.
+ */
+int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
+ unsigned int freq, int dir)
+{
+ if (codec->driver->set_sysclk)
+ return codec->driver->set_sysclk(codec, clk_id, freq, dir);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
+
+/**
* snd_soc_dai_set_clkdiv - configure DAI clock dividers.
* @dai: DAI
* @div_id: DAI specific clock divider ID
@@ -2997,11 +3154,35 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
if (dai->driver && dai->driver->ops->set_pll)
return dai->driver->ops->set_pll(dai, pll_id, source,
freq_in, freq_out);
+ else if (dai->codec && dai->codec->driver->set_pll)
+ return dai->codec->driver->set_pll(dai->codec, pll_id, source,
+ freq_in, freq_out);
else
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
+/*
+ * snd_soc_codec_set_pll - configure codec PLL.
+ * @codec: CODEC
+ * @pll_id: DAI specific PLL ID
+ * @source: DAI specific source for the PLL
+ * @freq_in: PLL input clock frequency in Hz
+ * @freq_out: requested PLL output clock frequency in Hz
+ *
+ * Configures and enables PLL to generate output clock based on input clock.
+ */
+int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ if (codec->driver->set_pll)
+ return codec->driver->set_pll(codec, pll_id, source,
+ freq_in, freq_out);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
+
/**
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
* @dai: DAI
@@ -3101,17 +3282,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
*
* @card: Card to register
*
- * Note that currently this is an internal only function: it will be
- * exposed to machine drivers after further backporting of ASoC v2
- * registration APIs.
*/
-static int snd_soc_register_card(struct snd_soc_card *card)
+int snd_soc_register_card(struct snd_soc_card *card)
{
int i;
if (!card->name || !card->dev)
return -EINVAL;
+ snd_soc_initialize_card_lists(card);
+
+ soc_init_card_debugfs(card);
+
card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
(card->num_links + card->num_aux_devs),
GFP_KERNEL);
@@ -3135,18 +3317,18 @@ static int snd_soc_register_card(struct snd_soc_card *card)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_register_card);
/**
* snd_soc_unregister_card - Unregister a card with the ASoC core
*
* @card: Card to unregister
*
- * Note that currently this is an internal only function: it will be
- * exposed to machine drivers after further backporting of ASoC v2
- * registration APIs.
*/
-static int snd_soc_unregister_card(struct snd_soc_card *card)
+int snd_soc_unregister_card(struct snd_soc_card *card)
{
+ if (card->instantiated)
+ soc_cleanup_card_resources(card);
mutex_lock(&client_mutex);
list_del(&card->list);
mutex_unlock(&client_mutex);
@@ -3154,6 +3336,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_card);
/*
* Simplify DAI link configuration by removing ".-1" from device names
@@ -3483,9 +3666,12 @@ int snd_soc_register_codec(struct device *dev,
codec->write = codec_drv->write;
codec->read = codec_drv->read;
+ codec->volatile_register = codec_drv->volatile_register;
+ codec->readable_register = codec_drv->readable_register;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
+ codec->dapm.seq_notifier = codec_drv->seq_notifier;
codec->dev = dev;
codec->driver = codec_drv;
codec->num_dai = num_dai;
@@ -3494,20 +3680,30 @@ int snd_soc_register_codec(struct device *dev,
/* allocate CODEC register cache */
if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+ codec->reg_size = reg_size;
/* it is necessary to make a copy of the default register cache
* because in the case of using a compression type that requires
* the default register cache to be marked as __devinitconst the
* kernel might have freed the array by the time we initialize
* the cache.
*/
- codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
- reg_size, GFP_KERNEL);
- if (!codec->reg_def_copy) {
- ret = -ENOMEM;
- goto fail;
+ if (codec_drv->reg_cache_default) {
+ codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
+ reg_size, GFP_KERNEL);
+ if (!codec->reg_def_copy) {
+ ret = -ENOMEM;
+ goto fail;
+ }
}
}
+ if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
+ if (!codec->volatile_register)
+ codec->volatile_register = snd_soc_default_volatile_register;
+ if (!codec->readable_register)
+ codec->readable_register = snd_soc_default_readable_register;
+ }
+
for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
fixup_codec_formats(&dai_drv[i].capture);
@@ -3574,22 +3770,22 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
- debugfs_root = debugfs_create_dir("asoc", NULL);
- if (IS_ERR(debugfs_root) || !debugfs_root) {
+ snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL);
+ if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) {
printk(KERN_WARNING
"ASoC: Failed to create debugfs directory\n");
- debugfs_root = NULL;
+ snd_soc_debugfs_root = NULL;
}
- if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+ if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL,
&codec_list_fops))
pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
- if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+ if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL,
&dai_list_fops))
pr_warn("ASoC: Failed to create DAI list debugfs file\n");
- if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+ if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL,
&platform_list_fops))
pr_warn("ASoC: Failed to create platform list debugfs file\n");
#endif
@@ -3601,7 +3797,7 @@ module_init(snd_soc_init);
static void __exit snd_soc_exit(void)
{
#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(debugfs_root);
+ debugfs_remove_recursive(snd_soc_debugfs_root);
#endif
platform_driver_unregister(&soc_driver);
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1790f83ee665..81c4052c127c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/async.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
@@ -125,17 +126,17 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
- * @card: audio device
+ * @dapm: DAPM context
* @level: level to configure
*
* Configure the bias (power) levels for the SoC audio device.
*
* Returns 0 for success else error.
*/
-static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
- struct snd_soc_dapm_context *dapm,
+static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
+ struct snd_soc_card *card = dapm->card;
int ret = 0;
switch (level) {
@@ -365,9 +366,20 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *w)
{
int i, ret = 0;
- size_t name_len;
+ size_t name_len, prefix_len;
struct snd_soc_dapm_path *path;
- struct snd_card *card = dapm->codec->card->snd_card;
+ struct snd_card *card = dapm->card->snd_card;
+ const char *prefix;
+
+ if (dapm->codec)
+ prefix = dapm->codec->name_prefix;
+ else
+ prefix = NULL;
+
+ if (prefix)
+ prefix_len = strlen(prefix) + 1;
+ else
+ prefix_len = 0;
/* add kcontrol */
for (i = 0; i < w->num_kcontrols; i++) {
@@ -396,8 +408,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
switch (w->id) {
default:
+ /* The control will get a prefix from
+ * the control creation process but
+ * we're also using the same prefix
+ * for widgets so cut the prefix off
+ * the front of the widget name.
+ */
snprintf(path->long_name, name_len, "%s %s",
- w->name, w->kcontrols[i].name);
+ w->name + prefix_len,
+ w->kcontrols[i].name);
break;
case snd_soc_dapm_mixer_named_ctl:
snprintf(path->long_name, name_len, "%s",
@@ -408,7 +427,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
path->long_name[name_len - 1] = '\0';
path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
- path->long_name);
+ path->long_name, prefix);
ret = snd_ctl_add(card, path->kcontrol);
if (ret < 0) {
dev_err(dapm->dev,
@@ -429,7 +448,9 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_path *path = NULL;
struct snd_kcontrol *kcontrol;
- struct snd_card *card = dapm->codec->card->snd_card;
+ struct snd_card *card = dapm->card->snd_card;
+ const char *prefix;
+ size_t prefix_len;
int ret = 0;
if (!w->num_kcontrols) {
@@ -437,7 +458,22 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
return -EINVAL;
}
- kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
+ if (dapm->codec)
+ prefix = dapm->codec->name_prefix;
+ else
+ prefix = NULL;
+
+ if (prefix)
+ prefix_len = strlen(prefix) + 1;
+ else
+ prefix_len = 0;
+
+ /* The control will get a prefix from the control creation
+ * process but we're also using the same prefix for widgets so
+ * cut the prefix off the front of the widget name.
+ */
+ kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len,
+ prefix);
ret = snd_ctl_add(card, kcontrol);
if (ret < 0)
@@ -479,7 +515,7 @@ static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
*/
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
- int level = snd_power_get_state(widget->dapm->codec->card->snd_card);
+ int level = snd_power_get_state(widget->dapm->card->snd_card);
switch (level) {
case SNDRV_CTL_POWER_D3hot:
@@ -734,10 +770,23 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
struct snd_soc_dapm_widget *b,
- int sort[])
+ bool power_up)
{
+ int *sort;
+
+ if (power_up)
+ sort = dapm_up_seq;
+ else
+ sort = dapm_down_seq;
+
if (sort[a->id] != sort[b->id])
return sort[a->id] - sort[b->id];
+ if (a->subseq != b->subseq) {
+ if (power_up)
+ return a->subseq - b->subseq;
+ else
+ return b->subseq - a->subseq;
+ }
if (a->reg != b->reg)
return a->reg - b->reg;
if (a->dapm != b->dapm)
@@ -749,12 +798,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
/* Insert a widget in order into a DAPM power sequence. */
static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
struct list_head *list,
- int sort[])
+ bool power_up)
{
struct snd_soc_dapm_widget *w;
list_for_each_entry(w, list, power_list)
- if (dapm_seq_compare(new_widget, w, sort) < 0) {
+ if (dapm_seq_compare(new_widget, w, power_up) < 0) {
list_add_tail(&new_widget->power_list, &w->power_list);
return;
}
@@ -865,26 +914,42 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
* handled.
*/
static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
- struct list_head *list, int event, int sort[])
+ struct list_head *list, int event, bool power_up)
{
struct snd_soc_dapm_widget *w, *n;
LIST_HEAD(pending);
int cur_sort = -1;
+ int cur_subseq = -1;
int cur_reg = SND_SOC_NOPM;
struct snd_soc_dapm_context *cur_dapm = NULL;
- int ret;
+ int ret, i;
+ int *sort;
+
+ if (power_up)
+ sort = dapm_up_seq;
+ else
+ sort = dapm_down_seq;
list_for_each_entry_safe(w, n, list, power_list) {
ret = 0;
/* Do we need to apply any queued changes? */
if (sort[w->id] != cur_sort || w->reg != cur_reg ||
- w->dapm != cur_dapm) {
+ w->dapm != cur_dapm || w->subseq != cur_subseq) {
if (!list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
+ if (cur_dapm && cur_dapm->seq_notifier) {
+ for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
+ if (sort[i] == cur_sort)
+ cur_dapm->seq_notifier(cur_dapm,
+ i,
+ cur_subseq);
+ }
+
INIT_LIST_HEAD(&pending);
cur_sort = -1;
+ cur_subseq = -1;
cur_reg = SND_SOC_NOPM;
cur_dapm = NULL;
}
@@ -929,6 +994,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
default:
/* Queue it up for application */
cur_sort = sort[w->id];
+ cur_subseq = w->subseq;
cur_reg = w->reg;
cur_dapm = w->dapm;
list_move(&w->power_list, &pending);
@@ -942,6 +1008,13 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
if (!list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
+
+ if (cur_dapm && cur_dapm->seq_notifier) {
+ for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
+ if (sort[i] == cur_sort)
+ cur_dapm->seq_notifier(cur_dapm,
+ i, cur_subseq);
+ }
}
static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
@@ -977,7 +1050,62 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
}
}
+/* Async callback run prior to DAPM sequences - brings to _PREPARE if
+ * they're changing state.
+ */
+static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
+{
+ struct snd_soc_dapm_context *d = data;
+ int ret;
+ if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
+ ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
+ if (ret != 0)
+ dev_err(d->dev,
+ "Failed to turn on bias: %d\n", ret);
+ }
+
+ /* If we're changing to all on or all off then prepare */
+ if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
+ (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
+ ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
+ if (ret != 0)
+ dev_err(d->dev,
+ "Failed to prepare bias: %d\n", ret);
+ }
+}
+
+/* Async callback run prior to DAPM sequences - brings to their final
+ * state.
+ */
+static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
+{
+ struct snd_soc_dapm_context *d = data;
+ int ret;
+
+ /* If we just powered the last thing off drop to standby bias */
+ if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
+ ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
+ if (ret != 0)
+ dev_err(d->dev, "Failed to apply standby bias: %d\n",
+ ret);
+ }
+
+ /* If we're in standby and can support bias off then do that */
+ if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) {
+ ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
+ if (ret != 0)
+ dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
+ }
+
+ /* If we just powered up then move to active bias */
+ if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
+ ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
+ if (ret != 0)
+ dev_err(d->dev, "Failed to apply active bias: %d\n",
+ ret);
+ }
+}
/*
* Scan each dapm widget for complete audio path.
@@ -990,12 +1118,12 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
*/
static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
{
- struct snd_soc_card *card = dapm->codec->card;
+ struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_context *d;
LIST_HEAD(up_list);
LIST_HEAD(down_list);
- int ret = 0;
+ LIST_HEAD(async_domain);
int power;
trace_snd_soc_dapm_start(card);
@@ -1010,10 +1138,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
list_for_each_entry(w, &card->widgets, list) {
switch (w->id) {
case snd_soc_dapm_pre:
- dapm_seq_insert(w, &down_list, dapm_down_seq);
+ dapm_seq_insert(w, &down_list, false);
break;
case snd_soc_dapm_post:
- dapm_seq_insert(w, &up_list, dapm_up_seq);
+ dapm_seq_insert(w, &up_list, true);
break;
default:
@@ -1033,9 +1161,9 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_widget_power(w, power);
if (power)
- dapm_seq_insert(w, &up_list, dapm_up_seq);
+ dapm_seq_insert(w, &up_list, true);
else
- dapm_seq_insert(w, &down_list, dapm_down_seq);
+ dapm_seq_insert(w, &down_list, false);
w->power = power;
break;
@@ -1073,65 +1201,25 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
}
}
- list_for_each_entry(d, &dapm->card->dapm_list, list) {
- if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_dapm_set_bias_level(card, d,
- SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- dev_err(d->dev,
- "Failed to turn on bias: %d\n", ret);
- }
-
- /* If we're changing to all on or all off then prepare */
- if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
- (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
- ret = snd_soc_dapm_set_bias_level(card, d,
- SND_SOC_BIAS_PREPARE);
- if (ret != 0)
- dev_err(d->dev,
- "Failed to prepare bias: %d\n", ret);
- }
- }
+ /* Run all the bias changes in parallel */
+ list_for_each_entry(d, &dapm->card->dapm_list, list)
+ async_schedule_domain(dapm_pre_sequence_async, d,
+ &async_domain);
+ async_synchronize_full_domain(&async_domain);
/* Power down widgets first; try to avoid amplifying pops. */
- dapm_seq_run(dapm, &down_list, event, dapm_down_seq);
+ dapm_seq_run(dapm, &down_list, event, false);
dapm_widget_update(dapm);
/* Now power up. */
- dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
-
- list_for_each_entry(d, &dapm->card->dapm_list, list) {
- /* If we just powered the last thing off drop to standby bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
- ret = snd_soc_dapm_set_bias_level(card, d,
- SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- dev_err(d->dev,
- "Failed to apply standby bias: %d\n",
- ret);
- }
+ dapm_seq_run(dapm, &up_list, event, true);
- /* If we're in standby and can support bias off then do that */
- if (d->bias_level == SND_SOC_BIAS_STANDBY &&
- d->idle_bias_off) {
- ret = snd_soc_dapm_set_bias_level(card, d,
- SND_SOC_BIAS_OFF);
- if (ret != 0)
- dev_err(d->dev,
- "Failed to turn off bias: %d\n", ret);
- }
-
- /* If we just powered up then move to active bias */
- if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
- ret = snd_soc_dapm_set_bias_level(card, d,
- SND_SOC_BIAS_ON);
- if (ret != 0)
- dev_err(d->dev,
- "Failed to apply active bias: %d\n",
- ret);
- }
- }
+ /* Run all the bias changes in parallel */
+ list_for_each_entry(d, &dapm->card->dapm_list, list)
+ async_schedule_domain(dapm_post_sequence_async, d,
+ &async_domain);
+ async_synchronize_full_domain(&async_domain);
pop_dbg(dapm->dev, card->pop_time,
"DAPM sequencing finished, waiting %dms\n", card->pop_time);
@@ -1189,7 +1277,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
- " in %s %s\n",
+ " in \"%s\" \"%s\"\n",
p->name ? p->name : "static",
p->source->name);
}
@@ -1199,7 +1287,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
- " out %s %s\n",
+ " out \"%s\" \"%s\"\n",
p->name ? p->name : "static",
p->sink->name);
}
@@ -1464,7 +1552,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
char prefixed_source[80];
int ret = 0;
- if (dapm->codec->name_prefix) {
+ if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
@@ -2114,14 +2202,14 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
return -ENOMEM;
name_len = strlen(widget->name) + 1;
- if (dapm->codec->name_prefix)
+ if (dapm->codec && dapm->codec->name_prefix)
name_len += 1 + strlen(dapm->codec->name_prefix);
w->name = kmalloc(name_len, GFP_KERNEL);
if (w->name == NULL) {
kfree(w);
return -ENOMEM;
}
- if (dapm->codec->name_prefix)
+ if (dapm->codec && dapm->codec->name_prefix)
snprintf(w->name, name_len, "%s %s",
dapm->codec->name_prefix, widget->name);
else
@@ -2226,7 +2314,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
mutex_unlock(&codec->mutex);
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
/**
* snd_soc_dapm_enable_pin - enable pin.
@@ -2393,7 +2480,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
if (w->dapm != dapm)
continue;
if (w->power) {
- dapm_seq_insert(w, &down_list, dapm_down_seq);
+ dapm_seq_insert(w, &down_list, false);
w->power = 0;
powerdown = 1;
}
@@ -2403,9 +2490,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
* standby.
*/
if (powerdown) {
- snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE);
- dapm_seq_run(dapm, &down_list, 0, dapm_down_seq);
- snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_STANDBY);
+ snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
+ dapm_seq_run(dapm, &down_list, 0, false);
+ snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
}
}
@@ -2418,7 +2505,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
list_for_each_entry(codec, &card->codec_dev_list, list) {
soc_dapm_shutdown_codec(&codec->dapm);
- snd_soc_dapm_set_bias_level(card, &codec->dapm, SND_SOC_BIAS_OFF);
+ snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
}
}
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ac5a5bc7375a..fcab80b36a37 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -37,6 +37,7 @@ int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
{
jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
+ INIT_LIST_HEAD(&jack->jack_zones);
BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
return snd_jack_new(codec->card->snd_card, id, type, &jack->jack);
@@ -100,7 +101,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
}
/* Report before the DAPM sync to help users updating micbias status */
- blocking_notifier_call_chain(&jack->notifier, status, NULL);
+ blocking_notifier_call_chain(&jack->notifier, status, jack);
snd_soc_dapm_sync(dapm);
@@ -112,6 +113,51 @@ out:
EXPORT_SYMBOL_GPL(snd_soc_jack_report);
/**
+ * snd_soc_jack_add_zones - Associate voltage zones with jack
+ *
+ * @jack: ASoC jack
+ * @count: Number of zones
+ * @zone: Array of zones
+ *
+ * After this function has been called the zones specified in the
+ * array will be associated with the jack.
+ */
+int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_zone *zones)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ INIT_LIST_HEAD(&zones[i].list);
+ list_add(&(zones[i].list), &jack->jack_zones);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_zones);
+
+/**
+ * snd_soc_jack_get_type - Based on the mic bias value, this function returns
+ * the type of jack from the zones delcared in the jack type
+ *
+ * @micbias_voltage: mic bias voltage at adc channel when jack is plugged in
+ *
+ * Based on the mic bias value passed, this function helps identify
+ * the type of jack from the already delcared jack zones
+ */
+int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage)
+{
+ struct snd_soc_jack_zone *zone;
+
+ list_for_each_entry(zone, &jack->jack_zones, list) {
+ if (micbias_voltage >= zone->min_mv &&
+ micbias_voltage < zone->max_mv)
+ return zone->jack_type;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_get_type);
+
+/**
* snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack
*
* @jack: ASoC jack
@@ -194,7 +240,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
int enable;
int report;
- enable = gpio_get_value(gpio->gpio);
+ enable = gpio_get_value_cansleep(gpio->gpio);
if (gpio->invert)
enable = !enable;
@@ -284,6 +330,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
if (ret)
goto err;
+ if (gpios[i].wake) {
+ ret = set_irq_wake(gpio_to_irq(gpios[i].gpio), 1);
+ if (ret != 0)
+ printk(KERN_ERR
+ "Failed to mark GPIO %d as wake source: %d\n",
+ gpios[i].gpio, ret);
+ }
+
#ifdef CONFIG_GPIO_SYSFS
/* Expose GPIO value over sysfs for diagnostic purposes */
gpio_export(gpios[i].gpio, false);
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 1d07b931f3d8..3f45e6a439bf 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -28,26 +28,9 @@ int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params)
{
int sample_size;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
- sample_size = 16;
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
- sample_size = 20;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
- sample_size = 24;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- case SNDRV_PCM_FORMAT_S32_BE:
- sample_size = 32;
- break;
- default:
- return -ENOTSUPP;
- }
+ sample_size = snd_pcm_format_width(params_format(params));
+ if (sample_size < 0)
+ return sample_size;
return snd_soc_calc_frame_size(sample_size, params_channels(params),
1);
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
new file mode 100644
index 000000000000..66b504f06c23
--- /dev/null
+++ b/sound/soc/tegra/Kconfig
@@ -0,0 +1,26 @@
+config SND_TEGRA_SOC
+ tristate "SoC Audio for the Tegra System-on-Chip"
+ depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
+ default m
+ help
+ Say Y or M here if you want support for SoC audio on Tegra.
+
+config SND_TEGRA_SOC_I2S
+ tristate
+ depends on SND_TEGRA_SOC
+ default m
+ help
+ Say Y or M if you want to add support for codecs attached to the
+ Tegra I2S interface. You will also need to select the individual
+ machine drivers to support below.
+
+config SND_TEGRA_SOC_HARMONY
+ tristate "SoC Audio support for Tegra Harmony reference board"
+ depends on SND_TEGRA_SOC && MACH_HARMONY && I2C
+ default m
+ select SND_TEGRA_SOC_I2S
+ select SND_SOC_WM8903
+ help
+ Say Y or M here if you want to add support for SoC audio on the
+ Tegra Harmony reference board.
+
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
new file mode 100644
index 000000000000..fd183d3ab4f1
--- /dev/null
+++ b/sound/soc/tegra/Makefile
@@ -0,0 +1,15 @@
+# Tegra platform Support
+snd-soc-tegra-das-objs := tegra_das.o
+snd-soc-tegra-pcm-objs := tegra_pcm.o
+snd-soc-tegra-i2s-objs := tegra_i2s.o
+snd-soc-tegra-utils-objs += tegra_asoc_utils.o
+
+obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o
+obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o
+obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o
+
+# Tegra machine Support
+snd-soc-tegra-harmony-objs := harmony.o
+
+obj-$(CONFIG_SND_TEGRA_SOC_HARMONY) += snd-soc-tegra-harmony.o
diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c
new file mode 100644
index 000000000000..8585957477eb
--- /dev/null
+++ b/sound/soc/tegra/harmony.c
@@ -0,0 +1,393 @@
+/*
+ * harmony.c - Harmony machine ASoC driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+#include <mach/harmony_audio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8903.h"
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-harmony"
+
+#define GPIO_SPKR_EN BIT(0)
+#define GPIO_INT_MIC_EN BIT(1)
+#define GPIO_EXT_MIC_EN BIT(2)
+
+struct tegra_harmony {
+ struct tegra_asoc_utils_data util_data;
+ struct harmony_audio_platform_data *pdata;
+ int gpio_requested;
+};
+
+static int harmony_asoc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
+ int srate, mclk, mclk_change;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 64000:
+ case 88200:
+ case 96000:
+ mclk = 128 * srate;
+ break;
+ default:
+ mclk = 256 * srate;
+ break;
+ }
+ /* FIXME: Codec only requires >= 3MHz if OSR==0 */
+ while (mclk < 6000000)
+ mclk *= 2;
+
+ err = tegra_asoc_utils_set_rate(&harmony->util_data, srate, mclk,
+ &mclk_change);
+ if (err < 0) {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai fmt not set\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (err < 0) {
+ dev_err(card->dev, "cpu_dai fmt not set\n");
+ return err;
+ }
+
+ if (mclk_change) {
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops harmony_asoc_ops = {
+ .hw_params = harmony_asoc_hw_params,
+};
+
+static struct snd_soc_jack harmony_hp_jack;
+
+static struct snd_soc_jack_pin harmony_hp_jack_pins[] = {
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio harmony_hp_jack_gpios[] = {
+ {
+ .name = "headphone detect",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+ .invert = 1,
+ }
+};
+
+static struct snd_soc_jack harmony_mic_jack;
+
+static struct snd_soc_jack_pin harmony_mic_jack_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
+static int harmony_event_int_spk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
+ struct harmony_audio_platform_data *pdata = harmony->pdata;
+
+ gpio_set_value_cansleep(pdata->gpio_spkr_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget harmony_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Int Spk", harmony_event_int_spk),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route harmony_audio_map[] = {
+ {"Headphone Jack", NULL, "HPOUTR"},
+ {"Headphone Jack", NULL, "HPOUTL"},
+ {"Int Spk", NULL, "ROP"},
+ {"Int Spk", NULL, "RON"},
+ {"Int Spk", NULL, "LOP"},
+ {"Int Spk", NULL, "LON"},
+ {"Mic Bias", NULL, "Mic Jack"},
+ {"IN1L", NULL, "Mic Bias"},
+};
+
+static const struct snd_kcontrol_new harmony_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Int Spk"),
+};
+
+static int harmony_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
+ struct harmony_audio_platform_data *pdata = harmony->pdata;
+ int ret;
+
+ ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
+ if (ret) {
+ dev_err(card->dev, "cannot get spkr_en gpio\n");
+ return ret;
+ }
+ harmony->gpio_requested |= GPIO_SPKR_EN;
+
+ gpio_direction_output(pdata->gpio_spkr_en, 0);
+
+ ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en");
+ if (ret) {
+ dev_err(card->dev, "cannot get int_mic_en gpio\n");
+ return ret;
+ }
+ harmony->gpio_requested |= GPIO_INT_MIC_EN;
+
+ /* Disable int mic; enable signal is active-high */
+ gpio_direction_output(pdata->gpio_int_mic_en, 0);
+
+ ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en");
+ if (ret) {
+ dev_err(card->dev, "cannot get ext_mic_en gpio\n");
+ return ret;
+ }
+ harmony->gpio_requested |= GPIO_EXT_MIC_EN;
+
+ /* Enable ext mic; enable signal is active-low */
+ gpio_direction_output(pdata->gpio_ext_mic_en, 0);
+
+ ret = snd_soc_add_controls(codec, harmony_controls,
+ ARRAY_SIZE(harmony_controls));
+ if (ret < 0)
+ return ret;
+
+ snd_soc_dapm_new_controls(dapm, harmony_dapm_widgets,
+ ARRAY_SIZE(harmony_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, harmony_audio_map,
+ ARRAY_SIZE(harmony_audio_map));
+
+ harmony_hp_jack_gpios[0].gpio = pdata->gpio_hp_det;
+ snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+ &harmony_hp_jack);
+ snd_soc_jack_add_pins(&harmony_hp_jack,
+ ARRAY_SIZE(harmony_hp_jack_pins),
+ harmony_hp_jack_pins);
+ snd_soc_jack_add_gpios(&harmony_hp_jack,
+ ARRAY_SIZE(harmony_hp_jack_gpios),
+ harmony_hp_jack_gpios);
+
+ snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+ &harmony_mic_jack);
+ snd_soc_jack_add_pins(&harmony_mic_jack,
+ ARRAY_SIZE(harmony_mic_jack_pins),
+ harmony_mic_jack_pins);
+ wm8903_mic_detect(codec, &harmony_mic_jack, SND_JACK_MICROPHONE, 0);
+
+ snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+
+ snd_soc_dapm_nc_pin(dapm, "IN3L");
+ snd_soc_dapm_nc_pin(dapm, "IN3R");
+ snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
+ snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link harmony_wm8903_dai = {
+ .name = "WM8903",
+ .stream_name = "WM8903 PCM",
+ .codec_name = "wm8903.0-001a",
+ .platform_name = "tegra-pcm-audio",
+ .cpu_dai_name = "tegra-i2s.0",
+ .codec_dai_name = "wm8903-hifi",
+ .init = harmony_asoc_init,
+ .ops = &harmony_asoc_ops,
+};
+
+static struct snd_soc_card snd_soc_harmony = {
+ .name = "tegra-harmony",
+ .dai_link = &harmony_wm8903_dai,
+ .num_links = 1,
+};
+
+static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_harmony;
+ struct tegra_harmony *harmony;
+ struct harmony_audio_platform_data *pdata;
+ int ret;
+
+ if (!machine_is_harmony()) {
+ dev_err(&pdev->dev, "Not running on Tegra Harmony!\n");
+ return -ENODEV;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data supplied\n");
+ return -EINVAL;
+ }
+
+ harmony = kzalloc(sizeof(struct tegra_harmony), GFP_KERNEL);
+ if (!harmony) {
+ dev_err(&pdev->dev, "Can't allocate tegra_harmony\n");
+ return -ENOMEM;
+ }
+
+ harmony->pdata = pdata;
+
+ ret = tegra_asoc_utils_init(&harmony->util_data, &pdev->dev);
+ if (ret)
+ goto err_free_harmony;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, harmony);
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_clear_drvdata;
+ }
+
+ return 0;
+
+err_clear_drvdata:
+ snd_soc_card_set_drvdata(card, NULL);
+ platform_set_drvdata(pdev, NULL);
+ card->dev = NULL;
+ tegra_asoc_utils_fini(&harmony->util_data);
+err_free_harmony:
+ kfree(harmony);
+ return ret;
+}
+
+static int __devexit tegra_snd_harmony_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card);
+ struct harmony_audio_platform_data *pdata = harmony->pdata;
+
+ snd_soc_unregister_card(card);
+
+ snd_soc_card_set_drvdata(card, NULL);
+ platform_set_drvdata(pdev, NULL);
+ card->dev = NULL;
+
+ tegra_asoc_utils_fini(&harmony->util_data);
+
+ if (harmony->gpio_requested & GPIO_EXT_MIC_EN)
+ gpio_free(pdata->gpio_ext_mic_en);
+ if (harmony->gpio_requested & GPIO_INT_MIC_EN)
+ gpio_free(pdata->gpio_int_mic_en);
+ if (harmony->gpio_requested & GPIO_SPKR_EN)
+ gpio_free(pdata->gpio_spkr_en);
+
+ kfree(harmony);
+
+ return 0;
+}
+
+static struct platform_driver tegra_snd_harmony_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_snd_harmony_probe,
+ .remove = __devexit_p(tegra_snd_harmony_remove),
+};
+
+static int __init snd_tegra_harmony_init(void)
+{
+ return platform_driver_register(&tegra_snd_harmony_driver);
+}
+module_init(snd_tegra_harmony_init);
+
+static void __exit snd_tegra_harmony_exit(void)
+{
+ platform_driver_unregister(&tegra_snd_harmony_driver);
+}
+module_exit(snd_tegra_harmony_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Harmony machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
new file mode 100644
index 000000000000..52f0a3f9ce40
--- /dev/null
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -0,0 +1,155 @@
+/*
+ * tegra_asoc_utils.c - Harmony machine ASoC driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+
+#include "tegra_asoc_utils.h"
+
+int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
+ int mclk, int *mclk_change)
+{
+ int new_baseclock;
+ int err;
+
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ new_baseclock = 56448000;
+ break;
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ new_baseclock = 73728000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *mclk_change = ((new_baseclock != data->set_baseclock) ||
+ (mclk != data->set_mclk));
+ if (!*mclk_change)
+ return 0;
+
+ data->set_baseclock = 0;
+ data->set_mclk = 0;
+
+ clk_disable(data->clk_cdev1);
+ clk_disable(data->clk_pll_a_out0);
+ clk_disable(data->clk_pll_a);
+
+ err = clk_set_rate(data->clk_pll_a, new_baseclock);
+ if (err) {
+ dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
+ return err;
+ }
+
+ err = clk_set_rate(data->clk_pll_a_out0, mclk);
+ if (err) {
+ dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err);
+ return err;
+ }
+
+ /* Don't set cdev1 rate; its locked to pll_a_out0 */
+
+ err = clk_enable(data->clk_pll_a);
+ if (err) {
+ dev_err(data->dev, "Can't enable pll_a: %d\n", err);
+ return err;
+ }
+
+ err = clk_enable(data->clk_pll_a_out0);
+ if (err) {
+ dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
+ return err;
+ }
+
+ err = clk_enable(data->clk_cdev1);
+ if (err) {
+ dev_err(data->dev, "Can't enable cdev1: %d\n", err);
+ return err;
+ }
+
+ data->set_baseclock = new_baseclock;
+ data->set_mclk = mclk;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate);
+
+int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
+ struct device *dev)
+{
+ int ret;
+
+ data->dev = dev;
+
+ data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+ if (IS_ERR(data->clk_pll_a)) {
+ dev_err(data->dev, "Can't retrieve clk pll_a\n");
+ ret = PTR_ERR(data->clk_pll_a);
+ goto err;
+ }
+
+ data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+ if (IS_ERR(data->clk_pll_a_out0)) {
+ dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
+ ret = PTR_ERR(data->clk_pll_a_out0);
+ goto err_put_pll_a;
+ }
+
+ data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+ if (IS_ERR(data->clk_cdev1)) {
+ dev_err(data->dev, "Can't retrieve clk cdev1\n");
+ ret = PTR_ERR(data->clk_cdev1);
+ goto err_put_pll_a_out0;
+ }
+
+ return 0;
+
+err_put_pll_a_out0:
+ clk_put(data->clk_pll_a_out0);
+err_put_pll_a:
+ clk_put(data->clk_pll_a);
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_init);
+
+void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
+{
+ clk_put(data->clk_cdev1);
+ clk_put(data->clk_pll_a_out0);
+ clk_put(data->clk_pll_a);
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra ASoC utility code");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
new file mode 100644
index 000000000000..bbba7afdfc2c
--- /dev/null
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -0,0 +1,45 @@
+/*
+ * tegra_asoc_utils.h - Definitions for Tegra DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA_ASOC_UTILS_H__
+#define __TEGRA_ASOC_UTILS_H_
+
+struct clk;
+struct device;
+
+struct tegra_asoc_utils_data {
+ struct device *dev;
+ struct clk *clk_pll_a;
+ struct clk *clk_pll_a_out0;
+ struct clk *clk_cdev1;
+ int set_baseclock;
+ int set_mclk;
+};
+
+int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
+ int mclk, int *mclk_change);
+int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
+ struct device *dev);
+void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
+
+#endif
+
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
new file mode 100644
index 000000000000..9f24ef73f2cb
--- /dev/null
+++ b/sound/soc/tegra/tegra_das.c
@@ -0,0 +1,265 @@
+/*
+ * tegra_das.c - Tegra DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/iomap.h>
+#include <sound/soc.h>
+#include "tegra_das.h"
+
+#define DRV_NAME "tegra-das"
+
+static struct tegra_das *das;
+
+static inline void tegra_das_write(u32 reg, u32 val)
+{
+ __raw_writel(val, das->regs + reg);
+}
+
+static inline u32 tegra_das_read(u32 reg)
+{
+ return __raw_readl(das->regs + reg);
+}
+
+int tegra_das_connect_dap_to_dac(int dap, int dac)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA_DAS_DAP_CTRL_SEL +
+ (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
+ reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+
+ tegra_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
+
+int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
+ int sdata1rx, int sdata2rx)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA_DAS_DAP_CTRL_SEL +
+ (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
+ reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
+ !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
+ !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
+ !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
+
+ tegra_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
+
+int tegra_das_connect_dac_to_dap(int dac, int dap)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
+ (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+ reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
+ dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
+ dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
+
+ tegra_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra_das_show(struct seq_file *s, void *unused)
+{
+ int i;
+ u32 addr;
+ u32 reg;
+
+ for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
+ addr = TEGRA_DAS_DAP_CTRL_SEL +
+ (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
+ reg = tegra_das_read(addr);
+ seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
+ }
+
+ for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
+ addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
+ (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+ reg = tegra_das_read(addr);
+ seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
+ i, reg);
+ }
+
+ return 0;
+}
+
+static int tegra_das_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, tegra_das_show, inode->i_private);
+}
+
+static const struct file_operations tegra_das_debug_fops = {
+ .open = tegra_das_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void tegra_das_debug_add(struct tegra_das *das)
+{
+ das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
+ snd_soc_debugfs_root, das,
+ &tegra_das_debug_fops);
+}
+
+static void tegra_das_debug_remove(struct tegra_das *das)
+{
+ if (das->debug)
+ debugfs_remove(das->debug);
+}
+#else
+static inline void tegra_das_debug_add(struct tegra_das *das)
+{
+}
+
+static inline void tegra_das_debug_remove(struct tegra_das *das)
+{
+}
+#endif
+
+static int __devinit tegra_das_probe(struct platform_device *pdev)
+{
+ struct resource *res, *region;
+ int ret = 0;
+
+ if (das)
+ return -ENODEV;
+
+ das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL);
+ if (!das) {
+ dev_err(&pdev->dev, "Can't allocate tegra_das\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ das->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_free;
+ }
+
+ region = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!region) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ das->regs = ioremap(res->start, resource_size(res));
+ if (!das->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ tegra_das_debug_add(das);
+
+ platform_set_drvdata(pdev, das);
+
+ return 0;
+
+err_release:
+ release_mem_region(res->start, resource_size(res));
+err_free:
+ kfree(das);
+ das = 0;
+exit:
+ return ret;
+}
+
+static int __devexit tegra_das_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ if (!das)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, NULL);
+
+ tegra_das_debug_remove(das);
+
+ iounmap(das->regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(das);
+ das = 0;
+
+ return 0;
+}
+
+static struct platform_driver tegra_das_driver = {
+ .probe = tegra_das_probe,
+ .remove = __devexit_p(tegra_das_remove),
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init tegra_das_modinit(void)
+{
+ return platform_driver_register(&tegra_das_driver);
+}
+module_init(tegra_das_modinit);
+
+static void __exit tegra_das_modexit(void)
+{
+ platform_driver_unregister(&tegra_das_driver);
+}
+module_exit(tegra_das_modexit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra DAS driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
new file mode 100644
index 000000000000..2c96c7b3c459
--- /dev/null
+++ b/sound/soc/tegra/tegra_das.h
@@ -0,0 +1,135 @@
+/*
+ * tegra_das.h - Definitions for Tegra DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA_DAS_H__
+#define __TEGRA_DAS_H__
+
+/* Register TEGRA_DAS_DAP_CTRL_SEL */
+#define TEGRA_DAS_DAP_CTRL_SEL 0x00
+#define TEGRA_DAS_DAP_CTRL_SEL_COUNT 5
+#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE 4
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0
+#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5
+
+/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA_DAS_DAP_SEL_DAC1 0
+#define TEGRA_DAS_DAP_SEL_DAC2 1
+#define TEGRA_DAS_DAP_SEL_DAC3 2
+#define TEGRA_DAS_DAP_SEL_DAP1 16
+#define TEGRA_DAS_DAP_SEL_DAP2 17
+#define TEGRA_DAS_DAP_SEL_DAP3 18
+#define TEGRA_DAS_DAP_SEL_DAP4 19
+#define TEGRA_DAS_DAP_SEL_DAP5 20
+
+/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL 0x40
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0
+#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4
+
+/*
+ * Values for:
+ * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA_DAS_DAC_SEL_DAP1 0
+#define TEGRA_DAS_DAC_SEL_DAP2 1
+#define TEGRA_DAS_DAC_SEL_DAP3 2
+#define TEGRA_DAS_DAC_SEL_DAP4 3
+#define TEGRA_DAS_DAC_SEL_DAP5 4
+
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
+
+#define TEGRA_DAS_DAP_ID_1 0
+#define TEGRA_DAS_DAP_ID_2 1
+#define TEGRA_DAS_DAP_ID_3 2
+#define TEGRA_DAS_DAP_ID_4 3
+#define TEGRA_DAS_DAP_ID_5 4
+
+#define TEGRA_DAS_DAC_ID_1 0
+#define TEGRA_DAS_DAC_ID_2 1
+#define TEGRA_DAS_DAC_ID_3 2
+
+struct tegra_das {
+ struct device *dev;
+ void __iomem *regs;
+ struct dentry *debug;
+};
+
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
+
+/*
+ * Connect a DAP to to a DAC
+ * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
+ * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
+ */
+extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
+
+/*
+ * Connect a DAP to to another DAP
+ * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
+ * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
+ * master: Is this DAP the master (1) or slave (0)
+ * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
+ * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
+ */
+extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
+ int master, int sdata1rx,
+ int sdata2rx);
+
+/*
+ * Connect a DAC's input to a DAP
+ * (DAC outputs are selected by the DAP)
+ * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
+ * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
+ */
+extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
+
+#endif
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
new file mode 100644
index 000000000000..4f5e2c90b020
--- /dev/null
+++ b/sound/soc/tegra/tegra_i2s.c
@@ -0,0 +1,503 @@
+/*
+ * tegra_i2s.c - Tegra I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/iomap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_das.h"
+#include "tegra_i2s.h"
+
+#define DRV_NAME "tegra-i2s"
+
+static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
+{
+ __raw_writel(val, i2s->regs + reg);
+}
+
+static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
+{
+ return __raw_readl(i2s->regs + reg);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int tegra_i2s_show(struct seq_file *s, void *unused)
+{
+#define REG(r) { r, #r }
+ static const struct {
+ int offset;
+ const char *name;
+ } regs[] = {
+ REG(TEGRA_I2S_CTRL),
+ REG(TEGRA_I2S_STATUS),
+ REG(TEGRA_I2S_TIMING),
+ REG(TEGRA_I2S_FIFO_SCR),
+ REG(TEGRA_I2S_PCM_CTRL),
+ REG(TEGRA_I2S_NW_CTRL),
+ REG(TEGRA_I2S_TDM_CTRL),
+ REG(TEGRA_I2S_TDM_TX_RX_CTRL),
+ };
+#undef REG
+
+ struct tegra_i2s *i2s = s->private;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ u32 val = tegra_i2s_read(i2s, regs[i].offset);
+ seq_printf(s, "%s = %08x\n", regs[i].name, val);
+ }
+
+ return 0;
+}
+
+static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, tegra_i2s_show, inode->i_private);
+}
+
+static const struct file_operations tegra_i2s_debug_fops = {
+ .open = tegra_i2s_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id)
+{
+ char name[] = DRV_NAME ".0";
+
+ snprintf(name, sizeof(name), DRV_NAME".%1d", id);
+ i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root,
+ i2s, &tegra_i2s_debug_fops);
+}
+
+static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
+{
+ if (i2s->debug)
+ debugfs_remove(i2s->debug);
+}
+#else
+static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
+{
+}
+
+static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
+{
+}
+#endif
+
+static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK |
+ TEGRA_I2S_CTRL_LRCK_MASK);
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = substream->pcm->card->dev;
+ struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 reg;
+ int ret, sample_size, srate, i2sclock, bitcnt;
+
+ i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
+ sample_size = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
+ sample_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
+ sample_size = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ srate = params_rate(params);
+
+ /* Final "* 2" required by Tegra hardware */
+ i2sclock = srate * params_channels(params) * sample_size * 2;
+
+ ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+ return ret;
+ }
+
+ bitcnt = (i2sclock / (2 * srate)) - 1;
+ if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+ return -EINVAL;
+ reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+ if (i2sclock % (2 * srate))
+ reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
+
+ tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
+
+ tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
+ TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+ TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+
+ return 0;
+}
+
+static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
+{
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
+ tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
+{
+ i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
+ tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
+{
+ i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
+ tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
+{
+ i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
+ tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (!i2s->clk_refs)
+ clk_enable(i2s->clk_i2s);
+ i2s->clk_refs++;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra_i2s_start_playback(i2s);
+ else
+ tegra_i2s_start_capture(i2s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra_i2s_stop_playback(i2s);
+ else
+ tegra_i2s_stop_capture(i2s);
+ i2s->clk_refs--;
+ if (!i2s->clk_refs)
+ clk_disable(i2s->clk_i2s);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra_i2s_probe(struct snd_soc_dai *dai)
+{
+ struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
+
+ dai->capture_dma_data = &i2s->capture_dma_data;
+ dai->playback_dma_data = &i2s->playback_dma_data;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops tegra_i2s_dai_ops = {
+ .set_fmt = tegra_i2s_set_fmt,
+ .hw_params = tegra_i2s_hw_params,
+ .trigger = tegra_i2s_trigger,
+};
+
+struct snd_soc_dai_driver tegra_i2s_dai[] = {
+ {
+ .name = DRV_NAME ".0",
+ .probe = tegra_i2s_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra_i2s_dai_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = DRV_NAME ".1",
+ .probe = tegra_i2s_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra_i2s_dai_ops,
+ .symmetric_rates = 1,
+ },
+};
+
+static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
+{
+ struct tegra_i2s * i2s;
+ char clk_name[12]; /* tegra-i2s.0 */
+ struct resource *mem, *memregion, *dmareq;
+ int ret;
+
+ if ((pdev->id < 0) ||
+ (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) {
+ dev_err(&pdev->dev, "ID %d out of range\n", pdev->id);
+ return -EINVAL;
+ }
+
+ /*
+ * FIXME: Until a codec driver exists for the tegra DAS, hard-code a
+ * 1:1 mapping between audio controllers and audio ports.
+ */
+ ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id,
+ TEGRA_DAS_DAP_SEL_DAC1 + pdev->id);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't set up DAP connection\n");
+ return ret;
+ }
+ ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id,
+ TEGRA_DAS_DAC_SEL_DAP1 + pdev->id);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't set up DAC connection\n");
+ return ret;
+ }
+
+ i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL);
+ if (!i2s) {
+ dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ dev_set_drvdata(&pdev->dev, i2s);
+
+ snprintf(clk_name, sizeof(clk_name), DRV_NAME ".%d", pdev->id);
+ i2s->clk_i2s = clk_get_sys(clk_name, NULL);
+ if (IS_ERR(i2s->clk_i2s)) {
+ dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+ ret = PTR_ERR(i2s->clk_i2s);
+ goto err_free;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmareq) {
+ dev_err(&pdev->dev, "No DMA resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ memregion = request_mem_region(mem->start, resource_size(mem),
+ DRV_NAME);
+ if (!memregion) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_clk_put;
+ }
+
+ i2s->regs = ioremap(mem->start, resource_size(mem));
+ if (!i2s->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
+ i2s->capture_dma_data.wrap = 4;
+ i2s->capture_dma_data.width = 32;
+ i2s->capture_dma_data.req_sel = dmareq->start;
+
+ i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
+ i2s->playback_dma_data.wrap = 4;
+ i2s->playback_dma_data.width = 32;
+ i2s->playback_dma_data.req_sel = dmareq->start;
+
+ i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+ ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ goto err_unmap;
+ }
+
+ tegra_i2s_debug_add(i2s, pdev->id);
+
+ return 0;
+
+err_unmap:
+ iounmap(i2s->regs);
+err_release:
+ release_mem_region(mem->start, resource_size(mem));
+err_clk_put:
+ clk_put(i2s->clk_i2s);
+err_free:
+ kfree(i2s);
+exit:
+ return ret;
+}
+
+static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
+{
+ struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
+ struct resource *res;
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ tegra_i2s_debug_remove(i2s);
+
+ iounmap(i2s->regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_put(i2s->clk_i2s);
+
+ kfree(i2s);
+
+ return 0;
+}
+
+static struct platform_driver tegra_i2s_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_i2s_platform_probe,
+ .remove = __devexit_p(tegra_i2s_platform_remove),
+};
+
+static int __init snd_tegra_i2s_init(void)
+{
+ return platform_driver_register(&tegra_i2s_driver);
+}
+module_init(snd_tegra_i2s_init);
+
+static void __exit snd_tegra_i2s_exit(void)
+{
+ platform_driver_unregister(&tegra_i2s_driver);
+}
+module_exit(snd_tegra_i2s_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h
new file mode 100644
index 000000000000..2b38a096f46c
--- /dev/null
+++ b/sound/soc/tegra/tegra_i2s.h
@@ -0,0 +1,165 @@
+/*
+ * tegra_i2s.h - Definitions for Tegra I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA_I2S_H__
+#define __TEGRA_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */
+
+#define TEGRA_I2S_CTRL 0x00
+#define TEGRA_I2S_STATUS 0x04
+#define TEGRA_I2S_TIMING 0x08
+#define TEGRA_I2S_FIFO_SCR 0x0c
+#define TEGRA_I2S_PCM_CTRL 0x10
+#define TEGRA_I2S_NW_CTRL 0x14
+#define TEGRA_I2S_TDM_CTRL 0x20
+#define TEGRA_I2S_TDM_TX_RX_CTRL 0x24
+#define TEGRA_I2S_FIFO1 0x40
+#define TEGRA_I2S_FIFO2 0x80
+
+/* Fields in TEGRA_I2S_CTRL */
+
+#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30)
+#define TEGRA_I2S_CTRL_FIFO1_ENABLE (1 << 29)
+#define TEGRA_I2S_CTRL_FIFO2_ENABLE (1 << 28)
+#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27)
+#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26)
+#define TEGRA_I2S_CTRL_MASTER_ENABLE (1 << 25)
+
+#define TEGRA_I2S_LRCK_LEFT_LOW 0
+#define TEGRA_I2S_LRCK_RIGHT_LOW 1
+
+#define TEGRA_I2S_CTRL_LRCK_SHIFT 24
+#define TEGRA_I2S_CTRL_LRCK_MASK (1 << TEGRA_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA_I2S_CTRL_LRCK_L_LOW (TEGRA_I2S_LRCK_LEFT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA_I2S_CTRL_LRCK_R_LOW (TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA_I2S_BIT_FORMAT_I2S 0
+#define TEGRA_I2S_BIT_FORMAT_RJM 1
+#define TEGRA_I2S_BIT_FORMAT_LJM 2
+#define TEGRA_I2S_BIT_FORMAT_DSP 3
+
+#define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT 10
+#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S (TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM (TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM (TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP (TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
+
+#define TEGRA_I2S_BIT_SIZE_16 0
+#define TEGRA_I2S_BIT_SIZE_20 1
+#define TEGRA_I2S_BIT_SIZE_24 2
+#define TEGRA_I2S_BIT_SIZE_32 3
+
+#define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT 8
+#define TEGRA_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_SIZE_16 (TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_SIZE_20 (TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_SIZE_24 (TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA_I2S_CTRL_BIT_SIZE_32 (TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
+
+#define TEGRA_I2S_FIFO_16_LSB 0
+#define TEGRA_I2S_FIFO_20_LSB 1
+#define TEGRA_I2S_FIFO_24_LSB 2
+#define TEGRA_I2S_FIFO_32 3
+#define TEGRA_I2S_FIFO_PACKED 7
+
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT 4
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_32 (TEGRA_I2S_FIFO_32 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
+
+#define TEGRA_I2S_CTRL_IE_FIFO1_ERR (1 << 3)
+#define TEGRA_I2S_CTRL_IE_FIFO2_ERR (1 << 2)
+#define TEGRA_I2S_CTRL_QE_FIFO1 (1 << 1)
+#define TEGRA_I2S_CTRL_QE_FIFO2 (1 << 0)
+
+/* Fields in TEGRA_I2S_STATUS */
+
+#define TEGRA_I2S_STATUS_FIFO1_RDY (1 << 31)
+#define TEGRA_I2S_STATUS_FIFO2_RDY (1 << 30)
+#define TEGRA_I2S_STATUS_FIFO1_BSY (1 << 29)
+#define TEGRA_I2S_STATUS_FIFO2_BSY (1 << 28)
+#define TEGRA_I2S_STATUS_FIFO1_ERR (1 << 3)
+#define TEGRA_I2S_STATUS_FIFO2_ERR (1 << 2)
+#define TEGRA_I2S_STATUS_QS_FIFO1 (1 << 1)
+#define TEGRA_I2S_STATUS_QS_FIFO2 (1 << 0)
+
+/* Fields in TEGRA_I2S_TIMING */
+
+#define TEGRA_I2S_TIMING_NON_SYM_ENABLE (1 << 12)
+#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0
+#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff
+#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA_I2S_FIFO_SCR */
+
+#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24
+#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16
+#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f
+
+#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR (1 << 12)
+#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR (1 << 8)
+
+#define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT 0
+#define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1
+#define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2
+#define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3
+
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+
+struct tegra_i2s {
+ struct clk *clk_i2s;
+ int clk_refs;
+ struct tegra_pcm_dma_params capture_dma_data;
+ struct tegra_pcm_dma_params playback_dma_data;
+ void __iomem *regs;
+ struct dentry *debug;
+ u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
new file mode 100644
index 000000000000..3c271f953582
--- /dev/null
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -0,0 +1,404 @@
+/*
+ * tegra_pcm.c - Tegra PCM driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ * Vijay Mali <vmali@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_pcm.h"
+
+#define DRV_NAME "tegra-pcm-audio"
+
+static const struct snd_pcm_hardware tegra_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
+ SNDRV_PCM_INFO_INTERLEAVED,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_min = 1024,
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = 2,
+ .periods_max = 8,
+ .buffer_bytes_max = PAGE_SIZE * 8,
+ .fifo_size = 4,
+};
+
+static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
+{
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ struct tegra_dma_req *dma_req;
+ unsigned long addr;
+
+ dma_req = &prtd->dma_req[prtd->dma_req_idx];
+ prtd->dma_req_idx = 1 - prtd->dma_req_idx;
+
+ addr = buf->addr + prtd->dma_pos;
+ prtd->dma_pos += dma_req->size;
+ if (prtd->dma_pos >= prtd->dma_pos_end)
+ prtd->dma_pos = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dma_req->source_addr = addr;
+ else
+ dma_req->dest_addr = addr;
+
+ tegra_dma_enqueue_req(prtd->dma_chan, dma_req);
+}
+
+static void dma_complete_callback(struct tegra_dma_req *req)
+{
+ struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
+ struct snd_pcm_substream *substream = prtd->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ spin_lock(&prtd->lock);
+
+ if (!prtd->running) {
+ spin_unlock(&prtd->lock);
+ return;
+ }
+
+ if (++prtd->period_index >= runtime->periods)
+ prtd->period_index = 0;
+
+ tegra_pcm_queue_dma(prtd);
+
+ spin_unlock(&prtd->lock);
+
+ snd_pcm_period_elapsed(substream);
+}
+
+static void setup_dma_tx_request(struct tegra_dma_req *req,
+ struct tegra_pcm_dma_params * dmap)
+{
+ req->complete = dma_complete_callback;
+ req->to_memory = false;
+ req->dest_addr = dmap->addr;
+ req->dest_wrap = dmap->wrap;
+ req->source_bus_width = 32;
+ req->source_wrap = 0;
+ req->dest_bus_width = dmap->width;
+ req->req_sel = dmap->req_sel;
+}
+
+static void setup_dma_rx_request(struct tegra_dma_req *req,
+ struct tegra_pcm_dma_params * dmap)
+{
+ req->complete = dma_complete_callback;
+ req->to_memory = true;
+ req->source_addr = dmap->addr;
+ req->dest_wrap = 0;
+ req->source_bus_width = dmap->width;
+ req->source_wrap = dmap->wrap;
+ req->dest_bus_width = 32;
+ req->req_sel = dmap->req_sel;
+}
+
+static int tegra_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct tegra_runtime_data *prtd;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct tegra_pcm_dma_params * dmap;
+ int ret = 0;
+
+ prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
+ if (prtd == NULL)
+ return -ENOMEM;
+
+ runtime->private_data = prtd;
+ prtd->substream = substream;
+
+ spin_lock_init(&prtd->lock);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ setup_dma_tx_request(&prtd->dma_req[0], dmap);
+ setup_dma_tx_request(&prtd->dma_req[1], dmap);
+ } else {
+ dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ setup_dma_rx_request(&prtd->dma_req[0], dmap);
+ setup_dma_rx_request(&prtd->dma_req[1], dmap);
+ }
+
+ prtd->dma_req[0].dev = prtd;
+ prtd->dma_req[1].dev = prtd;
+
+ prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT);
+ if (prtd->dma_chan == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Set HW params now that initialization is complete */
+ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
+
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ if (prtd->dma_chan) {
+ tegra_dma_free_channel(prtd->dma_chan);
+ }
+
+ kfree(prtd);
+
+ return ret;
+}
+
+static int tegra_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct tegra_runtime_data *prtd = runtime->private_data;
+
+ tegra_dma_free_channel(prtd->dma_chan);
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct tegra_runtime_data *prtd = runtime->private_data;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+ prtd->dma_req[0].size = params_period_bytes(params);
+ prtd->dma_req[1].size = prtd->dma_req[0].size;
+
+ return 0;
+}
+
+static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+
+ return 0;
+}
+
+static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct tegra_runtime_data *prtd = runtime->private_data;
+ unsigned long flags;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ prtd->dma_pos = 0;
+ prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size);
+ prtd->period_index = 0;
+ prtd->dma_req_idx = 0;
+ /* Fall-through */
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->running = 1;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ tegra_pcm_queue_dma(prtd);
+ tegra_pcm_queue_dma(prtd);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->running = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]);
+ tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct tegra_runtime_data *prtd = runtime->private_data;
+
+ return prtd->period_index * runtime->period_size;
+}
+
+
+static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops tegra_pcm_ops = {
+ .open = tegra_pcm_open,
+ .close = tegra_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = tegra_pcm_hw_params,
+ .hw_free = tegra_pcm_hw_free,
+ .trigger = tegra_pcm_trigger,
+ .pointer = tegra_pcm_pointer,
+ .mmap = tegra_pcm_mmap,
+};
+
+static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = tegra_pcm_hardware.buffer_bytes_max;
+
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->bytes = size;
+
+ return 0;
+}
+
+static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+
+ if (!buf->area)
+ return;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+}
+
+static u64 tegra_dma_mask = DMA_BIT_MASK(32);
+
+static int tegra_pcm_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &tegra_dma_mask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->driver->playback.channels_min) {
+ ret = tegra_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto err;
+ }
+
+ if (dai->driver->capture.channels_min) {
+ ret = tegra_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto err_free_play;
+ }
+
+ return 0;
+
+err_free_play:
+ tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+err:
+ return ret;
+}
+
+static void tegra_pcm_free(struct snd_pcm *pcm)
+{
+ tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
+ tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+struct snd_soc_platform_driver tegra_pcm_platform = {
+ .ops = &tegra_pcm_ops,
+ .pcm_new = tegra_pcm_new,
+ .pcm_free = tegra_pcm_free,
+};
+
+static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
+}
+
+static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver tegra_pcm_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_pcm_platform_probe,
+ .remove = __devexit_p(tegra_pcm_platform_remove),
+};
+
+static int __init snd_tegra_pcm_init(void)
+{
+ return platform_driver_register(&tegra_pcm_driver);
+}
+module_init(snd_tegra_pcm_init);
+
+static void __exit snd_tegra_pcm_exit(void)
+{
+ platform_driver_unregister(&tegra_pcm_driver);
+}
+module_exit(snd_tegra_pcm_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra PCM ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
new file mode 100644
index 000000000000..dbb90339fe0d
--- /dev/null
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -0,0 +1,55 @@
+/*
+ * tegra_pcm.h - Definitions for Tegra PCM driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA_PCM_H__
+#define __TEGRA_PCM_H__
+
+#include <mach/dma.h>
+
+struct tegra_pcm_dma_params {
+ unsigned long addr;
+ unsigned long wrap;
+ unsigned long width;
+ unsigned long req_sel;
+};
+
+struct tegra_runtime_data {
+ struct snd_pcm_substream *substream;
+ spinlock_t lock;
+ int running;
+ int dma_pos;
+ int dma_pos_end;
+ int period_index;
+ int dma_req_idx;
+ struct tegra_dma_req dma_req[2];
+ struct tegra_dma_channel *dma_chan;
+};
+
+#endif
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 5580aced8730..6ce277860fd7 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -384,6 +384,9 @@ int register_sound_special_device(const struct file_operations *fops, int unit,
case 4:
name = "audio";
break;
+ case 5:
+ name = "dspW";
+ break;
case 8:
name = "sequencer2";
if (unit >= SOUND_STEP)
diff --git a/sound/usb/6fire/Makefile b/sound/usb/6fire/Makefile
new file mode 100644
index 000000000000..dfce6ec53513
--- /dev/null
+++ b/sound/usb/6fire/Makefile
@@ -0,0 +1,3 @@
+snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o
+obj-$(CONFIG_SND_USB_6FIRE) += snd-usb-6fire.o
+
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
new file mode 100644
index 000000000000..c7dca7b0b9fe
--- /dev/null
+++ b/sound/usb/6fire/chip.c
@@ -0,0 +1,232 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Main routines and module definitions.
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "chip.h"
+#include "firmware.h"
+#include "pcm.h"
+#include "control.h"
+#include "comm.h"
+#include "midi.h"
+
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
+MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable card */
+static struct sfire_chip *chips[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+static struct usb_device *devices[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for the 6fire sound device");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for the 6fire sound device.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable the 6fire sound device.");
+
+static DEFINE_MUTEX(register_mutex);
+
+static void usb6fire_chip_abort(struct sfire_chip *chip)
+{
+ if (chip) {
+ if (chip->pcm)
+ usb6fire_pcm_abort(chip);
+ if (chip->midi)
+ usb6fire_midi_abort(chip);
+ if (chip->comm)
+ usb6fire_comm_abort(chip);
+ if (chip->control)
+ usb6fire_control_abort(chip);
+ if (chip->card) {
+ snd_card_disconnect(chip->card);
+ snd_card_free_when_closed(chip->card);
+ chip->card = NULL;
+ }
+ }
+}
+
+static void usb6fire_chip_destroy(struct sfire_chip *chip)
+{
+ if (chip) {
+ if (chip->pcm)
+ usb6fire_pcm_destroy(chip);
+ if (chip->midi)
+ usb6fire_midi_destroy(chip);
+ if (chip->comm)
+ usb6fire_comm_destroy(chip);
+ if (chip->control)
+ usb6fire_control_destroy(chip);
+ if (chip->card)
+ snd_card_free(chip->card);
+ }
+}
+
+static int __devinit usb6fire_chip_probe(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
+{
+ int ret;
+ int i;
+ struct sfire_chip *chip = NULL;
+ struct usb_device *device = interface_to_usbdev(intf);
+ int regidx = -1; /* index in module parameter array */
+ struct snd_card *card = NULL;
+
+ /* look if we already serve this card and return if so */
+ mutex_lock(&register_mutex);
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ if (devices[i] == device) {
+ if (chips[i])
+ chips[i]->intf_count++;
+ usb_set_intfdata(intf, chips[i]);
+ mutex_unlock(&register_mutex);
+ return 0;
+ } else if (regidx < 0)
+ regidx = i;
+ }
+ if (regidx < 0) {
+ mutex_unlock(&register_mutex);
+ snd_printk(KERN_ERR PREFIX "too many cards registered.\n");
+ return -ENODEV;
+ }
+ devices[regidx] = device;
+ mutex_unlock(&register_mutex);
+
+ /* check, if firmware is present on device, upload it if not */
+ ret = usb6fire_fw_init(intf);
+ if (ret < 0)
+ return ret;
+ else if (ret == FW_NOT_READY) /* firmware update performed */
+ return 0;
+
+ /* if we are here, card can be registered in alsa. */
+ if (usb_set_interface(device, 0, 0) != 0) {
+ snd_printk(KERN_ERR PREFIX "can't set first interface.\n");
+ return -EIO;
+ }
+ ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE,
+ sizeof(struct sfire_chip), &card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n");
+ return ret;
+ }
+ strcpy(card->driver, "6FireUSB");
+ strcpy(card->shortname, "TerraTec DMX6FireUSB");
+ sprintf(card->longname, "%s at %d:%d", card->shortname,
+ device->bus->busnum, device->devnum);
+ snd_card_set_dev(card, &intf->dev);
+
+ chip = card->private_data;
+ chips[regidx] = chip;
+ chip->dev = device;
+ chip->regidx = regidx;
+ chip->intf_count = 1;
+ chip->card = card;
+
+ ret = usb6fire_comm_init(chip);
+ if (ret < 0) {
+ usb6fire_chip_destroy(chip);
+ return ret;
+ }
+
+ ret = usb6fire_midi_init(chip);
+ if (ret < 0) {
+ usb6fire_chip_destroy(chip);
+ return ret;
+ }
+
+ ret = usb6fire_pcm_init(chip);
+ if (ret < 0) {
+ usb6fire_chip_destroy(chip);
+ return ret;
+ }
+
+ ret = usb6fire_control_init(chip);
+ if (ret < 0) {
+ usb6fire_chip_destroy(chip);
+ return ret;
+ }
+
+ ret = snd_card_register(card);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "cannot register card.");
+ usb6fire_chip_destroy(chip);
+ return ret;
+ }
+ usb_set_intfdata(intf, chip);
+ return 0;
+}
+
+static void usb6fire_chip_disconnect(struct usb_interface *intf)
+{
+ struct sfire_chip *chip;
+ struct snd_card *card;
+
+ chip = usb_get_intfdata(intf);
+ if (chip) { /* if !chip, fw upload has been performed */
+ card = chip->card;
+ chip->intf_count--;
+ if (!chip->intf_count) {
+ mutex_lock(&register_mutex);
+ devices[chip->regidx] = NULL;
+ chips[chip->regidx] = NULL;
+ mutex_unlock(&register_mutex);
+
+ chip->shutdown = true;
+ usb6fire_chip_abort(chip);
+ usb6fire_chip_destroy(chip);
+ }
+ }
+}
+
+static struct usb_device_id device_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x0ccd,
+ .idProduct = 0x0080
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static struct usb_driver driver = {
+ .name = "snd-usb-6fire",
+ .probe = usb6fire_chip_probe,
+ .disconnect = usb6fire_chip_disconnect,
+ .id_table = device_table,
+};
+
+static int __init usb6fire_chip_init(void)
+{
+ return usb_register(&driver);
+}
+
+static void __exit usb6fire_chip_cleanup(void)
+{
+ usb_deregister(&driver);
+}
+
+module_init(usb6fire_chip_init);
+module_exit(usb6fire_chip_cleanup);
diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h
new file mode 100644
index 000000000000..d11e5cb520f0
--- /dev/null
+++ b/sound/usb/6fire/chip.h
@@ -0,0 +1,32 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef USB6FIRE_CHIP_H
+#define USB6FIRE_CHIP_H
+
+#include "common.h"
+
+struct sfire_chip {
+ struct usb_device *dev;
+ struct snd_card *card;
+ int intf_count; /* number of registered interfaces */
+ int regidx; /* index in module parameter arrays */
+ bool shutdown;
+
+ struct midi_runtime *midi;
+ struct pcm_runtime *pcm;
+ struct control_runtime *control;
+ struct comm_runtime *comm;
+};
+#endif /* USB6FIRE_CHIP_H */
+
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
new file mode 100644
index 000000000000..c994daa57af2
--- /dev/null
+++ b/sound/usb/6fire/comm.c
@@ -0,0 +1,176 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Device communications
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "comm.h"
+#include "chip.h"
+#include "midi.h"
+
+enum {
+ COMM_EP = 1,
+ COMM_FPGA_EP = 2
+};
+
+static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,
+ u8 *buffer, void *context, void(*handler)(struct urb *urb))
+{
+ usb_init_urb(urb);
+ urb->transfer_buffer = buffer;
+ urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
+ urb->complete = handler;
+ urb->context = context;
+ urb->interval = 1;
+ urb->dev = rt->chip->dev;
+}
+
+static void usb6fire_comm_receiver_handler(struct urb *urb)
+{
+ struct comm_runtime *rt = urb->context;
+ struct midi_runtime *midi_rt = rt->chip->midi;
+
+ if (!urb->status) {
+ if (rt->receiver_buffer[0] == 0x10) /* midi in event */
+ if (midi_rt)
+ midi_rt->in_received(midi_rt,
+ rt->receiver_buffer + 2,
+ rt->receiver_buffer[1]);
+ }
+
+ if (!rt->chip->shutdown) {
+ urb->status = 0;
+ urb->actual_length = 0;
+ if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
+ snd_printk(KERN_WARNING PREFIX
+ "comm data receiver aborted.\n");
+ }
+}
+
+static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,
+ u8 reg, u8 vl, u8 vh)
+{
+ buffer[0] = 0x01;
+ buffer[2] = request;
+ buffer[3] = id;
+ switch (request) {
+ case 0x02:
+ buffer[1] = 0x05; /* length (starting at buffer[2]) */
+ buffer[4] = reg;
+ buffer[5] = vl;
+ buffer[6] = vh;
+ break;
+
+ case 0x12:
+ buffer[1] = 0x0b; /* length (starting at buffer[2]) */
+ buffer[4] = 0x00;
+ buffer[5] = 0x18;
+ buffer[6] = 0x05;
+ buffer[7] = 0x00;
+ buffer[8] = 0x01;
+ buffer[9] = 0x00;
+ buffer[10] = 0x9e;
+ buffer[11] = reg;
+ buffer[12] = vl;
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ buffer[1] = 0x04;
+ buffer[4] = reg;
+ buffer[5] = vl;
+ break;
+ }
+}
+
+static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
+{
+ int ret;
+ int actual_len;
+
+ ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
+ buffer, buffer[1] + 2, &actual_len, HZ);
+ if (ret < 0)
+ return ret;
+ else if (actual_len != buffer[1] + 2)
+ return -EIO;
+ return 0;
+}
+
+static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
+ u8 reg, u8 value)
+{
+ u8 buffer[13]; /* 13: maximum length of message */
+
+ usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
+ return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+}
+
+static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
+ u8 reg, u8 vl, u8 vh)
+{
+ u8 buffer[13]; /* 13: maximum length of message */
+
+ usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
+ return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+}
+
+int __devinit usb6fire_comm_init(struct sfire_chip *chip)
+{
+ struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
+ GFP_KERNEL);
+ struct urb *urb = &rt->receiver;
+ int ret;
+
+ if (!rt)
+ return -ENOMEM;
+
+ rt->serial = 1;
+ rt->chip = chip;
+ usb_init_urb(urb);
+ rt->init_urb = usb6fire_comm_init_urb;
+ rt->write8 = usb6fire_comm_write8;
+ rt->write16 = usb6fire_comm_write16;
+
+ /* submit an urb that receives communication data from device */
+ urb->transfer_buffer = rt->receiver_buffer;
+ urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;
+ urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);
+ urb->dev = chip->dev;
+ urb->complete = usb6fire_comm_receiver_handler;
+ urb->context = rt;
+ urb->interval = 1;
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret < 0) {
+ kfree(rt);
+ snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
+ return ret;
+ }
+ chip->comm = rt;
+ return 0;
+}
+
+void usb6fire_comm_abort(struct sfire_chip *chip)
+{
+ struct comm_runtime *rt = chip->comm;
+
+ if (rt)
+ usb_poison_urb(&rt->receiver);
+}
+
+void usb6fire_comm_destroy(struct sfire_chip *chip)
+{
+ kfree(chip->comm);
+ chip->comm = NULL;
+}
diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h
new file mode 100644
index 000000000000..edc5dc84b888
--- /dev/null
+++ b/sound/usb/6fire/comm.h
@@ -0,0 +1,44 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef USB6FIRE_COMM_H
+#define USB6FIRE_COMM_H
+
+#include "common.h"
+
+enum /* settings for comm */
+{
+ COMM_RECEIVER_BUFSIZE = 64,
+};
+
+struct comm_runtime {
+ struct sfire_chip *chip;
+
+ struct urb receiver;
+ u8 receiver_buffer[COMM_RECEIVER_BUFSIZE];
+
+ u8 serial; /* urb serial */
+
+ void (*init_urb)(struct comm_runtime *rt, struct urb *urb, u8 *buffer,
+ void *context, void(*handler)(struct urb *urb));
+ /* writes control data to the device */
+ int (*write8)(struct comm_runtime *rt, u8 request, u8 reg, u8 value);
+ int (*write16)(struct comm_runtime *rt, u8 request, u8 reg,
+ u8 vh, u8 vl);
+};
+
+int __devinit usb6fire_comm_init(struct sfire_chip *chip);
+void usb6fire_comm_abort(struct sfire_chip *chip);
+void usb6fire_comm_destroy(struct sfire_chip *chip);
+#endif /* USB6FIRE_COMM_H */
+
diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h
new file mode 100644
index 000000000000..7dbeb4a37831
--- /dev/null
+++ b/sound/usb/6fire/common.h
@@ -0,0 +1,30 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef USB6FIRE_COMMON_H
+#define USB6FIRE_COMMON_H
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+
+#define PREFIX "6fire: "
+
+struct sfire_chip;
+struct midi_runtime;
+struct pcm_runtime;
+struct control_runtime;
+struct comm_runtime;
+#endif /* USB6FIRE_COMMON_H */
+
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
new file mode 100644
index 000000000000..248463511186
--- /dev/null
+++ b/sound/usb/6fire/control.c
@@ -0,0 +1,275 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Mixer control
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <sound/control.h>
+
+#include "control.h"
+#include "comm.h"
+#include "chip.h"
+
+static char *opt_coax_texts[2] = { "Optical", "Coax" };
+static char *line_phono_texts[2] = { "Line", "Phono" };
+
+/*
+ * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$
+ * this is done because the linear values cause rapid degredation
+ * of volume in the uppermost region.
+ */
+static const u8 log_volume_table[128] = {
+ 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34,
+ 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43,
+ 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
+ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56,
+ 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
+ 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
+ 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
+ 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c,
+ 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
+ 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75,
+ 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79,
+ 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
+ 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f };
+
+/*
+ * data that needs to be sent to device. sets up card internal stuff.
+ * values dumped from windows driver and filtered by trial'n'error.
+ */
+static const struct {
+ u8 type;
+ u8 reg;
+ u8 value;
+}
+init_data[] = {
+ { 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
+ { 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
+ { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
+ { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
+ { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
+ { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
+ { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
+ { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
+ { 0 } /* TERMINATING ENTRY */
+};
+
+static void usb6fire_control_master_vol_update(struct control_runtime *rt)
+{
+ struct comm_runtime *comm_rt = rt->chip->comm;
+ if (comm_rt) {
+ /* set volume */
+ comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f -
+ log_volume_table[rt->master_vol]);
+ /* unmute */
+ comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00);
+ }
+}
+
+static void usb6fire_control_line_phono_update(struct control_runtime *rt)
+{
+ struct comm_runtime *comm_rt = rt->chip->comm;
+ if (comm_rt) {
+ comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
+ comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
+ }
+}
+
+static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
+{
+ struct comm_runtime *comm_rt = rt->chip->comm;
+ if (comm_rt) {
+ comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
+ comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
+ }
+}
+
+static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 127;
+ return 0;
+}
+
+static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ if (rt->master_vol != ucontrol->value.integer.value[0]) {
+ rt->master_vol = ucontrol->value.integer.value[0];
+ usb6fire_control_master_vol_update(rt);
+ changed = 1;
+ }
+ return changed;
+}
+
+static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = rt->master_vol;
+ return 0;
+}
+
+static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ line_phono_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+ if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
+ rt->line_phono_switch = ucontrol->value.integer.value[0];
+ usb6fire_control_line_phono_update(rt);
+ changed = 1;
+ }
+ return changed;
+}
+
+static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.integer.value[0] = rt->line_phono_switch;
+ return 0;
+}
+
+static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ opt_coax_texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+ if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
+ rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
+ usb6fire_control_opt_coax_update(rt);
+ changed = 1;
+ }
+ return changed;
+}
+
+static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
+ ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
+ return 0;
+}
+
+static struct __devinitdata snd_kcontrol_new elements[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Master Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = usb6fire_control_master_vol_info,
+ .get = usb6fire_control_master_vol_get,
+ .put = usb6fire_control_master_vol_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Line/Phono Capture Route",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = usb6fire_control_line_phono_info,
+ .get = usb6fire_control_line_phono_get,
+ .put = usb6fire_control_line_phono_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Opt/Coax Capture Route",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = usb6fire_control_opt_coax_info,
+ .get = usb6fire_control_opt_coax_get,
+ .put = usb6fire_control_opt_coax_put
+ },
+ {}
+};
+
+int __devinit usb6fire_control_init(struct sfire_chip *chip)
+{
+ int i;
+ int ret;
+ struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
+ GFP_KERNEL);
+ struct comm_runtime *comm_rt = chip->comm;
+
+ if (!rt)
+ return -ENOMEM;
+
+ rt->chip = chip;
+
+ i = 0;
+ while (init_data[i].type) {
+ comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
+ init_data[i].value);
+ i++;
+ }
+
+ usb6fire_control_opt_coax_update(rt);
+ usb6fire_control_line_phono_update(rt);
+ usb6fire_control_master_vol_update(rt);
+
+ i = 0;
+ while (elements[i].name) {
+ ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
+ if (ret < 0) {
+ kfree(rt);
+ snd_printk(KERN_ERR PREFIX "cannot add control.\n");
+ return ret;
+ }
+ i++;
+ }
+
+ chip->control = rt;
+ return 0;
+}
+
+void usb6fire_control_abort(struct sfire_chip *chip)
+{}
+
+void usb6fire_control_destroy(struct sfire_chip *chip)
+{
+ kfree(chip->control);
+ chip->control = NULL;
+}
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h
new file mode 100644
index 000000000000..b534c777ab02
--- /dev/null
+++ b/sound/usb/6fire/control.h
@@ -0,0 +1,37 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef USB6FIRE_CONTROL_H
+#define USB6FIRE_CONTROL_H
+
+#include "common.h"
+
+enum {
+ CONTROL_MAX_ELEMENTS = 32
+};
+
+struct control_runtime {
+ struct sfire_chip *chip;
+
+ struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
+ bool opt_coax_switch;
+ bool line_phono_switch;
+ u8 master_vol;
+};
+
+int __devinit usb6fire_control_init(struct sfire_chip *chip);
+void usb6fire_control_abort(struct sfire_chip *chip);
+void usb6fire_control_destroy(struct sfire_chip *chip);
+#endif /* USB6FIRE_CONTROL_H */
+
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
new file mode 100644
index 000000000000..9081a54a9c6c
--- /dev/null
+++ b/sound/usb/6fire/firmware.c
@@ -0,0 +1,426 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Firmware loader
+ *
+ * Currently not working for all devices. To be able to use the device
+ * in linux, it is also possible to let the windows driver upload the firmware.
+ * For that, start the computer in windows and reboot.
+ * As long as the device is connected to the power supply, no firmware reload
+ * needs to be performed.
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/firmware.h>
+
+#include "firmware.h"
+#include "chip.h"
+
+MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
+MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
+MODULE_FIRMWARE("6fire/dmx6firecf.bin");
+
+enum {
+ FPGA_BUFSIZE = 512, FPGA_EP = 2
+};
+
+static const u8 BIT_REVERSE_TABLE[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50,
+ 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8,
+ 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04,
+ 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4,
+ 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c,
+ 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82,
+ 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32,
+ 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46,
+ 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6,
+ 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e,
+ 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
+ 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
+ 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99,
+ 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25,
+ 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d,
+ 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3,
+ 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b,
+ 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb,
+ 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67,
+ 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f,
+ 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f,
+ 0xbf, 0x7f, 0xff };
+
+/*
+ * wMaxPacketSize of pcm endpoints.
+ * keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
+ * fpp: frames per isopacket
+ *
+ * CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
+ */
+static const u8 ep_w_max_packet_size[] = {
+ 0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
+ 0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
+ 0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
+};
+
+struct ihex_record {
+ u16 address;
+ u8 len;
+ u8 data[256];
+ char error; /* true if an error occured parsing this record */
+
+ u8 max_len; /* maximum record length in whole ihex */
+
+ /* private */
+ const char *txt_data;
+ unsigned int txt_length;
+ unsigned int txt_offset; /* current position in txt_data */
+};
+
+static u8 usb6fire_fw_ihex_nibble(const u8 n)
+{
+ if (n >= '0' && n <= '9')
+ return n - '0';
+ else if (n >= 'A' && n <= 'F')
+ return n - ('A' - 10);
+ else if (n >= 'a' && n <= 'f')
+ return n - ('a' - 10);
+ return 0;
+}
+
+static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
+{
+ u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) |
+ usb6fire_fw_ihex_nibble(data[1]);
+ *crc += val;
+ return val;
+}
+
+/*
+ * returns true if record is available, false otherwise.
+ * iff an error occured, false will be returned and record->error will be true.
+ */
+static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
+{
+ u8 crc = 0;
+ u8 type;
+ int i;
+
+ record->error = false;
+
+ /* find begin of record (marked by a colon) */
+ while (record->txt_offset < record->txt_length
+ && record->txt_data[record->txt_offset] != ':')
+ record->txt_offset++;
+ if (record->txt_offset == record->txt_length)
+ return false;
+
+ /* number of characters needed for len, addr and type entries */
+ record->txt_offset++;
+ if (record->txt_offset + 8 > record->txt_length) {
+ record->error = true;
+ return false;
+ }
+
+ record->len = usb6fire_fw_ihex_hex(record->txt_data +
+ record->txt_offset, &crc);
+ record->txt_offset += 2;
+ record->address = usb6fire_fw_ihex_hex(record->txt_data +
+ record->txt_offset, &crc) << 8;
+ record->txt_offset += 2;
+ record->address |= usb6fire_fw_ihex_hex(record->txt_data +
+ record->txt_offset, &crc);
+ record->txt_offset += 2;
+ type = usb6fire_fw_ihex_hex(record->txt_data +
+ record->txt_offset, &crc);
+ record->txt_offset += 2;
+
+ /* number of characters needed for data and crc entries */
+ if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
+ record->error = true;
+ return false;
+ }
+ for (i = 0; i < record->len; i++) {
+ record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
+ + record->txt_offset, &crc);
+ record->txt_offset += 2;
+ }
+ usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
+ if (crc) {
+ record->error = true;
+ return false;
+ }
+
+ if (type == 1 || !record->len) /* eof */
+ return false;
+ else if (type == 0)
+ return true;
+ else {
+ record->error = true;
+ return false;
+ }
+}
+
+static int usb6fire_fw_ihex_init(const struct firmware *fw,
+ struct ihex_record *record)
+{
+ record->txt_data = fw->data;
+ record->txt_length = fw->size;
+ record->txt_offset = 0;
+ record->max_len = 0;
+ /* read all records, if loop ends, record->error indicates,
+ * whether ihex is valid. */
+ while (usb6fire_fw_ihex_next_record(record))
+ record->max_len = max(record->len, record->max_len);
+ if (record->error)
+ return -EINVAL;
+ record->txt_offset = 0;
+ return 0;
+}
+
+static int usb6fire_fw_ezusb_write(struct usb_device *device,
+ int type, int value, char *data, int len)
+{
+ int ret;
+
+ ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, 0, data, len, HZ);
+ if (ret < 0)
+ return ret;
+ else if (ret != len)
+ return -EIO;
+ return 0;
+}
+
+static int usb6fire_fw_ezusb_read(struct usb_device *device,
+ int type, int value, char *data, int len)
+{
+ int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
+ 0, data, len, HZ);
+ if (ret < 0)
+ return ret;
+ else if (ret != len)
+ return -EIO;
+ return 0;
+}
+
+static int usb6fire_fw_fpga_write(struct usb_device *device,
+ char *data, int len)
+{
+ int actual_len;
+ int ret;
+
+ ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
+ &actual_len, HZ);
+ if (ret < 0)
+ return ret;
+ else if (actual_len != len)
+ return -EIO;
+ return 0;
+}
+
+static int usb6fire_fw_ezusb_upload(
+ struct usb_interface *intf, const char *fwname,
+ unsigned int postaddr, u8 *postdata, unsigned int postlen)
+{
+ int ret;
+ u8 data;
+ struct usb_device *device = interface_to_usbdev(intf);
+ const struct firmware *fw = 0;
+ struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
+ GFP_KERNEL);
+
+ if (!rec)
+ return -ENOMEM;
+
+ ret = request_firmware(&fw, fwname, &device->dev);
+ if (ret < 0) {
+ kfree(rec);
+ snd_printk(KERN_ERR PREFIX "error requesting ezusb "
+ "firmware %s.\n", fwname);
+ return ret;
+ }
+ ret = usb6fire_fw_ihex_init(fw, rec);
+ if (ret < 0) {
+ kfree(rec);
+ snd_printk(KERN_ERR PREFIX "error validating ezusb "
+ "firmware %s.\n", fwname);
+ return ret;
+ }
+ /* upload firmware image */
+ data = 0x01; /* stop ezusb cpu */
+ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
+ if (ret < 0) {
+ kfree(rec);
+ release_firmware(fw);
+ snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
+ "firmware %s: begin message.\n", fwname);
+ return ret;
+ }
+
+ while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
+ ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
+ rec->data, rec->len);
+ if (ret < 0) {
+ kfree(rec);
+ release_firmware(fw);
+ snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
+ "firmware %s: data urb.\n", fwname);
+ return ret;
+ }
+ }
+
+ release_firmware(fw);
+ kfree(rec);
+ if (postdata) { /* write data after firmware has been uploaded */
+ ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
+ postdata, postlen);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
+ "firmware %s: post urb.\n", fwname);
+ return ret;
+ }
+ }
+
+ data = 0x00; /* resume ezusb cpu */
+ ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
+ if (ret < 0) {
+ release_firmware(fw);
+ snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
+ "firmware %s: end message.\n", fwname);
+ return ret;
+ }
+ return 0;
+}
+
+static int usb6fire_fw_fpga_upload(
+ struct usb_interface *intf, const char *fwname)
+{
+ int ret;
+ int i;
+ struct usb_device *device = interface_to_usbdev(intf);
+ u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
+ const char *c;
+ const char *end;
+ const struct firmware *fw;
+
+ if (!buffer)
+ return -ENOMEM;
+
+ ret = request_firmware(&fw, fwname, &device->dev);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
+ fwname);
+ kfree(buffer);
+ return -EIO;
+ }
+
+ c = fw->data;
+ end = fw->data + fw->size;
+
+ ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
+ if (ret < 0) {
+ kfree(buffer);
+ release_firmware(fw);
+ snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
+ "begin urb.\n");
+ return ret;
+ }
+
+ while (c != end) {
+ for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
+ buffer[i] = BIT_REVERSE_TABLE[(u8) *c];
+
+ ret = usb6fire_fw_fpga_write(device, buffer, i);
+ if (ret < 0) {
+ release_firmware(fw);
+ kfree(buffer);
+ snd_printk(KERN_ERR PREFIX "unable to upload fpga "
+ "firmware: fw urb.\n");
+ return ret;
+ }
+ }
+ release_firmware(fw);
+ kfree(buffer);
+
+ ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
+ "end urb.\n");
+ return ret;
+ }
+ return 0;
+}
+
+int usb6fire_fw_init(struct usb_interface *intf)
+{
+ int i;
+ int ret;
+ struct usb_device *device = interface_to_usbdev(intf);
+ /* buffer: 8 receiving bytes from device and
+ * sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
+ u8 buffer[12];
+
+ ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "unable to receive device "
+ "firmware state.\n");
+ return ret;
+ }
+ if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55
+ || buffer[4] != 0x03 || buffer[5] != 0x01 || buffer[7]
+ != 0x00) {
+ snd_printk(KERN_ERR PREFIX "unknown device firmware state "
+ "received from device: ");
+ for (i = 0; i < 8; i++)
+ snd_printk("%02x ", buffer[i]);
+ snd_printk("\n");
+ return -EIO;
+ }
+ /* do we need fpga loader ezusb firmware? */
+ if (buffer[3] == 0x01 && buffer[6] == 0x19) {
+ ret = usb6fire_fw_ezusb_upload(intf,
+ "6fire/dmx6firel2.ihx", 0, NULL, 0);
+ if (ret < 0)
+ return ret;
+ return FW_NOT_READY;
+ }
+ /* do we need fpga firmware and application ezusb firmware? */
+ else if (buffer[3] == 0x02 && buffer[6] == 0x0b) {
+ ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
+ if (ret < 0)
+ return ret;
+ memcpy(buffer, ep_w_max_packet_size,
+ sizeof(ep_w_max_packet_size));
+ ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
+ 0x0003, buffer, sizeof(ep_w_max_packet_size));
+ if (ret < 0)
+ return ret;
+ return FW_NOT_READY;
+ }
+ /* all fw loaded? */
+ else if (buffer[3] == 0x03 && buffer[6] == 0x0b)
+ return 0;
+ /* unknown data? */
+ else {
+ snd_printk(KERN_ERR PREFIX "unknown device firmware state "
+ "received from device: ");
+ for (i = 0; i < 8; i++)
+ snd_printk("%02x ", buffer[i]);
+ snd_printk("\n");
+ return -EIO;
+ }
+ return 0;
+}
+
diff --git a/sound/usb/6fire/firmware.h b/sound/usb/6fire/firmware.h
new file mode 100644
index 000000000000..008569895381
--- /dev/null
+++ b/sound/usb/6fire/firmware.h
@@ -0,0 +1,27 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk
+ * Created: Jan 01, 2011
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef USB6FIRE_FIRMWARE_H
+#define USB6FIRE_FIRMWARE_H
+
+#include "common.h"
+
+enum /* firmware state of device */
+{
+ FW_READY = 0,
+ FW_NOT_READY = 1
+};
+
+int __devinit usb6fire_fw_init(struct usb_interface *intf);
+#endif /* USB6FIRE_FIRMWARE_H */
+
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c
new file mode 100644
index 000000000000..13f4509dce2b
--- /dev/null
+++ b/sound/usb/6fire/midi.c
@@ -0,0 +1,203 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Rawmidi driver
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <sound/rawmidi.h>
+
+#include "midi.h"
+#include "chip.h"
+#include "comm.h"
+
+static void usb6fire_midi_out_handler(struct urb *urb)
+{
+ struct midi_runtime *rt = urb->context;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rt->out_lock, flags);
+
+ if (rt->out) {
+ ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4,
+ MIDI_BUFSIZE - 4);
+ if (ret > 0) { /* more data available, send next packet */
+ rt->out_buffer[1] = ret + 2;
+ rt->out_buffer[3] = rt->out_serial++;
+ urb->transfer_buffer_length = ret + 4;
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ snd_printk(KERN_ERR PREFIX "midi out urb "
+ "submit failed: %d\n", ret);
+ } else /* no more data to transmit */
+ rt->out = NULL;
+ }
+ spin_unlock_irqrestore(&rt->out_lock, flags);
+}
+
+static void usb6fire_midi_in_received(
+ struct midi_runtime *rt, u8 *data, int length)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rt->in_lock, flags);
+ if (rt->in)
+ snd_rawmidi_receive(rt->in, data, length);
+ spin_unlock_irqrestore(&rt->in_lock, flags);
+}
+
+static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static void usb6fire_midi_out_trigger(
+ struct snd_rawmidi_substream *alsa_sub, int up)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+ struct urb *urb = &rt->out_urb;
+ __s8 ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rt->out_lock, flags);
+ if (up) { /* start transfer */
+ if (rt->out) { /* we are already transmitting so just return */
+ spin_unlock_irqrestore(&rt->out_lock, flags);
+ return;
+ }
+
+ ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4,
+ MIDI_BUFSIZE - 4);
+ if (ret > 0) {
+ rt->out_buffer[1] = ret + 2;
+ rt->out_buffer[3] = rt->out_serial++;
+ urb->transfer_buffer_length = ret + 4;
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ snd_printk(KERN_ERR PREFIX "midi out urb "
+ "submit failed: %d\n", ret);
+ else
+ rt->out = alsa_sub;
+ }
+ } else if (rt->out == alsa_sub)
+ rt->out = NULL;
+ spin_unlock_irqrestore(&rt->out_lock, flags);
+}
+
+static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+ int retry = 0;
+
+ while (rt->out && retry++ < 100)
+ msleep(10);
+}
+
+static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub)
+{
+ return 0;
+}
+
+static void usb6fire_midi_in_trigger(
+ struct snd_rawmidi_substream *alsa_sub, int up)
+{
+ struct midi_runtime *rt = alsa_sub->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rt->in_lock, flags);
+ if (up)
+ rt->in = alsa_sub;
+ else
+ rt->in = NULL;
+ spin_unlock_irqrestore(&rt->in_lock, flags);
+}
+
+static struct snd_rawmidi_ops out_ops = {
+ .open = usb6fire_midi_out_open,
+ .close = usb6fire_midi_out_close,
+ .trigger = usb6fire_midi_out_trigger,
+ .drain = usb6fire_midi_out_drain
+};
+
+static struct snd_rawmidi_ops in_ops = {
+ .open = usb6fire_midi_in_open,
+ .close = usb6fire_midi_in_close,
+ .trigger = usb6fire_midi_in_trigger
+};
+
+int __devinit usb6fire_midi_init(struct sfire_chip *chip)
+{
+ int ret;
+ struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime),
+ GFP_KERNEL);
+ struct comm_runtime *comm_rt = chip->comm;
+
+ if (!rt)
+ return -ENOMEM;
+
+ rt->chip = chip;
+ rt->in_received = usb6fire_midi_in_received;
+ rt->out_buffer[0] = 0x80; /* 'send midi' command */
+ rt->out_buffer[1] = 0x00; /* size of data */
+ rt->out_buffer[2] = 0x00; /* always 0 */
+ spin_lock_init(&rt->in_lock);
+ spin_lock_init(&rt->out_lock);
+
+ comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt,
+ usb6fire_midi_out_handler);
+
+ ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
+ if (ret < 0) {
+ kfree(rt);
+ snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
+ return ret;
+ }
+ rt->instance->private_data = rt;
+ strcpy(rt->instance->name, "DMX6FireUSB MIDI");
+ rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &out_ops);
+ snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT,
+ &in_ops);
+
+ chip->midi = rt;
+ return 0;
+}
+
+void usb6fire_midi_abort(struct sfire_chip *chip)
+{
+ struct midi_runtime *rt = chip->midi;
+
+ if (rt)
+ usb_poison_urb(&rt->out_urb);
+}
+
+void usb6fire_midi_destroy(struct sfire_chip *chip)
+{
+ kfree(chip->midi);
+ chip->midi = NULL;
+}
diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h
new file mode 100644
index 000000000000..97a7bf669135
--- /dev/null
+++ b/sound/usb/6fire/midi.h
@@ -0,0 +1,46 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef USB6FIRE_MIDI_H
+#define USB6FIRE_MIDI_H
+
+#include "common.h"
+
+enum {
+ MIDI_BUFSIZE = 64
+};
+
+struct midi_runtime {
+ struct sfire_chip *chip;
+ struct snd_rawmidi *instance;
+
+ struct snd_rawmidi_substream *in;
+ char in_active;
+
+ spinlock_t in_lock;
+ spinlock_t out_lock;
+ struct snd_rawmidi_substream *out;
+ struct urb out_urb;
+ u8 out_serial; /* serial number of out packet */
+ u8 out_buffer[MIDI_BUFSIZE];
+ int buffer_offset;
+
+ void (*in_received)(struct midi_runtime *rt, u8 *data, int length);
+};
+
+int __devinit usb6fire_midi_init(struct sfire_chip *chip);
+void usb6fire_midi_abort(struct sfire_chip *chip);
+void usb6fire_midi_destroy(struct sfire_chip *chip);
+#endif /* USB6FIRE_MIDI_H */
+
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
new file mode 100644
index 000000000000..ba62c7468ba8
--- /dev/null
+++ b/sound/usb/6fire/pcm.c
@@ -0,0 +1,688 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * PCM driver
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "pcm.h"
+#include "chip.h"
+#include "comm.h"
+
+enum {
+ OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
+};
+
+/* keep next two synced with
+ * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
+static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
+static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
+static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
+static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
+static const int rates_alsaid[] = {
+ SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
+ SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
+
+/* values to write to soundcard register for all samplerates */
+static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
+static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
+
+enum { /* settings for pcm */
+ OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
+};
+
+enum { /* pcm streaming states */
+ STREAM_DISABLED, /* no pcm streaming */
+ STREAM_STARTING, /* pcm streaming requested, waiting to become ready */
+ STREAM_RUNNING, /* pcm streaming running */
+ STREAM_STOPPING
+};
+
+enum { /* pcm sample rates (also index into RATES_XXX[]) */
+ RATE_44KHZ,
+ RATE_48KHZ,
+ RATE_88KHZ,
+ RATE_96KHZ,
+ RATE_176KHZ,
+ RATE_192KHZ
+};
+
+static const struct snd_pcm_hardware pcm_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH,
+
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000,
+
+ .rate_min = 44100,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 0, /* set in pcm_open, depending on capture/playback */
+ .buffer_bytes_max = MAX_BUFSIZE,
+ .period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4),
+ .period_bytes_max = MAX_BUFSIZE,
+ .periods_min = 2,
+ .periods_max = 1024
+};
+
+static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
+{
+ int ret;
+ struct usb_device *device = rt->chip->dev;
+ struct comm_runtime *comm_rt = rt->chip->comm;
+
+ if (rt->rate >= ARRAY_SIZE(rates))
+ return -EINVAL;
+ /* disable streaming */
+ ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error stopping streaming while "
+ "setting samplerate %d.\n", rates[rt->rate]);
+ return ret;
+ }
+
+ ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error setting interface "
+ "altsetting %d for samplerate %d.\n",
+ rates_altsetting[rt->rate], rates[rt->rate]);
+ return ret;
+ }
+
+ /* set soundcard clock */
+ ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
+ rates_6fire_vh[rt->rate]);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
+ rates[rt->rate]);
+ return ret;
+ }
+
+ /* enable analog inputs and outputs
+ * (one bit per stereo-channel) */
+ ret = comm_rt->write16(comm_rt, 0x02, 0x02,
+ (1 << (OUT_N_CHANNELS / 2)) - 1,
+ (1 << (IN_N_CHANNELS / 2)) - 1);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error initializing analog channels "
+ "while setting samplerate %d.\n",
+ rates[rt->rate]);
+ return ret;
+ }
+ /* disable digital inputs and outputs */
+ ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error initializing digital "
+ "channels while setting samplerate %d.\n",
+ rates[rt->rate]);
+ return ret;
+ }
+
+ ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
+ if (ret < 0) {
+ snd_printk(KERN_ERR PREFIX "error starting streaming while "
+ "setting samplerate %d.\n", rates[rt->rate]);
+ return ret;
+ }
+
+ rt->in_n_analog = IN_N_CHANNELS;
+ rt->out_n_analog = OUT_N_CHANNELS;
+ rt->in_packet_size = rates_in_packet_size[rt->rate];
+ rt->out_packet_size = rates_out_packet_size[rt->rate];
+ return 0;
+}
+
+static struct pcm_substream *usb6fire_pcm_get_substream(
+ struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+
+ if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return &rt->playback;
+ else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return &rt->capture;
+ snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n");
+ return NULL;
+}
+
+/* call with stream_mutex locked */
+static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
+{
+ int i;
+
+ if (rt->stream_state != STREAM_DISABLED) {
+ for (i = 0; i < PCM_N_URBS; i++) {
+ usb_kill_urb(&rt->in_urbs[i].instance);
+ usb_kill_urb(&rt->out_urbs[i].instance);
+ }
+ rt->stream_state = STREAM_DISABLED;
+ }
+}
+
+/* call with stream_mutex locked */
+static int usb6fire_pcm_stream_start(struct pcm_runtime *rt)
+{
+ int ret;
+ int i;
+ int k;
+ struct usb_iso_packet_descriptor *packet;
+
+ if (rt->stream_state == STREAM_DISABLED) {
+ /* submit our in urbs */
+ rt->stream_wait_cond = false;
+ rt->stream_state = STREAM_STARTING;
+ for (i = 0; i < PCM_N_URBS; i++) {
+ for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) {
+ packet = &rt->in_urbs[i].packets[k];
+ packet->offset = k * rt->in_packet_size;
+ packet->length = rt->in_packet_size;
+ packet->actual_length = 0;
+ packet->status = 0;
+ }
+ ret = usb_submit_urb(&rt->in_urbs[i].instance,
+ GFP_ATOMIC);
+ if (ret) {
+ usb6fire_pcm_stream_stop(rt);
+ return ret;
+ }
+ }
+
+ /* wait for first out urb to return (sent in in urb handler) */
+ wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
+ HZ);
+ if (rt->stream_wait_cond)
+ rt->stream_state = STREAM_RUNNING;
+ else {
+ usb6fire_pcm_stream_stop(rt);
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/* call with substream locked */
+static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
+{
+ int i;
+ int frame;
+ int frame_count;
+ unsigned int total_length = 0;
+ struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
+ struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
+ u32 *src = (u32 *) urb->buffer;
+ u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
+ * (alsa_rt->frame_bits >> 3));
+ u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
+ * (alsa_rt->frame_bits >> 3));
+ int bytes_per_frame = alsa_rt->channels << 2;
+
+ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
+ /* at least 4 header bytes for valid packet.
+ * after that: 32 bits per sample for analog channels */
+ if (urb->packets[i].actual_length > 4)
+ frame_count = (urb->packets[i].actual_length - 4)
+ / (rt->in_n_analog << 2);
+ else
+ frame_count = 0;
+
+ src = (u32 *) (urb->buffer + total_length);
+ src++; /* skip leading 4 bytes of every packet */
+ total_length += urb->packets[i].length;
+ for (frame = 0; frame < frame_count; frame++) {
+ memcpy(dest, src, bytes_per_frame);
+ dest += alsa_rt->channels;
+ src += rt->in_n_analog;
+ sub->dma_off++;
+ sub->period_off++;
+ if (dest == dest_end) {
+ sub->dma_off = 0;
+ dest = (u32 *) alsa_rt->dma_area;
+ }
+ }
+ }
+}
+
+/* call with substream locked */
+static void usb6fire_pcm_playback(struct pcm_substream *sub,
+ struct pcm_urb *urb)
+{
+ int i;
+ int frame;
+ int frame_count;
+ struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
+ struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
+ u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off
+ * (alsa_rt->frame_bits >> 3));
+ u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
+ * (alsa_rt->frame_bits >> 3));
+ u32 *dest = (u32 *) urb->buffer;
+ int bytes_per_frame = alsa_rt->channels << 2;
+
+ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
+ /* at least 4 header bytes for valid packet.
+ * after that: 32 bits per sample for analog channels */
+ if (urb->packets[i].length > 4)
+ frame_count = (urb->packets[i].length - 4)
+ / (rt->out_n_analog << 2);
+ else
+ frame_count = 0;
+ dest++; /* skip leading 4 bytes of every frame */
+ for (frame = 0; frame < frame_count; frame++) {
+ memcpy(dest, src, bytes_per_frame);
+ src += alsa_rt->channels;
+ dest += rt->out_n_analog;
+ sub->dma_off++;
+ sub->period_off++;
+ if (src == src_end) {
+ src = (u32 *) alsa_rt->dma_area;
+ sub->dma_off = 0;
+ }
+ }
+ }
+}
+
+static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
+{
+ struct pcm_urb *in_urb = usb_urb->context;
+ struct pcm_urb *out_urb = in_urb->peer;
+ struct pcm_runtime *rt = in_urb->chip->pcm;
+ struct pcm_substream *sub;
+ unsigned long flags;
+ int total_length = 0;
+ int frame_count;
+ int frame;
+ int channel;
+ int i;
+ u8 *dest;
+
+ if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING)
+ return;
+ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
+ if (in_urb->packets[i].status) {
+ rt->panic = true;
+ return;
+ }
+
+ if (rt->stream_state == STREAM_DISABLED) {
+ snd_printk(KERN_ERR PREFIX "internal error: "
+ "stream disabled in in-urb handler.\n");
+ return;
+ }
+
+ /* receive our capture data */
+ sub = &rt->capture;
+ spin_lock_irqsave(&sub->lock, flags);
+ if (sub->active) {
+ usb6fire_pcm_capture(sub, in_urb);
+ if (sub->period_off >= sub->instance->runtime->period_size) {
+ sub->period_off %= sub->instance->runtime->period_size;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ snd_pcm_period_elapsed(sub->instance);
+ } else
+ spin_unlock_irqrestore(&sub->lock, flags);
+ } else
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ /* setup out urb structure */
+ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
+ out_urb->packets[i].offset = total_length;
+ out_urb->packets[i].length = (in_urb->packets[i].actual_length
+ - 4) / (rt->in_n_analog << 2)
+ * (rt->out_n_analog << 2) + 4;
+ out_urb->packets[i].status = 0;
+ total_length += out_urb->packets[i].length;
+ }
+ memset(out_urb->buffer, 0, total_length);
+
+ /* now send our playback data (if a free out urb was found) */
+ sub = &rt->playback;
+ spin_lock_irqsave(&sub->lock, flags);
+ if (sub->active) {
+ usb6fire_pcm_playback(sub, out_urb);
+ if (sub->period_off >= sub->instance->runtime->period_size) {
+ sub->period_off %= sub->instance->runtime->period_size;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ snd_pcm_period_elapsed(sub->instance);
+ } else
+ spin_unlock_irqrestore(&sub->lock, flags);
+ } else
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ /* setup the 4th byte of each sample (0x40 for analog channels) */
+ dest = out_urb->buffer;
+ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
+ if (out_urb->packets[i].length >= 4) {
+ frame_count = (out_urb->packets[i].length - 4)
+ / (rt->out_n_analog << 2);
+ *(dest++) = 0xaa;
+ *(dest++) = 0xaa;
+ *(dest++) = frame_count;
+ *(dest++) = 0x00;
+ for (frame = 0; frame < frame_count; frame++)
+ for (channel = 0;
+ channel < rt->out_n_analog;
+ channel++) {
+ dest += 3; /* skip sample data */
+ *(dest++) = 0x40;
+ }
+ }
+ usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
+ usb_submit_urb(&in_urb->instance, GFP_ATOMIC);
+}
+
+static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb)
+{
+ struct pcm_urb *urb = usb_urb->context;
+ struct pcm_runtime *rt = urb->chip->pcm;
+
+ if (rt->stream_state == STREAM_STARTING) {
+ rt->stream_wait_cond = true;
+ wake_up(&rt->stream_wait_queue);
+ }
+}
+
+static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = NULL;
+ struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+
+ if (rt->panic)
+ return -EPIPE;
+
+ mutex_lock(&rt->stream_mutex);
+ alsa_rt->hw = pcm_hw;
+
+ if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (rt->rate >= 0)
+ alsa_rt->hw.rates = rates_alsaid[rt->rate];
+ alsa_rt->hw.channels_max = OUT_N_CHANNELS;
+ sub = &rt->playback;
+ } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (rt->rate >= 0)
+ alsa_rt->hw.rates = rates_alsaid[rt->rate];
+ alsa_rt->hw.channels_max = IN_N_CHANNELS;
+ sub = &rt->capture;
+ }
+
+ if (!sub) {
+ mutex_unlock(&rt->stream_mutex);
+ snd_printk(KERN_ERR PREFIX "invalid stream type.\n");
+ return -EINVAL;
+ }
+
+ sub->instance = alsa_sub;
+ sub->active = false;
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
+ unsigned long flags;
+
+ if (rt->panic)
+ return 0;
+
+ mutex_lock(&rt->stream_mutex);
+ if (sub) {
+ /* deactivate substream */
+ spin_lock_irqsave(&sub->lock, flags);
+ sub->instance = NULL;
+ sub->active = false;
+ spin_unlock_irqrestore(&sub->lock, flags);
+
+ /* all substreams closed? if so, stop streaming */
+ if (!rt->playback.instance && !rt->capture.instance) {
+ usb6fire_pcm_stream_stop(rt);
+ rt->rate = -1;
+ }
+ }
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
+ struct snd_pcm_hw_params *hw_params)
+{
+ return snd_pcm_lib_malloc_pages(alsa_sub,
+ params_buffer_bytes(hw_params));
+}
+
+static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
+{
+ return snd_pcm_lib_free_pages(alsa_sub);
+}
+
+static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
+ struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
+ int i;
+ int ret;
+
+ if (rt->panic)
+ return -EPIPE;
+ if (!sub)
+ return -ENODEV;
+
+ mutex_lock(&rt->stream_mutex);
+ sub->dma_off = 0;
+ sub->period_off = 0;
+
+ if (rt->stream_state == STREAM_DISABLED) {
+ for (i = 0; i < ARRAY_SIZE(rates); i++)
+ if (alsa_rt->rate == rates[i]) {
+ rt->rate = i;
+ break;
+ }
+ if (i == ARRAY_SIZE(rates)) {
+ mutex_unlock(&rt->stream_mutex);
+ snd_printk("invalid rate %d in prepare.\n",
+ alsa_rt->rate);
+ return -EINVAL;
+ }
+
+ ret = usb6fire_pcm_set_rate(rt);
+ if (ret) {
+ mutex_unlock(&rt->stream_mutex);
+ return ret;
+ }
+ ret = usb6fire_pcm_stream_start(rt);
+ if (ret) {
+ mutex_unlock(&rt->stream_mutex);
+ snd_printk(KERN_ERR PREFIX
+ "could not start pcm stream.\n");
+ return ret;
+ }
+ }
+ mutex_unlock(&rt->stream_mutex);
+ return 0;
+}
+
+static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)
+{
+ struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ unsigned long flags;
+
+ if (rt->panic)
+ return -EPIPE;
+ if (!sub)
+ return -ENODEV;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ spin_lock_irqsave(&sub->lock, flags);
+ sub->active = true;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ spin_lock_irqsave(&sub->lock, flags);
+ sub->active = false;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static snd_pcm_uframes_t usb6fire_pcm_pointer(
+ struct snd_pcm_substream *alsa_sub)
+{
+ struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
+ struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
+ unsigned long flags;
+ snd_pcm_uframes_t ret;
+
+ if (rt->panic || !sub)
+ return SNDRV_PCM_STATE_XRUN;
+
+ spin_lock_irqsave(&sub->lock, flags);
+ ret = sub->dma_off;
+ spin_unlock_irqrestore(&sub->lock, flags);
+ return ret;
+}
+
+static struct snd_pcm_ops pcm_ops = {
+ .open = usb6fire_pcm_open,
+ .close = usb6fire_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = usb6fire_pcm_hw_params,
+ .hw_free = usb6fire_pcm_hw_free,
+ .prepare = usb6fire_pcm_prepare,
+ .trigger = usb6fire_pcm_trigger,
+ .pointer = usb6fire_pcm_pointer,
+};
+
+static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb,
+ struct sfire_chip *chip, bool in, int ep,
+ void (*handler)(struct urb *))
+{
+ urb->chip = chip;
+ usb_init_urb(&urb->instance);
+ urb->instance.transfer_buffer = urb->buffer;
+ urb->instance.transfer_buffer_length =
+ PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE;
+ urb->instance.dev = chip->dev;
+ urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)
+ : usb_sndisocpipe(chip->dev, ep);
+ urb->instance.interval = 1;
+ urb->instance.transfer_flags = URB_ISO_ASAP;
+ urb->instance.complete = handler;
+ urb->instance.context = urb;
+ urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
+}
+
+int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
+{
+ int i;
+ int ret;
+ struct snd_pcm *pcm;
+ struct pcm_runtime *rt =
+ kzalloc(sizeof(struct pcm_runtime), GFP_KERNEL);
+
+ if (!rt)
+ return -ENOMEM;
+
+ rt->chip = chip;
+ rt->stream_state = STREAM_DISABLED;
+ rt->rate = -1;
+ init_waitqueue_head(&rt->stream_wait_queue);
+ mutex_init(&rt->stream_mutex);
+
+ spin_lock_init(&rt->playback.lock);
+ spin_lock_init(&rt->capture.lock);
+
+ for (i = 0; i < PCM_N_URBS; i++) {
+ usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP,
+ usb6fire_pcm_in_urb_handler);
+ usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP,
+ usb6fire_pcm_out_urb_handler);
+
+ rt->in_urbs[i].peer = &rt->out_urbs[i];
+ rt->out_urbs[i].peer = &rt->in_urbs[i];
+ }
+
+ ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
+ if (ret < 0) {
+ kfree(rt);
+ snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
+ return ret;
+ }
+
+ pcm->private_data = rt;
+ strcpy(pcm->name, "DMX 6Fire USB");
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
+
+ ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ MAX_BUFSIZE, MAX_BUFSIZE);
+ if (ret) {
+ kfree(rt);
+ snd_printk(KERN_ERR PREFIX
+ "error preallocating pcm buffers.\n");
+ return ret;
+ }
+ rt->instance = pcm;
+
+ chip->pcm = rt;
+ return 0;
+}
+
+void usb6fire_pcm_abort(struct sfire_chip *chip)
+{
+ struct pcm_runtime *rt = chip->pcm;
+ int i;
+
+ if (rt) {
+ rt->panic = true;
+
+ if (rt->playback.instance)
+ snd_pcm_stop(rt->playback.instance,
+ SNDRV_PCM_STATE_XRUN);
+ if (rt->capture.instance)
+ snd_pcm_stop(rt->capture.instance,
+ SNDRV_PCM_STATE_XRUN);
+
+ for (i = 0; i < PCM_N_URBS; i++) {
+ usb_poison_urb(&rt->in_urbs[i].instance);
+ usb_poison_urb(&rt->out_urbs[i].instance);
+ }
+
+ }
+}
+
+void usb6fire_pcm_destroy(struct sfire_chip *chip)
+{
+ kfree(chip->pcm);
+ chip->pcm = NULL;
+}
diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h
new file mode 100644
index 000000000000..2bee81374002
--- /dev/null
+++ b/sound/usb/6fire/pcm.h
@@ -0,0 +1,76 @@
+/*
+ * Linux driver for TerraTec DMX 6Fire USB
+ *
+ * Author: Torsten Schenk <torsten.schenk@zoho.com>
+ * Created: Jan 01, 2011
+ * Version: 0.3.0
+ * Copyright: (C) Torsten Schenk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef USB6FIRE_PCM_H
+#define USB6FIRE_PCM_H
+
+#include <sound/pcm.h>
+#include <linux/mutex.h>
+
+#include "common.h"
+
+enum /* settings for pcm */
+{
+ /* maximum of EP_W_MAX_PACKET_SIZE[] (see firmware.c) */
+ PCM_N_URBS = 16, PCM_N_PACKETS_PER_URB = 8, PCM_MAX_PACKET_SIZE = 604
+};
+
+struct pcm_urb {
+ struct sfire_chip *chip;
+
+ /* BEGIN DO NOT SEPARATE */
+ struct urb instance;
+ struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB];
+ /* END DO NOT SEPARATE */
+ u8 buffer[PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE];
+
+ struct pcm_urb *peer;
+};
+
+struct pcm_substream {
+ spinlock_t lock;
+ struct snd_pcm_substream *instance;
+
+ bool active;
+
+ snd_pcm_uframes_t dma_off; /* current position in alsa dma_area */
+ snd_pcm_uframes_t period_off; /* current position in current period */
+};
+
+struct pcm_runtime {
+ struct sfire_chip *chip;
+ struct snd_pcm *instance;
+
+ struct pcm_substream playback;
+ struct pcm_substream capture;
+ bool panic; /* if set driver won't do anymore pcm on device */
+
+ struct pcm_urb in_urbs[PCM_N_URBS];
+ struct pcm_urb out_urbs[PCM_N_URBS];
+ int in_packet_size;
+ int out_packet_size;
+ int in_n_analog; /* number of analog channels soundcard sends */
+ int out_n_analog; /* number of analog channels soundcard receives */
+
+ struct mutex stream_mutex;
+ u8 stream_state; /* one of STREAM_XXX (pcm.c) */
+ u8 rate; /* one of PCM_RATE_XXX */
+ wait_queue_head_t stream_wait_queue;
+ bool stream_wait_cond;
+};
+
+int __devinit usb6fire_pcm_init(struct sfire_chip *chip);
+void usb6fire_pcm_abort(struct sfire_chip *chip);
+void usb6fire_pcm_destroy(struct sfire_chip *chip);
+#endif /* USB6FIRE_PCM_H */
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index 112984f4080f..97724d8fa9f6 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -62,6 +62,7 @@ config SND_USB_CAIAQ
* Native Instruments Audio 2 DJ
* Native Instruments Audio 4 DJ
* Native Instruments Audio 8 DJ
+ * Native Instruments Traktor Audio 2
* Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1
@@ -97,5 +98,21 @@ config SND_USB_US122L
To compile this driver as a module, choose M here: the module
will be called snd-usb-us122l.
+config SND_USB_6FIRE
+ tristate "TerraTec DMX 6Fire USB"
+ depends on EXPERIMENTAL
+ select FW_LOADER
+ select SND_RAWMIDI
+ select SND_PCM
+ help
+ Say Y here to include support for TerraTec 6fire DMX USB interface.
+
+ You will need firmware files in order to be able to use the device
+ after it has been coldstarted. This driver currently does not support
+ firmware loading for all devices. If you own such a device,
+ you could start windows and let the windows driver upload
+ the firmware. As long as you do not unplug your device from power,
+ it should be usable.
+
endif # SND_USB
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 1e362bf8834f..cf9ed66445fa 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
-obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/
+obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 66eabafb1c24..d0d493ca28ae 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -805,6 +805,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2):
dev->samplerates |= SNDRV_PCM_RATE_88200;
break;
}
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 6480c3283c05..45bc4a2dc6f0 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -46,6 +46,7 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 2 DJ},"
"{Native Instruments, Audio 4 DJ},"
"{Native Instruments, Audio 8 DJ},"
+ "{Native Instruments, Traktor Audio 2},"
"{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}"
"{Native Instruments, Traktor Kontrol X1}"
@@ -140,6 +141,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORKONTROLS4
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = USB_VID_NATIVEINSTRUMENTS,
+ .idProduct = USB_PID_TRAKTORAUDIO2
+ },
{ /* terminator */ }
};
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index e3d8a3efb35b..b2b310194ffa 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -17,6 +17,7 @@
#define USB_PID_GUITARRIGMOBILE 0x0d8d
#define USB_PID_TRAKTORKONTROLX1 0x2305
#define USB_PID_TRAKTORKONTROLS4 0xbaff
+#define USB_PID_TRAKTORAUDIO2 0x041d
#define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
diff --git a/sound/usb/card.c b/sound/usb/card.c
index c0f8270bc199..40722f8711ad 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -65,6 +65,7 @@
#include "pcm.h"
#include "urb.h"
#include "format.h"
+#include "power.h"
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("USB Audio");
@@ -330,6 +331,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->setup = device_setup[idx];
chip->nrpacks = nrpacks;
chip->async_unlink = async_unlink;
+ chip->probing = 1;
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
@@ -451,6 +453,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
goto __error;
}
chip = usb_chip[i];
+ chip->probing = 1;
break;
}
}
@@ -466,6 +469,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
goto __error;
}
snd_card_set_dev(chip->card, &intf->dev);
+ chip->pm_intf = intf;
break;
}
if (!chip) {
@@ -505,6 +509,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
usb_chip[chip->index] = chip;
chip->num_interfaces++;
+ chip->probing = 0;
mutex_unlock(&register_mutex);
return chip;
@@ -581,29 +586,61 @@ static void usb_audio_disconnect(struct usb_interface *intf)
}
#ifdef CONFIG_PM
+
+int snd_usb_autoresume(struct snd_usb_audio *chip)
+{
+ int err = -ENODEV;
+
+ if (!chip->shutdown && !chip->probing)
+ err = usb_autopm_get_interface(chip->pm_intf);
+
+ return err;
+}
+
+void snd_usb_autosuspend(struct snd_usb_audio *chip)
+{
+ if (!chip->shutdown && !chip->probing)
+ usb_autopm_put_interface(chip->pm_intf);
+}
+
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct list_head *p;
struct snd_usb_stream *as;
+ struct usb_mixer_interface *mixer;
if (chip == (void *)-1L)
return 0;
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
- if (!chip->num_suspended_intf++) {
- list_for_each(p, &chip->pcm_list) {
- as = list_entry(p, struct snd_usb_stream, list);
- snd_pcm_suspend_all(as->pcm);
- }
+ if (!(message.event & PM_EVENT_AUTO)) {
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+ if (!chip->num_suspended_intf++) {
+ list_for_each(p, &chip->pcm_list) {
+ as = list_entry(p, struct snd_usb_stream, list);
+ snd_pcm_suspend_all(as->pcm);
+ }
+ }
+ } else {
+ /*
+ * otherwise we keep the rest of the system in the dark
+ * to keep this transparent
+ */
+ if (!chip->num_suspended_intf++)
+ chip->autosuspended = 1;
}
+ list_for_each_entry(mixer, &chip->mixer_list, list)
+ snd_usb_mixer_inactivate(mixer);
+
return 0;
}
static int usb_audio_resume(struct usb_interface *intf)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
+ struct usb_mixer_interface *mixer;
+ int err = 0;
if (chip == (void *)-1L)
return 0;
@@ -611,12 +648,20 @@ static int usb_audio_resume(struct usb_interface *intf)
return 0;
/*
* ALSA leaves material resumption to user space
- * we just notify
+ * we just notify and restart the mixers
*/
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ err = snd_usb_mixer_activate(mixer);
+ if (err < 0)
+ goto err_out;
+ }
- snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ if (!chip->autosuspended)
+ snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+ chip->autosuspended = 0;
- return 0;
+err_out:
+ return err;
}
#else
#define usb_audio_suspend NULL
@@ -644,6 +689,7 @@ static struct usb_driver usb_audio_driver = {
.suspend = usb_audio_suspend,
.resume = usb_audio_resume,
.id_table = usb_audio_ids,
+ .supports_autosuspend = 1,
};
static int __init snd_usb_audio_init(void)
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index db2dc5ffe6dd..b4b39c0b6c9e 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -54,6 +54,7 @@
#include <sound/asequencer.h>
#include "usbaudio.h"
#include "midi.h"
+#include "power.h"
#include "helper.h"
/*
@@ -1044,6 +1045,7 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
struct snd_usb_midi* umidi = substream->rmidi->private_data;
struct usbmidi_out_port* port = NULL;
int i, j;
+ int err;
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
if (umidi->endpoints[i].out)
@@ -1056,6 +1058,9 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
snd_BUG();
return -ENXIO;
}
+ err = usb_autopm_get_interface(umidi->iface);
+ if (err < 0)
+ return -EIO;
substream->runtime->private_data = port;
port->state = STATE_UNKNOWN;
substream_open(substream, 1);
@@ -1064,7 +1069,10 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
{
+ struct snd_usb_midi* umidi = substream->rmidi->private_data;
+
substream_open(substream, 0);
+ usb_autopm_put_interface(umidi->iface);
return 0;
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 85af6051b52d..5e4775716607 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -61,6 +61,7 @@
#include "mixer.h"
#include "helper.h"
#include "mixer_quirks.h"
+#include "power.h"
#define MAX_ID_ELEMS 256
@@ -295,16 +296,22 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
+ int err;
+ err = snd_usb_autoresume(cval->mixer->chip);
+ if (err < 0)
+ return -EIO;
while (timeout-- > 0) {
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= val_len) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
+ snd_usb_autosuspend(cval->mixer->chip);
return 0;
}
}
+ snd_usb_autosuspend(cval->mixer->chip);
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return -EINVAL;
@@ -328,12 +335,18 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
memset(buf, 0, sizeof(buf));
+ ret = snd_usb_autoresume(chip) ? -EIO : 0;
+ if (ret)
+ goto error;
+
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, size, 1000);
+ snd_usb_autosuspend(chip);
if (ret < 0) {
+error:
snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return ret;
@@ -413,7 +426,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
{
struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2];
- int val_len, timeout = 10;
+ int val_len, err, timeout = 10;
if (cval->mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
@@ -433,13 +446,19 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
+ err = snd_usb_autoresume(chip);
+ if (err < 0)
+ return -EIO;
while (timeout-- > 0)
if (snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
- buf, val_len, 100) >= 0)
+ buf, val_len, 100) >= 0) {
+ snd_usb_autosuspend(chip);
return 0;
+ }
+ snd_usb_autosuspend(chip);
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;
@@ -987,6 +1006,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
+ unsigned int range;
control++; /* change from zero-based to 1-based value */
@@ -1121,6 +1141,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
break;
+ case USB_ID(0x046d, 0x0808):
case USB_ID(0x046d, 0x0809):
case USB_ID(0x046d, 0x0991):
/* Most audio usb devices lie about volume resolution.
@@ -1136,6 +1157,21 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
+ range = (cval->max - cval->min) / cval->res;
+ /* Are there devices with volume range more than 255? I use a bit more
+ * to be sure. 384 is a resolution magic number found on Logitech
+ * devices. It will definitively catch all buggy Logitech devices.
+ */
+ if (range > 384) {
+ snd_printk(KERN_WARNING "usb_audio: Warning! Unlikely big "
+ "volume range (=%u), cval->res is probably wrong.",
+ range);
+ snd_printk(KERN_WARNING "usb_audio: [%d] FU [%s] ch = %d, "
+ "val = %d/%d/%d", cval->id,
+ kctl->id.name, cval->channels,
+ cval->min, cval->max, cval->res);
+ }
+
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
add_control_to_empty(state, kctl);
@@ -2058,8 +2094,9 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
{
struct usb_mixer_interface *mixer = urb->context;
int len = urb->actual_length;
+ int ustatus = urb->status;
- if (urb->status != 0)
+ if (ustatus != 0)
goto requeue;
if (mixer->protocol == UAC_VERSION_1) {
@@ -2100,12 +2137,32 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
}
requeue:
- if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
+ if (ustatus != -ENOENT && ustatus != -ECONNRESET && ustatus != -ESHUTDOWN) {
urb->dev = mixer->chip->dev;
usb_submit_urb(urb, GFP_ATOMIC);
}
}
+/* stop any bus activity of a mixer */
+void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
+{
+ usb_kill_urb(mixer->urb);
+ usb_kill_urb(mixer->rc_urb);
+}
+
+int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ if (mixer->urb) {
+ err = usb_submit_urb(mixer->urb, GFP_NOIO);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/* create the handler for the optional status interrupt endpoint */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 26c636c5c93a..b4a2c8165e4b 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -52,5 +52,7 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
+void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer);
+int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 782f741cd00a..73dcc8256bc0 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -346,6 +346,141 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
return 0;
}
+/* Native Instruments device quirks */
+
+#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
+
+static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_device *dev = mixer->chip->dev;
+ u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
+ u16 wIndex = kcontrol->private_value & 0xffff;
+ u8 tmp;
+
+ int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, cpu_to_le16(wIndex),
+ &tmp, sizeof(tmp), 1000);
+
+ if (ret < 0) {
+ snd_printk(KERN_ERR
+ "unable to issue vendor read request (ret = %d)", ret);
+ return ret;
+ }
+
+ ucontrol->value.integer.value[0] = tmp;
+
+ return 0;
+}
+
+static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_device *dev = mixer->chip->dev;
+ u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
+ u16 wIndex = kcontrol->private_value & 0xffff;
+ u16 wValue = ucontrol->value.integer.value[0];
+
+ int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ cpu_to_le16(wValue), cpu_to_le16(wIndex),
+ NULL, 0, 1000);
+
+ if (ret < 0) {
+ snd_printk(KERN_ERR
+ "unable to issue vendor write request (ret = %d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
+ {
+ .name = "Direct Thru Channel A",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x03),
+ },
+ {
+ .name = "Direct Thru Channel B",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x05),
+ },
+ {
+ .name = "Phono Input Channel A",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x03),
+ },
+ {
+ .name = "Phono Input Channel B",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x05),
+ },
+};
+
+static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = {
+ {
+ .name = "Direct Thru Channel A",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x03),
+ },
+ {
+ .name = "Direct Thru Channel B",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x05),
+ },
+ {
+ .name = "Direct Thru Channel C",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x07),
+ },
+ {
+ .name = "Direct Thru Channel D",
+ .private_value = _MAKE_NI_CONTROL(0x01, 0x09),
+ },
+ {
+ .name = "Phono Input Channel A",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x03),
+ },
+ {
+ .name = "Phono Input Channel B",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x05),
+ },
+ {
+ .name = "Phono Input Channel C",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x07),
+ },
+ {
+ .name = "Phono Input Channel D",
+ .private_value = _MAKE_NI_CONTROL(0x02, 0x09),
+ },
+};
+
+static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *kc,
+ unsigned int count)
+{
+ int i, err = 0;
+ struct snd_kcontrol_new template = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .get = snd_nativeinstruments_control_get,
+ .put = snd_nativeinstruments_control_put,
+ .info = snd_ctl_boolean_mono_info,
+ };
+
+ for (i = 0; i < count; i++) {
+ struct snd_kcontrol *c;
+
+ template.name = kc[i].name;
+ template.private_value = kc[i].private_value;
+
+ c = snd_ctl_new1(&template, mixer);
+ err = snd_ctl_add(mixer->chip->card, c);
+
+ if (err < 0)
+ break;
+ }
+
+ return err;
+}
+
void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
unsigned char samplerate_id)
{
@@ -367,31 +502,44 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
{
- int err;
+ int err = 0;
struct snd_info_entry *entry;
if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
return err;
- if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
- mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
- mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
- mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
- if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
- return err;
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x041e, 0x3020):
+ case USB_ID(0x041e, 0x3040):
+ case USB_ID(0x041e, 0x3042):
+ case USB_ID(0x041e, 0x3048):
+ err = snd_audigy2nx_controls_create(mixer);
+ if (err < 0)
+ break;
if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
snd_info_set_text_ops(entry, mixer,
snd_audigy2nx_proc_read);
- }
+ break;
- if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) ||
- mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) {
+ case USB_ID(0x0b05, 0x1739):
+ case USB_ID(0x0b05, 0x1743):
err = snd_xonar_u1_controls_create(mixer);
- if (err < 0)
- return err;
+ break;
+
+ case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
+ err = snd_nativeinstruments_create_mixer(mixer,
+ snd_nativeinstruments_ta6_mixers,
+ ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
+ break;
+
+ case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */
+ err = snd_nativeinstruments_create_mixer(mixer,
+ snd_nativeinstruments_ta10_mixers,
+ ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
+ break;
}
- return 0;
+ return err;
}
void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index e3f680526cb5..b8dcbf407bbb 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -32,6 +32,7 @@
#include "helper.h"
#include "pcm.h"
#include "clock.h"
+#include "power.h"
/*
* return the current pcm pointer. just based on the hwptr_done value.
@@ -739,6 +740,9 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
pt = 125 * (1 << fp->datainterval);
ptmin = min(ptmin, pt);
}
+ err = snd_usb_autoresume(subs->stream->chip);
+ if (err < 0)
+ return err;
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -756,21 +760,21 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
SNDRV_PCM_HW_PARAM_CHANNELS,
param_period_time_if_needed,
-1)) < 0)
- return err;
+ goto rep_err;
if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
hw_rule_channels, subs,
SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_RATE,
param_period_time_if_needed,
-1)) < 0)
- return err;
+ goto rep_err;
if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
hw_rule_format, subs,
SNDRV_PCM_HW_PARAM_RATE,
SNDRV_PCM_HW_PARAM_CHANNELS,
param_period_time_if_needed,
-1)) < 0)
- return err;
+ goto rep_err;
if (param_period_time_if_needed >= 0) {
err = snd_pcm_hw_rule_add(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
@@ -780,11 +784,15 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
SNDRV_PCM_HW_PARAM_RATE,
-1);
if (err < 0)
- return err;
+ goto rep_err;
}
if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
- return err;
+ goto rep_err;
return 0;
+
+rep_err:
+ snd_usb_autosuspend(subs->stream->chip);
+ return err;
}
static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
@@ -798,6 +806,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
runtime->hw = snd_usb_hardware;
runtime->private_data = subs;
subs->pcm_substream = substream;
+ /* runtime PM is also done there */
return setup_hw_info(runtime, subs);
}
@@ -811,6 +820,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
subs->interface = -1;
}
subs->pcm_substream = NULL;
+ snd_usb_autosuspend(subs->stream->chip);
return 0;
}
diff --git a/sound/usb/power.h b/sound/usb/power.h
new file mode 100644
index 000000000000..48ee51dcb71e
--- /dev/null
+++ b/sound/usb/power.h
@@ -0,0 +1,17 @@
+#ifndef __USBAUDIO_POWER_H
+#define __USBAUDIO_POWER_H
+
+#ifdef CONFIG_PM
+int snd_usb_autoresume(struct snd_usb_audio *chip);
+void snd_usb_autosuspend(struct snd_usb_audio *chip);
+#else
+static inline int snd_usb_autoresume(struct snd_usb_audio *chip)
+{
+ return 0;
+}
+static inline void snd_usb_autosuspend(struct snd_usb_audio *chip)
+{
+}
+#endif
+
+#endif /* __USBAUDIO_POWER_H */
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 921a86fd9884..c0dcfca9b5b5 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2290,6 +2290,20 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+/* Native Instruments MK2 series */
+{
+ /* Traktor Audio 6 */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x17cc,
+ .idProduct = 0x1010,
+},
+{
+ /* Traktor Audio 10 */
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = 0x17cc,
+ .idProduct = 0x1020,
+},
+
/* Miditech devices */
{
USB_DEVICE(0x4752, 0x0011),
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index e314cdb85003..355759bad581 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -425,6 +425,34 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
}
/*
+ * Some sound cards from Native Instruments are in fact compliant to the USB
+ * audio standard of version 2 and other approved USB standards, even though
+ * they come up as vendor-specific device when first connected.
+ *
+ * However, they can be told to come up with a new set of descriptors
+ * upon their next enumeration, and the interfaces announced by the new
+ * descriptors will then be handled by the kernel's class drivers. As the
+ * product ID will also change, no further checks are required.
+ */
+
+static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
+{
+ int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ cpu_to_le16(1), 0, NULL, 0, 1000);
+
+ if (ret < 0)
+ return ret;
+
+ usb_reset_device(dev);
+
+ /* return -EAGAIN, so the creation of an audio interface for this
+ * temporary device is aborted. The device will reconnect with a
+ * new product ID */
+ return -EAGAIN;
+}
+
+/*
* Setup quirks
*/
#define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */
@@ -489,27 +517,33 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
u32 id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
- /* SB Extigy needs special boot-up sequence */
- /* if more models come, this will go to the quirk list. */
- if (id == USB_ID(0x041e, 0x3000))
+ switch (id) {
+ case USB_ID(0x041e, 0x3000):
+ /* SB Extigy needs special boot-up sequence */
+ /* if more models come, this will go to the quirk list. */
return snd_usb_extigy_boot_quirk(dev, intf);
- /* SB Audigy 2 NX needs its own boot-up magic, too */
- if (id == USB_ID(0x041e, 0x3020))
+ case USB_ID(0x041e, 0x3020):
+ /* SB Audigy 2 NX needs its own boot-up magic, too */
return snd_usb_audigy2nx_boot_quirk(dev);
- /* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
- if (id == USB_ID(0x10f5, 0x0200))
+ case USB_ID(0x10f5, 0x0200):
+ /* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
return snd_usb_cm106_boot_quirk(dev);
- /* C-Media CM6206 / CM106-Like Sound Device */
- if (id == USB_ID(0x0d8c, 0x0102))
+ case USB_ID(0x0d8c, 0x0102):
+ /* C-Media CM6206 / CM106-Like Sound Device */
return snd_usb_cm6206_boot_quirk(dev);
- /* Access Music VirusTI Desktop */
- if (id == USB_ID(0x133e, 0x0815))
+ case USB_ID(0x133e, 0x0815):
+ /* Access Music VirusTI Desktop */
return snd_usb_accessmusic_boot_quirk(dev);
+ case USB_ID(0x17cc, 0x1010): /* Traktor Audio 6 */
+ case USB_ID(0x17cc, 0x1020): /* Traktor Audio 10 */
+ return snd_usb_nativeinstruments_boot_quirk(dev);
+ }
+
return 0;
}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 6e66fffe87f5..32f2a97f2f14 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -34,10 +34,14 @@ struct snd_usb_audio {
int index;
struct usb_device *dev;
struct snd_card *card;
+ struct usb_interface *pm_intf;
u32 usb_id;
- int shutdown;
struct mutex shutdown_mutex;
+ unsigned int shutdown:1;
+ unsigned int probing:1;
+ unsigned int autosuspended:1;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
+
int num_interfaces;
int num_suspended_intf;
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
new file mode 100644
index 000000000000..0cada9e053dc
--- /dev/null
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -0,0 +1,26 @@
+perf-evlist(1)
+==============
+
+NAME
+----
+perf-evlist - List the event names in a perf.data file
+
+SYNOPSIS
+--------
+[verse]
+'perf evlist <options>'
+
+DESCRIPTION
+-----------
+This command displays the names of events sampled in a perf.data file.
+
+OPTIONS
+-------
+-i::
+--input=::
+ Input file name. (default: perf.data)
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-list[1],
+linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 29ad94293cd2..66f040b30729 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -112,6 +112,28 @@ OPTIONS
--debug-mode::
Do various checks like samples ordering and lost events.
+-f::
+--fields
+ Comma separated list of fields to print. Options are:
+ comm, tid, pid, time, cpu, event, trace, sym. Field
+ list must be prepended with the type, trace, sw or hw,
+ to indicate to which event type the field list applies.
+ e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace
+
+-k::
+--vmlinux=<file>::
+ vmlinux pathname
+
+--kallsyms=<file>::
+ kallsyms pathname
+
+--symfs=<directory>::
+ Look for files with symbols relative to this directory.
+
+-G::
+--hide-call-graph::
+ When printing symbols do not display call chain.
+
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 9b8421805c5c..158c30e8210c 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -338,6 +338,7 @@ endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
+BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
new file mode 100644
index 000000000000..4c5e9e04a41f
--- /dev/null
+++ b/tools/perf/builtin-evlist.c
@@ -0,0 +1,54 @@
+/*
+ * Builtin evlist command: Show the list of event selectors present
+ * in a perf.data file.
+ */
+#include "builtin.h"
+
+#include "util/util.h"
+
+#include <linux/list.h>
+
+#include "perf.h"
+#include "util/evlist.h"
+#include "util/evsel.h"
+#include "util/parse-events.h"
+#include "util/parse-options.h"
+#include "util/session.h"
+
+static char const *input_name = "perf.data";
+
+static int __cmd_evlist(void)
+{
+ struct perf_session *session;
+ struct perf_evsel *pos;
+
+ session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
+ if (session == NULL)
+ return -ENOMEM;
+
+ list_for_each_entry(pos, &session->evlist->entries, node)
+ printf("%s\n", event_name(pos));
+
+ perf_session__delete(session);
+ return 0;
+}
+
+static const char * const evlist_usage[] = {
+ "perf evlist [<options>]",
+ NULL
+};
+
+static const struct option options[] = {
+ OPT_STRING('i', "input", &input_name, "file",
+ "input file name"),
+ OPT_END()
+};
+
+int cmd_evlist(int argc, const char **argv, const char *prefix __used)
+{
+ argc = parse_options(argc, argv, options, evlist_usage, 0);
+ if (argc)
+ usage_with_options(evlist_usage, options);
+
+ return __cmd_evlist();
+}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 2e93f99b1480..7a2a79d2cf2c 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -202,9 +202,20 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
SINGLE_KEY(nr_acquired)
SINGLE_KEY(nr_contended)
SINGLE_KEY(wait_time_total)
-SINGLE_KEY(wait_time_min)
SINGLE_KEY(wait_time_max)
+static int lock_stat_key_wait_time_min(struct lock_stat *one,
+ struct lock_stat *two)
+{
+ u64 s1 = one->wait_time_min;
+ u64 s2 = two->wait_time_min;
+ if (s1 == ULLONG_MAX)
+ s1 = 0;
+ if (s2 == ULLONG_MAX)
+ s2 = 0;
+ return s1 > s2;
+}
+
struct lock_key {
/*
* name: the value for specify by user
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 5f40df635dcb..9f5fc5492141 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -12,6 +12,8 @@
#include "util/trace-event.h"
#include "util/parse-options.h"
#include "util/util.h"
+#include "util/evlist.h"
+#include "util/evsel.h"
static char const *script_name;
static char const *generate_script_lang;
@@ -19,6 +21,183 @@ static bool debug_mode;
static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
+static bool no_callchain;
+
+enum perf_output_field {
+ PERF_OUTPUT_COMM = 1U << 0,
+ PERF_OUTPUT_TID = 1U << 1,
+ PERF_OUTPUT_PID = 1U << 2,
+ PERF_OUTPUT_TIME = 1U << 3,
+ PERF_OUTPUT_CPU = 1U << 4,
+ PERF_OUTPUT_EVNAME = 1U << 5,
+ PERF_OUTPUT_TRACE = 1U << 6,
+ PERF_OUTPUT_SYM = 1U << 7,
+};
+
+struct output_option {
+ const char *str;
+ enum perf_output_field field;
+} all_output_options[] = {
+ {.str = "comm", .field = PERF_OUTPUT_COMM},
+ {.str = "tid", .field = PERF_OUTPUT_TID},
+ {.str = "pid", .field = PERF_OUTPUT_PID},
+ {.str = "time", .field = PERF_OUTPUT_TIME},
+ {.str = "cpu", .field = PERF_OUTPUT_CPU},
+ {.str = "event", .field = PERF_OUTPUT_EVNAME},
+ {.str = "trace", .field = PERF_OUTPUT_TRACE},
+ {.str = "sym", .field = PERF_OUTPUT_SYM},
+};
+
+/* default set to maintain compatibility with current format */
+static u64 output_fields[PERF_TYPE_MAX] = {
+ [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
+ PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
+ PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
+
+ [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
+ PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
+ PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
+
+ [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
+ PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
+ PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
+};
+
+static bool output_set_by_user;
+
+#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x)
+
+static int perf_session__check_attr(struct perf_session *session,
+ struct perf_event_attr *attr)
+{
+ if (PRINT_FIELD(TRACE) &&
+ !perf_session__has_traces(session, "record -R"))
+ return -EINVAL;
+
+ if (PRINT_FIELD(SYM)) {
+ if (!(session->sample_type & PERF_SAMPLE_IP)) {
+ pr_err("Samples do not contain IP data.\n");
+ return -EINVAL;
+ }
+ if (!no_callchain &&
+ !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
+ symbol_conf.use_callchain = false;
+ }
+
+ if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
+ !(session->sample_type & PERF_SAMPLE_TID)) {
+ pr_err("Samples do not contain TID/PID data.\n");
+ return -EINVAL;
+ }
+
+ if (PRINT_FIELD(TIME) &&
+ !(session->sample_type & PERF_SAMPLE_TIME)) {
+ pr_err("Samples do not contain timestamps.\n");
+ return -EINVAL;
+ }
+
+ if (PRINT_FIELD(CPU) &&
+ !(session->sample_type & PERF_SAMPLE_CPU)) {
+ pr_err("Samples do not contain cpu.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void print_sample_start(struct perf_sample *sample,
+ struct thread *thread,
+ struct perf_event_attr *attr)
+{
+ int type;
+ struct event *event;
+ const char *evname = NULL;
+ unsigned long secs;
+ unsigned long usecs;
+ unsigned long long nsecs;
+
+ if (PRINT_FIELD(COMM)) {
+ if (latency_format)
+ printf("%8.8s ", thread->comm);
+ else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
+ printf("%s ", thread->comm);
+ else
+ printf("%16s ", thread->comm);
+ }
+
+ if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
+ printf("%5d/%-5d ", sample->pid, sample->tid);
+ else if (PRINT_FIELD(PID))
+ printf("%5d ", sample->pid);
+ else if (PRINT_FIELD(TID))
+ printf("%5d ", sample->tid);
+
+ if (PRINT_FIELD(CPU)) {
+ if (latency_format)
+ printf("%3d ", sample->cpu);
+ else
+ printf("[%03d] ", sample->cpu);
+ }
+
+ if (PRINT_FIELD(TIME)) {
+ nsecs = sample->time;
+ secs = nsecs / NSECS_PER_SEC;
+ nsecs -= secs * NSECS_PER_SEC;
+ usecs = nsecs / NSECS_PER_USEC;
+ printf("%5lu.%06lu: ", secs, usecs);
+ }
+
+ if (PRINT_FIELD(EVNAME)) {
+ if (attr->type == PERF_TYPE_TRACEPOINT) {
+ type = trace_parse_common_type(sample->raw_data);
+ event = trace_find_event(type);
+ if (event)
+ evname = event->name;
+ } else
+ evname = __event_name(attr->type, attr->config);
+
+ printf("%s: ", evname ? evname : "(unknown)");
+ }
+}
+
+static void process_event(union perf_event *event __unused,
+ struct perf_sample *sample,
+ struct perf_session *session,
+ struct thread *thread)
+{
+ struct perf_event_attr *attr;
+ struct perf_evsel *evsel;
+
+ evsel = perf_evlist__id2evsel(session->evlist, sample->id);
+ if (evsel == NULL) {
+ pr_err("Invalid data. Contains samples with id not in "
+ "its header!\n");
+ return;
+ }
+ attr = &evsel->attr;
+
+ if (output_fields[attr->type] == 0)
+ return;
+
+ if (perf_session__check_attr(session, attr) < 0)
+ return;
+
+ print_sample_start(sample, thread, attr);
+
+ if (PRINT_FIELD(TRACE))
+ print_trace_event(sample->cpu, sample->raw_data,
+ sample->raw_size);
+
+ if (PRINT_FIELD(SYM)) {
+ if (!symbol_conf.use_callchain)
+ printf(" ");
+ else
+ printf("\n");
+ perf_session__print_symbols(event, sample, session);
+ }
+
+ printf("\n");
+}
static int default_start_script(const char *script __unused,
int argc __unused,
@@ -40,7 +219,7 @@ static int default_generate_script(const char *outfile __unused)
static struct scripting_ops default_scripting_ops = {
.start_script = default_start_script,
.stop_script = default_stop_script,
- .process_event = print_event,
+ .process_event = process_event,
.generate_script = default_generate_script,
};
@@ -75,26 +254,17 @@ static int process_sample_event(union perf_event *event,
return -1;
}
- if (session->sample_type & PERF_SAMPLE_RAW) {
- if (debug_mode) {
- if (sample->time < last_timestamp) {
- pr_err("Samples misordered, previous: %" PRIu64
- " this: %" PRIu64 "\n", last_timestamp,
- sample->time);
- nr_unordered++;
- }
- last_timestamp = sample->time;
- return 0;
+ if (debug_mode) {
+ if (sample->time < last_timestamp) {
+ pr_err("Samples misordered, previous: %" PRIu64
+ " this: %" PRIu64 "\n", last_timestamp,
+ sample->time);
+ nr_unordered++;
}
- /*
- * FIXME: better resolve from pid from the struct trace_entry
- * field, although it should be the same than this perf
- * event pid
- */
- scripting_ops->process_event(sample->cpu, sample->raw_data,
- sample->raw_size,
- sample->time, thread->comm);
+ last_timestamp = sample->time;
+ return 0;
}
+ scripting_ops->process_event(event, sample, session, thread);
session->hists.stats.total_period += sample->period;
return 0;
@@ -102,7 +272,10 @@ static int process_sample_event(union perf_event *event,
static struct perf_event_ops event_ops = {
.sample = process_sample_event,
+ .mmap = perf_event__process_mmap,
.comm = perf_event__process_comm,
+ .exit = perf_event__process_task,
+ .fork = perf_event__process_task,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
@@ -280,6 +453,68 @@ static int parse_scriptname(const struct option *opt __used,
return 0;
}
+static int parse_output_fields(const struct option *opt __used,
+ const char *arg, int unset __used)
+{
+ char *tok;
+ int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
+ int rc = 0;
+ char *str = strdup(arg);
+ int type = -1;
+
+ if (!str)
+ return -ENOMEM;
+
+ tok = strtok(str, ":");
+ if (!tok) {
+ fprintf(stderr,
+ "Invalid field string - not prepended with type.");
+ return -EINVAL;
+ }
+
+ /* first word should state which event type user
+ * is specifying the fields
+ */
+ if (!strcmp(tok, "hw"))
+ type = PERF_TYPE_HARDWARE;
+ else if (!strcmp(tok, "sw"))
+ type = PERF_TYPE_SOFTWARE;
+ else if (!strcmp(tok, "trace"))
+ type = PERF_TYPE_TRACEPOINT;
+ else {
+ fprintf(stderr, "Invalid event type in field string.");
+ return -EINVAL;
+ }
+
+ output_fields[type] = 0;
+ while (1) {
+ tok = strtok(NULL, ",");
+ if (!tok)
+ break;
+ for (i = 0; i < imax; ++i) {
+ if (strcmp(tok, all_output_options[i].str) == 0) {
+ output_fields[type] |= all_output_options[i].field;
+ break;
+ }
+ }
+ if (i == imax) {
+ fprintf(stderr, "Invalid field requested.");
+ rc = -EINVAL;
+ break;
+ }
+ }
+
+ if (output_fields[type] == 0) {
+ pr_debug("No fields requested for %s type. "
+ "Events will not be displayed\n", event_type(type));
+ }
+
+ output_set_by_user = true;
+
+ free(str);
+ return rc;
+}
+
/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
static int is_directory(const char *base_path, const struct dirent *dent)
{
@@ -592,6 +827,17 @@ static const struct option options[] = {
"input file name"),
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
"do various checks like samples ordering and lost events"),
+ OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+ "file", "vmlinux pathname"),
+ OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
+ "file", "kallsyms pathname"),
+ OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
+ "When printing symbols do not display call chain"),
+ OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
+ OPT_CALLBACK('f', "fields", NULL, "str",
+ "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym",
+ parse_output_fields),
OPT_END()
};
@@ -772,14 +1018,22 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
if (session == NULL)
return -ENOMEM;
- if (strcmp(input_name, "-") &&
- !perf_session__has_traces(session, "record -R"))
- return -EINVAL;
+ if (!no_callchain)
+ symbol_conf.use_callchain = true;
+ else
+ symbol_conf.use_callchain = false;
if (generate_script_lang) {
struct stat perf_stat;
+ int input;
+
+ if (output_set_by_user) {
+ fprintf(stderr,
+ "custom fields not supported for generated scripts");
+ return -1;
+ }
- int input = open(input_name, O_RDONLY);
+ input = open(input_name, O_RDONLY);
if (input < 0) {
perror("failed to open file");
exit(-1);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 21c025222496..e2109f9b43eb 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -333,6 +333,12 @@ static int run_perf_stat(int argc __used, const char **argv)
}
}
+ if (perf_evlist__set_filters(evsel_list)) {
+ error("failed to set filter with %d (%s)\n", errno,
+ strerror(errno));
+ return -1;
+ }
+
/*
* Enable counters and exec the command:
*/
@@ -634,6 +640,8 @@ static const struct option options[] = {
OPT_CALLBACK('e', "event", &evsel_list, "event",
"event selector. use 'perf list' to list available events",
parse_events),
+ OPT_CALLBACK(0, "filter", &evsel_list, "filter",
+ "event filter", parse_filter),
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
"child tasks do not inherit counters"),
OPT_INTEGER('p', "pid", &target_pid,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 80c9e062bd5b..70f1075cc5b0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -152,7 +152,7 @@ static int parse_source(struct sym_entry *syme)
/*
* We can't annotate with just /proc/kallsyms
*/
- if (map->dso->origin == DSO__ORIG_KERNEL) {
+ if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
pr_err("Can't annotate %s: No vmlinux file was found in the "
"path\n", sym->name);
sleep(1);
@@ -515,24 +515,25 @@ static void handle_keypress(struct perf_session *session, int c)
break;
case 'E':
if (top.evlist->nr_entries > 1) {
+ int counter;
fprintf(stderr, "\nAvailable events:");
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
- prompt_integer(&top.sym_counter, "Enter details event counter");
+ prompt_integer(&counter, "Enter details event counter");
- if (top.sym_counter >= top.evlist->nr_entries) {
+ if (counter >= top.evlist->nr_entries) {
top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
- top.sym_counter = 0;
fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
sleep(1);
break;
}
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
- if (top.sym_evsel->idx == top.sym_counter)
+ if (top.sym_evsel->idx == counter)
break;
- } else top.sym_counter = 0;
+ } else
+ top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
break;
case 'f':
prompt_integer(&top.count_filter, "Enter display event count filter");
@@ -675,7 +676,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
for (i = 0; skip_symbols[i]; i++) {
if (!strcmp(skip_symbols[i], name)) {
- syme->skip = 1;
+ sym->ignore = true;
break;
}
}
@@ -768,7 +769,7 @@ static void perf_event__process_sample(const union perf_event *event,
struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
pr_err("Can't annotate %s", sym->name);
- if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
+ if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
pr_err(": No vmlinux file was found in the path:\n");
machine__fprintf_vmlinux_path(machine, stderr);
} else
@@ -778,10 +779,9 @@ static void perf_event__process_sample(const union perf_event *event,
}
syme = symbol__priv(al.sym);
- if (!syme->skip) {
+ if (!al.sym->ignore) {
struct perf_evsel *evsel;
- syme->origin = origin;
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
assert(evsel != NULL);
syme->count[evsel->idx]++;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index c7798c7f24ed..4702e2443a8e 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -19,6 +19,7 @@ extern int cmd_bench(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
+extern int cmd_evlist(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
extern int cmd_sched(int argc, const char **argv, const char *prefix);
extern int cmd_list(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 16b5088cf8f4..d695fe40fbff 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -8,6 +8,7 @@ perf-bench mainporcelain common
perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common
perf-diff mainporcelain common
+perf-evlist mainporcelain common
perf-inject mainporcelain common
perf-list mainporcelain common
perf-sched mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 595d0f4a7103..ec635b7cc8ea 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -313,6 +313,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "buildid-cache", cmd_buildid_cache, 0 },
{ "buildid-list", cmd_buildid_list, 0 },
{ "diff", cmd_diff, 0 },
+ { "evlist", cmd_evlist, 0 },
{ "help", cmd_help, 0 },
{ "list", cmd_list, 0 },
{ "record", cmd_record, 0 },
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 97d76562a1a0..26d4d3fd6deb 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -23,10 +23,10 @@ if test -d ../../.git -o -f ../../.git &&
then
VN=$(echo "$VN" | sed -e 's/-/./g');
else
- eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '`
- eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
- eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
- eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
+ eval $(grep '^VERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
+ eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
+ eval $(grep '^SUBLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
+ eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
fi
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 0d0830c98cd7..e01af2b1a469 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -294,7 +294,7 @@ fallback:
free_filename = false;
}
- if (dso->origin == DSO__ORIG_KERNEL) {
+ if (dso->symtab_type == SYMTAB__KALLSYMS) {
char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
char *build_id_msg = NULL;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 54a7e2634d58..952b4ae3d954 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -263,6 +263,28 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
return name;
}
+const char *event_type(int type)
+{
+ switch (type) {
+ case PERF_TYPE_HARDWARE:
+ return "hardware";
+
+ case PERF_TYPE_SOFTWARE:
+ return "software";
+
+ case PERF_TYPE_TRACEPOINT:
+ return "tracepoint";
+
+ case PERF_TYPE_HW_CACHE:
+ return "hardware-cache";
+
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
const char *event_name(struct perf_evsel *evsel)
{
u64 config = evsel->attr.config;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 212f88e07a9c..746d3fcbfc2a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -20,6 +20,7 @@ struct tracepoint_path {
extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern bool have_tracepoints(struct list_head *evlist);
+const char *event_type(int type);
const char *event_name(struct perf_evsel *event);
extern const char *__event_name(int type, u64 config);
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 93680818e244..621427212e86 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -245,9 +245,10 @@ static inline struct event *find_cache_event(int type)
return event;
}
-static void perl_process_event(int cpu, void *data,
- int size __unused,
- unsigned long long nsecs, char *comm)
+static void perl_process_event(union perf_event *pevent __unused,
+ struct perf_sample *sample,
+ struct perf_session *session __unused,
+ struct thread *thread)
{
struct format_field *field;
static char handler[256];
@@ -256,6 +257,10 @@ static void perl_process_event(int cpu, void *data,
struct event *event;
int type;
int pid;
+ int cpu = sample->cpu;
+ void *data = sample->raw_data;
+ unsigned long long nsecs = sample->time;
+ char *comm = thread->comm;
dSP;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 2040b8538527..1b85d6055159 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -204,9 +204,10 @@ static inline struct event *find_cache_event(int type)
return event;
}
-static void python_process_event(int cpu, void *data,
- int size __unused,
- unsigned long long nsecs, char *comm)
+static void python_process_event(union perf_event *pevent __unused,
+ struct perf_sample *sample,
+ struct perf_session *session __unused,
+ struct thread *thread)
{
PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
static char handler_name[256];
@@ -217,6 +218,10 @@ static void python_process_event(int cpu, void *data,
unsigned n = 0;
int type;
int pid;
+ int cpu = sample->cpu;
+ void *data = sample->raw_data;
+ unsigned long long nsecs = sample->time;
+ char *comm = thread->comm;
t = PyTuple_New(MAX_FIELDS);
if (!t)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f26639fa0fb3..c68cf40764f9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
return ret;
}
+
+void perf_session__print_symbols(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session)
+{
+ struct addr_location al;
+ const char *symname, *dsoname;
+ struct callchain_cursor *cursor = &session->callchain_cursor;
+ struct callchain_cursor_node *node;
+
+ if (perf_event__preprocess_sample(event, session, &al, sample,
+ NULL) < 0) {
+ error("problem processing %d event, skipping it.\n",
+ event->header.type);
+ return;
+ }
+
+ if (symbol_conf.use_callchain && sample->callchain) {
+
+ if (perf_session__resolve_callchain(session, al.thread,
+ sample->callchain, NULL) != 0) {
+ if (verbose)
+ error("Failed to resolve callchain. Skipping\n");
+ return;
+ }
+ callchain_cursor_commit(cursor);
+
+ while (1) {
+ node = callchain_cursor_current(cursor);
+ if (!node)
+ break;
+
+ if (node->sym && node->sym->name)
+ symname = node->sym->name;
+ else
+ symname = "";
+
+ if (node->map && node->map->dso && node->map->dso->name)
+ dsoname = node->map->dso->name;
+ else
+ dsoname = "";
+
+ printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
+
+ callchain_cursor_advance(cursor);
+ }
+
+ } else {
+ if (al.sym && al.sym->name)
+ symname = al.sym->name;
+ else
+ symname = "";
+
+ if (al.map && al.map->dso && al.map->dso->name)
+ dsoname = al.map->dso->name;
+ else
+ dsoname = "";
+
+ printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
+ }
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index b5b148b0aaca..0b3c9afecaa9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
session->sample_id_all, sample);
}
+void perf_session__print_symbols(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session);
+
#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 00014e32c288..651dbfe7f4f3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -207,7 +207,7 @@ struct dso *dso__new(const char *name)
dso__set_short_name(self, self->name);
for (i = 0; i < MAP__NR_TYPES; ++i)
self->symbols[i] = self->symbol_names[i] = RB_ROOT;
- self->origin = DSO__ORIG_NOT_FOUND;
+ self->symtab_type = SYMTAB__NOT_FOUND;
self->loaded = 0;
self->sorted_by_name = 0;
self->has_build_id = 0;
@@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
return -1;
if (self->kernel == DSO_TYPE_GUEST_KERNEL)
- self->origin = DSO__ORIG_GUEST_KERNEL;
+ self->symtab_type = SYMTAB__GUEST_KALLSYMS;
else
- self->origin = DSO__ORIG_KERNEL;
+ self->symtab_type = SYMTAB__KALLSYMS;
return dso__split_kallsyms(self, map, filter);
}
@@ -1204,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
}
curr_map->map_ip = identity__map_ip;
curr_map->unmap_ip = identity__map_ip;
- curr_dso->origin = self->origin;
+ curr_dso->symtab_type = self->symtab_type;
map_groups__insert(kmap->kmaps, curr_map);
dsos__add(&self->node, curr_dso);
dso__set_loaded(curr_dso, map->type);
@@ -1430,21 +1430,21 @@ out:
char dso__symtab_origin(const struct dso *self)
{
static const char origin[] = {
- [DSO__ORIG_KERNEL] = 'k',
- [DSO__ORIG_JAVA_JIT] = 'j',
- [DSO__ORIG_BUILD_ID_CACHE] = 'B',
- [DSO__ORIG_FEDORA] = 'f',
- [DSO__ORIG_UBUNTU] = 'u',
- [DSO__ORIG_BUILDID] = 'b',
- [DSO__ORIG_DSO] = 'd',
- [DSO__ORIG_KMODULE] = 'K',
- [DSO__ORIG_GUEST_KERNEL] = 'g',
- [DSO__ORIG_GUEST_KMODULE] = 'G',
+ [SYMTAB__KALLSYMS] = 'k',
+ [SYMTAB__JAVA_JIT] = 'j',
+ [SYMTAB__BUILD_ID_CACHE] = 'B',
+ [SYMTAB__FEDORA_DEBUGINFO] = 'f',
+ [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
+ [SYMTAB__BUILDID_DEBUGINFO] = 'b',
+ [SYMTAB__SYSTEM_PATH_DSO] = 'd',
+ [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
+ [SYMTAB__GUEST_KALLSYMS] = 'g',
+ [SYMTAB__GUEST_KMODULE] = 'G',
};
- if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
+ if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)
return '!';
- return origin[self->origin];
+ return origin[self->symtab_type];
}
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
@@ -1477,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
ret = dso__load_perf_map(self, map, filter);
- self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
- DSO__ORIG_NOT_FOUND;
+ self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
+ SYMTAB__NOT_FOUND;
return ret;
}
@@ -1486,26 +1486,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
* On the first pass, only load images if they have a full symtab.
* Failing that, do a second pass where we accept .dynsym also
*/
- for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
- self->origin != DSO__ORIG_NOT_FOUND;
- self->origin++) {
- switch (self->origin) {
- case DSO__ORIG_BUILD_ID_CACHE:
+ for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1;
+ self->symtab_type != SYMTAB__NOT_FOUND;
+ self->symtab_type++) {
+ switch (self->symtab_type) {
+ case SYMTAB__BUILD_ID_CACHE:
/* skip the locally configured cache if a symfs is given */
if (symbol_conf.symfs[0] ||
(dso__build_id_filename(self, name, size) == NULL)) {
continue;
}
break;
- case DSO__ORIG_FEDORA:
+ case SYMTAB__FEDORA_DEBUGINFO:
snprintf(name, size, "%s/usr/lib/debug%s.debug",
symbol_conf.symfs, self->long_name);
break;
- case DSO__ORIG_UBUNTU:
+ case SYMTAB__UBUNTU_DEBUGINFO:
snprintf(name, size, "%s/usr/lib/debug%s",
symbol_conf.symfs, self->long_name);
break;
- case DSO__ORIG_BUILDID: {
+ case SYMTAB__BUILDID_DEBUGINFO: {
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
if (!self->has_build_id)
@@ -1519,11 +1519,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
}
break;
- case DSO__ORIG_DSO:
+ case SYMTAB__SYSTEM_PATH_DSO:
snprintf(name, size, "%s%s",
symbol_conf.symfs, self->long_name);
break;
- case DSO__ORIG_GUEST_KMODULE:
+ case SYMTAB__GUEST_KMODULE:
if (map->groups && machine)
root_dir = machine->root_dir;
else
@@ -1532,7 +1532,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
root_dir, self->long_name);
break;
- case DSO__ORIG_KMODULE:
+ case SYMTAB__SYSTEM_PATH_KMODULE:
snprintf(name, size, "%s%s", symbol_conf.symfs,
self->long_name);
break;
@@ -1544,7 +1544,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
*/
if (want_symtab) {
want_symtab = 0;
- self->origin = DSO__ORIG_BUILD_ID_CACHE;
+ self->symtab_type = SYMTAB__BUILD_ID_CACHE;
} else
continue;
}
@@ -1757,9 +1757,9 @@ struct map *machine__new_module(struct machine *self, u64 start,
return NULL;
if (machine__is_host(self))
- dso->origin = DSO__ORIG_KMODULE;
+ dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
else
- dso->origin = DSO__ORIG_GUEST_KMODULE;
+ dso->symtab_type = SYMTAB__GUEST_KMODULE;
map_groups__insert(&self->kmaps, map);
return map;
}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 4d7ed09fe332..713b0b40cc4a 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -48,12 +48,17 @@ char *strxfrchar(char *s, char from, char to);
#define BUILD_ID_SIZE 20
+/** struct symbol - symtab entry
+ *
+ * @ignore - resolvable but tools ignore it (e.g. idle routines)
+ */
struct symbol {
struct rb_node rb_node;
u64 start;
u64 end;
u16 namelen;
u8 binding;
+ bool ignore;
char name[0];
};
@@ -137,7 +142,7 @@ struct dso {
u8 annotate_warned:1;
u8 sname_alloc:1;
u8 lname_alloc:1;
- unsigned char origin;
+ unsigned char symtab_type;
u8 sorted_by_name;
u8 loaded;
u8 build_id[BUILD_ID_SIZE];
@@ -188,18 +193,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp);
size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
-enum dso_origin {
- DSO__ORIG_KERNEL = 0,
- DSO__ORIG_GUEST_KERNEL,
- DSO__ORIG_JAVA_JIT,
- DSO__ORIG_BUILD_ID_CACHE,
- DSO__ORIG_FEDORA,
- DSO__ORIG_UBUNTU,
- DSO__ORIG_BUILDID,
- DSO__ORIG_DSO,
- DSO__ORIG_GUEST_KMODULE,
- DSO__ORIG_KMODULE,
- DSO__ORIG_NOT_FOUND,
+enum symtab_type {
+ SYMTAB__KALLSYMS = 0,
+ SYMTAB__GUEST_KALLSYMS,
+ SYMTAB__JAVA_JIT,
+ SYMTAB__BUILD_ID_CACHE,
+ SYMTAB__FEDORA_DEBUGINFO,
+ SYMTAB__UBUNTU_DEBUGINFO,
+ SYMTAB__BUILDID_DEBUGINFO,
+ SYMTAB__SYSTEM_PATH_DSO,
+ SYMTAB__GUEST_KMODULE,
+ SYMTAB__SYSTEM_PATH_KMODULE,
+ SYMTAB__NOT_FOUND,
};
char dso__symtab_origin(const struct dso *self);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 75cfe4d45119..a11f60735a18 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -171,7 +171,7 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
{
struct sym_entry *syme, *n;
float sum_ksamples = 0.0;
- int snap = !top->display_weighted ? top->sym_counter : 0, j;
+ int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
/* Sort the active symbols */
pthread_mutex_lock(&top->active_symbols_lock);
@@ -184,9 +184,9 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
if (syme->snap_count != 0) {
if ((top->hide_user_symbols &&
- syme->origin == PERF_RECORD_MISC_USER) ||
+ syme->map->dso->kernel == DSO_TYPE_USER) ||
(top->hide_kernel_symbols &&
- syme->origin == PERF_RECORD_MISC_KERNEL)) {
+ syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
perf_top__remove_active_sym(top, syme);
continue;
}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 96d1cb78af01..bfbf95bcc603 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -16,8 +16,6 @@ struct sym_entry {
struct list_head node;
unsigned long snap_count;
double weight;
- int skip;
- u8 origin;
struct map *map;
unsigned long count[0];
};
@@ -41,7 +39,7 @@ struct perf_top {
u64 exact_samples;
u64 guest_us_samples, guest_kernel_samples;
int print_entries, count_filter, delay_secs;
- int display_weighted, freq, rb_entries, sym_counter;
+ int display_weighted, freq, rb_entries;
pid_t target_pid, target_tid;
bool hide_kernel_symbols, hide_user_symbols, zero;
const char *cpu_list;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index d8e622dd738a..0a7ed5b5e281 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -2643,68 +2643,13 @@ static void print_lat_fmt(void *data, int size __unused)
printf(".");
if (lock_depth < 0)
- printf(".");
+ printf(". ");
else
- printf("%d", lock_depth);
+ printf("%d ", lock_depth);
}
-/* taken from Linux, written by Frederic Weisbecker */
-static void print_graph_cpu(int cpu)
-{
- int i;
- int log10_this = log10_cpu(cpu);
- int log10_all = log10_cpu(cpus);
-
-
- /*
- * Start with a space character - to make it stand out
- * to the right a bit when trace output is pasted into
- * email:
- */
- printf(" ");
-
- /*
- * Tricky - we space the CPU field according to the max
- * number of online CPUs. On a 2-cpu system it would take
- * a maximum of 1 digit - on a 128 cpu system it would
- * take up to 3 digits:
- */
- for (i = 0; i < log10_all - log10_this; i++)
- printf(" ");
-
- printf("%d) ", cpu);
-}
-
-#define TRACE_GRAPH_PROCINFO_LENGTH 14
#define TRACE_GRAPH_INDENT 2
-static void print_graph_proc(int pid, const char *comm)
-{
- /* sign + log10(MAX_INT) + '\0' */
- char pid_str[11];
- int spaces = 0;
- int len;
- int i;
-
- sprintf(pid_str, "%d", pid);
-
- /* 1 stands for the "-" character */
- len = strlen(comm) + strlen(pid_str) + 1;
-
- if (len < TRACE_GRAPH_PROCINFO_LENGTH)
- spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
-
- /* First spaces to align center */
- for (i = 0; i < spaces / 2; i++)
- printf(" ");
-
- printf("%s-%s", comm, pid_str);
-
- /* Last spaces to align center */
- for (i = 0; i < spaces - (spaces / 2); i++)
- printf(" ");
-}
-
static struct record *
get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
struct record *next)
@@ -2876,21 +2821,13 @@ static void print_graph_nested(struct event *event, void *data)
static void
pretty_print_func_ent(void *data, int size, struct event *event,
- int cpu, int pid, const char *comm,
- unsigned long secs, unsigned long usecs)
+ int cpu, int pid)
{
struct format_field *field;
struct record *rec;
void *copy_data;
unsigned long val;
- printf("%5lu.%06lu | ", secs, usecs);
-
- print_graph_cpu(cpu);
- print_graph_proc(pid, comm);
-
- printf(" | ");
-
if (latency_format) {
print_lat_fmt(data, size);
printf(" | ");
@@ -2923,22 +2860,13 @@ out_free:
}
static void
-pretty_print_func_ret(void *data, int size __unused, struct event *event,
- int cpu, int pid, const char *comm,
- unsigned long secs, unsigned long usecs)
+pretty_print_func_ret(void *data, int size __unused, struct event *event)
{
unsigned long long rettime, calltime;
unsigned long long duration, depth;
struct format_field *field;
int i;
- printf("%5lu.%06lu | ", secs, usecs);
-
- print_graph_cpu(cpu);
- print_graph_proc(pid, comm);
-
- printf(" | ");
-
if (latency_format) {
print_lat_fmt(data, size);
printf(" | ");
@@ -2976,31 +2904,21 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
static void
pretty_print_func_graph(void *data, int size, struct event *event,
- int cpu, int pid, const char *comm,
- unsigned long secs, unsigned long usecs)
+ int cpu, int pid)
{
if (event->flags & EVENT_FL_ISFUNCENT)
- pretty_print_func_ent(data, size, event,
- cpu, pid, comm, secs, usecs);
+ pretty_print_func_ent(data, size, event, cpu, pid);
else if (event->flags & EVENT_FL_ISFUNCRET)
- pretty_print_func_ret(data, size, event,
- cpu, pid, comm, secs, usecs);
+ pretty_print_func_ret(data, size, event);
printf("\n");
}
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
- char *comm)
+void print_trace_event(int cpu, void *data, int size)
{
struct event *event;
- unsigned long secs;
- unsigned long usecs;
int type;
int pid;
- secs = nsecs / NSECS_PER_SEC;
- nsecs -= secs * NSECS_PER_SEC;
- usecs = nsecs / NSECS_PER_USEC;
-
type = trace_parse_common_type(data);
event = trace_find_event(type);
@@ -3012,17 +2930,10 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
pid = trace_parse_common_pid(data);
if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
- return pretty_print_func_graph(data, size, event, cpu,
- pid, comm, secs, usecs);
+ return pretty_print_func_graph(data, size, event, cpu, pid);
- if (latency_format) {
- printf("%8.8s-%-5d %3d",
- comm, pid, cpu);
+ if (latency_format)
print_lat_fmt(data, size);
- } else
- printf("%16s-%-5d [%03d]", comm, pid, cpu);
-
- printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
if (event->flags & EVENT_FL_FAILED) {
printf("EVENT '%s' FAILED TO PARSE\n",
@@ -3031,7 +2942,6 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
}
pretty_print(data, size, event);
- printf("\n");
}
static void print_fields(struct print_flag_sym *field)
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index f7af2fca965d..66f4b78737ab 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -36,11 +36,10 @@ static int stop_script_unsupported(void)
return 0;
}
-static void process_event_unsupported(int cpu __unused,
- void *data __unused,
- int size __unused,
- unsigned long long nsecs __unused,
- char *comm __unused)
+static void process_event_unsupported(union perf_event *event __unused,
+ struct perf_sample *sample __unused,
+ struct perf_session *session __unused,
+ struct thread *thread __unused)
{
}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b5f12ca24d99..b04da5722437 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "parse-events.h"
+#include "session.h"
#define __unused __attribute__((unused))
@@ -176,8 +177,7 @@ void print_printk(void);
int parse_ftrace_file(char *buf, unsigned long size);
int parse_event_file(char *buf, unsigned long size, char *sys);
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
- char *comm);
+void print_trace_event(int cpu, void *data, int size);
extern int file_bigendian;
extern int host_bigendian;
@@ -278,8 +278,10 @@ struct scripting_ops {
const char *name;
int (*start_script) (const char *script, int argc, const char **argv);
int (*stop_script) (void);
- void (*process_event) (int cpu, void *data, int size,
- unsigned long long nsecs, char *comm);
+ void (*process_event) (union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session,
+ struct thread *thread);
int (*generate_script) (const char *outfile);
};
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index 2ca4535f4fb7..3656849f78a0 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -313,8 +313,9 @@ kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) {
/*
* This rcu_assign_pointer is needed for when
- * another thread calls kvm_irqfd_update before
- * we flush workqueue below.
+ * another thread calls kvm_irq_routing_update before
+ * we flush workqueue below (we synchronize with
+ * kvm_irq_routing_update using irqfds.lock).
* It is paired with synchronize_rcu done by caller
* of that function.
*/
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f29abeb6a912..1fa0d292119a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -69,7 +69,7 @@ MODULE_LICENSE("GPL");
* kvm->lock --> kvm->slots_lock --> kvm->irq_lock
*/
-DEFINE_SPINLOCK(kvm_lock);
+DEFINE_RAW_SPINLOCK(kvm_lock);
LIST_HEAD(vm_list);
static cpumask_var_t cpus_hardware_enabled;
@@ -137,6 +137,14 @@ void vcpu_load(struct kvm_vcpu *vcpu)
int cpu;
mutex_lock(&vcpu->mutex);
+ if (unlikely(vcpu->pid != current->pids[PIDTYPE_PID].pid)) {
+ /* The thread running this VCPU changed. */
+ struct pid *oldpid = vcpu->pid;
+ struct pid *newpid = get_task_pid(current, PIDTYPE_PID);
+ rcu_assign_pointer(vcpu->pid, newpid);
+ synchronize_rcu();
+ put_pid(oldpid);
+ }
cpu = get_cpu();
preempt_notifier_register(&vcpu->preempt_notifier);
kvm_arch_vcpu_load(vcpu, cpu);
@@ -165,13 +173,16 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
zalloc_cpumask_var(&cpus, GFP_ATOMIC);
- raw_spin_lock(&kvm->requests_lock);
- me = smp_processor_id();
+ me = get_cpu();
kvm_for_each_vcpu(i, vcpu, kvm) {
- if (kvm_make_check_request(req, vcpu))
- continue;
+ kvm_make_request(req, vcpu);
cpu = vcpu->cpu;
- if (cpus != NULL && cpu != -1 && cpu != me)
+
+ /* Set ->requests bit before we read ->mode */
+ smp_mb();
+
+ if (cpus != NULL && cpu != -1 && cpu != me &&
+ kvm_vcpu_exiting_guest_mode(vcpu) != OUTSIDE_GUEST_MODE)
cpumask_set_cpu(cpu, cpus);
}
if (unlikely(cpus == NULL))
@@ -180,7 +191,7 @@ static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
smp_call_function_many(cpus, ack_flush, NULL, 1);
else
called = false;
- raw_spin_unlock(&kvm->requests_lock);
+ put_cpu();
free_cpumask_var(cpus);
return called;
}
@@ -209,6 +220,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
vcpu->cpu = -1;
vcpu->kvm = kvm;
vcpu->vcpu_id = id;
+ vcpu->pid = NULL;
init_waitqueue_head(&vcpu->wq);
kvm_async_pf_vcpu_init(vcpu);
@@ -233,6 +245,7 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_init);
void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
{
+ put_pid(vcpu->pid);
kvm_arch_vcpu_uninit(vcpu);
free_page((unsigned long)vcpu->run);
}
@@ -463,15 +476,14 @@ static struct kvm *kvm_create_vm(void)
kvm->mm = current->mm;
atomic_inc(&kvm->mm->mm_count);
spin_lock_init(&kvm->mmu_lock);
- raw_spin_lock_init(&kvm->requests_lock);
kvm_eventfd_init(kvm);
mutex_init(&kvm->lock);
mutex_init(&kvm->irq_lock);
mutex_init(&kvm->slots_lock);
atomic_set(&kvm->users_count, 1);
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
return kvm;
@@ -544,9 +556,9 @@ static void kvm_destroy_vm(struct kvm *kvm)
struct mm_struct *mm = kvm->mm;
kvm_arch_sync_events(kvm);
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_del(&kvm->vm_list);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
kvm_free_irq_routing(kvm);
for (i = 0; i < KVM_NR_BUSES; i++)
kvm_io_bus_destroy(kvm->buses[i]);
@@ -588,6 +600,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
return 0;
}
+#ifndef CONFIG_S390
/*
* Allocation size is twice as large as the actual dirty bitmap size.
* This makes it possible to do double buffering: see x86's
@@ -608,6 +621,7 @@ static int kvm_create_dirty_bitmap(struct kvm_memory_slot *memslot)
memslot->dirty_bitmap_head = memslot->dirty_bitmap;
return 0;
}
+#endif /* !CONFIG_S390 */
/*
* Allocate some memory and give it an address in the guest physical address
@@ -621,7 +635,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
int user_alloc)
{
- int r, flush_shadow = 0;
+ int r;
gfn_t base_gfn;
unsigned long npages;
unsigned long i;
@@ -741,8 +755,6 @@ skip_lpage:
if (kvm_create_dirty_bitmap(&new) < 0)
goto out_free;
/* destroy any largepage mappings for dirty tracking */
- if (old.npages)
- flush_shadow = 1;
}
#else /* not defined CONFIG_S390 */
new.user_alloc = user_alloc;
@@ -813,9 +825,6 @@ skip_lpage:
kvm_free_physmem_slot(&old, &new);
kfree(old_memslots);
- if (flush_shadow)
- kvm_arch_flush_shadow(kvm);
-
return 0;
out_free:
@@ -1029,6 +1038,15 @@ static pfn_t get_fault_pfn(void)
return fault_pfn;
}
+static inline int check_user_page_hwpoison(unsigned long addr)
+{
+ int rc, flags = FOLL_TOUCH | FOLL_HWPOISON | FOLL_WRITE;
+
+ rc = __get_user_pages(current, current->mm, addr, 1,
+ flags, NULL, NULL, NULL);
+ return rc == -EHWPOISON;
+}
+
static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
bool *async, bool write_fault, bool *writable)
{
@@ -1076,7 +1094,7 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
return get_fault_pfn();
down_read(&current->mm->mmap_sem);
- if (is_hwpoison_address(addr)) {
+ if (check_user_page_hwpoison(addr)) {
up_read(&current->mm->mmap_sem);
get_page(hwpoison_page);
return page_to_pfn(hwpoison_page);
@@ -1466,18 +1484,55 @@ void kvm_resched(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_resched);
-void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu)
+void kvm_vcpu_on_spin(struct kvm_vcpu *me)
{
- ktime_t expires;
- DEFINE_WAIT(wait);
-
- prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
-
- /* Sleep for 100 us, and hope lock-holder got scheduled */
- expires = ktime_add_ns(ktime_get(), 100000UL);
- schedule_hrtimeout(&expires, HRTIMER_MODE_ABS);
+ struct kvm *kvm = me->kvm;
+ struct kvm_vcpu *vcpu;
+ int last_boosted_vcpu = me->kvm->last_boosted_vcpu;
+ int yielded = 0;
+ int pass;
+ int i;
- finish_wait(&vcpu->wq, &wait);
+ /*
+ * We boost the priority of a VCPU that is runnable but not
+ * currently running, because it got preempted by something
+ * else and called schedule in __vcpu_run. Hopefully that
+ * VCPU is holding the lock that we need and will release it.
+ * We approximate round-robin by starting at the last boosted VCPU.
+ */
+ for (pass = 0; pass < 2 && !yielded; pass++) {
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ struct task_struct *task = NULL;
+ struct pid *pid;
+ if (!pass && i < last_boosted_vcpu) {
+ i = last_boosted_vcpu;
+ continue;
+ } else if (pass && i > last_boosted_vcpu)
+ break;
+ if (vcpu == me)
+ continue;
+ if (waitqueue_active(&vcpu->wq))
+ continue;
+ rcu_read_lock();
+ pid = rcu_dereference(vcpu->pid);
+ if (pid)
+ task = get_pid_task(vcpu->pid, PIDTYPE_PID);
+ rcu_read_unlock();
+ if (!task)
+ continue;
+ if (task->flags & PF_VCPU) {
+ put_task_struct(task);
+ continue;
+ }
+ if (yield_to(task, 1)) {
+ put_task_struct(task);
+ kvm->last_boosted_vcpu = i;
+ yielded = 1;
+ break;
+ }
+ put_task_struct(task);
+ }
+ }
}
EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin);
@@ -2122,9 +2177,9 @@ static void hardware_enable_nolock(void *junk)
static void hardware_enable(void *junk)
{
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
hardware_enable_nolock(junk);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
}
static void hardware_disable_nolock(void *junk)
@@ -2139,9 +2194,9 @@ static void hardware_disable_nolock(void *junk)
static void hardware_disable(void *junk)
{
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
hardware_disable_nolock(junk);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
}
static void hardware_disable_all_nolock(void)
@@ -2155,16 +2210,16 @@ static void hardware_disable_all_nolock(void)
static void hardware_disable_all(void)
{
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
hardware_disable_all_nolock();
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
}
static int hardware_enable_all(void)
{
int r = 0;
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
kvm_usage_count++;
if (kvm_usage_count == 1) {
@@ -2177,7 +2232,7 @@ static int hardware_enable_all(void)
}
}
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
return r;
}
@@ -2339,10 +2394,10 @@ static int vm_stat_get(void *_offset, u64 *val)
struct kvm *kvm;
*val = 0;
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list)
*val += *(u32 *)((void *)kvm + offset);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
return 0;
}
@@ -2356,12 +2411,12 @@ static int vcpu_stat_get(void *_offset, u64 *val)
int i;
*val = 0;
- spin_lock(&kvm_lock);
+ raw_spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list)
kvm_for_each_vcpu(i, vcpu, kvm)
*val += *(u32 *)((void *)vcpu + offset);
- spin_unlock(&kvm_lock);
+ raw_spin_unlock(&kvm_lock);
return 0;
}
@@ -2402,7 +2457,7 @@ static int kvm_suspend(struct sys_device *dev, pm_message_t state)
static int kvm_resume(struct sys_device *dev)
{
if (kvm_usage_count) {
- WARN_ON(spin_is_locked(&kvm_lock));
+ WARN_ON(raw_spin_is_locked(&kvm_lock));
hardware_enable_nolock(NULL);
}
return 0;