summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig19
-rw-r--r--arch/arm/boot/compressed/Makefile34
-rw-r--r--arch/arm/boot/compressed/misc.c116
-rw-r--r--arch/arm/boot/compressed/piggy.gzip.S6
-rw-r--r--arch/arm/boot/compressed/piggy.lzo.S (renamed from arch/arm/boot/compressed/piggy.S)2
-rw-r--r--arch/arm/common/clkdev.c10
-rw-r--r--arch/arm/common/dmabounce.c4
-rw-r--r--arch/arm/configs/raumfeld_defconfig1898
-rw-r--r--arch/arm/configs/u300_defconfig81
-rw-r--r--arch/arm/include/asm/cacheflush.h56
-rw-r--r--arch/arm/include/asm/clkdev.h3
-rw-r--r--arch/arm/include/asm/cpu.h1
-rw-r--r--arch/arm/include/asm/dma-mapping.h79
-rw-r--r--arch/arm/include/asm/dma.h4
-rw-r--r--arch/arm/include/asm/entry-macro-vic2.S57
-rw-r--r--arch/arm/include/asm/io.h15
-rw-r--r--arch/arm/include/asm/kgdb.h11
-rw-r--r--arch/arm/include/asm/kmap_types.h1
-rw-r--r--arch/arm/include/asm/mach/time.h8
-rw-r--r--arch/arm/include/asm/page.h7
-rw-r--r--arch/arm/include/asm/ptrace.h6
-rw-r--r--arch/arm/include/asm/setup.h12
-rw-r--r--arch/arm/include/asm/smp_plat.h5
-rw-r--r--arch/arm/include/asm/unistd.h1
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/asm-offsets.c5
-rw-r--r--arch/arm/kernel/entry-armv.S4
-rw-r--r--arch/arm/kernel/kgdb.c13
-rw-r--r--arch/arm/kernel/leds.c115
-rw-r--r--arch/arm/kernel/process.c3
-rw-r--r--arch/arm/kernel/setup.c77
-rw-r--r--arch/arm/kernel/time.c178
-rw-r--r--arch/arm/kernel/traps.c5
-rw-r--r--arch/arm/kernel/vmlinux.lds.S4
-rw-r--r--arch/arm/mach-bcmring/core.c3
-rw-r--r--arch/arm/mach-davinci/Kconfig4
-rw-r--r--arch/arm/mach-davinci/Makefile3
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c34
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c1
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c11
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c1
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c143
-rw-r--r--arch/arm/mach-davinci/cdce949.c289
-rw-r--r--arch/arm/mach-davinci/clock.c71
-rw-r--r--arch/arm/mach-davinci/clock.h25
-rw-r--r--arch/arm/mach-davinci/common.c2
-rw-r--r--arch/arm/mach-davinci/cp_intc.c11
-rw-r--r--arch/arm/mach-davinci/cpuidle.c38
-rw-r--r--arch/arm/mach-davinci/da830.c8
-rw-r--r--arch/arm/mach-davinci/da850.c82
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c155
-rw-r--r--arch/arm/mach-davinci/dm355.c8
-rw-r--r--arch/arm/mach-davinci/dm365.c3
-rw-r--r--arch/arm/mach-davinci/dm644x.c10
-rw-r--r--arch/arm/mach-davinci/dm646x.c12
-rw-r--r--arch/arm/mach-davinci/dma.c67
-rw-r--r--arch/arm/mach-davinci/include/mach/cdce949.h19
-rw-r--r--arch/arm/mach-davinci/include/mach/cpuidle.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h18
-rw-r--r--arch/arm/mach-davinci/include/mach/dm365.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/dm644x.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/dm646x.h4
-rw-r--r--arch/arm/mach-davinci/include/mach/edma.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/emac.h36
-rw-r--r--arch/arm/mach-davinci/include/mach/i2c.h2
-rw-r--r--arch/arm/mach-davinci/include/mach/keyscan.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/memory.h5
-rw-r--r--arch/arm/mach-davinci/include/mach/mux.h1
-rw-r--r--arch/arm/mach-davinci/include/mach/pm.h54
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h15
-rw-r--r--arch/arm/mach-davinci/include/mach/timex.h7
-rw-r--r--arch/arm/mach-davinci/io.c2
-rw-r--r--arch/arm/mach-davinci/pm.c158
-rw-r--r--arch/arm/mach-davinci/psc.c11
-rw-r--r--arch/arm/mach-davinci/sleep.S224
-rw-r--r--arch/arm/mach-ep93xx/clock.c30
-rw-r--r--arch/arm/mach-ep93xx/core.c9
-rw-r--r--arch/arm/mach-ep93xx/dma-m2p.c6
-rw-r--r--arch/arm/mach-ep93xx/edb93xx.c21
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h7
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ts72xx.h19
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c188
-rw-r--r--arch/arm/mach-footbridge/common.c7
-rw-r--r--arch/arm/mach-integrator/core.c3
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c4
-rw-r--r--arch/arm/mach-iop13xx/io.c7
-rw-r--r--arch/arm/mach-lh7a40x/clocks.c2
-rw-r--r--arch/arm/mach-mmp/clock.c8
-rw-r--r--arch/arm/mach-mmp/clock.h2
-rw-r--r--arch/arm/mach-mmp/pxa168.c2
-rw-r--r--arch/arm/mach-mmp/pxa910.c2
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c2
-rw-r--r--arch/arm/mach-msm/Kconfig671
-rw-r--r--arch/arm/mach-msm/Makefile75
-rw-r--r--arch/arm/mach-msm/Makefile.boot18
-rw-r--r--arch/arm/mach-msm/acpuclock-8x50.c723
-rw-r--r--arch/arm/mach-msm/acpuclock.c915
-rw-r--r--arch/arm/mach-msm/acpuclock.h39
-rw-r--r--arch/arm/mach-msm/avs.c323
-rw-r--r--arch/arm/mach-msm/avs.h52
-rw-r--r--arch/arm/mach-msm/avs_hw.S158
-rw-r--r--arch/arm/mach-msm/board-comet.c488
-rw-r--r--arch/arm/mach-msm/board-halibut-keypad.c177
-rw-r--r--arch/arm/mach-msm/board-halibut.c704
-rw-r--r--arch/arm/mach-msm/board-msm7x27.c1195
-rw-r--r--arch/arm/mach-msm/board-msm7x30.c209
-rw-r--r--arch/arm/mach-msm/board-qsd8x50.c538
-rw-r--r--arch/arm/mach-msm/board-sapphire-gpio.c326
-rw-r--r--arch/arm/mach-msm/board-sapphire-h2w.c545
-rw-r--r--arch/arm/mach-msm/board-sapphire-keypad.c122
-rw-r--r--arch/arm/mach-msm/board-sapphire-mmc.c479
-rw-r--r--arch/arm/mach-msm/board-sapphire-panel.c656
-rw-r--r--arch/arm/mach-msm/board-sapphire-rfkill.c99
-rw-r--r--arch/arm/mach-msm/board-sapphire-wifi.c74
-rw-r--r--arch/arm/mach-msm/board-sapphire.c1175
-rw-r--r--arch/arm/mach-msm/board-sapphire.h219
-rw-r--r--arch/arm/mach-msm/board-trout-gpio.c305
-rw-r--r--arch/arm/mach-msm/board-trout-keypad.c345
-rw-r--r--arch/arm/mach-msm/board-trout-mmc.c437
-rw-r--r--arch/arm/mach-msm/board-trout-panel.c642
-rw-r--r--arch/arm/mach-msm/board-trout-rfkill.c93
-rw-r--r--arch/arm/mach-msm/board-trout-wifi.c74
-rw-r--r--arch/arm/mach-msm/board-trout.c841
-rw-r--r--arch/arm/mach-msm/board-trout.h162
-rw-r--r--arch/arm/mach-msm/clock-7x01a.c126
-rw-r--r--arch/arm/mach-msm/clock-7x30.c957
-rw-r--r--arch/arm/mach-msm/clock-7x30.h143
-rw-r--r--arch/arm/mach-msm/clock-pcom.c130
-rw-r--r--arch/arm/mach-msm/clock-pcom.h147
-rw-r--r--arch/arm/mach-msm/clock.c332
-rw-r--r--arch/arm/mach-msm/clock.h69
-rw-r--r--arch/arm/mach-msm/cpufreq.c126
-rw-r--r--arch/arm/mach-msm/dal.c1363
-rw-r--r--arch/arm/mach-msm/dal_remotetest.c454
-rw-r--r--arch/arm/mach-msm/dal_remotetest.h187
-rw-r--r--arch/arm/mach-msm/devices.c358
-rw-r--r--arch/arm/mach-msm/devices.h24
-rw-r--r--arch/arm/mach-msm/devices_htc.c450
-rw-r--r--arch/arm/mach-msm/dma.c81
-rw-r--r--arch/arm/mach-msm/dma_test.c404
-rw-r--r--arch/arm/mach-msm/fiq_glue.S64
-rw-r--r--arch/arm/mach-msm/generic_gpio.c274
-rw-r--r--arch/arm/mach-msm/gpio.c746
-rw-r--r--arch/arm/mach-msm/gpio.h35
-rw-r--r--arch/arm/mach-msm/gpio_chip.h61
-rw-r--r--arch/arm/mach-msm/gpio_hw-7x30.h112
-rw-r--r--arch/arm/mach-msm/gpio_hw-7xxx.h73
-rw-r--r--arch/arm/mach-msm/gpio_hw-8xxx.h112
-rw-r--r--arch/arm/mach-msm/gpio_hw.h49
-rw-r--r--arch/arm/mach-msm/htc_acoustic.c239
-rw-r--r--arch/arm/mach-msm/htc_akm_cal.c64
-rw-r--r--arch/arm/mach-msm/htc_battery.c769
-rw-r--r--arch/arm/mach-msm/htc_headset.c1246
-rw-r--r--arch/arm/mach-msm/htc_pwrsink.c281
-rw-r--r--arch/arm/mach-msm/htc_wifi_nvs.c56
-rw-r--r--arch/arm/mach-msm/idle-v6.S177
-rw-r--r--arch/arm/mach-msm/idle-v7.S175
-rw-r--r--arch/arm/mach-msm/idle.S36
-rw-r--r--arch/arm/mach-msm/idle.h36
-rw-r--r--arch/arm/mach-msm/include/mach/board.h30
-rw-r--r--arch/arm/mach-msm/include/mach/board_htc.h78
-rw-r--r--arch/arm/mach-msm/include/mach/camera.h297
-rw-r--r--arch/arm/mach-msm/include/mach/clk.h53
-rw-r--r--arch/arm/mach-msm/include/mach/dal.h155
-rw-r--r--arch/arm/mach-msm/include/mach/dma.h40
-rw-r--r--arch/arm/mach-msm/include/mach/dma_test.h67
-rw-r--r--arch/arm/mach-msm/include/mach/fiq.h33
-rw-r--r--arch/arm/mach-msm/include/mach/gpio.h167
-rw-r--r--arch/arm/mach-msm/include/mach/htc_headset.h173
-rw-r--r--arch/arm/mach-msm/include/mach/htc_pwrsink.h87
-rw-r--r--arch/arm/mach-msm/include/mach/internal_power_rail.h46
-rw-r--r--arch/arm/mach-msm/include/mach/io.h2
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-7x30.h158
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-7xxx.h76
-rw-r--r--arch/arm/mach-msm/include/mach/irqs-8xxx.h104
-rw-r--r--arch/arm/mach-msm/include/mach/irqs.h81
-rw-r--r--arch/arm/mach-msm/include/mach/memory.h29
-rw-r--r--arch/arm/mach-msm/include/mach/mmc.h18
-rw-r--r--arch/arm/mach-msm/include/mach/mpp.h73
-rw-r--r--arch/arm/mach-msm/include/mach/msm_handset.h34
-rw-r--r--arch/arm/mach-msm/include/mach/msm_i2ckbd.h41
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap.h102
-rw-r--r--arch/arm/mach-msm/include/mach/msm_otg.h72
-rw-r--r--arch/arm/mach-msm/include/mach/msm_rpcrouter.h296
-rw-r--r--arch/arm/mach-msm/include/mach/msm_smd.h82
-rw-r--r--arch/arm/mach-msm/include/mach/msm_touch.h26
-rw-r--r--arch/arm/mach-msm/include/mach/msm_touchpad.h37
-rw-r--r--arch/arm/mach-msm/include/mach/oem_rapi_client.h91
-rw-r--r--arch/arm/mach-msm/include/mach/pmic.h557
-rw-r--r--arch/arm/mach-msm/include/mach/remote_spinlock.h115
-rw-r--r--arch/arm/mach-msm/include/mach/rpc_hsusb.h45
-rw-r--r--arch/arm/mach-msm/include/mach/sirc.h103
-rw-r--r--arch/arm/mach-msm/include/mach/smem_log.h245
-rw-r--r--arch/arm/mach-msm/include/mach/system.h5
-rw-r--r--arch/arm/mach-msm/include/mach/uncompress.h1
-rw-r--r--arch/arm/mach-msm/include/mach/usbdiag.h44
-rw-r--r--arch/arm/mach-msm/include/mach/vmalloc.h7
-rw-r--r--arch/arm/mach-msm/include/mach/vreg.h2
-rw-r--r--arch/arm/mach-msm/internal_power_rail.c90
-rw-r--r--arch/arm/mach-msm/io.c128
-rw-r--r--arch/arm/mach-msm/irq.c535
-rw-r--r--arch/arm/mach-msm/irq.h43
-rw-r--r--arch/arm/mach-msm/jtag-v7.S117
-rw-r--r--arch/arm/mach-msm/keypad-surf-ffa.c316
-rw-r--r--arch/arm/mach-msm/keypad-surf-ffa.h29
-rw-r--r--arch/arm/mach-msm/memory.c86
-rw-r--r--arch/arm/mach-msm/modem_notifier.c237
-rw-r--r--arch/arm/mach-msm/modem_notifier.h48
-rw-r--r--arch/arm/mach-msm/mpp.c176
-rw-r--r--arch/arm/mach-msm/msm-keypad-devices.h22
-rw-r--r--arch/arm/mach-msm/msm_vibrator.c137
-rw-r--r--arch/arm/mach-msm/nand_partitions.c187
-rw-r--r--arch/arm/mach-msm/nohlt.c86
-rw-r--r--arch/arm/mach-msm/oem_rapi_client.c489
-rw-r--r--arch/arm/mach-msm/ping_mdm_rpc_client.c772
-rw-r--r--arch/arm/mach-msm/pm.c954
-rw-r--r--arch/arm/mach-msm/pm.h42
-rw-r--r--arch/arm/mach-msm/pm2.c1666
-rw-r--r--arch/arm/mach-msm/pmic.c1095
-rw-r--r--arch/arm/mach-msm/pmic8058-gpio.c150
-rw-r--r--arch/arm/mach-msm/pmic8058-mpp.c105
-rw-r--r--arch/arm/mach-msm/pmic_debugfs.c1200
-rw-r--r--arch/arm/mach-msm/proc_comm.c93
-rw-r--r--arch/arm/mach-msm/proc_comm.h192
-rw-r--r--arch/arm/mach-msm/proc_comm_test.c169
-rw-r--r--arch/arm/mach-msm/remote_spinlock.c85
-rw-r--r--arch/arm/mach-msm/reset_modem.c226
-rw-r--r--arch/arm/mach-msm/rpc_hsusb.c574
-rw-r--r--arch/arm/mach-msm/rpc_server_dog_keepalive.c77
-rw-r--r--arch/arm/mach-msm/rpc_server_handset.c380
-rw-r--r--arch/arm/mach-msm/rpc_server_time_remote.c90
-rw-r--r--arch/arm/mach-msm/rpc_server_time_remote.h21
-rw-r--r--arch/arm/mach-msm/sirc.c239
-rw-r--r--arch/arm/mach-msm/smd.c1960
-rw-r--r--arch/arm/mach-msm/smd_ctl2.c677
-rw-r--r--arch/arm/mach-msm/smd_nmea.c249
-rw-r--r--arch/arm/mach-msm/smd_private.h256
-rw-r--r--arch/arm/mach-msm/smd_qmi.c844
-rw-r--r--arch/arm/mach-msm/smd_rpcrouter.c2199
-rw-r--r--arch/arm/mach-msm/smd_rpcrouter.h210
-rw-r--r--arch/arm/mach-msm/smd_rpcrouter_clients.c607
-rw-r--r--arch/arm/mach-msm/smd_rpcrouter_device.c380
-rw-r--r--arch/arm/mach-msm/smd_rpcrouter_servers.c434
-rw-r--r--arch/arm/mach-msm/smd_tty.c284
-rw-r--r--arch/arm/mach-msm/smem_log.c2024
-rw-r--r--arch/arm/mach-msm/socinfo.c430
-rw-r--r--arch/arm/mach-msm/socinfo.h97
-rw-r--r--arch/arm/mach-msm/timer.c714
-rw-r--r--arch/arm/mach-msm/timer.h38
-rw-r--r--arch/arm/mach-msm/vreg.c170
-rw-r--r--arch/arm/mach-mx1/clock.c4
-rw-r--r--arch/arm/mach-mx2/clock_imx21.c4
-rw-r--r--arch/arm/mach-mx2/clock_imx27.c4
-rw-r--r--arch/arm/mach-mx2/mxt_td60.c24
-rw-r--r--arch/arm/mach-mx25/clock.c8
-rw-r--r--arch/arm/mach-mx25/devices.c19
-rw-r--r--arch/arm/mach-mx25/devices.h1
-rw-r--r--arch/arm/mach-mx25/mx25pdk.c46
-rw-r--r--arch/arm/mach-mx3/Kconfig3
-rw-r--r--arch/arm/mach-mx3/clock-imx35.c4
-rw-r--r--arch/arm/mach-mx3/clock.c4
-rw-r--r--arch/arm/mach-mx3/mm.c5
-rw-r--r--arch/arm/mach-mx3/mx31ads.c5
-rw-r--r--arch/arm/mach-mx3/mx31lite.c9
-rw-r--r--arch/arm/mach-mx3/mx31moboard-devboard.c2
-rw-r--r--arch/arm/mach-mx3/mx31moboard-marxbot.c2
-rw-r--r--arch/arm/mach-mx3/mx31moboard.c7
-rw-r--r--arch/arm/mach-mx3/mx31pdk.c5
-rw-r--r--arch/arm/mach-mx3/pcm037.c32
-rw-r--r--arch/arm/mach-mxc91231/clock.c4
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c8
-rw-r--r--arch/arm/mach-omap1/Makefile2
-rw-r--r--arch/arm/mach-omap1/board-fsample.c9
-rw-r--r--arch/arm/mach-omap1/board-h2.c9
-rw-r--r--arch/arm/mach-omap1/board-h3.c9
-rw-r--r--arch/arm/mach-omap1/board-innovator.c9
-rw-r--r--arch/arm/mach-omap1/board-osk.c9
-rw-r--r--arch/arm/mach-omap1/board-palmte.c9
-rw-r--r--arch/arm/mach-omap1/board-palmtt.c9
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c10
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c9
-rw-r--r--arch/arm/mach-omap1/board-sx1.c11
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c9
-rw-r--r--arch/arm/mach-omap1/clock_data.c10
-rw-r--r--arch/arm/mach-omap1/devices.c35
-rw-r--r--arch/arm/mach-omap1/flash.c33
-rw-r--r--arch/arm/mach-omap1/mux.c8
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c7
-rw-r--r--[-rwxr-xr-x]arch/arm/mach-omap2/board-3630sdp.c0
-rw-r--r--arch/arm/mach-omap2/board-h4.c7
-rw-r--r--[-rwxr-xr-x]arch/arm/mach-omap2/board-zoom-peripherals.c17
-rw-r--r--arch/arm/mach-omap2/board-zoom3.c14
-rw-r--r--arch/arm/mach-omap2/clock2xxx.c57
-rw-r--r--arch/arm/mach-omap2/clock34xx.c1
-rw-r--r--arch/arm/mach-omap2/clock34xx_data.c6
-rw-r--r--arch/arm/mach-omap2/clockdomain.c4
-rw-r--r--arch/arm/mach-omap2/io.c19
-rw-r--r--arch/arm/mach-omap2/mux.c41
-rw-r--r--arch/arm/mach-omap2/opp2420_data.c38
-rw-r--r--arch/arm/mach-omap2/opp2430_data.c30
-rw-r--r--arch/arm/mach-omap2/pm34xx.c4
-rw-r--r--arch/arm/mach-omap2/serial.c31
-rw-r--r--arch/arm/mach-pnx4008/clock.c173
-rw-r--r--arch/arm/mach-pnx4008/clock.h6
-rw-r--r--arch/arm/mach-pnx4008/i2c.c108
-rw-r--r--arch/arm/mach-pnx4008/include/mach/clkdev.h7
-rw-r--r--arch/arm/mach-pnx4008/include/mach/timex.h54
-rw-r--r--arch/arm/mach-pnx4008/pm.c2
-rw-r--r--arch/arm/mach-pnx4008/time.c2
-rw-r--r--arch/arm/mach-pnx4008/time.h70
-rw-r--r--arch/arm/mach-pxa/Kconfig20
-rw-r--r--arch/arm/mach-pxa/Makefile3
-rw-r--r--arch/arm/mach-pxa/clock.c8
-rw-r--r--arch/arm/mach-pxa/clock.h4
-rw-r--r--arch/arm/mach-pxa/eseries.c2
-rw-r--r--arch/arm/mach-pxa/include/mach/hardware.h9
-rw-r--r--arch/arm/mach-pxa/include/mach/zylonite.h7
-rw-r--r--arch/arm/mach-pxa/littleton.c6
-rw-r--r--arch/arm/mach-pxa/magician.c2
-rw-r--r--arch/arm/mach-pxa/palmld.c2
-rw-r--r--arch/arm/mach-pxa/palmt5.c2
-rw-r--r--arch/arm/mach-pxa/palmtc.c2
-rw-r--r--arch/arm/mach-pxa/palmte2.c2
-rw-r--r--arch/arm/mach-pxa/palmtreo.c2
-rw-r--r--arch/arm/mach-pxa/palmtx.c2
-rw-r--r--arch/arm/mach-pxa/palmz72.c2
-rw-r--r--arch/arm/mach-pxa/poodle.c2
-rw-r--r--arch/arm/mach-pxa/pxa25x.c4
-rw-r--r--arch/arm/mach-pxa/pxa27x.c2
-rw-r--r--arch/arm/mach-pxa/pxa300.c4
-rw-r--r--arch/arm/mach-pxa/pxa320.c2
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c2
-rw-r--r--arch/arm/mach-pxa/raumfeld.c1100
-rw-r--r--arch/arm/mach-pxa/spitz.c4
-rw-r--r--arch/arm/mach-pxa/viper.c2
-rw-r--r--arch/arm/mach-pxa/zeus.c36
-rw-r--r--arch/arm/mach-pxa/zylonite.c87
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa300.c12
-rw-r--r--arch/arm/mach-pxa/zylonite_pxa320.c4
-rw-r--r--arch/arm/mach-realview/core.c5
-rw-r--r--arch/arm/mach-realview/include/mach/board-pb1176.h4
-rw-r--r--arch/arm/mach-realview/include/mach/platform.h2
-rw-r--r--arch/arm/mach-realview/realview_eb.c15
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c10
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c11
-rw-r--r--arch/arm/mach-realview/realview_pba8.c15
-rw-r--r--arch/arm/mach-realview/realview_pbx.c15
-rw-r--r--arch/arm/mach-s3c2410/include/mach/spi-gpio.h2
-rw-r--r--arch/arm/mach-s3c2412/clock.c52
-rw-r--r--arch/arm/mach-s3c2440/clock.c6
-rw-r--r--arch/arm/mach-s3c2442/clock.c6
-rw-r--r--arch/arm/mach-s3c2443/clock.c97
-rw-r--r--arch/arm/mach-s3c6400/include/mach/entry-macro.S28
-rw-r--r--arch/arm/mach-s3c6400/include/mach/map.h4
-rw-r--r--arch/arm/mach-s3c6400/include/mach/tick.h2
-rw-r--r--arch/arm/mach-s5pc100/setup-sdhci.c4
-rw-r--r--arch/arm/mach-u300/clock.c5
-rw-r--r--arch/arm/mach-ux500/clock.c5
-rw-r--r--arch/arm/mach-versatile/core.c3
-rw-r--r--arch/arm/mach-w90x900/clock.c9
-rw-r--r--arch/arm/mach-w90x900/clock.h1
-rw-r--r--arch/arm/mach-w90x900/cpu.c2
-rw-r--r--arch/arm/mach-w90x900/include/mach/system.h15
-rw-r--r--arch/arm/mach-w90x900/time.c64
-rw-r--r--arch/arm/mm/Makefile12
-rw-r--r--arch/arm/mm/alignment.c6
-rw-r--r--arch/arm/mm/cache-fa.S32
-rw-r--r--arch/arm/mm/cache-v3.S43
-rw-r--r--arch/arm/mm/cache-v4.S43
-rw-r--r--arch/arm/mm/cache-v4wb.S32
-rw-r--r--arch/arm/mm/cache-v4wt.S40
-rw-r--r--arch/arm/mm/cache-v6.S34
-rw-r--r--arch/arm/mm/cache-v7.S34
-rw-r--r--arch/arm/mm/cache-xsc3l2.c11
-rw-r--r--arch/arm/mm/copypage-feroceon.c3
-rw-r--r--arch/arm/mm/copypage-v3.c2
-rw-r--r--arch/arm/mm/copypage-v4mc.c2
-rw-r--r--arch/arm/mm/copypage-v4wb.c3
-rw-r--r--arch/arm/mm/copypage-v4wt.c2
-rw-r--r--arch/arm/mm/copypage-v6.c4
-rw-r--r--arch/arm/mm/copypage-xsc3.c3
-rw-r--r--arch/arm/mm/copypage-xscale.c2
-rw-r--r--arch/arm/mm/dma-mapping.c159
-rw-r--r--arch/arm/mm/flush.c51
-rw-r--r--arch/arm/mm/init.c14
-rw-r--r--arch/arm/mm/ioremap.c57
-rw-r--r--arch/arm/mm/mmu.c41
-rw-r--r--arch/arm/mm/nommu.c12
-rw-r--r--arch/arm/mm/proc-arm1020.S32
-rw-r--r--arch/arm/mm/proc-arm1020e.S32
-rw-r--r--arch/arm/mm/proc-arm1022.S32
-rw-r--r--arch/arm/mm/proc-arm1026.S32
-rw-r--r--arch/arm/mm/proc-arm920.S32
-rw-r--r--arch/arm/mm/proc-arm922.S32
-rw-r--r--arch/arm/mm/proc-arm925.S32
-rw-r--r--arch/arm/mm/proc-arm926.S32
-rw-r--r--arch/arm/mm/proc-arm940.S32
-rw-r--r--arch/arm/mm/proc-arm946.S32
-rw-r--r--arch/arm/mm/proc-feroceon.S54
-rw-r--r--arch/arm/mm/proc-mohawk.S32
-rw-r--r--arch/arm/mm/proc-xsc3.S39
-rw-r--r--arch/arm/mm/proc-xscale.S49
-rw-r--r--arch/arm/mm/tlb-v7.S1
-rw-r--r--arch/arm/plat-iop/io.c3
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx25.h58
-rw-r--r--arch/arm/plat-mxc/include/mach/mx25.h4
-rw-r--r--arch/arm/plat-omap/clock.c16
-rw-r--r--arch/arm/plat-omap/cpu-omap.c1
-rw-r--r--arch/arm/plat-omap/dma.c2
-rw-r--r--arch/arm/plat-omap/gpio.c63
-rw-r--r--arch/arm/plat-omap/include/plat/board.h1
-rw-r--r--arch/arm/plat-omap/include/plat/clock.h2
-rw-r--r--arch/arm/plat-omap/include/plat/control.h2
-rw-r--r--arch/arm/plat-omap/include/plat/flash.h16
-rw-r--r--arch/arm/plat-omap/include/plat/io.h36
-rw-r--r--arch/arm/plat-omap/include/plat/mux.h8
-rw-r--r--arch/arm/plat-omap/include/plat/omap7xx.h3
-rw-r--r--arch/arm/plat-omap/io.c14
-rw-r--r--arch/arm/plat-omap/iommu.c2
-rw-r--r--arch/arm/plat-omap/mcbsp.c20
-rw-r--r--arch/arm/plat-pxa/pwm.c8
-rw-r--r--arch/arm/plat-s3c/Kconfig75
-rw-r--r--arch/arm/plat-s3c/Makefile17
-rw-r--r--arch/arm/plat-s3c/include/plat/nand.h2
-rw-r--r--arch/arm/plat-s3c24xx/clock-dclk.c22
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x-clock.c4
-rw-r--r--arch/arm/plat-s3c64xx/Kconfig3
-rw-r--r--arch/arm/plat-s3c64xx/clock.c10
-rw-r--r--arch/arm/plat-s3c64xx/cpu.c4
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/irqs.h8
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/regs-clock.h71
-rw-r--r--arch/arm/plat-s3c64xx/irq.c209
-rw-r--r--arch/arm/plat-s3c64xx/s3c6400-clock.c518
-rw-r--r--arch/arm/plat-s5pc1xx/clock.c20
-rw-r--r--arch/arm/plat-s5pc1xx/s5pc100-clock.c126
-rw-r--r--arch/arm/plat-samsung/Kconfig102
-rw-r--r--arch/arm/plat-samsung/Makefile22
-rw-r--r--arch/arm/plat-samsung/clock-clksrc.c203
-rw-r--r--arch/arm/plat-samsung/clock.c (renamed from arch/arm/plat-s3c/clock.c)55
-rw-r--r--arch/arm/plat-samsung/dev-fb.c (renamed from arch/arm/plat-s3c/dev-fb.c)0
-rw-r--r--arch/arm/plat-samsung/dev-hsmmc.c (renamed from arch/arm/plat-s3c/dev-hsmmc.c)0
-rw-r--r--arch/arm/plat-samsung/dev-hsmmc1.c (renamed from arch/arm/plat-s3c/dev-hsmmc1.c)0
-rw-r--r--arch/arm/plat-samsung/dev-hsmmc2.c (renamed from arch/arm/plat-s3c/dev-hsmmc2.c)0
-rw-r--r--arch/arm/plat-samsung/dev-i2c0.c (renamed from arch/arm/plat-s3c/dev-i2c0.c)0
-rw-r--r--arch/arm/plat-samsung/dev-i2c1.c (renamed from arch/arm/plat-s3c/dev-i2c1.c)0
-rw-r--r--arch/arm/plat-samsung/dev-nand.c (renamed from arch/arm/plat-s3c/dev-nand.c)0
-rw-r--r--arch/arm/plat-samsung/dev-usb-hsotg.c (renamed from arch/arm/plat-s3c/dev-usb-hsotg.c)0
-rw-r--r--arch/arm/plat-samsung/dev-usb.c (renamed from arch/arm/plat-s3c/dev-usb.c)0
-rw-r--r--arch/arm/plat-samsung/gpio-config.c (renamed from arch/arm/plat-s3c/gpio-config.c)0
-rw-r--r--arch/arm/plat-samsung/include/plat/clock-clksrc.h83
-rw-r--r--arch/arm/plat-samsung/include/plat/clock.h (renamed from arch/arm/plat-s3c/include/plat/clock.h)34
-rw-r--r--arch/arm/plat-samsung/include/plat/irq-uart.h20
-rw-r--r--arch/arm/plat-samsung/include/plat/irq-vic-timer.h13
-rw-r--r--arch/arm/plat-samsung/irq-uart.c143
-rw-r--r--arch/arm/plat-samsung/irq-vic-timer.c86
-rw-r--r--arch/arm/plat-samsung/pwm-clock.c (renamed from arch/arm/plat-s3c/pwm-clock.c)112
-rw-r--r--arch/arm/plat-stmp3xxx/clock.c3
459 files changed, 56274 insertions, 3539 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 233a222752c0..2e5784e1ae42 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -18,6 +18,8 @@ config ARM
select HAVE_KRETPROBES if (HAVE_KPROBES)
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
select HAVE_GENERIC_DMA_COHERENT
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZO
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -50,6 +52,9 @@ config HAVE_TCM
bool
select GENERIC_ALLOCATOR
+config HAVE_PROC_CPU
+ bool
+
config NO_IOPORT
bool
@@ -552,6 +557,7 @@ config ARCH_PNX4008
bool "Philips Nexperia PNX4008 Mobile"
select CPU_ARM926T
select HAVE_CLK
+ select COMMON_CLKDEV
help
This enables support for Philips PNX4008 mobile platform.
@@ -573,14 +579,14 @@ config ARCH_PXA
config ARCH_MSM
bool "Qualcomm MSM"
- select CPU_V6
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
help
- Support for Qualcomm MSM7K based systems. This runs on the ARM11
- apps processor of the MSM7K and depends on a shared memory
- interface to the ARM9 modem processor which runs the baseband stack
- and controls some vital subsystems (clock and power control, etc).
+ Support for Qualcomm MSM/QSD based systems. This runs on the
+ apps processor of the MSM/QSD and depends on a shared memory
+ interface to the modem processor which runs the baseband
+ stack and controls some vital subsystems
+ (clock and power control, etc).
config ARCH_RPC
bool "RiscPC"
@@ -688,6 +694,7 @@ config ARCH_DAVINCI
select HAVE_IDE
select COMMON_CLKDEV
select GENERIC_ALLOCATOR
+ select ARCH_HAS_HOLES_MEMORYMODEL
help
Support for TI's DaVinci platform.
@@ -699,6 +706,7 @@ config ARCH_OMAP
select ARCH_HAS_CPUFREQ
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select ARCH_HAS_HOLES_MEMORYMODEL
help
Support for TI's OMAP platform (OMAP1 and OMAP2).
@@ -1226,6 +1234,7 @@ config ALIGNMENT_TRAP
bool
depends on CPU_CP15_MMU
default y if !ARCH_EBSA110
+ select HAVE_PROC_CPU if PROC_FS
help
ARM processors cannot fetch/store information which is not
naturally aligned on the bus, i.e., a 4 byte fetch must start at an
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index ce39dc540085..2d4d88ba73bf 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -63,8 +63,12 @@ endif
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
-targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \
- head.o misc.o $(OBJS)
+suffix_$(CONFIG_KERNEL_GZIP) = gzip
+suffix_$(CONFIG_KERNEL_LZO) = lzo
+
+targets := vmlinux vmlinux.lds \
+ piggy.$(suffix_y) piggy.$(suffix_y).o \
+ font.o font.c head.o misc.o $(OBJS)
ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
@@ -87,22 +91,34 @@ endif
ifneq ($(PARAMS_PHYS),)
LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS)
endif
-LDFLAGS_vmlinux += -p --no-undefined -X \
- $(shell $(CC) $(KBUILD_CFLAGS) --print-libgcc-file-name) -T
+# ?
+LDFLAGS_vmlinux += -p
+# Report unresolved symbol references
+LDFLAGS_vmlinux += --no-undefined
+# Delete all temporary local symbols
+LDFLAGS_vmlinux += -X
+# Next argument is a linker script
+LDFLAGS_vmlinux += -T
+
+# For __aeabi_uidivmod
+lib1funcs = $(obj)/lib1funcs.o
+
+$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
+ $(call cmd,shipped)
# Don't allow any static data in misc.o, which
# would otherwise mess up our GOT table
CFLAGS_misc.o := -Dstatic=
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
- $(addprefix $(obj)/, $(OBJS)) FORCE
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
+ $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
$(call if_changed,ld)
@:
-$(obj)/piggy.gz: $(obj)/../Image FORCE
- $(call if_changed,gzip)
+$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
+ $(call if_changed,$(suffix_y))
-$(obj)/piggy.o: $(obj)/piggy.gz FORCE
+$(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE
CFLAGS_font.o := -Dstatic=
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 17153b54613b..7e0fe4d42c7b 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -18,10 +18,15 @@
unsigned int __machine_arch_type;
+#define _LINUX_STRING_H_
+
#include <linux/compiler.h> /* for inline */
#include <linux/types.h> /* for size_t */
#include <linux/stddef.h> /* for NULL */
#include <asm/string.h>
+#include <linux/linkage.h>
+
+#include <asm/unaligned.h>
#ifdef STANDALONE_DEBUG
#define putstr printf
@@ -188,34 +193,8 @@ static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
/*
* gzip delarations
*/
-#define OF(args) args
#define STATIC static
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define WSIZE 0x8000 /* Window size must be at least 32k, */
- /* and a power of two */
-
-static uch *inbuf; /* input buffer */
-static uch window[WSIZE]; /* Sliding window buffer */
-
-static unsigned insize; /* valid bytes in inbuf */
-static unsigned inptr; /* index of next byte to be processed in inbuf */
-static unsigned outcnt; /* bytes in output buffer */
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
/* Diagnostic functions */
#ifdef DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
@@ -233,24 +212,20 @@ static unsigned outcnt; /* bytes in output buffer */
# define Tracecv(c,x)
#endif
-static int fill_inbuf(void);
-static void flush_window(void);
static void error(char *m);
extern char input_data[];
extern char input_data_end[];
-static uch *output_data;
-static ulg output_ptr;
-static ulg bytes_out;
+static unsigned char *output_data;
+static unsigned long output_ptr;
static void error(char *m);
static void putstr(const char *);
-extern int end;
-static ulg free_mem_ptr;
-static ulg free_mem_end_ptr;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
#ifdef STANDALONE_DEBUG
#define NO_INFLATE_MALLOC
@@ -258,46 +233,13 @@ static ulg free_mem_end_ptr;
#define ARCH_HAS_DECOMP_WDOG
-#include "../../../../lib/inflate.c"
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-int fill_inbuf(void)
-{
- if (insize != 0)
- error("ran out of input data");
-
- inbuf = input_data;
- insize = &input_data_end[0] - &input_data[0];
-
- inptr = 1;
- return inbuf[0];
-}
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-void flush_window(void)
-{
- ulg c = crc;
- unsigned n;
- uch *in, *out, ch;
-
- in = window;
- out = &output_data[output_ptr];
- for (n = 0; n < outcnt; n++) {
- ch = *out++ = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- output_ptr += (ulg)outcnt;
- outcnt = 0;
- putstr(".");
-}
+#ifdef CONFIG_KERNEL_LZO
+#include "../../../../lib/decompress_unlzo.c"
+#endif
#ifndef arch_error
#define arch_error(x)
@@ -314,22 +256,33 @@ static void error(char *x)
while(1); /* Halt */
}
+asmlinkage void __div0(void)
+{
+ error("Attempting division by 0!");
+}
+
#ifndef STANDALONE_DEBUG
-ulg
-decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
- int arch_id)
+unsigned long
+decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
+ unsigned long free_mem_ptr_end_p,
+ int arch_id)
{
- output_data = (uch *)output_start; /* Points to kernel start */
+ unsigned char *tmp;
+
+ output_data = (unsigned char *)output_start;
free_mem_ptr = free_mem_ptr_p;
free_mem_end_ptr = free_mem_ptr_end_p;
__machine_arch_type = arch_id;
arch_decomp_setup();
- makecrc();
+ tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
+ output_ptr = get_unaligned_le32(tmp);
+
putstr("Uncompressing Linux...");
- gunzip();
+ decompress(input_data, input_data_end - input_data,
+ NULL, NULL, output_data, NULL, error);
putstr(" done, booting the kernel.\n");
return output_ptr;
}
@@ -341,11 +294,10 @@ int main()
{
output_data = output_buffer;
- makecrc();
putstr("Uncompressing Linux...");
- gunzip();
+ decompress(input_data, input_data_end - input_data,
+ NULL, NULL, output_data, NULL, error);
putstr("done.\n");
return 0;
}
#endif
-
diff --git a/arch/arm/boot/compressed/piggy.gzip.S b/arch/arm/boot/compressed/piggy.gzip.S
new file mode 100644
index 000000000000..a68adf91a165
--- /dev/null
+++ b/arch/arm/boot/compressed/piggy.gzip.S
@@ -0,0 +1,6 @@
+ .section .piggydata,#alloc
+ .globl input_data
+input_data:
+ .incbin "arch/arm/boot/compressed/piggy.gzip"
+ .globl input_data_end
+input_data_end:
diff --git a/arch/arm/boot/compressed/piggy.S b/arch/arm/boot/compressed/piggy.lzo.S
index 54c951800ebd..a425ad95959a 100644
--- a/arch/arm/boot/compressed/piggy.S
+++ b/arch/arm/boot/compressed/piggy.lzo.S
@@ -1,6 +1,6 @@
.section .piggydata,#alloc
.globl input_data
input_data:
- .incbin "arch/arm/boot/compressed/piggy.gz"
+ .incbin "arch/arm/boot/compressed/piggy.lzo"
.globl input_data_end
input_data_end:
diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c
index aae5bc01acc8..446b696196e3 100644
--- a/arch/arm/common/clkdev.c
+++ b/arch/arm/common/clkdev.c
@@ -99,6 +99,16 @@ void clkdev_add(struct clk_lookup *cl)
}
EXPORT_SYMBOL(clkdev_add);
+void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+{
+ mutex_lock(&clocks_mutex);
+ while (num--) {
+ list_add_tail(&cl->node, &clocks);
+ cl++;
+ }
+ mutex_unlock(&clocks_mutex);
+}
+
#define MAX_DEV_ID 20
#define MAX_CON_ID 16
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index cc32c1e54a59..cc0a932bbea9 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -277,7 +277,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size,
* We don't need to sync the DMA buffer since
* it was allocated via the coherent allocators.
*/
- dma_cache_maint(ptr, size, dir);
+ __dma_single_cpu_to_dev(ptr, size, dir);
}
return dma_addr;
@@ -315,6 +315,8 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr,
__cpuc_flush_dcache_area(ptr, size);
}
free_safe_buffer(dev->archdata.dmabounce, buf);
+ } else {
+ __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir);
}
}
diff --git a/arch/arm/configs/raumfeld_defconfig b/arch/arm/configs/raumfeld_defconfig
new file mode 100644
index 000000000000..acb1a8f30e31
--- /dev/null
+++ b/arch/arm/configs/raumfeld_defconfig
@@ -0,0 +1,1898 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.32-rc5
+# Sun Nov 1 21:57:32 2009
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_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 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+CONFIG_SLOW_WORK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+
+#
+# Supported PXA3xx Processor Variants
+#
+CONFIG_CPU_PXA300=y
+# CONFIG_CPU_PXA310 is not set
+CONFIG_CPU_PXA320=y
+# CONFIG_CPU_PXA930 is not set
+# CONFIG_CPU_PXA935 is not set
+# CONFIG_CPU_PXA950 is not set
+
+#
+# Intel/Marvell Dev Platforms (sorted by hardware release time)
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+
+#
+# Third Party Dev Platforms (sorted by vendor name)
+#
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_VIPER is not set
+# CONFIG_MACH_BALLOON3 is not set
+# CONFIG_MACH_CSB726 is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_EXEDA is not set
+# CONFIG_MACH_CM_X300 is not set
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_MACH_INTELMOTE2 is not set
+# CONFIG_MACH_STARGATE2 is not set
+# CONFIG_MACH_XCEP is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_COLIBRI300 is not set
+# CONFIG_MACH_COLIBRI320 is not set
+
+#
+# End-user Products (sorted by vendor name)
+#
+# CONFIG_MACH_H4700 is not set
+# CONFIG_MACH_H5000 is not set
+# CONFIG_MACH_HIMALAYA is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_MIOA701 is not set
+# CONFIG_PXA_EZX is not set
+# CONFIG_MACH_MP900C is not set
+# CONFIG_ARCH_PXA_PALM is not set
+CONFIG_MACH_RAUMFELD_RC=y
+CONFIG_MACH_RAUMFELD_CONNECTOR=y
+CONFIG_MACH_RAUMFELD_PROTO=y
+CONFIG_MACH_RAUMFELD_SPEAKER=y
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+CONFIG_PXA3xx=y
+CONFIG_PXA_SSP=y
+CONFIG_PLAT_PXA=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSC3=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_IO_36=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_XSC3L2=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_IWMMXT=y
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="console=ttyS0,115200 rw"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+CONFIG_CFG80211_REG_DEBUG=y
+CONFIG_CFG80211_DEFAULT_PS=y
+CONFIG_CFG80211_DEFAULT_PS_VALUE=1
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_RC_MINSTREL=y
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+CONFIG_NFTL=y
+CONFIG_NFTL_RW=y
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_PXA3xx=y
+# CONFIG_MTD_NAND_PXA3xx_BUILTIN is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_ISL29003=y
+CONFIG_TI_DAC7512=y
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=y
+# CONFIG_LIBERTAS_USB is not set
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_SPI is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL12XX is not set
+# CONFIG_IWM is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+CONFIG_USB_NET_MCS7830=y
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+CONFIG_INPUT_POLLDEV=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_PXA27x is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+CONFIG_TOUCHSCREEN_EETI=m
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=y
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PXA=y
+# CONFIG_I2C_PXA_SLAVE is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+# CONFIG_SPI_PXA2XX is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+CONFIG_W1=m
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+CONFIG_W1_MASTER_GPIO=m
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+CONFIG_W1_SLAVE_DS2760=m
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+CONFIG_PDA_POWER=y
+# CONFIG_APM_POWER is not set
+CONFIG_BATTERY_DS2760=m
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_SENSORS_LIS3_SPI=y
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+CONFIG_REGULATOR_MAX8660=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_OVERLAY is not set
+# CONFIG_FB_PXA_SMARTPANEL is not set
+# CONFIG_FB_PXA_PARAMETERS is not set
+CONFIG_PXA3XX_GCU=y
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_W100 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_RAUMFELD_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_LIB=y
+# CONFIG_SND_PXA2XX_AC97 is not set
+CONFIG_SND_SPI=y
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_PXA2XX_SOC=y
+CONFIG_SND_PXA_SOC_SSP=y
+CONFIG_SND_SOC_RAUMFELD=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_AK4104=y
+CONFIG_SND_SOC_CS4270=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+# CONFIG_DRAGONRISE_FF is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_PXA=m
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_AT91 is not set
+# CONFIG_MMC_ATMELMCI is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
+CONFIG_LEDS_LT3593=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_SA1100 is not set
+CONFIG_RTC_DRV_PXA=y
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=y
+# CONFIG_UIO_PDRV is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_SMX is not set
+# CONFIG_UIO_SERCOS3 is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+CONFIG_FSCACHE=y
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_DEBUG is not set
+CONFIG_CACHEFILES=y
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig
index 610ac3c47b0f..9155196e623b 100644
--- a/arch/arm/configs/u300_defconfig
+++ b/arch/arm/configs/u300_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.32-rc5
-# Sat Oct 17 23:32:24 2009
+# Linux kernel version: 2.6.33-rc2
+# Wed Jan 6 00:01:36 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -46,6 +46,7 @@ CONFIG_SYSVIPC_SYSCTL=y
#
CONFIG_TREE_RCU=y
# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
# CONFIG_RCU_TRACE is not set
CONFIG_RCU_FANOUT=32
# CONFIG_RCU_FANOUT_EXACT is not set
@@ -119,14 +120,41 @@ CONFIG_BLOCK=y
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
CONFIG_IOSCHED_DEADLINE=y
# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_DEFAULT_AS is not set
CONFIG_DEFAULT_DEADLINE=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
# CONFIG_FREEZER is not set
#
@@ -155,6 +183,7 @@ CONFIG_MMU=y
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
# CONFIG_ARCH_KIRKWOOD is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
@@ -177,6 +206,7 @@ CONFIG_ARCH_U300=y
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_U8500 is not set
#
# ST-Ericsson AB U300/U330/U335/U365 Platform
@@ -265,12 +295,10 @@ CONFIG_FLATMEM_MANUAL=y
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_SPLIT_PTLOCK_CPUS=999999
# CONFIG_PHYS_ADDR_T_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_HAVE_MLOCK=y
-CONFIG_HAVE_MLOCKED_PAGE_BIT=y
# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ALIGNMENT_TRAP=y
@@ -499,14 +527,21 @@ CONFIG_MTD_NAND_IDS=y
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_ISL29003 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
# CONFIG_C2PORT is not set
#
@@ -517,6 +552,7 @@ CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -539,6 +575,7 @@ CONFIG_HAVE_IDE=y
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
#
# Userland interfaces
@@ -645,7 +682,6 @@ CONFIG_I2C_STU300=y
#
# Miscellaneous I2C Chip support
#
-# CONFIG_DS1682 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
@@ -661,6 +697,8 @@ CONFIG_SPI_MASTER=y
# CONFIG_SPI_BITBANG is not set
# CONFIG_SPI_GPIO is not set
CONFIG_SPI_PL022=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
#
# SPI Protocol Masters
@@ -708,6 +746,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X is not set
# CONFIG_MFD_WM8350_I2C is not set
@@ -716,6 +755,8 @@ CONFIG_SSB_POSSIBLE=y
CONFIG_AB3100_CORE=y
CONFIG_AB3100_OTP=y
# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_88PM8607 is not set
+# CONFIG_AB4500_CORE is not set
CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
@@ -723,6 +764,7 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
# CONFIG_REGULATOR_LP3971 is not set
CONFIG_REGULATOR_AB3100=y
# CONFIG_REGULATOR_TPS65023 is not set
@@ -840,7 +882,9 @@ CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_REGULATOR is not set
# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
#
# LED Triggers
@@ -882,6 +926,7 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8581 is not set
@@ -911,7 +956,9 @@ CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_DRV_M48T86 is not set
# CONFIG_RTC_DRV_M48T35 is not set
# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
# CONFIG_RTC_DRV_V3020 is not set
CONFIG_RTC_DRV_AB3100=y
@@ -926,6 +973,15 @@ CONFIG_DMADEVICES=y
#
# DMA Devices
#
+CONFIG_COH901318=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
@@ -1018,7 +1074,7 @@ CONFIG_MISC_FILESYSTEMS=y
CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
@@ -1135,6 +1191,7 @@ CONFIG_ARM_UNWIND=y
# CONFIG_DEBUG_ERRORS is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
#
# Security options
@@ -1142,7 +1199,11 @@ CONFIG_ARM_UNWIND=y
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
# CONFIG_CRYPTO is not set
# CONFIG_BINARY_PRINTF is not set
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 730aefcfbee3..be8b4d79cf41 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -182,21 +182,6 @@
* DMA Cache Coherency
* ===================
*
- * dma_inv_range(start, end)
- *
- * Invalidate (discard) the specified virtual address range.
- * May not write back any entries. If 'start' or 'end'
- * are not cache line aligned, those lines must be written
- * back.
- * - start - virtual start address
- * - end - virtual end address
- *
- * dma_clean_range(start, end)
- *
- * Clean (write back) the specified virtual address range.
- * - start - virtual start address
- * - end - virtual end address
- *
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -213,8 +198,9 @@ struct cpu_cache_fns {
void (*coherent_user_range)(unsigned long, unsigned long);
void (*flush_kern_dcache_area)(void *, size_t);
- void (*dma_inv_range)(const void *, const void *);
- void (*dma_clean_range)(const void *, const void *);
+ void (*dma_map_area)(const void *, size_t, int);
+ void (*dma_unmap_area)(const void *, size_t, int);
+
void (*dma_flush_range)(const void *, const void *);
};
@@ -244,8 +230,8 @@ extern struct cpu_cache_fns cpu_cache;
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
-#define dmac_inv_range cpu_cache.dma_inv_range
-#define dmac_clean_range cpu_cache.dma_clean_range
+#define dmac_map_area cpu_cache.dma_map_area
+#define dmac_unmap_area cpu_cache.dma_unmap_area
#define dmac_flush_range cpu_cache.dma_flush_range
#else
@@ -270,12 +256,12 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
-#define dmac_inv_range __glue(_CACHE,_dma_inv_range)
-#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
+#define dmac_map_area __glue(_CACHE,_dma_map_area)
+#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
-extern void dmac_inv_range(const void *, const void *);
-extern void dmac_clean_range(const void *, const void *);
+extern void dmac_map_area(const void *, size_t, int);
+extern void dmac_unmap_area(const void *, size_t, int);
extern void dmac_flush_range(const void *, const void *);
#endif
@@ -316,12 +302,8 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
* processes address space. Really, we want to allow our "user
* space" model to handle this.
*/
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
- do { \
- memcpy(dst, src, len); \
- flush_ptrace_access(vma, page, vaddr, dst, len, 1);\
- } while (0)
-
+extern void copy_to_user_page(struct vm_area_struct *, struct page *,
+ unsigned long, void *, const void *, unsigned long);
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
do { \
memcpy(dst, src, len); \
@@ -355,17 +337,6 @@ vivt_flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
}
}
-static inline void
-vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
- unsigned long uaddr, void *kaddr,
- unsigned long len, int write)
-{
- if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
- unsigned long addr = (unsigned long)kaddr;
- __cpuc_coherent_kern_range(addr, addr + len);
- }
-}
-
#ifndef CONFIG_CPU_CACHE_VIPT
#define flush_cache_mm(mm) \
vivt_flush_cache_mm(mm)
@@ -373,15 +344,10 @@ vivt_flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
vivt_flush_cache_range(vma,start,end)
#define flush_cache_page(vma,addr,pfn) \
vivt_flush_cache_page(vma,addr,pfn)
-#define flush_ptrace_access(vma,page,ua,ka,len,write) \
- vivt_flush_ptrace_access(vma,page,ua,ka,len,write)
#else
extern void flush_cache_mm(struct mm_struct *mm);
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn);
-extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
- unsigned long uaddr, void *kaddr,
- unsigned long len, int write);
#endif
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h
index b6ec7c627b39..7a0690da5e63 100644
--- a/arch/arm/include/asm/clkdev.h
+++ b/arch/arm/include/asm/clkdev.h
@@ -27,4 +27,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
void clkdev_add(struct clk_lookup *cl);
void clkdev_drop(struct clk_lookup *cl);
+void clkdev_add_table(struct clk_lookup *, size_t);
+int clk_add_alias(const char *, const char *, char *, struct device *);
+
#endif
diff --git a/arch/arm/include/asm/cpu.h b/arch/arm/include/asm/cpu.h
index 634b2d7c612a..793968173bef 100644
--- a/arch/arm/include/asm/cpu.h
+++ b/arch/arm/include/asm/cpu.h
@@ -11,6 +11,7 @@
#define __ASM_ARM_CPU_H
#include <linux/percpu.h>
+#include <linux/cpu.h>
struct cpuinfo_arm {
struct cpu cpu;
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index a96300bf83fd..256ee1c9f51a 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -57,18 +57,58 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
#endif
/*
- * DMA-consistent mapping functions. These allocate/free a region of
- * uncached, unwrite-buffered mapped memory space for use with DMA
- * devices. This is the "generic" version. The PCI specific version
- * is in pci.h
+ * The DMA API is built upon the notion of "buffer ownership". A buffer
+ * is either exclusively owned by the CPU (and therefore may be accessed
+ * by it) or exclusively owned by the DMA device. These helper functions
+ * represent the transitions between these two ownership states.
*
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ * Note, however, that on later ARMs, this notion does not work due to
+ * speculative prefetches. We model our approach on the assumption that
+ * the CPU does do speculative prefetches, which means we clean caches
+ * before transfers and delay cache invalidation until transfer completion.
+ *
+ * Private support functions: these are not part of the API and are
+ * liable to change. Drivers must not use these.
*/
-extern void dma_cache_maint(const void *kaddr, size_t size, int rw);
-extern void dma_cache_maint_page(struct page *page, unsigned long offset,
- size_t size, int rw);
+static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ extern void ___dma_single_cpu_to_dev(const void *, size_t,
+ enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_single_cpu_to_dev(kaddr, size, dir);
+}
+
+static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
+ enum dma_data_direction dir)
+{
+ extern void ___dma_single_dev_to_cpu(const void *, size_t,
+ enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_single_dev_to_cpu(kaddr, size, dir);
+}
+
+static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ extern void ___dma_page_cpu_to_dev(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_page_cpu_to_dev(page, off, size, dir);
+}
+
+static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ extern void ___dma_page_dev_to_cpu(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+
+ if (!arch_is_coherent())
+ ___dma_page_dev_to_cpu(page, off, size, dir);
+}
/*
* Return whether the given device DMA address mask can be supported
@@ -304,8 +344,7 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
{
BUG_ON(!valid_dma_direction(dir));
- if (!arch_is_coherent())
- dma_cache_maint(cpu_addr, size, dir);
+ __dma_single_cpu_to_dev(cpu_addr, size, dir);
return virt_to_dma(dev, cpu_addr);
}
@@ -329,8 +368,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
{
BUG_ON(!valid_dma_direction(dir));
- if (!arch_is_coherent())
- dma_cache_maint_page(page, offset, size, dir);
+ __dma_page_cpu_to_dev(page, offset, size, dir);
return page_to_dma(dev, page) + offset;
}
@@ -352,7 +390,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
- /* nothing to do */
+ __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir);
}
/**
@@ -372,7 +410,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
- /* nothing to do */
+ __dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK,
+ size, dir);
}
#endif /* CONFIG_DMABOUNCE */
@@ -400,7 +439,10 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
{
BUG_ON(!valid_dma_direction(dir));
- dmabounce_sync_for_cpu(dev, handle, offset, size, dir);
+ if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
+ return;
+
+ __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
}
static inline void dma_sync_single_range_for_device(struct device *dev,
@@ -412,8 +454,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
return;
- if (!arch_is_coherent())
- dma_cache_maint(dma_to_virt(dev, handle) + offset, size, dir);
+ __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
}
static inline void dma_sync_single_for_cpu(struct device *dev,
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index 7edf3536df24..ca51143f97f1 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -138,12 +138,12 @@ extern int get_dma_residue(unsigned int chan);
#define NO_DMA 255
#endif
+#endif /* CONFIG_ISA_DMA_API */
+
#ifdef CONFIG_PCI
extern int isa_dma_bridge_buggy;
#else
#define isa_dma_bridge_buggy (0)
#endif
-#endif /* CONFIG_ISA_DMA_API */
-
#endif /* __ASM_ARM_DMA_H */
diff --git a/arch/arm/include/asm/entry-macro-vic2.S b/arch/arm/include/asm/entry-macro-vic2.S
new file mode 100644
index 000000000000..3ceb85e43850
--- /dev/null
+++ b/arch/arm/include/asm/entry-macro-vic2.S
@@ -0,0 +1,57 @@
+/* arch/arm/include/asm/entry-macro-vic2.S
+ *
+ * Originally arch/arm/mach-s3c6400/include/mach/entry-macro.S
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Low-level IRQ helper macros for a device with two VICs
+ *
+ * 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.
+*/
+
+/* This should be included from <mach/entry-macro.S> with the necessary
+ * defines for virtual addresses and IRQ bases for the two vics.
+ *
+ * The code needs the following defined:
+ * IRQ_VIC0_BASE IRQ number of VIC0's first IRQ
+ * IRQ_VIC1_BASE IRQ number of VIC1's first IRQ
+ * VA_VIC0 Virtual address of VIC0
+ * VA_VIC1 Virtual address of VIC1
+ *
+ * Note, code assumes VIC0's virtual address is an ARM immediate constant
+ * away from VIC1.
+*/
+
+#include <asm/hardware/vic.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ ldr \base, =VA_VIC0
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+ @ check the vic0
+ mov \irqnr, #IRQ_VIC0_BASE + 31
+ ldr \irqstat, [ \base, # VIC_IRQ_STATUS ]
+ teq \irqstat, #0
+
+ @ otherwise try vic1
+ addeq \tmp, \base, #(VA_VIC1 - VA_VIC0)
+ addeq \irqnr, \irqnr, #(IRQ_VIC1_BASE - IRQ_VIC0_BASE)
+ ldreq \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
+ teqeq \irqstat, #0
+
+ clzne \irqstat, \irqstat
+ subne \irqnr, \irqnr, \irqstat
+ .endm
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index d2a59cfc30ce..3082d5b70e3b 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -69,9 +69,16 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
/*
* __arm_ioremap takes CPU physical address.
* __arm_ioremap_pfn takes a Page Frame Number and an offset into that page
+ * The _caller variety takes a __builtin_return_address(0) value for
+ * /proc/vmalloc to use - and should only be used in non-inline functions.
*/
-extern void __iomem * __arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
+ size_t, unsigned int, void *);
+extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+ void *);
+
+extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
+extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
extern void __iounmap(volatile void __iomem *addr);
/*
@@ -240,10 +247,14 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; })
#define ioread16(p) ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __v; })
#define ioread32(p) ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __v; })
+#define ioread16be(p) ({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __v; })
+#define ioread32be(p) ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __v; })
#define iowrite8(v,p) __raw_writeb(v, p)
#define iowrite16(v,p) __raw_writew((__force __u16)cpu_to_le16(v), p)
#define iowrite32(v,p) __raw_writel((__force __u32)cpu_to_le32(v), p)
+#define iowrite16be(v,p) __raw_writew((__force __u16)cpu_to_be16(v), p)
+#define iowrite32be(v,p) __raw_writel((__force __u32)cpu_to_be32(v), p)
#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 67af4b841984..17c69ae4c309 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -11,6 +11,7 @@
#define __ARM_KGDB_H__
#include <linux/ptrace.h>
+#include <linux/notifier.h>
/*
* GDB assumes that we're a user process being debugged, so
@@ -95,6 +96,16 @@ extern int kgdb_fault_expected;
#define _PC 15
#define _CPSR (GDB_MAX_REGS - 1)
+#ifdef CONFIG_KGDB
+int kgdb_die_hook(int cmd, const char *str, struct pt_regs *regs, int err);
+#else
+static inline int kgdb_die_hook(int cmd, const char *str,
+ struct pt_regs *regs, int err)
+{
+ return NOTIFY_DONE;
+}
+#endif
+
/*
* So that we can denote the end of a frame for tracing,
* in the simple case:
diff --git a/arch/arm/include/asm/kmap_types.h b/arch/arm/include/asm/kmap_types.h
index c019949a5189..3a9fb574fd8d 100644
--- a/arch/arm/include/asm/kmap_types.h
+++ b/arch/arm/include/asm/kmap_types.h
@@ -19,6 +19,7 @@ enum km_type {
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_L2_CACHE,
+ KM_KDB,
KM_TYPE_NR
};
diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h
index b2cc1fcd0400..8bffc3ff3acf 100644
--- a/arch/arm/include/asm/mach/time.h
+++ b/arch/arm/include/asm/mach/time.h
@@ -46,12 +46,4 @@ struct sys_timer {
extern struct sys_timer *system_timer;
extern void timer_tick(void);
-/*
- * Kernel time keeping support.
- */
-struct timespec;
-extern int (*set_rtc)(void);
-extern void save_time_delta(struct timespec *delta, struct timespec *rtc);
-extern void restore_time_delta(struct timespec *delta, struct timespec *rtc);
-
#endif
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 3a32af4cce30..a485ac3c8696 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -117,11 +117,12 @@
#endif
struct page;
+struct vm_area_struct;
struct cpu_user_fns {
void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr);
void (*cpu_copy_user_highpage)(struct page *to, struct page *from,
- unsigned long vaddr);
+ unsigned long vaddr, struct vm_area_struct *vma);
};
#ifdef MULTI_USER
@@ -137,7 +138,7 @@ extern struct cpu_user_fns cpu_user;
extern void __cpu_clear_user_highpage(struct page *page, unsigned long vaddr);
extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr);
+ unsigned long vaddr, struct vm_area_struct *vma);
#endif
#define clear_user_highpage(page,vaddr) \
@@ -145,7 +146,7 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
#define __HAVE_ARCH_COPY_USER_HIGHPAGE
#define copy_user_highpage(to,from,vaddr,vma) \
- __cpu_copy_user_highpage(to, from, vaddr)
+ __cpu_copy_user_highpage(to, from, vaddr, vma)
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
extern void copy_page(void *to, const void *from);
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index bbecccda76d0..eec6e897ceb2 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -97,9 +97,15 @@
* stack during a system call. Note that sizeof(struct pt_regs)
* has to be a multiple of 8.
*/
+#ifndef __KERNEL__
struct pt_regs {
long uregs[18];
};
+#else /* __KERNEL__ */
+struct pt_regs {
+ unsigned long uregs[18];
+};
+#endif /* __KERNEL__ */
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 5ccce0a9b03c..f392fb4437af 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -223,18 +223,6 @@ extern struct meminfo meminfo;
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
#define bank_phys_size(bank) (bank)->size
-/*
- * Early command line parameters.
- */
-struct early_params {
- const char *arg;
- void (*fn)(char **p);
-};
-
-#define __early_param(name,fn) \
-static struct early_params __early_##fn __used \
-__attribute__((__section__(".early_param.init"))) = { name, fn }
-
#endif /* __KERNEL__ */
#endif
diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h
index 59303e200845..e6215305544a 100644
--- a/arch/arm/include/asm/smp_plat.h
+++ b/arch/arm/include/asm/smp_plat.h
@@ -13,4 +13,9 @@ static inline int tlb_ops_need_broadcast(void)
return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
}
+static inline int cache_ops_need_broadcast(void)
+{
+ return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1;
+}
+
#endif
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 4e506d09e5f9..cf9cdaa2d4d4 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -391,6 +391,7 @@
#define __NR_pwritev (__NR_SYSCALL_BASE+362)
#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363)
#define __NR_perf_event_open (__NR_SYSCALL_BASE+364)
+#define __NR_recvmmsg (__NR_SYSCALL_BASE+365)
/*
* The following SWIs are ARM private.
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index dd00f747e2ad..eb0284cd8661 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -17,6 +17,7 @@ obj-y := compat.o elf.o entry-armv.o entry-common.o irq.o \
process.o ptrace.o return_address.o setup.o signal.o \
sys_arm.o stacktrace.o time.o traps.o
+obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_OC_ETM) += etm.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 4a881258bb17..883511522fca 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -12,6 +12,7 @@
*/
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/dma-mapping.h>
#include <asm/mach/arch.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
@@ -112,5 +113,9 @@ int main(void)
#ifdef MULTI_PABORT
DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort));
#endif
+ BLANK();
+ DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL);
+ DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE);
+ DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE);
return 0;
}
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index d2903e3bc861..6c5cf369183b 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -957,9 +957,7 @@ kuser_cmpxchg_fixup:
#else
-#ifdef CONFIG_SMP
- mcr p15, 0, r0, c7, c10, 5 @ dmb
-#endif
+ smp_dmb
1: ldrex r3, [r2]
subs r3, r3, r0
strexeq r3, r1, [r2]
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index ba8ccfede964..3c0e5e533e95 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -10,6 +10,7 @@
* Deepak Saxena <dsaxena@plexity.net>
*/
#include <linux/kgdb.h>
+#include <linux/notifier.h>
#include <asm/traps.h>
/* Make a local copy of the registers passed into the handler (bletch) */
@@ -97,6 +98,11 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
gdb_regs[_CPSR] = thread_regs->ARM_cpsr;
}
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
+{
+ regs->ARM_pc = pc;
+}
+
static int compiled_break;
int kgdb_arch_handle_exception(int exception_vector, int signo,
@@ -184,6 +190,13 @@ void kgdb_arch_exit(void)
unregister_undef_hook(&kgdb_compiled_brkpt_hook);
}
+int kgdb_die_hook(int cmd, const char *str, struct pt_regs *regs, int err)
+{
+ if (kgdb_handle_exception(1, err, cmd, regs))
+ return NOTIFY_DONE;
+ return NOTIFY_STOP;
+}
+
/*
* Register our undef instruction hooks with ARM undef core.
* We regsiter a hook specifically looking for the KGB break inst
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
new file mode 100644
index 000000000000..31a316c1777b
--- /dev/null
+++ b/arch/arm/kernel/leds.c
@@ -0,0 +1,115 @@
+/*
+ * LED support code, ripped out of arch/arm/kernel/time.c
+ *
+ * Copyright (C) 1994-2001 Russell King
+ *
+ * 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/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/leds.h>
+
+static void dummy_leds_event(led_event_t evt)
+{
+}
+
+void (*leds_event)(led_event_t) = dummy_leds_event;
+
+struct leds_evt_name {
+ const char name[8];
+ int on;
+ int off;
+};
+
+static const struct leds_evt_name evt_names[] = {
+ { "amber", led_amber_on, led_amber_off },
+ { "blue", led_blue_on, led_blue_off },
+ { "green", led_green_on, led_green_off },
+ { "red", led_red_on, led_red_off },
+};
+
+static ssize_t leds_store(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret = -EINVAL, len = strcspn(buf, " ");
+
+ if (len > 0 && buf[len] == '\0')
+ len--;
+
+ if (strncmp(buf, "claim", len) == 0) {
+ leds_event(led_claim);
+ ret = size;
+ } else if (strncmp(buf, "release", len) == 0) {
+ leds_event(led_release);
+ ret = size;
+ } else {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
+ if (strlen(evt_names[i].name) != len ||
+ strncmp(buf, evt_names[i].name, len) != 0)
+ continue;
+ if (strncmp(buf+len, " on", 3) == 0) {
+ leds_event(evt_names[i].on);
+ ret = size;
+ } else if (strncmp(buf+len, " off", 4) == 0) {
+ leds_event(evt_names[i].off);
+ ret = size;
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+static SYSDEV_ATTR(event, 0200, NULL, leds_store);
+
+static int leds_suspend(struct sys_device *dev, pm_message_t state)
+{
+ leds_event(led_stop);
+ return 0;
+}
+
+static int leds_resume(struct sys_device *dev)
+{
+ leds_event(led_start);
+ return 0;
+}
+
+static int leds_shutdown(struct sys_device *dev)
+{
+ leds_event(led_halted);
+ return 0;
+}
+
+static struct sysdev_class leds_sysclass = {
+ .name = "leds",
+ .shutdown = leds_shutdown,
+ .suspend = leds_suspend,
+ .resume = leds_resume,
+};
+
+static struct sys_device leds_device = {
+ .id = 0,
+ .cls = &leds_sysclass,
+};
+
+static int __init leds_init(void)
+{
+ int ret;
+ ret = sysdev_class_register(&leds_sysclass);
+ if (ret == 0)
+ ret = sysdev_register(&leds_device);
+ if (ret == 0)
+ ret = sysdev_create_file(&leds_device, &attr_event);
+ return ret;
+}
+
+device_initcall(leds_init);
+
+EXPORT_SYMBOL(leds_event);
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 67304138a2ca..ba2adefa53f7 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -212,7 +212,8 @@ void __show_regs(struct pt_regs *regs)
char buf[64];
printk("CPU: %d %s (%s %.*s)\n",
- smp_processor_id(), print_tainted(), init_utsname()->release,
+ raw_smp_processor_id(), print_tainted(),
+ init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
print_symbol("PC is at %s\n", instruction_pointer(regs));
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index c6c57b640b6b..b01a56a03ed8 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/fs.h>
+#include <linux/proc_fs.h>
#include <asm/unified.h>
#include <asm/cpu.h>
@@ -417,10 +418,11 @@ static int __init arm_add_memory(unsigned long start, unsigned long size)
* Pick out the memory size. We look for mem=size@start,
* where start and size are "size[KkMm]"
*/
-static void __init early_mem(char **p)
+static int __init early_mem(char *p)
{
static int usermem __initdata = 0;
unsigned long size, start;
+ char *endp;
/*
* If the user specifies memory size, we
@@ -433,52 +435,15 @@ static void __init early_mem(char **p)
}
start = PHYS_OFFSET;
- size = memparse(*p, p);
- if (**p == '@')
- start = memparse(*p + 1, p);
+ size = memparse(p, &endp);
+ if (*endp == '@')
+ start = memparse(endp + 1, NULL);
arm_add_memory(start, size);
-}
-__early_param("mem=", early_mem);
-/*
- * Initial parsing of the command line.
- */
-static void __init parse_cmdline(char **cmdline_p, char *from)
-{
- char c = ' ', *to = command_line;
- int len = 0;
-
- for (;;) {
- if (c == ' ') {
- extern struct early_params __early_begin, __early_end;
- struct early_params *p;
-
- for (p = &__early_begin; p < &__early_end; p++) {
- int arglen = strlen(p->arg);
-
- if (memcmp(from, p->arg, arglen) == 0) {
- if (to != command_line)
- to -= 1;
- from += arglen;
- p->fn(&from);
-
- while (*from != ' ' && *from != '\0')
- from++;
- break;
- }
- }
- }
- c = *from++;
- if (!c)
- break;
- if (COMMAND_LINE_SIZE <= ++len)
- break;
- *to++ = c;
- }
- *to = '\0';
- *cmdline_p = command_line;
+ return 0;
}
+early_param("mem", early_mem);
static void __init
setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
@@ -739,9 +704,15 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = (unsigned long) _end;
- memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
- boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
- parse_cmdline(cmdline_p, from);
+ /* parse_early_param needs a boot_command_line */
+ strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
+
+ /* populate command_line too for later use, preserving boot_command_line */
+ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+ *cmdline_p = command_line;
+
+ parse_early_param();
+
paging_init(mdesc);
request_standard_resources(&meminfo, mdesc);
@@ -782,9 +753,21 @@ static int __init topology_init(void)
return 0;
}
-
subsys_initcall(topology_init);
+#ifdef CONFIG_HAVE_PROC_CPU
+static int __init proc_cpu_init(void)
+{
+ struct proc_dir_entry *res;
+
+ res = proc_mkdir("cpu", NULL);
+ if (!res)
+ return -ENOMEM;
+ return 0;
+}
+fs_initcall(proc_cpu_init);
+#endif
+
static const char *hwcap_str[] = {
"swp",
"half",
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index d38cdf2c8276..28753805d2d1 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -10,11 +10,6 @@
*
* This file contains the ARM-specific time handling details:
* reading the RTC at bootup, etc...
- *
- * 1994-07-02 Alan Modra
- * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1998-12-20 Updated NTP code according to technical memorandum Jan '96
- * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -77,11 +72,6 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
#endif
-/*
- * hook for setting the RTC's idea of the current time.
- */
-int (*set_rtc)(void);
-
#ifndef CONFIG_GENERIC_TIME
static unsigned long dummy_gettimeoffset(void)
{
@@ -89,140 +79,6 @@ static unsigned long dummy_gettimeoffset(void)
}
#endif
-static unsigned long next_rtc_update;
-
-/*
- * If we have an externally synchronized linux clock, then update
- * CMOS clock accordingly every ~11 minutes. set_rtc() has to be
- * called as close as possible to 500 ms before the new second
- * starts.
- */
-static inline void do_set_rtc(void)
-{
- if (!ntp_synced() || set_rtc == NULL)
- return;
-
- if (next_rtc_update &&
- time_before((unsigned long)xtime.tv_sec, next_rtc_update))
- return;
-
- if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
- xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1))
- return;
-
- if (set_rtc())
- /*
- * rtc update failed. Try again in 60s
- */
- next_rtc_update = xtime.tv_sec + 60;
- else
- next_rtc_update = xtime.tv_sec + 660;
-}
-
-#ifdef CONFIG_LEDS
-
-static void dummy_leds_event(led_event_t evt)
-{
-}
-
-void (*leds_event)(led_event_t) = dummy_leds_event;
-
-struct leds_evt_name {
- const char name[8];
- int on;
- int off;
-};
-
-static const struct leds_evt_name evt_names[] = {
- { "amber", led_amber_on, led_amber_off },
- { "blue", led_blue_on, led_blue_off },
- { "green", led_green_on, led_green_off },
- { "red", led_red_on, led_red_off },
-};
-
-static ssize_t leds_store(struct sys_device *dev,
- struct sysdev_attribute *attr,
- const char *buf, size_t size)
-{
- int ret = -EINVAL, len = strcspn(buf, " ");
-
- if (len > 0 && buf[len] == '\0')
- len--;
-
- if (strncmp(buf, "claim", len) == 0) {
- leds_event(led_claim);
- ret = size;
- } else if (strncmp(buf, "release", len) == 0) {
- leds_event(led_release);
- ret = size;
- } else {
- int i;
-
- for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
- if (strlen(evt_names[i].name) != len ||
- strncmp(buf, evt_names[i].name, len) != 0)
- continue;
- if (strncmp(buf+len, " on", 3) == 0) {
- leds_event(evt_names[i].on);
- ret = size;
- } else if (strncmp(buf+len, " off", 4) == 0) {
- leds_event(evt_names[i].off);
- ret = size;
- }
- break;
- }
- }
- return ret;
-}
-
-static SYSDEV_ATTR(event, 0200, NULL, leds_store);
-
-static int leds_suspend(struct sys_device *dev, pm_message_t state)
-{
- leds_event(led_stop);
- return 0;
-}
-
-static int leds_resume(struct sys_device *dev)
-{
- leds_event(led_start);
- return 0;
-}
-
-static int leds_shutdown(struct sys_device *dev)
-{
- leds_event(led_halted);
- return 0;
-}
-
-static struct sysdev_class leds_sysclass = {
- .name = "leds",
- .shutdown = leds_shutdown,
- .suspend = leds_suspend,
- .resume = leds_resume,
-};
-
-static struct sys_device leds_device = {
- .id = 0,
- .cls = &leds_sysclass,
-};
-
-static int __init leds_init(void)
-{
- int ret;
- ret = sysdev_class_register(&leds_sysclass);
- if (ret == 0)
- ret = sysdev_register(&leds_device);
- if (ret == 0)
- ret = sysdev_create_file(&leds_device, &attr_event);
- return ret;
-}
-
-device_initcall(leds_init);
-
-EXPORT_SYMBOL(leds_event);
-#endif
-
#ifdef CONFIG_LEDS_TIMER
static inline void do_leds(void)
{
@@ -295,39 +151,6 @@ int do_settimeofday(struct timespec *tv)
EXPORT_SYMBOL(do_settimeofday);
#endif /* !CONFIG_GENERIC_TIME */
-/**
- * save_time_delta - Save the offset between system time and RTC time
- * @delta: pointer to timespec to store delta
- * @rtc: pointer to timespec for current RTC time
- *
- * Return a delta between the system time and the RTC time, such
- * that system time can be restored later with restore_time_delta()
- */
-void save_time_delta(struct timespec *delta, struct timespec *rtc)
-{
- set_normalized_timespec(delta,
- xtime.tv_sec - rtc->tv_sec,
- xtime.tv_nsec - rtc->tv_nsec);
-}
-EXPORT_SYMBOL(save_time_delta);
-
-/**
- * restore_time_delta - Restore the current system time
- * @delta: delta returned by save_time_delta()
- * @rtc: pointer to timespec for current RTC time
- */
-void restore_time_delta(struct timespec *delta, struct timespec *rtc)
-{
- struct timespec ts;
-
- set_normalized_timespec(&ts,
- delta->tv_sec + rtc->tv_sec,
- delta->tv_nsec + rtc->tv_nsec);
-
- do_settimeofday(&ts);
-}
-EXPORT_SYMBOL(restore_time_delta);
-
#ifndef CONFIG_GENERIC_CLOCKEVENTS
/*
* Kernel system timer support.
@@ -336,7 +159,6 @@ void timer_tick(void)
{
profile_tick(CPU_PROFILING);
do_leds();
- do_set_rtc();
write_seqlock(&xtime_lock);
do_timer(1);
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3f361a783f43..707e82418885 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -21,6 +21,9 @@
#include <linux/hardirq.h>
#include <linux/init.h>
#include <linux/uaccess.h>
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+#include <linux/notifier.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
@@ -254,6 +257,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
{
struct thread_info *thread = current_thread_info();
+ kgdb_die_hook(DIE_OOPS, str, regs, err);
+
oops_enter();
spin_lock_irq(&die_lock);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 4957e13ef55b..b16c07914b55 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -43,10 +43,6 @@ SECTIONS
INIT_SETUP(16)
- __early_begin = .;
- *(.early_param.init)
- __early_end = .;
-
INIT_CALLS
CON_INITCALL
SECURITY_INITCALL
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index e590bbe0a7b4..72e405df0fb0 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -142,8 +142,7 @@ void __init bcmring_amba_init(void)
chipcHw_busInterfaceClockEnable(bus_clock);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 033bfede6b67..0ebe185610bf 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -91,10 +91,14 @@ config MACH_DAVINCI_DM6467_EVM
bool "TI DM6467 EVM"
default ARCH_DAVINCI_DM646x
depends on ARCH_DAVINCI_DM646x
+ select MACH_DAVINCI_DM6467TEVM
help
Configure this option to specify the whether the board used
for development is a DM6467 EVM
+config MACH_DAVINCI_DM6467TEVM
+ bool
+
config MACH_DAVINCI_DM365_EVM
bool "TI DM365 EVM"
default ARCH_DAVINCI_DM365
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index eeb9230d8844..6aac880eb794 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -26,7 +26,7 @@ obj-$(CONFIG_MACH_SFFSDR) += board-sffsdr.o
obj-$(CONFIG_MACH_NEUROS_OSD2) += board-neuros-osd2.o
obj-$(CONFIG_MACH_DAVINCI_DM355_EVM) += board-dm355-evm.o
obj-$(CONFIG_MACH_DM355_LEOPARD) += board-dm355-leopard.o
-obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o
+obj-$(CONFIG_MACH_DAVINCI_DM6467_EVM) += board-dm646x-evm.o cdce949.o
obj-$(CONFIG_MACH_DAVINCI_DM365_EVM) += board-dm365-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA830_EVM) += board-da830-evm.o
obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
@@ -34,3 +34,4 @@ obj-$(CONFIG_MACH_DAVINCI_DA850_EVM) += board-da850-evm.o
# Power Management
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+obj-$(CONFIG_SUSPEND) += pm.o sleep.o
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 31dc9901e556..dc19870b23cd 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -112,7 +112,7 @@ static __init void da830_evm_usb_init(void)
* Set up USB clock/mode in the CFGCHIP2 register.
* FYI: CFGCHIP2 is 0x0000ef00 initially.
*/
- cfgchip2 = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+ cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
/* USB2.0 PHY reference clock is 24 MHz */
cfgchip2 &= ~CFGCHIP2_REFFREQ;
@@ -139,7 +139,7 @@ static __init void da830_evm_usb_init(void)
cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;
#endif
- __raw_writel(cfgchip2, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG));
+ __raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
/* USB_REFCLKIN is not used. */
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 07de8db14581..411284d0b0fa 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -46,8 +46,20 @@
static struct mtd_partition da850_evm_norflash_partition[] = {
{
- .name = "NOR filesystem",
+ .name = "bootloaders + env",
.offset = 0,
+ .size = SZ_512K,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ .mask_flags = 0,
+ },
+ {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
.mask_flags = 0,
},
@@ -77,6 +89,18 @@ static struct platform_device da850_evm_norflash_device = {
.resource = da850_evm_norflash_resource,
};
+static struct davinci_pm_config da850_pm_pdata = {
+ .sleepcount = 128,
+};
+
+static struct platform_device da850_pm_device = {
+ .name = "pm-davinci",
+ .dev = {
+ .platform_data = &da850_pm_pdata,
+ },
+ .id = -1,
+};
+
/* DA850/OMAP-L138 EVM includes a 512 MByte large-page NAND flash
* (128K blocks). It may be used instead of the (default) SPI flash
* to boot, using TI's tools to install the secondary boot loader
@@ -119,6 +143,7 @@ static struct davinci_nand_pdata da850_evm_nandflash_data = {
.parts = da850_evm_nandflash_partition,
.nr_parts = ARRAY_SIZE(da850_evm_nandflash_partition),
.ecc_mode = NAND_ECC_HW,
+ .ecc_bits = 4,
.options = NAND_USE_FLASH_BBT,
};
@@ -537,7 +562,7 @@ static int __init da850_evm_config_emac(void)
if (!machine_is_davinci_da850_evm())
return 0;
- cfg_chip3_base = DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG);
+ cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
val = __raw_readl(cfg_chip3_base);
@@ -696,6 +721,11 @@ static __init void da850_evm_init(void)
if (ret)
pr_warning("da850_evm_init: cpuidle registration failed: %d\n",
ret);
+
+ ret = da850_register_pm(&da850_pm_device);
+ if (ret)
+ pr_warning("da850_evm_init: suspend registration failed: %d\n",
+ ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index a9b650dcc172..077ecf4fecda 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -236,6 +236,7 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = {
static struct vpfe_config vpfe_cfg = {
.num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+ .i2c_adapter_id = 1,
.sub_devs = vpfe_sub_devs,
.card_name = "DM355 EVM",
.ccdc = "DM355 CCDC",
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index 289fe1b7d25a..b476395d2cd4 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -192,7 +192,11 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
-#ifdef CONFIG_KEYBOARD_DAVINCI
+static int dm365evm_keyscan_enable(struct device *dev)
+{
+ return davinci_cfg_reg(DM365_KEYSCAN);
+}
+
static unsigned short dm365evm_keymap[] = {
KEY_KP2,
KEY_LEFT,
@@ -214,6 +218,7 @@ static unsigned short dm365evm_keymap[] = {
};
static struct davinci_ks_platform_data dm365evm_ks_data = {
+ .device_enable = dm365evm_keyscan_enable,
.keymap = dm365evm_keymap,
.keymapsize = ARRAY_SIZE(dm365evm_keymap),
.rep = 1,
@@ -222,7 +227,6 @@ static struct davinci_ks_platform_data dm365evm_ks_data = {
.interval = 0x2,
.matrix_type = DAVINCI_KEYSCAN_MATRIX_4X4,
};
-#endif
static int cpld_mmc_get_cd(int module)
{
@@ -511,10 +515,7 @@ static __init void dm365_evm_init(void)
dm365_init_asp(&dm365_evm_snd_data);
dm365_init_rtc();
-
-#ifdef CONFIG_KEYBOARD_DAVINCI
dm365_init_ks(&dm365evm_ks_data);
-#endif
}
static __init void dm365_evm_irq_init(void)
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index fd0398bc6db3..e9612cf727b7 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -247,6 +247,7 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = {
static struct vpfe_config vpfe_cfg = {
.num_subdevs = ARRAY_SIZE(vpfe_sub_devs),
+ .i2c_adapter_id = 1,
.sub_devs = vpfe_sub_devs,
.card_name = "DM6446 EVM",
.ccdc = "DM6446 CCDC",
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 8d0b0e01c59b..815067b2413e 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -30,6 +30,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,54 +40,13 @@
#include <mach/serial.h>
#include <mach/i2c.h>
#include <mach/nand.h>
+#include <mach/clock.h>
+#include <mach/cdce949.h>
-#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
- defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
-#define HAS_ATA 1
-#else
-#define HAS_ATA 0
-#endif
-
-#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000
-#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000
+#include "clock.h"
#define NAND_BLOCK_SIZE SZ_128K
-/* CPLD Register 0 bits to control ATA */
-#define DM646X_EVM_ATA_RST BIT(0)
-#define DM646X_EVM_ATA_PWD BIT(1)
-
-#define DM646X_EVM_PHY_MASK (0x2)
-#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
-
-#define VIDCLKCTL_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
-#define VSCLKDIS_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
-#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
-#define VCH2CLK_SYSCLK8 (BIT(9))
-#define VCH2CLK_AUXCLK (BIT(9) | BIT(8))
-#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
-#define VCH3CLK_SYSCLK8 (BIT(13))
-#define VCH3CLK_AUXCLK (BIT(14) | BIT(13))
-
-#define VIDCH2CLK (BIT(10))
-#define VIDCH3CLK (BIT(11))
-#define VIDCH1CLK (BIT(4))
-#define TVP7002_INPUT (BIT(4))
-#define TVP5147_INPUT (~BIT(4))
-#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
-#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
-#define TVP5147_CH0 "tvp514x-0"
-#define TVP5147_CH1 "tvp514x-1"
-
-static void __iomem *vpif_vidclkctl_reg;
-static void __iomem *vpif_vsclkdis_reg;
-/* spin lock for updating above registers */
-static spinlock_t vpif_reg_lock;
-
-static struct davinci_uart_config uart_config __initdata = {
- .enabled_uarts = (1 << 0),
-};
-
/* Note: We are setting first partition as 'bootloader' constituting UBL, U-Boot
* and U-Boot environment this avoids dependency on any particular combination
* of UBL, U-Boot or flashing tools etc.
@@ -120,6 +80,9 @@ static struct davinci_nand_pdata davinci_nand_data = {
.options = 0,
};
+#define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x20008000
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x42000000
+
static struct resource davinci_nand_resources[] = {
{
.start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
@@ -144,6 +107,17 @@ static struct platform_device davinci_nand_device = {
},
};
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#define HAS_ATA 1
+#else
+#define HAS_ATA 0
+#endif
+
+/* CPLD Register 0 bits to control ATA */
+#define DM646X_EVM_ATA_RST BIT(0)
+#define DM646X_EVM_ATA_PWD BIT(1)
+
/* CPLD Register 0 Client: used for I/O Control */
static int cpld_reg0_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -417,6 +391,9 @@ static struct i2c_board_info __initdata i2c_info[] = {
{
I2C_BOARD_INFO("cpld_video", 0x3b),
},
+ {
+ I2C_BOARD_INFO("cdce949", 0x6c),
+ },
};
static struct davinci_i2c_platform_data i2c_pdata = {
@@ -424,6 +401,30 @@ static struct davinci_i2c_platform_data i2c_pdata = {
.bus_delay = 0 /* usec */,
};
+#define VIDCLKCTL_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x38)
+#define VSCLKDIS_OFFSET (DAVINCI_SYSTEM_MODULE_BASE + 0x6c)
+#define VCH2CLK_MASK (BIT_MASK(10) | BIT_MASK(9) | BIT_MASK(8))
+#define VCH2CLK_SYSCLK8 (BIT(9))
+#define VCH2CLK_AUXCLK (BIT(9) | BIT(8))
+#define VCH3CLK_MASK (BIT_MASK(14) | BIT_MASK(13) | BIT_MASK(12))
+#define VCH3CLK_SYSCLK8 (BIT(13))
+#define VCH3CLK_AUXCLK (BIT(14) | BIT(13))
+
+#define VIDCH2CLK (BIT(10))
+#define VIDCH3CLK (BIT(11))
+#define VIDCH1CLK (BIT(4))
+#define TVP7002_INPUT (BIT(4))
+#define TVP5147_INPUT (~BIT(4))
+#define VPIF_INPUT_ONE_CHANNEL (BIT(5))
+#define VPIF_INPUT_TWO_CHANNEL (~BIT(5))
+#define TVP5147_CH0 "tvp514x-0"
+#define TVP5147_CH1 "tvp514x-1"
+
+static void __iomem *vpif_vidclkctl_reg;
+static void __iomem *vpif_vsclkdis_reg;
+/* spin lock for updating above registers */
+static spinlock_t vpif_reg_lock;
+
static int set_vpif_clock(int mux_mode, int hd)
{
unsigned long flags;
@@ -685,11 +686,44 @@ static void __init evm_init_i2c(void)
evm_init_video();
}
+#define CDCE949_XIN_RATE 27000000
+
+/* CDCE949 support - "lpsc" field is overridden to work as clock number */
+static struct clk cdce_clk_in = {
+ .name = "cdce_xin",
+ .rate = CDCE949_XIN_RATE,
+};
+
+static struct davinci_clk cdce_clks[] = {
+ CLK(NULL, "xin", &cdce_clk_in),
+ CLK(NULL, NULL, NULL),
+};
+
+static void __init cdce_clk_init(void)
+{
+ struct davinci_clk *c;
+ struct clk *clk;
+
+ for (c = cdce_clks; c->lk.clk; c++) {
+ clk = c->lk.clk;
+ clkdev_add(&c->lk);
+ clk_register(clk);
+ }
+}
+
static void __init davinci_map_io(void)
{
dm646x_init();
+ cdce_clk_init();
}
+static struct davinci_uart_config uart_config __initdata = {
+ .enabled_uarts = (1 << 0),
+};
+
+#define DM646X_EVM_PHY_MASK (0x2)
+#define DM646X_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
+
static __init void evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -713,6 +747,17 @@ static __init void davinci_dm646x_evm_irq_init(void)
davinci_irq_init();
}
+#define DM646X_EVM_REF_FREQ 27000000
+#define DM6467T_EVM_REF_FREQ 33000000
+
+void __init dm646x_board_setup_refclk(struct clk *clk)
+{
+ if (machine_is_davinci_dm6467tevm())
+ clk->rate = DM6467T_EVM_REF_FREQ;
+ else
+ clk->rate = DM646X_EVM_REF_FREQ;
+}
+
MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
.phys_io = IO_PHYS,
.io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
@@ -723,3 +768,13 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
.init_machine = evm_init,
MACHINE_END
+MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
+ .phys_io = IO_PHYS,
+ .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+ .boot_params = (0x80000100),
+ .map_io = davinci_map_io,
+ .init_irq = davinci_dm646x_evm_irq_init,
+ .timer = &davinci_timer,
+ .init_machine = evm_init,
+MACHINE_END
+
diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c
new file mode 100644
index 000000000000..6af3289e0527
--- /dev/null
+++ b/arch/arm/mach-davinci/cdce949.c
@@ -0,0 +1,289 @@
+/*
+ * TI CDCE949 clock synthesizer driver
+ *
+ * Note: This implementation assumes an input of 27MHz to the CDCE.
+ * This is by no means constrained by CDCE hardware although the datasheet
+ * does use this as an example for all illustrations and more importantly:
+ * that is the crystal input on boards it is currently used on.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated. 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <mach/clock.h>
+
+#include "clock.h"
+
+static struct i2c_client *cdce_i2c_client;
+
+/* CDCE register descriptor */
+struct cdce_reg {
+ u8 addr;
+ u8 val;
+};
+
+/* Per-Output (Y1, Y2 etc.) frequency descriptor */
+struct cdce_freq {
+ /* Frequency in KHz */
+ unsigned long frequency;
+ /*
+ * List of registers to program to obtain a particular frequency.
+ * 0x0 in register address and value is the end of list marker.
+ */
+ struct cdce_reg *reglist;
+};
+
+#define CDCE_FREQ_TABLE_ENTRY(line, out) \
+{ \
+ .reglist = cdce_y ##line## _ ##out, \
+ .frequency = out, \
+}
+
+/* List of CDCE outputs */
+struct cdce_output {
+ /* List of frequencies on this output */
+ struct cdce_freq *freq_table;
+ /* Number of possible frequencies */
+ int size;
+};
+
+/*
+ * Finding out the values to program into CDCE949 registers for a particular
+ * frequency output is not a simple calculation. Have a look at the datasheet
+ * for the details. There is desktop software available to help users with
+ * the calculations. Here, we just depend on the output of that software
+ * (or hand calculations) instead trying to runtime calculate the register
+ * values and inflicting misery on ourselves.
+ */
+static struct cdce_reg cdce_y1_148500[] = {
+ { 0x13, 0x00 },
+ /* program PLL1_0 multiplier */
+ { 0x18, 0xaf },
+ { 0x19, 0x50 },
+ { 0x1a, 0x02 },
+ { 0x1b, 0xc9 },
+ /* program PLL1_11 multiplier */
+ { 0x1c, 0x00 },
+ { 0x1d, 0x40 },
+ { 0x1e, 0x02 },
+ { 0x1f, 0xc9 },
+ /* output state selection */
+ { 0x15, 0x00 },
+ { 0x14, 0xef },
+ /* switch MUX to PLL1 output */
+ { 0x14, 0x6f },
+ { 0x16, 0x06 },
+ /* set P2DIV divider, P3DIV and input crystal */
+ { 0x17, 0x06 },
+ { 0x01, 0x00 },
+ { 0x05, 0x48 },
+ { 0x02, 0x80 },
+ /* enable and disable PLL */
+ { 0x02, 0xbc },
+ { 0x03, 0x01 },
+ { },
+};
+
+static struct cdce_reg cdce_y1_74250[] = {
+ { 0x13, 0x00 },
+ { 0x18, 0xaf },
+ { 0x19, 0x50 },
+ { 0x1a, 0x02 },
+ { 0x1b, 0xc9 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0x40 },
+ { 0x1e, 0x02 },
+ { 0x1f, 0xc9 },
+ /* output state selection */
+ { 0x15, 0x00 },
+ { 0x14, 0xef },
+ /* switch MUX to PLL1 output */
+ { 0x14, 0x6f },
+ { 0x16, 0x06 },
+ /* set P2DIV divider, P3DIV and input crystal */
+ { 0x17, 0x06 },
+ { 0x01, 0x00 },
+ { 0x05, 0x48 },
+ { 0x02, 0x80 },
+ /* enable and disable PLL */
+ { 0x02, 0xbc },
+ { 0x03, 0x02 },
+ { },
+};
+
+static struct cdce_reg cdce_y1_27000[] = {
+ { 0x13, 0x00 },
+ { 0x18, 0x00 },
+ { 0x19, 0x40 },
+ { 0x1a, 0x02 },
+ { 0x1b, 0x08 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0x40 },
+ { 0x1e, 0x02 },
+ { 0x1f, 0x08 },
+ { 0x15, 0x02 },
+ { 0x14, 0xed },
+ { 0x16, 0x01 },
+ { 0x17, 0x01 },
+ { 0x01, 0x00 },
+ { 0x05, 0x50 },
+ { 0x02, 0xb4 },
+ { 0x03, 0x01 },
+ { },
+};
+
+static struct cdce_freq cdce_y1_freqs[] = {
+ CDCE_FREQ_TABLE_ENTRY(1, 148500),
+ CDCE_FREQ_TABLE_ENTRY(1, 74250),
+ CDCE_FREQ_TABLE_ENTRY(1, 27000),
+};
+
+static struct cdce_reg cdce_y5_13500[] = {
+ { 0x27, 0x08 },
+ { 0x28, 0x00 },
+ { 0x29, 0x40 },
+ { 0x2a, 0x02 },
+ { 0x2b, 0x08 },
+ { 0x24, 0x6f },
+ { },
+};
+
+static struct cdce_reg cdce_y5_16875[] = {
+ { 0x27, 0x08 },
+ { 0x28, 0x9f },
+ { 0x29, 0xb0 },
+ { 0x2a, 0x02 },
+ { 0x2b, 0x89 },
+ { 0x24, 0x6f },
+ { },
+};
+
+static struct cdce_reg cdce_y5_27000[] = {
+ { 0x27, 0x04 },
+ { 0x28, 0x00 },
+ { 0x29, 0x40 },
+ { 0x2a, 0x02 },
+ { 0x2b, 0x08 },
+ { 0x24, 0x6f },
+ { },
+};
+static struct cdce_reg cdce_y5_54000[] = {
+ { 0x27, 0x04 },
+ { 0x28, 0xff },
+ { 0x29, 0x80 },
+ { 0x2a, 0x02 },
+ { 0x2b, 0x07 },
+ { 0x24, 0x6f },
+ { },
+};
+
+static struct cdce_reg cdce_y5_81000[] = {
+ { 0x27, 0x02 },
+ { 0x28, 0xbf },
+ { 0x29, 0xa0 },
+ { 0x2a, 0x03 },
+ { 0x2b, 0x0a },
+ { 0x24, 0x6f },
+ { },
+};
+
+static struct cdce_freq cdce_y5_freqs[] = {
+ CDCE_FREQ_TABLE_ENTRY(5, 13500),
+ CDCE_FREQ_TABLE_ENTRY(5, 16875),
+ CDCE_FREQ_TABLE_ENTRY(5, 27000),
+ CDCE_FREQ_TABLE_ENTRY(5, 54000),
+ CDCE_FREQ_TABLE_ENTRY(5, 81000),
+};
+
+
+static struct cdce_output output_list[] = {
+ [1] = { cdce_y1_freqs, ARRAY_SIZE(cdce_y1_freqs) },
+ [5] = { cdce_y5_freqs, ARRAY_SIZE(cdce_y5_freqs) },
+};
+
+int cdce_set_rate(struct clk *clk, unsigned long rate)
+{
+ int i, ret = 0;
+ struct cdce_freq *freq_table = output_list[clk->lpsc].freq_table;
+ struct cdce_reg *regs = NULL;
+
+ if (!cdce_i2c_client)
+ return -ENODEV;
+
+ if (!freq_table)
+ return -EINVAL;
+
+ for (i = 0; i < output_list[clk->lpsc].size; i++) {
+ if (freq_table[i].frequency == rate / 1000) {
+ regs = freq_table[i].reglist;
+ break;
+ }
+ }
+
+ if (!regs)
+ return -EINVAL;
+
+ for (i = 0; regs[i].addr; i++) {
+ ret = i2c_smbus_write_byte_data(cdce_i2c_client,
+ regs[i].addr | 0x80, regs[i].val);
+ if (ret)
+ return ret;
+ }
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+static int cdce_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ cdce_i2c_client = client;
+ return 0;
+}
+
+static int __devexit cdce_remove(struct i2c_client *client)
+{
+ cdce_i2c_client = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id cdce_id[] = {
+ {"cdce949", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, cdce_id);
+
+static struct i2c_driver cdce_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cdce949",
+ },
+ .probe = cdce_probe,
+ .remove = __devexit_p(cdce_remove),
+ .id_table = cdce_id,
+};
+
+static int __init cdce_init(void)
+{
+ return i2c_add_driver(&cdce_driver);
+}
+subsys_initcall(cdce_init);
+
+static void __exit cdce_exit(void)
+{
+ i2c_del_driver(&cdce_driver);
+}
+module_exit(cdce_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("CDCE949 clock synthesizer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index baece65cb9c0..123839332d50 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -49,7 +49,8 @@ static void __clk_disable(struct clk *clk)
{
if (WARN_ON(clk->usecount == 0))
return;
- if (--clk->usecount == 0 && !(clk->flags & CLK_PLL))
+ if (--clk->usecount == 0 && !(clk->flags & CLK_PLL) &&
+ (clk->flags & CLK_PSC))
davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, 0);
if (clk->parent)
__clk_disable(clk->parent);
@@ -376,7 +377,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
locktime = ((2000 * prediv) / 100);
prediv = (prediv - 1) | PLLDIV_EN;
} else {
- locktime = 20;
+ locktime = PLL_LOCK_TIME;
}
if (postdiv)
postdiv = (postdiv - 1) | PLLDIV_EN;
@@ -389,12 +390,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
__raw_writel(ctrl, pll->base + PLLCTL);
- /*
- * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched
- * to bypass mode. Delay of 1us ensures we are good for all > 4MHz
- * OSCIN/CLKIN inputs. Typically the input is ~25MHz.
- */
- udelay(1);
+ udelay(PLL_BYPASS_TIME);
/* Reset and enable PLL */
ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS);
@@ -408,11 +404,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
if (pll->flags & PLL_HAS_POSTDIV)
__raw_writel(postdiv, pll->base + POSTDIV);
- /*
- * Wait for PLL to reset properly, OMAP-L138 datasheet says
- * 'min' time = 125ns
- */
- udelay(1);
+ udelay(PLL_RESET_TIME);
/* Bring PLL out of reset */
ctrl |= PLLCTL_PLLRST;
@@ -468,24 +460,10 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
return 0;
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
-static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
-{
- return *pos < 1 ? (void *)1 : NULL;
-}
+#ifdef CONFIG_DEBUG_FS
-static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
-{
- ++*pos;
- return NULL;
-}
-
-static void davinci_ck_stop(struct seq_file *m, void *v)
-{
-}
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#define CLKNAME_MAX 10 /* longest clock name */
#define NEST_DELTA 2
@@ -525,41 +503,38 @@ dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
static int davinci_ck_show(struct seq_file *m, void *v)
{
- /* Show clock tree; we know the main oscillator is first.
- * We trust nonzero usecounts equate to PSC enables...
+ struct clk *clk;
+
+ /*
+ * Show clock tree; We trust nonzero usecounts equate to PSC enables...
*/
mutex_lock(&clocks_mutex);
- if (!list_empty(&clocks))
- dump_clock(m, 0, list_first_entry(&clocks, struct clk, node));
+ list_for_each_entry(clk, &clocks, node)
+ if (!clk->parent)
+ dump_clock(m, 0, clk);
mutex_unlock(&clocks_mutex);
return 0;
}
-static const struct seq_operations davinci_ck_op = {
- .start = davinci_ck_start,
- .next = davinci_ck_next,
- .stop = davinci_ck_stop,
- .show = davinci_ck_show
-};
-
static int davinci_ck_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &davinci_ck_op);
+ return single_open(file, davinci_ck_show, NULL);
}
-static const struct file_operations proc_davinci_ck_operations = {
+static const struct file_operations davinci_ck_operations = {
.open = davinci_ck_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = single_release,
};
-static int __init davinci_ck_proc_init(void)
+static int __init davinci_clk_debugfs_init(void)
{
- proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations);
+ debugfs_create_file("davinci_clocks", S_IFREG | S_IRUGO, NULL, NULL,
+ &davinci_ck_operations);
return 0;
}
-__initcall(davinci_ck_proc_init);
-#endif /* CONFIG_DEBUG_PROC_FS */
+device_initcall(davinci_clk_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index c92d77a3008d..31fb6eac712c 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -12,9 +12,6 @@
#ifndef __ARCH_ARM_DAVINCI_CLOCK_H
#define __ARCH_ARM_DAVINCI_CLOCK_H
-#include <linux/list.h>
-#include <asm/clkdev.h>
-
#define DAVINCI_PLL1_BASE 0x01c40800
#define DAVINCI_PLL2_BASE 0x01c40c00
#define MAX_PLL 2
@@ -53,6 +50,26 @@
#define PLLDIV_EN BIT(15)
#define PLLDIV_RATIO_MASK 0x1f
+/*
+ * OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN
+ * cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us
+ * ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input
+ * is ~25MHz. Units are micro seconds.
+ */
+#define PLL_BYPASS_TIME 1
+/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */
+#define PLL_RESET_TIME 1
+/*
+ * From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4
+ * Units are micro seconds.
+ */
+#define PLL_LOCK_TIME 20
+
+#ifndef __ASSEMBLER__
+
+#include <linux/list.h>
+#include <asm/clkdev.h>
+
struct pll_data {
u32 phys_base;
void __iomem *base;
@@ -109,3 +126,5 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
extern struct platform_device davinci_wdt_device;
#endif
+
+#endif
diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c
index c2de94cde56a..94f27cbcd55a 100644
--- a/arch/arm/mach-davinci/common.c
+++ b/arch/arm/mach-davinci/common.c
@@ -11,13 +11,13 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/etherdevice.h>
+#include <linux/davinci_emac.h>
#include <asm/tlb.h>
#include <asm/mach/map.h>
#include <mach/common.h>
#include <mach/cputype.h>
-#include <mach/emac.h>
#include "clock.h"
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
index 52b287cf3a42..37311d1830eb 100644
--- a/arch/arm/mach-davinci/cp_intc.c
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -81,12 +81,23 @@ static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
return 0;
}
+/*
+ * Faking this allows us to to work with suspend functions of
+ * generic drivers which call {enable|disable}_irq_wake for
+ * wake up interrupt sources (eg RTC on DA850).
+ */
+static int cp_intc_set_wake(unsigned int irq, unsigned int on)
+{
+ return 0;
+}
+
static struct irq_chip cp_intc_irq_chip = {
.name = "cp_intc",
.ack = cp_intc_ack_irq,
.mask = cp_intc_mask_irq,
.unmask = cp_intc_unmask_irq,
.set_type = cp_intc_set_irq_type,
+ .set_wake = cp_intc_set_wake,
};
void __init cp_intc_init(void __iomem *base, unsigned short num_irq,
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 97a90f36fc92..bd59f31b8a95 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -19,6 +19,7 @@
#include <asm/proc-fns.h>
#include <mach/cpuidle.h>
+#include <mach/memory.h>
#define DAVINCI_CPUIDLE_MAX_STATES 2
@@ -39,10 +40,6 @@ static struct cpuidle_driver davinci_idle_driver = {
static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
static void __iomem *ddr2_reg_base;
-#define DDR2_SDRCR_OFFSET 0xc
-#define DDR2_SRPD_BIT BIT(23)
-#define DDR2_LPMODEN_BIT BIT(31)
-
static void davinci_save_ddr_power(int enter, bool pdown)
{
u32 val;
@@ -109,8 +106,6 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
int ret;
struct cpuidle_device *device;
struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
- struct resource *ddr2_regs;
- resource_size_t len;
device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
@@ -119,28 +114,12 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
return -ENOENT;
}
- ddr2_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!ddr2_regs) {
- dev_err(&pdev->dev, "cannot get DDR2 controller register base");
- return -ENODEV;
- }
-
- len = resource_size(ddr2_regs);
-
- ddr2_regs = request_mem_region(ddr2_regs->start, len, ddr2_regs->name);
- if (!ddr2_regs)
- return -EBUSY;
-
- ddr2_reg_base = ioremap(ddr2_regs->start, len);
- if (!ddr2_reg_base) {
- ret = -ENOMEM;
- goto ioremap_fail;
- }
+ ddr2_reg_base = pdata->ddr2_ctlr_base;
ret = cpuidle_register_driver(&davinci_idle_driver);
if (ret) {
dev_err(&pdev->dev, "failed to register driver\n");
- goto driver_register_fail;
+ return ret;
}
/* Wait for interrupt state */
@@ -167,18 +146,11 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ret = cpuidle_register_device(device);
if (ret) {
dev_err(&pdev->dev, "failed to register device\n");
- goto device_register_fail;
+ cpuidle_unregister_driver(&davinci_idle_driver);
+ return ret;
}
return 0;
-
-device_register_fail:
- cpuidle_unregister_driver(&davinci_idle_driver);
-driver_register_fail:
- iounmap(ddr2_reg_base);
-ioremap_fail:
- release_mem_region(ddr2_regs->start, len);
- return ret;
}
static struct platform_driver davinci_cpuidle_driver = {
diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c
index b22b5cf04250..54796050a2ff 100644
--- a/arch/arm/mach-davinci/da830.c
+++ b/arch/arm/mach-davinci/da830.c
@@ -1208,13 +1208,13 @@ static struct davinci_soc_info davinci_soc_info_da830 = {
void __init da830_init(void)
{
- da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
- if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module"))
return;
davinci_soc_info_da830.jtag_id_base =
- DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
- davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+ DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da830.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120);
davinci_common_init(&davinci_soc_info_da830);
}
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 717806c6cef9..b9a7b3bc36b2 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -26,6 +26,7 @@
#include <mach/time.h>
#include <mach/da8xx.h>
#include <mach/cpufreq.h>
+#include <mach/pm.h>
#include "clock.h"
#include "mux.h"
@@ -40,6 +41,7 @@
#define DA850_REF_FREQ 24000000
#define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
+#define CFGCHIP3_PLL1_MASTER_LOCK BIT(5)
#define CFGCHIP0_PLL_MASTER_LOCK BIT(4)
static int da850_set_armrate(struct clk *clk, unsigned long rate);
@@ -535,6 +537,7 @@ static const struct mux_config da850_pins[] = {
MUX_CFG(DA850, GPIO2_15, 5, 0, 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, RTC_ALARM, 0, 28, 15, 2, false)
#endif
};
@@ -770,6 +773,12 @@ static struct map_desc da850_io_desc[] = {
.length = DA8XX_CP_INTC_SIZE,
.type = MT_DEVICE
},
+ {
+ .virtual = SRAM_VIRT,
+ .pfn = __phys_to_pfn(DA8XX_ARM_RAM_BASE),
+ .length = SZ_8K,
+ .type = MT_DEVICE
+ },
};
static void __iomem *da850_psc_bases[] = {
@@ -838,12 +847,12 @@ static void da850_set_async3_src(int pllnum)
}
}
- v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+ v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
if (pllnum)
v |= CFGCHIP3_ASYNC3_CLKSRC;
else
v &= ~CFGCHIP3_ASYNC3_CLKSRC;
- __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
+ __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
}
#ifdef CONFIG_CPU_FREQ
@@ -987,7 +996,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
unsigned int prediv, mult, postdiv;
struct da850_opp *opp;
struct pll_data *pll = clk->pll_data;
- unsigned int v;
int ret;
opp = (struct da850_opp *) da850_freq_table[index].index;
@@ -995,11 +1003,6 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
mult = opp->mult;
postdiv = opp->postdiv;
- /* Unlock writing to PLL registers */
- v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
- v &= ~CFGCHIP0_PLL_MASTER_LOCK;
- __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
-
ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
if (WARN_ON(ret))
return ret;
@@ -1028,6 +1031,43 @@ static int da850_round_armrate(struct clk *clk, unsigned long rate)
}
#endif
+int da850_register_pm(struct platform_device *pdev)
+{
+ int ret;
+ struct davinci_pm_config *pdata = pdev->dev.platform_data;
+
+ ret = davinci_cfg_reg(DA850_RTC_ALARM);
+ if (ret)
+ return ret;
+
+ pdata->ddr2_ctlr_base = da8xx_get_mem_ctlr();
+ pdata->deepsleep_reg = DA8XX_SYSCFG1_VIRT(DA8XX_DEEPSLEEP_REG);
+ pdata->ddrpsc_num = DA8XX_LPSC1_EMIF3C;
+
+ pdata->cpupll_reg_base = ioremap(DA8XX_PLL0_BASE, SZ_4K);
+ if (!pdata->cpupll_reg_base)
+ return -ENOMEM;
+
+ pdata->ddrpll_reg_base = ioremap(DA8XX_PLL1_BASE, SZ_4K);
+ if (!pdata->ddrpll_reg_base) {
+ ret = -ENOMEM;
+ goto no_ddrpll_mem;
+ }
+
+ pdata->ddrpsc_reg_base = ioremap(DA8XX_PSC1_BASE, SZ_4K);
+ if (!pdata->ddrpsc_reg_base) {
+ ret = -ENOMEM;
+ goto no_ddrpsc_mem;
+ }
+
+ return platform_device_register(pdev);
+
+no_ddrpsc_mem:
+ iounmap(pdata->ddrpll_reg_base);
+no_ddrpll_mem:
+ iounmap(pdata->cpupll_reg_base);
+ return ret;
+}
static struct davinci_soc_info davinci_soc_info_da850 = {
.io_desc = da850_io_desc,
@@ -1049,17 +1089,25 @@ static struct davinci_soc_info davinci_soc_info_da850 = {
.gpio_irq = IRQ_DA8XX_GPIO0,
.serial_dev = &da8xx_serial_device,
.emac_pdata = &da8xx_emac_pdata,
+ .sram_dma = DA8XX_ARM_RAM_BASE,
+ .sram_len = SZ_8K,
};
void __init da850_init(void)
{
- da8xx_syscfg_base = ioremap(DA8XX_SYSCFG_BASE, SZ_4K);
- if (WARN(!da8xx_syscfg_base, "Unable to map syscfg module"))
+ unsigned int v;
+
+ da8xx_syscfg0_base = ioremap(DA8XX_SYSCFG0_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg0_base, "Unable to map syscfg0 module"))
+ return;
+
+ da8xx_syscfg1_base = ioremap(DA8XX_SYSCFG1_BASE, SZ_4K);
+ if (WARN(!da8xx_syscfg1_base, "Unable to map syscfg1 module"))
return;
davinci_soc_info_da850.jtag_id_base =
- DA8XX_SYSCFG_VIRT(DA8XX_JTAG_ID_REG);
- davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG_VIRT(0x120);
+ DA8XX_SYSCFG0_VIRT(DA8XX_JTAG_ID_REG);
+ davinci_soc_info_da850.pinmux_base = DA8XX_SYSCFG0_VIRT(0x120);
davinci_common_init(&davinci_soc_info_da850);
@@ -1071,4 +1119,14 @@ void __init da850_init(void)
* be any noticible change even in non-DVFS use cases.
*/
da850_set_async3_src(1);
+
+ /* Unlock writing to PLL0 registers */
+ v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
+ v &= ~CFGCHIP0_PLL_MASTER_LOCK;
+ __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP0_REG));
+
+ /* Unlock writing to PLL1 registers */
+ v = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
+ v &= ~CFGCHIP3_PLL1_MASTER_LOCK;
+ __raw_writel(v, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG));
}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index dd2d32c4ce86..0a96791d3b0f 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -24,8 +24,10 @@
#include "clock.h"
#define DA8XX_TPCC_BASE 0x01c00000
+#define DA850_TPCC1_BASE 0x01e30000
#define DA8XX_TPTC0_BASE 0x01c08000
#define DA8XX_TPTC1_BASE 0x01c08400
+#define DA850_TPTC2_BASE 0x01e38000
#define DA8XX_WDOG_BASE 0x01c21000 /* DA8XX_TIMER64P1_BASE */
#define DA8XX_I2C0_BASE 0x01c22000
#define DA8XX_RTC_BASE 0x01C23000
@@ -42,7 +44,8 @@
#define DA8XX_MDIO_REG_OFFSET 0x4000
#define DA8XX_EMAC_CTRL_RAM_SIZE SZ_8K
-void __iomem *da8xx_syscfg_base;
+void __iomem *da8xx_syscfg0_base;
+void __iomem *da8xx_syscfg1_base;
static struct plat_serial8250_port da8xx_serial_pdata[] = {
{
@@ -82,11 +85,6 @@ struct platform_device da8xx_serial_device = {
},
};
-static const s8 da8xx_dma_chan_no_event[] = {
- 20, 21,
- -1
-};
-
static const s8 da8xx_queue_tc_mapping[][2] = {
/* {event queue no, TC no} */
{0, 0},
@@ -101,20 +99,52 @@ static const s8 da8xx_queue_priority_mapping[][2] = {
{-1, -1}
};
-static struct edma_soc_info da8xx_edma_info[] = {
+static const s8 da850_queue_tc_mapping[][2] = {
+ /* {event queue no, TC no} */
+ {0, 0},
+ {-1, -1}
+};
+
+static const s8 da850_queue_priority_mapping[][2] = {
+ /* {event queue no, Priority} */
+ {0, 3},
+ {-1, -1}
+};
+
+static struct edma_soc_info da830_edma_info[] = {
+ {
+ .n_channel = 32,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 2,
+ .n_cc = 1,
+ .queue_tc_mapping = da8xx_queue_tc_mapping,
+ .queue_priority_mapping = da8xx_queue_priority_mapping,
+ },
+};
+
+static struct edma_soc_info da850_edma_info[] = {
{
.n_channel = 32,
.n_region = 4,
.n_slot = 128,
.n_tc = 2,
.n_cc = 1,
- .noevent = da8xx_dma_chan_no_event,
.queue_tc_mapping = da8xx_queue_tc_mapping,
.queue_priority_mapping = da8xx_queue_priority_mapping,
},
+ {
+ .n_channel = 32,
+ .n_region = 4,
+ .n_slot = 128,
+ .n_tc = 1,
+ .n_cc = 1,
+ .queue_tc_mapping = da850_queue_tc_mapping,
+ .queue_priority_mapping = da850_queue_priority_mapping,
+ },
};
-static struct resource da8xx_edma_resources[] = {
+static struct resource da830_edma_resources[] = {
{
.name = "edma_cc0",
.start = DA8XX_TPCC_BASE,
@@ -145,19 +175,91 @@ static struct resource da8xx_edma_resources[] = {
},
};
-static struct platform_device da8xx_edma_device = {
+static struct resource da850_edma_resources[] = {
+ {
+ .name = "edma_cc0",
+ .start = DA8XX_TPCC_BASE,
+ .end = DA8XX_TPCC_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc0",
+ .start = DA8XX_TPTC0_BASE,
+ .end = DA8XX_TPTC0_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc1",
+ .start = DA8XX_TPTC1_BASE,
+ .end = DA8XX_TPTC1_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_cc1",
+ .start = DA850_TPCC1_BASE,
+ .end = DA850_TPCC1_BASE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma_tc2",
+ .start = DA850_TPTC2_BASE,
+ .end = DA850_TPTC2_BASE + SZ_1K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "edma0",
+ .start = IRQ_DA8XX_CCINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma0_err",
+ .start = IRQ_DA8XX_CCERRINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma1",
+ .start = IRQ_DA850_CCINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "edma1_err",
+ .start = IRQ_DA850_CCERRINT1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device da830_edma_device = {
.name = "edma",
.id = -1,
.dev = {
- .platform_data = da8xx_edma_info,
+ .platform_data = da830_edma_info,
},
- .num_resources = ARRAY_SIZE(da8xx_edma_resources),
- .resource = da8xx_edma_resources,
+ .num_resources = ARRAY_SIZE(da830_edma_resources),
+ .resource = da830_edma_resources,
+};
+
+static struct platform_device da850_edma_device = {
+ .name = "edma",
+ .id = -1,
+ .dev = {
+ .platform_data = da850_edma_info,
+ },
+ .num_resources = ARRAY_SIZE(da850_edma_resources),
+ .resource = da850_edma_resources,
};
int __init da8xx_register_edma(void)
{
- return platform_device_register(&da8xx_edma_device);
+ struct platform_device *pdev;
+
+ if (cpu_is_davinci_da830())
+ pdev = &da830_edma_device;
+ else if (cpu_is_davinci_da850())
+ pdev = &da850_edma_device;
+ else
+ return -ENODEV;
+
+ return platform_device_register(pdev);
}
static struct resource da8xx_i2c_resources0[] = {
@@ -481,11 +583,31 @@ static struct platform_device da8xx_rtc_device = {
int da8xx_register_rtc(void)
{
+ int ret;
+
/* Unlock the rtc's registers */
__raw_writel(0x83e70b13, IO_ADDRESS(DA8XX_RTC_BASE + 0x6c));
__raw_writel(0x95a4f1e0, IO_ADDRESS(DA8XX_RTC_BASE + 0x70));
- return platform_device_register(&da8xx_rtc_device);
+ ret = platform_device_register(&da8xx_rtc_device);
+ if (!ret)
+ /* Atleast on DA850, RTC is a wakeup source */
+ device_init_wakeup(&da8xx_rtc_device.dev, true);
+
+ return ret;
+}
+
+static void __iomem *da8xx_ddr2_ctlr_base;
+void __iomem * __init da8xx_get_mem_ctlr(void)
+{
+ if (da8xx_ddr2_ctlr_base)
+ return da8xx_ddr2_ctlr_base;
+
+ da8xx_ddr2_ctlr_base = ioremap(DA8XX_DDR2_CTL_BASE, SZ_32K);
+ if (!da8xx_ddr2_ctlr_base)
+ pr_warning("%s: Unable to map DDR2 controller", __func__);
+
+ return da8xx_ddr2_ctlr_base;
}
static struct resource da8xx_cpuidle_resources[] = {
@@ -513,6 +635,7 @@ static struct platform_device da8xx_cpuidle_device = {
int __init da8xx_register_cpuidle(void)
{
+ da8xx_cpuidle_pdata.ddr2_ctlr_base = da8xx_get_mem_ctlr();
+
return platform_device_register(&da8xx_cpuidle_device);
}
-
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index dedf4d4f3a27..b1185f82ffb3 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -564,13 +564,6 @@ static u8 dm355_default_priorities[DAVINCI_N_AINTC_IRQ] = {
/*----------------------------------------------------------------------*/
-static const s8 dma_chan_dm355_no_event[] = {
- 12, 13, 24, 56, 57,
- 58, 59, 60, 61, 62,
- 63,
- -1
-};
-
static const s8
queue_tc_mapping[][2] = {
/* {event queue no, TC no} */
@@ -594,7 +587,6 @@ static struct edma_soc_info dm355_edma_info[] = {
.n_slot = 128,
.n_tc = 2,
.n_cc = 1,
- .noevent = dma_chan_dm355_no_event,
.queue_tc_mapping = queue_tc_mapping,
.queue_priority_mapping = queue_priority_mapping,
},
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 2ec619ec1657..b4a00c4a6e78 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -754,7 +754,7 @@ static struct edma_soc_info dm365_edma_info[] = {
.n_cc = 1,
.queue_tc_mapping = dm365_queue_tc_mapping,
.queue_priority_mapping = dm365_queue_priority_mapping,
- .default_queue = EVENTQ_2,
+ .default_queue = EVENTQ_3,
},
};
@@ -993,7 +993,6 @@ void __init dm365_init_asp(struct snd_platform_data *pdata)
void __init dm365_init_ks(struct davinci_ks_platform_data *pdata)
{
- davinci_cfg_reg(DM365_KEYSCAN);
dm365_ks_device.dev.platform_data = pdata;
platform_device_register(&dm365_ks_device);
}
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index 2cd008156dea..fc060e7aefdf 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -479,15 +479,6 @@ static u8 dm644x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
/*----------------------------------------------------------------------*/
-static const s8 dma_chan_dm644x_no_event[] = {
- 0, 1, 12, 13, 14,
- 15, 25, 30, 31, 45,
- 46, 47, 55, 56, 57,
- 58, 59, 60, 61, 62,
- 63,
- -1
-};
-
static const s8
queue_tc_mapping[][2] = {
/* {event queue no, TC no} */
@@ -511,7 +502,6 @@ static struct edma_soc_info dm644x_edma_info[] = {
.n_slot = 128,
.n_tc = 2,
.n_cc = 1,
- .noevent = dma_chan_dm644x_no_event,
.queue_tc_mapping = queue_tc_mapping,
.queue_priority_mapping = queue_priority_mapping,
},
diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c
index 829a44bcf799..7eb34e9253c6 100644
--- a/arch/arm/mach-davinci/dm646x.c
+++ b/arch/arm/mach-davinci/dm646x.c
@@ -42,7 +42,6 @@
/*
* Device specific clocks
*/
-#define DM646X_REF_FREQ 27000000
#define DM646X_AUX_FREQ 24000000
static struct pll_data pll1_data = {
@@ -57,7 +56,6 @@ static struct pll_data pll2_data = {
static struct clk ref_clk = {
.name = "ref_clk",
- .rate = DM646X_REF_FREQ,
};
static struct clk aux_clkin = {
@@ -513,14 +511,6 @@ static u8 dm646x_default_priorities[DAVINCI_N_AINTC_IRQ] = {
/*----------------------------------------------------------------------*/
-static const s8 dma_chan_dm646x_no_event[] = {
- 0, 1, 2, 3, 13,
- 14, 15, 24, 25, 26,
- 27, 30, 31, 54, 55,
- 56,
- -1
-};
-
/* Four Transfer Controllers on DM646x */
static const s8
dm646x_queue_tc_mapping[][2] = {
@@ -549,7 +539,6 @@ static struct edma_soc_info dm646x_edma_info[] = {
.n_slot = 512,
.n_tc = 4,
.n_cc = 1,
- .noevent = dma_chan_dm646x_no_event,
.queue_tc_mapping = dm646x_queue_tc_mapping,
.queue_priority_mapping = dm646x_queue_priority_mapping,
},
@@ -925,6 +914,7 @@ void dm646x_setup_vpif(struct vpif_display_config *display_config,
void __init dm646x_init(void)
{
+ dm646x_board_setup_refclk(&ref_clk);
davinci_common_init(&davinci_soc_info_dm646x);
}
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index 648fbb760ae1..15dd886df04c 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -226,11 +226,11 @@ struct edma {
*/
DECLARE_BITMAP(edma_inuse, EDMA_MAX_PARAMENTRY);
- /* The edma_noevent bit for each channel is clear unless
- * it doesn't trigger DMA events on this platform. It uses a
- * bit of SOC-specific initialization code.
+ /* The edma_unused bit for each channel is clear unless
+ * it is not being used on this platform. It uses a bit
+ * of SOC-specific initialization code.
*/
- DECLARE_BITMAP(edma_noevent, EDMA_MAX_DMACH);
+ DECLARE_BITMAP(edma_unused, EDMA_MAX_DMACH);
unsigned irq_res_start;
unsigned irq_res_end;
@@ -243,6 +243,7 @@ struct edma {
};
static struct edma *edma_info[EDMA_MAX_CC];
+static int arch_num_cc;
/* dummy param set used to (re)initialize parameter RAM slots */
static const struct edmacc_param dummy_paramset = {
@@ -555,8 +556,27 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
return EDMA_CTLR_CHAN(ctlr, i - num_slots + 1);
}
+static int prepare_unused_channel_list(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int i, ctlr;
+
+ for (i = 0; i < pdev->num_resources; i++) {
+ if ((pdev->resource[i].flags & IORESOURCE_DMA) &&
+ (int)pdev->resource[i].start >= 0) {
+ ctlr = EDMA_CTLR(pdev->resource[i].start);
+ clear_bit(EDMA_CHAN_SLOT(pdev->resource[i].start),
+ edma_info[ctlr]->edma_unused);
+ }
+ }
+
+ return 0;
+}
+
/*-----------------------------------------------------------------------*/
+static bool unused_chan_list_done;
+
/* Resource alloc/free: dma channels, parameter RAM slots */
/**
@@ -594,7 +614,22 @@ int edma_alloc_channel(int channel,
void *data,
enum dma_event_q eventq_no)
{
- unsigned i, done, ctlr = 0;
+ unsigned i, done = 0, ctlr = 0;
+ int ret = 0;
+
+ if (!unused_chan_list_done) {
+ /*
+ * Scan all the platform devices to find out the EDMA channels
+ * used and clear them in the unused list, making the rest
+ * available for ARM usage.
+ */
+ ret = bus_for_each_dev(&platform_bus_type, NULL, NULL,
+ prepare_unused_channel_list);
+ if (ret < 0)
+ return ret;
+
+ unused_chan_list_done = true;
+ }
if (channel >= 0) {
ctlr = EDMA_CTLR(channel);
@@ -602,15 +637,15 @@ int edma_alloc_channel(int channel,
}
if (channel < 0) {
- for (i = 0; i < EDMA_MAX_CC; i++) {
+ for (i = 0; i < arch_num_cc; i++) {
channel = 0;
for (;;) {
channel = find_next_bit(edma_info[i]->
- edma_noevent,
+ edma_unused,
edma_info[i]->num_channels,
channel);
if (channel == edma_info[i]->num_channels)
- return -ENOMEM;
+ break;
if (!test_and_set_bit(channel,
edma_info[i]->edma_inuse)) {
done = 1;
@@ -622,6 +657,8 @@ int edma_alloc_channel(int channel,
if (done)
break;
}
+ if (!done)
+ return -ENOMEM;
} else if (channel >= edma_info[ctlr]->num_channels) {
return -EINVAL;
} else if (test_and_set_bit(channel, edma_info[ctlr]->edma_inuse)) {
@@ -642,7 +679,7 @@ int edma_alloc_channel(int channel,
map_dmach_queue(ctlr, channel, eventq_no);
- return channel;
+ return EDMA_CTLR_CHAN(ctlr, channel);
}
EXPORT_SYMBOL(edma_alloc_channel);
@@ -1219,7 +1256,7 @@ int edma_start(unsigned channel)
unsigned int mask = (1 << (channel & 0x1f));
/* EDMA channels without event association */
- if (test_bit(channel, edma_info[ctlr]->edma_noevent)) {
+ if (test_bit(channel, edma_info[ctlr]->edma_unused)) {
pr_debug("EDMA: ESR%d %08x\n", j,
edma_shadow0_read_array(ctlr, SH_ESR, j));
edma_shadow0_write_array(ctlr, SH_ESR, j, mask);
@@ -1344,7 +1381,6 @@ static int __init edma_probe(struct platform_device *pdev)
const s8 (*queue_tc_mapping)[2];
int i, j, found = 0;
int status = -1;
- const s8 *noevent;
int irq[EDMA_MAX_CC] = {0, 0};
int err_irq[EDMA_MAX_CC] = {0, 0};
struct resource *r[EDMA_MAX_CC] = {NULL};
@@ -1407,11 +1443,9 @@ static int __init edma_probe(struct platform_device *pdev)
memcpy_toio(edmacc_regs_base[j] + PARM_OFFSET(i),
&dummy_paramset, PARM_SIZE);
- noevent = info[j].noevent;
- if (noevent) {
- while (*noevent != -1)
- set_bit(*noevent++, edma_info[j]->edma_noevent);
- }
+ /* Mark all channels as unused */
+ memset(edma_info[j]->edma_unused, 0xff,
+ sizeof(edma_info[j]->edma_unused));
sprintf(irq_name, "edma%d", j);
irq[j] = platform_get_irq_byname(pdev, irq_name);
@@ -1467,6 +1501,7 @@ static int __init edma_probe(struct platform_device *pdev)
edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
edma_write_array(j, EDMA_QRAE, i, 0x0);
}
+ arch_num_cc++;
}
if (tc_errs_handled) {
diff --git a/arch/arm/mach-davinci/include/mach/cdce949.h b/arch/arm/mach-davinci/include/mach/cdce949.h
new file mode 100644
index 000000000000..c73331fae341
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/cdce949.h
@@ -0,0 +1,19 @@
+/*
+ * TI CDCE949 off-chip clock synthesizer support
+ *
+ * 2009 (C) Texas Instruments, Inc. http://www.ti.com/
+ *
+ * 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.
+ */
+#ifndef _MACH_DAVINCI_CDCE949_H
+#define _MACH_DAVINCI_CDCE949_H
+
+#include <linux/clk.h>
+
+#include <mach/clock.h>
+
+int cdce_set_rate(struct clk *clk, unsigned long rate);
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/cpuidle.h b/arch/arm/mach-davinci/include/mach/cpuidle.h
index cbfc6a9c81b4..74f088b0edfb 100644
--- a/arch/arm/mach-davinci/include/mach/cpuidle.h
+++ b/arch/arm/mach-davinci/include/mach/cpuidle.h
@@ -12,6 +12,7 @@
struct davinci_cpuidle_config {
u32 ddr2_pdown;
+ void __iomem *ddr2_ctlr_base;
};
#endif
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 90704910d343..cc9be7fee627 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -13,15 +13,17 @@
#include <video/da8xx-fb.h>
+#include <linux/davinci_emac.h>
#include <mach/serial.h>
#include <mach/edma.h>
#include <mach/i2c.h>
-#include <mach/emac.h>
#include <mach/asp.h>
#include <mach/mmc.h>
#include <mach/usb.h>
+#include <mach/pm.h>
-extern void __iomem *da8xx_syscfg_base;
+extern void __iomem *da8xx_syscfg0_base;
+extern void __iomem *da8xx_syscfg1_base;
/*
* The cp_intc interrupt controller for the da8xx isn't in the same
@@ -34,13 +36,17 @@ extern void __iomem *da8xx_syscfg_base;
#define DA8XX_CP_INTC_SIZE SZ_8K
#define DA8XX_CP_INTC_VIRT (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K)
-#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000)
-#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x))
+#define DA8XX_SYSCFG0_BASE (IO_PHYS + 0x14000)
+#define DA8XX_SYSCFG0_VIRT(x) (da8xx_syscfg0_base + (x))
#define DA8XX_JTAG_ID_REG 0x18
#define DA8XX_CFGCHIP0_REG 0x17c
#define DA8XX_CFGCHIP2_REG 0x184
#define DA8XX_CFGCHIP3_REG 0x188
+#define DA8XX_SYSCFG1_BASE (IO_PHYS + 0x22C000)
+#define DA8XX_SYSCFG1_VIRT(x) (da8xx_syscfg1_base + (x))
+#define DA8XX_DEEPSLEEP_REG 0x8
+
#define DA8XX_PSC0_BASE 0x01c10000
#define DA8XX_PLL0_BASE 0x01c11000
#define DA8XX_TIMER64P0_BASE 0x01c20000
@@ -48,11 +54,13 @@ extern void __iomem *da8xx_syscfg_base;
#define DA8XX_GPIO_BASE 0x01e26000
#define DA8XX_PSC1_BASE 0x01e27000
#define DA8XX_LCD_CNTRL_BASE 0x01e13000
+#define DA8XX_PLL1_BASE 0x01e1a000
#define DA8XX_MMCSD0_BASE 0x01c40000
#define DA8XX_AEMIF_CS2_BASE 0x60000000
#define DA8XX_AEMIF_CS3_BASE 0x62000000
#define DA8XX_AEMIF_CTL_BASE 0x68000000
#define DA8XX_DDR2_CTL_BASE 0xb0000000
+#define DA8XX_ARM_RAM_BASE 0xffff0000
#define PINMUX0 0x00
#define PINMUX1 0x04
@@ -90,6 +98,8 @@ void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
int da8xx_register_rtc(void);
int da850_register_cpufreq(void);
int da8xx_register_cpuidle(void);
+void __iomem * __init da8xx_get_mem_ctlr(void);
+int da850_register_pm(struct platform_device *pdev);
extern struct platform_device da8xx_serial_device;
extern struct emac_platform_data da8xx_emac_pdata;
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
index f1710a30e7ba..3c07a88b4249 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -14,8 +14,8 @@
#define __ASM_ARCH_DM665_H
#include <linux/platform_device.h>
+#include <linux/davinci_emac.h>
#include <mach/hardware.h>
-#include <mach/emac.h>
#include <mach/asp.h>
#include <mach/keyscan.h>
diff --git a/arch/arm/mach-davinci/include/mach/dm644x.h b/arch/arm/mach-davinci/include/mach/dm644x.h
index 44e8f0fae9ea..1a8b09ccc3c8 100644
--- a/arch/arm/mach-davinci/include/mach/dm644x.h
+++ b/arch/arm/mach-davinci/include/mach/dm644x.h
@@ -22,8 +22,8 @@
#ifndef __ASM_ARCH_DM644X_H
#define __ASM_ARCH_DM644X_H
+#include <linux/davinci_emac.h>
#include <mach/hardware.h>
-#include <mach/emac.h>
#include <mach/asp.h>
#include <media/davinci/vpfe_capture.h>
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
index 8cec746ae9d2..846da98b619a 100644
--- a/arch/arm/mach-davinci/include/mach/dm646x.h
+++ b/arch/arm/mach-davinci/include/mach/dm646x.h
@@ -12,10 +12,11 @@
#define __ASM_ARCH_DM646X_H
#include <mach/hardware.h>
-#include <mach/emac.h>
#include <mach/asp.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
+#include <linux/clk.h>
+#include <linux/davinci_emac.h>
#define DM646X_EMAC_BASE (0x01C80000)
#define DM646X_EMAC_CNTRL_OFFSET (0x0000)
@@ -30,6 +31,7 @@ void __init dm646x_init(void);
void __init dm646x_init_ide(void);
void __init dm646x_init_mcasp0(struct snd_platform_data *pdata);
void __init dm646x_init_mcasp1(struct snd_platform_data *pdata);
+void __init dm646x_board_setup_refclk(struct clk *clk);
void dm646x_video_init(void);
diff --git a/arch/arm/mach-davinci/include/mach/edma.h b/arch/arm/mach-davinci/include/mach/edma.h
index eb8bfd7925e7..ced3092af5ba 100644
--- a/arch/arm/mach-davinci/include/mach/edma.h
+++ b/arch/arm/mach-davinci/include/mach/edma.h
@@ -280,8 +280,6 @@ struct edma_soc_info {
unsigned n_cc;
enum dma_event_q default_queue;
- /* list of channels with no even trigger; terminated by "-1" */
- const s8 *noevent;
const s8 (*queue_tc_mapping)[2];
const s8 (*queue_priority_mapping)[2];
};
diff --git a/arch/arm/mach-davinci/include/mach/emac.h b/arch/arm/mach-davinci/include/mach/emac.h
deleted file mode 100644
index beff4fb7c845..000000000000
--- a/arch/arm/mach-davinci/include/mach/emac.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * TI DaVinci EMAC platform support
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * 2007 (c) Deep Root Systems, LLC. 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.
- */
-#ifndef _MACH_DAVINCI_EMAC_H
-#define _MACH_DAVINCI_EMAC_H
-
-#include <linux/if_ether.h>
-#include <linux/memory.h>
-
-struct emac_platform_data {
- char mac_addr[ETH_ALEN];
- u32 ctrl_reg_offset;
- u32 ctrl_mod_reg_offset;
- u32 ctrl_ram_offset;
- u32 mdio_reg_offset;
- u32 ctrl_ram_size;
- u32 phy_mask;
- u32 mdio_max_freq;
- u8 rmii_en;
- u8 version;
-};
-
-enum {
- EMAC_VERSION_1, /* DM644x */
- EMAC_VERSION_2, /* DM646x */
-};
-
-void davinci_get_mac_addr(struct memory_accessor *mem_acc, void *context);
-#endif
diff --git a/arch/arm/mach-davinci/include/mach/i2c.h b/arch/arm/mach-davinci/include/mach/i2c.h
index c248e9b7e825..44bdea13cc8c 100644
--- a/arch/arm/mach-davinci/include/mach/i2c.h
+++ b/arch/arm/mach-davinci/include/mach/i2c.h
@@ -1,5 +1,5 @@
/*
- * DaVinci I2C controller platfrom_device info
+ * DaVinci I2C controller platform_device info
*
* Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
*
diff --git a/arch/arm/mach-davinci/include/mach/keyscan.h b/arch/arm/mach-davinci/include/mach/keyscan.h
index b4e21a2976d1..7a560e05bda8 100644
--- a/arch/arm/mach-davinci/include/mach/keyscan.h
+++ b/arch/arm/mach-davinci/include/mach/keyscan.h
@@ -29,6 +29,7 @@ enum davinci_matrix_types {
};
struct davinci_ks_platform_data {
+ int (*device_enable)(struct device *dev);
unsigned short *keymap;
u32 keymapsize;
u8 rep:1;
diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h
index 80309aed534a..a91edfb8beea 100644
--- a/arch/arm/mach-davinci/include/mach/memory.h
+++ b/arch/arm/mach-davinci/include/mach/memory.h
@@ -31,6 +31,11 @@
#define PHYS_OFFSET DAVINCI_DDR_BASE
#endif
+#define DDR2_SDRCR_OFFSET 0xc
+#define DDR2_SRPD_BIT BIT(23)
+#define DDR2_MCLKSTOPEN_BIT BIT(30)
+#define DDR2_LPMODEN_BIT BIT(31)
+
/*
* Increase size of DMA-consistent memory region
*/
diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h
index b60c693985ff..137bfba51d1f 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -899,6 +899,7 @@ enum davinci_da850_index {
DA850_GPIO2_15,
DA850_GPIO4_0,
DA850_GPIO4_1,
+ DA850_RTC_ALARM,
};
#ifdef CONFIG_DAVINCI_MUX
diff --git a/arch/arm/mach-davinci/include/mach/pm.h b/arch/arm/mach-davinci/include/mach/pm.h
new file mode 100644
index 000000000000..37b19bf35a85
--- /dev/null
+++ b/arch/arm/mach-davinci/include/mach/pm.h
@@ -0,0 +1,54 @@
+/*
+ * TI DaVinci platform support for power management.
+ *
+ * Copyright (C) 2009 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 _MACH_DAVINCI_PM_H
+#define _MACH_DAVINCI_PM_H
+
+/*
+ * Caution: Assembly code in sleep.S makes assumtion on the order
+ * of the members of this structure.
+ */
+struct davinci_pm_config {
+ void __iomem *ddr2_ctlr_base;
+ void __iomem *ddrpsc_reg_base;
+ int ddrpsc_num;
+ void __iomem *ddrpll_reg_base;
+ void __iomem *deepsleep_reg;
+ void __iomem *cpupll_reg_base;
+ /*
+ * Note on SLEEPCOUNT:
+ * The SLEEPCOUNT feature is mainly intended for cases in which
+ * the internal oscillator is used. The internal oscillator is
+ * fully disabled in deep sleep mode. When you exist deep sleep
+ * mode, the oscillator will be turned on and will generate very
+ * small oscillations which will not be detected by the deep sleep
+ * counter. Eventually those oscillations will grow to an amplitude
+ * large enough to start incrementing the deep sleep counter.
+ * In this case recommendation from hardware engineers is that the
+ * SLEEPCOUNT be set to 4096. This means that 4096 valid clock cycles
+ * must be detected before the clock is passed to the rest of the
+ * system.
+ * In the case that the internal oscillator is not used and the
+ * clock is generated externally, the SLEEPCOUNT value can be very
+ * small since the clock input is assumed to be stable before SoC
+ * is taken out of deepsleep mode. A value of 128 would be more than
+ * adequate.
+ */
+ int sleepcount;
+};
+
+extern unsigned int davinci_cpu_suspend_sz;
+extern void davinci_cpu_suspend(struct davinci_pm_config *);
+
+#endif
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 171173c1dbad..651f6d8158fa 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -180,8 +180,23 @@
#define DA8XX_LPSC1_CR_P3_SS 26
#define DA8XX_LPSC1_L3_CBA_RAM 31
+/* PSC register offsets */
+#define EPCPR 0x070
+#define PTCMD 0x120
+#define PTSTAT 0x128
+#define PDSTAT 0x200
+#define PDCTL1 0x304
+#define MDSTAT 0x800
+#define MDCTL 0xA00
+
+#define MDSTAT_STATE_MASK 0x1f
+
+#ifndef __ASSEMBLER__
+
extern int davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id);
extern void davinci_psc_config(unsigned int domain, unsigned int ctlr,
unsigned int id, char enable);
+#endif
+
#endif /* __ASM_ARCH_PSC_H */
diff --git a/arch/arm/mach-davinci/include/mach/timex.h b/arch/arm/mach-davinci/include/mach/timex.h
index 52827567841d..9b885298f106 100644
--- a/arch/arm/mach-davinci/include/mach/timex.h
+++ b/arch/arm/mach-davinci/include/mach/timex.h
@@ -11,7 +11,12 @@
#ifndef __ASM_ARCH_TIMEX_H
#define __ASM_ARCH_TIMEX_H
-/* The source frequency for the timers is the 27MHz clock */
+/*
+ * Alert: Not all timers of the DaVinci family run at a frequency of 27MHz,
+ * but we should be fine as long as CLOCK_TICK_RATE or LATCH (see include/
+ * linux/jiffies.h) are not used directly in code. Currently none of the
+ * code relevant to DaVinci platform depends on these values directly.
+ */
#define CLOCK_TICK_RATE 27000000
#endif /* __ASM_ARCH_TIMEX_H__ */
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c
index 49912b48b1b0..a1c0b6b99edf 100644
--- a/arch/arm/mach-davinci/io.c
+++ b/arch/arm/mach-davinci/io.c
@@ -24,7 +24,7 @@ void __iomem *davinci_ioremap(unsigned long p, size_t size, unsigned int type)
if (BETWEEN(p, IO_PHYS, IO_SIZE))
return XLATE(p, IO_PHYS, IO_VIRT);
- return __arm_ioremap(p, size, type);
+ return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
}
EXPORT_SYMBOL(davinci_ioremap);
diff --git a/arch/arm/mach-davinci/pm.c b/arch/arm/mach-davinci/pm.c
new file mode 100644
index 000000000000..fab953b43dea
--- /dev/null
+++ b/arch/arm/mach-davinci/pm.c
@@ -0,0 +1,158 @@
+/*
+ * DaVinci Power Management Routines
+ *
+ * Copyright (C) 2009 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/delay.h>
+
+#include <mach/da8xx.h>
+#include <mach/sram.h>
+#include <mach/pm.h>
+
+#include "clock.h"
+
+#define DEEPSLEEP_SLEEPCOUNT_MASK 0xFFFF
+
+static void (*davinci_sram_suspend) (struct davinci_pm_config *);
+static struct davinci_pm_config *pdata;
+
+static void davinci_sram_push(void *dest, void *src, unsigned int size)
+{
+ memcpy(dest, src, size);
+ flush_icache_range((unsigned long)dest, (unsigned long)(dest + size));
+}
+
+static void davinci_pm_suspend(void)
+{
+ unsigned val;
+
+ if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
+
+ /* Switch CPU PLL to bypass mode */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN);
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+ udelay(PLL_BYPASS_TIME);
+
+ /* Powerdown CPU PLL */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val |= PLLCTL_PLLPWRDN;
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+ }
+
+ /* Configure sleep count in deep sleep register */
+ val = __raw_readl(pdata->deepsleep_reg);
+ val &= ~DEEPSLEEP_SLEEPCOUNT_MASK,
+ val |= pdata->sleepcount;
+ __raw_writel(val, pdata->deepsleep_reg);
+
+ /* System goes to sleep in this call */
+ davinci_sram_suspend(pdata);
+
+ if (pdata->cpupll_reg_base != pdata->ddrpll_reg_base) {
+
+ /* put CPU PLL in reset */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val &= ~PLLCTL_PLLRST;
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+ /* put CPU PLL in power down */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val &= ~PLLCTL_PLLPWRDN;
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+ /* wait for CPU PLL reset */
+ udelay(PLL_RESET_TIME);
+
+ /* bring CPU PLL out of reset */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val |= PLLCTL_PLLRST;
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+
+ /* Wait for CPU PLL to lock */
+ udelay(PLL_LOCK_TIME);
+
+ /* Remove CPU PLL from bypass mode */
+ val = __raw_readl(pdata->cpupll_reg_base + PLLCTL);
+ val &= ~PLLCTL_PLLENSRC;
+ val |= PLLCTL_PLLEN;
+ __raw_writel(val, pdata->cpupll_reg_base + PLLCTL);
+ }
+}
+
+static int davinci_pm_enter(suspend_state_t state)
+{
+ int ret = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ davinci_pm_suspend();
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct platform_suspend_ops davinci_pm_ops = {
+ .enter = davinci_pm_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static int __init davinci_pm_probe(struct platform_device *pdev)
+{
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "cannot get platform data\n");
+ return -ENOENT;
+ }
+
+ davinci_sram_suspend = sram_alloc(davinci_cpu_suspend_sz, NULL);
+ if (!davinci_sram_suspend) {
+ dev_err(&pdev->dev, "cannot allocate SRAM memory\n");
+ return -ENOMEM;
+ }
+
+ davinci_sram_push(davinci_sram_suspend, davinci_cpu_suspend,
+ davinci_cpu_suspend_sz);
+
+ suspend_set_ops(&davinci_pm_ops);
+
+ return 0;
+}
+
+static int __exit davinci_pm_remove(struct platform_device *pdev)
+{
+ sram_free(davinci_sram_suspend, davinci_cpu_suspend_sz);
+ return 0;
+}
+
+static struct platform_driver davinci_pm_driver = {
+ .driver = {
+ .name = "pm-davinci",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(davinci_pm_remove),
+};
+
+static int __init davinci_pm_init(void)
+{
+ return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
+}
+late_initcall(davinci_pm_init);
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index 04a3cb72c5ab..adf6b5c7f1e5 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -25,17 +25,6 @@
#include <mach/cputype.h>
#include <mach/psc.h>
-/* PSC register offsets */
-#define EPCPR 0x070
-#define PTCMD 0x120
-#define PTSTAT 0x128
-#define PDSTAT 0x200
-#define PDCTL1 0x304
-#define MDSTAT 0x800
-#define MDCTL 0xA00
-
-#define MDSTAT_STATE_MASK 0x1f
-
/* Return nonzero iff the domain's clock is active */
int __init davinci_psc_is_clk_active(unsigned int ctlr, unsigned int id)
{
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
new file mode 100644
index 000000000000..fb5e72b532b0
--- /dev/null
+++ b/arch/arm/mach-davinci/sleep.S
@@ -0,0 +1,224 @@
+/*
+ * (C) Copyright 2009, 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
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* replicated define because linux/bitops.h cannot be included in assembly */
+#define BIT(nr) (1 << (nr))
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/psc.h>
+#include <mach/memory.h>
+
+#include "clock.h"
+
+/* Arbitrary, hardware currently does not update PHYRDY correctly */
+#define PHYRDY_CYCLES 0x1000
+
+/* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */
+#define PLL_BYPASS_CYCLES (PLL_BYPASS_TIME * 25)
+#define PLL_RESET_CYCLES (PLL_RESET_TIME * 25)
+#define PLL_LOCK_CYCLES (PLL_LOCK_TIME * 25)
+
+#define DEEPSLEEP_SLEEPENABLE_BIT BIT(31)
+
+ .text
+/*
+ * Move DaVinci into deep sleep state
+ *
+ * Note: This code is copied to internal SRAM by PM code. When the DaVinci
+ * wakes up it continues execution at the point it went to sleep.
+ * Register Usage:
+ * r0: contains virtual base for DDR2 controller
+ * r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
+ * r2: contains PSC number for DDR2
+ * r3: contains virtual base DDR2 PLL controller
+ * r4: contains virtual address of the DEEPSLEEP register
+ */
+ENTRY(davinci_cpu_suspend)
+ stmfd sp!, {r0-r12, lr} @ save registers on stack
+
+ ldr ip, CACHE_FLUSH
+ blx ip
+
+ ldmia r0, {r0-r4}
+
+ /*
+ * Switch DDR to self-refresh mode.
+ */
+
+ /* calculate SDRCR address */
+ ldr ip, [r0, #DDR2_SDRCR_OFFSET]
+ bic ip, ip, #DDR2_SRPD_BIT
+ orr ip, ip, #DDR2_LPMODEN_BIT
+ str ip, [r0, #DDR2_SDRCR_OFFSET]
+
+ ldr ip, [r0, #DDR2_SDRCR_OFFSET]
+ orr ip, ip, #DDR2_MCLKSTOPEN_BIT
+ str ip, [r0, #DDR2_SDRCR_OFFSET]
+
+ mov ip, #PHYRDY_CYCLES
+1: subs ip, ip, #0x1
+ bne 1b
+
+ /* Disable DDR2 LPSC */
+ mov r7, r0
+ mov r0, #0x2
+ bl davinci_ddr_psc_config
+ mov r0, r7
+
+ /* Disable clock to DDR PHY */
+ ldr ip, [r3, #PLLDIV1]
+ bic ip, ip, #PLLDIV_EN
+ str ip, [r3, #PLLDIV1]
+
+ /* Put the DDR PLL in bypass and power down */
+ ldr ip, [r3, #PLLCTL]
+ bic ip, ip, #PLLCTL_PLLENSRC
+ bic ip, ip, #PLLCTL_PLLEN
+ str ip, [r3, #PLLCTL]
+
+ /* Wait for PLL to switch to bypass */
+ mov ip, #PLL_BYPASS_CYCLES
+2: subs ip, ip, #0x1
+ bne 2b
+
+ /* Power down the PLL */
+ ldr ip, [r3, #PLLCTL]
+ orr ip, ip, #PLLCTL_PLLPWRDN
+ str ip, [r3, #PLLCTL]
+
+ /* Go to deep sleep */
+ ldr ip, [r4]
+ orr ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
+ /* System goes to sleep beyond after this instruction */
+ str ip, [r4]
+
+ /* Wake up from sleep */
+
+ /* Clear sleep enable */
+ ldr ip, [r4]
+ bic ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT
+ str ip, [r4]
+
+ /* initialize the DDR PLL controller */
+
+ /* Put PLL in reset */
+ ldr ip, [r3, #PLLCTL]
+ bic ip, ip, #PLLCTL_PLLRST
+ str ip, [r3, #PLLCTL]
+
+ /* Clear PLL power down */
+ ldr ip, [r3, #PLLCTL]
+ bic ip, ip, #PLLCTL_PLLPWRDN
+ str ip, [r3, #PLLCTL]
+
+ mov ip, #PLL_RESET_CYCLES
+3: subs ip, ip, #0x1
+ bne 3b
+
+ /* Bring PLL out of reset */
+ ldr ip, [r3, #PLLCTL]
+ orr ip, ip, #PLLCTL_PLLRST
+ str ip, [r3, #PLLCTL]
+
+ /* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */
+ mov ip, #PLL_LOCK_CYCLES
+4: subs ip, ip, #0x1
+ bne 4b
+
+ /* Remove PLL from bypass mode */
+ ldr ip, [r3, #PLLCTL]
+ bic ip, ip, #PLLCTL_PLLENSRC
+ orr ip, ip, #PLLCTL_PLLEN
+ str ip, [r3, #PLLCTL]
+
+ /* Start 2x clock to DDR2 */
+
+ ldr ip, [r3, #PLLDIV1]
+ orr ip, ip, #PLLDIV_EN
+ str ip, [r3, #PLLDIV1]
+
+ /* Enable VCLK */
+
+ /* Enable DDR2 LPSC */
+ mov r7, r0
+ mov r0, #0x3
+ bl davinci_ddr_psc_config
+ mov r0, r7
+
+ /* clear MCLKSTOPEN */
+
+ ldr ip, [r0, #DDR2_SDRCR_OFFSET]
+ bic ip, ip, #DDR2_MCLKSTOPEN_BIT
+ str ip, [r0, #DDR2_SDRCR_OFFSET]
+
+ ldr ip, [r0, #DDR2_SDRCR_OFFSET]
+ bic ip, ip, #DDR2_LPMODEN_BIT
+ str ip, [r0, #DDR2_SDRCR_OFFSET]
+
+ /* Restore registers and return */
+ ldmfd sp!, {r0-r12, pc}
+
+ENDPROC(davinci_cpu_suspend)
+
+/*
+ * Disables or Enables DDR2 LPSC
+ * Register Usage:
+ * r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC
+ * r1: contains virtual base for DDR2 Power and Sleep controller (PSC)
+ * r2: contains PSC number for DDR2
+ */
+ENTRY(davinci_ddr_psc_config)
+ /* Set next state in mdctl for DDR2 */
+ mov r6, #MDCTL
+ add r6, r6, r2, lsl #2
+ ldr ip, [r1, r6]
+ bic ip, ip, #MDSTAT_STATE_MASK
+ orr ip, ip, r0
+ str ip, [r1, r6]
+
+ /* Enable the Power Domain Transition Command */
+ ldr ip, [r1, #PTCMD]
+ orr ip, ip, #0x1
+ str ip, [r1, #PTCMD]
+
+ /* Check for Transition Complete (PTSTAT) */
+ptstat_done:
+ ldr ip, [r1, #PTSTAT]
+ and ip, ip, #0x1
+ cmp ip, #0x0
+ bne ptstat_done
+
+ /* Check for DDR2 clock disable completion; */
+ mov r6, #MDSTAT
+ add r6, r6, r2, lsl #2
+ddr2clk_stop_done:
+ ldr ip, [r1, r6]
+ and ip, ip, #MDSTAT_STATE_MASK
+ cmp ip, r0
+ bne ddr2clk_stop_done
+
+ mov pc, lr
+ENDPROC(davinci_ddr_psc_config)
+
+CACHE_FLUSH:
+ .word arm926_flush_kern_cache_all
+
+ENTRY(davinci_cpu_suspend_sz)
+ .word . - davinci_cpu_suspend
+ENDPROC(davinci_cpu_suspend_sz)
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 1d0f9d8aff2e..e894ee0d603d 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -10,6 +10,8 @@
* your option) any later version.
*/
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -445,37 +447,39 @@ static void __init ep93xx_dma_clock_init(void)
static int __init ep93xx_clock_init(void)
{
u32 value;
- int i;
- value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
- if (!(value & 0x00800000)) { /* PLL1 bypassed? */
+ /* Determine the bootloader configured pll1 rate */
+ value = __raw_readl(EP93XX_SYSCON_CLKSET1);
+ if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
clk_pll1.rate = clk_xtali.rate;
- } else {
+ else
clk_pll1.rate = calc_pll_rate(value);
- }
+
+ /* Initialize the pll1 derived clocks */
clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7];
clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7];
clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3];
ep93xx_dma_clock_init();
+ /* Determine the bootloader configured pll2 rate */
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
- if (!(value & 0x00080000)) { /* PLL2 bypassed? */
+ if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
clk_pll2.rate = clk_xtali.rate;
- } else if (value & 0x00040000) { /* PLL2 enabled? */
+ else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
clk_pll2.rate = calc_pll_rate(value);
- } else {
+ else
clk_pll2.rate = 0;
- }
+
+ /* Initialize the pll2 derived clocks */
clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
- printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
+ pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
- printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
+ pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
clk_f.rate / 1000000, clk_h.rate / 1000000,
clk_p.rate / 1000000);
- for (i = 0; i < ARRAY_SIZE(clocks); i++)
- clkdev_add(&clocks[i]);
+ clkdev_add_table(clocks, ARRAY_SIZE(clocks));
return 0;
}
arch_initcall(ep93xx_clock_init);
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 1f0d66561bbe..41064bd63e38 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -14,6 +14,8 @@
* your option) any later version.
*/
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -318,8 +320,7 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
desc->handle_irq = handle_edge_irq;
break;
default:
- pr_err("ep93xx: failed to set irq type %d for gpio %d\n",
- type, gpio);
+ pr_err("failed to set irq type %d for gpio %d\n", type, gpio);
return -EINVAL;
}
@@ -572,9 +573,9 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
* CMOS driver.
*/
if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT)
- pr_warning("ep93xx: sda != EEDAT, open drain has no effect\n");
+ pr_warning("sda != EEDAT, open drain has no effect\n");
if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK)
- pr_warning("ep93xx: scl != EECLK, open drain has no effect\n");
+ pr_warning("scl != EECLK, open drain has no effect\n");
__raw_writel((data->sda_is_open_drain << 1) |
(data->scl_is_open_drain << 0),
diff --git a/arch/arm/mach-ep93xx/dma-m2p.c b/arch/arm/mach-ep93xx/dma-m2p.c
index dbcac9c40a28..8904ca4e2e24 100644
--- a/arch/arm/mach-ep93xx/dma-m2p.c
+++ b/arch/arm/mach-ep93xx/dma-m2p.c
@@ -28,6 +28,8 @@
* with this implementation.
*/
+#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -173,7 +175,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id)
switch (m2p_channel_state(ch)) {
case STATE_IDLE:
- pr_crit("m2p_irq: dma interrupt without a dma buffer\n");
+ pr_crit("dma interrupt without a dma buffer\n");
BUG();
break;
@@ -197,7 +199,7 @@ static irqreturn_t m2p_irq(int irq, void *dev_id)
break;
case STATE_NEXT:
- pr_crit("m2p_irq: dma interrupt while next\n");
+ pr_crit("dma interrupt while next\n");
BUG();
break;
}
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index a4a7be308000..d22d67ac8b99 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -118,12 +118,33 @@ static void __init edb93xx_register_i2c(void)
}
}
+
+/*************************************************************************
+ * EDB93xx pwm
+ *************************************************************************/
+static void __init edb93xx_register_pwm(void)
+{
+ if (machine_is_edb9301() ||
+ machine_is_edb9302() || machine_is_edb9302a()) {
+ /* EP9301 and EP9302 only have pwm.1 (EGPIO14) */
+ ep93xx_register_pwm(0, 1);
+ } else if (machine_is_edb9307() || machine_is_edb9307a()) {
+ /* EP9307 only has pwm.0 (PWMOUT) */
+ ep93xx_register_pwm(1, 0);
+ } else {
+ /* EP9312 and EP9315 have both */
+ ep93xx_register_pwm(1, 1);
+ }
+}
+
+
static void __init edb93xx_init_machine(void)
{
ep93xx_init_devices();
edb93xx_register_flash();
ep93xx_register_eth(&edb93xx_eth_data, 1);
edb93xx_register_i2c();
+ edb93xx_register_pwm();
}
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index d55194a4c093..cd359120c1f5 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -167,8 +167,11 @@
#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16)
#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08)
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
-#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20)
-#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLKSET1_NBYP1 (1<<23)
+#define EP93XX_SYSCON_CLKSET2 EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_CLKSET2_NBYP2 (1<<19)
+#define EP93XX_SYSCON_CLKSET2_PLL2_EN (1<<18)
#define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80)
#define EP93XX_SYSCON_DEVCFG_SWRST (1<<31)
#define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30)
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
index 3bd934e9a7f1..61c0e132c63e 100644
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
@@ -9,9 +9,6 @@
* febff000 22000000 4K model number register
* febfe000 22400000 4K options register
* febfd000 22800000 4K options register #2
- * febfc000 [67]0000000 4K NAND data register
- * febfb000 [67]0400000 4K NAND control register
- * febfa000 [67]0800000 4K NAND busy register
* febf9000 10800000 4K TS-5620 RTC index register
* febf8000 11700000 4K TS-5620 RTC data register
*/
@@ -41,22 +38,6 @@
#define TS72XX_OPTIONS2_TS9420_BOOT 0x02
-#define TS72XX_NAND1_DATA_PHYS_BASE 0x60000000
-#define TS72XX_NAND2_DATA_PHYS_BASE 0x70000000
-#define TS72XX_NAND_DATA_VIRT_BASE 0xfebfc000
-#define TS72XX_NAND_DATA_SIZE 0x00001000
-
-#define TS72XX_NAND1_CONTROL_PHYS_BASE 0x60400000
-#define TS72XX_NAND2_CONTROL_PHYS_BASE 0x70400000
-#define TS72XX_NAND_CONTROL_VIRT_BASE 0xfebfb000
-#define TS72XX_NAND_CONTROL_SIZE 0x00001000
-
-#define TS72XX_NAND1_BUSY_PHYS_BASE 0x60800000
-#define TS72XX_NAND2_BUSY_PHYS_BASE 0x70800000
-#define TS72XX_NAND_BUSY_VIRT_BASE 0xfebfa000
-#define TS72XX_NAND_BUSY_SIZE 0x00001000
-
-
#define TS72XX_RTC_INDEX_VIRT_BASE 0xfebf9000
#define TS72XX_RTC_INDEX_PHYS_BASE 0x10800000
#define TS72XX_RTC_INDEX_SIZE 0x00001000
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index 259f7822ba52..47a86f07831d 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -10,12 +10,16 @@
* your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/m48t86.h>
#include <linux/mtd/physmap.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
#include <mach/hardware.h>
#include <mach/ts72xx.h>
@@ -54,92 +58,162 @@ static struct map_desc ts72xx_io_desc[] __initdata = {
}
};
-static struct map_desc ts72xx_nand_io_desc[] __initdata = {
- {
- .virtual = TS72XX_NAND_DATA_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND1_DATA_PHYS_BASE),
- .length = TS72XX_NAND_DATA_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = TS72XX_NAND_CONTROL_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND1_CONTROL_PHYS_BASE),
- .length = TS72XX_NAND_CONTROL_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = TS72XX_NAND_BUSY_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND1_BUSY_PHYS_BASE),
- .length = TS72XX_NAND_BUSY_SIZE,
- .type = MT_DEVICE,
+static void __init ts72xx_map_io(void)
+{
+ ep93xx_map_io();
+ iotable_init(ts72xx_io_desc, ARRAY_SIZE(ts72xx_io_desc));
+}
+
+
+/*************************************************************************
+ * NAND flash
+ *************************************************************************/
+#define TS72XX_NAND_CONTROL_ADDR_LINE 22 /* 0xN0400000 */
+#define TS72XX_NAND_BUSY_ADDR_LINE 23 /* 0xN0800000 */
+
+static void ts72xx_nand_hwcontrol(struct mtd_info *mtd,
+ int cmd, unsigned int ctrl)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ void __iomem *addr = chip->IO_ADDR_R;
+ unsigned char bits;
+
+ addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE);
+
+ bits = __raw_readb(addr) & ~0x07;
+ bits |= (ctrl & NAND_NCE) << 2; /* bit 0 -> bit 2 */
+ bits |= (ctrl & NAND_CLE); /* bit 1 -> bit 1 */
+ bits |= (ctrl & NAND_ALE) >> 2; /* bit 2 -> bit 0 */
+
+ __raw_writeb(bits, addr);
}
-};
-static struct map_desc ts72xx_alternate_nand_io_desc[] __initdata = {
+ if (cmd != NAND_CMD_NONE)
+ __raw_writeb(cmd, chip->IO_ADDR_W);
+}
+
+static int ts72xx_nand_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ void __iomem *addr = chip->IO_ADDR_R;
+
+ addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
+
+ return !!(__raw_readb(addr) & 0x20);
+}
+
+static const char *ts72xx_nand_part_probes[] = { "cmdlinepart", NULL };
+
+#define TS72XX_BOOTROM_PART_SIZE (SZ_16K)
+#define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M)
+
+static struct mtd_partition ts72xx_nand_parts[] = {
{
- .virtual = TS72XX_NAND_DATA_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND2_DATA_PHYS_BASE),
- .length = TS72XX_NAND_DATA_SIZE,
- .type = MT_DEVICE,
+ .name = "TS-BOOTROM",
+ .offset = 0,
+ .size = TS72XX_BOOTROM_PART_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
- .virtual = TS72XX_NAND_CONTROL_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND2_CONTROL_PHYS_BASE),
- .length = TS72XX_NAND_CONTROL_SIZE,
- .type = MT_DEVICE,
+ .name = "Linux",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 0, /* filled in later */
}, {
- .virtual = TS72XX_NAND_BUSY_VIRT_BASE,
- .pfn = __phys_to_pfn(TS72XX_NAND2_BUSY_PHYS_BASE),
- .length = TS72XX_NAND_BUSY_SIZE,
- .type = MT_DEVICE,
- }
+ .name = "RedBoot",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
};
-static void __init ts72xx_map_io(void)
+static void ts72xx_nand_set_parts(uint64_t size,
+ struct platform_nand_chip *chip)
{
- ep93xx_map_io();
- iotable_init(ts72xx_io_desc, ARRAY_SIZE(ts72xx_io_desc));
+ /* Factory TS-72xx boards only come with 32MiB or 128MiB NAND options */
+ if (size == SZ_32M || size == SZ_128M) {
+ /* Set the "Linux" partition size */
+ ts72xx_nand_parts[1].size = size - TS72XX_REDBOOT_PART_SIZE;
- /*
- * The TS-7200 has NOR flash, the other models have NAND flash.
- */
- if (!board_is_ts7200()) {
- if (is_ts9420_installed()) {
- iotable_init(ts72xx_alternate_nand_io_desc,
- ARRAY_SIZE(ts72xx_alternate_nand_io_desc));
- } else {
- iotable_init(ts72xx_nand_io_desc,
- ARRAY_SIZE(ts72xx_nand_io_desc));
- }
+ chip->partitions = ts72xx_nand_parts;
+ chip->nr_partitions = ARRAY_SIZE(ts72xx_nand_parts);
+ } else {
+ pr_warning("Unknown nand disk size:%lluMiB\n", size >> 20);
}
}
+static struct platform_nand_data ts72xx_nand_data = {
+ .chip = {
+ .nr_chips = 1,
+ .chip_offset = 0,
+ .chip_delay = 15,
+ .part_probe_types = ts72xx_nand_part_probes,
+ .set_parts = ts72xx_nand_set_parts,
+ },
+ .ctrl = {
+ .cmd_ctrl = ts72xx_nand_hwcontrol,
+ .dev_ready = ts72xx_nand_device_ready,
+ },
+};
+
+static struct resource ts72xx_nand_resource[] = {
+ {
+ .start = 0, /* filled in later */
+ .end = 0, /* filled in later */
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ts72xx_nand_flash = {
+ .name = "gen_nand",
+ .id = -1,
+ .dev.platform_data = &ts72xx_nand_data,
+ .resource = ts72xx_nand_resource,
+ .num_resources = ARRAY_SIZE(ts72xx_nand_resource),
+};
+
+
/*************************************************************************
* NOR flash (TS-7200 only)
*************************************************************************/
-static struct physmap_flash_data ts72xx_flash_data = {
+static struct physmap_flash_data ts72xx_nor_data = {
.width = 2,
};
-static struct resource ts72xx_flash_resource = {
+static struct resource ts72xx_nor_resource = {
.start = EP93XX_CS6_PHYS_BASE,
.end = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
.flags = IORESOURCE_MEM,
};
-static struct platform_device ts72xx_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &ts72xx_flash_data,
- },
- .num_resources = 1,
- .resource = &ts72xx_flash_resource,
+static struct platform_device ts72xx_nor_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev.platform_data = &ts72xx_nor_data,
+ .resource = &ts72xx_nor_resource,
+ .num_resources = 1,
};
static void __init ts72xx_register_flash(void)
{
- if (board_is_ts7200())
- platform_device_register(&ts72xx_flash);
+ if (board_is_ts7200()) {
+ platform_device_register(&ts72xx_nor_flash);
+ } else {
+ resource_size_t start;
+
+ if (is_ts9420_installed())
+ start = EP93XX_CS7_PHYS_BASE;
+ else
+ start = EP93XX_CS6_PHYS_BASE;
+
+ ts72xx_nand_resource[0].start = start;
+ ts72xx_nand_resource[0].end = start + SZ_16M - 1;
+
+ platform_device_register(&ts72xx_nand_flash);
+ }
}
+
static unsigned char ts72xx_rtc_readbyte(unsigned long addr)
{
__raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index 41febc796b1c..e3bc3f6f6b10 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -32,12 +32,13 @@ unsigned int mem_fclk_21285 = 50000000;
EXPORT_SYMBOL(mem_fclk_21285);
-static void __init early_fclk(char **arg)
+static int __init early_fclk(char *arg)
{
- mem_fclk_21285 = simple_strtoul(*arg, arg, 0);
+ mem_fclk_21285 = simple_strtoul(arg, NULL, 0);
+ return 0;
}
-__early_param("mem_fclk_21285=", early_fclk);
+early_param("mem_fclk_21285", early_fclk);
static int __init parse_tag_memclk(const struct tag *tag)
{
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index a0f60e55da6a..8b390e36ba69 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -144,8 +144,7 @@ static int __init integrator_init(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 3f35293d457a..66ef86d6d9e3 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -558,9 +558,7 @@ static void __init intcp_init(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(cp_lookups); i++)
- clkdev_add(&cp_lookups[i]);
-
+ clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups));
platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 529580997814..48642e66c566 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
(cookie - IOP13XX_PCIE_LOWER_MEM_RA));
break;
case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
- retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA +
+ retval = __arm_ioremap_caller(IOP13XX_PBI_LOWER_MEM_PA +
(cookie - IOP13XX_PBI_LOWER_MEM_RA),
- size, mtype);
+ size, mtype, __builtin_return_address(0));
break;
case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
@@ -75,7 +75,8 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
break;
default:
- retval = __arm_ioremap(cookie, size, mtype);
+ retval = __arm_ioremap_caller(cookie, size, mtype,
+ __builtin_return_address(0));
}
return retval;
diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c
index fcaf876f19b6..0651f96653f9 100644
--- a/arch/arm/mach-lh7a40x/clocks.c
+++ b/arch/arm/mach-lh7a40x/clocks.c
@@ -10,6 +10,8 @@
#include <mach/hardware.h>
#include <mach/clocks.h>
#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/string.h>
struct module;
diff --git a/arch/arm/mach-mmp/clock.c b/arch/arm/mach-mmp/clock.c
index 2a46ed5cc2a2..886e05648f08 100644
--- a/arch/arm/mach-mmp/clock.c
+++ b/arch/arm/mach-mmp/clock.c
@@ -88,11 +88,3 @@ unsigned long clk_get_rate(struct clk *clk)
return rate;
}
EXPORT_SYMBOL(clk_get_rate);
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
- int i;
-
- for (i = 0; i < num; i++)
- clkdev_add(&clks[i]);
-}
diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h
index eefffbe683b0..016ae94691c0 100644
--- a/arch/arm/mach-mmp/clock.h
+++ b/arch/arm/mach-mmp/clock.h
@@ -68,5 +68,3 @@ struct clk clk_##_name = { \
extern struct clk clk_pxa168_gpio;
extern struct clk clk_pxa168_timers;
-
-extern void clks_register(struct clk_lookup *, size_t);
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 37dbdde17fac..1873c821df90 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -94,7 +94,7 @@ static int __init pxa168_init(void)
mfp_init_base(MFPR_VIRT_BASE);
mfp_init_addr(pxa168_mfp_addr_map);
pxa_init_dma(IRQ_PXA168_DMA_INT0, 32);
- clks_register(ARRAY_AND_SIZE(pxa168_clkregs));
+ clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
}
return 0;
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index d4049508a4df..46f2d69bef3c 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -131,7 +131,7 @@ static int __init pxa910_init(void)
mfp_init_base(MFPR_VIRT_BASE);
mfp_init_addr(pxa910_mfp_addr_map);
pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
- clks_register(ARRAY_AND_SIZE(pxa910_clkregs));
+ clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
}
return 0;
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 8f49b2b12608..b22dec4abf78 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -24,8 +24,6 @@
#include "common.h"
-#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
-
static unsigned long ttc_dkb_pin_config[] __initdata = {
/* UART2 */
GPIO47_UART2_RXD,
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f780086befd7..57012e82e3cd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1,7 +1,189 @@
if ARCH_MSM
-comment "MSM Board Type"
- depends on ARCH_MSM
+choice
+ prompt "MSM SoC Type"
+ default ARCH_MSM7X00A
+
+config ARCH_MSM7X01A
+ bool "MSM7x00A / MSM7x01A"
+ select ARCH_MSM_ARM11
+ select CPU_V6
+
+config ARCH_MSM7X27
+ bool "MSM7x27"
+ select ARCH_MSM_ARM11
+ select CPU_V6
+
+config ARCH_MSM7X30
+ bool "MSM7x30"
+ select ARCH_MSM_SCORPION
+ select CPU_V7
+
+config ARCH_QSD8X50
+ bool "QSD8X50"
+ select ARCH_MSM_SCORPION
+ select VERIFY_PERMISSION_FAULT
+ select CPU_V7
+
+endchoice
+
+config ARCH_MSM_ARM11
+ bool
+config ARCH_MSM_SCORPION
+ bool
+
+
+menu "MSM Board Selection"
+
+config MACH_HALIBUT
+ select CPU_V6
+ depends on ARCH_MSM7X01A
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "Halibut Board (QCT SURF7201A)"
+ help
+ Support for the Qualcomm SURF7201A eval board.
+
+config MACH_MSM7201A_SURF
+ depends on ARCH_MSM7X01A
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "MSM7201A SURF"
+ help
+ Support for the Qualcomm MSM7201A SURF eval board.
+
+config MACH_MSM7201A_FFA
+ depends on ARCH_MSM7X01A
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "MSM7201A FFA"
+ help
+ Support for the Qualcomm MSM7201A FFA eval board.
+
+config MACH_TROUT
+ select CPU_V6
+ depends on ARCH_MSM7X01A
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "HTC Dream (aka trout)"
+ help
+ Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
+
+config MACH_MSM7X27_SURF
+ depends on ARCH_MSM7X27
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM7x27 SURF"
+ help
+ Support for the Qualcomm MSM7x27 SURF eval board.
+
+config MACH_MSM7X27_FFA
+ depends on ARCH_MSM7X27
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM7x27 FFA"
+ help
+ Support for the Qualcomm MSM7x27 FFA eval board.
+
+config MACH_MSM7X30_SURF
+ depends on ARCH_MSM7X30
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM7x30 SURF"
+ help
+ Support for the Qualcomm MSM7x30 SURF eval board.
+
+config MACH_MSM7X30_FFA
+ depends on ARCH_MSM7X30
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM7x30 FFA"
+ help
+ Support for the Qualcomm MSM7x30 FFA eval board.
+
+config MACH_MSM7X30_FLUID
+ depends on ARCH_MSM7X30
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM7x30 FLUID"
+ help
+ Support for the Qualcomm MSM7x30 FLUID eval board.
+
+config MACH_SAPPHIRE
+ depends on ARCH_MSM7X01A
+ default n
+ bool "Sapphire"
+
+config MACH_QSD8X50_SURF
+ depends on ARCH_QSD8X50
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "QSD8x50 SURF"
+ help
+ Support for the Qualcomm QSD8x50 SURF eval board.
+
+config MACH_QSD8X50_FFA
+ depends on ARCH_QSD8X50
+ depends on MSM_STACKED_MEMORY
+ default y
+ bool "QSD8x50 FFA"
+ help
+ Support for the Qualcomm QSD8x50 FFA eval board.
+
+config MACH_QSD8X50_COMET
+ depends on ARCH_QSD8X50
+ depends on MSM_STACKED_MEMORY
+ default n
+ bool "QSD8x50 Comet"
+ help
+ Support for the Qualcomm Comet eval board.
+
+config MACH_QSD8X50_GRAPEFRUIT
+ depends on ARCH_QSD8X50
+ depends on MSM_STACKED_MEMORY
+ default n
+ bool "QSD8x50 Grapefruit"
+ help
+ Support for the Qualcomm Grapefruit eval board.
+
+config MACH_QSD8X50_ST1
+ depends on ARCH_QSD8X50
+ depends on MSM_STACKED_MEMORY
+ default n
+ bool "QSD8x50 ST1"
+ help
+ Support for the Qualcomm ST1.
+
+endmenu
+
+config MSM_STACKED_MEMORY
+ bool "Stacked Memory"
+ default y
+ help
+ This option is used to indicate the presence of on-die stacked
+ memory. When present this memory bank is used for a high speed
+ shared memory interface. When not present regular RAM is used.
+
+config MSM_AMSS_VERSION
+ int
+ default 6210 if MSM_AMSS_VERSION_6210
+ default 6220 if MSM_AMSS_VERSION_6220
+ default 6225 if MSM_AMSS_VERSION_6225
+
+choice
+ prompt "AMSS modem firmware version"
+
+ default MSM_AMSS_VERSION_6225
+
+ config MSM_AMSS_VERSION_6210
+ bool "6.2.10"
+
+ config MSM_AMSS_VERSION_6220
+ bool "6.2.20"
+
+ config MSM_AMSS_VERSION_6225
+ bool "6.2.20 + New ADSP"
+endchoice
config MSM_DEBUG_UART
int
@@ -27,17 +209,488 @@ choice
bool "UART3"
endchoice
-config MACH_HALIBUT
- depends on ARCH_MSM
+choice
+ prompt "Default Timer"
+ default MSM7X00A_USE_GP_TIMER
+
+ config MSM7X00A_USE_GP_TIMER
+ bool "GP Timer"
+ help
+ Low resolution timer that allows power collapse from idle.
+
+ config MSM7X00A_USE_DG_TIMER
+ bool "DG Timer"
+ help
+ High resolution timer.
+endchoice
+
+choice
+ prompt "Suspend sleep mode"
+ default MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+ help
+ Allows overriding the sleep mode used. Leave at power
+ collapse suspend unless the arm9 image has problems.
+
+ config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+ bool "Power collapse suspend"
+ help
+ Lowest sleep state. Returns through reset vector.
+
+ config MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+ bool "Power collapse"
+ help
+ Sleep state that returns through reset vector.
+
+ config MSM7X00A_SLEEP_MODE_APPS_SLEEP
+ bool "Apps Sleep"
+
+ config MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+ bool "Ramp down cpu clock and wait for interrupt"
+
+ config MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+ bool "Wait for interrupt"
+endchoice
+
+config MSM7X00A_SLEEP_MODE
+ int
+ default 0 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+ default 1 if MSM7X00A_SLEEP_MODE_POWER_COLLAPSE
+ default 2 if MSM7X00A_SLEEP_MODE_APPS_SLEEP
+ default 3 if MSM7X00A_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+ default 4 if MSM7X00A_SLEEP_WAIT_FOR_INTERRUPT
+
+choice
+ prompt "Idle sleep mode"
+ default MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+ help
+ Allows overriding the sleep mode used from idle. Leave at power
+ collapse suspend unless the arm9 image has problems.
+
+ config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+ bool "Power collapse suspend"
+ help
+ Lowest sleep state. Returns through reset vector.
+
+ config MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+ bool "Power collapse"
+ help
+ Sleep state that returns through reset vector.
+
+ config MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+ bool "Apps Sleep"
+
+ config MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+ bool "Ramp down cpu clock and wait for interrupt"
+
+ config MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+ bool "Wait for interrupt"
+endchoice
+
+config MSM7X00A_IDLE_SLEEP_MODE
+ int
+ default 0 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE_SUSPEND
+ default 1 if MSM7X00A_IDLE_SLEEP_MODE_POWER_COLLAPSE
+ default 2 if MSM7X00A_IDLE_SLEEP_MODE_APPS_SLEEP
+ default 3 if MSM7X00A_IDLE_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT
+ default 4 if MSM7X00A_IDLE_SLEEP_WAIT_FOR_INTERRUPT
+
+config MSM7X00A_IDLE_SLEEP_MIN_TIME
+ int "Minimum idle time before sleep"
+ default 20000000
+ help
+ Minimum idle time in nanoseconds before entering low power mode.
+
+config MSM7X00A_IDLE_SPIN_TIME
+ int "Idle spin time before cpu ramp down"
+ default 80000
+ help
+ Spin time in nanoseconds before ramping down cpu clock and entering
+ any low power state.
+
+menuconfig MSM_IDLE_STATS
+ bool "Collect idle statistics"
default y
- bool "Halibut Board (QCT SURF7201A)"
help
- Support for the Qualcomm SURF7201A eval board.
+ Collect idle statistics and export them in proc/msm_pm_stats.
-config MACH_TROUT
+if MSM_IDLE_STATS
+
+config MSM_IDLE_STATS_FIRST_BUCKET
+ int "First bucket time"
+ default 62500
+ help
+ Upper time limit in nanoseconds of first bucket.
+
+config MSM_IDLE_STATS_BUCKET_SHIFT
+ int "Bucket shift"
+ default 2
+
+config MSM_IDLE_STATS_BUCKET_COUNT
+ int "Bucket count"
+ default 10
+
+config MSM_SUSPEND_STATS_FIRST_BUCKET
+ int "First bucket time for suspend"
+ default 1000000000
+ help
+ Upper time limit in nanoseconds of first bucket of the
+ histogram. This is for collecting statistics on suspend.
+
+endif # MSM_IDLE_STATS
+
+config MSM_JTAG_V7
+ depends on CPU_V7
+ default y if DEBUG_KERNEL
+ bool "JTAG debug support"
+ help
+ Add additional support for JTAG kernel debugging.
+
+config HTC_HEADSET
+ tristate "HTC 2 Wire detection driver"
+ default n
+ help
+ Provides support for detecting HTC 2 wire devices, such as wired
+ headset, on the trout platform. Can be used with the msm serial
+ debugger, but not with serial console.
+
+config TROUT_BATTCHG
+ depends on MACH_TROUT && POWER_SUPPLY
default y
- bool "HTC Dream (aka trout)"
+ bool "Trout battery / charger driver"
+
+config HTC_PWRSINK
+ depends on MSM_SMD
+ default n
+ bool "HTC Power Sink Driver"
+
+config QSD_SVS
+ bool "QSD Static Voltage Scaling"
+ depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET)
+ default y
+ select TPS65023
help
- Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
+ Enables static voltage scaling using the TPS65023 PMIC.
+
+config QSD_PMIC_DEFAULT_DCDC1
+ int "PMIC default output voltage"
+ depends on (MACH_QSD8X50_SURF || MACH_QSD8X50_FFA || MACH_QSD8X50_COMET)
+ default 1250
+ help
+ This is the PMIC voltage at Linux kernel boot.
+
+config MSM_FIQ_SUPPORT
+ default y
+ bool "Enable installation of an FIQ handler."
+
+config MSM_SMD
+ default y
+ bool "MSM Shared Memory Driver (SMD)"
+ help
+ Support for the shared memory interface between the apps
+ processor and the baseband processor. Provides access to
+ the "shared heap", as well as virtual serial channels
+ used to communicate with various services on the baseband
+ processor.
+
+choice
+ prompt "MSM Shared memory interface version"
+ depends on MSM_SMD
+ default MSM_SMD_PKG3 if ARCH_MSM_ARM11
+ default MSM_SMD_PKG4 if ARCH_MSM_SCORPION
+
+ config MSM_SMD_PKG3
+ bool "Package 3"
+
+ config MSM_SMD_PKG4
+ bool "Package 4"
+endchoice
+
+config MSM_SMD_DEBUG
+ depends on MSM_SMD
+ default y
+ bool "MSM SMD debug support"
+ help
+ Support for debugging the SMD for communication
+ between the ARM9 and ARM11
+
+config MSM_N_WAY_SMD
+ depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM7X27))
+ default y
+ bool "MSM N-WAY SMD support"
+ help
+ Supports APPS-QDSP SMD communication along with
+ normal APPS-MODEM SMD communication.
+
+config MSM_N_WAY_SMSM
+ depends on (MSM_SMD && (ARCH_MSM_SCORPION || ARCH_MSM7X27))
+ default y
+ bool "MSM N-WAY SMSM support"
+ help
+ Supports APPS-QDSP SMSM communication along with
+ normal APPS-MODEM SMSM communication.
+
+config MSM_RESET_MODEM
+ tristate "Reset Modem Driver"
+ depends on MSM_SMD
+ default m
+ help
+ Allows the user to reset the modem through a device node.
+
+config MSM_SMD_LOGGING
+ depends on MSM_SMD
+ default y
+ bool "MSM Shared Memory Logger"
+ help
+ This option exposes the shared memory logger at /dev/smem_log
+ and a debugfs node named smem_log.
+
+ If in doubt, say yes.
+
+config MSM_SMD_NMEA
+ bool "NMEA GPS Driver"
+ depends on MSM_SMD
+ default y
+ help
+ Enable this to support the NMEA GPS device.
+
+ If in doubt, say yes.
+
+config MSM_SMD_TTY
+ bool "SMD TTY Driver"
+ depends on MSM_SMD
+ default y
+ help
+ Provides TTY interfaces to interact with the modem.
+
+ If in doubt, say yes.
+
+config MSM_SMD_QMI
+ bool "SMD QMI Driver"
+ depends on MSM_SMD
+ default y
+ help
+ Manages network data connections.
+
+ If in doubt, say yes.
+
+config MSM_SMD_CTL
+ bool "SMD Control Driver"
+ depends on MSM_SMD
+ default y
+ help
+ Provides a binary SMD non-muxed control port interface.
+
+ If in doubt, say yes.
+
+config MSM_ONCRPCROUTER
+ depends on MSM_SMD
+ default y
+ bool "MSM ONCRPC router support"
+ help
+ Support for the MSM ONCRPC router for communication between
+ the ARM9 and ARM11
+
+config MSM_ONCRPCROUTER_DEBUG
+ depends on MSM_ONCRPCROUTER
+ default y
+ bool "MSM debug ONCRPC router support"
+ help
+ Support for debugging the ONCRPC router for communication
+ between the ARM9 and ARM11
+
+config MSM_RPCSERVERS
+ depends on MSM_ONCRPCROUTER
+ select RTC_HCTOSYS
+ default y
+ bool "Kernel side RPC server bundle"
+ help
+ none
+
+config MSM_RPC_PING
+ depends on MSM_ONCRPCROUTER && DEBUG_FS
+ default m
+ bool "MSM rpc ping"
+ help
+ Implements MSM rpc ping test module.
+
+config MSM_RPC_PROC_COMM_TEST
+ depends on DEBUG_FS
+ default m
+ bool "MSM rpc proc comm test"
+ help
+ Implements MSM rpc proc comm test module.
+
+config MSM_RPC_OEM_RAPI
+ depends on MSM_ONCRPCROUTER
+ default m
+ bool "MSM oem rapi"
+ help
+ Implements MSM oem rapi client module.
+
+config MSM_RPCSERVER_HANDSET
+ depends on MSM_ONCRPCROUTER
+ default y
+ bool "Handset events RPC server"
+ help
+ Support for receiving handset events like headset detect,
+ headset switch and clamshell state.
+
+config MSM_DALRPC
+ bool "DAL RPC support"
+ depends on ARCH_MSM_SCORPION
+ default y
+ help
+ Supports RPC calls to DAL devices on remote processor cores.
+
+config MSM_DALRPC_TEST
+ tristate "DAL RPC test module"
+ depends on (MSM_DALRPC && DEBUG_FS)
+ default m
+ help
+ Exercises DAL RPC calls to QDSP6.
+
+config MSM_CPU_FREQ_SCREEN
+ depends on (HAS_EARLYSUSPEND && !CPU_FREQ_MSM)
+ default n
+ bool "Enable simple cpu frequency scaling"
+ help
+ Simple cpufreq scaling based on screen ON/OFF.
+
+if MSM_CPU_FREQ_SCREEN
+
+config MSM_CPU_FREQ_SCREEN_OFF
+ int "Screen off cpu frequency"
+ default 245760
+
+config MSM_CPU_FREQ_SCREEN_ON
+ int "Screen on cpu frequency"
+ default 384000
+
+endif # MSM_CPU_FREQ_SCREEN
+
+if CPU_FREQ_MSM
+
+config MSM_CPU_FREQ_SET_MIN_MAX
+ bool "Set Min/Max CPU frequencies."
+ default n
+ help
+ Allow setting min and max CPU frequencies. Sysfs can be used
+ to override these values.
+
+config MSM_CPU_FREQ_MAX
+ int "Max CPU Frequency"
+ depends on MSM_CPU_FREQ_SET_MIN_MAX
+ default 384000
+
+config MSM_CPU_FREQ_MIN
+ int "Min CPU Frequency"
+ depends on MSM_CPU_FREQ_SET_MIN_MAX
+ default 245760
+
+endif # CPU_FREQ_MSM
+
+config MSM_CPU_AVS
+ bool "Enable Adaptive Voltage Scaling (AVS)"
+ depends on (ARCH_MSM_SCORPION && QSD_SVS)
+ depends on ARCH_QSD8X50
+ default y
+ help
+ This enables the Adaptive Voltage Scaling feature of
+ Qualcomm ARMv7 CPUs. It adjusts the voltage for each frequency
+ based on feedback from three ring oscillators in the CPU.
+
+config MSM_VREG_SWITCH_INVERTED
+ bool "Reverse vreg switch polarity"
+ default n
+ help
+ Reverses the enable and disable for vreg switch.
+
+config MSM_DMA_TEST
+ tristate "MSM DMA test module"
+ default m
+ help
+ Intended to be compiled as a module. Provides a device node
+ and ioctls for testing the MSM dma system.
+
+config WIFI_CONTROL_FUNC
+ bool "Enable WiFi control function abstraction"
+ help
+ Enables Power/Reset/Carddetect function abstraction
+
+config WIFI_MEM_PREALLOC
+ depends on WIFI_CONTROL_FUNC
+ bool "Preallocate memory for WiFi buffers"
+ help
+ Preallocates memory buffers for WiFi driver
+
+config QSD_AUDIO
+ bool "QSD audio"
+ depends on (ARCH_MSM_SCORPION && MSM_DALRPC)
+ default y
+ help
+ Provides PCM, MP3, and AAC audio playback.
+
+config AUDIO_AAC_PLUS
+ depends on (MSM_ADSP || QSD_AUDIO)
+ bool "AAC+ Audio"
+ default y
+ help
+ Provides AAC+ decoding
+
+config AUDIO_ENHANCED_AAC_PLUS
+ depends on AUDIO_AAC_PLUS
+ bool "Enhanced AAC+ Audio"
+ default y
+ help
+ Provides Enhanced AAC+ decoding
+
+config SURF_FFA_GPIO_KEYPAD
+ bool "MSM SURF/FFA GPIO keypad"
+ depends on INPUT_GPIO = "y"
+ default y
+ help
+ Select if the GPIO keypad is attached.
+
+config CLOCK_BASED_SLEEP_LIMIT
+ default y
+ bool "Set sleep limitation based on clock usage"
+ help
+ The application processor checks for enabled clocks and
+ decides accordingly the sleep limitation which it informs
+ the modem to use.
+
+config MSM_ADM_OFF_AT_POWER_COLLAPSE
+ bool "Turn off ADM clock during power collapse"
+ default n
+ help
+ The application processor turns off the ADM clock before
+ entering power collapse and turns it back on after exiting
+ power collapse.
+
+config MSM_SLEEP_TIME_OVERRIDE
+ bool "Allow overriding suspend/sleep time with PM module parameter"
+ default y
+ help
+ Enable the module parameter sleep_time_override. Specified
+ in units of seconds, it overwrites the normal sleep time of
+ suspend. The feature is required for automated power management
+ testing.
+
+choice
+ prompt "Power management timeout action"
+ default MSM_PM_TIMEOUT_HALT
+ help
+ Selects the Application Processor's action when Power Management
+ times out waiting for Modem's handshake.
+
+ config MSM_PM_TIMEOUT_HALT
+ bool "Halt the Application Processor"
+
+ config MSM_PM_TIMEOUT_RESET_MODEM
+ bool "Reset the Modem Processor"
+
+ config MSM_PM_TIMEOUT_RESET_CHIP
+ bool "Reset the entire chip"
+endchoice
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 91e6f5c95dc1..6d7937fa50ce 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -1,9 +1,78 @@
-obj-y += io.o idle.o irq.o timer.o dma.o
+obj-y += io.o irq.o timer.o dma.o
obj-y += devices.o
obj-y += proc_comm.o
+obj-y += vreg.o mpp.o
obj-y += vreg.o
-obj-y += clock.o clock-7x01a.o
+obj-y += clock.o clock-pcom.o
+obj-y += gpio.o generic_gpio.o
+obj-y += nand_partitions.o
+obj-y += remote_spinlock.o modem_notifier.o
+obj-y += rpc_hsusb.o
+obj-y += socinfo.o
+obj-y += cpufreq.o
+obj-y += nohlt.o
+obj-y += pmic.o
+obj-y += internal_power_rail.o
-obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
+obj-$(CONFIG_ARCH_MSM_ARM11) += acpuclock.o
+obj-$(CONFIG_ARCH_MSM_SCORPION) += acpuclock-8x50.o
+obj-$(CONFIG_MSM_CPU_AVS) += avs.o avs_hw.o
+obj-$(CONFIG_CPU_V6) += idle-v6.o
+obj-$(CONFIG_CPU_V7) += idle-v7.o
+obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o
+
+obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
+obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-rfkill.o
+obj-$(CONFIG_MSM_SMD) += smd.o
+obj-$(CONFIG_MSM_SMD_LOGGING) += smem_log.o
+obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
+obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
+obj-$(CONFIG_MSM_SMD_CTL) += smd_ctl2.o
+obj-$(CONFIG_MSM_SMD_NMEA) += smd_nmea.o
+obj-$(CONFIG_DEBUG_FS) += pmic_debugfs.o
+obj-$(CONFIG_MSM_RESET_MODEM) += reset_modem.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
+obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_clients.o
+obj-$(CONFIG_MSM_RPC_PING) += ping_mdm_rpc_client.o
+obj-$(CONFIG_MSM_RPC_PROC_COMM_TEST) += proc_comm_test.o
+obj-$(CONFIG_MSM_RPC_OEM_RAPI) += oem_rapi_client.o
+obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o
+obj-$(CONFIG_MSM_DALRPC) += dal.o
+obj-$(CONFIG_MSM_DALRPC_TEST) += dal_remotetest.o
+obj-$(CONFIG_MSM_RPCSERVER_HANDSET) += rpc_server_handset.o
+ifdef CONFIG_MSM_N_WAY_SMSM
+ obj-$(CONFIG_PM) += pm2.o
+else
+ obj-$(CONFIG_PM) += pm.o
+endif
+obj-$(CONFIG_MSM_DMA_TEST) += dma_test.o
+obj-$(CONFIG_SURF_FFA_GPIO_KEYPAD) += keypad-surf-ffa.o
obj-$(CONFIG_MACH_TROUT) += board-dream.o
+obj-$(CONFIG_ARCH_MSM7X01A) += board-halibut.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-keypad.o board-trout-panel.o
+obj-$(CONFIG_MACH_TROUT) += htc_akm_cal.o htc_wifi_nvs.o htc_acoustic.o
+obj-$(CONFIG_MACH_TROUT) += board-trout-mmc.o board-trout-wifi.o
+obj-$(CONFIG_MACH_QSD8X50_SURF) += board-qsd8x50.o
+obj-$(CONFIG_MACH_QSD8X50_FFA) += board-qsd8x50.o
+obj-$(CONFIG_MACH_QSD8X50_COMET) += board-comet.o
+obj-$(CONFIG_TROUT_H2W) += board-trout-h2w.o
+obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o
+obj-$(CONFIG_TROUT_PWRSINK) += htc_pwrsink.o
+obj-$(CONFIG_ARCH_MSM7X27) += board-msm7x27.o
+obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o clock-7x30.o
+
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
+obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o
+
+obj-$(CONFIG_TROUT_BATTCHG) += htc_battery.o
+
+obj-$(CONFIG_HTC_PWRSINK) += htc_pwrsink.o
+obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
+obj-$(CONFIG_PMIC8058) += pmic8058-gpio.o pmic8058-mpp.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 24dfbf8c07c4..9acaeef05ea9 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -1,3 +1,21 @@
+ifeq ($(CONFIG_ARCH_MSM_SCORPION),y)
+ifeq ($(CONFIG_MSM_STACKED_MEMORY), y)
+ zreladdr-y := 0x20008000
+params_phys-y := 0x20000100
+initrd_phys-y := 0x24000000
+else # !CONFIG_MSM_STACKED_MEMORY
+ zreladdr-y := 0x00208000
+params_phys-y := 0x00200100
+initrd_phys-y := 0x01200000
+endif # CONFIG_MSM_STACKED_MEMORY
+else # !CONFIG_ARCH_MSM_SCORPION
+ifeq ($(CONFIG_MSM_STACKED_MEMORY), y)
zreladdr-y := 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
+else # !CONFIG_MSM_STACKED_MEMORY
+ zreladdr-y := 0x00208000
+params_phys-y := 0x00200100
+initrd_phys-y := 0x0A000000
+endif # CONFIG_MSM_STACKED_MEMORY
+endif # CONFIG_ARCH_MSM_SCORPION
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
new file mode 100644
index 000000000000..dde6900b0f0a
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -0,0 +1,723 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/cpufreq.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+#include "acpuclock.h"
+#include "avs.h"
+#include "clock.h"
+
+#define SHOT_SWITCH 4
+#define HOP_SWITCH 5
+#define SIMPLE_SLEW 6
+#define COMPLEX_SLEW 7
+
+#define SPSS_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
+#define SPSS_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
+
+/* Scorpion PLL registers */
+#define SCPLL_CTL_ADDR (MSM_SCPLL_BASE + 0x4)
+#define SCPLL_STATUS_ADDR (MSM_SCPLL_BASE + 0x18)
+#define SCPLL_FSM_CTL_EXT_ADDR (MSM_SCPLL_BASE + 0x10)
+
+enum {
+ ACPU_PLL_TCXO = -1,
+ ACPU_PLL_0 = 0,
+ ACPU_PLL_1,
+ ACPU_PLL_2,
+ ACPU_PLL_3,
+ ACPU_PLL_END,
+};
+
+struct clkctl_acpu_speed {
+ unsigned int use_for_scaling;
+ unsigned int acpuclk_khz;
+ int pll;
+ unsigned int acpuclk_src_sel;
+ unsigned int acpuclk_src_div;
+ unsigned int ahbclk_khz;
+ unsigned int ahbclk_div;
+ unsigned int axiclk_khz;
+ unsigned int sc_core_src_sel_mask;
+ unsigned int sc_l_value;
+ int vdd;
+ unsigned long lpj; /* loops_per_jiffy */
+};
+
+struct clkctl_acpu_speed acpu_freq_tbl[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 0, 0, 14000, 0, 0, 1000},
+ { 0, 128000, ACPU_PLL_1, 1, 5, 0, 0, 14000, 2, 0, 1000},
+ { 1, 245760, ACPU_PLL_0, 4, 0, 0, 0, 29000, 0, 0, 1000},
+ { 1, 384000, ACPU_PLL_3, 0, 0, 0, 0, 58000, 1, 0xA, 1000},
+ { 0, 422400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xB, 1000},
+ { 0, 460800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xC, 1000},
+ { 0, 499200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xD, 1025},
+ { 0, 537600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xE, 1050},
+ { 1, 576000, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0xF, 1050},
+ { 0, 614400, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x10, 1075},
+ { 0, 652800, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x11, 1100},
+ { 0, 691200, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x12, 1125},
+ { 0, 729600, ACPU_PLL_3, 0, 0, 0, 0, 117000, 1, 0x13, 1150},
+ { 1, 768000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x14, 1150},
+ { 0, 806400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x15, 1175},
+ { 0, 844800, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x16, 1200},
+ { 0, 883200, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x17, 1225},
+ { 0, 921600, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x18, 1250},
+ { 0, 960000, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x19, 1250},
+ { 1, 998400, ACPU_PLL_3, 0, 0, 0, 0, 128000, 1, 0x1A, 1250},
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[20];
+
+static void __init cpufreq_table_init(void)
+{
+ unsigned int i;
+ unsigned int freq_cnt = 0;
+
+ /* Construct the freq_table table from acpu_freq_tbl since the
+ * freq_table values need to match frequencies specified in
+ * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init.
+ */
+ for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0
+ && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) {
+ if (acpu_freq_tbl[i].use_for_scaling) {
+ freq_table[freq_cnt].index = freq_cnt;
+ freq_table[freq_cnt].frequency
+ = acpu_freq_tbl[i].acpuclk_khz;
+ freq_cnt++;
+ }
+ }
+
+ /* freq_table not big enough to store all usable freqs. */
+ BUG_ON(acpu_freq_tbl[i].acpuclk_khz != 0);
+
+ freq_table[freq_cnt].index = freq_cnt;
+ freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+ pr_info("%d scaling frequencies supported.\n", freq_cnt);
+}
+#endif
+
+struct clock_state {
+ struct clkctl_acpu_speed *current_speed;
+ struct mutex lock;
+ uint32_t acpu_switch_time_us;
+ uint32_t max_speed_delta_khz;
+ uint32_t vdd_switch_time_us;
+ unsigned long power_collapse_khz;
+ unsigned long wait_for_irq_khz;
+ unsigned int max_vdd;
+ int (*acpu_set_vdd) (int mvolts);
+};
+
+static struct clock_state drv_state = { 0 };
+
+unsigned long clk_get_max_axi_khz(void)
+{
+ return 128000;
+}
+EXPORT_SYMBOL(clk_get_max_axi_khz);
+
+static void scpll_set_freq(uint32_t lval, unsigned freq_switch)
+{
+ uint32_t regval;
+
+ if (lval > 33)
+ lval = 33;
+ if (lval < 10)
+ lval = 10;
+
+ /* wait for any calibrations or frequency switches to finish */
+ while (readl(SCPLL_STATUS_ADDR) & 0x3)
+ ;
+
+ /* write the new L val and switch mode */
+ regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+ regval &= ~(0x3f << 3);
+ regval |= (lval << 3);
+ if (freq_switch == SIMPLE_SLEW)
+ regval |= (0x1 << 9);
+
+ regval &= ~(0x3 << 0);
+ regval |= (freq_switch << 0);
+ writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+ dmb();
+
+ /* put in normal mode */
+ regval = readl(SCPLL_CTL_ADDR);
+ regval |= 0x7;
+ writel(regval, SCPLL_CTL_ADDR);
+
+ dmb();
+
+ /* wait for frequency switch to finish */
+ while (readl(SCPLL_STATUS_ADDR) & 0x1)
+ ;
+
+ /* status bit seems to clear early, using
+ * 100us to handle the worst case. */
+ udelay(100);
+}
+
+static void scpll_apps_enable(bool state)
+{
+ uint32_t regval;
+
+ /* Wait for any frequency switches to finish. */
+ while (readl(SCPLL_STATUS_ADDR) & 0x1)
+ ;
+
+ /* put the pll in standby mode */
+ regval = readl(SCPLL_CTL_ADDR);
+ regval &= ~(0x7);
+ regval |= (0x2);
+ writel(regval, SCPLL_CTL_ADDR);
+
+ dmb();
+
+ if (state) {
+ /* put the pll in normal mode */
+ regval = readl(SCPLL_CTL_ADDR);
+ regval |= (0x7);
+ writel(regval, SCPLL_CTL_ADDR);
+ udelay(200);
+ } else {
+ /* put the pll in power down mode */
+ regval = readl(SCPLL_CTL_ADDR);
+ regval &= ~(0x7);
+ writel(regval, SCPLL_CTL_ADDR);
+ }
+ udelay(drv_state.vdd_switch_time_us);
+}
+
+static void scpll_init(void)
+{
+ uint32_t regval;
+#define L_VAL_384MHZ 0xA
+#define L_VAL_768MHZ 0x14
+
+ /* power down scpll */
+ writel(0x0, SCPLL_CTL_ADDR);
+
+ dmb();
+
+ /* set bypassnl, put into standby */
+ writel(0x00400002, SCPLL_CTL_ADDR);
+
+ /* set bypassnl, reset_n, full calibration */
+ writel(0x00600004, SCPLL_CTL_ADDR);
+
+ /* Ensure register write to initiate calibration has taken
+ effect before reading status flag */
+ dmb();
+
+ /* wait for cal_all_done */
+ while (readl(SCPLL_STATUS_ADDR) & 0x2)
+ ;
+
+ /* Start: Set of experimentally derived steps
+ * to work around a h/w bug. */
+
+ /* Put the pll in normal mode */
+ scpll_apps_enable(1);
+
+ /* SHOT switch to 384 MHz */
+ regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+ regval &= ~(0x3f << 3);
+ regval |= (L_VAL_384MHZ << 3);
+ writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+ regval &= ~0x7;
+ regval |= SHOT_SWITCH;
+ writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+ /* Wait for frequency switch to finish */
+ while (readl(SCPLL_STATUS_ADDR) & 0x1)
+ ;
+
+ /* Status bit seems to clear early, using
+ * 800 microseconds for the worst case. */
+ udelay(800);
+
+ /* HOP switch to 768 MHz. */
+ regval = readl(SCPLL_FSM_CTL_EXT_ADDR);
+ regval &= ~(0x3f << 3);
+ regval |= (L_VAL_768MHZ << 3);
+ writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+ regval &= ~0x7;
+ regval |= HOP_SWITCH;
+ writel(regval, SCPLL_FSM_CTL_EXT_ADDR);
+
+ /* Wait for frequency switch to finish */
+ while (readl(SCPLL_STATUS_ADDR) & 0x1)
+ ;
+
+ /* Status bit seems to clear early, using
+ * 100 microseconds for the worst case. */
+ udelay(100);
+
+ /* End: Work around for h/w bug */
+
+ /* Power down scpll */
+ scpll_apps_enable(0);
+}
+
+static void config_pll(struct clkctl_acpu_speed *s)
+{
+ uint32_t regval;
+
+ if (s->pll == ACPU_PLL_3)
+ scpll_set_freq(s->sc_l_value, HOP_SWITCH);
+ /* Configure the PLL divider mux if we plan to use it. */
+ else if (s->sc_core_src_sel_mask == 0) {
+ /* get the current clock source selection */
+ regval = readl(SPSS_CLK_SEL_ADDR) & 0x1;
+
+ /* configure the other clock source, then switch to it,
+ * using the glitch free mux */
+ switch (regval) {
+ case 0x0:
+ regval = readl(SPSS_CLK_CNTL_ADDR);
+ regval &= ~(0x7 << 4 | 0xf);
+ regval |= (s->acpuclk_src_sel << 4);
+ regval |= (s->acpuclk_src_div << 0);
+ writel(regval, SPSS_CLK_CNTL_ADDR);
+
+ regval = readl(SPSS_CLK_SEL_ADDR);
+ regval |= 0x1;
+ writel(regval, SPSS_CLK_SEL_ADDR);
+ break;
+
+ case 0x1:
+ regval = readl(SPSS_CLK_CNTL_ADDR);
+ regval &= ~(0x7 << 12 | 0xf << 8);
+ regval |= (s->acpuclk_src_sel << 12);
+ regval |= (s->acpuclk_src_div << 8);
+ writel(regval, SPSS_CLK_CNTL_ADDR);
+
+ regval = readl(SPSS_CLK_SEL_ADDR);
+ regval &= ~0x1;
+ writel(regval, SPSS_CLK_SEL_ADDR);
+ break;
+ }
+ dmb();
+ }
+
+ regval = readl(SPSS_CLK_SEL_ADDR);
+ regval &= ~(0x3 << 1);
+ regval |= (s->sc_core_src_sel_mask << 1);
+ writel(regval, SPSS_CLK_SEL_ADDR);
+}
+
+void config_switching_pll(void)
+{
+ uint32_t regval;
+
+ /* Use AXI clock temporarily when we're changing
+ * scpll. PLL0 is faster, but it may not be available during
+ * early modem initialization, and we will only be using this
+ * a very short time (while scpll is reconfigured).
+ */
+
+ regval = readl(SPSS_CLK_SEL_ADDR);
+ regval &= ~(0x3 << 1);
+ regval |= (0x2 << 1);
+ writel(regval, SPSS_CLK_SEL_ADDR);
+}
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+ if (drv_state.acpu_set_vdd)
+ return drv_state.acpu_set_vdd(vdd);
+ else {
+ /* Assume that the PMIC supports scaling the processor
+ * to its maximum frequency at its default voltage.
+ */
+ return 0;
+ }
+}
+
+int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason)
+{
+ struct clkctl_acpu_speed *tgt_s, *strt_s;
+ int rc = 0;
+ int freq_index = 0;
+
+ if (reason == SETRATE_CPUFREQ)
+ mutex_lock(&drv_state.lock);
+
+ strt_s = drv_state.current_speed;
+
+ if (rate == (strt_s->acpuclk_khz * 1000))
+ goto out;
+
+ for (tgt_s = acpu_freq_tbl; tgt_s->acpuclk_khz != 0; tgt_s++) {
+ if (tgt_s->acpuclk_khz == (rate / 1000))
+ break;
+ freq_index++;
+ }
+
+ if (tgt_s->acpuclk_khz == 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (reason == SETRATE_CPUFREQ) {
+#ifdef CONFIG_MSM_CPU_AVS
+ /* Notify avs before changing frequency */
+ rc = avs_adjust_freq(freq_index, 1);
+ if (rc) {
+ printk(KERN_ERR
+ "acpuclock: Unable to increase ACPU "
+ "vdd.\n");
+ goto out;
+ }
+#endif
+ /* Increase VDD if needed. */
+ if (tgt_s->vdd > strt_s->vdd) {
+ rc = acpuclk_set_vdd_level(tgt_s->vdd);
+ if (rc) {
+ printk(KERN_ERR
+ "acpuclock: Unable to increase ACPU "
+ "vdd.\n");
+ goto out;
+ }
+ }
+ }
+
+ if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) {
+ config_pll(tgt_s);
+ } else if (strt_s->pll != ACPU_PLL_3 && tgt_s->pll == ACPU_PLL_3) {
+ scpll_apps_enable(1);
+ config_pll(tgt_s);
+ } else if (strt_s->pll == ACPU_PLL_3 && tgt_s->pll != ACPU_PLL_3) {
+ config_pll(tgt_s);
+ scpll_apps_enable(0);
+ } else {
+ config_switching_pll();
+ config_pll(tgt_s);
+ }
+
+ /* Update the driver state with the new clock freq */
+ drv_state.current_speed = tgt_s;
+
+ /* Re-adjust lpj for the new clock speed. */
+ loops_per_jiffy = tgt_s->lpj;
+
+ /* Nothing else to do for SWFI. */
+ if (reason == SETRATE_SWFI)
+ goto out;
+
+ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+ rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK,
+ tgt_s->axiclk_khz * 1000);
+ if (rc < 0)
+ pr_err("Setting AXI min rate failed!\n");
+ }
+
+ /* Nothing else to do for power collapse */
+ if (reason == SETRATE_PC)
+ goto out;
+
+#ifdef CONFIG_MSM_CPU_AVS
+ /* notify avs after changing frequency */
+ rc = avs_adjust_freq(freq_index, 0);
+ if (rc)
+ printk(KERN_ERR
+ "acpuclock: Unable to drop ACPU vdd.\n");
+#endif
+
+ /* Drop VDD level if we can. */
+ if (tgt_s->vdd < strt_s->vdd) {
+ rc = acpuclk_set_vdd_level(tgt_s->vdd);
+ if (rc)
+ printk(KERN_ERR
+ "acpuclock: Unable to drop ACPU vdd.\n");
+ }
+out:
+ if (reason == SETRATE_CPUFREQ)
+ mutex_unlock(&drv_state.lock);
+ return rc;
+}
+
+static void __init acpuclk_init(void)
+{
+ struct clkctl_acpu_speed *speed;
+ uint32_t div, sel, regval;
+ int rc;
+
+ /* Determine the source of the Scorpion clock. */
+ regval = readl(SPSS_CLK_SEL_ADDR);
+ switch ((regval & 0x6) >> 1) {
+ case 0: /* raw source clock */
+ case 3: /* low jitter PLL1 (768Mhz) */
+ if (regval & 0x1) {
+ sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 4) & 0x7);
+ div = ((readl(SPSS_CLK_CNTL_ADDR) >> 0) & 0xf);
+ } else {
+ sel = ((readl(SPSS_CLK_CNTL_ADDR) >> 12) & 0x7);
+ div = ((readl(SPSS_CLK_CNTL_ADDR) >> 8) & 0xf);
+ }
+
+ /* Find the matching clock rate. */
+ for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) {
+ if (speed->acpuclk_src_sel == sel &&
+ speed->acpuclk_src_div == div)
+ break;
+ }
+ break;
+
+ case 1: /* unbuffered scorpion pll (384Mhz to 998.4Mhz) */
+ sel = ((readl(SCPLL_FSM_CTL_EXT_ADDR) >> 3) & 0x3f);
+
+ /* Find the matching clock rate. */
+ for (speed = acpu_freq_tbl; speed->acpuclk_khz != 0; speed++) {
+ if (speed->sc_l_value == sel &&
+ speed->sc_core_src_sel_mask == 1)
+ break;
+ }
+ break;
+
+ case 2: /* AXI bus clock (128Mhz) */
+ default:
+ speed = &acpu_freq_tbl[4];
+ }
+
+ /* Initialize scpll only if it wasn't already initialized by the boot
+ * loader. If the CPU is already running on scpll, then the scpll was
+ * initialized by the boot loader. */
+ if (speed->pll != ACPU_PLL_3)
+ scpll_init();
+
+ if (speed->acpuclk_khz == 0) {
+ printk(KERN_WARNING "Warning - ACPU clock reports invalid "
+ "speed\n");
+ return;
+ }
+
+ drv_state.current_speed = speed;
+ rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, speed->axiclk_khz * 1000);
+ if (rc < 0)
+ pr_err("Setting AXI min rate failed!\n");
+
+ printk(KERN_INFO "ACPU running at %d KHz\n", speed->acpuclk_khz);
+}
+
+unsigned long acpuclk_get_rate(void)
+{
+ return drv_state.current_speed->acpuclk_khz;
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+ return drv_state.acpu_switch_time_us;
+}
+
+unsigned long acpuclk_power_collapse(void)
+{
+ int ret = acpuclk_get_rate();
+ acpuclk_set_rate(drv_state.power_collapse_khz, SETRATE_PC);
+ return ret * 1000;
+}
+
+unsigned long acpuclk_wait_for_irq(void)
+{
+ int ret = acpuclk_get_rate();
+ acpuclk_set_rate(drv_state.wait_for_irq_khz, SETRATE_SWFI);
+ return ret * 1000;
+}
+
+/* Spare register populated with efuse data on max ACPU freq. */
+#define CT_CSR_PHYS 0xA8700000
+#define TCSR_SPARE2_ADDR (ct_csr_base + 0x60)
+
+#define PLL0_M_VAL_ADDR (MSM_CLK_CTL_BASE + 0x308)
+
+static void __init acpu_freq_tbl_fixup(void)
+{
+ void __iomem *ct_csr_base;
+ uint32_t tcsr_spare2, pll0_m_val;
+ unsigned int max_acpu_khz, pll0_fixup;
+ unsigned int i;
+
+ ct_csr_base = ioremap(CT_CSR_PHYS, PAGE_SIZE);
+ BUG_ON(ct_csr_base == NULL);
+
+ tcsr_spare2 = readl(TCSR_SPARE2_ADDR);
+
+ /* Check if the register is supported and meaningful. */
+ if ((tcsr_spare2 & 0xF000) != 0xA000) {
+ pr_info("Efuse data on Max ACPU freq not present.\n");
+ goto skip_efuse_fixup;
+ }
+
+ switch (tcsr_spare2 & 0xF0) {
+ case 0x70:
+ max_acpu_khz = 768000;
+ break;
+ case 0x30:
+ case 0x00:
+ max_acpu_khz = 998400;
+ break;
+ case 0x10:
+ max_acpu_khz = 1267200;
+ break;
+ default:
+ pr_warning("Invalid efuse data (%x) on Max ACPU freq!\n",
+ tcsr_spare2);
+ goto skip_efuse_fixup;
+ }
+
+ pr_info("Max ACPU freq from efuse data is %d KHz\n", max_acpu_khz);
+
+ for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) {
+ if (acpu_freq_tbl[i].acpuclk_khz > max_acpu_khz) {
+ acpu_freq_tbl[i].acpuclk_khz = 0;
+ break;
+ }
+ }
+
+skip_efuse_fixup:
+ iounmap(ct_csr_base);
+ BUG_ON(drv_state.max_vdd == 0);
+
+ /* pll0_m_val will be 36 when PLL0 is run at 235MHz
+ * instead of the usual 245MHz. */
+ pll0_m_val = readl(PLL0_M_VAL_ADDR) & 0x7FFFF;
+ pll0_fixup = (pll0_m_val == 36);
+
+ for (i = 0; acpu_freq_tbl[i].acpuclk_khz != 0; i++) {
+ if (acpu_freq_tbl[i].pll == ACPU_PLL_0
+ && acpu_freq_tbl[i].acpuclk_khz == 245760
+ && pll0_fixup) {
+ acpu_freq_tbl[i].acpuclk_khz = 235930;
+ }
+ if (acpu_freq_tbl[i].vdd > drv_state.max_vdd) {
+ acpu_freq_tbl[i].acpuclk_khz = 0;
+ break;
+ }
+ }
+}
+
+/* Initalize the lpj field in the acpu_freq_tbl. */
+static void __init lpj_init(void)
+{
+ int i;
+ const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+ for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
+ acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
+ base_clk->acpuclk_khz,
+ acpu_freq_tbl[i].acpuclk_khz);
+ }
+}
+
+#ifdef CONFIG_MSM_CPU_AVS
+static int __init acpu_avs_init(int (*set_vdd) (int), int khz)
+{
+ int i;
+ int freq_count = 0;
+ int freq_index = -1;
+
+ for (i = 0; acpu_freq_tbl[i].acpuclk_khz; i++) {
+ freq_count++;
+ if (acpu_freq_tbl[i].acpuclk_khz == khz)
+ freq_index = i;
+ }
+
+ return avs_init(set_vdd, freq_count, freq_index);
+}
+#endif
+
+void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+{
+ mutex_init(&drv_state.lock);
+ drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
+ drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
+ drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
+ drv_state.power_collapse_khz = clkdata->power_collapse_khz;
+ drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz;
+ drv_state.max_vdd = clkdata->max_vdd;
+ drv_state.acpu_set_vdd = clkdata->acpu_set_vdd;
+
+ acpu_freq_tbl_fixup();
+ acpuclk_init();
+ lpj_init();
+#ifdef CONFIG_CPU_FREQ_MSM
+ cpufreq_table_init();
+ cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
+#endif
+#ifdef CONFIG_MSM_CPU_AVS
+ if (!acpu_avs_init(drv_state.acpu_set_vdd,
+ drv_state.current_speed->acpuclk_khz)) {
+ /* avs init successful. avs will handle voltage changes */
+ drv_state.acpu_set_vdd = NULL;
+ }
+#endif
+}
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
new file mode 100644
index 000000000000..bcc8491ab342
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -0,0 +1,915 @@
+/* arch/arm/mach-msm/acpuclock.c
+ *
+ * MSM architecture clock driver
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/sort.h>
+#include <linux/remote_spinlock.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach-types.h>
+
+#include "proc_comm.h"
+#include "smd_private.h"
+#include "clock.h"
+#include "acpuclock.h"
+#include "socinfo.h"
+
+#define PERF_SWITCH_DEBUG 0
+#define PERF_SWITCH_STEP_DEBUG 0
+
+#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)
+#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
+#define PLLn_L_VAL(n) (MSM_CLK_CTL_BASE + 0x304 + 28 * (n))
+
+enum {
+ ACPU_PLL_TCXO = -1,
+ ACPU_PLL_0 = 0,
+ ACPU_PLL_1,
+ ACPU_PLL_2,
+ ACPU_PLL_3,
+ ACPU_PLL_END,
+};
+
+struct clock_state
+{
+ struct clkctl_acpu_speed *current_speed;
+ struct mutex lock;
+ uint32_t acpu_switch_time_us;
+ uint32_t max_speed_delta_khz;
+ uint32_t vdd_switch_time_us;
+ unsigned long power_collapse_khz;
+ unsigned long wait_for_irq_khz;
+ unsigned long max_axi_khz;
+};
+
+#define PLL_BASE 7
+
+struct shared_pll_control {
+ uint32_t version;
+ struct {
+ /* Denotes if the PLL is ON. Technically, this can be read
+ * directly from the PLL registers, but this feild is here,
+ * so let's use it.
+ */
+ uint32_t on;
+ /* One bit for each processor core. The application processor
+ * is allocated bit position 1. All other bits should be
+ * considered as votes from other processors.
+ */
+ uint32_t votes;
+ } pll[PLL_BASE + ACPU_PLL_END];
+};
+
+struct clkctl_acpu_speed {
+ unsigned int use_for_scaling;
+ unsigned int a11clk_khz;
+ int pll;
+ unsigned int a11clk_src_sel;
+ unsigned int a11clk_src_div;
+ unsigned int ahbclk_khz;
+ unsigned int ahbclk_div;
+ int vdd;
+ unsigned int axiclk_khz;
+ unsigned long lpj; /* loops_per_jiffy */
+/* Pointers in acpu_freq_tbl[] for max up/down steppings. */
+ struct clkctl_acpu_speed *down[3];
+ struct clkctl_acpu_speed *up[3];
+};
+
+static remote_spinlock_t pll_lock;
+static struct shared_pll_control *pll_control;
+static struct clock_state drv_state = { 0 };
+static struct clkctl_acpu_speed *acpu_freq_tbl;
+
+static void __init acpuclk_init(void);
+
+/*
+ * ACPU freq tables used for different PLLs frequency combinations. The
+ * correct table is selected during init.
+ *
+ * Table stepping up/down entries are calculated during boot to choose the
+ * largest frequency jump that's less than max_speed_delta_khz on each PLL.
+ */
+
+/* 7x01/7x25 normal with GSM capable modem */
+static struct clkctl_acpu_speed pll0_245_pll1_768_pll2_1056[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+ { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
+ { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 61440 },
+ { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 },
+ { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 },
+ { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
+ { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 },
+ { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
+ { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x01/7x25 normal with CDMA-only modem */
+static struct clkctl_acpu_speed pll0_196_pll1_768_pll2_1056[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+ { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 },
+ { 0, 128000, ACPU_PLL_1, 1, 5, 64000, 1, 3, 24576 },
+ { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 },
+ { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 },
+ { 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
+ { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 128000 },
+ { 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
+ { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x01/7x25 turbo with GSM capable modem */
+static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1056[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+ { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 61440 },
+ { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
+ { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 61440 },
+ { 1, 245760, ACPU_PLL_0, 4, 0, 81920, 2, 4, 61440 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
+ { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
+ { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 122880 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x01/7x25 turbo with CDMA-only modem */
+static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1056[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+ { 1, 98304, ACPU_PLL_0, 4, 1, 49152, 1, 3, 24576 },
+ { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 24576 },
+ { 0, 176000, ACPU_PLL_2, 2, 5, 88000, 1, 3, 24576 },
+ { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 24576 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
+ { 0, 352000, ACPU_PLL_2, 2, 2, 88000, 3, 5, 120000 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
+ { 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 120000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x27 normal with GSM capable modem */
+static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+ { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 61440 },
+ { 1, 122880, ACPU_PLL_0, 4, 1, 61440, 1, 3, 61440 },
+ { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 },
+ { 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 4, 61440 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 122880 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 122880 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x27 normal with CDMA-only modem */
+static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1200[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+ { 1, 98304, ACPU_PLL_0, 4, 1, 98304, 0, 3, 49152 },
+ { 0, 120000, ACPU_PLL_1, 1, 7, 60000, 1, 3, 49152 },
+ { 1, 196608, ACPU_PLL_0, 4, 0, 65536, 2, 4, 98304 },
+ { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 },
+ { 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 120000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
+ { 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 120000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x27 normal with GSM capable modem - PLL0 and PLL1 swapped */
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
+ { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 61440 },
+ { 1, 122880, ACPU_PLL_1, 1, 1, 61440, 1, 3, 61440 },
+ { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 61440 },
+ { 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4, 61440 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+/* 7x27 normal with CDMA-only modem - PLL0 and PLL1 swapped */
+static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200[] = {
+ { 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
+ { 1, 98304, ACPU_PLL_1, 1, 1, 98304, 0, 3, 49152 },
+ { 0, 120000, ACPU_PLL_0, 4, 7, 60000, 1, 3, 49152 },
+ { 1, 196608, ACPU_PLL_1, 1, 0, 65536, 2, 4, 98304 },
+ { 0, 200000, ACPU_PLL_2, 2, 5, 66667, 2, 4, 98304 },
+ { 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 },
+ { 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
+ { 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 },
+ { 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, {0, 0, 0} }
+};
+
+#define PLL_196_MHZ 10
+#define PLL_245_MHZ 12
+#define PLL_491_MHZ 25
+#define PLL_768_MHZ 40
+#define PLL_960_MHZ 50
+#define PLL_1056_MHZ 55
+#define PLL_1200_MHZ 62
+
+#define PLL_CONFIG(m0, m1, m2) { \
+ PLL_##m0##_MHZ, PLL_##m1##_MHZ, PLL_##m2##_MHZ, \
+ pll0_##m0##_pll1_##m1##_pll2_##m2 \
+}
+
+struct pll_freq_tbl_map {
+ unsigned int pll0_l;
+ unsigned int pll1_l;
+ unsigned int pll2_l;
+ struct clkctl_acpu_speed *tbl;
+};
+
+static struct pll_freq_tbl_map acpu_freq_tbl_list[] = {
+ PLL_CONFIG(196, 768, 1056),
+ PLL_CONFIG(245, 768, 1056),
+ PLL_CONFIG(196, 960, 1056),
+ PLL_CONFIG(245, 960, 1056),
+ PLL_CONFIG(196, 960, 1200),
+ PLL_CONFIG(245, 960, 1200),
+ PLL_CONFIG(960, 196, 1200),
+ PLL_CONFIG(960, 245, 1200),
+ { 0, 0, 0, 0 }
+};
+
+#ifdef CONFIG_CPU_FREQ_MSM
+static struct cpufreq_frequency_table freq_table[20];
+
+static void __init cpufreq_table_init(void)
+{
+ unsigned int i;
+ unsigned int freq_cnt = 0;
+
+ /* Construct the freq_table table from acpu_freq_tbl since the
+ * freq_table values need to match frequencies specified in
+ * acpu_freq_tbl and acpu_freq_tbl needs to be fixed up during init.
+ */
+ for (i = 0; acpu_freq_tbl[i].a11clk_khz != 0
+ && freq_cnt < ARRAY_SIZE(freq_table)-1; i++) {
+ if (acpu_freq_tbl[i].use_for_scaling) {
+ freq_table[freq_cnt].index = freq_cnt;
+ freq_table[freq_cnt].frequency
+ = acpu_freq_tbl[i].a11clk_khz;
+ freq_cnt++;
+ }
+ }
+
+ /* freq_table not big enough to store all usable freqs. */
+ BUG_ON(acpu_freq_tbl[i].a11clk_khz != 0);
+
+ freq_table[freq_cnt].index = freq_cnt;
+ freq_table[freq_cnt].frequency = CPUFREQ_TABLE_END;
+
+ pr_info("%d scaling frequencies supported.\n", freq_cnt);
+}
+#endif
+
+unsigned long clk_get_max_axi_khz(void)
+{
+ return drv_state.max_axi_khz;
+}
+EXPORT_SYMBOL(clk_get_max_axi_khz);
+
+static int pc_pll_request(unsigned id, unsigned on)
+{
+ int res = 0;
+ on = !!on;
+
+#if PERF_SWITCH_DEBUG
+ if (on)
+ printk(KERN_DEBUG "Enabling PLL %d\n", id);
+ else
+ printk(KERN_DEBUG "Disabling PLL %d\n", id);
+#endif
+
+ if (id >= ACPU_PLL_END)
+ return -EINVAL;
+
+ if (pll_control) {
+ remote_spin_lock(&pll_lock);
+ if (on) {
+ pll_control->pll[PLL_BASE + id].votes |= 2;
+ if (!pll_control->pll[PLL_BASE + id].on) {
+ writel(6, PLLn_MODE(id));
+ udelay(50);
+ writel(7, PLLn_MODE(id));
+ pll_control->pll[PLL_BASE + id].on = 1;
+ }
+ } else {
+ pll_control->pll[PLL_BASE + id].votes &= ~2;
+ if (pll_control->pll[PLL_BASE + id].on
+ && !pll_control->pll[PLL_BASE + id].votes) {
+ writel(0, PLLn_MODE(id));
+ pll_control->pll[PLL_BASE + id].on = 0;
+ }
+ }
+ remote_spin_unlock(&pll_lock);
+ } else {
+ res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
+ if (res < 0)
+ return res;
+ else if ((int) id < 0)
+ return -EINVAL;
+ }
+
+#if PERF_SWITCH_DEBUG
+ if (on)
+ printk(KERN_DEBUG "PLL enabled\n");
+ else
+ printk(KERN_DEBUG "PLL disabled\n");
+#endif
+ return res;
+}
+
+
+/*----------------------------------------------------------------------------
+ * ARM11 'owned' clock control
+ *---------------------------------------------------------------------------*/
+
+unsigned long acpuclk_power_collapse(void) {
+ int ret = acpuclk_get_rate();
+ acpuclk_set_rate(drv_state.power_collapse_khz, SETRATE_PC);
+ return ret * 1000;
+}
+
+unsigned long acpuclk_wait_for_irq(void) {
+ int ret = acpuclk_get_rate();
+ acpuclk_set_rate(drv_state.wait_for_irq_khz, SETRATE_SWFI);
+ return ret * 1000;
+}
+
+static int acpuclk_set_vdd_level(int vdd)
+{
+ uint32_t current_vdd;
+
+ current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07;
+
+#if PERF_SWITCH_DEBUG
+ printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n",
+ current_vdd, vdd);
+#endif
+ writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR);
+ udelay(drv_state.vdd_switch_time_us);
+ if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) {
+#if PERF_SWITCH_DEBUG
+ printk(KERN_ERR "acpuclock: VDD set failed\n");
+#endif
+ return -EIO;
+ }
+
+#if PERF_SWITCH_DEBUG
+ printk(KERN_DEBUG "acpuclock: VDD switched\n");
+#endif
+ return 0;
+}
+
+/* Set proper dividers for the given clock speed. */
+static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) {
+ uint32_t reg_clkctl, reg_clksel, clk_div, src_sel;
+
+ reg_clksel = readl(A11S_CLK_SEL_ADDR);
+
+ /* AHB_CLK_DIV */
+ clk_div = (reg_clksel >> 1) & 0x03;
+ /* CLK_SEL_SRC1NO */
+ src_sel = reg_clksel & 1;
+
+ /*
+ * If the new clock divider is higher than the previous, then
+ * program the divider before switching the clock
+ */
+ if (hunt_s->ahbclk_div > clk_div) {
+ reg_clksel &= ~(0x3 << 1);
+ reg_clksel |= (hunt_s->ahbclk_div << 1);
+ writel(reg_clksel, A11S_CLK_SEL_ADDR);
+ }
+
+ /* Program clock source and divider */
+ reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
+ reg_clkctl &= ~(0xFF << (8 * src_sel));
+ reg_clkctl |= hunt_s->a11clk_src_sel << (4 + 8 * src_sel);
+ reg_clkctl |= hunt_s->a11clk_src_div << (0 + 8 * src_sel);
+ writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+ /* Program clock source selection */
+ reg_clksel ^= 1;
+ writel(reg_clksel, A11S_CLK_SEL_ADDR);
+
+ /*
+ * If the new clock divider is lower than the previous, then
+ * program the divider after switching the clock
+ */
+ if (hunt_s->ahbclk_div < clk_div) {
+ reg_clksel &= ~(0x3 << 1);
+ reg_clksel |= (hunt_s->ahbclk_div << 1);
+ writel(reg_clksel, A11S_CLK_SEL_ADDR);
+ }
+}
+
+int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason)
+{
+ uint32_t reg_clkctl;
+ struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
+ int rc = 0;
+ unsigned int plls_enabled = 0, pll;
+
+ if (reason == SETRATE_CPUFREQ)
+ mutex_lock(&drv_state.lock);
+
+ strt_s = cur_s = drv_state.current_speed;
+
+ WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n");
+ if (cur_s == NULL) {
+ rc = -ENOENT;
+ goto out;
+ }
+
+ if (rate == (cur_s->a11clk_khz * 1000))
+ goto out;
+
+ for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) {
+ if (tgt_s->a11clk_khz == (rate / 1000))
+ break;
+ }
+
+ if (tgt_s->a11clk_khz == 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* Choose the highest speed at or below 'rate' with same PLL. */
+ if (reason != SETRATE_CPUFREQ
+ && tgt_s->a11clk_khz < cur_s->a11clk_khz) {
+ while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll)
+ tgt_s--;
+ }
+
+ if (strt_s->pll != ACPU_PLL_TCXO)
+ plls_enabled |= 1 << strt_s->pll;
+
+ if (reason == SETRATE_CPUFREQ) {
+ if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
+ rc = pc_pll_request(tgt_s->pll, 1);
+ if (rc < 0) {
+ pr_err("PLL%d enable failed (%d)\n",
+ tgt_s->pll, rc);
+ goto out;
+ }
+ plls_enabled |= 1 << tgt_s->pll;
+ }
+ }
+ /* Need to do this when coming out of power collapse since some modem
+ * firmwares reset the VDD when the application processor enters power
+ * collapse. */
+ if (reason == SETRATE_CPUFREQ || reason == SETRATE_PC) {
+ /* Increase VDD if needed. */
+ if (tgt_s->vdd > cur_s->vdd) {
+ if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) {
+ printk(KERN_ERR "Unable to switch ACPU vdd\n");
+ goto out;
+ }
+ }
+ }
+
+ /* Set wait states for CPU inbetween frequency changes */
+ reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
+ reg_clkctl |= (100 << 16); /* set WT_ST_CNT */
+ writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
+
+#if PERF_SWITCH_DEBUG
+ printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n",
+ strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000);
+#endif
+
+ while (cur_s != tgt_s) {
+ /*
+ * Always jump to target freq if within 256mhz, regulardless of
+ * PLL. If differnece is greater, use the predefinied
+ * steppings in the table.
+ */
+ int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz));
+ if (d > drv_state.max_speed_delta_khz) {
+
+ if (tgt_s->a11clk_khz > cur_s->a11clk_khz) {
+ /* Step up: jump to target PLL as early as
+ * possible so indexing using TCXO (up[-1])
+ * never occurs. */
+ if (likely(cur_s->up[tgt_s->pll]))
+ cur_s = cur_s->up[tgt_s->pll];
+ else
+ cur_s = cur_s->up[cur_s->pll];
+ } else {
+ /* Step down: stay on current PLL as long as
+ * possible so indexing using TCXO (down[-1])
+ * never occurs. */
+ if (likely(cur_s->down[cur_s->pll]))
+ cur_s = cur_s->down[cur_s->pll];
+ else
+ cur_s = cur_s->down[tgt_s->pll];
+ }
+
+ if (cur_s == NULL) { /* This should not happen. */
+ pr_err("No stepping frequencies found. "
+ "strt_s:%u tgt_s:%u\n",
+ strt_s->a11clk_khz, tgt_s->a11clk_khz);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ } else {
+ cur_s = tgt_s;
+ }
+#if PERF_SWITCH_STEP_DEBUG
+ printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n",
+ __FUNCTION__, cur_s->a11clk_khz, cur_s->pll);
+#endif
+ if (cur_s->pll != ACPU_PLL_TCXO
+ && !(plls_enabled & (1 << cur_s->pll))) {
+ rc = pc_pll_request(cur_s->pll, 1);
+ if (rc < 0) {
+ pr_err("PLL%d enable failed (%d)\n",
+ cur_s->pll, rc);
+ goto out;
+ }
+ plls_enabled |= 1 << cur_s->pll;
+ }
+
+ acpuclk_set_div(cur_s);
+ drv_state.current_speed = cur_s;
+ /* Re-adjust lpj for the new clock speed. */
+ loops_per_jiffy = cur_s->lpj;
+ udelay(drv_state.acpu_switch_time_us);
+ }
+
+ /* Nothing else to do for SWFI. */
+ if (reason == SETRATE_SWFI)
+ goto out;
+
+ /* Change the AXI bus frequency if we can. */
+ if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
+ rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK,
+ tgt_s->axiclk_khz * 1000);
+ if (rc < 0)
+ pr_err("Setting AXI min rate failed!\n");
+ }
+
+ /* Nothing else to do for power collapse if not 7x27. */
+ if (reason == SETRATE_PC && !cpu_is_msm7x27())
+ goto out;
+
+ /* Disable PLLs we are not using anymore. */
+ if (tgt_s->pll != ACPU_PLL_TCXO)
+ plls_enabled &= ~(1 << tgt_s->pll);
+ for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++)
+ if (plls_enabled & (1 << pll)) {
+ rc = pc_pll_request(pll, 0);
+ if (rc < 0) {
+ pr_err("PLL%d disable failed (%d)\n", pll, rc);
+ goto out;
+ }
+ }
+
+ /* Nothing else to do for power collapse. */
+ if (reason == SETRATE_PC)
+ goto out;
+
+ /* Drop VDD level if we can. */
+ if (tgt_s->vdd < strt_s->vdd) {
+ if (acpuclk_set_vdd_level(tgt_s->vdd) < 0)
+ printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n");
+ }
+
+#if PERF_SWITCH_DEBUG
+ printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__);
+#endif
+out:
+ if (reason == SETRATE_CPUFREQ)
+ mutex_unlock(&drv_state.lock);
+ return rc;
+}
+
+static void __init acpuclk_init(void)
+{
+ struct clkctl_acpu_speed *speed;
+ uint32_t div, sel;
+ int rc;
+
+ /*
+ * Determine the rate of ACPU clock
+ */
+
+ if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */
+ /* CLK_SRC0_SEL */
+ sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7;
+ /* CLK_SRC0_DIV */
+ div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f;
+ } else {
+ /* CLK_SRC1_SEL */
+ sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07;
+ /* CLK_SRC1_DIV */
+ div = readl(A11S_CLK_CNTL_ADDR) & 0x0f;
+ }
+
+ for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
+ if (speed->a11clk_src_sel == sel
+ && (speed->a11clk_src_div == div))
+ break;
+ }
+ if (speed->a11clk_khz == 0) {
+ printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n");
+ return;
+ }
+
+ drv_state.current_speed = speed;
+
+ rc = ebi1_clk_set_min_rate(CLKVOTE_ACPUCLK, speed->axiclk_khz * 1000);
+ if (rc < 0)
+ pr_err("Setting AXI min rate failed!\n");
+
+ printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz);
+}
+
+unsigned long acpuclk_get_rate(void)
+{
+ WARN_ONCE(drv_state.current_speed == NULL,
+ "acpuclk_get_rate: not initialized\n");
+ if (drv_state.current_speed)
+ return drv_state.current_speed->a11clk_khz;
+ else
+ return 0;
+}
+
+uint32_t acpuclk_get_switch_time(void)
+{
+ return drv_state.acpu_switch_time_us;
+}
+
+/*----------------------------------------------------------------------------
+ * Clock driver initialization
+ *---------------------------------------------------------------------------*/
+
+#define DIV2REG(n) ((n)-1)
+#define REG2DIV(n) ((n)+1)
+#define SLOWER_BY(div, factor) div = DIV2REG(REG2DIV(div) * factor)
+
+static void __init acpu_freq_tbl_fixup(void)
+{
+ unsigned long pll0_l, pll1_l, pll2_l;
+ int axi_160mhz = 0, axi_200mhz = 0;
+ struct pll_freq_tbl_map *lst;
+ struct clkctl_acpu_speed *t;
+ unsigned int pll0_needs_fixup = 0;
+
+ /* Wait for the PLLs to be initialized and then read their frequency.
+ */
+ do {
+ pll0_l = readl(PLLn_L_VAL(0)) & 0x3f;
+ cpu_relax();
+ udelay(50);
+ } while (pll0_l == 0);
+ do {
+ pll1_l = readl(PLLn_L_VAL(1)) & 0x3f;
+ cpu_relax();
+ udelay(50);
+ } while (pll1_l == 0);
+ do {
+ pll2_l = readl(PLLn_L_VAL(2)) & 0x3f;
+ cpu_relax();
+ udelay(50);
+ } while (pll2_l == 0);
+
+ printk(KERN_INFO "L val: PLL0: %d, PLL1: %d, PLL2: %d\n",
+ (int)pll0_l, (int)pll1_l, (int)pll2_l);
+
+ /* Some configurations run PLL0 twice as fast. Instead of having
+ * separate tables for this case, we simply fix up the ACPU clock
+ * source divider since it's a simple fix up.
+ */
+ if (pll0_l == PLL_491_MHZ) {
+ pll0_l = PLL_245_MHZ;
+ pll0_needs_fixup = 1;
+ }
+
+ /* Select the right table to use. */
+ for (lst = acpu_freq_tbl_list; lst->tbl != 0; lst++) {
+ if (lst->pll0_l == pll0_l && lst->pll1_l == pll1_l
+ && lst->pll2_l == pll2_l) {
+ acpu_freq_tbl = lst->tbl;
+ break;
+ }
+ }
+
+ if (acpu_freq_tbl == NULL) {
+ pr_crit("Unknown PLL configuration!\n");
+ BUG();
+ }
+
+ /* Fix up PLL0 source divider if necessary. Also, fix up the AXI to
+ * the max that's supported by the board (RAM used in board).
+ */
+ axi_160mhz = (pll0_l == PLL_960_MHZ || pll1_l == PLL_960_MHZ);
+ axi_200mhz = (pll2_l == PLL_1200_MHZ);
+ for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) {
+
+ if (pll0_needs_fixup && t->pll == ACPU_PLL_0)
+ SLOWER_BY(t->a11clk_src_div, 2);
+ if (axi_160mhz && drv_state.max_axi_khz >= 160000
+ && t->ahbclk_khz > 128000)
+ t->axiclk_khz = 160000;
+ if (axi_200mhz && drv_state.max_axi_khz >= 200000
+ && t->ahbclk_khz > 160000)
+ t->axiclk_khz = 200000;
+ }
+
+ t--;
+ drv_state.max_axi_khz = t->axiclk_khz;
+
+ /* The default 7x27 ACPU clock plan supports running the AXI bus at
+ * 200 MHz. So we don't classify it as Turbo mode.
+ */
+ if (cpu_is_msm7x27())
+ return;
+
+ if (!axi_160mhz)
+ pr_info("Turbo mode not supported.\n");
+ else if (t->axiclk_khz == 160000)
+ pr_info("Turbo mode supported and enabled.\n");
+ else
+ pr_info("Turbo mode supported but not enabled.\n");
+}
+
+/* Initalize the lpj field in the acpu_freq_tbl. */
+static void __init lpj_init(void)
+{
+ int i;
+ const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
+ for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+ acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
+ base_clk->a11clk_khz,
+ acpu_freq_tbl[i].a11clk_khz);
+ }
+}
+
+static void __init precompute_stepping(void)
+{
+ int i, step_idx;
+
+#define cur_freq acpu_freq_tbl[i].a11clk_khz
+#define step_freq acpu_freq_tbl[step_idx].a11clk_khz
+#define cur_pll acpu_freq_tbl[i].pll
+#define step_pll acpu_freq_tbl[step_idx].pll
+
+ for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
+
+ /* Calculate max "up" step for each destination PLL */
+ step_idx = i + 1;
+ while (step_freq && (step_freq - cur_freq)
+ <= drv_state.max_speed_delta_khz) {
+ acpu_freq_tbl[i].up[step_pll] =
+ &acpu_freq_tbl[step_idx];
+ step_idx++;
+ }
+ if (step_idx == (i + 1) && step_freq) {
+ pr_crit("Delta between freqs %u KHz and %u KHz is"
+ " too high!\n", cur_freq, step_freq);
+ BUG();
+ }
+
+ /* Calculate max "down" step for each destination PLL */
+ step_idx = i - 1;
+ while (step_idx >= 0 && (cur_freq - step_freq)
+ <= drv_state.max_speed_delta_khz) {
+ acpu_freq_tbl[i].down[step_pll] =
+ &acpu_freq_tbl[step_idx];
+ step_idx--;
+ }
+ if (step_idx == (i - 1) && i > 0) {
+ pr_crit("Delta between freqs %u KHz and %u KHz is"
+ " too high!\n", cur_freq, step_freq);
+ BUG();
+ }
+ }
+}
+
+static void __init print_acpu_freq_tbl(void)
+{
+ struct clkctl_acpu_speed *t;
+ short down_idx[3];
+ short up_idx[3];
+ int i, j;
+
+#define FREQ_IDX(freq_ptr) (freq_ptr - acpu_freq_tbl)
+ pr_info("Id CPU-KHz PLL DIV AHB-KHz ADIV AXI-KHz "
+ "D0 D1 D2 U0 U1 U2\n");
+
+ t = &acpu_freq_tbl[0];
+ for (i = 0; t->a11clk_khz != 0; i++) {
+
+ for (j = 0; j < 3; j++) {
+ down_idx[j] = t->down[j] ? FREQ_IDX(t->down[j]) : -1;
+ up_idx[j] = t->up[j] ? FREQ_IDX(t->up[j]) : -1;
+ }
+
+ pr_info("%2d %7d %3d %3d %7d %4d %7d "
+ "%2d %2d %2d %2d %2d %2d\n",
+ i, t->a11clk_khz, t->pll, t->a11clk_src_div + 1,
+ t->ahbclk_khz, t->ahbclk_div + 1, t->axiclk_khz,
+ down_idx[0], down_idx[1], down_idx[2],
+ up_idx[0], up_idx[1], up_idx[2]);
+
+ t++;
+ }
+}
+
+static void msm7x25_acpu_pll_hw_bug_fix(void)
+{
+ unsigned int n;
+
+ /* The 7625 has a hardware bug and in order to select PLL2 we
+ * must program PLL3. Use the same table, and just fix up the
+ * numbers on this target. */
+ for (n = 0; acpu_freq_tbl[n].a11clk_khz != 0; n++)
+ if (acpu_freq_tbl[n].pll == ACPU_PLL_2)
+ acpu_freq_tbl[n].a11clk_src_sel = 3;
+}
+
+static void shared_pll_control_init(void)
+{
+#define PLL_REMOTE_SPINLOCK_ID 7
+ unsigned smem_size;
+ remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
+ pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
+
+ if (!pll_control)
+ pr_err("Unable to find shared PLL control data structure!\n");
+ /* There might be more PLLs than what the application processor knows
+ * about. But the index used for each PLL is guaranteed to remain the
+ * same. */
+ else if (smem_size < sizeof(struct shared_pll_control))
+ pr_err("Shared PLL control data structure too small!\n");
+ else if (pll_control->version != 0xCCEE0001)
+ pr_err("Shared PLL control version mismatch!\n");
+ else {
+ pr_info("Shared PLL control available.\n");
+ return;
+ }
+
+ pll_control = NULL;
+ pr_err("Falling back to proc_comm PLL control.\n");
+}
+
+void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
+{
+ pr_info("acpu_clock_init()\n");
+
+ mutex_init(&drv_state.lock);
+ drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
+ drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
+ drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
+ drv_state.power_collapse_khz = clkdata->power_collapse_khz;
+ drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz;
+ drv_state.max_axi_khz = clkdata->max_axi_khz;
+ acpu_freq_tbl_fixup();
+ precompute_stepping();
+ acpuclk_init();
+ lpj_init();
+ print_acpu_freq_tbl();
+ if (cpu_is_msm7x25())
+ msm7x25_acpu_pll_hw_bug_fix();
+ if (cpu_is_msm7x27())
+ shared_pll_control_init();
+#ifdef CONFIG_CPU_FREQ_MSM
+ cpufreq_table_init();
+ cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
+#endif
+}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
new file mode 100644
index 000000000000..ad7b4cd2399d
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -0,0 +1,39 @@
+/* arch/arm/mach-msm/acpuclock.h
+ *
+ * MSM architecture clock driver header
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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 __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
+#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
+
+#include <linux/list.h>
+
+enum setrate_reason {
+ SETRATE_CPUFREQ = 0,
+ SETRATE_SWFI,
+ SETRATE_PC,
+};
+
+int acpuclk_set_rate(unsigned long rate, enum setrate_reason reason);
+unsigned long acpuclk_get_rate(void);
+uint32_t acpuclk_get_switch_time(void);
+unsigned long acpuclk_wait_for_irq(void);
+unsigned long acpuclk_power_collapse(void);
+
+
+#endif
+
diff --git a/arch/arm/mach-msm/avs.c b/arch/arm/mach-msm/avs.c
new file mode 100644
index 000000000000..297d3e1a4d52
--- /dev/null
+++ b/arch/arm/mach-msm/avs.c
@@ -0,0 +1,323 @@
+/*
+ * 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/kernel_stat.h>
+#include <linux/workqueue.h>
+
+#include "avs.h"
+
+#define AVSDSCR_INPUT 0x01004860 /* magic # from circuit designer */
+#define TSCSR_INPUT 0x00000001 /* enable temperature sense */
+
+#define TEMPRS 16 /* total number of temperature regions */
+#define GET_TEMPR() (avs_get_tscsr() >> 28) /* scale TSCSR[CTEMP] to regions */
+
+struct mutex avs_lock;
+
+static struct avs_state_s
+{
+ u32 freq_cnt; /* Frequencies supported list */
+ short *avs_v; /* Dyanmically allocated storage for
+ * 2D table of voltages over temp &
+ * freq. Used as a set of 1D tables.
+ * Each table is for a single temp.
+ * For usage see avs_get_voltage
+ */
+ int (*set_vdd) (int); /* Function Ptr for setting voltage */
+ int changing; /* Clock frequency is changing */
+ u32 freq_idx; /* Current frequency index */
+ int vdd; /* Current ACPU voltage */
+} avs_state;
+
+/*
+ * Update the AVS voltage vs frequency table, for current temperature
+ * Adjust based on the AVS delay circuit hardware status
+ */
+static void avs_update_voltage_table(short *vdd_table)
+{
+ u32 avscsr;
+ int cpu;
+ int vu;
+ int l2;
+ int i;
+ u32 cur_freq_idx;
+ short cur_voltage;
+
+ cur_freq_idx = avs_state.freq_idx;
+ cur_voltage = avs_state.vdd;
+
+ avscsr = avs_test_delays();
+ AVSDEBUG("avscsr=%x, avsdscr=%x\n", avscsr, avs_get_avsdscr());
+
+ /*
+ * Read the results for the various unit's AVS delay circuits
+ * 2=> up, 1=>down, 0=>no-change
+ */
+ cpu = ((avscsr >> 23) & 2) + ((avscsr >> 16) & 1);
+ vu = ((avscsr >> 28) & 2) + ((avscsr >> 21) & 1);
+ l2 = ((avscsr >> 29) & 2) + ((avscsr >> 22) & 1);
+
+ if ((cpu == 3) || (vu == 3) || (l2 == 3)) {
+ printk(KERN_ERR "AVS: Dly Synth O/P error\n");
+ } else if ((cpu == 2) || (l2 == 2) || (vu == 2)) {
+ /*
+ * even if one oscillator asks for up, increase the voltage,
+ * as its an indication we are running outside the
+ * critical acceptable range of v-f combination.
+ */
+ AVSDEBUG("cpu=%d l2=%d vu=%d\n", cpu, l2, vu);
+ AVSDEBUG("Voltage up at %d\n", cur_freq_idx);
+
+ if (cur_voltage >= VOLTAGE_MAX)
+ printk(KERN_ERR
+ "AVS: Voltage can not get high enough!\n");
+
+ /* Raise the voltage for all frequencies */
+ for (i = 0; i < avs_state.freq_cnt; i++) {
+ vdd_table[i] = cur_voltage + VOLTAGE_STEP;
+ if (vdd_table[i] > VOLTAGE_MAX)
+ vdd_table[i] = VOLTAGE_MAX;
+ }
+ } else if ((cpu == 1) && (l2 == 1) && (vu == 1)) {
+ if ((cur_voltage - VOLTAGE_STEP >= VOLTAGE_MIN) &&
+ (cur_voltage <= vdd_table[cur_freq_idx])) {
+ vdd_table[cur_freq_idx] = cur_voltage - VOLTAGE_STEP;
+ AVSDEBUG("Voltage down for %d and lower levels\n",
+ cur_freq_idx);
+
+ /* clamp to this voltage for all lower levels */
+ for (i = 0; i < cur_freq_idx; i++) {
+ if (vdd_table[i] > vdd_table[cur_freq_idx])
+ vdd_table[i] = vdd_table[cur_freq_idx];
+ }
+ }
+ }
+}
+
+/*
+ * Return the voltage for the target performance freq_idx and optionally
+ * use AVS hardware to check the present voltage freq_idx
+ */
+static short avs_get_target_voltage(int freq_idx, bool update_table)
+{
+ unsigned cur_tempr = GET_TEMPR();
+ unsigned temp_index = cur_tempr*avs_state.freq_cnt;
+
+ /* Table of voltages vs frequencies for this temp */
+ short *vdd_table = avs_state.avs_v + temp_index;
+
+ if (update_table)
+ avs_update_voltage_table(vdd_table);
+
+ return vdd_table[freq_idx];
+}
+
+
+/*
+ * Set the voltage for the freq_idx and optionally
+ * use AVS hardware to update the voltage
+ */
+static int avs_set_target_voltage(int freq_idx, bool update_table)
+{
+ int rc = 0;
+ int new_voltage = avs_get_target_voltage(freq_idx, update_table);
+ if (avs_state.vdd != new_voltage) {
+ AVSDEBUG("AVS setting V to %d mV @%d\n",
+ new_voltage, freq_idx);
+ rc = avs_state.set_vdd(new_voltage);
+ if (rc)
+ return rc;
+ avs_state.vdd = new_voltage;
+ }
+ return rc;
+}
+
+/*
+ * Notify avs of clk frquency transition begin & end
+ */
+int avs_adjust_freq(u32 freq_idx, int begin)
+{
+ int rc = 0;
+
+ if (!avs_state.set_vdd) {
+ /* AVS not initialized */
+ return 0;
+ }
+
+ if (freq_idx >= avs_state.freq_cnt) {
+ AVSDEBUG("Out of range :%d\n", freq_idx);
+ return -EINVAL;
+ }
+
+ mutex_lock(&avs_lock);
+ if ((begin && (freq_idx > avs_state.freq_idx)) ||
+ (!begin && (freq_idx < avs_state.freq_idx))) {
+ /* Update voltage before increasing frequency &
+ * after decreasing frequency
+ */
+ rc = avs_set_target_voltage(freq_idx, 0);
+ if (rc)
+ goto aaf_out;
+
+ avs_state.freq_idx = freq_idx;
+ }
+ avs_state.changing = begin;
+aaf_out:
+ mutex_unlock(&avs_lock);
+
+ return rc;
+}
+
+
+static struct delayed_work avs_work;
+static struct workqueue_struct *kavs_wq;
+#define AVS_DELAY ((CONFIG_HZ * 50 + 999) / 1000)
+
+static void do_avs_timer(struct work_struct *work)
+{
+ int cur_freq_idx;
+
+ mutex_lock(&avs_lock);
+ if (!avs_state.changing) {
+ /* Only adjust the voltage if clk is stable */
+ cur_freq_idx = avs_state.freq_idx;
+ avs_set_target_voltage(cur_freq_idx, 1);
+ }
+ mutex_unlock(&avs_lock);
+ queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
+}
+
+
+static void __init avs_timer_init(void)
+{
+ INIT_DELAYED_WORK_DEFERRABLE(&avs_work, do_avs_timer);
+ queue_delayed_work_on(0, kavs_wq, &avs_work, AVS_DELAY);
+}
+
+static void __exit avs_timer_exit(void)
+{
+ cancel_delayed_work(&avs_work);
+}
+
+static int __init avs_work_init(void)
+{
+ kavs_wq = create_workqueue("avs");
+ if (!kavs_wq) {
+ printk(KERN_ERR "AVS initialization failed\n");
+ return -EFAULT;
+ }
+ avs_timer_init();
+
+ return 1;
+}
+
+static void __exit avs_work_exit(void)
+{
+ avs_timer_exit();
+ destroy_workqueue(kavs_wq);
+}
+
+int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx)
+{
+ int i;
+
+ mutex_init(&avs_lock);
+
+ if (freq_cnt == 0)
+ return -EINVAL;
+
+ avs_state.freq_cnt = freq_cnt;
+
+ if (freq_idx >= avs_state.freq_cnt)
+ return -EINVAL;
+
+ avs_state.avs_v = kmalloc(TEMPRS * avs_state.freq_cnt *
+ sizeof(avs_state.avs_v[0]), GFP_KERNEL);
+
+ if (avs_state.avs_v == 0)
+ return -ENOMEM;
+
+ for (i = 0; i < TEMPRS*avs_state.freq_cnt; i++)
+ avs_state.avs_v[i] = VOLTAGE_MAX;
+
+ avs_reset_delays(AVSDSCR_INPUT);
+ avs_set_tscsr(TSCSR_INPUT);
+
+ avs_state.set_vdd = set_vdd;
+ avs_state.changing = 0;
+ avs_state.freq_idx = -1;
+ avs_state.vdd = -1;
+ avs_adjust_freq(freq_idx, 0);
+
+ avs_work_init();
+
+ return 0;
+}
+
+void __exit avs_exit()
+{
+ avs_work_exit();
+
+ kfree(avs_state.avs_v);
+}
+
+
diff --git a/arch/arm/mach-msm/avs.h b/arch/arm/mach-msm/avs.h
new file mode 100644
index 000000000000..daae78938297
--- /dev/null
+++ b/arch/arm/mach-msm/avs.h
@@ -0,0 +1,52 @@
+/*
+ * 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 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.
+ */
+
+#ifndef AVS_H
+#define AVS_H
+
+#define VOLTAGE_MIN 1000 /* mV */
+#define VOLTAGE_MAX 1250
+#define VOLTAGE_STEP 25
+
+int __init avs_init(int (*set_vdd)(int), u32 freq_cnt, u32 freq_idx);
+void __exit avs_exit(void);
+
+int avs_adjust_freq(u32 freq_index, int begin);
+
+/* Routines exported from avs_hw.S */
+u32 avs_test_delays(void);
+u32 avs_reset_delays(u32 avsdscr);
+u32 avs_get_avscsr(void);
+u32 avs_get_avsdscr(void);
+u32 avs_get_tscsr(void);
+void avs_set_tscsr(u32 to_tscsr);
+
+/*#define AVSDEBUG(x...) pr_info("AVS: " x);*/
+#define AVSDEBUG(...)
+
+#endif /* AVS_H */
diff --git a/arch/arm/mach-msm/avs_hw.S b/arch/arm/mach-msm/avs_hw.S
new file mode 100644
index 000000000000..57521b60d8f0
--- /dev/null
+++ b/arch/arm/mach-msm/avs_hw.S
@@ -0,0 +1,158 @@
+/*
+ * 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ */
+
+ .text
+
+ .global avs_test_delays
+avs_test_delays:
+
+/* Read r1=CPMR and enable Never Sleep for VSLPDLY */
+ mrc p15, 7, r1, c15, c0, 5
+ orr r12, r1, #3, 24
+ mcr p15, 7, r12, c15, c0, 5
+
+/* Read r2=CPACR and enable full access to CP10 and CP11 space */
+ mrc p15, 0, r2, c1, c0, 2
+ orr r12, r2, #(0xf << 20)
+ mcr p15, 0, r12, c1, c0, 2
+ isb
+
+/* Read r3=FPEXC and or in FP enable, VFP/ASE enable = FPEXC[30]; */
+ fmrx r3, fpexc
+ orr r12, r3, #1, 2
+ fmxr fpexc, r12
+
+/*
+ * Do floating-point operations to prime the VFP pipeline. Use
+ * fcpyd d0, d0 as a floating point nop. This avoids changing VFP
+ * state.
+ */
+ fcpyd d0, d0
+ fcpyd d0, d0
+ fcpyd d0, d0
+
+/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
+ mrc p15, 7, r0, c15, c1, 7
+
+/* Restore FPEXC */
+ fmxr fpexc, r3
+
+/* Restore CPACR */
+ MCR p15, 0, r2, c1, c0, 2
+
+/* Restore CPMR */
+ mcr p15, 7, r1, c15, c0, 5
+ isb
+
+ bx lr
+
+
+
+
+ .global avs_get_avscsr
+/* Read r0=AVSCSR to get status from CPU, VFP, and L2 ring oscillators */
+
+avs_get_avscsr:
+ mrc p15, 7, r0, c15, c1, 7
+ bx lr
+
+ .global avs_get_avsdscr
+/* Read r0=AVSDSCR to get the AVS Delay Synthesizer control settings */
+
+avs_get_avsdscr:
+ mrc p15, 7, r0, c15, c0, 6
+ bx lr
+
+
+
+
+ .global avs_get_tscsr
+/* Read r0=TSCSR to get temperature sensor control and status */
+
+avs_get_tscsr:
+ mrc p15, 7, r0, c15, c1, 0
+ bx lr
+
+ .global avs_set_tscsr
+/* Write TSCSR=r0 to set temperature sensor control and status */
+
+avs_set_tscsr:
+ mcr p15, 7, r0, c15, c1, 0
+ bx lr
+
+
+
+
+
+ .global avs_reset_delays
+avs_reset_delays:
+
+/* AVSCSR(0x61) to enable CPU, V and L2 AVS module */
+ mov r3, #0x61
+ mcr p15, 7, r3, c15, c1, 7
+
+/* AVSDSCR(dly) to program delay */
+ mcr p15, 7, r0, c15, c0, 6
+
+/* Read r0=AVSDSCR */
+ mrc p15, 7, r0, c15, c0, 6
+
+ bx lr
+
+ .end
+
+
diff --git a/arch/arm/mach-msm/board-comet.c b/arch/arm/mach-msm/board-comet.c
new file mode 100644
index 000000000000..9d8e290e8930
--- /dev/null
+++ b/arch/arm/mach-msm/board-comet.c
@@ -0,0 +1,488 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <asm/mach/mmc.h>
+#include <mach/vreg.h>
+#include <mach/board.h>
+#include <mach/sirc.h>
+#include <linux/spi/spi.h>
+
+#include "devices.h"
+#include "timer.h"
+#include "pm.h"
+
+#define TOUCHPAD_SUSPEND 34
+#define TOUCHPAD_IRQ 42
+
+#define MSM_PMEM_MDP_SIZE 0x800000
+#define MSM_FB_SIZE 0x500000
+#define MSM_AUDIO_SIZE 0x200000
+
+#define MSM_SMI_BASE 0x2b00000
+#define MSM_SMI_SIZE 0x1500000
+
+#define MSM_FB_BASE MSM_SMI_BASE
+#define MSM_PMEM_GPU0_BASE (MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_GPU0_SIZE (MSM_SMI_SIZE - MSM_FB_SIZE)
+
+#define COMET_CPLD_START 0x70004000
+#define COMET_CPLD_PER_ENABLE 0x00000010
+#define COMET_CPLD_PER_RESET 0x00000018
+#define COMET_CPLD_STATUS 0x00000028
+#define COMET_CPLD_EXT_PER_ENABLE 0x00000030
+#define COMET_CPLD_I2C_ENABLE 0x00000038
+#define COMET_CPLD_EXT_PER_RESET 0x00000048
+#define COMET_CPLD_VERSION 0x00000058
+
+#define COMET_CPLD_SIZE 0x00000060
+#define COMET_CPLD_STATUS_WVGA 0x0004
+#define COMET_CPLD_VERSION_MAJOR 0xFF00
+#define COMET_CPLD_PER_ENABLE_WVGA 0x0400
+#define COMET_CPLD_PER_ENABLE_LVDS 0x0200
+#define COMET_CPLD_PER_ENABLE_WXGA 0x0040
+#define COMET_CPLD_EXT_PER_ENABLE_WXGA 0x0080
+
+static unsigned long vreg_sts, gpio_sts;
+static struct vreg *vreg_mmc;
+static int gp6_enabled;
+
+static int cpld_version;
+static bool wvga_present;
+static bool wxga_present;
+static struct comet_cpld_t {
+ u16 per_reset_all_reset;
+ u16 ext_per_reset_all_reset;
+ u16 i2c_enable;
+ u16 per_enable_all;
+ u16 ext_per_enable_all;
+ u16 bt_reset_reg;
+ u16 bt_reset_mask;
+} comet_cpld[] = {
+ [0] = {
+ .per_reset_all_reset = 0x00FF,
+ /* enable all peripherals except microphones and */
+ /* reset line for i2c touchpad */
+ .per_enable_all = 0xFFD8,
+ .bt_reset_reg = 0x0018,
+ .bt_reset_mask = 0x0001,
+ },
+ [1] = {
+ .per_reset_all_reset = 0x00BF,
+ .ext_per_reset_all_reset = 0x0007,
+ .i2c_enable = 0x07F7,
+ /* enable all peripherals except microphones and */
+ /* displays */
+ .per_enable_all = 0xF9B8,
+ .ext_per_enable_all = 0x007D,
+ .bt_reset_reg = 0x0048,
+ .bt_reset_mask = 0x0004,
+ },
+};
+static struct comet_cpld_t *cpld_info;
+
+static struct resource smc911x_resources[] = {
+ [0] = {
+ .start = 0x84000000,
+ .end = 0x84000100,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MSM_GPIO_TO_INT(156),
+ .end = 156,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc911x_device = {
+ .name = "smc911x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc911x_resources),
+ .resource = smc911x_resources,
+};
+
+static void __iomem *comet_cpld_base(void)
+{
+ static void __iomem *comet_cpld_base_addr;
+
+ if (!comet_cpld_base_addr) {
+ if (!request_mem_region(COMET_CPLD_START, COMET_CPLD_SIZE,
+ "cpld")) {
+ printk(KERN_ERR
+ "%s: request_mem_region for comet cpld failed\n",
+ __func__);
+ goto cpld_base_exit;
+ }
+ comet_cpld_base_addr = ioremap(COMET_CPLD_START,
+ COMET_CPLD_SIZE);
+ if (!comet_cpld_base_addr) {
+ release_mem_region(COMET_CPLD_START,
+ COMET_CPLD_SIZE);
+ printk(KERN_ERR "%s: Could not map comet cpld\n",
+ __func__);
+ }
+ }
+cpld_base_exit:
+ return comet_cpld_base_addr;
+}
+
+static struct platform_device *devices[] __initdata = {
+ &msm_device_smd,
+ &msm_device_dmov,
+ &smc911x_device,
+ &msm_device_nand,
+};
+
+
+#define KBD_RST 35
+#define KBD_IRQ 144
+
+static void kbd_gpio_release(void)
+{
+ gpio_free(KBD_IRQ);
+ gpio_free(KBD_RST);
+}
+
+static int kbd_gpio_setup(void)
+{
+ int rc;
+ int respin = KBD_RST;
+ int irqpin = KBD_IRQ;
+ unsigned rescfg =
+ GPIO_CFG(respin, 0, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA);
+ unsigned irqcfg =
+ GPIO_CFG(irqpin, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA);
+
+ rc = gpio_request(irqpin, "gpio_keybd_irq");
+ if (rc) {
+ pr_err("gpio_request failed on pin %d (rc=%d)\n",
+ irqpin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_request(respin, "gpio_keybd_reset");
+ if (rc) {
+ pr_err("gpio_request failed on pin %d (rc=%d)\n",
+ respin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_tlmm_config(rescfg, GPIO_ENABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+ respin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_tlmm_config(irqcfg, GPIO_ENABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+ irqpin, rc);
+ goto err_gpioconfig;
+ }
+ return rc;
+
+err_gpioconfig:
+ kbd_gpio_release();
+ return rc;
+}
+
+static void __init comet_init_irq(void)
+{
+ msm_init_irq();
+ msm_init_sirc();
+}
+
+static void sdcc_gpio_init(void)
+{
+ /* SDC1 GPIOs */
+ if (gpio_request(51, "sdc1_data_3"))
+ pr_err("failed to request gpio sdc1_data_3\n");
+ if (gpio_request(52, "sdc1_data_2"))
+ pr_err("failed to request gpio sdc1_data_2\n");
+ if (gpio_request(53, "sdc1_data_1"))
+ pr_err("failed to request gpio sdc1_data_1\n");
+ if (gpio_request(54, "sdc1_data_0"))
+ pr_err("failed to request gpio sdc1_data_0\n");
+ if (gpio_request(55, "sdc1_cmd"))
+ pr_err("failed to request gpio sdc1_cmd\n");
+ if (gpio_request(56, "sdc1_clk"))
+ pr_err("failed to request gpio sdc1_clk\n");
+
+ /* SDC2 GPIOs */
+ if (gpio_request(62, "sdc2_clk"))
+ pr_err("failed to request gpio sdc2_clk\n");
+ if (gpio_request(63, "sdc2_cmd"))
+ pr_err("failed to request gpio sdc2_cmd\n");
+ if (gpio_request(64, "sdc2_data_3"))
+ pr_err("failed to request gpio sdc2_data_3\n");
+ if (gpio_request(65, "sdc2_data_2"))
+ pr_err("failed to request gpio sdc2_data_2\n");
+ if (gpio_request(66, "sdc2_data_1"))
+ pr_err("failed to request gpio sdc2_data_1\n");
+ if (gpio_request(67, "sdc2_data_0"))
+ pr_err("failed to request gpio sdc2_data_0\n");
+
+ /* SDC3 GPIOs */
+ if (gpio_request(88, "sdc3_clk"))
+ pr_err("failed to request gpio sdc3_clk\n");
+ if (gpio_request(89, "sdc3_cmd"))
+ pr_err("failed to request gpio sdc3_cmd\n");
+ if (gpio_request(90, "sdc3_data_3"))
+ pr_err("failed to request gpio sdc3_data_3\n");
+ if (gpio_request(91, "sdc3_data_2"))
+ pr_err("failed to request gpio sdc3_data_2\n");
+ if (gpio_request(92, "sdc3_data_1"))
+ pr_err("failed to request gpio sdc3_data_1\n");
+ if (gpio_request(93, "sdc3_data_0"))
+ pr_err("failed to request gpio sdc3_data_0\n");
+
+}
+
+static unsigned sdcc_cfg_data[][6] = {
+ /* SDC1 configs */
+ {
+ GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ },
+ /* SDC2 configs */
+ {
+ GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ /* SDC3 configs */
+ {
+ GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+};
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+ int i, rc;
+
+ if (!(test_bit(dev_id, &gpio_sts)^enable))
+ return;
+
+ if (enable)
+ set_bit(dev_id, &gpio_sts);
+ else
+ clear_bit(dev_id, &gpio_sts);
+
+ for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) {
+ rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i],
+ enable ? GPIO_ENABLE : GPIO_DISABLE);
+ if (rc)
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, sdcc_cfg_data[dev_id - 1][i], rc);
+ }
+}
+
+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);
+ msm_sdcc_setup_gpio(pdev->id, !!vdd);
+
+ if (vdd == 0) {
+ if (!vreg_sts)
+ return 0;
+
+ clear_bit(pdev->id, &vreg_sts);
+
+ if (!vreg_sts && !gp6_enabled) {
+ rc = vreg_disable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ return 0;
+ }
+
+ if (!vreg_sts && !gp6_enabled) {
+ rc = vreg_set_level(vreg_mmc, 2850);
+ if (!rc)
+ rc = vreg_enable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ set_bit(pdev->id, &vreg_sts);
+ return 0;
+}
+
+static struct mmc_platform_data comet_sdcc_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .translate_vdd = msm_sdcc_setup_power,
+};
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 8594,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 23740,
+
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 4594,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 23740,
+
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled
+ = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 443,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 1098,
+
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 2,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0,
+};
+
+static void __init comet_init(void)
+{
+ char __iomem *cpld_base;
+ int per_enable;
+ int ext_per_enable;
+
+ cpld_base = comet_cpld_base();
+
+ if (!cpld_base)
+ return;
+
+ cpld_version = (readw(cpld_base + COMET_CPLD_VERSION) &
+ COMET_CPLD_VERSION_MAJOR) >> 8;
+ if (cpld_version >= 2) {
+ cpld_info = &comet_cpld[1];
+ per_enable = cpld_info->per_enable_all;
+ wvga_present = (readw(cpld_base + COMET_CPLD_STATUS)
+ & COMET_CPLD_STATUS_WVGA) != 0;
+ wxga_present = !wvga_present;
+ ext_per_enable = cpld_info->ext_per_enable_all;
+ if (wvga_present)
+ per_enable |= COMET_CPLD_PER_ENABLE_WVGA;
+ else {
+ per_enable |= COMET_CPLD_PER_ENABLE_LVDS |
+ COMET_CPLD_PER_ENABLE_WXGA;
+ ext_per_enable |= COMET_CPLD_EXT_PER_ENABLE_WXGA;
+ }
+ writew(ext_per_enable,
+ cpld_base + COMET_CPLD_EXT_PER_ENABLE);
+ writew(cpld_info->i2c_enable,
+ cpld_base + COMET_CPLD_I2C_ENABLE);
+ writew(cpld_info->ext_per_reset_all_reset,
+ cpld_base + COMET_CPLD_EXT_PER_RESET);
+ } else {
+ cpld_info = &comet_cpld[0];
+ wvga_present = 1;
+ wxga_present = 0;
+ per_enable = cpld_info->per_enable_all;
+ smc911x_resources[0].start = 0x90000000;
+ smc911x_resources[0].end = 0x90000100;
+ }
+
+ writew(per_enable,
+ cpld_base + COMET_CPLD_PER_ENABLE);
+ writew(cpld_info->per_reset_all_reset,
+ cpld_base + COMET_CPLD_PER_RESET);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ msm_pm_set_platform_data(msm_pm_data);
+}
+
+static void __init comet_map_io(void)
+{
+ msm_map_comet_io();
+ msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
+}
+
+MACHINE_START(QSD8X50_COMET, "QCT QSD8x50 Comet")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x0,
+ .map_io = comet_map_io,
+ .init_irq = comet_init_irq,
+ .init_machine = comet_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-halibut-keypad.c b/arch/arm/mach-msm/board-halibut-keypad.c
new file mode 100644
index 000000000000..49c1075627d3
--- /dev/null
+++ b/arch/arm/mach-msm/board-halibut-keypad.c
@@ -0,0 +1,177 @@
+/* linux/arch/arm/mach-msm/board-halibut-keypad.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * 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.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_halibut."
+static int halibut_ffa;
+module_param_named(ffa, halibut_ffa, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SCAN_FUNCTION_KEYS 0 /* don't turn this on without updating the ffa support */
+
+static unsigned int halibut_row_gpios[] = {
+ 31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+ , 42
+#endif
+};
+
+static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col))
+
+static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_5,
+ [KEYMAP_INDEX(0, 1)] = KEY_9,
+ [KEYMAP_INDEX(0, 2)] = 229, /* SOFT1 */
+ [KEYMAP_INDEX(0, 3)] = KEY_6,
+ [KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_0,
+ [KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+ [KEYMAP_INDEX(1, 2)] = KEY_1,
+ [KEYMAP_INDEX(1, 3)] = 228, /* KEY_SHARP */
+ [KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+ [KEYMAP_INDEX(2, 1)] = KEY_HOME, /* FA */
+ [KEYMAP_INDEX(2, 2)] = KEY_F8, /* QCHT */
+ [KEYMAP_INDEX(2, 3)] = KEY_F6, /* R+ */
+ [KEYMAP_INDEX(2, 4)] = KEY_F7, /* R- */
+
+ [KEYMAP_INDEX(3, 0)] = KEY_UP,
+ [KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+ [KEYMAP_INDEX(3, 2)] = KEY_4,
+ [KEYMAP_INDEX(3, 3)] = KEY_MUTE, /* SPKR */
+ [KEYMAP_INDEX(3, 4)] = KEY_2,
+
+ [KEYMAP_INDEX(4, 0)] = 230, /* SOFT2 */
+ [KEYMAP_INDEX(4, 1)] = 232, /* KEY_CENTER */
+ [KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+ [KEYMAP_INDEX(4, 3)] = KEY_BACK, /* FB */
+ [KEYMAP_INDEX(4, 4)] = KEY_8,
+
+ [KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */
+ [KEYMAP_INDEX(5, 2)] = KEY_MAIL, /* MESG */
+ [KEYMAP_INDEX(5, 3)] = KEY_3,
+ [KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+ [KEYMAP_INDEX(6, 0)] = KEY_F5,
+ [KEYMAP_INDEX(6, 1)] = KEY_F4,
+ [KEYMAP_INDEX(6, 2)] = KEY_F3,
+ [KEYMAP_INDEX(6, 3)] = KEY_F2,
+ [KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short halibut_keymap_ffa[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
+ /*[KEYMAP_INDEX(0, 0)] = ,*/
+ /*[KEYMAP_INDEX(0, 1)] = ,*/
+ [KEYMAP_INDEX(0, 2)] = KEY_1,
+ [KEYMAP_INDEX(0, 3)] = KEY_SEND,
+ [KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_3,
+ [KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+ [KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+ /*[KEYMAP_INDEX(1, 3)] = ,*/
+ [KEYMAP_INDEX(1, 4)] = KEY_6,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */
+ [KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */
+ [KEYMAP_INDEX(2, 2)] = KEY_0,
+ [KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */
+ [KEYMAP_INDEX(2, 4)] = KEY_9,
+
+ [KEYMAP_INDEX(3, 0)] = KEY_UP,
+ [KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+ [KEYMAP_INDEX(3, 2)] = KEY_4,
+ /*[KEYMAP_INDEX(3, 3)] = ,*/
+ [KEYMAP_INDEX(3, 4)] = KEY_2,
+
+ [KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+ [KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+ [KEYMAP_INDEX(4, 3)] = KEY_8,
+ [KEYMAP_INDEX(4, 4)] = KEY_5,
+
+ /*[KEYMAP_INDEX(5, 0)] = ,*/
+ [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */
+ [KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+ [KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */
+ [KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static struct gpio_event_matrix_info halibut_matrix_info = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = halibut_keymap,
+ .output_gpios = halibut_row_gpios,
+ .input_gpios = halibut_col_gpios,
+ .noutputs = ARRAY_SIZE(halibut_row_gpios),
+ .ninputs = ARRAY_SIZE(halibut_col_gpios),
+ .settle_time.tv.nsec = 0,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE | GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+struct gpio_event_info *halibut_keypad_info[] = {
+ &halibut_matrix_info.info
+};
+
+static struct gpio_event_platform_data halibut_keypad_data = {
+ .name = "halibut_keypad",
+ .info = halibut_keypad_info,
+ .info_count = ARRAY_SIZE(halibut_keypad_info)
+};
+
+static struct platform_device halibut_keypad_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &halibut_keypad_data,
+ },
+};
+
+static int __init halibut_init_keypad(void)
+{
+ if (!machine_is_halibut())
+ return 0;
+ if (halibut_ffa)
+ halibut_matrix_info.keymap = halibut_keymap_ffa;
+ return platform_device_register(&halibut_keypad_device);
+}
+
+device_initcall(halibut_init_keypad);
diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
index e61967dde9a1..537516723f16 100644
--- a/arch/arm/mach-msm/board-halibut.c
+++ b/arch/arm/mach-msm/board-halibut.c
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/board-halibut.c
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -13,33 +14,64 @@
* GNU General Public License for more details.
*
*/
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/i2c.h>
+#include <linux/android_pmem.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
#include <mach/hardware.h>
+#include <mach/irqs.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#include <asm/mach/mmc.h>
+#include <mach/vreg.h>
+#include <mach/mpp.h>
+#include <mach/gpio.h>
#include <mach/irqs.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
-
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/msm_hsusb.h>
+#include <mach/vreg.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/memory.h>
+#include <mach/camera.h>
#include "devices.h"
+#include "socinfo.h"
+#include "clock.h"
+#include "msm-keypad-devices.h"
+#include "pm.h"
+
+#ifdef CONFIG_MSM_STACKED_MEMORY
+#define MSM_SMI_BASE 0x100000
+#define MSM_SMI_SIZE 0x800000
+
+#define MSM_PMEM_GPU0_BASE MSM_SMI_BASE
+#define MSM_PMEM_GPU0_SIZE 0x800000
+#endif
+
+#define MSM_PMEM_MDP_SIZE 0x800000
+#define MSM_PMEM_CAMERA_SIZE 0xa00000
+#define MSM_PMEM_ADSP_SIZE 0x800000
+#define MSM_PMEM_GPU1_SIZE 0x800000
+#define MSM_FB_SIZE 0x200000
static struct resource smc91x_resources[] = {
[0] = {
.start = 0x9C004300,
- .end = 0x9C004400,
+ .end = 0x9C0043ff,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -49,6 +81,132 @@ static struct resource smc91x_resources[] = {
},
};
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_mass_storage_platform_data usb_mass_storage_pdata = {
+ .nluns = 0x02,
+ .buf_size = 16384,
+ .vendor = "GOOGLE",
+ .product = "Mass storage",
+ .release = 0xffff,
+};
+
+static struct platform_device mass_storage_device = {
+ .name = "usb_mass_storage",
+ .id = -1,
+ .dev = {
+ .platform_data = &usb_mass_storage_pdata,
+ },
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x05C6,
+ .product_id = 0xF000,
+ .adb_product_id = 0x9015,
+ .version = 0x0100,
+ .product_name = "Qualcomm HSUSB Device",
+ .manufacturer_name = "Qualcomm Incorporated",
+ .nluns = 1,
+};
+
+static struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+#endif
+
+#ifdef CONFIG_USB_FUNCTION
+static void hsusb_gpio_init(void)
+{
+ if (gpio_request(111, "ulpi_data_0"))
+ pr_err("failed to request gpio ulpi_data_0\n");
+ if (gpio_request(112, "ulpi_data_1"))
+ pr_err("failed to request gpio ulpi_data_1\n");
+ if (gpio_request(113, "ulpi_data_2"))
+ pr_err("failed to request gpio ulpi_data_2\n");
+ if (gpio_request(114, "ulpi_data_3"))
+ pr_err("failed to request gpio ulpi_data_3\n");
+ if (gpio_request(115, "ulpi_data_4"))
+ pr_err("failed to request gpio ulpi_data_4\n");
+ if (gpio_request(116, "ulpi_data_5"))
+ pr_err("failed to request gpio ulpi_data_5\n");
+ if (gpio_request(117, "ulpi_data_6"))
+ pr_err("failed to request gpio ulpi_data_6\n");
+ if (gpio_request(118, "ulpi_data_7"))
+ pr_err("failed to request gpio ulpi_data_7\n");
+ if (gpio_request(119, "ulpi_dir"))
+ pr_err("failed to request gpio ulpi_dir\n");
+ if (gpio_request(120, "ulpi_next"))
+ pr_err("failed to request gpio ulpi_next\n");
+ if (gpio_request(121, "ulpi_stop"))
+ pr_err("failed to request gpio ulpi_stop\n");
+}
+
+static unsigned usb_gpio_lpm_config[] = {
+ GPIO_CFG(111, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 0 */
+ GPIO_CFG(112, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 1 */
+ GPIO_CFG(113, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 2 */
+ GPIO_CFG(114, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 3 */
+ GPIO_CFG(115, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 4 */
+ GPIO_CFG(116, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 5 */
+ GPIO_CFG(117, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 6 */
+ GPIO_CFG(118, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DATA 7 */
+ GPIO_CFG(119, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* DIR */
+ GPIO_CFG(120, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* NEXT */
+ GPIO_CFG(121, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* STOP */
+};
+
+static unsigned usb_gpio_lpm_unconfig[] = {
+ GPIO_CFG(111, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 0 */
+ GPIO_CFG(112, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 1 */
+ GPIO_CFG(113, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 2 */
+ GPIO_CFG(114, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 3 */
+ GPIO_CFG(115, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 4 */
+ GPIO_CFG(116, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 5 */
+ GPIO_CFG(117, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 6 */
+ GPIO_CFG(118, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DATA 7 */
+ GPIO_CFG(119, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DIR */
+ GPIO_CFG(120, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* NEXT */
+ GPIO_CFG(121, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_2MA), /* STOP */
+};
+
+static int usb_config_gpio(int config)
+{
+ int pin, rc;
+
+ if (config) {
+ for (pin = 0; pin < ARRAY_SIZE(usb_gpio_lpm_config); pin++) {
+ rc = gpio_tlmm_config(usb_gpio_lpm_config[pin],
+ GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, usb_gpio_lpm_config[pin], rc);
+ return -EIO;
+ }
+ }
+ } else {
+ for (pin = 0; pin < ARRAY_SIZE(usb_gpio_lpm_unconfig); pin++) {
+ rc = gpio_tlmm_config(usb_gpio_lpm_unconfig[pin],
+ GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, usb_gpio_lpm_config[pin], rc);
+ return -EIO;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+
static struct platform_device smc91x_device = {
.name = "smc91x",
.id = 0,
@@ -57,33 +215,565 @@ static struct platform_device smc91x_device = {
};
static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
&msm_device_uart3,
+#endif
+ &msm_device_uart_dm1,
&msm_device_smd,
+ &msm_device_dmov,
&msm_device_nand,
- &msm_device_hsusb,
&msm_device_i2c,
&smc91x_device,
+ &msm_device_tssc,
+ &android_pmem_camera_device,
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+#ifdef CONFIG_MSM_STACKED_MEMORY
+ &android_pmem_gpu0_device,
+#endif
+ &android_pmem_gpu1_device,
+ &msm_device_hsusb_otg,
+ &msm_device_hsusb_host,
+#if defined(CONFIG_USB_FUNCTION) || defined(CONFIG_USB_ANDROID)
+ &msm_device_hsusb_peripheral,
+#endif
+#ifdef CONFIG_USB_FUNCTION
+ &mass_storage_device,
+#endif
+#ifdef CONFIG_USB_ANDROID
+ &android_usb_device,
+#endif
+
+#ifdef CONFIG_BT
+ &msm_bt_power_device,
+#endif
+ &halibut_snd,
+ &msm_bluesleep_device,
+ &msm_fb_device,
+ &mddi_toshiba_device,
+ &mddi_sharp_device,
};
extern struct sys_timer msm_timer;
+static struct i2c_board_info i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
+ },
+ {
+ I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+ },
+ {
+ I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+ },
+ {
+ I2C_BOARD_INFO("mt9t013", 0x6C),
+ },
+};
+
+static uint32_t camera_off_gpio_table[] = {
+ /* parallel CAMERA interfaces */
+ GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+ GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+ GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */
+ GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+ /* parallel CAMERA interfaces */
+ GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+ GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+ GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+ GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n, rc;
+ for (n = 0; n < len; n++) {
+ rc = gpio_tlmm_config(table[n], GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, table[n], rc);
+ break;
+ }
+ }
+}
+
+static void config_camera_on_gpios(void)
+{
+ config_gpio_table(camera_on_gpio_table,
+ ARRAY_SIZE(camera_on_gpio_table));
+}
+
+static void config_camera_off_gpios(void)
+{
+ config_gpio_table(camera_off_gpio_table,
+ ARRAY_SIZE(camera_off_gpio_table));
+}
+
+#define MSM_PROBE_INIT(name) name##_probe_init
+static struct msm_camera_sensor_info msm_camera_sensor[] = {
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "mt9d112",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9d112),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "s5k3e2fx",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(s5k3e2fx),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 88,
+ .sensor_name = "mt9p012",
+ .flash_type = MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9p012),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "mt9t013",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9t013),
+#endif
+ },
+};
+#undef MSM_PROBE_INIT
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+ .camera_gpio_on = config_camera_on_gpios,
+ .camera_gpio_off = config_camera_off_gpios,
+ .snum = ARRAY_SIZE(msm_camera_sensor),
+ .sinfo = &msm_camera_sensor[0],
+ .ioext.mdcphy = MSM_MDC_PHYS,
+ .ioext.mdcsz = MSM_MDC_SIZE,
+ .ioext.appphy = MSM_CLK_CTL_PHYS,
+ .ioext.appsz = MSM_CLK_CTL_SIZE,
+};
+
+static void __init msm_camera_add_device(void)
+{
+ msm_camera_register_device(NULL, 0, &msm_camera_device_data);
+ config_camera_off_gpios();
+}
+
static void __init halibut_init_irq(void)
{
msm_init_irq();
}
+static struct msm_acpu_clock_platform_data halibut_clock_data = {
+ .acpu_switch_time_us = 50,
+ .max_speed_delta_khz = 256000,
+ .vdd_switch_time_us = 62,
+ .power_collapse_khz = 19200000,
+ .wait_for_irq_khz = 128000000,
+ .max_axi_khz = 128000,
+};
+
+void msm_serial_debug_init(unsigned int base, int irq,
+ struct device *clk_device, int signal_irq);
+static void sdcc_gpio_init(void)
+{
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ int rc = 0;
+ if (gpio_request(49, "sdc1_status_irq"))
+ pr_err("failed to request gpio sdc1_status_irq\n");
+ rc = gpio_tlmm_config(GPIO_CFG(49, 0, GPIO_INPUT, GPIO_PULL_UP,
+ GPIO_2MA), GPIO_ENABLE);
+ if (rc)
+ printk(KERN_ERR "%s: Failed to configure GPIO %d\n",
+ __func__, rc);
+#endif
+ /* SDC1 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ if (gpio_request(51, "sdc1_data_3"))
+ pr_err("failed to request gpio sdc1_data_3\n");
+ if (gpio_request(52, "sdc1_data_2"))
+ pr_err("failed to request gpio sdc1_data_2\n");
+ if (gpio_request(53, "sdc1_data_1"))
+ pr_err("failed to request gpio sdc1_data_1\n");
+ if (gpio_request(54, "sdc1_data_0"))
+ pr_err("failed to request gpio sdc1_data_0\n");
+ if (gpio_request(55, "sdc1_cmd"))
+ pr_err("failed to request gpio sdc1_cmd\n");
+ if (gpio_request(56, "sdc1_clk"))
+ pr_err("failed to request gpio sdc1_clk\n");
+#endif
+
+ if (machine_is_msm7201a_ffa())
+ return;
+
+ /* SDC2 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ if (gpio_request(62, "sdc2_clk"))
+ pr_err("failed to request gpio sdc2_clk\n");
+ if (gpio_request(63, "sdc2_cmd"))
+ pr_err("failed to request gpio sdc2_cmd\n");
+ if (gpio_request(64, "sdc2_data_3"))
+ pr_err("failed to request gpio sdc2_data_3\n");
+ if (gpio_request(65, "sdc2_data_2"))
+ pr_err("failed to request gpio sdc2_data_2\n");
+ if (gpio_request(66, "sdc2_data_1"))
+ pr_err("failed to request gpio sdc2_data_1\n");
+ if (gpio_request(67, "sdc2_data_0"))
+ pr_err("failed to request gpio sdc2_data_0\n");
+#endif
+
+ /* SDC4 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ if (gpio_request(19, "sdc4_data_3"))
+ pr_err("failed to request gpio sdc4_data_3\n");
+ if (gpio_request(20, "sdc4_data_2"))
+ pr_err("failed to request gpio sdc4_data_2\n");
+ if (gpio_request(21, "sdc4_data_1"))
+ pr_err("failed to request gpio sdc4_data_1\n");
+ if (gpio_request(107, "sdc4_cmd"))
+ pr_err("failed to request gpio sdc4_cmd\n");
+ if (gpio_request(108, "sdc4_data_0"))
+ pr_err("failed to request gpio sdc4_data_0\n");
+ if (gpio_request(109, "sdc4_clk"))
+ pr_err("failed to request gpio sdc4_clk\n");
+#endif
+}
+
+static unsigned sdcc_cfg_data[][6] = {
+ /* SDC1 configs */
+ {
+ GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ },
+ /* SDC2 configs */
+ {
+ GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ {
+ /* SDC3 configs */
+ },
+ /* SDC4 configs */
+ {
+ GPIO_CFG(19, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(20, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(21, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(107, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(108, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(109, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ }
+};
+
+static unsigned long vreg_sts, gpio_sts;
+static struct mpp *mpp_mmc;
+static struct vreg *vreg_mmc;
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+ int i, rc;
+
+ if (!(test_bit(dev_id, &gpio_sts)^enable))
+ return;
+
+ if (enable)
+ set_bit(dev_id, &gpio_sts);
+ else
+ clear_bit(dev_id, &gpio_sts);
+
+ for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) {
+ rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i],
+ enable ? GPIO_ENABLE : GPIO_DISABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, sdcc_cfg_data[dev_id - 1][i], rc);
+ }
+ }
+}
+
+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);
+ msm_sdcc_setup_gpio(pdev->id, !!vdd);
+
+ if (vdd == 0) {
+ if (!vreg_sts)
+ return 0;
+
+ clear_bit(pdev->id, &vreg_sts);
+
+ if (!vreg_sts) {
+ if (machine_is_msm7201a_ffa())
+ rc = mpp_config_digital_out(mpp_mmc,
+ MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+ MPP_DLOGIC_OUT_CTRL_LOW));
+ else
+ rc = vreg_disable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ return 0;
+ }
+
+ if (!vreg_sts) {
+ if (machine_is_msm7201a_ffa())
+ rc = mpp_config_digital_out(mpp_mmc,
+ MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+ MPP_DLOGIC_OUT_CTRL_HIGH));
+ else {
+ rc = vreg_set_level(vreg_mmc, 2850);
+ if (!rc)
+ rc = vreg_enable(vreg_mmc);
+ }
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ set_bit(pdev->id, &vreg_sts);
+ return 0;
+}
+
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+static unsigned int halibut_sdcc_slot_status(struct device *dev)
+{
+ return (unsinged int) gpio_get_value(49);
+}
+#endif
+
+static struct mmc_platform_data halibut_sdcc_data = {
+ .ocr_mask = MMC_VDD_28_29,
+ .translate_vdd = msm_sdcc_setup_power,
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+ .status = halibut_sdcc_slot_status,
+ .status_irq = MSM_GPIO_TO_INT(49),
+ .irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+};
+
+static void __init halibut_init_mmc(void)
+{
+ if (machine_is_msm7201a_ffa()) {
+ mpp_mmc = mpp_get(NULL, "mpp3");
+ if (!mpp_mmc) {
+ printk(KERN_ERR "%s: mpp get failed (%ld)\n",
+ __func__, PTR_ERR(vreg_mmc));
+ return;
+ }
+ } else {
+ vreg_mmc = vreg_get(NULL, "mmc");
+ if (IS_ERR(vreg_mmc)) {
+ printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+ __func__, PTR_ERR(vreg_mmc));
+ return;
+ }
+ }
+
+ sdcc_gpio_init();
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ msm_add_sdcc(1, &halibut_sdcc_data);
+#endif
+
+ if (machine_is_msm7201a_surf()) {
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ msm_add_sdcc(2, &halibut_sdcc_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ msm_add_sdcc(4, &halibut_sdcc_data);
+#endif
+ }
+}
+
+static struct msm_panel_common_pdata mdp_pdata = {
+ .gpio = 97,
+};
+
+static void __init msm_fb_add_devices(void)
+{
+ msm_fb_register_device("mdp", &mdp_pdata);
+ msm_fb_register_device("ebi2", 0);
+ msm_fb_register_device("pmdh", &mddi_pdata);
+ msm_fb_register_device("emdh", 0);
+ msm_fb_register_device("tvenc", &tvenc_pdata);
+}
+
+static struct msm_i2c_platform_data msm_i2c_pdata = {
+ .clk_freq = 100000,
+};
+
+static void __init msm_device_i2c_init(void)
+{
+ msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
+}
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000,
+};
+
static void __init halibut_init(void)
{
+ if (socinfo_init() < 0)
+ BUG();
+
+ if (machine_is_msm7201a_ffa()) {
+ smc91x_resources[0].start = 0x98000300;
+ smc91x_resources[0].end = 0x980003ff;
+ smc91x_resources[1].start = MSM_GPIO_TO_INT(85);
+ smc91x_resources[1].end = MSM_GPIO_TO_INT(85);
+ }
+
+ /* All 7x01 2.0 based boards are expected to have RAM chips capable
+ * of 160 MHz. */
+ if (cpu_is_msm7x01()
+ && SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2)
+ halibut_clock_data.max_axi_khz = 160000;
+
+ msm_acpu_clock_init(&halibut_clock_data);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+ &msm_device_uart3.dev, 1);
+#endif
+ msm_hsusb_pdata.soc_version = socinfo_get_version();
+ msm_acpu_clock_init(&halibut_clock_data);
+ msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata,
+ msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata,
platform_add_devices(devices, ARRAY_SIZE(devices));
+ halibut_init_mmc();
+ msm_pm_set_platform_data(msm_pm_data);
+}
+
+static void __init msm_halibut_allocate_memory_regions(void)
+{
+ void *addr;
+ unsigned long size;
+
+ size = MSM_PMEM_MDP_SIZE;
+ addr = alloc_bootmem(size);
+ android_pmem_pdata.start = __pa(addr);
+ android_pmem_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for pmem\n", size, addr, __pa(addr));
+
+ size = MSM_PMEM_CAMERA_SIZE;
+ addr = alloc_bootmem(size);
+ android_pmem_camera_pdata.start = __pa(addr);
+ android_pmem_camera_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for camera pmem\n", size, addr, __pa(addr));
+
+ size = MSM_PMEM_ADSP_SIZE;
+ addr = alloc_bootmem(size);
+ android_pmem_adsp_pdata.start = __pa(addr);
+ android_pmem_adsp_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for adsp pmem\n", size, addr, __pa(addr));
+
+ size = MSM_PMEM_GPU1_SIZE;
+ addr = alloc_bootmem_aligned(size, 0x100000);
+ android_pmem_gpu1_pdata.start = __pa(addr);
+ android_pmem_gpu1_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for gpu1 pmem\n", size, addr, __pa(addr));
+
+ size = MSM_FB_SIZE;
+ addr = alloc_bootmem(size);
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical) for fb\n",
+ size, addr, __pa(addr));
+
}
static void __init halibut_map_io(void)
{
+ msm_shared_ram_phys = 0x01F00000;
+
msm_map_common_io();
- msm_clock_init();
+ msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a);
+ msm_halibut_allocate_memory_regions();
}
MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x10000100,
+ .map_io = halibut_map_io,
+ .init_irq = halibut_init_irq,
+ .init_machine = halibut_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM7201A_FFA, "QCT FFA7201A Board")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x10000100,
+ .map_io = halibut_map_io,
+ .init_irq = halibut_init_irq,
+ .init_machine = halibut_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM7201A_SURF, "QCT SURF7201A Board")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
.boot_params = 0x10000100,
.map_io = halibut_map_io,
.init_irq = halibut_init_irq,
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
new file mode 100644
index 000000000000..32cdf4cabc72
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/usb/mass_storage_function.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#ifdef CONFIG_CACHE_L2X0
+#include <asm/hardware/cache-l2x0.h>
+#endif
+
+#include <asm/mach/mmc.h>
+#include <mach/vreg.h>
+#include <mach/mpp.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_hsusb.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/memory.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
+#include <linux/android_pmem.h>
+#include <mach/camera.h>
+
+#include "devices.h"
+#include "socinfo.h"
+#include "clock.h"
+#include "msm-keypad-devices.h"
+#include "pm.h"
+
+#define MSM_PMEM_MDP_SIZE 0x800000
+#define MSM_PMEM_ADSP_SIZE 0x800000
+#define MSM_PMEM_GPU1_SIZE 0x800000
+#define MSM_FB_SIZE 0x200000
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x9C004300,
+ .end = 0x9C0043ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MSM_GPIO_TO_INT(132),
+ .end = MSM_GPIO_TO_INT(132),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct usb_mass_storage_platform_data usb_mass_storage_pdata = {
+ .nluns = 0x02,
+ .buf_size = 16384,
+ .vendor = "GOOGLE",
+ .product = "Mass storage",
+ .release = 0xffff,
+};
+
+static struct platform_device mass_storage_device = {
+ .name = "usb_mass_storage",
+ .id = -1,
+ .dev = {
+ .platform_data = &usb_mass_storage_pdata,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct usb_function_map usb_functions_map[] = {
+ {"diag", 0},
+ {"adb", 1},
+ {"modem", 2},
+ {"nmea", 3},
+ {"mass_storage", 4},
+ {"ethernet", 5},
+};
+
+/* dynamic composition */
+static struct usb_composition usb_func_composition[] = {
+ {
+ .product_id = 0x9012,
+ .functions = 0x5, /* 0101 */
+ },
+
+ {
+ .product_id = 0x9013,
+ .functions = 0x15, /* 10101 */
+ },
+
+ {
+ .product_id = 0x9014,
+ .functions = 0x30, /* 110000 */
+ },
+
+ {
+ .product_id = 0x9016,
+ .functions = 0xD, /* 01101 */
+ },
+
+ {
+ .product_id = 0x9017,
+ .functions = 0x1D, /* 11101 */
+ },
+
+ {
+ .product_id = 0xF000,
+ .functions = 0x10, /* 10000 */
+ },
+
+ {
+ .product_id = 0xF009,
+ .functions = 0x20, /* 100000 */
+ },
+
+ {
+ .product_id = 0x9018,
+ .functions = 0x1F, /* 011111 */
+ },
+
+};
+
+static struct msm_hsusb_platform_data msm_hsusb_pdata = {
+ .version = 0x0100,
+ .phy_info = (USB_PHY_INTEGRATED | USB_PHY_MODEL_65NM),
+ .vendor_id = 0x5c6,
+ .product_name = "Qualcomm HSUSB Device",
+ .serial_number = "1234567890ABCDEF",
+ .manufacturer_name = "Qualcomm Incorporated",
+ .compositions = usb_func_composition,
+ .num_compositions = ARRAY_SIZE(usb_func_composition),
+ .function_map = usb_functions_map,
+ .num_functions = ARRAY_SIZE(usb_functions_map),
+};
+
+#define SND(desc, num) { .name = #desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+ SND(HANDSET, 0),
+ SND(MONO_HEADSET, 2),
+ SND(HEADSET, 3),
+ SND(SPEAKER, 6),
+ SND(TTY_HEADSET, 8),
+ SND(TTY_VCO, 9),
+ SND(TTY_HCO, 10),
+ SND(BT, 12),
+ SND(IN_S_SADC_OUT_HANDSET, 16),
+ SND(IN_S_SADC_OUT_SPEAKER_PHONE, 25),
+ SND(CURRENT, 27),
+};
+#undef SND
+
+static struct msm_snd_endpoints msm_device_snd_endpoints = {
+ .endpoints = snd_endpoints_list,
+ .num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
+};
+
+static struct platform_device msm_device_snd = {
+ .name = "msm_snd",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_device_snd_endpoints
+ },
+};
+
+#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
+ (1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
+ (1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
+ (1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
+ (1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
+ (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_WAV)|(1<<MSM_ADSP_CODEC_ADPCM)| \
+ (1<<MSM_ADSP_CODEC_YADPCM)|(1<<MSM_ADSP_CODEC_QCELP)| \
+ (1<<MSM_ADSP_CODEC_MP3))
+#define DEC2_FORMAT ((1<<MSM_ADSP_CODEC_WAV)|(1<<MSM_ADSP_CODEC_ADPCM)| \
+ (1<<MSM_ADSP_CODEC_YADPCM)|(1<<MSM_ADSP_CODEC_QCELP)| \
+ (1<<MSM_ADSP_CODEC_MP3))
+#define DEC3_FORMAT ((1<<MSM_ADSP_CODEC_WAV)|(1<<MSM_ADSP_CODEC_ADPCM)| \
+ (1<<MSM_ADSP_CODEC_YADPCM)|(1<<MSM_ADSP_CODEC_QCELP))
+#define DEC4_FORMAT (1<<MSM_ADSP_CODEC_MIDI)
+
+static unsigned int dec_concurrency_table[] = {
+ /* Audio LP */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DMA)), 0,
+ 0, 0, 0,
+
+ /* Concurrency 1 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+
+ /* Concurrency 2 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+
+ /* Concurrency 3 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+
+ /* Concurrency 4 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+
+ /* Concurrency 5 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+
+ /* Concurrency 6 */
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC2_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC3_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ (DEC4_FORMAT),
+};
+
+#define DEC_INFO(name, queueid, decid, nr_codec) { .module_name = name, \
+ .module_queueid = queueid, .module_decid = decid, \
+ .nr_codec_support = nr_codec}
+
+static struct msm_adspdec_info dec_info_list[] = {
+ DEC_INFO("AUDPLAY0TASK", 13, 0, 11), /* AudPlay0BitStreamCtrlQueue */
+ DEC_INFO("AUDPLAY1TASK", 14, 1, 5), /* AudPlay1BitStreamCtrlQueue */
+ DEC_INFO("AUDPLAY2TASK", 15, 2, 5), /* AudPlay2BitStreamCtrlQueue */
+ DEC_INFO("AUDPLAY3TASK", 16, 3, 4), /* AudPlay3BitStreamCtrlQueue */
+ DEC_INFO("AUDPLAY4TASK", 17, 4, 1), /* AudPlay4BitStreamCtrlQueue */
+};
+
+static struct msm_adspdec_database msm_device_adspdec_database = {
+ .num_dec = ARRAY_SIZE(dec_info_list),
+ .num_concurrency_support = (ARRAY_SIZE(dec_concurrency_table) / \
+ ARRAY_SIZE(dec_info_list)),
+ .dec_concurrency_table = dec_concurrency_table,
+ .dec_info_list = dec_info_list,
+};
+
+static struct platform_device msm_device_adspdec = {
+ .name = "msm_adspdec",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_device_adspdec_database
+ },
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem",
+ .no_allocator = 0,
+ .cached = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+ .name = "pmem_adsp",
+ .no_allocator = 0,
+ .cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu1_pdata = {
+ .name = "pmem_gpu1",
+ .no_allocator = 1,
+ .cached = 0,
+};
+
+static struct platform_device android_pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+ .dev = { .platform_data = &android_pmem_pdata },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+ .name = "android_pmem",
+ .id = 1,
+ .dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_gpu1_device = {
+ .name = "android_pmem",
+ .id = 3,
+ .dev = { .platform_data = &android_pmem_gpu1_pdata },
+};
+
+#define LCDC_CONFIG_PROC 21
+#define LCDC_UN_CONFIG_PROC 22
+#define LCDC_API_PROG 0x30000066
+#define LCDC_API_VERS 0x00010001
+
+#define GPIO_OUT_132 132
+#define GPIO_OUT_131 131
+#define GPIO_OUT_103 103
+#define GPIO_OUT_102 102
+#define GPIO_OUT_88 88
+
+static struct msm_rpc_endpoint *lcdc_ep;
+
+static int msm_fb_lcdc_config(int on)
+{
+ int rc = 0;
+ struct rpc_request_hdr hdr;
+
+ if (on)
+ printk(KERN_INFO "lcdc config\n");
+ else
+ printk(KERN_INFO "lcdc un-config\n");
+
+ lcdc_ep = msm_rpc_connect_compatible(LCDC_API_PROG, LCDC_API_VERS, 0);
+ if (IS_ERR(lcdc_ep)) {
+ printk(KERN_ERR "%s: msm_rpc_connect failed! rc = %ld\n",
+ __func__, PTR_ERR(lcdc_ep));
+ return -EINVAL;
+ }
+
+ rc = msm_rpc_call(lcdc_ep,
+ (on) ? LCDC_CONFIG_PROC : LCDC_UN_CONFIG_PROC,
+ &hdr, sizeof(hdr),
+ 5 * HZ);
+ if (rc)
+ printk(KERN_ERR
+ "%s: msm_rpc_call failed! rc = %d\n", __func__, rc);
+
+ msm_rpc_close(lcdc_ep);
+ return rc;
+}
+
+static int gpio_array_num[] = {
+ GPIO_OUT_132, /* spi_clk */
+ GPIO_OUT_131, /* spi_cs */
+ GPIO_OUT_103, /* spi_sdi */
+ GPIO_OUT_102, /* spi_sdoi */
+ GPIO_OUT_88
+ };
+
+static void lcdc_gordon_gpio_init(void)
+{
+ if (gpio_request(GPIO_OUT_132, "spi_clk"))
+ pr_err("failed to request gpio spi_clk\n");
+ if (gpio_request(GPIO_OUT_131, "spi_cs"))
+ pr_err("failed to request gpio spi_cs\n");
+ if (gpio_request(GPIO_OUT_103, "spi_sdi"))
+ pr_err("failed to request gpio spi_sdi\n");
+ if (gpio_request(GPIO_OUT_102, "spi_sdoi"))
+ pr_err("failed to request gpio spi_sdoi\n");
+ if (gpio_request(GPIO_OUT_88, "gpio_dac"))
+ pr_err("failed to request gpio_dac\n");
+}
+
+static uint32_t lcdc_gpio_table[] = {
+ GPIO_CFG(GPIO_OUT_132, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+ GPIO_CFG(GPIO_OUT_131, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+ GPIO_CFG(GPIO_OUT_103, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+ GPIO_CFG(GPIO_OUT_102, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+ GPIO_CFG(GPIO_OUT_88, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+};
+
+static void config_lcdc_gpio_table(uint32_t *table, int len, unsigned enable)
+{
+ int n, rc;
+ for (n = 0; n < len; n++) {
+ rc = gpio_tlmm_config(table[n],
+ enable ? GPIO_ENABLE : GPIO_DISABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, table[n], rc);
+ break;
+ }
+ }
+}
+
+static void lcdc_gordon_config_gpios(int enable)
+{
+ config_lcdc_gpio_table(lcdc_gpio_table,
+ ARRAY_SIZE(lcdc_gpio_table), enable);
+}
+
+static struct lcdc_platform_data lcdc_pdata = {
+ .lcdc_gpio_config = msm_fb_lcdc_config
+};
+
+static struct msm_panel_common_pdata lcdc_gordon_panel_data = {
+ .panel_config_gpio = lcdc_gordon_config_gpios,
+ .gpio_num = gpio_array_num,
+};
+
+static struct platform_device lcdc_gordon_panel_device = {
+ .name = "lcdc_gordon_vga",
+ .id = 0,
+ .dev = {
+ .platform_data = &lcdc_gordon_panel_data,
+ }
+};
+
+static struct resource msm_fb_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+ int ret = -EPERM;
+
+ if (machine_is_msm7x27_ffa() || machine_is_msm7x27_ffa()) {
+ if (!strcmp(name, "lcdc_gordon_vga"))
+ ret = 0;
+ else
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+ .detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+ .name = "msm_fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_fb_resources),
+ .resource = msm_fb_resources,
+ .dev = {
+ .platform_data = &msm_fb_pdata,
+ }
+};
+
+#ifdef CONFIG_BT
+static struct platform_device msm_bt_power_device = {
+ .name = "bt_power",
+};
+
+enum {
+ BT_WAKE,
+ BT_RFR,
+ BT_CTS,
+ BT_RX,
+ BT_TX,
+ BT_PCM_DOUT,
+ BT_PCM_DIN,
+ BT_PCM_SYNC,
+ BT_PCM_CLK,
+ BT_HOST_WAKE,
+};
+
+static unsigned bt_config_power_on[] = {
+ GPIO_CFG(42, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* WAKE */
+ GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* RFR */
+ GPIO_CFG(44, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* CTS */
+ GPIO_CFG(45, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* Rx */
+ GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* Tx */
+ GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DOUT */
+ GPIO_CFG(69, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_DIN */
+ GPIO_CFG(70, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_SYNC */
+ GPIO_CFG(71, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* PCM_CLK */
+ GPIO_CFG(83, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), /* HOST_WAKE */
+};
+static unsigned bt_config_power_off[] = {
+ GPIO_CFG(42, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* WAKE */
+ GPIO_CFG(43, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* RFR */
+ GPIO_CFG(44, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* CTS */
+ GPIO_CFG(45, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Rx */
+ GPIO_CFG(46, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* Tx */
+ GPIO_CFG(68, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DOUT */
+ GPIO_CFG(69, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_DIN */
+ GPIO_CFG(70, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_SYNC */
+ GPIO_CFG(71, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCM_CLK */
+ GPIO_CFG(83, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HOST_WAKE */
+};
+
+static int bluetooth_power(int on)
+{
+ struct vreg *vreg_bt;
+ int pin, rc;
+
+ printk(KERN_DEBUG "%s\n", __func__);
+
+ /* do not have vreg bt defined, gp6 is the same */
+ /* vreg_get parameter 1 (struct device *) is ignored */
+ vreg_bt = vreg_get(NULL, "gp6");
+
+ if (IS_ERR(vreg_bt)) {
+ printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+ __func__, PTR_ERR(vreg_bt));
+ return PTR_ERR(vreg_bt);
+ }
+
+ if (on) {
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on); pin++) {
+ rc = gpio_tlmm_config(bt_config_power_on[pin],
+ GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, bt_config_power_on[pin], rc);
+ return -EIO;
+ }
+ }
+
+ /* units of mV, steps of 50 mV */
+ rc = vreg_set_level(vreg_bt, 2600);
+ if (rc) {
+ printk(KERN_ERR "%s: vreg set level failed (%d)\n",
+ __func__, rc);
+ return -EIO;
+ }
+ rc = vreg_enable(vreg_bt);
+ if (rc) {
+ printk(KERN_ERR "%s: vreg enable failed (%d)\n",
+ __func__, rc);
+ return -EIO;
+ }
+ } else {
+ rc = vreg_disable(vreg_bt);
+ if (rc) {
+ printk(KERN_ERR "%s: vreg disable failed (%d)\n",
+ __func__, rc);
+ return -EIO;
+ }
+ for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off); pin++) {
+ rc = gpio_tlmm_config(bt_config_power_off[pin],
+ GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, bt_config_power_off[pin], rc);
+ return -EIO;
+ }
+ }
+ }
+ return 0;
+}
+
+static void __init bt_power_init(void)
+{
+ msm_bt_power_device.dev.platform_data = &bluetooth_power;
+}
+#else
+#define bt_power_init(x) do {} while (0)
+#endif
+
+static struct resource bluesleep_resources[] = {
+ {
+ .name = "gpio_host_wake",
+ .start = 83,
+ .end = 83,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "gpio_ext_wake",
+ .start = 42,
+ .end = 42,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .name = "host_wake",
+ .start = MSM_GPIO_TO_INT(83),
+ .end = MSM_GPIO_TO_INT(83),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device msm_bluesleep_device = {
+ .name = "bluesleep",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bluesleep_resources),
+ .resource = bluesleep_resources,
+};
+
+static struct i2c_board_info i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("mt9d112", 0x78 >> 1),
+ },
+ {
+ I2C_BOARD_INFO("s5k3e2fx", 0x20 >> 1),
+ },
+ {
+ I2C_BOARD_INFO("mt9p012", 0x6C >> 1),
+ },
+ {
+ I2C_BOARD_INFO("mt9t013", 0x6C),
+ },
+};
+
+static uint32_t camera_off_gpio_table[] = {
+ /* parallel CAMERA interfaces */
+ GPIO_CFG(0, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+ GPIO_CFG(1, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+ GPIO_CFG(2, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ GPIO_CFG(3, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ GPIO_CFG(4, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ GPIO_CFG(5, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ GPIO_CFG(6, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ GPIO_CFG(7, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ GPIO_CFG(8, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ GPIO_CFG(9, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ GPIO_CFG(10, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ GPIO_CFG(11, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ GPIO_CFG(12, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* PCLK */
+ GPIO_CFG(13, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ GPIO_CFG(14, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+ /* parallel CAMERA interfaces */
+ GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+ GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+ GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+ GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n, rc;
+ for (n = 0; n < len; n++) {
+ rc = gpio_tlmm_config(table[n], GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, table[n], rc);
+ break;
+ }
+ }
+}
+
+static void config_camera_on_gpios(void)
+{
+ config_gpio_table(camera_on_gpio_table,
+ ARRAY_SIZE(camera_on_gpio_table));
+}
+
+static void config_camera_off_gpios(void)
+{
+ config_gpio_table(camera_off_gpio_table,
+ ARRAY_SIZE(camera_off_gpio_table));
+}
+
+#define MSM_PROBE_INIT(name) name##_probe_init
+static struct msm_camera_sensor_info msm_camera_sensor[] = {
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "mt9d112",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9d112),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "s5k3e2fx",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(s5k3e2fx),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 88,
+ .sensor_name = "mt9p012",
+ .flash_type = MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9p012),
+#endif
+ },
+ {
+ .sensor_reset = 89,
+ .sensor_pwd = 85,
+ .vcm_pwd = 0,
+ .sensor_name = "mt9t013",
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+#ifdef CONFIG_MSM_CAMERA
+ .sensor_probe = MSM_PROBE_INIT(mt9t013),
+#endif
+ },
+};
+#undef MSM_PROBE_INIT
+
+static struct msm_camera_device_platform_data msm_camera_device_data = {
+ .camera_gpio_on = config_camera_on_gpios,
+ .camera_gpio_off = config_camera_off_gpios,
+ .snum = ARRAY_SIZE(msm_camera_sensor),
+ .sinfo = &msm_camera_sensor[0],
+ .ioext.mdcphy = MSM_MDC_PHYS,
+ .ioext.mdcsz = MSM_MDC_SIZE,
+ .ioext.appphy = MSM_CLK_CTL_PHYS,
+ .ioext.appsz = MSM_CLK_CTL_SIZE,
+};
+
+static void __init msm_camera_add_device(void)
+{
+ msm_camera_register_device(NULL, 0, &msm_camera_device_data);
+ config_camera_off_gpios();
+}
+
+static struct platform_device *devices[] __initdata = {
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ &msm_device_uart3,
+#endif
+ &msm_device_smd,
+ &msm_device_dmov,
+ &msm_device_nand,
+ &msm_device_hsusb_otg,
+ &msm_device_hsusb_host,
+ &msm_device_hsusb_peripheral,
+ &mass_storage_device,
+ &msm_device_i2c,
+ &smc91x_device,
+ &msm_device_tssc,
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+ &android_pmem_gpu1_device,
+ &msm_fb_device,
+ &lcdc_gordon_panel_device,
+ &msm_device_uart_dm1,
+#ifdef CONFIG_BT
+ &msm_bt_power_device,
+#endif
+ &msm_device_snd,
+ &msm_device_adspdec,
+ &msm_bluesleep_device,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+ .gpio = 97,
+};
+
+static void __init msm_fb_add_devices(void)
+{
+ msm_fb_register_device("mdp", &mdp_pdata);
+ msm_fb_register_device("pmdh", 0);
+ msm_fb_register_device("lcdc", &lcdc_pdata);
+}
+
+extern struct sys_timer msm_timer;
+
+static void __init msm7x27_init_irq(void)
+{
+ msm_init_irq();
+}
+
+static struct msm_acpu_clock_platform_data msm7x27_clock_data = {
+ .acpu_switch_time_us = 50,
+ .max_speed_delta_khz = 256000,
+ .vdd_switch_time_us = 62,
+ .power_collapse_khz = 19200000,
+ .wait_for_irq_khz = 128000000,
+ .max_axi_khz = 128000,
+};
+
+void msm_serial_debug_init(unsigned int base, int irq,
+ struct device *clk_device, int signal_irq);
+
+static void sdcc_gpio_init(void)
+{
+ /* SDC1 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ if (gpio_request(51, "sdc1_data_3"))
+ pr_err("failed to request gpio sdc1_data_3\n");
+ if (gpio_request(52, "sdc1_data_2"))
+ pr_err("failed to request gpio sdc1_data_2\n");
+ if (gpio_request(53, "sdc1_data_1"))
+ pr_err("failed to request gpio sdc1_data_1\n");
+ if (gpio_request(54, "sdc1_data_0"))
+ pr_err("failed to request gpio sdc1_data_0\n");
+ if (gpio_request(55, "sdc1_cmd"))
+ pr_err("failed to request gpio sdc1_cmd\n");
+ if (gpio_request(56, "sdc1_clk"))
+ pr_err("failed to request gpio sdc1_clk\n");
+#endif
+
+ if (machine_is_msm7x27_ffa() || machine_is_msm7x27_ffa())
+ return;
+
+ /* SDC2 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ if (gpio_request(62, "sdc2_clk"))
+ pr_err("failed to request gpio sdc2_clk\n");
+ if (gpio_request(63, "sdc2_cmd"))
+ pr_err("failed to request gpio sdc2_cmd\n");
+ if (gpio_request(64, "sdc2_data_3"))
+ pr_err("failed to request gpio sdc2_data_3\n");
+ if (gpio_request(65, "sdc2_data_2"))
+ pr_err("failed to request gpio sdc2_data_2\n");
+ if (gpio_request(66, "sdc2_data_1"))
+ pr_err("failed to request gpio sdc2_data_1\n");
+ if (gpio_request(67, "sdc2_data_0"))
+ pr_err("failed to request gpio sdc2_data_0\n");
+#endif
+
+ /* SDC3 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+ if (gpio_request(88, "sdc3_clk"))
+ pr_err("failed to request gpio sdc3_clk\n");
+ if (gpio_request(89, "sdc3_cmd"))
+ pr_err("failed to request gpio sdc3_cmd\n");
+ if (gpio_request(90, "sdc3_data_3"))
+ pr_err("failed to request gpio sdc3_data_3\n");
+ if (gpio_request(91, "sdc3_data_2"))
+ pr_err("failed to request gpio sdc3_data_2\n");
+ if (gpio_request(92, "sdc3_data_1"))
+ pr_err("failed to request gpio sdc3_data_1\n");
+ if (gpio_request(93, "sdc3_data_0"))
+ pr_err("failed to request gpio sdc3_data_0\n");
+#endif
+
+ /* SDC4 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ if (gpio_request(19, "sdc4_data_3"))
+ pr_err("failed to request gpio sdc4_data_3\n");
+ if (gpio_request(20, "sdc4_data_2"))
+ pr_err("failed to request gpio sdc4_data_2\n");
+ if (gpio_request(21, "sdc4_data_1"))
+ pr_err("failed to request gpio sdc4_data_1\n");
+ if (gpio_request(107, "sdc4_cmd"))
+ pr_err("failed to request gpio sdc4_cmd\n");
+ if (gpio_request(108, "sdc4_data_0"))
+ pr_err("failed to request gpio sdc4_data_0\n");
+ if (gpio_request(109, "sdc4_clk"))
+ pr_err("failed to request gpio sdc4_clk\n");
+#endif
+}
+
+static unsigned sdcc_cfg_data[][6] = {
+ /* SDC1 configs */
+ {
+ GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ },
+ /* SDC2 configs */
+ {
+ GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ /* SDC3 configs */
+ {
+ GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ /* SDC4 configs */
+ {
+ GPIO_CFG(19, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(20, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(21, 4, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(107, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(108, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(109, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ }
+};
+
+static unsigned long vreg_sts, gpio_sts;
+static struct mpp *mpp_mmc;
+static struct vreg *vreg_mmc;
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+ int i, rc;
+
+ if (!(test_bit(dev_id, &gpio_sts)^enable))
+ return;
+
+ if (enable)
+ set_bit(dev_id, &gpio_sts);
+ else
+ clear_bit(dev_id, &gpio_sts);
+
+ for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) {
+ rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i],
+ enable ? GPIO_ENABLE : GPIO_DISABLE);
+ if (rc)
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, sdcc_cfg_data[dev_id - 1][i], rc);
+ }
+}
+
+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);
+ msm_sdcc_setup_gpio(pdev->id, !!vdd);
+
+ if (vdd == 0) {
+ if (!vreg_sts)
+ return 0;
+
+ clear_bit(pdev->id, &vreg_sts);
+
+ if (!vreg_sts) {
+ if (machine_is_msm7x27_ffa()) {
+ rc = mpp_config_digital_out(mpp_mmc,
+ MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+ MPP_DLOGIC_OUT_CTRL_LOW));
+ } else
+ rc = vreg_disable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ return 0;
+ }
+
+ if (!vreg_sts) {
+ if (machine_is_msm7x27_ffa()) {
+ rc = mpp_config_digital_out(mpp_mmc,
+ MPP_CFG(MPP_DLOGIC_LVL_MSMP,
+ MPP_DLOGIC_OUT_CTRL_HIGH));
+ } else {
+ rc = vreg_set_level(vreg_mmc, 2850);
+ if (!rc)
+ rc = vreg_enable(vreg_mmc);
+ }
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ set_bit(pdev->id, &vreg_sts);
+ return 0;
+}
+
+static struct mmc_platform_data msm7x27_sdcc_data = {
+ .ocr_mask = MMC_VDD_28_29,
+ .translate_vdd = msm_sdcc_setup_power,
+};
+
+static void __init msm7x27_init_mmc(void)
+{
+ if (machine_is_msm7x27_ffa()) {
+ mpp_mmc = mpp_get(NULL, "mpp3");
+ if (!mpp_mmc) {
+ printk(KERN_ERR "%s: mpp get failed (%ld)\n",
+ __func__, PTR_ERR(vreg_mmc));
+ return;
+ }
+ } else {
+ vreg_mmc = vreg_get(NULL, "mmc");
+ if (IS_ERR(vreg_mmc)) {
+ printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+ __func__, PTR_ERR(vreg_mmc));
+ return;
+ }
+ }
+
+ sdcc_gpio_init();
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ msm_add_sdcc(1, &msm7x27_sdcc_data);
+#endif
+
+ if (machine_is_msm7x27_surf()) {
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ msm_add_sdcc(2, &msm7x27_sdcc_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+ msm_add_sdcc(3, &msm7x27_sdcc_data);
+#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ msm_add_sdcc(4, &msm7x27_sdcc_data);
+#endif
+ }
+}
+
+static struct msm_i2c_platform_data msm_i2c_pdata = {
+ .clk_freq = 100000,
+};
+
+static void __init msm_device_i2c_init(void)
+{
+ msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
+}
+
+static struct msm_pm_platform_data msm7x27_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000,
+
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000,
+
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled
+ = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 0,
+};
+
+static void __init msm7x27_init(void)
+{
+ if (socinfo_init() < 0)
+ BUG();
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+ &msm_device_uart3.dev, 1);
+#endif
+ if (machine_is_msm7x27_ffa()) {
+ smc91x_resources[0].start = 0x98000300;
+ smc91x_resources[0].end = 0x980003ff;
+ smc91x_resources[1].start = MSM_GPIO_TO_INT(85);
+ smc91x_resources[1].end = MSM_GPIO_TO_INT(85);
+ if (gpio_tlmm_config(GPIO_CFG(85, 0,
+ GPIO_INPUT,
+ GPIO_PULL_DOWN,
+ GPIO_2MA),
+ GPIO_ENABLE)) {
+ printk(KERN_ERR
+ "%s: Err: Config GPIO-85 INT\n",
+ __func__);
+ }
+
+ msm7x27_clock_data.max_axi_khz = 160000;
+ }
+
+ if (cpu_is_msm7x27())
+ msm7x27_clock_data.max_axi_khz = 200000;
+
+ msm_acpu_clock_init(&msm7x27_clock_data);
+ msm_device_hsusb_peripheral.dev.platform_data = &msm_hsusb_pdata;
+ msm_device_hsusb_host.dev.platform_data = &msm_hsusb_pdata;
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ msm_camera_add_device();
+ msm_device_i2c_init();
+ i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+
+#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
+ if (machine_is_msm7x27_ffa())
+ platform_device_register(&keypad_device_7k_ffa);
+ else
+ platform_device_register(&keypad_device_surf);
+#endif
+ lcdc_gordon_gpio_init();
+ msm_fb_add_devices();
+ msm7x27_init_mmc();
+ bt_power_init();
+
+ if (cpu_is_msm7x27())
+ msm_pm_set_platform_data(msm7x27_pm_data);
+ else
+ msm_pm_set_platform_data(msm7x27_pm_data);
+}
+
+static void __init msm_msm7x27_allocate_memory_regions(void)
+{
+ void *addr;
+ unsigned long size;
+
+ size = MSM_PMEM_MDP_SIZE;
+ addr = alloc_bootmem(size);
+ android_pmem_pdata.start = __pa(addr);
+ android_pmem_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for pmem\n", size, addr, __pa(addr));
+
+ size = MSM_PMEM_ADSP_SIZE;
+ addr = alloc_bootmem(size);
+ android_pmem_adsp_pdata.start = __pa(addr);
+ android_pmem_adsp_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for adsp pmem\n", size, addr, __pa(addr));
+
+ size = MSM_PMEM_GPU1_SIZE;
+ addr = alloc_bootmem_aligned(size, 0x100000);
+ android_pmem_gpu1_pdata.start = __pa(addr);
+ android_pmem_gpu1_pdata.size = size;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical)"
+ "for gpu1 pmem\n", size, addr, __pa(addr));
+
+ size = MSM_FB_SIZE;
+ addr = alloc_bootmem(size);
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ printk(KERN_INFO "allocating %lu bytes at %p (%lx physical) for fb\n",
+ size, addr, __pa(addr));
+}
+
+static void __init msm7x27_map_io(void)
+{
+ msm_map_common_io();
+ /* Technically dependent on the SoC but using machine_is
+ * macros since socinfo is not available this early and there
+ * are plans to restructure the code which will eliminate the
+ * need for socinfo.
+ */
+ if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa())
+ msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27);
+ else
+ msm_clock_init(msm_clocks_7x27, msm_num_clocks_7x27);
+ msm_msm7x27_allocate_memory_regions();
+
+#ifdef CONFIG_CACHE_L2X0
+ if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) {
+ /* 7x27 has 256KB L2 cache:
+ 64Kb/Way and 4-Way Associativity;
+ R/W latency: 3 cycles;
+ evmon/parity/share disabled. */
+ l2x0_init(MSM_L2CC_BASE, 0x00068012, 0xfe000000);
+ }
+#endif
+}
+
+MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x00200100,
+ .map_io = msm7x27_map_io,
+ .init_irq = msm7x27_init_irq,
+ .init_machine = msm7x27_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x00200100,
+ .map_io = msm7x27_map_io,
+ .init_irq = msm7x27_init_irq,
+ .init_machine = msm7x27_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
new file mode 100644
index 000000000000..3dc0fc54322a
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -0,0 +1,209 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/memory.h>
+#include <mach/msm_iomap.h>
+
+#include "devices.h"
+#include "timer.h"
+#include "socinfo.h"
+#include "pm.h"
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x8A000300,
+ .end = 0x8A0003ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MSM_GPIO_TO_INT(156),
+ .end = MSM_GPIO_TO_INT(156),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &msm_device_smd,
+ &msm_device_dmov,
+ &smc91x_device,
+ &msm_device_nand,
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+ &msm_device_uart2,
+#endif
+};
+
+static void __init msm7x30_init_irq(void)
+{
+ msm_init_irq();
+}
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 0,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 0,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 20000,
+
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 0,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 0,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 0,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 20000,
+
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 0,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled
+ = 0,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 10000,
+
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 0,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 0,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 0,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 500,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0,
+};
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+static struct msm_gpio uart2_config_data[] = {
+ { GPIO_CFG(49, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_RFR"},
+ { GPIO_CFG(50, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_CTS"},
+ { GPIO_CFG(51, 2, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
+ { GPIO_CFG(52, 2, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
+};
+
+static void msm7x30_init_uart2(void)
+{
+ msm_gpios_request_enable(uart2_config_data,
+ ARRAY_SIZE(uart2_config_data));
+
+}
+#endif
+
+static void __init msm7x30_init(void)
+{
+ if (socinfo_init() < 0)
+ printk(KERN_ERR "%s: socinfo_init() failed!\n",
+ __func__);
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ msm_pm_set_platform_data(msm_pm_data);
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+ msm7x30_init_uart2();
+#endif
+}
+
+static void __init msm7x30_map_io(void)
+{
+ msm_shared_ram_phys = 0x00100000;
+ msm_map_msm7x30_io();
+ msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30);
+}
+
+MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x00200100,
+ .map_io = msm7x30_map_io,
+ .init_irq = msm7x30_init_irq,
+ .init_machine = msm7x30_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x00200100,
+ .map_io = msm7x30_map_io,
+ .init_irq = msm7x30_init_irq,
+ .init_machine = msm7x30_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x00200100,
+ .map_io = msm7x30_map_io,
+ .init_irq = msm7x30_init_irq,
+ .init_machine = msm7x30_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
new file mode 100644
index 000000000000..75e59be7fd4b
--- /dev/null
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -0,0 +1,538 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <asm/mach/mmc.h>
+#include <mach/vreg.h>
+#include <mach/mpp.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/sirc.h>
+#include <mach/msm_touchpad.h>
+#include <mach/msm_i2ckbd.h>
+#include <mach/pmic.h>
+#include <mach/memory.h>
+
+#include "devices.h"
+#include "timer.h"
+#include "socinfo.h"
+#include "msm-keypad-devices.h"
+#include "pm.h"
+
+#define TOUCHPAD_SUSPEND 34
+#define TOUCHPAD_IRQ 38
+
+#define MSM_PMEM_MDP_SIZE 0x800000
+#define MSM_PMEM_CAMERA_SIZE 0xa00000
+#define MSM_PMEM_ADSP_SIZE 0x1100000
+#define MSM_PMEM_GPU1_SIZE 0x800000
+#define MSM_FB_SIZE 0x500000
+#define MSM_AUDIO_SIZE 0x200000
+#define MSM_GPU_PHYS_SIZE SZ_2M
+
+#define MSM_SMI_BASE 0x2b00000
+#define MSM_SMI_SIZE 0x1500000
+
+#define MSM_FB_BASE MSM_SMI_BASE
+#define MSM_GPU_PHYS_BASE (MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_GPU0_BASE (MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE)
+#define MSM_PMEM_GPU0_SIZE (MSM_SMI_SIZE - MSM_FB_SIZE - MSM_GPU_PHYS_SIZE)
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+
+static struct platform_device *devices[] __initdata = {
+ &smc91x_device,
+ &msm_device_smd,
+ &msm_device_dmov,
+ &msm_device_nand,
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ &msm_device_uart3,
+#endif
+};
+
+#define KBD_RST 35
+#define KBD_IRQ 36
+
+static void kbd_gpio_release(void)
+{
+ gpio_free(KBD_IRQ);
+ gpio_free(KBD_RST);
+}
+
+static int kbd_gpio_setup(void)
+{
+ int rc;
+ int respin = KBD_RST;
+ int irqpin = KBD_IRQ;
+ unsigned rescfg =
+ GPIO_CFG(respin, 0, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA);
+ unsigned irqcfg =
+ GPIO_CFG(irqpin, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA);
+
+ rc = gpio_request(irqpin, "gpio_keybd_irq");
+ if (rc) {
+ pr_err("gpio_request failed on pin %d (rc=%d)\n",
+ irqpin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_request(respin, "gpio_keybd_reset");
+ if (rc) {
+ pr_err("gpio_request failed on pin %d (rc=%d)\n",
+ respin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_tlmm_config(rescfg, GPIO_ENABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+ respin, rc);
+ goto err_gpioconfig;
+ }
+ rc = gpio_tlmm_config(irqcfg, GPIO_ENABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config failed on pin %d (rc=%d)\n",
+ irqpin, rc);
+ goto err_gpioconfig;
+ }
+ return rc;
+
+err_gpioconfig:
+ kbd_gpio_release();
+ return rc;
+}
+
+static struct msm_i2ckbd_platform_data msm_kybd_data = {
+ .hwrepeat = 0,
+ .scanset1 = 1,
+ .gpioreset = KBD_RST,
+ .gpioirq = KBD_IRQ,
+ .gpio_setup = kbd_gpio_setup,
+ .gpio_shutdown = kbd_gpio_release,
+};
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n, rc;
+ for (n = 0; n < len; n++) {
+ rc = gpio_tlmm_config(table[n], GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, table[n], rc);
+ break;
+ }
+ }
+}
+
+static void __init qsd8x50_init_irq(void)
+{
+ msm_init_irq();
+ msm_init_sirc();
+}
+
+static void sdcc_gpio_init(void)
+{
+ /* SDC1 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ if (gpio_request(51, "sdc1_data_3"))
+ pr_err("failed to request gpio sdc1_data_3\n");
+ if (gpio_request(52, "sdc1_data_2"))
+ pr_err("failed to request gpio sdc1_data_2\n");
+ if (gpio_request(53, "sdc1_data_1"))
+ pr_err("failed to request gpio sdc1_data_1\n");
+ if (gpio_request(54, "sdc1_data_0"))
+ pr_err("failed to request gpio sdc1_data_0\n");
+ if (gpio_request(55, "sdc1_cmd"))
+ pr_err("failed to request gpio sdc1_cmd\n");
+ if (gpio_request(56, "sdc1_clk"))
+ pr_err("failed to request gpio sdc1_clk\n");
+#endif
+
+ if (machine_is_qsd8x50_ffa())
+ return;
+
+ /* SDC2 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ if (gpio_request(62, "sdc2_clk"))
+ pr_err("failed to request gpio sdc2_clk\n");
+ if (gpio_request(63, "sdc2_cmd"))
+ pr_err("failed to request gpio sdc2_cmd\n");
+ if (gpio_request(64, "sdc2_data_3"))
+ pr_err("failed to request gpio sdc2_data_3\n");
+ if (gpio_request(65, "sdc2_data_2"))
+ pr_err("failed to request gpio sdc2_data_2\n");
+ if (gpio_request(66, "sdc2_data_1"))
+ pr_err("failed to request gpio sdc2_data_1\n");
+ if (gpio_request(67, "sdc2_data_0"))
+ pr_err("failed to request gpio sdc2_data_0\n");
+#endif
+
+ /* SDC3 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
+ if (gpio_request(88, "sdc3_clk"))
+ pr_err("failed to request gpio sdc3_clk\n");
+ if (gpio_request(89, "sdc3_cmd"))
+ pr_err("failed to request gpio sdc3_cmd\n");
+ if (gpio_request(90, "sdc3_data_3"))
+ pr_err("failed to request gpio sdc3_data_3\n");
+ if (gpio_request(91, "sdc3_data_2"))
+ pr_err("failed to request gpio sdc3_data_2\n");
+ if (gpio_request(92, "sdc3_data_1"))
+ pr_err("failed to request gpio sdc3_data_1\n");
+ if (gpio_request(93, "sdc3_data_0"))
+ pr_err("failed to request gpio sdc3_data_0\n");
+#endif
+
+ /* SDC4 GPIOs */
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ if (gpio_request(142, "sdc4_clk"))
+ pr_err("failed to request gpio sdc4_clk\n");
+ if (gpio_request(143, "sdc4_cmd"))
+ pr_err("failed to request gpio sdc4_cmd\n");
+ if (gpio_request(144, "sdc4_data_0"))
+ pr_err("failed to request gpio sdc4_data_0\n");
+ if (gpio_request(145, "sdc4_data_1"))
+ pr_err("failed to request gpio sdc4_data_1\n");
+ if (gpio_request(146, "sdc4_data_2"))
+ pr_err("failed to request gpio sdc4_data_2\n");
+ if (gpio_request(147, "sdc4_data_3"))
+ pr_err("failed to request gpio sdc4_data_3\n");
+#endif
+}
+
+static unsigned sdcc_cfg_data[][6] = {
+ /* SDC1 configs */
+ {
+ GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ },
+ /* SDC2 configs */
+ {
+ GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ /* SDC3 configs */
+ {
+ GPIO_CFG(88, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(89, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(90, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(91, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(92, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(93, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ },
+ /* SDC4 configs */
+ {
+ GPIO_CFG(142, 3, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA),
+ GPIO_CFG(143, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(144, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(145, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(146, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ GPIO_CFG(147, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ }
+};
+
+static unsigned long vreg_sts, gpio_sts;
+static struct vreg *vreg_mmc;
+
+static void msm_sdcc_setup_gpio(int dev_id, unsigned int enable)
+{
+ int i, rc;
+
+ if (!(test_bit(dev_id, &gpio_sts)^enable))
+ return;
+
+ if (enable)
+ set_bit(dev_id, &gpio_sts);
+ else
+ clear_bit(dev_id, &gpio_sts);
+
+ for (i = 0; i < ARRAY_SIZE(sdcc_cfg_data[dev_id - 1]); i++) {
+ rc = gpio_tlmm_config(sdcc_cfg_data[dev_id - 1][i],
+ enable ? GPIO_ENABLE : GPIO_DISABLE);
+ if (rc)
+ printk(KERN_ERR "%s: gpio_tlmm_config(%#x)=%d\n",
+ __func__, sdcc_cfg_data[dev_id - 1][i], rc);
+ }
+}
+
+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);
+ msm_sdcc_setup_gpio(pdev->id, !!vdd);
+
+ if (vdd == 0) {
+ if (!vreg_sts)
+ return 0;
+
+ clear_bit(pdev->id, &vreg_sts);
+
+ if (!vreg_sts && !machine_is_qsd8x50_ffa()) {
+ rc = vreg_disable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ return 0;
+ }
+
+ if (!vreg_sts && !machine_is_qsd8x50_ffa()) {
+ rc = vreg_set_level(vreg_mmc, 2850);
+ if (!rc)
+ rc = vreg_enable(vreg_mmc);
+ if (rc)
+ printk(KERN_ERR "%s: return val: %d \n",
+ __func__, rc);
+ }
+ set_bit(pdev->id, &vreg_sts);
+ return 0;
+}
+
+static struct mmc_platform_data qsd8x50_sdcc_data = {
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+ .translate_vdd = msm_sdcc_setup_power,
+};
+
+static void __init qsd8x50_cfg_smc91x(void)
+{
+ int rc = 0;
+
+ if (machine_is_qsd8x50_surf()) {
+ smc91x_resources[0].start = 0x70000300;
+ smc91x_resources[0].end = 0x700003ff;
+ smc91x_resources[1].start = MSM_GPIO_TO_INT(156);
+ smc91x_resources[1].end = MSM_GPIO_TO_INT(156);
+ } else if (machine_is_qsd8x50_ffa()) {
+ smc91x_resources[0].start = 0x84000300;
+ smc91x_resources[0].end = 0x840003ff;
+ smc91x_resources[1].start = MSM_GPIO_TO_INT(87);
+ smc91x_resources[1].end = MSM_GPIO_TO_INT(87);
+
+ rc = gpio_tlmm_config(GPIO_CFG(87, 0, GPIO_INPUT,
+ GPIO_PULL_DOWN, GPIO_2MA),
+ GPIO_ENABLE);
+ if (rc) {
+ printk(KERN_ERR "%s: gpio_tlmm_config=%d\n",
+ __func__, rc);
+ }
+ } else
+ printk(KERN_ERR "%s: invalid machine type\n", __func__);
+}
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 8594,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].residency = 23740,
+
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].supported = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 4594,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].residency = 23740,
+
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].supported = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].suspend_enabled
+ = 1,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].idle_enabled = 0,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 443,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].residency = 1098,
+
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].supported = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].suspend_enabled = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].idle_enabled = 1,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].latency = 2,
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT].residency = 0,
+};
+
+static void __init gp6_init(void)
+{
+ struct vreg *vreg;
+ int rc;
+
+ vreg = vreg_get(NULL, "gp6");
+ if (IS_ERR(vreg)) {
+ printk(KERN_ERR "%s: vreg get failed (%ld)\n",
+ __func__, PTR_ERR(vreg));
+ return;
+ }
+
+ /* units of mV, steps of 50 mV */
+ rc = vreg_set_level(vreg, 2850);
+ if (rc) {
+ printk(KERN_ERR "%s: vreg set level failed (%d)\n",
+ __func__, rc);
+ return;
+ }
+
+ rc = vreg_enable(vreg);
+ if (rc) {
+ printk(KERN_ERR "%s: vreg enable failed (%d)\n",
+ __func__, rc);
+ return;
+ }
+
+ if (machine_is_qsd8x50_ffa())
+ vreg_mmc = vreg;
+}
+
+static void __init qsd8x50_init(void)
+{
+ if (socinfo_init() < 0)
+ printk(KERN_ERR "%s: socinfo_init() failed!\n",
+ __func__);
+ qsd8x50_cfg_smc91x();
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ gp6_init();
+ msm_pm_set_platform_data(msm_pm_data);
+
+#ifdef CONFIG_SURF_FFA_GPIO_KEYPAD
+ if (machine_is_qsd8x50_ffa())
+ platform_device_register(&keypad_device_8k_ffa);
+ else
+ platform_device_register(&keypad_device_surf);
+#endif
+}
+
+
+static void __init qsd8x50_map_io(void)
+{
+ msm_map_qsd8x50_io();
+ msm_clock_init(msm_clocks_8x50, msm_num_clocks_8x50);
+}
+
+MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x20000100,
+ .map_io = qsd8x50_map_io,
+ .init_irq = qsd8x50_init_irq,
+ .init_machine = qsd8x50_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(QSD8X50_GRAPEFRUIT, "QCT QSD8X50 GRAPEFRUIT")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x20000100,
+ .map_io = qsd8x50_map_io,
+ .init_irq = qsd8x50_init_irq,
+ .init_machine = qsd8x50_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(QSD8X50_FFA, "QCT QSD8X50 FFA")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x20000100,
+ .map_io = qsd8x50_map_io,
+ .init_irq = qsd8x50_init_irq,
+ .init_machine = qsd8x50_init,
+ .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(QSD8X50_ST1, "QCT QSD8X50 ST1")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x20000100,
+ .map_io = qsd8x50_map_io,
+ .init_irq = qsd8x50_init_irq,
+ .init_machine = qsd8x50_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-sapphire-gpio.c b/arch/arm/mach-msm/board-sapphire-gpio.c
new file mode 100644
index 000000000000..2f2df97956cf
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-gpio.c
@@ -0,0 +1,326 @@
+/* arch/arm/mach-msm/board-sapphire-gpio.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/errno.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/sysdev.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+#ifdef DEBUG_SAPPHIRE_GPIO
+#define DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n", __func__, ## arg)
+#else
+#define DBG(fmt, arg...) do {} while (0)
+#endif
+
+#define SAPPHIRE_CPLD_INT_STATUS (SAPPHIRE_CPLD_BASE + 0x0E)
+#define SAPPHIRE_CPLD_INT_LEVEL (SAPPHIRE_CPLD_BASE + 0x08)
+#define SAPPHIRE_CPLD_INT_MASK (SAPPHIRE_CPLD_BASE + 0x0C)
+
+/*CPLD misc reg offset*/
+static const int _g_CPLD_MISCn_Offset[] = { 0x0A, /*misc1 reg*/
+ 0x00, /*misc2 reg*/
+ 0x02, /*misc3 reg*/
+ 0x04, /*misc4 reg*/
+ 0x06}; /*misc5 reg*/
+/*CPLD INT Bank*/
+/*BANK0: int1 status, int2 level, int3 mask*/
+static const int _g_INT_BANK_Offset[][3] = {{0x0E, 0x08, 0x0C} };
+
+static uint8_t sapphire_cpld_initdata[4] = {
+ [0] = 0x80, /* for serial debug UART3, low current misc2*/
+ [1] = 0x34, /* jog & tp enable, I2C pull misc3*/
+ [3] = 0x04, /* mmdi 32k en misc5*/
+};
+
+/*save current working int mask, so the value can be restored after resume.
+Sapphire has only bank0.*/
+static uint8_t sapphire_int_mask[] = {
+ [0] = 0xfb, /* enable all interrupts, bit 2 is not used */
+};
+
+/*Sleep have to prepare the wake up source in advance.
+default to disable all wakeup sources when suspend.*/
+static uint8_t sapphire_sleep_int_mask[] = {
+ [0] = 0x00, /* bit2 is not used */
+};
+
+static int sapphire_suspended;
+
+static int sapphire_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+ if (n < SAPPHIRE_GPIO_INT_B0_BASE) /*MISCn*/
+ return !!(readb(CPLD_GPIO_REG(n)) & CPLD_GPIO_BIT_POS_MASK(n));
+ else if (n <= SAPPHIRE_GPIO_END) /*gpio n is INT pin*/
+ return !!(readb(CPLD_INT_LEVEL_REG_G(n)) &
+ CPLD_GPIO_BIT_POS_MASK(n));
+ return 0;
+}
+
+/*CPLD Write only register :MISC2, MISC3, MISC4, MISC5 => reg=0,2,4,6
+Reading from write-only registers is undefined, so the writing value
+should be kept in shadow for later usage.*/
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+ unsigned long flags;
+ uint8_t reg_val;
+ if (n > SAPPHIRE_GPIO_END)
+ return -1;
+
+ local_irq_save(flags);
+ reg_val = readb(CPLD_GPIO_REG(n));
+ if (on)
+ reg_val |= CPLD_GPIO_BIT_POS_MASK(n);
+ else
+ reg_val &= ~CPLD_GPIO_BIT_POS_MASK(n);
+ writeb(reg_val, CPLD_GPIO_REG(n));
+
+ DBG("gpio=%d, l=0x%x\r\n", n, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static int sapphire_gpio_configure(struct gpio_chip *chip, unsigned int gpio,
+ unsigned long flags)
+{
+ if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+ sapphire_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+
+ DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+ return 0;
+}
+
+static int sapphire_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio,
+ unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+ DBG("gpio=%d, l=0x%x\r\n", gpio, readb(SAPPHIRE_CPLD_INT_LEVEL));
+ DBG("SAPPHIRE_GPIO_INT_B0_BASE=%d, SAPPHIRE_GPIO_LAST_INT=%d\r\n",
+ SAPPHIRE_GPIO_INT_B0_BASE, SAPPHIRE_GPIO_LAST_INT);
+ if ((gpio < SAPPHIRE_GPIO_INT_B0_BASE) ||
+ (gpio > SAPPHIRE_GPIO_LAST_INT))
+ return -ENOENT;
+ *irqp = SAPPHIRE_GPIO_TO_INT(gpio);
+ DBG("*irqp=%d\r\n", *irqp);
+ if (irqnumflagsp)
+ *irqnumflagsp = 0;
+ return 0;
+}
+
+/*write 1 to clear INT status bit.*/
+static void sapphire_gpio_irq_ack(unsigned int irq)
+{
+ /*write 1 to clear*/
+ writeb(SAPPHIRE_INT_BIT_MASK(irq), CPLD_INT_STATUS_REG(irq));
+}
+
+/*unmask/enable the INT
+static void sapphire_gpio_irq_unmask(unsigned int irq)*/
+static void sapphire_gpio_irq_enable(unsigned int irq)
+{
+ unsigned long flags;
+ uint8_t reg_val;
+
+ local_irq_save(flags); /*disabling all interrupts*/
+
+ reg_val = readb(CPLD_INT_MASK_REG(irq)) | SAPPHIRE_INT_BIT_MASK(irq);
+ DBG("(irq=%d,0x%x, 0x%x)\r\n", irq, CPLD_INT_MASK_REG(irq),
+ SAPPHIRE_INT_BIT_MASK(irq));
+ DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+ /*printk(KERN_INFO "sapphire_gpio_irq_mask irq %d => %d:%02x\n",
+ irq, bank, reg_val);*/
+ if (!sapphire_suspended)
+ writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+ reg_val = readb(CPLD_INT_MASK_REG(irq));
+ DBG("reg_val= 0x%x\r\n", reg_val);
+ DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+ local_irq_restore(flags); /*restore the interrupts*/
+}
+
+/*mask/disable INT
+static void sapphire_gpio_irq_mask(unsigned int irq)*/
+static void sapphire_gpio_irq_disable(unsigned int irq)
+{
+ unsigned long flags;
+ uint8_t reg_val;
+
+ local_irq_save(flags);
+ reg_val = readb(CPLD_INT_MASK_REG(irq)) & ~SAPPHIRE_INT_BIT_MASK(irq);
+ /*CPLD INT MASK is r/w now.*/
+
+ /*printk(KERN_INFO "sapphire_gpio_irq_unmask irq %d => %d:%02x\n",
+ irq, bank, reg_val);*/
+ DBG("(%d,0x%x, 0x%x, 0x%x)\r\n", irq, reg_val, CPLD_INT_MASK_REG(irq),
+ SAPPHIRE_INT_BIT_MASK(irq));
+ DBG("sapphire_suspended=%d\r\n", sapphire_suspended);
+ if (!sapphire_suspended)
+ writeb(reg_val, CPLD_INT_MASK_REG(irq));
+
+ reg_val = readb(CPLD_INT_MASK_REG(irq));
+ DBG("reg_val= 0x%x\r\n", reg_val);
+ DBG("l=0x%x\r\n", readb(SAPPHIRE_CPLD_INT_LEVEL));
+
+ local_irq_restore(flags);
+}
+
+/*preparing enable/disable wake source before sleep*/
+int sapphire_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ unsigned long flags;
+ uint8_t mask = SAPPHIRE_INT_BIT_MASK(irq);
+
+ local_irq_save(flags);
+
+ if (on) /*wake on -> mask the bit*/
+ sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] |= mask;
+ else /*no wake -> unmask the bit*/
+ sapphire_sleep_int_mask[CPLD_INT_TO_BANK(irq)] &= ~mask;
+ local_irq_restore(flags);
+ return 0;
+}
+
+/*Sapphire has only one INT Bank.*/
+static void sapphire_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int j;
+ unsigned v;
+ int int_base = SAPPHIRE_INT_START;
+
+ v = readb(SAPPHIRE_CPLD_INT_STATUS); /*INT1 status reg, BANK0*/
+
+ for (j = 0; j < 8 ; j++) { /*8 bit per bank*/
+ if (v & (1U << j)) { /*got the INT Bit*/
+ DBG("generic_handle_irq j=0x%x\r\n", j);
+ generic_handle_irq(int_base + j);
+ }
+ }
+
+ desc->chip->ack(irq); /*clear CPLD INT in SOC side.*/
+ DBG("irq=%d, l=0x%x\r\n", irq, readb(SAPPHIRE_CPLD_INT_LEVEL));
+}
+
+/*Save current working sources before sleep, so we can restore it after
+ * resume.*/
+static int sapphire_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+ sapphire_suspended = 1;
+ /*save current masking*/
+ sapphire_int_mask[0] = readb(SAPPHIRE_CPLD_BASE +
+ SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+ /*set waking source before sleep.*/
+ writeb(sapphire_sleep_int_mask[0],
+ SAPPHIRE_CPLD_BASE + SAPPHIRE_GPIO_INT_B0_MASK_REG);
+
+ return 0;
+}
+
+/*All the registers will be kept till a power loss...*/
+int sapphire_sysdev_resume(struct sys_device *dev)
+{
+ /*restore the working mask saved before sleep*/
+ writeb(sapphire_int_mask[0], SAPPHIRE_CPLD_BASE +
+ SAPPHIRE_GPIO_INT_B0_MASK_REG);
+ sapphire_suspended = 0;
+ return 0;
+}
+
+/**
+ * linux/irq.h :: struct irq_chip
+ * @enable: enable the interrupt (defaults to chip->unmask if NULL)
+ * @disable: disable the interrupt (defaults to chip->mask if NULL)
+ * @ack: start of a new interrupt
+ * @mask: mask an interrupt source
+ * @mask_ack: ack and mask an interrupt source
+ * @unmask: unmask an interrupt source
+ */
+static struct irq_chip sapphire_gpio_irq_chip = {
+ .name = "sapphiregpio",
+ .ack = sapphire_gpio_irq_ack,
+ .mask = sapphire_gpio_irq_disable, /*sapphire_gpio_irq_mask,*/
+ .unmask = sapphire_gpio_irq_enable, /*sapphire_gpio_irq_unmask,*/
+ .set_wake = sapphire_gpio_irq_set_wake,
+ /*.set_type = sapphire_gpio_irq_set_type,*/
+};
+
+/*Thomas:For CPLD*/
+static struct gpio_chip sapphire_gpio_chip = {
+ .start = SAPPHIRE_GPIO_START,
+ .end = SAPPHIRE_GPIO_END,
+ .configure = sapphire_gpio_configure,
+ .get_irq_num = sapphire_gpio_get_irq_num,
+ .read = sapphire_gpio_read,
+ .write = sapphire_gpio_write,
+/* .read_detect_status = sapphire_gpio_read_detect_status,
+ .clear_detect_status = sapphire_gpio_clear_detect_status */
+};
+
+struct sysdev_class sapphire_sysdev_class = {
+ .name = "sapphiregpio_irq",
+ .suspend = sapphire_sysdev_suspend,
+ .resume = sapphire_sysdev_resume,
+};
+
+static struct sys_device sapphire_irq_device = {
+ .cls = &sapphire_sysdev_class,
+};
+
+int sapphire_init_gpio(void)
+{
+ int i;
+ if (!machine_is_sapphire())
+ return 0;
+
+ DBG("%d,%d\r\n", SAPPHIRE_INT_START, SAPPHIRE_INT_END);
+ DBG("NR_MSM_IRQS=%d, NR_GPIO_IRQS=%d\r\n", NR_MSM_IRQS, NR_GPIO_IRQS);
+ for (i = SAPPHIRE_INT_START; i <= SAPPHIRE_INT_END; i++) {
+ set_irq_chip(i, &sapphire_gpio_irq_chip);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ register_gpio_chip(&sapphire_gpio_chip);
+
+ /*setup CPLD INT connecting to SOC's gpio 17 */
+ set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+ set_irq_chained_handler(MSM_GPIO_TO_INT(17), sapphire_gpio_irq_handler);
+ set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
+ if (sysdev_class_register(&sapphire_sysdev_class) == 0)
+ sysdev_register(&sapphire_irq_device);
+
+ return 0;
+}
+
+int sapphire_init_cpld(unsigned int sys_rev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sapphire_cpld_initdata); i++)
+ writeb(sapphire_cpld_initdata[i], SAPPHIRE_CPLD_BASE + i * 2);
+ return 0;
+}
+
+arch_initcall(sapphire_init_gpio);
diff --git a/arch/arm/mach-msm/board-sapphire-h2w.c b/arch/arm/mach-msm/board-sapphire-h2w.c
new file mode 100644
index 000000000000..aa83e216974d
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-h2w.c
@@ -0,0 +1,545 @@
+/*
+ * H2W device detection driver.
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Authors:
+ * Laurence Chen <Laurence_Chen@htc.com>
+ * Nick Pelly <npelly@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.
+ *
+ */
+
+/* For detecting HTC 2 Wire devices, such as wired headset.
+
+ Logically, the H2W driver is always present, and H2W state (hi->state)
+ indicates what is currently plugged into the H2W interface.
+
+ When the headset is plugged in, CABLE_IN1 is pulled low. When the headset
+ button is pressed, CABLE_IN2 is pulled low. These two lines are shared with
+ the TX and RX (respectively) of UART3 - used for serial debugging.
+
+ This headset driver keeps the CPLD configured as UART3 for as long as
+ possible, so that we can do serial FIQ debugging even when the kernel is
+ locked and this driver no longer runs. So it only configures the CPLD to
+ GPIO while the headset is plugged in, and for 10ms during detection work.
+
+ Unfortunately we can't leave the CPLD as UART3 while a headset is plugged
+ in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA
+ drain on sapphire.
+
+ The headset detection work involves setting CPLD to GPIO, and then pulling
+ CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still
+ pull this line low, whereas other attachments such as a serial console
+ would get pulled up by this stronger pullup.
+
+ Headset insertion/removal causes UEvent's to be sent, and
+ /sys/class/switch/h2w/state to be updated.
+
+ Button presses are interpreted as input event (KEY_MEDIA). Button presses
+ are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm
+ jack adapters do not work until a headset is plugged into the adapter. This
+ is to avoid serial RX traffic causing spurious button press events.
+
+ We tend to check the status of CABLE_IN1 a few more times than strictly
+ necessary during headset detection, to avoid spurious headset insertion
+ events caused by serial debugger TX traffic.
+*/
+
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+#include "board-sapphire.h"
+
+#ifdef CONFIG_DEBUG_SAPPHIRE_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\n", __FUNCTION__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+static struct workqueue_struct *g_detection_work_queue;
+static void detection_work(struct work_struct *work);
+static DECLARE_WORK(g_detection_work, detection_work);
+enum {
+ NO_DEVICE = 0,
+ HTC_HEADSET = 1,
+};
+
+enum {
+ UART3 = 0,
+ GPIO = 1,
+};
+
+struct h2w_info {
+ struct switch_dev sdev;
+ struct input_dev *input;
+
+ atomic_t btn_state;
+ int ignore_btn;
+
+ unsigned int irq;
+ unsigned int irq_btn;
+
+ struct hrtimer timer;
+ ktime_t debounce_time;
+
+ struct hrtimer btn_timer;
+ ktime_t btn_debounce_time;
+};
+static struct h2w_info *hi;
+
+static ssize_t sapphire_h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+ switch (switch_get_state(&hi->sdev)) {
+ case NO_DEVICE:
+ return sprintf(buf, "No Device\n");
+ case HTC_HEADSET:
+ return sprintf(buf, "Headset\n");
+ }
+ return -EINVAL;
+}
+
+static void configure_cpld(int route)
+{
+ H2W_DBG(" route = %s", route == UART3 ? "UART3" : "GPIO");
+ switch (route) {
+ case UART3:
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+ break;
+ case GPIO:
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+ break;
+ }
+}
+
+static void button_pressed(void)
+{
+ H2W_DBG("");
+ atomic_set(&hi->btn_state, 1);
+ input_report_key(hi->input, KEY_MEDIA, 1);
+ input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+ H2W_DBG("");
+ atomic_set(&hi->btn_state, 0);
+ input_report_key(hi->input, KEY_MEDIA, 0);
+ input_sync(hi->input);
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(void)
+{
+ unsigned long irq_flags;
+
+ H2W_DBG("");
+
+ switch_set_state(&hi->sdev, HTC_HEADSET);
+ configure_cpld(GPIO);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+ msm_serial_debug_enable(false);
+#endif
+
+
+ /* On some non-standard headset adapters (usually those without a
+ * button) the btn line is pulled down at the same time as the detect
+ * line. We can check here by sampling the button line, if it is
+ * low then it is probably a bad adapter so ignore the button.
+ * If the button is released then we stop ignoring the button, so that
+ * the user can recover from the situation where a headset is plugged
+ * in with button held down.
+ */
+ hi->ignore_btn = !gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+
+ /* Enable button irq */
+ local_irq_save(irq_flags);
+ enable_irq(hi->irq_btn);
+ local_irq_restore(irq_flags);
+
+ hi->debounce_time = ktime_set(0, 20000000); /* 20 ms */
+}
+
+static void remove_headset(void)
+{
+ unsigned long irq_flags;
+
+ H2W_DBG("");
+
+ switch_set_state(&hi->sdev, NO_DEVICE);
+ configure_cpld(UART3);
+
+ /* Disable button */
+ local_irq_save(irq_flags);
+ disable_irq(hi->irq_btn);
+ local_irq_restore(irq_flags);
+
+ if (atomic_read(&hi->btn_state))
+ button_released();
+
+ hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */
+}
+
+static void detection_work(struct work_struct *work)
+{
+ unsigned long irq_flags;
+ int clk, cable_in1;
+
+ H2W_DBG("");
+
+ if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1) != 0) {
+ /* Headset not plugged in */
+ if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+ remove_headset();
+ return;
+ }
+
+ /* Something plugged in, lets make sure its a headset */
+
+ /* Switch CPLD to GPIO to do detection */
+ configure_cpld(GPIO);
+ /* Disable headset interrupt while detecting.*/
+ local_irq_save(irq_flags);
+ disable_irq(hi->irq);
+ local_irq_restore(irq_flags);
+
+ /* Set GPIO_CABLE_IN1 as output high */
+ gpio_direction_output(SAPPHIRE_GPIO_CABLE_IN1, 1);
+ /* Delay 10ms for pin stable. */
+ msleep(10);
+ /* Save H2W_CLK */
+ clk = gpio_get_value(SAPPHIRE_GPIO_H2W_CLK_GPI);
+ /* Set GPIO_CABLE_IN1 as input */
+ gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+
+ /* Restore IRQs */
+ local_irq_save(irq_flags);
+ enable_irq(hi->irq);
+ local_irq_restore(irq_flags);
+
+ cable_in1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+
+ if (cable_in1 == 0 && clk == 0) {
+ if (switch_get_state(&hi->sdev) == NO_DEVICE)
+ insert_headset();
+ } else {
+ configure_cpld(UART3);
+ H2W_DBG("CABLE_IN1 was low, but not a headset "
+ "(recent cable_in1 = %d, clk = %d)", cable_in1, clk);
+ }
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+ H2W_DBG("");
+
+ if (switch_get_state(&hi->sdev) == HTC_HEADSET) {
+ if (gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2)) {
+ if (hi->ignore_btn)
+ hi->ignore_btn = 0;
+ else if (atomic_read(&hi->btn_state))
+ button_released();
+ } else {
+ if (!hi->ignore_btn && !atomic_read(&hi->btn_state))
+ button_pressed();
+ }
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
+{
+ H2W_DBG("");
+
+ queue_work(g_detection_work_queue, &g_detection_work);
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t detect_irq_handler(int irq, void *dev_id)
+{
+ int value1, value2;
+ int retry_limit = 10;
+
+ H2W_DBG("");
+ do {
+ value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+ set_irq_type(hi->irq, value1 ?
+ IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+ value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN1);
+ } while (value1 != value2 && retry_limit-- > 0);
+
+ H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+ if ((switch_get_state(&hi->sdev) == NO_DEVICE) ^ value2) {
+ if (switch_get_state(&hi->sdev) == HTC_HEADSET)
+ hi->ignore_btn = 1;
+ /* Do the rest of the work in timer context */
+ hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t button_irq_handler(int irq, void *dev_id)
+{
+ int value1, value2;
+ int retry_limit = 10;
+
+ H2W_DBG("");
+ do {
+ value1 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+ set_irq_type(hi->irq_btn, value1 ?
+ IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+ value2 = gpio_get_value(SAPPHIRE_GPIO_CABLE_IN2);
+ } while (value1 != value2 && retry_limit-- > 0);
+
+ H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+ hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL);
+
+ return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static void h2w_debug_set(void *data, u64 val)
+{
+ switch_set_state(&hi->sdev, (int)val);
+}
+
+static u64 h2w_debug_get(void *data)
+{
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n");
+static int __init h2w_debug_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("h2w", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops);
+
+ return 0;
+}
+
+device_initcall(h2w_debug_init);
+#endif
+
+static int sapphire_h2w_probe(struct platform_device *pdev)
+{
+ int ret;
+ unsigned long irq_flags;
+
+ printk(KERN_INFO "H2W: Registering H2W (headset) driver\n");
+ hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL);
+ if (!hi)
+ return -ENOMEM;
+
+ atomic_set(&hi->btn_state, 0);
+ hi->ignore_btn = 0;
+
+ hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */
+ hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */
+ hi->sdev.name = "h2w";
+ hi->sdev.print_name = sapphire_h2w_print_name;
+
+ ret = switch_dev_register(&hi->sdev);
+ if (ret < 0)
+ goto err_switch_dev_register;
+
+ g_detection_work_queue = create_workqueue("detection");
+ if (g_detection_work_queue == NULL) {
+ ret = -ENOMEM;
+ goto err_create_work_queue;
+ }
+
+ ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN1, "h2w_detect");
+ if (ret < 0)
+ goto err_request_detect_gpio;
+
+ ret = gpio_request(SAPPHIRE_GPIO_CABLE_IN2, "h2w_button");
+ if (ret < 0)
+ goto err_request_button_gpio;
+
+ ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN1);
+ if (ret < 0)
+ goto err_set_detect_gpio;
+
+ ret = gpio_direction_input(SAPPHIRE_GPIO_CABLE_IN2);
+ if (ret < 0)
+ goto err_set_button_gpio;
+
+ hi->irq = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN1);
+ if (hi->irq < 0) {
+ ret = hi->irq;
+ goto err_get_h2w_detect_irq_num_failed;
+ }
+
+ hi->irq_btn = gpio_to_irq(SAPPHIRE_GPIO_CABLE_IN2);
+ if (hi->irq_btn < 0) {
+ ret = hi->irq_btn;
+ goto err_get_button_irq_num_failed;
+ }
+
+ /* Set CPLD MUX to H2W <-> CPLD GPIO */
+ configure_cpld(UART3);
+ /* Set the CPLD connected H2W GPIO's to input */
+ gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0);
+
+ hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hi->timer.function = detect_event_timer_func;
+ hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hi->btn_timer.function = button_event_timer_func;
+
+ ret = request_irq(hi->irq, detect_irq_handler,
+ IRQF_TRIGGER_LOW, "h2w_detect", NULL);
+ if (ret < 0)
+ goto err_request_detect_irq;
+
+ /* Disable button until plugged in */
+ set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN);
+ ret = request_irq(hi->irq_btn, button_irq_handler,
+ IRQF_TRIGGER_LOW, "h2w_button", NULL);
+ if (ret < 0)
+ goto err_request_h2w_headset_button_irq;
+
+ ret = set_irq_wake(hi->irq, 1);
+ if (ret < 0)
+ goto err_request_input_dev;
+ ret = set_irq_wake(hi->irq_btn, 1);
+ if (ret < 0)
+ goto err_request_input_dev;
+
+ hi->input = input_allocate_device();
+ if (!hi->input) {
+ ret = -ENOMEM;
+ goto err_request_input_dev;
+ }
+
+ hi->input->name = "h2w headset";
+ hi->input->evbit[0] = BIT_MASK(EV_KEY);
+ hi->input->keybit[BIT_WORD(KEY_MEDIA)] = BIT_MASK(KEY_MEDIA);
+
+ ret = input_register_device(hi->input);
+ if (ret < 0)
+ goto err_register_input_dev;
+
+ return 0;
+
+err_register_input_dev:
+ input_free_device(hi->input);
+err_request_input_dev:
+ free_irq(hi->irq_btn, 0);
+err_request_h2w_headset_button_irq:
+ free_irq(hi->irq, 0);
+err_request_detect_irq:
+err_get_button_irq_num_failed:
+err_get_h2w_detect_irq_num_failed:
+err_set_button_gpio:
+err_set_detect_gpio:
+ gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+err_request_button_gpio:
+ gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+err_request_detect_gpio:
+ destroy_workqueue(g_detection_work_queue);
+err_create_work_queue:
+ switch_dev_unregister(&hi->sdev);
+err_switch_dev_register:
+ printk(KERN_ERR "H2W: Failed to register driver\n");
+
+ return ret;
+}
+
+static int sapphire_h2w_remove(struct platform_device *pdev)
+{
+ H2W_DBG("");
+ if (switch_get_state(&hi->sdev))
+ remove_headset();
+ input_unregister_device(hi->input);
+ gpio_free(SAPPHIRE_GPIO_CABLE_IN2);
+ gpio_free(SAPPHIRE_GPIO_CABLE_IN1);
+ free_irq(hi->irq_btn, 0);
+ free_irq(hi->irq, 0);
+ destroy_workqueue(g_detection_work_queue);
+ switch_dev_unregister(&hi->sdev);
+
+ return 0;
+}
+
+static struct platform_device sapphire_h2w_device = {
+ .name = "sapphire-h2w",
+};
+
+static struct platform_driver sapphire_h2w_driver = {
+ .probe = sapphire_h2w_probe,
+ .remove = sapphire_h2w_remove,
+ .driver = {
+ .name = "sapphire-h2w",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sapphire_h2w_init(void)
+{
+ if (!machine_is_sapphire())
+ return 0;
+ int ret;
+ H2W_DBG("");
+ ret = platform_driver_register(&sapphire_h2w_driver);
+ if (ret)
+ return ret;
+ return platform_device_register(&sapphire_h2w_device);
+}
+
+static void __exit sapphire_h2w_exit(void)
+{
+ platform_device_unregister(&sapphire_h2w_device);
+ platform_driver_unregister(&sapphire_h2w_driver);
+}
+
+module_init(sapphire_h2w_init);
+module_exit(sapphire_h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver for sapphire");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-keypad.c b/arch/arm/mach-msm/board-sapphire-keypad.c
new file mode 100644
index 000000000000..14f12e5e865c
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-keypad.c
@@ -0,0 +1,122 @@
+/* arch/arm/mach-msm/board-sapphire-keypad.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_sapphire."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int sapphire_col_gpios[] = { 35, 34 };
+
+/* KP_MKIN2 (GPIO40) is not used? */
+static unsigned int sapphire_row_gpios[] = { 42, 41 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(sapphire_row_gpios) + (row))
+
+/*scan matrix key*/
+/* HOME(up) + MENU (down)*/
+static const unsigned short sapphire_keymap1[ARRAY_SIZE(sapphire_col_gpios) *
+ ARRAY_SIZE(sapphire_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_BACK,
+ [KEYMAP_INDEX(0, 1)] = KEY_MENU,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_HOME,
+ [KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+/* MENU(up) + HOME (down)*/
+static const unsigned short sapphire_keymap0[ARRAY_SIZE(sapphire_col_gpios) *
+ ARRAY_SIZE(sapphire_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_BACK,
+ [KEYMAP_INDEX(0, 1)] = KEY_HOME,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_MENU,
+ [KEYMAP_INDEX(1, 1)] = KEY_SEND,
+};
+
+static struct gpio_event_matrix_info sapphire_keypad_matrix_info = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = sapphire_keymap1,
+ .output_gpios = sapphire_col_gpios,
+ .input_gpios = sapphire_row_gpios,
+ .noutputs = ARRAY_SIZE(sapphire_col_gpios),
+ .ninputs = ARRAY_SIZE(sapphire_row_gpios),
+ .settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .debounce_delay.tv.nsec = 50 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ |
+ GPIOKPF_REMOVE_PHANTOM_KEYS |
+ GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry sapphire_keypad_nav_map[] = {
+ { SAPPHIRE_POWER_KEY, KEY_END },
+ { SAPPHIRE_VOLUME_UP, KEY_VOLUMEUP },
+ { SAPPHIRE_VOLUME_DOWN, KEY_VOLUMEDOWN },
+};
+
+static struct gpio_event_input_info sapphire_keypad_nav_info = {
+ .info.func = gpio_event_input_func,
+ .flags = 0,
+ .type = EV_KEY,
+ .keymap = sapphire_keypad_nav_map,
+ .debounce_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .keymap_size = ARRAY_SIZE(sapphire_keypad_nav_map)
+};
+
+static struct gpio_event_info *sapphire_keypad_info[] = {
+ &sapphire_keypad_matrix_info.info,
+ &sapphire_keypad_nav_info.info,
+};
+
+static struct gpio_event_platform_data sapphire_keypad_data = {
+ .name = "sapphire-keypad",
+ .info = sapphire_keypad_info,
+ .info_count = ARRAY_SIZE(sapphire_keypad_info)
+};
+
+static struct platform_device sapphire_keypad_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &sapphire_keypad_data,
+ },
+};
+
+static int __init sapphire_init_keypad(void)
+{
+ if (!machine_is_sapphire())
+ return 0;
+
+ switch (sapphire_get_hwid()) {
+ case 0:
+ sapphire_keypad_matrix_info.keymap = sapphire_keymap0;
+ break;
+ default:
+ sapphire_keypad_matrix_info.keymap = sapphire_keymap1;
+ break;
+ }
+ return platform_device_register(&sapphire_keypad_device);
+}
+
+device_initcall(sapphire_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-sapphire-mmc.c b/arch/arm/mach-msm/board-sapphire-mmc.c
new file mode 100644
index 000000000000..ff2a5fdc6c14
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-mmc.c
@@ -0,0 +1,479 @@
+/* linux/arch/arm/mach-msm/board-sapphire-mmc.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include <asm/mach/mmc.h>
+
+#include "devices.h"
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+extern int msm_add_sdcc(unsigned int controller,
+ struct mmc_platform_data *plat);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n;
+ unsigned id;
+ for (n = 0; n < len; n++) {
+ id = table[n];
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+ }
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+ PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+ PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+ PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+ PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+ PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+ PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+ PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+ PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init sapphire_disablesdcard_setup(char *str)
+{
+ int cal = simple_strtol(str, NULL, 0);
+
+ opt_disable_sdcard = cal;
+ return 1;
+}
+
+__setup("board_sapphire.disable_sdcard=", sapphire_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot; /* SD slot power */
+
+struct mmc_vdd_xlat {
+ int mask;
+ int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+ { MMC_VDD_165_195, 1800 },
+ { MMC_VDD_20_21, 2050 },
+ { MMC_VDD_21_22, 2150 },
+ { MMC_VDD_22_23, 2250 },
+ { MMC_VDD_23_24, 2350 },
+ { MMC_VDD_24_25, 2450 },
+ { MMC_VDD_25_26, 2550 },
+ { MMC_VDD_26_27, 2650 },
+ { MMC_VDD_27_28, 2750 },
+ { MMC_VDD_28_29, 2850 },
+ { MMC_VDD_29_30, 2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t sapphire_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+ int i, rc;
+
+ BUG_ON(!vreg_sdslot);
+
+ if (vdd == sdslot_vdd)
+ return 0;
+
+ sdslot_vdd = vdd;
+
+ if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+ printk(KERN_DEBUG "%s: Disabling SD slot power\n", __func__);
+#endif
+ config_gpio_table(sdcard_off_gpio_table,
+ ARRAY_SIZE(sdcard_off_gpio_table));
+ vreg_disable(vreg_sdslot);
+ sdslot_vreg_enabled = 0;
+ return 0;
+ }
+
+ if (!sdslot_vreg_enabled) {
+ rc = vreg_enable(vreg_sdslot);
+ if (rc) {
+ printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+ __func__, rc);
+ }
+ config_gpio_table(sdcard_on_gpio_table,
+ ARRAY_SIZE(sdcard_on_gpio_table));
+ sdslot_vreg_enabled = 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+ if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+ printk(KERN_DEBUG "%s: Setting level to %u\n",
+ __func__, mmc_vdd_table[i].level);
+#endif
+ rc = vreg_set_level(vreg_sdslot,
+ mmc_vdd_table[i].level);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: Error setting vreg level (%d)\n",
+ __func__, rc);
+ }
+ return 0;
+ }
+ }
+
+ printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+ return 0;
+}
+
+static unsigned int sapphire_sdslot_status(struct device *dev)
+{
+ unsigned int status;
+
+ status = (unsigned int) gpio_get_value(SAPPHIRE_GPIO_SDMC_CD_N);
+ return !status;
+}
+
+#define SAPPHIRE_MMC_VDD (MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+ | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+ | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+ | MMC_VDD_28_29 | MMC_VDD_29_30)
+
+static struct mmc_platform_data sapphire_sdslot_data = {
+ .ocr_mask = SAPPHIRE_MMC_VDD,
+ .status_irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N),
+ .status = sapphire_sdslot_status,
+ .translate_vdd = sapphire_sdslot_switchvdd,
+};
+
+/* ---- WIFI ---- */
+
+static uint32_t wifi_on_gpio_table[] = {
+ PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+ PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+ PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+ PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+ PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+ PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+ PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+ PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
+};
+
+static struct vreg *vreg_wifi_osc; /* WIFI 32khz oscilator */
+static int sapphire_wifi_cd = 0; /* WIFI virtual 'card detect' status */
+
+static struct sdio_embedded_func wifi_func = {
+ .f_class = SDIO_CLASS_WLAN,
+ .f_maxblksize = 512,
+};
+
+static struct embedded_sdio_data sapphire_wifi_emb_data = {
+ .cis = {
+ .vendor = 0x104c,
+ .device = 0x9066,
+ .blksize = 512,
+ .max_dtr = 20000000,
+ },
+ .cccr = {
+ .multi_block = 0,
+ .low_speed = 0,
+ .wide_bus = 1,
+ .high_power = 0,
+ .high_speed = 0,
+ },
+ .funcs = &wifi_func,
+ .num_funcs = 1,
+};
+
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int sapphire_wifi_status_register(void (*callback)(int card_present,
+ void *dev_id),
+ void *dev_id)
+{
+ if (wifi_status_cb)
+ return -EAGAIN;
+ wifi_status_cb = callback;
+ wifi_status_cb_devid = dev_id;
+ return 0;
+}
+
+static unsigned int sapphire_wifi_status(struct device *dev)
+{
+ return sapphire_wifi_cd;
+}
+
+int sapphire_wifi_set_carddetect(int val)
+{
+ printk(KERN_DEBUG "%s: %d\n", __func__, val);
+ sapphire_wifi_cd = val;
+ if (wifi_status_cb)
+ wifi_status_cb(val, wifi_status_cb_devid);
+ else
+ printk(KERN_WARNING "%s: Nobody to notify\n", __func__);
+ return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_set_carddetect);
+#endif
+
+static int sapphire_wifi_power_state;
+static int sapphire_bt_power_state;
+
+int sapphire_wifi_power(int on)
+{
+ int rc;
+
+ printk(KERN_DEBUG "%s: %d\n", __func__, on);
+
+ if (on) {
+ config_gpio_table(wifi_on_gpio_table,
+ ARRAY_SIZE(wifi_on_gpio_table));
+ rc = vreg_enable(vreg_wifi_osc);
+ if (rc)
+ return rc;
+ htc_pwrsink_set(PWRSINK_WIFI, 70);
+ } else {
+ config_gpio_table(wifi_off_gpio_table,
+ ARRAY_SIZE(wifi_off_gpio_table));
+ htc_pwrsink_set(PWRSINK_WIFI, 0);
+ }
+ gpio_set_value(SAPPHIRE_GPIO_MAC_32K_EN, on);
+ mdelay(100);
+ gpio_set_value(SAPPHIRE_GPIO_WIFI_EN, on);
+ mdelay(100);
+ if (!on)
+ vreg_disable(vreg_wifi_osc);
+ sapphire_wifi_power_state = on;
+ return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_power);
+#endif
+
+/* Eenable VREG_MMC pin to turn on fastclock oscillator : colin */
+int sapphire_bt_fastclock_power(int on)
+{
+ int rc;
+
+ printk(KERN_DEBUG "sapphire_bt_fastclock_power on = %d\n", on);
+ if (vreg_wifi_osc) {
+ if (on) {
+ rc = vreg_enable(vreg_wifi_osc);
+ printk(KERN_DEBUG "BT vreg_enable vreg_mmc, rc=%d\n",
+ rc);
+ if (rc) {
+ printk("Error turn sapphire_bt_fastclock_power rc=%d\n", rc);
+ return rc;
+ }
+ } else {
+ if (!sapphire_wifi_power_state) {
+ vreg_disable(vreg_wifi_osc);
+ printk(KERN_DEBUG "BT disable vreg_wifi_osc.\n");
+ } else
+ printk(KERN_DEBUG "BT shouldn't disable vreg_wifi_osc. WiFi is using it!!\n");
+ }
+ }
+ sapphire_bt_power_state = on;
+ return 0;
+}
+EXPORT_SYMBOL(sapphire_bt_fastclock_power);
+
+static int sapphire_wifi_reset_state;
+void sapphire_wifi_reset(int on)
+{
+ printk(KERN_DEBUG "%s: %d\n", __func__, on);
+ gpio_set_value(SAPPHIRE_GPIO_WIFI_PA_RESETX, !on);
+ sapphire_wifi_reset_state = on;
+ mdelay(50);
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(sapphire_wifi_reset);
+#endif
+
+static struct mmc_platform_data sapphire_wifi_data = {
+ .ocr_mask = MMC_VDD_28_29,
+ .status = sapphire_wifi_status,
+ .register_status_notify = sapphire_wifi_status_register,
+ .embedded_sdio = &sapphire_wifi_emb_data,
+};
+
+int __init sapphire_init_mmc(unsigned int sys_rev)
+{
+ wifi_status_cb = NULL;
+
+ sdslot_vreg_enabled = 0;
+
+ vreg_sdslot = vreg_get(0, "gp6");
+ if (IS_ERR(vreg_sdslot))
+ return PTR_ERR(vreg_sdslot);
+ vreg_wifi_osc = vreg_get(0, "mmc");
+ if (IS_ERR(vreg_wifi_osc))
+ return PTR_ERR(vreg_wifi_osc);
+
+ set_irq_wake(SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_SDMC_CD_N), 1);
+
+ msm_add_sdcc(1, &sapphire_wifi_data);
+
+ if (!opt_disable_sdcard)
+ msm_add_sdcc(2, &sapphire_sdslot_data);
+ else
+ printk(KERN_INFO "sapphire: SD-Card interface disabled\n");
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int sapphiremmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+ sapphire_wifi_reset((int) val);
+ return 0;
+}
+
+static int sapphiremmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+ *val = sapphire_wifi_reset_state;
+ return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+ sapphire_wifi_set_carddetect((int) val);
+ return 0;
+}
+
+static int sapphiremmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+ *val = sapphire_wifi_cd;
+ return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+ sapphire_wifi_power((int) val);
+ return 0;
+}
+
+static int sapphiremmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+
+ *val = sapphire_wifi_power_state;
+ return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+ sapphire_sdslot_switchvdd(NULL, (unsigned int) val);
+ return 0;
+}
+
+static int sapphiremmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+ *val = sdslot_vdd;
+ return 0;
+}
+
+static int sapphiremmc_dbg_sd_cd_set(void *data, u64 val)
+{
+ return -ENOSYS;
+}
+
+static int sapphiremmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+ *val = sapphire_sdslot_status(NULL);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_reset_fops,
+ sapphiremmc_dbg_wifi_reset_get,
+ sapphiremmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_cd_fops,
+ sapphiremmc_dbg_wifi_cd_get,
+ sapphiremmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_wifi_pwr_fops,
+ sapphiremmc_dbg_wifi_pwr_get,
+ sapphiremmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_pwr_fops,
+ sapphiremmc_dbg_sd_pwr_get,
+ sapphiremmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(sapphiremmc_dbg_sd_cd_fops,
+ sapphiremmc_dbg_sd_cd_get,
+ sapphiremmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init sapphiremmc_dbg_init(void)
+{
+ struct dentry *dent;
+
+ if (!machine_is_sapphire())
+ return 0;
+
+ dent = debugfs_create_dir("sapphiremmc_dbg", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("wifi_reset", 0644, dent, NULL,
+ &sapphiremmc_dbg_wifi_reset_fops);
+ debugfs_create_file("wifi_cd", 0644, dent, NULL,
+ &sapphiremmc_dbg_wifi_cd_fops);
+ debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+ &sapphiremmc_dbg_wifi_pwr_fops);
+
+ debugfs_create_file("sd_pwr", 0644, dent, NULL,
+ &sapphiremmc_dbg_sd_pwr_fops);
+ debugfs_create_file("sd_cd", 0644, dent, NULL,
+ &sapphiremmc_dbg_sd_cd_fops);
+
+ return 0;
+}
+
+device_initcall(sapphiremmc_dbg_init);
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire-panel.c b/arch/arm/mach-msm/board-sapphire-panel.c
new file mode 100644
index 000000000000..9129f4cdcb5f
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-panel.c
@@ -0,0 +1,656 @@
+/* linux/arch/arm/mach-msm/board-sapphire-panel.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "proc_comm.h"
+#include "devices.h"
+
+enum sapphire_panel_type {
+ SAPPHIRE_PANEL_SHARP = 0,
+ SAPPHIRE_PANEL_TOPPOLY,
+ NUM_OF_SAPPHIRE_PANELS,
+};
+static int g_panel_id = -1 ;
+
+#define SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS 132
+
+static int sapphire_backlight_off;
+static int sapphire_backlight_brightness =
+ SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS;
+
+static uint8_t sapphire_backlight_last_level = 33;
+static DEFINE_MUTEX(sapphire_backlight_lock);
+
+/* Divide dimming level into 12 sections, and restrict maximum level to 27 */
+#define DIMMING_STEPS 12
+static unsigned dimming_levels[NUM_OF_SAPPHIRE_PANELS][DIMMING_STEPS] = {
+ {0, 1, 2, 3, 6, 9, 11, 13, 16, 19, 22, 25}, /* Sharp */
+ {0, 1, 2, 4, 7, 10, 13, 15, 18, 21, 24, 27}, /* Toppolly */
+};
+static unsigned pwrsink_percents[] = {0, 6, 8, 15, 26, 34, 46, 54, 65, 77, 87,
+ 100};
+
+static void sapphire_set_backlight_level(uint8_t level)
+{
+ unsigned dimming_factor = 255/DIMMING_STEPS + 1;
+ int index = (level + dimming_factor - 1) / dimming_factor;
+ unsigned percent;
+ unsigned long flags;
+ int i = 0;
+
+ printk(KERN_INFO "level=%d, new level=dimming_levels[%d]=%d\n",
+ level, index, dimming_levels[g_panel_id][index]);
+ percent = pwrsink_percents[index];
+ level = dimming_levels[g_panel_id][index];
+
+ if (sapphire_backlight_last_level == level)
+ return;
+
+ if (level == 0) {
+ gpio_set_value(27, 0);
+ msleep(2);
+ } else {
+ local_irq_save(flags);
+ if (sapphire_backlight_last_level == 0) {
+ gpio_set_value(27, 1);
+ udelay(40);
+ sapphire_backlight_last_level = 33;
+ }
+ i = (sapphire_backlight_last_level - level + 33) % 33;
+ while (i-- > 0) {
+ gpio_set_value(27, 0);
+ udelay(1);
+ gpio_set_value(27, 1);
+ udelay(1);
+ }
+ local_irq_restore(flags);
+ }
+ sapphire_backlight_last_level = level;
+ htc_pwrsink_set(PWRSINK_BACKLIGHT, percent);
+}
+
+#define MDDI_CLIENT_CORE_BASE 0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE 0x120000
+#define I2C_BLOCK_BASE 0x130000
+#define PWM_BLOCK_BASE 0x140000
+#define GPIO_BLOCK_BASE 0x150000
+#define SYSTEM_BLOCK1_BASE 0x160000
+#define SYSTEM_BLOCK2_BASE 0x170000
+
+
+#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
+#define SYSCLKENA (MDDI_CLIENT_CORE_BASE|0x2C)
+#define PWM0OFF (PWM_BLOCK_BASE|0x1C)
+
+#define V_VDDE2E_VDD2_GPIO 0
+#define V_VDDE2E_VDD2_GPIO_5M 89
+#define MDDI_RST_N 82
+
+#define MDDICAP0 (MDDI_CLIENT_CORE_BASE|0x00)
+#define MDDICAP1 (MDDI_CLIENT_CORE_BASE|0x04)
+#define MDDICAP2 (MDDI_CLIENT_CORE_BASE|0x08)
+#define MDDICAP3 (MDDI_CLIENT_CORE_BASE|0x0C)
+#define MDCAPCHG (MDDI_CLIENT_CORE_BASE|0x10)
+#define MDCRCERC (MDDI_CLIENT_CORE_BASE|0x14)
+#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18)
+#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C)
+#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20)
+#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
+#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28)
+#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C)
+#define TESTMODE (MDDI_CLIENT_CORE_BASE|0x30)
+#define FIFOMONI (MDDI_CLIENT_CORE_BASE|0x34)
+#define INTMONI (MDDI_CLIENT_CORE_BASE|0x38)
+#define MDIOBIST (MDDI_CLIENT_CORE_BASE|0x3C)
+#define MDIOPSET (MDDI_CLIENT_CORE_BASE|0x40)
+#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44)
+#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48)
+#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C)
+#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50)
+#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54)
+
+#define SRST (LCD_CONTROL_BLOCK_BASE|0x00)
+#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04)
+#define START (LCD_CONTROL_BLOCK_BASE|0x08)
+#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C)
+#define CMN (LCD_CONTROL_BLOCK_BASE|0x10)
+#define GAMMA (LCD_CONTROL_BLOCK_BASE|0x14)
+#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
+#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
+#define HDE_LEFT (LCD_CONTROL_BLOCK_BASE|0x24)
+#define VDE_TOP (LCD_CONTROL_BLOCK_BASE|0x28)
+#define PXL (LCD_CONTROL_BLOCK_BASE|0x30)
+#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
+#define HSW (LCD_CONTROL_BLOCK_BASE|0x38)
+#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40)
+#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44)
+#define VSW (LCD_CONTROL_BLOCK_BASE|0x48)
+#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50)
+#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
+#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58)
+#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60)
+#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64)
+#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68)
+#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70)
+#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74)
+#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78)
+#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80)
+#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84)
+#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88)
+#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C)
+
+#define SSICTL (SPI_BLOCK_BASE|0x00)
+#define SSITIME (SPI_BLOCK_BASE|0x04)
+#define SSITX (SPI_BLOCK_BASE|0x08)
+#define SSIRX (SPI_BLOCK_BASE|0x0C)
+#define SSIINTC (SPI_BLOCK_BASE|0x10)
+#define SSIINTS (SPI_BLOCK_BASE|0x14)
+#define SSIDBG1 (SPI_BLOCK_BASE|0x18)
+#define SSIDBG2 (SPI_BLOCK_BASE|0x1C)
+#define SSIID (SPI_BLOCK_BASE|0x20)
+
+#define WKREQ (SYSTEM_BLOCK1_BASE|0x00)
+#define CLKENB (SYSTEM_BLOCK1_BASE|0x04)
+#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08)
+#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C)
+#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
+
+#define GPIODATA (GPIO_BLOCK_BASE|0x00)
+#define GPIODIR (GPIO_BLOCK_BASE|0x04)
+#define GPIOIS (GPIO_BLOCK_BASE|0x08)
+#define GPIOIBE (GPIO_BLOCK_BASE|0x0C)
+#define GPIOIEV (GPIO_BLOCK_BASE|0x10)
+#define GPIOIE (GPIO_BLOCK_BASE|0x14)
+#define GPIORIS (GPIO_BLOCK_BASE|0x18)
+#define GPIOMIS (GPIO_BLOCK_BASE|0x1C)
+#define GPIOIC (GPIO_BLOCK_BASE|0x20)
+#define GPIOOMS (GPIO_BLOCK_BASE|0x24)
+#define GPIOPC (GPIO_BLOCK_BASE|0x28)
+#define GPIOID (GPIO_BLOCK_BASE|0x30)
+
+#define SPI_WRITE(reg, val) \
+ { SSITX, 0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \
+ { 0, 5 },
+
+#define SPI_WRITE1(reg) \
+ { SSITX, (reg) & 0xff }, \
+ { 0, 5 },
+
+struct mddi_table {
+ uint32_t reg;
+ uint32_t value;
+};
+static struct mddi_table mddi_toshiba_init_table[] = {
+ { DPSET0, 0x09e90046 },
+ { DPSET1, 0x00000118 },
+ { DPSUS, 0x00000000 },
+ { DPRUN, 0x00000001 },
+ { 1, 14 }, /* msleep 14 */
+ { SYSCKENA, 0x00000001 },
+ /*{ CLKENB, 0x000000EF } */
+ { CLKENB, 0x0000A1EF }, /* # SYS.CLKENB # Enable clocks for each module (without DCLK , i2cCLK) */
+ /*{ CLKENB, 0x000025CB }, Clock enable register */
+
+ { GPIODATA, 0x02000200 }, /* # GPI .GPIODATA # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */
+ { GPIODIR, 0x000030D }, /* 24D # GPI .GPIODIR # Select direction of GPIO port (0,2,3,6,9 output) */
+ { GPIOSEL, 0/*0x00000173*/}, /* # SYS.GPIOSEL # GPIO port multiplexing control */
+ { GPIOPC, 0x03C300C0 }, /* # GPI .GPIOPC # GPIO2,3 PD cut */
+ { WKREQ, 0x00000000 }, /* # SYS.WKREQ # Wake-up request event is VSYNC alignment */
+
+ { GPIOIBE, 0x000003FF },
+ { GPIOIS, 0x00000000 },
+ { GPIOIC, 0x000003FF },
+ { GPIOIE, 0x00000000 },
+
+ { GPIODATA, 0x00040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
+ { 1, 1 }, /* msleep 1 */
+ { GPIODATA, 0x02040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
+ { DRAMPWR, 0x00000001 }, /* eDRAM power */
+};
+
+static struct mddi_table mddi_toshiba_panel_init_table[] = {
+ { SRST, 0x00000003 }, /* FIFO/LCDC not reset */
+ { PORT_ENB, 0x00000001 }, /* Enable sync. Port */
+ { START, 0x00000000 }, /* To stop operation */
+ /*{ START, 0x00000001 }, To start operation */
+ { PORT, 0x00000004 }, /* Polarity of VS/HS/DE. */
+ { CMN, 0x00000000 },
+ { GAMMA, 0x00000000 }, /* No Gamma correction */
+ { INTFLG, 0x00000000 }, /* VSYNC interrupt flag clear/status */
+ { INTMSK, 0x00000000 }, /* VSYNC interrupt mask is off. */
+ { MPLFBUF, 0x00000000 }, /* Select frame buffer's base address. */
+ { HDE_LEFT, 0x00000000 }, /* The value of HDE_LEFT. */
+ { VDE_TOP, 0x00000000 }, /* The value of VDE_TPO. */
+ { PXL, 0x00000001 }, /* 1. RGB666 */
+ /* 2. Data is valid from 1st frame of beginning. */
+ { HDE_START, 0x00000006 }, /* HDE_START= 14 PCLK */
+ { HDE_SIZE, 0x0000009F }, /* HDE_SIZE=320 PCLK */
+ { HSW, 0x00000004 }, /* HSW= 10 PCLK */
+ { VSW, 0x00000001 }, /* VSW=2 HCYCLE */
+ { VDE_START, 0x00000003 }, /* VDE_START=4 HCYCLE */
+ { VDE_SIZE, 0x000001DF }, /* VDE_SIZE=480 HCYCLE */
+ { WAKEUP, 0x000001e2 }, /* Wakeup position in VSYNC mode. */
+ { WSYN_DLY, 0x00000000 }, /* Wakeup position in VSIN mode. */
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { CLKENB, 0x000025CB }, /* Clock enable register */
+
+ { SSICTL, 0x00000170 }, /* SSI control register */
+ { SSITIME, 0x00000250 }, /* SSI timing control register */
+ { SSICTL, 0x00000172 }, /* SSI control register */
+};
+
+
+static struct mddi_table mddi_sharp_init_table[] = {
+ { VCYCLE, 0x000001eb },
+ { HCYCLE, 0x000000ae },
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { 1, 1 }, /* msleep 1 */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { 1, 10 }, /* msleep 10 */
+ SPI_WRITE(0x5f, 0x01)
+ SPI_WRITE1(0x11)
+ { 1, 200 }, /* msleep 200 */
+ SPI_WRITE1(0x29)
+ SPI_WRITE1(0xde)
+ { START, 0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_sharp_deinit_table[] = {
+ { 1, 200 }, /* msleep 200 */
+ SPI_WRITE(0x10, 0x1)
+ { 1, 100 }, /* msleep 100 */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { 1, 10 }, /* msleep 10 */
+};
+
+static struct mddi_table mddi_tpo_init_table[] = {
+ { VCYCLE, 0x000001e5 },
+ { HCYCLE, 0x000000ac },
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { 0, 20 }, /* udelay 20 */
+ { GPIODATA, 0x00000004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { 0, 20 }, /* udelay 20 */
+
+ SPI_WRITE(0x08, 0x01)
+ { 0, 500 }, /* udelay 500 */
+ SPI_WRITE(0x08, 0x00)
+ SPI_WRITE(0x02, 0x00)
+ SPI_WRITE(0x03, 0x04)
+ SPI_WRITE(0x04, 0x0e)
+ SPI_WRITE(0x09, 0x02)
+ SPI_WRITE(0x0b, 0x08)
+ SPI_WRITE(0x0c, 0x53)
+ SPI_WRITE(0x0d, 0x01)
+ SPI_WRITE(0x0e, 0xe0)
+ SPI_WRITE(0x0f, 0x01)
+ SPI_WRITE(0x10, 0x58)
+ SPI_WRITE(0x20, 0x1e)
+ SPI_WRITE(0x21, 0x0a)
+ SPI_WRITE(0x22, 0x0a)
+ SPI_WRITE(0x23, 0x1e)
+ SPI_WRITE(0x25, 0x32)
+ SPI_WRITE(0x26, 0x00)
+ SPI_WRITE(0x27, 0xac)
+ SPI_WRITE(0x29, 0x06)
+ SPI_WRITE(0x2a, 0xa4)
+ SPI_WRITE(0x2b, 0x45)
+ SPI_WRITE(0x2c, 0x45)
+ SPI_WRITE(0x2d, 0x15)
+ SPI_WRITE(0x2e, 0x5a)
+ SPI_WRITE(0x2f, 0xff)
+ SPI_WRITE(0x30, 0x6b)
+ SPI_WRITE(0x31, 0x0d)
+ SPI_WRITE(0x32, 0x48)
+ SPI_WRITE(0x33, 0x82)
+ SPI_WRITE(0x34, 0xbd)
+ SPI_WRITE(0x35, 0xe7)
+ SPI_WRITE(0x36, 0x18)
+ SPI_WRITE(0x37, 0x94)
+ SPI_WRITE(0x38, 0x01)
+ SPI_WRITE(0x39, 0x5d)
+ SPI_WRITE(0x3a, 0xae)
+ SPI_WRITE(0x3b, 0xff)
+ SPI_WRITE(0x07, 0x09)
+ { 0, 10 }, /* udelay 10 */
+ { START, 0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_tpo_deinit_table[] = {
+ SPI_WRITE(0x07, 0x19)
+ { START, 0x00000000 }, /* To stop operation */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { 0, 5 }, /* usleep 5 */
+};
+
+
+#define GPIOSEL_VWAKEINT (1U << 0)
+#define INTMASK_VWAKEOUT (1U << 0)
+
+static void sapphire_process_mddi_table(
+ struct msm_mddi_client_data *client_data,
+ struct mddi_table *table, size_t count)
+{
+ int i;
+ for (i = 0; i < count; i++) {
+ uint32_t reg = table[i].reg;
+ uint32_t value = table[i].value;
+
+ if (reg == 0)
+ udelay(value);
+ else if (reg == 1)
+ msleep(value);
+ else
+ client_data->remote_write(client_data, value, reg);
+ }
+}
+
+static struct vreg *vreg_lcm_2v85;
+
+static void sapphire_mddi_power_client(struct msm_mddi_client_data *client_data,
+ int on)
+{
+ unsigned id, on_off;
+ printk(KERN_INFO "sapphire_mddi_client_power:%d\r\n", on);
+ if (on) {
+ on_off = 0;
+ id = PM_VREG_PDOWN_MDDI_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+
+ gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 1);
+ mdelay(5); /* delay time >5ms and <10ms */
+
+ if (is_12pin_camera())
+ gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 1);
+ else
+ gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
+
+ gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 1);
+ msleep(3);
+ id = PM_VREG_PDOWN_AUX_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ vreg_enable(vreg_lcm_2v85);
+ msleep(3);
+ gpio_set_value(MDDI_RST_N, 1);
+ msleep(10);
+ } else {
+ gpio_set_value(SAPPHIRE_GPIO_MDDI_32K_EN, 0);
+ gpio_set_value(MDDI_RST_N, 0);
+ msleep(10);
+ vreg_disable(vreg_lcm_2v85);
+ on_off = 1;
+ id = PM_VREG_PDOWN_AUX_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ msleep(5);
+ if (is_12pin_camera())
+ gpio_set_value(V_VDDE2E_VDD2_GPIO_5M, 0);
+ else
+ gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
+
+ msleep(200);
+ gpio_set_value(SAPPHIRE_MDDI_1V5_EN, 0);
+ id = PM_VREG_PDOWN_MDDI_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ }
+}
+
+static int sapphire_mddi_toshiba_client_init(
+ struct msm_mddi_bridge_platform_data *bridge_data,
+ struct msm_mddi_client_data *client_data)
+{
+ int panel_id;
+
+ client_data->auto_hibernate(client_data, 0);
+ sapphire_process_mddi_table(client_data, mddi_toshiba_init_table,
+ ARRAY_SIZE(mddi_toshiba_init_table));
+ client_data->auto_hibernate(client_data, 1);
+ g_panel_id = panel_id =
+ (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+ if (panel_id > 1) {
+ printk(KERN_ERR "unknown panel id at mddi_enable\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int sapphire_mddi_toshiba_client_uninit(
+ struct msm_mddi_bridge_platform_data *bridge_data,
+ struct msm_mddi_client_data *client_data)
+{
+ return 0;
+}
+
+static int sapphire_mddi_panel_unblank(
+ struct msm_mddi_bridge_platform_data *bridge_data,
+ struct msm_mddi_client_data *client_data)
+{
+ int panel_id, ret = 0;
+
+ sapphire_set_backlight_level(0);
+ client_data->auto_hibernate(client_data, 0);
+ sapphire_process_mddi_table(client_data, mddi_toshiba_panel_init_table,
+ ARRAY_SIZE(mddi_toshiba_panel_init_table));
+ panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+ switch (panel_id) {
+ case 0:
+ printk(KERN_DEBUG "init sharp panel\n");
+ sapphire_process_mddi_table(client_data,
+ mddi_sharp_init_table,
+ ARRAY_SIZE(mddi_sharp_init_table));
+ break;
+ case 1:
+ printk(KERN_DEBUG "init tpo panel\n");
+ sapphire_process_mddi_table(client_data,
+ mddi_tpo_init_table,
+ ARRAY_SIZE(mddi_tpo_init_table));
+ break;
+ default:
+ printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+ ret = -1;
+ };
+ mutex_lock(&sapphire_backlight_lock);
+ sapphire_set_backlight_level(sapphire_backlight_brightness);
+ sapphire_backlight_off = 0;
+ mutex_unlock(&sapphire_backlight_lock);
+ client_data->auto_hibernate(client_data, 1);
+ /* reenable vsync */
+ client_data->remote_write(client_data, GPIOSEL_VWAKEINT,
+ GPIOSEL);
+ client_data->remote_write(client_data, INTMASK_VWAKEOUT,
+ INTMASK);
+ return ret;
+
+}
+
+static int sapphire_mddi_panel_blank(
+ struct msm_mddi_bridge_platform_data *bridge_data,
+ struct msm_mddi_client_data *client_data)
+{
+ int panel_id, ret = 0;
+
+ panel_id = (client_data->remote_read(client_data, GPIODATA) >> 4) & 3;
+ client_data->auto_hibernate(client_data, 0);
+ switch (panel_id) {
+ case 0:
+ printk(KERN_DEBUG "deinit sharp panel\n");
+ sapphire_process_mddi_table(client_data,
+ mddi_sharp_deinit_table,
+ ARRAY_SIZE(mddi_sharp_deinit_table));
+ break;
+ case 1:
+ printk(KERN_DEBUG "deinit tpo panel\n");
+ sapphire_process_mddi_table(client_data,
+ mddi_tpo_deinit_table,
+ ARRAY_SIZE(mddi_tpo_deinit_table));
+ break;
+ default:
+ printk(KERN_DEBUG "unknown panel_id: %d\n", panel_id);
+ ret = -1;
+ };
+ client_data->auto_hibernate(client_data, 1);
+ mutex_lock(&sapphire_backlight_lock);
+ sapphire_set_backlight_level(0);
+ sapphire_backlight_off = 1;
+ mutex_unlock(&sapphire_backlight_lock);
+ client_data->remote_write(client_data, 0, SYSCLKENA);
+ client_data->remote_write(client_data, 1, DPSUS);
+
+ return ret;
+}
+
+static void sapphire_brightness_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+ mutex_lock(&sapphire_backlight_lock);
+ sapphire_backlight_brightness = value;
+ if (!sapphire_backlight_off)
+ sapphire_set_backlight_level(sapphire_backlight_brightness);
+ mutex_unlock(&sapphire_backlight_lock);
+}
+
+static struct led_classdev sapphire_backlight_led = {
+ .name = "lcd-backlight",
+ .brightness = SAPPHIRE_DEFAULT_BACKLIGHT_BRIGHTNESS,
+ .brightness_set = sapphire_brightness_set,
+};
+
+static int sapphire_backlight_probe(struct platform_device *pdev)
+{
+ led_classdev_register(&pdev->dev, &sapphire_backlight_led);
+ return 0;
+}
+
+static int sapphire_backlight_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&sapphire_backlight_led);
+ return 0;
+}
+
+static struct platform_driver sapphire_backlight_driver = {
+ .probe = sapphire_backlight_probe,
+ .remove = sapphire_backlight_remove,
+ .driver = {
+ .name = "sapphire-backlight",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct resource resources_msm_fb[] = {
+ {
+ .start = SMI64_MSM_FB_BASE,
+ .end = SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct msm_mddi_bridge_platform_data toshiba_client_data = {
+ .init = sapphire_mddi_toshiba_client_init,
+ .uninit = sapphire_mddi_toshiba_client_uninit,
+ .blank = sapphire_mddi_panel_blank,
+ .unblank = sapphire_mddi_panel_unblank,
+ .fb_data = {
+ .xres = 320,
+ .yres = 480,
+ .width = 45,
+ .height = 67,
+ .output_format = 0,
+ },
+};
+
+static struct msm_mddi_platform_data mddi_pdata = {
+ .clk_rate = 122880000,
+ .power_client = sapphire_mddi_power_client,
+ .fb_resource = resources_msm_fb,
+ .num_clients = 1,
+ .client_platform_data = {
+ {
+ .product_id = (0xd263 << 16 | 0),
+ .name = "mddi_c_d263_0000",
+ .id = 0,
+ .client_data = &toshiba_client_data,
+ .clk_rate = 0,
+ },
+ },
+};
+
+static struct platform_device sapphire_backlight = {
+ .name = "sapphire-backlight",
+};
+
+int __init sapphire_init_panel(void)
+{
+ int rc = -1;
+ uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA); /* GPIO27 */
+
+ if (!machine_is_sapphire())
+ return 0;
+
+ /* checking board as soon as possible */
+ printk("sapphire_init_panel:machine_is_sapphire=%d, machine_arch_type=%d, MACH_TYPE_SAPPHIRE=%d\r\n", machine_is_sapphire(), machine_arch_type, MACH_TYPE_SAPPHIRE);
+ if (!machine_is_sapphire())
+ return 0;
+
+ vreg_lcm_2v85 = vreg_get(0, "gp4");
+ if (IS_ERR(vreg_lcm_2v85))
+ return PTR_ERR(vreg_lcm_2v85);
+
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+
+ /* setup FB by SMI size */
+ if (sapphire_get_smi_size() == 32) {
+ resources_msm_fb[0].start = SMI32_MSM_FB_BASE;
+ resources_msm_fb[0].end = SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE - 1;
+ }
+
+ rc = platform_device_register(&msm_device_mdp);
+ if (rc)
+ return rc;
+ msm_device_mddi0.dev.platform_data = &mddi_pdata;
+ rc = platform_device_register(&msm_device_mddi0);
+ if (rc)
+ return rc;
+ platform_device_register(&sapphire_backlight);
+ return platform_driver_register(&sapphire_backlight_driver);
+}
+
+device_initcall(sapphire_init_panel);
diff --git a/arch/arm/mach-msm/board-sapphire-rfkill.c b/arch/arm/mach-msm/board-sapphire-rfkill.c
new file mode 100644
index 000000000000..135ffe82c328
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-rfkill.c
@@ -0,0 +1,99 @@
+/* linux/arch/arm/mach-msm/board-sapphire-rfkill.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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.
+*/
+
+/* Control bluetooth power for sapphire platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+extern int sapphire_bt_fastclock_power(int on);
+
+static int bluetooth_set_power(void *data, enum rfkill_state state)
+{
+ switch (state) {
+ case RFKILL_STATE_UNBLOCKED:
+ sapphire_bt_fastclock_power(1);
+ gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 1);
+ udelay(10);
+ gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
+ break;
+ case RFKILL_STATE_SOFT_BLOCKED:
+ gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
+ gpio_set_value(SAPPHIRE_GPIO_BT_32K_EN, 0);
+ sapphire_bt_fastclock_power(0);
+ break;
+ default:
+ printk(KERN_ERR "bad bluetooth rfkill state %d\n", state);
+ }
+ return 0;
+}
+
+static int __init sapphire_rfkill_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ /* default to bluetooth off */
+ rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED);
+ bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED);
+
+ bt_rfk = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH);
+ if (!bt_rfk)
+ return -ENOMEM;
+
+ bt_rfk->name = bt_name;
+ bt_rfk->state = RFKILL_STATE_SOFT_BLOCKED;
+ /* userspace cannot take exclusive control */
+ bt_rfk->user_claim_unsupported = 1;
+ bt_rfk->user_claim = 0;
+ bt_rfk->data = NULL; /* user data */
+ bt_rfk->toggle_radio = bluetooth_set_power;
+
+ rc = rfkill_register(bt_rfk);
+
+ if (rc)
+ rfkill_free(bt_rfk);
+ return rc;
+}
+
+static struct platform_driver sapphire_rfkill_driver = {
+ .probe = sapphire_rfkill_probe,
+ .driver = {
+ .name = "sapphire_rfkill",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sapphire_rfkill_init(void)
+{
+ if (!machine_is_sapphire())
+ return 0;
+ return platform_driver_register(&sapphire_rfkill_driver);
+}
+
+module_init(sapphire_rfkill_init);
+MODULE_DESCRIPTION("sapphire rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-sapphire-wifi.c b/arch/arm/mach-msm/board-sapphire-wifi.c
new file mode 100644
index 000000000000..43f827c60f13
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-sapphire-wifi.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@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.
+ *
+ */
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/wifi_tiwlan.h>
+
+extern int sapphire_wifi_set_carddetect(int val);
+extern int sapphire_wifi_power(int on);
+extern int sapphire_wifi_reset(int on);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+typedef struct wifi_mem_prealloc_struct {
+ void *mem_ptr;
+ unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = {
+ { NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) },
+ { NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) },
+ { NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) }
+};
+
+static void *sapphire_wifi_mem_prealloc(int section, unsigned long size)
+{
+ if ((section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS))
+ return NULL;
+ if (wifi_mem_array[section].size < size)
+ return NULL;
+ return wifi_mem_array[section].mem_ptr;
+}
+
+int __init sapphire_init_wifi_mem (void)
+{
+ int i;
+
+ for (i = 0; (i < WMPA_NUMBER_OF_SECTIONS); i++) {
+ wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size);
+ if (wifi_mem_array[i].mem_ptr == NULL)
+ return -ENOMEM;
+ }
+ return 0;
+}
+#endif
+
+struct wifi_platform_data sapphire_wifi_control = {
+ .set_power = sapphire_wifi_power,
+ .set_reset = sapphire_wifi_reset,
+ .set_carddetect = sapphire_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+ .mem_prealloc = sapphire_wifi_mem_prealloc,
+#else
+ .mem_prealloc = NULL,
+#endif
+};
+
+#endif
diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
new file mode 100644
index 000000000000..8de7a45ea649
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire.c
@@ -0,0 +1,1175 @@
+/* linux/arch/arm/mach-msm/board-sapphire.c
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/keyreset.h>
+#include <linux/leds.h>
+#include <linux/switch.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/elan_i2c.h>
+#include <linux/akm8976.h>
+#include <mach/htc_headset.h>
+#include <linux/sysdev.h>
+#include <linux/android_pmem.h>
+
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+#include <asm/system.h>
+#include <mach/system.h>
+#include <mach/vreg.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/setup.h>
+
+#include <linux/gpio_event.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/mmc.h>
+#include <linux/mmc/sdio_ids.h>
+
+
+#include "gpio_chip.h"
+#include "board-sapphire.h"
+#include "pm.h"
+
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/htc_pwrsink.h>
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+extern int sapphire_init_wifi_mem(void);
+#endif
+extern struct wifi_platform_data sapphire_wifi_control;
+#endif
+
+#include "proc_comm.h"
+#include "devices.h"
+
+void msm_init_irq(void);
+void msm_init_gpio(void);
+void msm_init_pmic_vibrator(void);
+
+extern int sapphire_init_mmc(unsigned int);
+
+struct sapphire_axis_info {
+ struct gpio_event_axis_info info;
+ uint16_t in_state;
+ uint16_t out_state;
+ uint16_t temp_state;
+ uint16_t threshold;
+};
+static bool nav_just_on;
+static int nav_on_jiffies;
+static int smi_sz = 64;
+static unsigned int hwid = 0;
+static unsigned int skuid = 0;
+static unsigned engineerid = (0x01 << 1); /* default is 3M sensor */
+
+uint16_t sapphire_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+ struct sapphire_axis_info *ai = container_of(info, struct sapphire_axis_info, info);
+ uint16_t out = ai->out_state;
+
+ if (nav_just_on) {
+ if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1)
+ goto ignore;
+ nav_just_on = 0;
+ }
+ if ((ai->in_state ^ in) & 1)
+ out--;
+ if ((ai->in_state ^ in) & 2)
+ out++;
+ ai->out_state = out;
+ignore:
+ ai->in_state = in;
+ if (ai->out_state - ai->temp_state == ai->threshold) {
+ ai->temp_state++;
+ ai->out_state = ai->temp_state;
+ } else if (ai->temp_state - ai->out_state == ai->threshold) {
+ ai->temp_state--;
+ ai->out_state = ai->temp_state;
+ } else if (abs(ai->out_state - ai->temp_state) > ai->threshold)
+ ai->temp_state = ai->out_state;
+
+ return ai->temp_state;
+}
+
+int sapphire_nav_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+ gpio_set_value(SAPPHIRE_GPIO_JOG_EN, on);
+ if (on) {
+ nav_just_on = 1;
+ nav_on_jiffies = jiffies;
+ }
+ return 0;
+}
+
+static uint32_t sapphire_x_axis_gpios[] = {
+ SAPPHIRE_BALL_LEFT_0, SAPPHIRE_BALL_RIGHT_0
+};
+
+static struct sapphire_axis_info sapphire_x_axis = {
+ .threshold = 2,
+ .info = {
+ .info.func = gpio_event_axis_func,
+ .count = ARRAY_SIZE(sapphire_x_axis_gpios),
+ .type = EV_REL,
+ .code = REL_X,
+ .decoded_size = 1U << ARRAY_SIZE(sapphire_x_axis_gpios),
+ .map = sapphire_axis_map,
+ .gpio = sapphire_x_axis_gpios,
+ .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+ }
+};
+
+static uint32_t sapphire_y_axis_gpios[] = {
+ SAPPHIRE_BALL_UP_0, SAPPHIRE_BALL_DOWN_0
+};
+
+static struct sapphire_axis_info sapphire_y_axis = {
+ .threshold = 2,
+ .info = {
+ .info.func = gpio_event_axis_func,
+ .count = ARRAY_SIZE(sapphire_y_axis_gpios),
+ .type = EV_REL,
+ .code = REL_Y,
+ .decoded_size = 1U << ARRAY_SIZE(sapphire_y_axis_gpios),
+ .map = sapphire_axis_map,
+ .gpio = sapphire_y_axis_gpios,
+ .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+ }
+};
+
+static struct gpio_event_direct_entry sapphire_nav_buttons[] = {
+ { SAPPHIRE_GPIO_NAVI_ACT_N, BTN_MOUSE },
+ { SAPPHIRE_GPIO_SEARCH_ACT_N, KEY_COMPOSE }, /* CPLD Key Search */
+};
+
+static struct gpio_event_input_info sapphire_nav_button_info = {
+ .info.func = gpio_event_input_func,
+ .flags = GPIOEDF_PRINT_KEYS | GPIOEDF_PRINT_KEY_DEBOUNCE,
+ .poll_time.tv.nsec = 40 * NSEC_PER_MSEC,
+ .type = EV_KEY,
+ .keymap = sapphire_nav_buttons,
+ .keymap_size = ARRAY_SIZE(sapphire_nav_buttons)
+};
+
+static struct gpio_event_info *sapphire_nav_info[] = {
+ &sapphire_x_axis.info.info,
+ &sapphire_y_axis.info.info,
+ &sapphire_nav_button_info.info
+};
+
+static struct gpio_event_platform_data sapphire_nav_data = {
+ .name = "sapphire-nav",
+ .info = sapphire_nav_info,
+ .info_count = ARRAY_SIZE(sapphire_nav_info),
+ .power = sapphire_nav_power,
+};
+
+static struct platform_device sapphire_nav_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 2,
+ .dev = {
+ .platform_data = &sapphire_nav_data,
+ },
+};
+
+static int sapphire_reset_keys_up[] = {
+ BTN_MOUSE,
+ 0
+};
+
+static struct keyreset_platform_data sapphire_reset_keys_pdata = {
+ .keys_up = sapphire_reset_keys_up,
+ .keys_down = {
+ KEY_SEND,
+ KEY_MENU,
+ KEY_END,
+ 0
+ },
+};
+
+struct platform_device sapphire_reset_keys_device = {
+ .name = KEYRESET_NAME,
+ .dev.platform_data = &sapphire_reset_keys_pdata,
+};
+
+static int sapphire_ts_power(int on)
+{
+ int gpio_tp_ls_en = SAPPHIRE_TP_LS_EN;
+
+ if (is_12pin_camera())
+ gpio_tp_ls_en = SAPPHIRE20_TP_LS_EN;
+
+ if (on) {
+ sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 1);
+ /* touchscreen must be powered before we enable i2c pullup */
+ msleep(2);
+ /* enable touch panel level shift */
+ gpio_direction_output(gpio_tp_ls_en, 1);
+ msleep(2);
+ } else {
+ gpio_direction_output(gpio_tp_ls_en, 0);
+ udelay(50);
+ sapphire_gpio_write(NULL, SAPPHIRE_GPIO_TP_EN, 0);
+ }
+
+ return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data sapphire_ts_data[] = {
+{
+ .version = 0x0101,
+ .power = sapphire_ts_power,
+ .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+ .inactive_left = -50 * 0x10000 / 4334,
+ .inactive_right = -50 * 0x10000 / 4334,
+ .inactive_top = -40 * 0x10000 / 6696,
+ .inactive_bottom = -40 * 0x10000 / 6696,
+ .snap_left_on = 50 * 0x10000 / 4334,
+ .snap_left_off = 60 * 0x10000 / 4334,
+ .snap_right_on = 50 * 0x10000 / 4334,
+ .snap_right_off = 60 * 0x10000 / 4334,
+ .snap_top_on = 100 * 0x10000 / 6696,
+ .snap_top_off = 110 * 0x10000 / 6696,
+ .snap_bottom_on = 100 * 0x10000 / 6696,
+ .snap_bottom_off = 110 * 0x10000 / 6696,
+ },
+ {
+ .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+ .inactive_left = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+ .inactive_right = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+ .inactive_top = ((6946 - 6696) / 2) * 0x10000 / 6696,
+ .inactive_bottom = ((6946 - 6696) / 2) * 0x10000 / 6696,
+ }
+};
+
+static struct akm8976_platform_data compass_platform_data = {
+ .reset = SAPPHIRE_GPIO_COMPASS_RST_N,
+ .clk_on = SAPPHIRE_GPIO_COMPASS_32K_EN,
+ .intr = SAPPHIRE_GPIO_COMPASS_IRQ,
+};
+
+static struct elan_i2c_platform_data elan_i2c_data[] = {
+ {
+ .version = 0x104,
+ .abs_x_min = 0,
+ .abs_y_min = 0,
+ .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+ .power = sapphire_ts_power,
+ },
+ {
+ .version = 0x103,
+ .abs_x_min = 0,
+ .abs_x_max = 512 * 2,
+ .abs_y_min = 0,
+ .abs_y_max = 896 * 2,
+ .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+ .power = sapphire_ts_power,
+ },
+ {
+ .version = 0x102,
+ .abs_x_min = 0,
+ .abs_x_max = 384,
+ .abs_y_min = 0,
+ .abs_y_max = 576,
+ .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+ .power = sapphire_ts_power,
+ },
+ {
+ .version = 0x101,
+ .abs_x_min = 32 + 1,
+ .abs_x_max = 352 - 1,
+ .abs_y_min = 32 + 1,
+ .abs_y_max = 544 - 1,
+ .intr_gpio = SAPPHIRE_GPIO_TP_ATT_N,
+ .power = sapphire_ts_power,
+ }
+};
+
+static struct msm_camera_device_platform_data msm_camera_device_mt9t013 = {
+ .sensor_reset = 108,
+ .sensor_pwd = 85,
+ .vcm_pwd = SAPPHIRE_GPIO_VCM_PWDN,
+ .config_gpio_on = config_sapphire_camera_on_gpios,
+ .config_gpio_off = config_sapphire_camera_off_gpios,
+};
+
+static struct platform_device sapphire_camera = {
+ .name = "camera",
+ .dev = {
+ .platform_data = &msm_camera_device_mt9t013,
+ },
+};
+
+static struct i2c_board_info i2c_devices[] = {
+ {
+ I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20),
+ .platform_data = sapphire_ts_data,
+ .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N)
+ },
+ {
+ I2C_BOARD_INFO(ELAN_8232_I2C_NAME, 0x10),
+ .platform_data = &elan_i2c_data,
+ .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_TP_ATT_N),
+ },
+ {
+ I2C_BOARD_INFO("akm8976", 0x1C),
+ .platform_data = &compass_platform_data,
+ .irq = SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_COMPASS_IRQ),
+ },
+ {
+ I2C_BOARD_INFO("mt9t013", 0x6C >> 1),
+ .platform_data = &msm_camera_device_mt9t013,
+ },
+};
+
+#ifdef CONFIG_LEDS_CPLD
+static struct resource cpldled_resources[] = {
+ {
+ .start = SAPPHIRE_CPLD_LED_BASE,
+ .end = SAPPHIRE_CPLD_LED_BASE + SAPPHIRE_CPLD_LED_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device android_CPLD_leds = {
+ .name = "leds-cpld",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cpldled_resources),
+ .resource = cpldled_resources,
+};
+#endif
+
+static struct gpio_led android_led_list[] = {
+ {
+ .name = "button-backlight",
+ .gpio = SAPPHIRE_GPIO_APKEY_LED_EN,
+ },
+};
+
+static struct gpio_led_platform_data android_leds_data = {
+ .num_leds = ARRAY_SIZE(android_led_list),
+ .leds = android_led_list,
+};
+
+static struct platform_device android_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_leds_data,
+ },
+};
+
+#ifdef CONFIG_HTC_HEADSET
+/* RTS/CTS to GPO/GPI. */
+static uint32_t uart1_on_gpio_table[] = {
+ /* allenou, uart hs test, 2008/11/18 */
+ #ifdef CONFIG_SERIAL_MSM_HS
+ /* RTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 2,
+ GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA),
+ /* CTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 2,
+ GPIO_INPUT, GPIO_PULL_UP, GPIO_8MA),
+ #else
+ /* RTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 1,
+ GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA),
+ /* CTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 1,
+ GPIO_INPUT, GPIO_PULL_DOWN, GPIO_4MA),
+ #endif
+};
+
+/* RTS,CTS to BT. */
+static uint32_t uart1_off_gpio_table[] = {
+ /* RTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_RTS, 0,
+ GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+ /* CTS */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART1_CTS, 0,
+ GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+};
+
+/* Sapphire: Switch between UART3 and GPIO */
+static uint32_t uart3_on_gpio_table[] = {
+ /* RX */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_RX, 1,
+ GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+ /* TX */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_UART3_TX, 1,
+ GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA),
+};
+
+/* set TX,RX to GPI */
+static uint32_t uart3_off_gpi_table[] = {
+ /* RX, H2W DATA */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_DATA, 0,
+ GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA),
+ /* TX, H2W CLK */
+ PCOM_GPIO_CFG(SAPPHIRE_GPIO_H2W_CLK, 0,
+ GPIO_INPUT, GPIO_KEEPER, GPIO_2MA),
+};
+
+static int sapphire_h2w_path = H2W_GPIO;
+
+static void h2w_config_cpld(int route)
+{
+ switch (route) {
+ case H2W_UART1:
+ /* Make sure uart1 funtion pin opened. */
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+1, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+ sapphire_h2w_path = H2W_UART1;
+ printk(KERN_INFO "H2W route = H2W-UART1, BT-X, UART3-X \n");
+ break;
+ case H2W_BT:
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 1);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+ /* UART1 RTS/CTS to GPO/GPI. */
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_off_gpio_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_off_gpio_table+1, 0);
+ sapphire_h2w_path = H2W_BT;
+ printk(KERN_INFO "H2W route = H2W-BT, UART1-X, UART3-X \n");
+ break;
+ case H2W_UART3:
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart3_on_gpio_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart3_on_gpio_table+1, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+ /* Make sure uart1 funtion pin opened. */
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+1, 0);
+ sapphire_h2w_path = H2W_UART3;
+ printk(KERN_INFO "H2W route = H2W-UART3, BT-UART1 \n");
+ break;
+ case H2W_GPIO: /*H2W_UART3 TX,RX are changed to H2W_GPIO */
+ default:
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 0);
+ /* Set the CPLD connected H2W GPIO's to input */
+ gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, 0);
+ /* TX,RX GPI first. */
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart3_off_gpi_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart3_off_gpi_table+1, 0);
+ /* Make sure uart1 funtion pin opened. */
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+0, 0);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+ uart1_on_gpio_table+1, 0);
+ sapphire_h2w_path = H2W_GPIO;
+ printk(KERN_INFO "H2W route = H2W-GPIO, BT-UART1 \n");
+ break;
+ }
+}
+
+static void h2w_init_cpld(void)
+{
+ h2w_config_cpld(H2W_GPIO);
+}
+
+static void set_h2w_dat(int n)
+{
+ gpio_set_value(SAPPHIRE_GPIO_H2W_DATA, n);
+}
+
+static void set_h2w_clk(int n)
+{
+ gpio_set_value(SAPPHIRE_GPIO_H2W_CLK, n);
+}
+
+static void set_h2w_dat_dir(int n)
+{
+ if (n == 0) /* input */
+ gpio_direction_input(SAPPHIRE_GPIO_H2W_DATA);
+ else
+ gpio_configure(SAPPHIRE_GPIO_H2W_DATA, GPIOF_DRIVE_OUTPUT);
+
+ gpio_set_value(SAPPHIRE_GPIO_H2W_DAT_DIR, n);
+
+}
+
+static void set_h2w_clk_dir(int n)
+{
+ if (n == 0) /* input */
+ gpio_direction_input(SAPPHIRE_GPIO_H2W_CLK);
+ else
+ gpio_configure(SAPPHIRE_GPIO_H2W_CLK, GPIOF_DRIVE_OUTPUT);
+
+ gpio_set_value(SAPPHIRE_GPIO_H2W_CLK_DIR, n);
+}
+
+static int get_h2w_dat(void)
+{
+ return gpio_get_value(SAPPHIRE_GPIO_H2W_DATA);
+}
+
+static int get_h2w_clk(void)
+{
+ return gpio_get_value(SAPPHIRE_GPIO_H2W_CLK);
+}
+
+static int set_h2w_path(const char *val, struct kernel_param *kp)
+{
+ int ret = -EINVAL;
+
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ switch (sapphire_h2w_path) {
+ case H2W_GPIO:
+ case H2W_UART1:
+ case H2W_UART3:
+ case H2W_BT:
+ break;
+ default:
+ sapphire_h2w_path = -1;
+ return -EINVAL;
+ }
+
+ h2w_config_cpld(sapphire_h2w_path);
+ return ret;
+}
+module_param_call(h2w_path, set_h2w_path, param_get_int,
+ &sapphire_h2w_path, S_IWUSR | S_IRUGO);
+
+
+static struct h2w_platform_data sapphire_h2w_data = {
+ .power_name = "wlan",
+ .cable_in1 = SAPPHIRE_GPIO_CABLE_IN1,
+ .cable_in2 = SAPPHIRE_GPIO_CABLE_IN2,
+ .h2w_clk = SAPPHIRE_GPIO_H2W_CLK,
+ .h2w_data = SAPPHIRE_GPIO_H2W_DATA,
+ .debug_uart = H2W_UART3,
+ .config_cpld = h2w_config_cpld,
+ .init_cpld = h2w_init_cpld,
+ .set_dat = set_h2w_dat,
+ .set_clk = set_h2w_clk,
+ .set_dat_dir = set_h2w_dat_dir,
+ .set_clk_dir = set_h2w_clk_dir,
+ .get_dat = get_h2w_dat,
+ .get_clk = get_h2w_clk,
+};
+
+static struct platform_device sapphire_h2w = {
+ .name = "h2w",
+ .id = -1,
+ .dev = {
+ .platform_data = &sapphire_h2w_data,
+ },
+};
+#endif
+
+static void sapphire_phy_reset(void)
+{
+ gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 0);
+ mdelay(10);
+ gpio_set_value(SAPPHIRE_GPIO_USB_PHY_RST_N, 1);
+ mdelay(10);
+}
+
+static struct pwr_sink sapphire_pwrsink_table[] = {
+ {
+ .id = PWRSINK_AUDIO,
+ .ua_max = 100000,
+ },
+ {
+ .id = PWRSINK_BACKLIGHT,
+ .ua_max = 125000,
+ },
+ {
+ .id = PWRSINK_LED_BUTTON,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_LED_KEYBOARD,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_GP_CLK,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_BLUETOOTH,
+ .ua_max = 15000,
+ },
+ {
+ .id = PWRSINK_CAMERA,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_SDCARD,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_VIDEO,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_WIFI,
+ .ua_max = 200000,
+ },
+ {
+ .id = PWRSINK_SYSTEM_LOAD,
+ .ua_max = 100000,
+ .percent_util = 38,
+ },
+};
+
+static struct pwr_sink_platform_data sapphire_pwrsink_data = {
+ .num_sinks = ARRAY_SIZE(sapphire_pwrsink_table),
+ .sinks = sapphire_pwrsink_table,
+ .suspend_late = NULL,
+ .resume_early = NULL,
+ .suspend_early = NULL,
+ .resume_late = NULL,
+};
+
+static struct platform_device sapphire_pwr_sink = {
+ .name = "htc_pwrsink",
+ .id = -1,
+ .dev = {
+ .platform_data = &sapphire_pwrsink_data,
+ },
+};
+
+static struct platform_device sapphire_rfkill = {
+ .name = "sapphire_rfkill",
+ .id = -1,
+};
+
+static struct msm_pmem_setting pmem_setting_32 = {
+ .pmem_start = SMI32_MSM_PMEM_MDP_BASE,
+ .pmem_size = SMI32_MSM_PMEM_MDP_SIZE,
+ .pmem_adsp_start = SMI32_MSM_PMEM_ADSP_BASE,
+ .pmem_adsp_size = SMI32_MSM_PMEM_ADSP_SIZE,
+ .pmem_gpu0_start = MSM_PMEM_GPU0_BASE,
+ .pmem_gpu0_size = MSM_PMEM_GPU0_SIZE,
+ .pmem_gpu1_start = MSM_PMEM_GPU1_BASE,
+ .pmem_gpu1_size = MSM_PMEM_GPU1_SIZE,
+ .pmem_camera_start = 0,
+ .pmem_camera_size = 0,
+ .ram_console_start = MSM_RAM_CONSOLE_BASE,
+ .ram_console_size = MSM_RAM_CONSOLE_SIZE,
+};
+
+static struct msm_pmem_setting pmem_setting_64 = {
+ .pmem_start = SMI64_MSM_PMEM_MDP_BASE,
+ .pmem_size = SMI64_MSM_PMEM_MDP_SIZE,
+ .pmem_adsp_start = SMI64_MSM_PMEM_ADSP_BASE,
+ .pmem_adsp_size = SMI64_MSM_PMEM_ADSP_SIZE,
+ .pmem_gpu0_start = MSM_PMEM_GPU0_BASE,
+ .pmem_gpu0_size = MSM_PMEM_GPU0_SIZE,
+ .pmem_gpu1_start = MSM_PMEM_GPU1_BASE,
+ .pmem_gpu1_size = MSM_PMEM_GPU1_SIZE,
+ .pmem_camera_start = SMI64_MSM_PMEM_CAMERA_BASE,
+ .pmem_camera_size = SMI64_MSM_PMEM_CAMERA_SIZE,
+ .ram_console_start = MSM_RAM_CONSOLE_BASE,
+ .ram_console_size = MSM_RAM_CONSOLE_SIZE,
+};
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+static struct platform_device sapphire_wifi = {
+ .name = "msm_wifi",
+ .id = 1,
+ .num_resources = 0,
+ .resource = NULL,
+ .dev = {
+ .platform_data = &sapphire_wifi_control,
+ },
+};
+#endif
+
+#define SND(num, desc) { .name = desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+ SND(0, "HANDSET"),
+ SND(1, "SPEAKER"),
+ SND(2, "HEADSET"),
+ SND(3, "BT"),
+ SND(44, "BT_EC_OFF"),
+ SND(10, "HEADSET_AND_SPEAKER"),
+ SND(256, "CURRENT"),
+
+ /* Bluetooth accessories. */
+
+ SND(12, "HTC BH S100"),
+ SND(13, "HTC BH M100"),
+ SND(14, "Motorola H500"),
+ SND(15, "Nokia HS-36W"),
+ SND(16, "PLT 510v.D"),
+ SND(17, "M2500 by Plantronics"),
+ SND(18, "Nokia HDW-3"),
+ SND(19, "HBH-608"),
+ SND(20, "HBH-DS970"),
+ SND(21, "i.Tech BlueBAND"),
+ SND(22, "Nokia BH-800"),
+ SND(23, "Motorola H700"),
+ SND(24, "HTC BH M200"),
+ SND(25, "Jabra JX10"),
+ SND(26, "320Plantronics"),
+ SND(27, "640Plantronics"),
+ SND(28, "Jabra BT500"),
+ SND(29, "Motorola HT820"),
+ SND(30, "HBH-IV840"),
+ SND(31, "6XXPlantronics"),
+ SND(32, "3XXPlantronics"),
+ SND(33, "HBH-PV710"),
+ SND(34, "Motorola H670"),
+ SND(35, "HBM-300"),
+ SND(36, "Nokia BH-208"),
+ SND(37, "Samsung WEP410"),
+ SND(38, "Jabra BT8010"),
+ SND(39, "Motorola S9"),
+ SND(40, "Jabra BT620s"),
+ SND(41, "Nokia BH-902"),
+ SND(42, "HBH-DS220"),
+ SND(43, "HBH-DS980"),
+};
+#undef SND
+
+static struct msm_snd_endpoints sapphire_snd_endpoints = {
+ .endpoints = snd_endpoints_list,
+ .num = ARRAY_SIZE(snd_endpoints_list),
+};
+
+static struct platform_device sapphire_snd = {
+ .name = "msm_snd",
+ .id = -1,
+ .dev = {
+ .platform_data = &sapphire_snd_endpoints,
+ },
+};
+
+static struct platform_device *devices[] __initdata = {
+ &msm_device_smd,
+ &msm_device_dmov,
+ &msm_device_nand,
+ &msm_device_i2c,
+ &msm_device_uart1,
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W)
+ &msm_device_uart3,
+#endif
+#ifdef CONFIG_SERIAL_MSM_HS
+ &msm_device_uart_dm1,
+#endif
+ &sapphire_nav_device,
+ &sapphire_reset_keys_device,
+ &android_leds,
+#ifdef CONFIG_LEDS_CPLD
+ &android_CPLD_leds,
+#endif
+#ifdef CONFIG_HTC_HEADSET
+ &sapphire_h2w,
+#endif
+ &sapphire_rfkill,
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+ &sapphire_wifi,
+#endif
+
+#ifdef CONFIG_HTC_PWRSINK
+ &sapphire_pwr_sink,
+#endif
+ &sapphire_snd,
+ &sapphire_camera,
+};
+
+extern struct sys_timer msm_timer;
+
+static void __init sapphire_init_irq(void)
+{
+ printk(KERN_DEBUG "sapphire_init_irq()\n");
+ msm_init_irq();
+}
+
+static uint cpld_iset;
+static uint cpld_charger_en;
+static uint cpld_usb_h2w_sw;
+static uint opt_disable_uart3;
+
+module_param_named(iset, cpld_iset, uint, 0);
+module_param_named(charger_en, cpld_charger_en, uint, 0);
+module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0);
+module_param_named(disable_uart3, opt_disable_uart3, uint, 0);
+
+static void sapphire_reset(void)
+{
+ gpio_set_value(SAPPHIRE_GPIO_PS_HOLD, 0);
+}
+
+static uint32_t gpio_table[] = {
+ /* BLUETOOTH */
+#ifdef CONFIG_SERIAL_MSM_HS
+ PCOM_GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+ PCOM_GPIO_CFG(44, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+ PCOM_GPIO_CFG(45, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+ PCOM_GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#else
+ PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+ PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+ PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+ PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#endif
+};
+
+
+static uint32_t camera_off_gpio_table[] = {
+ /* CAMERA */
+ PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */
+ PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */
+ PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */
+ PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */
+ PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */
+ PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */
+ PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */
+ PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */
+ PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */
+ PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */
+ PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */
+ PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_table[] = {
+ /* CAMERA */
+ PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+ PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static uint32_t camera_off_gpio_12pins_table[] = {
+ /* CAMERA */
+ PCOM_GPIO_CFG(0, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+ PCOM_GPIO_CFG(1, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(2, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(3, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(4, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT4 */
+ PCOM_GPIO_CFG(5, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT5 */
+ PCOM_GPIO_CFG(6, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT6 */
+ PCOM_GPIO_CFG(7, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT7 */
+ PCOM_GPIO_CFG(8, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT8 */
+ PCOM_GPIO_CFG(9, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT9 */
+ PCOM_GPIO_CFG(10, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT10 */
+ PCOM_GPIO_CFG(11, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT11 */
+ PCOM_GPIO_CFG(12, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* PCLK */
+ PCOM_GPIO_CFG(13, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* HSYNC_IN */
+ PCOM_GPIO_CFG(14, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* VSYNC_IN */
+ PCOM_GPIO_CFG(15, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* MCLK */
+};
+
+static uint32_t camera_on_gpio_12pins_table[] = {
+ /* CAMERA */
+ PCOM_GPIO_CFG(0, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT0 */
+ PCOM_GPIO_CFG(1, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT1 */
+ PCOM_GPIO_CFG(2, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT2 */
+ PCOM_GPIO_CFG(3, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT3 */
+ PCOM_GPIO_CFG(4, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT4 */
+ PCOM_GPIO_CFG(5, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT5 */
+ PCOM_GPIO_CFG(6, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT6 */
+ PCOM_GPIO_CFG(7, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT7 */
+ PCOM_GPIO_CFG(8, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT8 */
+ PCOM_GPIO_CFG(9, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT9 */
+ PCOM_GPIO_CFG(10, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT10 */
+ PCOM_GPIO_CFG(11, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* DAT11 */
+ PCOM_GPIO_CFG(12, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_16MA), /* PCLK */
+ PCOM_GPIO_CFG(13, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* HSYNC_IN */
+ PCOM_GPIO_CFG(14, 1, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA), /* VSYNC_IN */
+ PCOM_GPIO_CFG(15, 1, GPIO_OUTPUT, GPIO_PULL_DOWN, GPIO_16MA), /* MCLK */
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n;
+ unsigned id;
+ for (n = 0; n < len; n++) {
+ id = table[n];
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+ }
+}
+
+void config_sapphire_camera_on_gpios(void)
+{
+ /*Add for judage it's 10 pins or 12 pins platform ----->*/
+ if (is_12pin_camera()) {
+ config_gpio_table(camera_on_gpio_12pins_table,
+ ARRAY_SIZE(camera_on_gpio_12pins_table));
+ } else {
+ config_gpio_table(camera_on_gpio_table,
+ ARRAY_SIZE(camera_on_gpio_table));
+ }
+ /*End Of Add for judage it's 10 pins or 12 pins platform*/
+}
+
+void config_sapphire_camera_off_gpios(void)
+{
+ /*Add for judage it's 10 pins or 12 pins platform ----->*/
+ if (is_12pin_camera()) {
+ config_gpio_table(camera_off_gpio_12pins_table,
+ ARRAY_SIZE(camera_off_gpio_12pins_table));
+ } else {
+ config_gpio_table(camera_off_gpio_table,
+ ARRAY_SIZE(camera_off_gpio_table));
+ }
+ /*End Of Add for judage it's 10 pins or 12 pins platform*/
+}
+
+static void __init config_gpios(void)
+{
+ config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table));
+ config_sapphire_camera_off_gpios();
+}
+
+void msm_serial_debug_init(unsigned int base, int irq,
+ struct device *clk_device, int signal_irq);
+
+static struct msm_acpu_clock_platform_data sapphire_clock_data = {
+ .acpu_switch_time_us = 20,
+ .max_speed_delta_khz = 256000,
+ .vdd_switch_time_us = 62,
+ .power_collapse_khz = 19200000,
+ .wait_for_irq_khz = 128000000,
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+ .wakeup_irq = MSM_GPIO_TO_INT(45),
+ .inject_rx_on_wakeup = 1,
+ .rx_to_inject = 0x32,
+};
+#endif
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000,
+};
+
+static void __init sapphire_init(void)
+{
+ int rc;
+ int i;
+ printk("sapphire_init() revision=%d\n", system_rev);
+
+ /*
+ * Setup common MSM GPIOS
+ */
+ config_gpios();
+
+ msm_hw_reset_hook = sapphire_reset;
+
+ msm_acpu_clock_init(&sapphire_clock_data);
+
+ /* adjust GPIOs based on bootloader request */
+ printk("sapphire_init: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw);
+ gpio_set_value(SAPPHIRE_GPIO_USB_H2W_SW, cpld_usb_h2w_sw);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ if (!opt_disable_uart3)
+ msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+ &msm_device_uart3.dev, 1);
+#endif
+
+ /* gpio_configure(108, IRQF_TRIGGER_LOW); */
+
+ /* H2W pins <-> UART3, Bluetooth <-> UART1 */
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL0, 0);
+ gpio_set_value(SAPPHIRE_GPIO_H2W_SEL1, 1);
+ /* put the AF VCM in powerdown mode to avoid noise */
+ if (sapphire_is_5M_camera())
+ sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 0);
+ else
+ sapphire_gpio_write(NULL, SAPPHIRE_GPIO_VCM_PWDN, 1);
+ mdelay(100);
+
+#ifdef CONFIG_SERIAL_MSM_HS
+ msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#endif
+ msm_add_usb_devices(sapphire_phy_reset);
+
+ if (32 == smi_sz)
+ msm_add_mem_devices(&pmem_setting_32);
+ else
+ msm_add_mem_devices(&pmem_setting_64);
+
+ rc = sapphire_init_mmc(system_rev);
+ if (rc)
+ printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+ rc = sapphire_init_wifi_mem();
+ if (rc) {
+ printk(KERN_CRIT "%s: WiFi memory init failure (%d)\n",
+ __func__, rc);
+ }
+#endif
+ msm_init_pmic_vibrator();
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+ msm_pm_set_platform_data(msm_pm_data);
+}
+
+static struct map_desc sapphire_io_desc[] __initdata = {
+ {
+ .virtual = SAPPHIRE_CPLD_BASE,
+ .pfn = __phys_to_pfn(SAPPHIRE_CPLD_START),
+ .length = SAPPHIRE_CPLD_SIZE,
+ .type = MT_DEVICE_NONSHARED
+ }
+};
+
+
+unsigned int sapphire_get_hwid(void)
+{
+ printk(KERN_DEBUG "sapphire_get_hwid=0x%x\r\n", hwid);
+
+ return hwid;
+}
+
+unsigned int sapphire_get_skuid(void)
+{
+ printk(KERN_DEBUG "sapphire_get_skuid=0x%x\r\n", skuid);
+
+ return skuid;
+}
+
+unsigned sapphire_engineerid(void)
+{
+ printk(KERN_DEBUG "sapphire_engineerid=0x%x\r\n", engineerid);
+
+ return engineerid;
+}
+
+int sapphire_is_5M_camera(void)
+{
+ int ret = 0;
+ if (sapphire_get_skuid() == 0x1FF00 && !(sapphire_engineerid() & 0x02))
+ ret = 1;
+ else if (sapphire_get_skuid() == 0x20100 && !(sapphire_engineerid() & 0x02))
+ ret = 1;
+ printk(KERN_DEBUG "sapphire_is_5M_camera=%d\n", ret);
+ return ret;
+}
+
+/* it can support 3M and 5M sensor */
+unsigned int is_12pin_camera(void)
+{
+ unsigned int ret = 0;
+
+ if (sapphire_get_skuid() == 0x1FF00 || sapphire_get_skuid() == 0x20100)
+ ret = 1;
+ else
+ ret = 0;
+ printk(KERN_DEBUG "is_12pin_camera=%d\r\n", ret);
+ return ret;
+}
+
+int sapphire_get_smi_size(void)
+{
+ printk(KERN_DEBUG "get_smi_size=%d\r\n", smi_sz);
+ return smi_sz;
+}
+
+static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags,
+ char **cmdline, struct meminfo *mi)
+{
+ smi_sz = parse_tag_smi((const struct tag *)tags);
+ printk("sapphire_fixup:smisize=%d\n", smi_sz);
+ hwid = parse_tag_hwid((const struct tag *)tags);
+ printk("sapphire_fixup:hwid=0x%x\n", hwid);
+ skuid = parse_tag_skuid((const struct tag *)tags);
+ printk("sapphire_fixup:skuid=0x%x\n", skuid);
+ engineerid = parse_tag_engineerid((const struct tag *)tags);
+ printk("sapphire_fixup:engineerid=0x%x\n", engineerid);
+
+ mi->nr_banks = 1;
+ mi->bank[0].start = PHYS_OFFSET;
+ mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+ if (smi_sz == 32) {
+ mi->bank[0].size = (84*1024*1024);
+ } else if (smi_sz == 64) {
+ mi->bank[0].size = (101*1024*1024);
+ } else {
+ printk(KERN_ERR "can not get smi size\n");
+
+ /*Give a default value when not get smi size*/
+ smi_sz = 64;
+ mi->bank[0].size = (101*1024*1024);
+ printk(KERN_ERR "use default : smisize=%d\n", smi_sz);
+ }
+}
+
+static void __init sapphire_map_io(void)
+{
+ msm_map_common_io();
+ iotable_init(sapphire_io_desc, ARRAY_SIZE(sapphire_io_desc));
+ msm_clock_init();
+}
+
+MACHINE_START(SAPPHIRE, "sapphire")
+/* Maintainer: Brian Swetland <swetland@google.com> */
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x10000100,
+ .fixup = sapphire_fixup,
+ .map_io = sapphire_map_io,
+ .init_irq = sapphire_init_irq,
+ .init_machine = sapphire_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-sapphire.h b/arch/arm/mach-msm/board-sapphire.h
new file mode 100644
index 000000000000..3327dfeafde0
--- /dev/null
+++ b/arch/arm/mach-msm/board-sapphire.h
@@ -0,0 +1,219 @@
+/* linux/arch/arm/mach-msm/board-sapphire.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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 __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+#define __ARCH_ARM_MACH_MSM_BOARD_SAPPHIRE_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE 0x00000000
+#define MSM_SMI_SIZE 0x00800000
+
+#define MSM_EBI_BASE 0x10000000
+#define MSM_EBI_SIZE 0x06e00000
+
+#define MSM_PMEM_GPU0_BASE 0x00000000
+#define MSM_PMEM_GPU0_SIZE 0x00700000
+
+#define SMI64_MSM_PMEM_MDP_BASE 0x02000000
+#define SMI64_MSM_PMEM_MDP_SIZE 0x00800000
+
+#define SMI64_MSM_PMEM_ADSP_BASE 0x02800000
+#define SMI64_MSM_PMEM_ADSP_SIZE 0x00800000
+
+#define SMI64_MSM_PMEM_CAMERA_BASE 0x03000000
+#define SMI64_MSM_PMEM_CAMERA_SIZE 0x01000000
+
+#define SMI64_MSM_FB_BASE 0x00700000
+#define SMI64_MSM_FB_SIZE 0x00100000
+
+#define SMI64_MSM_LINUX_BASE MSM_EBI_BASE
+#define SMI64_MSM_LINUX_SIZE 0x06500000
+
+
+#define SMI32_MSM_LINUX_BASE MSM_EBI_BASE
+#define SMI32_MSM_LINUX_SIZE 0x5400000
+
+#define SMI32_MSM_PMEM_MDP_BASE SMI32_MSM_LINUX_BASE + SMI32_MSM_LINUX_SIZE
+#define SMI32_MSM_PMEM_MDP_SIZE 0x800000
+
+#define SMI32_MSM_PMEM_ADSP_BASE SMI32_MSM_PMEM_MDP_BASE + SMI32_MSM_PMEM_MDP_SIZE
+#define SMI32_MSM_PMEM_ADSP_SIZE 0x800000
+
+#define SMI32_MSM_FB_BASE SMI32_MSM_PMEM_ADSP_BASE + SMI32_MSM_PMEM_ADSP_SIZE
+#define SMI32_MSM_FB_SIZE 0x9b000
+
+
+#define MSM_PMEM_GPU1_SIZE 0x800000
+#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
+
+#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000
+#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K
+
+#if (SMI32_MSM_FB_BASE + SMI32_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#if (SMI64_MSM_FB_BASE + SMI64_MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+/*
+** SOC GPIO
+*/
+#define SAPPHIRE_BALL_UP_0 94
+#define SAPPHIRE_BALL_LEFT_0 18
+#define SAPPHIRE_BALL_DOWN_0 49
+#define SAPPHIRE_BALL_RIGHT_0 19
+
+#define SAPPHIRE_POWER_KEY 20
+#define SAPPHIRE_VOLUME_UP 36
+#define SAPPHIRE_VOLUME_DOWN 39
+
+#define SAPPHIRE_GPIO_PS_HOLD (25)
+#define SAPPHIRE_MDDI_1V5_EN (28)
+#define SAPPHIRE_BL_PWM (27)
+#define SAPPHIRE_TP_LS_EN (1)
+#define SAPPHIRE20_TP_LS_EN (88)
+
+/* H2W */
+#define SAPPHIRE_GPIO_CABLE_IN1 (83)
+#define SAPPHIRE_GPIO_CABLE_IN2 (37)
+#define SAPPHIRE_GPIO_UART3_RX (86)
+#define SAPPHIRE_GPIO_UART3_TX (87)
+#define SAPPHIRE_GPIO_H2W_DATA (86)
+#define SAPPHIRE_GPIO_H2W_CLK (87)
+
+#define SAPPHIRE_GPIO_UART1_RTS (43)
+#define SAPPHIRE_GPIO_UART1_CTS (44)
+
+/*
+** CPLD GPIO
+**
+** Sapphire Altera CPLD can keep the registers value and
+** doesn't need a shadow to backup.
+**/
+#define SAPPHIRE_CPLD_BASE 0xE8100000 /* VA */
+#define SAPPHIRE_CPLD_START 0x98000000 /* PA */
+#define SAPPHIRE_CPLD_SIZE SZ_4K
+
+#define SAPPHIRE_GPIO_START (128) /* Pseudo GPIO number */
+
+/* Sapphire has one INT BANK only. */
+#define SAPPHIRE_GPIO_INT_B0_MASK_REG (0x0c) /*INT3 MASK*/
+#define SAPPHIRE_GPIO_INT_B0_STAT_REG (0x0e) /*INT1 STATUS*/
+
+/* LED control register */
+#define SAPPHIRE_CPLD_LED_BASE (SAPPHIRE_CPLD_BASE + 0x10) /* VA */
+#define SAPPHIRE_CPLD_LED_START (SAPPHIRE_CPLD_START + 0x10) /* PA */
+#define SAPPHIRE_CPLD_LED_SIZE 0x08
+
+/* MISCn: GPO pin to Enable/Disable some functions. */
+#define SAPPHIRE_GPIO_MISC1_BASE (SAPPHIRE_GPIO_START + 0x00)
+#define SAPPHIRE_GPIO_MISC2_BASE (SAPPHIRE_GPIO_START + 0x08)
+#define SAPPHIRE_GPIO_MISC3_BASE (SAPPHIRE_GPIO_START + 0x10)
+#define SAPPHIRE_GPIO_MISC4_BASE (SAPPHIRE_GPIO_START + 0x18)
+#define SAPPHIRE_GPIO_MISC5_BASE (SAPPHIRE_GPIO_START + 0x20)
+
+/* INT BANK0: INT1: int status, INT2: int level, INT3: int Mask */
+#define SAPPHIRE_GPIO_INT_B0_BASE (SAPPHIRE_GPIO_START + 0x28)
+
+/* MISCn GPIO: */
+#define SAPPHIRE_GPIO_CPLD128_VER_0 (SAPPHIRE_GPIO_MISC1_BASE + 4)
+#define SAPPHIRE_GPIO_CPLD128_VER_1 (SAPPHIRE_GPIO_MISC1_BASE + 5)
+#define SAPPHIRE_GPIO_CPLD128_VER_2 (SAPPHIRE_GPIO_MISC1_BASE + 6)
+#define SAPPHIRE_GPIO_CPLD128_VER_3 (SAPPHIRE_GPIO_MISC1_BASE + 7)
+
+#define SAPPHIRE_GPIO_H2W_DAT_DIR (SAPPHIRE_GPIO_MISC2_BASE + 2)
+#define SAPPHIRE_GPIO_H2W_CLK_DIR (SAPPHIRE_GPIO_MISC2_BASE + 3)
+#define SAPPHIRE_GPIO_H2W_SEL0 (SAPPHIRE_GPIO_MISC2_BASE + 6)
+#define SAPPHIRE_GPIO_H2W_SEL1 (SAPPHIRE_GPIO_MISC2_BASE + 7)
+
+#define SAPPHIRE_GPIO_I2C_PULL (SAPPHIRE_GPIO_MISC3_BASE + 2)
+#define SAPPHIRE_GPIO_TP_EN (SAPPHIRE_GPIO_MISC3_BASE + 4)
+#define SAPPHIRE_GPIO_JOG_EN (SAPPHIRE_GPIO_MISC3_BASE + 5)
+#define SAPPHIRE_GPIO_JOG_LED_EN (SAPPHIRE_GPIO_MISC3_BASE + 6)
+#define SAPPHIRE_GPIO_APKEY_LED_EN (SAPPHIRE_GPIO_MISC3_BASE + 7)
+
+#define SAPPHIRE_GPIO_VCM_PWDN (SAPPHIRE_GPIO_MISC4_BASE + 0)
+#define SAPPHIRE_GPIO_USB_H2W_SW (SAPPHIRE_GPIO_MISC4_BASE + 1)
+#define SAPPHIRE_GPIO_COMPASS_RST_N (SAPPHIRE_GPIO_MISC4_BASE + 2)
+#define SAPPHIRE_GPIO_USB_PHY_RST_N (SAPPHIRE_GPIO_MISC4_BASE + 5)
+#define SAPPHIRE_GPIO_WIFI_PA_RESETX (SAPPHIRE_GPIO_MISC4_BASE + 6)
+#define SAPPHIRE_GPIO_WIFI_EN (SAPPHIRE_GPIO_MISC4_BASE + 7)
+
+#define SAPPHIRE_GPIO_BT_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 0)
+#define SAPPHIRE_GPIO_MAC_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 1)
+#define SAPPHIRE_GPIO_MDDI_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 2)
+#define SAPPHIRE_GPIO_COMPASS_32K_EN (SAPPHIRE_GPIO_MISC5_BASE + 3)
+
+/* INT STATUS/LEVEL/MASK : INT GPIO should be the last. */
+#define SAPPHIRE_GPIO_NAVI_ACT_N (SAPPHIRE_GPIO_INT_B0_BASE + 0)
+#define SAPPHIRE_GPIO_COMPASS_IRQ (SAPPHIRE_GPIO_INT_B0_BASE + 1)
+#define SAPPHIRE_GPIO_SEARCH_ACT_N (SAPPHIRE_GPIO_INT_B0_BASE + 2)
+#define SAPPHIRE_GPIO_AUD_HSMIC_DET_N (SAPPHIRE_GPIO_INT_B0_BASE + 3)
+#define SAPPHIRE_GPIO_SDMC_CD_N (SAPPHIRE_GPIO_INT_B0_BASE + 4)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP1_N (SAPPHIRE_GPIO_INT_B0_BASE + 5)
+#define SAPPHIRE_GPIO_CAM_BTN_STEP2_N (SAPPHIRE_GPIO_INT_B0_BASE + 6)
+#define SAPPHIRE_GPIO_TP_ATT_N (SAPPHIRE_GPIO_INT_B0_BASE + 7)
+
+#define SAPPHIRE_GPIO_END SAPPHIRE_GPIO_TP_ATT_N
+#define SAPPHIRE_GPIO_LAST_INT (SAPPHIRE_GPIO_TP_ATT_N)
+
+/* Bit position in the CPLD MISCn by the CPLD GPIOn: only bit0-7 is used. */
+#define CPLD_GPIO_BIT_POS_MASK(n) (1U << ((n) & 7))
+#define CPLD_GPIO_REG_OFFSET(n) _g_CPLD_MISCn_Offset[((n)-SAPPHIRE_GPIO_START) >> 3]
+#define CPLD_GPIO_REG(n) (CPLD_GPIO_REG_OFFSET(n) + SAPPHIRE_CPLD_BASE)
+
+/*
+** CPLD INT Start
+*/
+#define SAPPHIRE_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS) /* pseudo number for CPLD INT */
+/* Using INT status/Bank0 for GPIO to INT */
+#define SAPPHIRE_GPIO_TO_INT(n) ((n-SAPPHIRE_GPIO_INT_B0_BASE) + SAPPHIRE_INT_START)
+#define SAPPHIRE_INT_END (SAPPHIRE_GPIO_TO_INT(SAPPHIRE_GPIO_END))
+
+/* get the INT reg by GPIO number */
+#define CPLD_INT_GPIO_TO_BANK(n) (((n)-SAPPHIRE_GPIO_INT_B0_BASE) >> 3)
+#define CPLD_INT_STATUS_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][0]
+#define CPLD_INT_LEVEL_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][1]
+#define CPLD_INT_MASK_REG_OFFSET_G(n) _g_INT_BANK_Offset[CPLD_INT_GPIO_TO_BANK(n)][2]
+#define CPLD_INT_STATUS_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET_G(n))
+#define CPLD_INT_LEVEL_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET_G(n))
+#define CPLD_INT_MASK_REG_G(n) (SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET_G(n))
+
+/* get the INT reg by INT number */
+#define CPLD_INT_TO_BANK(i) ((i-SAPPHIRE_INT_START) >> 3)
+#define CPLD_INT_STATUS_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][0]
+#define CPLD_INT_LEVEL_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][1]
+#define CPLD_INT_MASK_REG_OFFSET(i) _g_INT_BANK_Offset[CPLD_INT_TO_BANK(i)][2]
+#define CPLD_INT_STATUS_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_STATUS_REG_OFFSET(i))
+#define CPLD_INT_LEVEL_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_LEVEL_REG_OFFSET(i))
+#define CPLD_INT_MASK_REG(i) (SAPPHIRE_CPLD_BASE + CPLD_INT_MASK_REG_OFFSET(i) )
+
+/* return the bit mask by INT number */
+#define SAPPHIRE_INT_BIT_MASK(i) (1U << ((i - SAPPHIRE_INT_START) & 7))
+
+void config_sapphire_camera_on_gpios(void);
+void config_sapphire_camera_off_gpios(void);
+int sapphire_get_smi_size(void);
+unsigned int sapphire_get_hwid(void);
+unsigned int sapphire_get_skuid(void);
+unsigned int is_12pin_camera(void);
+int sapphire_is_5M_camera(void);
+int sapphire_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on);
+
+#endif /* GUARD */
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
new file mode 100644
index 000000000000..527379ec3597
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -0,0 +1,305 @@
+/* arch/arm/mach-msm/board-trout-gpio.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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/errno.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/sysdev.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/htc_pwrsink.h>
+
+#include "board-trout.h"
+#include "gpio_chip.h"
+
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_trout."
+
+static uint cpld_usb_h2w_sw;
+module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0);
+
+static uint8_t trout_cpld_shadow[4] = {
+#if defined(CONFIG_MSM_DEBUG_UART1)
+ /* H2W pins <-> UART1 */
+ [0] = 0x40, // for serial debug, low current
+#else
+ /* H2W pins <-> UART3, Bluetooth <-> UART1 */
+ [0] = 0x80, // for serial debug, low current
+#endif
+ [1] = 0x04, // I2C_PULL
+ [3] = 0x04, // mmdi 32k en
+};
+static uint8_t trout_int_mask[2] = {
+ [0] = 0xff, /* mask all interrupts */
+ [1] = 0xff,
+};
+static uint8_t trout_sleep_int_mask[] = {
+ [0] = 0xff,
+ [1] = 0xff,
+};
+static int trout_suspended;
+
+static int trout_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+ uint8_t b;
+ int reg;
+ if (n >= TROUT_GPIO_VIRTUAL_BASE)
+ n += TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET;
+ b = 1U << (n & 7);
+ reg = (n & 0x78) >> 2; // assumes base is 128
+ return !!(readb(TROUT_CPLD_BASE + reg) & b);
+}
+
+static void update_pwrsink(unsigned gpio, unsigned on)
+{
+ switch(gpio) {
+ case TROUT_GPIO_UI_LED_EN:
+ htc_pwrsink_set(PWRSINK_LED_BUTTON, on ? 100 : 0);
+ break;
+ case TROUT_GPIO_QTKEY_LED_EN:
+ htc_pwrsink_set(PWRSINK_LED_KEYBOARD, on ? 100 : 0);
+ break;
+ }
+}
+
+static uint8_t trout_gpio_write_shadow(unsigned n, unsigned on)
+{
+ uint8_t b = 1U << (n & 7);
+ int reg = (n & 0x78) >> 2; // assumes base is 128
+
+ if(on)
+ return trout_cpld_shadow[reg >> 1] |= b;
+ else
+ return trout_cpld_shadow[reg >> 1] &= ~b;
+}
+
+static int trout_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+ int reg = (n & 0x78) >> 2; // assumes base is 128
+ unsigned long flags;
+ uint8_t reg_val;
+
+ if ((reg >> 1) >= ARRAY_SIZE(trout_cpld_shadow)) {
+ printk(KERN_ERR "trout_gpio_write called on input %d\n", n);
+ return -ENOTSUPP;
+ }
+
+ local_irq_save(flags);
+ update_pwrsink(n, on);
+ reg_val = trout_gpio_write_shadow(n, on);
+ writeb(reg_val, TROUT_CPLD_BASE + reg);
+ local_irq_restore(flags);
+ return 0;
+}
+
+static int trout_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags)
+{
+ if(flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+ trout_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+ return 0;
+}
+
+static int trout_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+ if ((gpio < TROUT_GPIO_BANK0_FIRST_INT_SOURCE ||
+ gpio > TROUT_GPIO_BANK0_LAST_INT_SOURCE) &&
+ (gpio < TROUT_GPIO_BANK1_FIRST_INT_SOURCE ||
+ gpio > TROUT_GPIO_BANK1_LAST_INT_SOURCE))
+ return -ENOENT;
+ *irqp = TROUT_GPIO_TO_INT(gpio);
+ if(irqnumflagsp)
+ *irqnumflagsp = 0;
+ return 0;
+}
+
+static void trout_gpio_irq_ack(unsigned int irq)
+{
+ int bank = TROUT_INT_TO_BANK(irq);
+ uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int reg = TROUT_BANK_TO_STAT_REG(bank);
+ /*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+ writeb(mask, TROUT_CPLD_BASE + reg);
+}
+
+static void trout_gpio_irq_mask(unsigned int irq)
+{
+ unsigned long flags;
+ uint8_t reg_val;
+ int bank = TROUT_INT_TO_BANK(irq);
+ uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+ local_irq_save(flags);
+ reg_val = trout_int_mask[bank] |= mask;
+ /*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
+ irq, bank, reg_val);*/
+ if (!trout_suspended)
+ writeb(reg_val, TROUT_CPLD_BASE + reg);
+ local_irq_restore(flags);
+}
+
+static void trout_gpio_irq_unmask(unsigned int irq)
+{
+ unsigned long flags;
+ uint8_t reg_val;
+ int bank = TROUT_INT_TO_BANK(irq);
+ uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+ local_irq_save(flags);
+ reg_val = trout_int_mask[bank] &= ~mask;
+ /*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
+ irq, bank, reg_val);*/
+ if (!trout_suspended)
+ writeb(reg_val, TROUT_CPLD_BASE + reg);
+ local_irq_restore(flags);
+}
+
+int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ unsigned long flags;
+ int bank = TROUT_INT_TO_BANK(irq);
+ uint8_t mask = TROUT_INT_TO_MASK(irq);
+
+ local_irq_save(flags);
+ if(on)
+ trout_sleep_int_mask[bank] &= ~mask;
+ else
+ trout_sleep_int_mask[bank] |= mask;
+ local_irq_restore(flags);
+ return 0;
+}
+
+static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int j, m;
+ unsigned v;
+ int bank;
+ int stat_reg;
+ int int_base = TROUT_INT_START;
+ uint8_t int_mask;
+
+ for (bank = 0; bank < 2; bank++) {
+ stat_reg = TROUT_BANK_TO_STAT_REG(bank);
+ v = readb(TROUT_CPLD_BASE + stat_reg);
+ int_mask = trout_int_mask[bank];
+ if (v & int_mask) {
+ writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
+ printk(KERN_ERR "trout_gpio_irq_handler: got masked "
+ "interrupt: %d:%02x\n", bank, v & int_mask);
+ }
+ v &= ~int_mask;
+ while (v) {
+ m = v & -v;
+ j = fls(m) - 1;
+ /*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
+ "it %d irq %d\n", bank, v, m, j, int_base + j);*/
+ v &= ~m;
+ generic_handle_irq(int_base + j);
+ }
+ int_base += TROUT_INT_BANK0_COUNT;
+ }
+ desc->chip->ack(irq);
+}
+
+static int trout_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+ trout_suspended = 1;
+ writeb(trout_sleep_int_mask[0],
+ TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG);
+ writeb(trout_sleep_int_mask[1],
+ TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG);
+ writeb(trout_sleep_int_mask[0],
+ TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT0_REG);
+ writeb(trout_sleep_int_mask[1],
+ TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT1_REG);
+ return 0;
+}
+
+int trout_sysdev_resume(struct sys_device *dev)
+{
+ writeb(trout_int_mask[0], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG);
+ writeb(trout_int_mask[1], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG);
+ trout_suspended = 0;
+ return 0;
+}
+
+static struct irq_chip trout_gpio_irq_chip = {
+ .name = "troutgpio",
+ .ack = trout_gpio_irq_ack,
+ .mask = trout_gpio_irq_mask,
+ .unmask = trout_gpio_irq_unmask,
+ .set_wake = trout_gpio_irq_set_wake,
+ //.set_type = trout_gpio_irq_set_type,
+};
+
+static struct gpio_chip trout_gpio_chip = {
+ .start = TROUT_GPIO_START,
+ .end = TROUT_GPIO_END,
+ .configure = trout_gpio_configure,
+ .get_irq_num = trout_gpio_get_irq_num,
+ .read = trout_gpio_read,
+ .write = trout_gpio_write,
+// .read_detect_status = trout_gpio_read_detect_status,
+// .clear_detect_status = trout_gpio_clear_detect_status
+};
+
+struct sysdev_class trout_sysdev_class = {
+ .name = "troutgpio_irq",
+ .suspend = trout_sysdev_suspend,
+ .resume = trout_sysdev_resume,
+};
+
+static struct sys_device trout_irq_device = {
+ .cls = &trout_sysdev_class,
+};
+
+static int __init trout_init_gpio(void)
+{
+ int i;
+
+ if (!machine_is_trout())
+ return 0;
+
+ /* adjust GPIOs based on bootloader request */
+ pr_info("trout_init_gpio: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw);
+ trout_gpio_write_shadow(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw);
+
+ for(i = 0; i < ARRAY_SIZE(trout_cpld_shadow); i++)
+ writeb(trout_cpld_shadow[i], TROUT_CPLD_BASE + i * 2);
+
+ for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
+ set_irq_chip(i, &trout_gpio_irq_chip);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ register_gpio_chip(&trout_gpio_chip);
+
+ set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+ set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
+ set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
+ if(sysdev_class_register(&trout_sysdev_class) == 0)
+ sysdev_register(&trout_irq_device);
+
+ return 0;
+}
+
+postcore_initcall(trout_init_gpio);
diff --git a/arch/arm/mach-msm/board-trout-keypad.c b/arch/arm/mach-msm/board-trout-keypad.c
new file mode 100644
index 000000000000..0299d0686de9
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-keypad.c
@@ -0,0 +1,345 @@
+/* arch/arm/mach-msm/board-trout-keypad.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/gpio_event.h>
+#include <asm/mach-types.h>
+
+#include "board-trout.h"
+
+static char *keycaps = "--qwerty";
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "board_trout."
+module_param_named(keycaps, keycaps, charp, 0);
+
+
+static unsigned int trout_col_gpios[] = { 35, 34, 33, 32, 31, 23, 30, 78 };
+static unsigned int trout_row_gpios[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(trout_row_gpios) + (row))
+
+static const unsigned short trout_keymap[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_BACK,
+ [KEYMAP_INDEX(0, 1)] = KEY_HOME,
+// [KEYMAP_INDEX(0, 2)] = KEY_,
+ [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+ [KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+ [KEYMAP_INDEX(0, 5)] = KEY_RIGHTALT,
+ [KEYMAP_INDEX(0, 6)] = KEY_P,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_MENU,
+// [KEYMAP_INDEX(1, 0)] = 229, // SOFT1
+ [KEYMAP_INDEX(1, 1)] = KEY_SEND,
+ [KEYMAP_INDEX(1, 2)] = KEY_END,
+ [KEYMAP_INDEX(1, 3)] = KEY_LEFTALT,
+ [KEYMAP_INDEX(1, 4)] = KEY_A,
+ [KEYMAP_INDEX(1, 5)] = KEY_LEFTSHIFT,
+ [KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_U,
+ [KEYMAP_INDEX(2, 1)] = KEY_7,
+ [KEYMAP_INDEX(2, 2)] = KEY_K,
+ [KEYMAP_INDEX(2, 3)] = KEY_J,
+ [KEYMAP_INDEX(2, 4)] = KEY_M,
+ [KEYMAP_INDEX(2, 5)] = KEY_SLASH,
+ [KEYMAP_INDEX(2, 6)] = KEY_8,
+
+ [KEYMAP_INDEX(3, 0)] = KEY_5,
+ [KEYMAP_INDEX(3, 1)] = KEY_6,
+ [KEYMAP_INDEX(3, 2)] = KEY_B,
+ [KEYMAP_INDEX(3, 3)] = KEY_H,
+ [KEYMAP_INDEX(3, 4)] = KEY_N,
+ [KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+ [KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+ [KEYMAP_INDEX(4, 0)] = KEY_4,
+ [KEYMAP_INDEX(4, 1)] = KEY_R,
+ [KEYMAP_INDEX(4, 2)] = KEY_V,
+ [KEYMAP_INDEX(4, 3)] = KEY_G,
+ [KEYMAP_INDEX(4, 4)] = KEY_C,
+ //[KEYMAP_INDEX(4, 5)] = KEY_,
+ [KEYMAP_INDEX(4, 6)] = KEY_T,
+
+ [KEYMAP_INDEX(5, 0)] = KEY_2,
+ [KEYMAP_INDEX(5, 1)] = KEY_W,
+ [KEYMAP_INDEX(5, 2)] = KEY_COMPOSE,
+ [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+ [KEYMAP_INDEX(5, 4)] = KEY_S,
+ [KEYMAP_INDEX(5, 5)] = KEY_Z,
+ [KEYMAP_INDEX(5, 6)] = KEY_1,
+
+ [KEYMAP_INDEX(6, 0)] = KEY_I,
+ [KEYMAP_INDEX(6, 1)] = KEY_0,
+ [KEYMAP_INDEX(6, 2)] = KEY_O,
+ [KEYMAP_INDEX(6, 3)] = KEY_L,
+ [KEYMAP_INDEX(6, 4)] = KEY_DOT,
+ [KEYMAP_INDEX(6, 5)] = KEY_COMMA,
+ [KEYMAP_INDEX(6, 6)] = KEY_9,
+
+ [KEYMAP_INDEX(7, 0)] = KEY_3,
+ [KEYMAP_INDEX(7, 1)] = KEY_E,
+ [KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+ [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(7, 4)] = KEY_X,
+ [KEYMAP_INDEX(7, 5)] = KEY_F,
+ [KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static unsigned int trout_col_gpios_evt2[] = { 35, 34, 33, 32, 31, 23, 30, 109 };
+static unsigned int trout_row_gpios_evt2[] = { 42, 41, 40, 39, 38, 37, 36 };
+
+static const unsigned short trout_keymap_evt2_1[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_BACK,
+ [KEYMAP_INDEX(0, 1)] = KEY_HOME,
+// [KEYMAP_INDEX(0, 2)] = KEY_,
+ [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+ [KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+ [KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT,
+ [KEYMAP_INDEX(0, 6)] = KEY_P,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_MENU,
+ [KEYMAP_INDEX(1, 1)] = KEY_SEND,
+// [KEYMAP_INDEX(1, 2)] = KEY_,
+ [KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+ [KEYMAP_INDEX(1, 4)] = KEY_A,
+ [KEYMAP_INDEX(1, 5)] = KEY_COMPOSE,
+ [KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_U,
+ [KEYMAP_INDEX(2, 1)] = KEY_7,
+ [KEYMAP_INDEX(2, 2)] = KEY_K,
+ [KEYMAP_INDEX(2, 3)] = KEY_J,
+ [KEYMAP_INDEX(2, 4)] = KEY_M,
+ [KEYMAP_INDEX(2, 5)] = KEY_SLASH,
+ [KEYMAP_INDEX(2, 6)] = KEY_8,
+
+ [KEYMAP_INDEX(3, 0)] = KEY_5,
+ [KEYMAP_INDEX(3, 1)] = KEY_6,
+ [KEYMAP_INDEX(3, 2)] = KEY_B,
+ [KEYMAP_INDEX(3, 3)] = KEY_H,
+ [KEYMAP_INDEX(3, 4)] = KEY_N,
+ [KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+ [KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+ [KEYMAP_INDEX(4, 0)] = KEY_4,
+ [KEYMAP_INDEX(4, 1)] = KEY_R,
+ [KEYMAP_INDEX(4, 2)] = KEY_V,
+ [KEYMAP_INDEX(4, 3)] = KEY_G,
+ [KEYMAP_INDEX(4, 4)] = KEY_C,
+// [KEYMAP_INDEX(4, 5)] = KEY_,
+ [KEYMAP_INDEX(4, 6)] = KEY_T,
+
+ [KEYMAP_INDEX(5, 0)] = KEY_2,
+ [KEYMAP_INDEX(5, 1)] = KEY_W,
+ [KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+ [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+ [KEYMAP_INDEX(5, 4)] = KEY_S,
+ [KEYMAP_INDEX(5, 5)] = KEY_Z,
+ [KEYMAP_INDEX(5, 6)] = KEY_1,
+
+ [KEYMAP_INDEX(6, 0)] = KEY_I,
+ [KEYMAP_INDEX(6, 1)] = KEY_0,
+ [KEYMAP_INDEX(6, 2)] = KEY_O,
+ [KEYMAP_INDEX(6, 3)] = KEY_L,
+ [KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+ [KEYMAP_INDEX(6, 5)] = KEY_DOT,
+ [KEYMAP_INDEX(6, 6)] = KEY_9,
+
+ [KEYMAP_INDEX(7, 0)] = KEY_3,
+ [KEYMAP_INDEX(7, 1)] = KEY_E,
+ [KEYMAP_INDEX(7, 2)] = KEY_EMAIL, // @
+ [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(7, 4)] = KEY_X,
+ [KEYMAP_INDEX(7, 5)] = KEY_F,
+ [KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static const unsigned short trout_keymap_evt2_2[ARRAY_SIZE(trout_col_gpios) * ARRAY_SIZE(trout_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_BACK,
+ [KEYMAP_INDEX(0, 1)] = KEY_HOME,
+// [KEYMAP_INDEX(0, 2)] = KEY_,
+ [KEYMAP_INDEX(0, 3)] = KEY_BACKSPACE,
+ [KEYMAP_INDEX(0, 4)] = KEY_ENTER,
+ [KEYMAP_INDEX(0, 5)] = KEY_RIGHTSHIFT,
+ [KEYMAP_INDEX(0, 6)] = KEY_P,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_MENU, /* external menu key */
+ [KEYMAP_INDEX(1, 1)] = KEY_SEND,
+// [KEYMAP_INDEX(1, 2)] = KEY_,
+ [KEYMAP_INDEX(1, 3)] = KEY_LEFTSHIFT,
+ [KEYMAP_INDEX(1, 4)] = KEY_A,
+ [KEYMAP_INDEX(1, 5)] = KEY_F1, /* qwerty menu key */
+ [KEYMAP_INDEX(1, 6)] = KEY_Q,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_U,
+ [KEYMAP_INDEX(2, 1)] = KEY_7,
+ [KEYMAP_INDEX(2, 2)] = KEY_K,
+ [KEYMAP_INDEX(2, 3)] = KEY_J,
+ [KEYMAP_INDEX(2, 4)] = KEY_M,
+ [KEYMAP_INDEX(2, 5)] = KEY_DOT,
+ [KEYMAP_INDEX(2, 6)] = KEY_8,
+
+ [KEYMAP_INDEX(3, 0)] = KEY_5,
+ [KEYMAP_INDEX(3, 1)] = KEY_6,
+ [KEYMAP_INDEX(3, 2)] = KEY_B,
+ [KEYMAP_INDEX(3, 3)] = KEY_H,
+ [KEYMAP_INDEX(3, 4)] = KEY_N,
+ [KEYMAP_INDEX(3, 5)] = KEY_SPACE,
+ [KEYMAP_INDEX(3, 6)] = KEY_Y,
+
+ [KEYMAP_INDEX(4, 0)] = KEY_4,
+ [KEYMAP_INDEX(4, 1)] = KEY_R,
+ [KEYMAP_INDEX(4, 2)] = KEY_V,
+ [KEYMAP_INDEX(4, 3)] = KEY_G,
+ [KEYMAP_INDEX(4, 4)] = KEY_C,
+ [KEYMAP_INDEX(4, 5)] = KEY_EMAIL, // @
+ [KEYMAP_INDEX(4, 6)] = KEY_T,
+
+ [KEYMAP_INDEX(5, 0)] = KEY_2,
+ [KEYMAP_INDEX(5, 1)] = KEY_W,
+ [KEYMAP_INDEX(5, 2)] = KEY_LEFTALT,
+ [KEYMAP_INDEX(5, 3)] = KEY_VOLUMEUP,
+ [KEYMAP_INDEX(5, 4)] = KEY_S,
+ [KEYMAP_INDEX(5, 5)] = KEY_Z,
+ [KEYMAP_INDEX(5, 6)] = KEY_1,
+
+ [KEYMAP_INDEX(6, 0)] = KEY_I,
+ [KEYMAP_INDEX(6, 1)] = KEY_0,
+ [KEYMAP_INDEX(6, 2)] = KEY_O,
+ [KEYMAP_INDEX(6, 3)] = KEY_L,
+ [KEYMAP_INDEX(6, 4)] = KEY_COMMA,
+ [KEYMAP_INDEX(6, 5)] = KEY_RIGHTALT,
+ [KEYMAP_INDEX(6, 6)] = KEY_9,
+
+ [KEYMAP_INDEX(7, 0)] = KEY_3,
+ [KEYMAP_INDEX(7, 1)] = KEY_E,
+ [KEYMAP_INDEX(7, 2)] = KEY_COMPOSE,
+ [KEYMAP_INDEX(7, 3)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(7, 4)] = KEY_X,
+ [KEYMAP_INDEX(7, 5)] = KEY_F,
+ [KEYMAP_INDEX(7, 6)] = KEY_D
+};
+
+static struct gpio_event_matrix_info trout_keypad_matrix_info = {
+ .info.func = gpio_event_matrix_func,
+ .keymap = trout_keymap,
+ .output_gpios = trout_col_gpios,
+ .input_gpios = trout_row_gpios,
+ .noutputs = ARRAY_SIZE(trout_col_gpios),
+ .ninputs = ARRAY_SIZE(trout_row_gpios),
+ .settle_time.tv.nsec = 40 * NSEC_PER_USEC,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_REMOVE_PHANTOM_KEYS |GPIOKPF_PRINT_UNMAPPED_KEYS /*| GPIOKPF_PRINT_MAPPED_KEYS*/
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map[] = {
+ { TROUT_POWER_KEY, KEY_POWER },
+ { TROUT_GPIO_CAM_BTN_STEP1_N, KEY_CAMERA-1 }, //steal KEY_HP
+ { TROUT_GPIO_CAM_BTN_STEP2_N, KEY_CAMERA },
+};
+
+static struct gpio_event_direct_entry trout_keypad_nav_map_evt2[] = {
+ { TROUT_POWER_KEY, KEY_END },
+ { TROUT_GPIO_CAM_BTN_STEP1_N, KEY_CAMERA-1 }, //steal KEY_HP
+ { TROUT_GPIO_CAM_BTN_STEP2_N, KEY_CAMERA },
+};
+
+static struct gpio_event_input_info trout_keypad_nav_info = {
+ .info.func = gpio_event_input_func,
+ .flags = 0,
+ .type = EV_KEY,
+ .keymap = trout_keypad_nav_map,
+ .keymap_size = ARRAY_SIZE(trout_keypad_nav_map)
+};
+
+static struct gpio_event_direct_entry trout_keypad_switch_map[] = {
+ { TROUT_GPIO_SLIDING_DET, SW_LID }
+};
+
+static struct gpio_event_input_info trout_keypad_switch_info = {
+ .info.func = gpio_event_input_func,
+ .flags = 0,
+ .type = EV_SW,
+ .keymap = trout_keypad_switch_map,
+ .keymap_size = ARRAY_SIZE(trout_keypad_switch_map)
+};
+
+static struct gpio_event_info *trout_keypad_info[] = {
+ &trout_keypad_matrix_info.info,
+ &trout_keypad_nav_info.info,
+ &trout_keypad_switch_info.info,
+};
+
+static struct gpio_event_platform_data trout_keypad_data = {
+ .name = "trout-keypad",
+ .info = trout_keypad_info,
+ .info_count = ARRAY_SIZE(trout_keypad_info)
+};
+
+static struct platform_device trout_keypad_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &trout_keypad_data,
+ },
+};
+
+static int __init trout_init_keypad(void)
+{
+ if (!machine_is_trout())
+ return 0;
+
+ switch (system_rev) {
+ case 0:
+ /* legacy default keylayout */
+ break;
+ case 1:
+ /* v1 has a new keyboard layout */
+ trout_keypad_matrix_info.keymap = trout_keymap_evt2_1;
+ trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+ trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+
+ /* v1 has new direct keys */
+ trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+ trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+ /* userspace needs to know about these changes as well */
+ trout_keypad_data.name = "trout-keypad-v2";
+ break;
+ default: /* 2, 3, 4 currently */
+ /* v2 has a new keyboard layout */
+ trout_keypad_matrix_info.keymap = trout_keymap_evt2_2;
+ trout_keypad_matrix_info.output_gpios = trout_col_gpios_evt2;
+ trout_keypad_matrix_info.input_gpios = trout_row_gpios_evt2;
+
+ /* v2 has new direct keys */
+ trout_keypad_nav_info.keymap = trout_keypad_nav_map_evt2;
+ trout_keypad_nav_info.keymap_size = ARRAY_SIZE(trout_keypad_nav_map_evt2);
+
+ /* userspace needs to know about these changes as well */
+ if (!strcmp(keycaps, "qwertz")) {
+ trout_keypad_data.name = "trout-keypad-qwertz";
+ } else {
+ trout_keypad_data.name = "trout-keypad-v3";
+ }
+ break;
+ }
+ return platform_device_register(&trout_keypad_device);
+}
+
+device_initcall(trout_init_keypad);
+
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
new file mode 100644
index 000000000000..f417fa4f4152
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -0,0 +1,437 @@
+/* linux/arch/arm/mach-msm/board-trout-mmc.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include <asm/mach/mmc.h>
+
+#include "devices.h"
+
+#include "board-trout.h"
+
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat);
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n;
+ unsigned id;
+ for(n = 0; n < len; n++) {
+ id = table[n];
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+ }
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+ PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+ PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+ PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+ PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+ PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+ PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+ PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+ PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init trout_disablesdcard_setup(char *str)
+{
+ int cal = simple_strtol(str, NULL, 0);
+
+ opt_disable_sdcard = cal;
+ return 1;
+}
+
+__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot; /* SD slot power */
+
+struct mmc_vdd_xlat {
+ int mask;
+ int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+ { MMC_VDD_165_195, 1800 },
+ { MMC_VDD_20_21, 2050 },
+ { MMC_VDD_21_22, 2150 },
+ { MMC_VDD_22_23, 2250 },
+ { MMC_VDD_23_24, 2350 },
+ { MMC_VDD_24_25, 2450 },
+ { MMC_VDD_25_26, 2550 },
+ { MMC_VDD_26_27, 2650 },
+ { MMC_VDD_27_28, 2750 },
+ { MMC_VDD_28_29, 2850 },
+ { MMC_VDD_29_30, 2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+ int i, rc;
+
+ BUG_ON(!vreg_sdslot);
+
+ if (vdd == sdslot_vdd)
+ return 0;
+
+ sdslot_vdd = vdd;
+
+ if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+ printk("%s: Disabling SD slot power\n", __func__);
+#endif
+ config_gpio_table(sdcard_off_gpio_table,
+ ARRAY_SIZE(sdcard_off_gpio_table));
+ vreg_disable(vreg_sdslot);
+ sdslot_vreg_enabled = 0;
+ return 0;
+ }
+
+ if (!sdslot_vreg_enabled) {
+ rc = vreg_enable(vreg_sdslot);
+ if (rc) {
+ printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+ __func__, rc);
+ }
+ config_gpio_table(sdcard_on_gpio_table,
+ ARRAY_SIZE(sdcard_on_gpio_table));
+ sdslot_vreg_enabled = 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+ if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+ printk("%s: Setting level to %u\n",
+ __func__, mmc_vdd_table[i].level);
+#endif
+ rc = vreg_set_level(vreg_sdslot,
+ mmc_vdd_table[i].level);
+ if (rc) {
+ printk(KERN_ERR
+ "%s: Error setting vreg level (%d)\n",
+ __func__, rc);
+ }
+ return 0;
+ }
+ }
+
+ printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+ return 0;
+}
+
+static unsigned int trout_sdslot_status(struct device *dev)
+{
+ unsigned int status;
+
+ status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N);
+ return (!status);
+}
+
+#define TROUT_MMC_VDD MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+ | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+ | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+ | MMC_VDD_28_29 | MMC_VDD_29_30
+
+static struct mmc_platform_data trout_sdslot_data = {
+ .ocr_mask = TROUT_MMC_VDD,
+ .status_irq = TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N),
+ .status = trout_sdslot_status,
+ .translate_vdd = trout_sdslot_switchvdd,
+};
+
+/* ---- WIFI ---- */
+
+static uint32_t wifi_on_gpio_table[] = {
+ PCOM_GPIO_CFG(51, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(52, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(53, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(54, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+ PCOM_GPIO_CFG(55, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+ PCOM_GPIO_CFG(56, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+ PCOM_GPIO_CFG(29, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
+};
+
+static uint32_t wifi_off_gpio_table[] = {
+ PCOM_GPIO_CFG(51, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+ PCOM_GPIO_CFG(52, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+ PCOM_GPIO_CFG(53, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+ PCOM_GPIO_CFG(54, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+ PCOM_GPIO_CFG(55, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+ PCOM_GPIO_CFG(56, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+ PCOM_GPIO_CFG(29, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
+};
+
+static struct vreg *vreg_wifi_osc; /* WIFI 32khz oscilator */
+static int trout_wifi_cd = 0; /* WIFI virtual 'card detect' status */
+
+static struct sdio_embedded_func wifi_func = {
+ .f_class = SDIO_CLASS_WLAN,
+ .f_maxblksize = 512,
+};
+
+static struct embedded_sdio_data trout_wifi_emb_data = {
+ .cis = {
+ .vendor = 0x104c,
+ .device = 0x9066,
+ .blksize = 512,
+ /*.max_dtr = 24000000, Max of chip - no worky on Trout */
+ .max_dtr = 20000000,
+ },
+ .cccr = {
+ .multi_block = 0,
+ .low_speed = 0,
+ .wide_bus = 1,
+ .high_power = 0,
+ .high_speed = 0,
+ },
+ .funcs = &wifi_func,
+ .num_funcs = 1,
+};
+
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static int trout_wifi_status_register(void (*callback)(int card_present, void *dev_id), void *dev_id)
+{
+ if (wifi_status_cb)
+ return -EAGAIN;
+ wifi_status_cb = callback;
+ wifi_status_cb_devid = dev_id;
+ return 0;
+}
+
+static unsigned int trout_wifi_status(struct device *dev)
+{
+ return trout_wifi_cd;
+}
+
+int trout_wifi_set_carddetect(int val)
+{
+ printk("%s: %d\n", __func__, val);
+ trout_wifi_cd = val;
+ if (wifi_status_cb) {
+ wifi_status_cb(val, wifi_status_cb_devid);
+ } else
+ printk(KERN_WARNING "%s: Nobody to notify\n", __func__);
+ return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(trout_wifi_set_carddetect);
+#endif
+
+static int trout_wifi_power_state;
+
+int trout_wifi_power(int on)
+{
+ int rc;
+
+ printk("%s: %d\n", __func__, on);
+
+ if (on) {
+ config_gpio_table(wifi_on_gpio_table,
+ ARRAY_SIZE(wifi_on_gpio_table));
+ rc = vreg_enable(vreg_wifi_osc);
+ if (rc)
+ return rc;
+ htc_pwrsink_set(PWRSINK_WIFI, 70);
+ } else {
+ config_gpio_table(wifi_off_gpio_table,
+ ARRAY_SIZE(wifi_off_gpio_table));
+ htc_pwrsink_set(PWRSINK_WIFI, 0);
+ }
+ gpio_set_value( TROUT_GPIO_MAC_32K_EN, on);
+ mdelay(100);
+ gpio_set_value( TROUT_GPIO_WIFI_EN, on);
+ mdelay(100);
+ if (!on) {
+ vreg_disable(vreg_wifi_osc);
+ }
+ trout_wifi_power_state = on;
+ return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(trout_wifi_power);
+#endif
+
+static int trout_wifi_reset_state;
+int trout_wifi_reset(int on)
+{
+ printk("%s: %d\n", __func__, on);
+ gpio_set_value( TROUT_GPIO_WIFI_PA_RESETX, !on );
+ trout_wifi_reset_state = on;
+ mdelay(50);
+ return 0;
+}
+#ifndef CONFIG_WIFI_CONTROL_FUNC
+EXPORT_SYMBOL(trout_wifi_reset);
+#endif
+
+static struct mmc_platform_data trout_wifi_data = {
+ .ocr_mask = MMC_VDD_28_29,
+ .status = trout_wifi_status,
+ .register_status_notify = trout_wifi_status_register,
+ .embedded_sdio = &trout_wifi_emb_data,
+};
+
+int __init trout_init_mmc(unsigned int sys_rev)
+{
+ wifi_status_cb = NULL;
+
+ sdslot_vreg_enabled = 0;
+
+ vreg_sdslot = vreg_get(0, "gp6");
+ if (IS_ERR(vreg_sdslot))
+ return PTR_ERR(vreg_sdslot);
+ vreg_wifi_osc = vreg_get(0, "mmc");
+ if (IS_ERR(vreg_wifi_osc))
+ return PTR_ERR(vreg_wifi_osc);
+
+ set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1);
+
+ msm_add_sdcc(1, &trout_wifi_data);
+
+ if (!opt_disable_sdcard)
+ msm_add_sdcc(2, &trout_sdslot_data);
+ else
+ printk(KERN_INFO "trout: SD-Card interface disabled\n");
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int troutmmc_dbg_wifi_reset_set(void *data, u64 val)
+{
+ trout_wifi_reset((int) val);
+ return 0;
+}
+
+static int troutmmc_dbg_wifi_reset_get(void *data, u64 *val)
+{
+ *val = trout_wifi_reset_state;
+ return 0;
+}
+
+static int troutmmc_dbg_wifi_cd_set(void *data, u64 val)
+{
+ trout_wifi_set_carddetect((int) val);
+ return 0;
+}
+
+static int troutmmc_dbg_wifi_cd_get(void *data, u64 *val)
+{
+ *val = trout_wifi_cd;
+ return 0;
+}
+
+static int troutmmc_dbg_wifi_pwr_set(void *data, u64 val)
+{
+ trout_wifi_power((int) val);
+ return 0;
+}
+
+static int troutmmc_dbg_wifi_pwr_get(void *data, u64 *val)
+{
+
+ *val = trout_wifi_power_state;
+ return 0;
+}
+
+static int troutmmc_dbg_sd_pwr_set(void *data, u64 val)
+{
+ trout_sdslot_switchvdd(NULL, (unsigned int) val);
+ return 0;
+}
+
+static int troutmmc_dbg_sd_pwr_get(void *data, u64 *val)
+{
+ *val = sdslot_vdd;
+ return 0;
+}
+
+static int troutmmc_dbg_sd_cd_set(void *data, u64 val)
+{
+ return -ENOSYS;
+}
+
+static int troutmmc_dbg_sd_cd_get(void *data, u64 *val)
+{
+ *val = trout_sdslot_status(NULL);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_reset_fops,
+ troutmmc_dbg_wifi_reset_get,
+ troutmmc_dbg_wifi_reset_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_cd_fops,
+ troutmmc_dbg_wifi_cd_get,
+ troutmmc_dbg_wifi_cd_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_wifi_pwr_fops,
+ troutmmc_dbg_wifi_pwr_get,
+ troutmmc_dbg_wifi_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_pwr_fops,
+ troutmmc_dbg_sd_pwr_get,
+ troutmmc_dbg_sd_pwr_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(troutmmc_dbg_sd_cd_fops,
+ troutmmc_dbg_sd_cd_get,
+ troutmmc_dbg_sd_cd_set, "%llu\n");
+
+static int __init troutmmc_dbg_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("troutmmc_dbg", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("wifi_reset", 0644, dent, NULL,
+ &troutmmc_dbg_wifi_reset_fops);
+ debugfs_create_file("wifi_cd", 0644, dent, NULL,
+ &troutmmc_dbg_wifi_cd_fops);
+ debugfs_create_file("wifi_pwr", 0644, dent, NULL,
+ &troutmmc_dbg_wifi_pwr_fops);
+
+ debugfs_create_file("sd_pwr", 0644, dent, NULL,
+ &troutmmc_dbg_sd_pwr_fops);
+ debugfs_create_file("sd_cd", 0644, dent, NULL,
+ &troutmmc_dbg_sd_cd_fops);
+
+ return 0;
+}
+
+device_initcall(troutmmc_dbg_init);
+
+#endif
diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c
new file mode 100644
index 000000000000..900b8b1a6f76
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-panel.c
@@ -0,0 +1,642 @@
+/* linux/arch/arm/mach-msm/board-trout-mddi.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+
+#include <mach/msm_fb.h>
+#include <mach/vreg.h>
+#include <mach/htc_pwrsink.h>
+
+#include "board-trout.h"
+#include "proc_comm.h"
+#include "devices.h"
+
+#define TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS 255
+
+static struct clk *gp_clk;
+static int trout_backlight_off;
+static int trout_backlight_brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS;
+static int trout_new_backlight = 1;
+static uint8_t trout_backlight_last_level = 33;
+static DEFINE_MUTEX(trout_backlight_lock);
+
+static void trout_set_backlight_level(uint8_t level)
+{
+ unsigned percent = ((int)level * 100) / 255;
+
+ if (trout_new_backlight) {
+ unsigned long flags;
+ int i = 0;
+ level = (int)level * 34 / 256;
+
+ if (trout_backlight_last_level == level)
+ return;
+
+ if (level == 0) {
+ gpio_set_value(27, 0);
+ msleep(2);
+ } else {
+ local_irq_save(flags);
+ if (trout_backlight_last_level == 0) {
+ gpio_set_value(27, 1);
+ udelay(40);
+ trout_backlight_last_level = 33;
+ }
+ i = (trout_backlight_last_level - level + 33) % 33;
+ while (i-- > 0) {
+ gpio_set_value(27, 0);
+ udelay(1);
+ gpio_set_value(27, 1);
+ udelay(1);
+ }
+ local_irq_restore(flags);
+ }
+ trout_backlight_last_level = level;
+ }
+ else {
+ if(level) {
+ clk_enable(gp_clk);
+ writel((1U << 16) | (~level & 0xffff),
+ MSM_CLK_CTL_BASE + 0x58);
+ /* Going directly to a 100% duty cycle does not
+ * seem to work */
+ if(level == 255) {
+ writel((~127 << 16) | 0xb20,
+ MSM_CLK_CTL_BASE + 0x5c);
+ udelay(1);
+ }
+ writel((~127 << 16) | 0xb58, MSM_CLK_CTL_BASE + 0x5c);
+ }
+ else {
+ writel(0x0, MSM_CLK_CTL_BASE + 0x5c);
+ clk_disable(gp_clk);
+ }
+ }
+ htc_pwrsink_set(PWRSINK_BACKLIGHT, percent);
+}
+
+#define MDDI_CLIENT_CORE_BASE 0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE 0x120000
+#define I2C_BLOCK_BASE 0x130000
+#define PWM_BLOCK_BASE 0x140000
+#define GPIO_BLOCK_BASE 0x150000
+#define SYSTEM_BLOCK1_BASE 0x160000
+#define SYSTEM_BLOCK2_BASE 0x170000
+
+
+#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
+#define SYSCLKENA (MDDI_CLIENT_CORE_BASE|0x2C)
+#define PWM0OFF (PWM_BLOCK_BASE|0x1C)
+
+#define V_VDDE2E_VDD2_GPIO 0
+#define MDDI_RST_N 82
+
+#define MDDICAP0 (MDDI_CLIENT_CORE_BASE|0x00)
+#define MDDICAP1 (MDDI_CLIENT_CORE_BASE|0x04)
+#define MDDICAP2 (MDDI_CLIENT_CORE_BASE|0x08)
+#define MDDICAP3 (MDDI_CLIENT_CORE_BASE|0x0C)
+#define MDCAPCHG (MDDI_CLIENT_CORE_BASE|0x10)
+#define MDCRCERC (MDDI_CLIENT_CORE_BASE|0x14)
+#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18)
+#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C)
+#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20)
+#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
+#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28)
+#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C)
+#define TESTMODE (MDDI_CLIENT_CORE_BASE|0x30)
+#define FIFOMONI (MDDI_CLIENT_CORE_BASE|0x34)
+#define INTMONI (MDDI_CLIENT_CORE_BASE|0x38)
+#define MDIOBIST (MDDI_CLIENT_CORE_BASE|0x3C)
+#define MDIOPSET (MDDI_CLIENT_CORE_BASE|0x40)
+#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44)
+#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48)
+#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C)
+#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50)
+#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54)
+
+#define SRST (LCD_CONTROL_BLOCK_BASE|0x00)
+#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04)
+#define START (LCD_CONTROL_BLOCK_BASE|0x08)
+#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C)
+#define CMN (LCD_CONTROL_BLOCK_BASE|0x10)
+#define GAMMA (LCD_CONTROL_BLOCK_BASE|0x14)
+#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
+#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
+#define HDE_LEFT (LCD_CONTROL_BLOCK_BASE|0x24)
+#define VDE_TOP (LCD_CONTROL_BLOCK_BASE|0x28)
+#define PXL (LCD_CONTROL_BLOCK_BASE|0x30)
+#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
+#define HSW (LCD_CONTROL_BLOCK_BASE|0x38)
+#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40)
+#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44)
+#define VSW (LCD_CONTROL_BLOCK_BASE|0x48)
+#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50)
+#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
+#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58)
+#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60)
+#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64)
+#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68)
+#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70)
+#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74)
+#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78)
+#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80)
+#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84)
+#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88)
+#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C)
+
+#define SSICTL (SPI_BLOCK_BASE|0x00)
+#define SSITIME (SPI_BLOCK_BASE|0x04)
+#define SSITX (SPI_BLOCK_BASE|0x08)
+#define SSIRX (SPI_BLOCK_BASE|0x0C)
+#define SSIINTC (SPI_BLOCK_BASE|0x10)
+#define SSIINTS (SPI_BLOCK_BASE|0x14)
+#define SSIDBG1 (SPI_BLOCK_BASE|0x18)
+#define SSIDBG2 (SPI_BLOCK_BASE|0x1C)
+#define SSIID (SPI_BLOCK_BASE|0x20)
+
+#define WKREQ (SYSTEM_BLOCK1_BASE|0x00)
+#define CLKENB (SYSTEM_BLOCK1_BASE|0x04)
+#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08)
+#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C)
+#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
+
+#define GPIODATA (GPIO_BLOCK_BASE|0x00)
+#define GPIODIR (GPIO_BLOCK_BASE|0x04)
+#define GPIOIS (GPIO_BLOCK_BASE|0x08)
+#define GPIOIBE (GPIO_BLOCK_BASE|0x0C)
+#define GPIOIEV (GPIO_BLOCK_BASE|0x10)
+#define GPIOIE (GPIO_BLOCK_BASE|0x14)
+#define GPIORIS (GPIO_BLOCK_BASE|0x18)
+#define GPIOMIS (GPIO_BLOCK_BASE|0x1C)
+#define GPIOIC (GPIO_BLOCK_BASE|0x20)
+#define GPIOOMS (GPIO_BLOCK_BASE|0x24)
+#define GPIOPC (GPIO_BLOCK_BASE|0x28)
+#define GPIOID (GPIO_BLOCK_BASE|0x30)
+
+#define SPI_WRITE(reg, val) \
+ { SSITX, 0x00010000 | (((reg) & 0xff) << 8) | ((val) & 0xff) }, \
+ { 0, 5 },
+
+#define SPI_WRITE1(reg) \
+ { SSITX, (reg) & 0xff }, \
+ { 0, 5 },
+
+struct mddi_table {
+ uint32_t reg;
+ uint32_t value;
+};
+static struct mddi_table mddi_toshiba_init_table[] = {
+ { DPSET0, 0x09e90046 },
+ { DPSET1, 0x00000118 },
+ { DPSUS, 0x00000000 },
+ { DPRUN, 0x00000001 },
+ { 1, 14 }, /* msleep 14 */
+ { SYSCKENA, 0x00000001 },
+ //{ CLKENB, 0x000000EF },
+ { CLKENB, 0x0000A1EF }, /* # SYS.CLKENB # Enable clocks for each module (without DCLK , i2cCLK) */
+ //{ CLKENB, 0x000025CB }, /* Clock enable register */
+
+ { GPIODATA, 0x02000200 }, /* # GPI .GPIODATA # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0 */
+ { GPIODIR, 0x000030D }, /* 24D # GPI .GPIODIR # Select direction of GPIO port (0,2,3,6,9 output) */
+ { GPIOSEL, 0/*0x00000173*/}, /* # SYS.GPIOSEL # GPIO port multiplexing control */
+ { GPIOPC, 0x03C300C0 }, /* # GPI .GPIOPC # GPIO2,3 PD cut */
+ { WKREQ, 0x00000000 }, /* # SYS.WKREQ # Wake-up request event is VSYNC alignment */
+
+ { GPIOIBE, 0x000003FF },
+ { GPIOIS, 0x00000000 },
+ { GPIOIC, 0x000003FF },
+ { GPIOIE, 0x00000000 },
+
+ { GPIODATA, 0x00040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
+ { 1, 1 }, /* msleep 1 */
+ { GPIODATA, 0x02040004 }, /* # GPI .GPIODATA # eDRAM VD supply */
+ { DRAMPWR, 0x00000001 }, /* eDRAM power */
+};
+
+static struct mddi_table mddi_toshiba_panel_init_table[] = {
+ { SRST, 0x00000003 }, /* FIFO/LCDC not reset */
+ { PORT_ENB, 0x00000001 }, /* Enable sync. Port */
+ { START, 0x00000000 }, /* To stop operation */
+ //{ START, 0x00000001 }, /* To start operation */
+ { PORT, 0x00000004 }, /* Polarity of VS/HS/DE. */
+ { CMN, 0x00000000 },
+ { GAMMA, 0x00000000 }, /* No Gamma correction */
+ { INTFLG, 0x00000000 }, /* VSYNC interrupt flag clear/status */
+ { INTMSK, 0x00000000 }, /* VSYNC interrupt mask is off. */
+ { MPLFBUF, 0x00000000 }, /* Select frame buffer's base address. */
+ { HDE_LEFT, 0x00000000 }, /* The value of HDE_LEFT. */
+ { VDE_TOP, 0x00000000 }, /* The value of VDE_TPO. */
+ { PXL, 0x00000001 }, /* 1. RGB666 */
+ /* 2. Data is valid from 1st frame of beginning. */
+ { HDE_START, 0x00000006 }, /* HDE_START= 14 PCLK */
+ { HDE_SIZE, 0x0000009F }, /* HDE_SIZE=320 PCLK */
+ { HSW, 0x00000004 }, /* HSW= 10 PCLK */
+ { VSW, 0x00000001 }, /* VSW=2 HCYCLE */
+ { VDE_START, 0x00000003 }, /* VDE_START=4 HCYCLE */
+ { VDE_SIZE, 0x000001DF }, /* VDE_SIZE=480 HCYCLE */
+ { WAKEUP, 0x000001e2 }, /* Wakeup position in VSYNC mode. */
+ { WSYN_DLY, 0x00000000 }, /* Wakeup position in VSIN mode. */
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { CLKENB, 0x000025CB }, /* Clock enable register */
+
+ { SSICTL, 0x00000170 }, /* SSI control register */
+ { SSITIME, 0x00000250 }, /* SSI timing control register */
+ { SSICTL, 0x00000172 }, /* SSI control register */
+};
+
+
+static struct mddi_table mddi_sharp_init_table[] = {
+ { VCYCLE, 0x000001eb },
+ { HCYCLE, 0x000000ae },
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { 1, 1 }, /* msleep 1 */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { 1, 10 }, /* msleep 10 */
+ SPI_WRITE(0x5f, 0x01)
+ SPI_WRITE1(0x11)
+ { 1, 200 }, /* msleep 200 */
+ SPI_WRITE1(0x29)
+ SPI_WRITE1(0xde)
+ { START, 0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_sharp_deinit_table[] = {
+ { 1, 200 }, /* msleep 200 */
+ SPI_WRITE(0x10, 0x1)
+ { 1, 100 }, /* msleep 100 */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { 1, 10 }, /* msleep 10 */
+};
+
+static struct mddi_table mddi_tpo_init_table[] = {
+ { VCYCLE, 0x000001e5 },
+ { HCYCLE, 0x000000ac },
+ { REGENB, 0x00000001 }, /* Set 1 to enable to change the value of registers. */
+ { 0, 20 }, /* udelay 20 */
+ { GPIODATA, 0x00000004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { 0, 20 }, /* udelay 20 */
+
+ SPI_WRITE(0x08, 0x01)
+ { 0, 500 }, /* udelay 500 */
+ SPI_WRITE(0x08, 0x00)
+ SPI_WRITE(0x02, 0x00)
+ SPI_WRITE(0x03, 0x04)
+ SPI_WRITE(0x04, 0x0e)
+ SPI_WRITE(0x09, 0x02)
+ SPI_WRITE(0x0b, 0x08)
+ SPI_WRITE(0x0c, 0x53)
+ SPI_WRITE(0x0d, 0x01)
+ SPI_WRITE(0x0e, 0xe0)
+ SPI_WRITE(0x0f, 0x01)
+ SPI_WRITE(0x10, 0x58)
+ SPI_WRITE(0x20, 0x1e)
+ SPI_WRITE(0x21, 0x0a)
+ SPI_WRITE(0x22, 0x0a)
+ SPI_WRITE(0x23, 0x1e)
+ SPI_WRITE(0x25, 0x32)
+ SPI_WRITE(0x26, 0x00)
+ SPI_WRITE(0x27, 0xac)
+ SPI_WRITE(0x29, 0x06)
+ SPI_WRITE(0x2a, 0xa4)
+ SPI_WRITE(0x2b, 0x45)
+ SPI_WRITE(0x2c, 0x45)
+ SPI_WRITE(0x2d, 0x15)
+ SPI_WRITE(0x2e, 0x5a)
+ SPI_WRITE(0x2f, 0xff)
+ SPI_WRITE(0x30, 0x6b)
+ SPI_WRITE(0x31, 0x0d)
+ SPI_WRITE(0x32, 0x48)
+ SPI_WRITE(0x33, 0x82)
+ SPI_WRITE(0x34, 0xbd)
+ SPI_WRITE(0x35, 0xe7)
+ SPI_WRITE(0x36, 0x18)
+ SPI_WRITE(0x37, 0x94)
+ SPI_WRITE(0x38, 0x01)
+ SPI_WRITE(0x39, 0x5d)
+ SPI_WRITE(0x3a, 0xae)
+ SPI_WRITE(0x3b, 0xff)
+ SPI_WRITE(0x07, 0x09)
+ { 0, 10 }, /* udelay 10 */
+ { START, 0x00000001 }, /* To start operation */
+};
+
+static struct mddi_table mddi_tpo_deinit_table[] = {
+ SPI_WRITE(0x07, 0x19)
+ { START, 0x00000000 }, /* To stop operation */
+ { GPIODATA, 0x00040004 }, /* GPIO2 high */
+ { GPIODIR, 0x00000004 }, /* GPIO2 out */
+ { GPIODATA, 0x00040000 }, /* GPIO2 low */
+ { 0, 5 }, /* usleep 5 */
+};
+
+
+#define GPIOSEL_VWAKEINT (1U << 0)
+#define INTMASK_VWAKEOUT (1U << 0)
+
+static void trout_process_mddi_table(struct msm_mddi_client_data *cdata,
+ struct mddi_table *table, size_t count)
+{
+ int i;
+ for(i = 0; i < count; i++) {
+ uint32_t reg = table[i].reg;
+ uint32_t value = table[i].value;
+
+ if (reg == 0)
+ udelay(value);
+ else if (reg == 1)
+ msleep(value);
+ else
+ cdata->remote_write(cdata, value, reg);
+ }
+}
+
+static struct vreg *vreg_mddi_1v5;
+static struct vreg *vreg_lcm_2v85;
+
+static void trout_mddi_power_client(struct msm_mddi_client_data *cdata,
+ int on)
+{
+ unsigned id, on_off;
+ if(on) {
+ on_off = 0;
+ id = PM_VREG_PDOWN_MDDI_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ vreg_enable(vreg_mddi_1v5);
+ mdelay(5); // delay time >5ms and <10ms
+ gpio_set_value(V_VDDE2E_VDD2_GPIO, 1);
+ gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 1);
+ msleep(3);
+ id = PM_VREG_PDOWN_AUX_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ vreg_enable(vreg_lcm_2v85);
+ msleep(3);
+ gpio_set_value(MDDI_RST_N, 1);
+ msleep(10);
+ } else {
+ gpio_set_value(TROUT_GPIO_MDDI_32K_EN, 0);
+ gpio_set_value(MDDI_RST_N, 0);
+ msleep(10);
+ vreg_disable(vreg_lcm_2v85);
+ on_off = 1;
+ id = PM_VREG_PDOWN_AUX_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ msleep(5);
+ gpio_set_value(V_VDDE2E_VDD2_GPIO, 0);
+ msleep(200);
+ vreg_disable(vreg_mddi_1v5);
+ id = PM_VREG_PDOWN_MDDI_ID;
+ msm_proc_comm(PCOM_VREG_PULLDOWN, &on_off, &id);
+ }
+}
+
+static int trout_mddi_toshiba_client_init(struct msm_mddi_client_data *cdata)
+{
+ int panel_id;
+
+ cdata->auto_hibernate(cdata, 0);
+ trout_process_mddi_table(cdata, mddi_toshiba_init_table,
+ ARRAY_SIZE(mddi_toshiba_init_table));
+ cdata->auto_hibernate(cdata, 1);
+ panel_id = (cdata->remote_read(cdata, GPIODATA) >> 4) & 3;
+ if (panel_id > 1) {
+ printk("unknown panel id at mddi_enable\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int trout_mddi_toshiba_client_uninit(struct msm_mddi_client_data *cdata)
+{
+ return 0;
+}
+
+static int trout_mddi_panel_unblank(struct msm_panel_data *panel_data)
+{
+ struct msm_mddi_panel_info *panel = container_of(panel_data,
+ struct msm_mddi_panel_info, panel_data);
+ struct msm_mddi_client_data *mddi_client = panel->client_data;
+
+ int panel_id, ret = 0;
+
+ trout_set_backlight_level(0);
+ mddi_client->auto_hibernate(mddi_client, 0);
+ trout_process_mddi_table(mddi_client, mddi_toshiba_panel_init_table,
+ ARRAY_SIZE(mddi_toshiba_panel_init_table));
+ panel_id = (mddi_client->remote_read(mddi_client, GPIODATA) >> 4) & 3;
+ switch(panel_id) {
+ case 0:
+ printk("init sharp panel\n");
+ trout_process_mddi_table(mddi_client,
+ mddi_sharp_init_table,
+ ARRAY_SIZE(mddi_sharp_init_table));
+ break;
+ case 1:
+ printk("init tpo panel\n");
+ trout_process_mddi_table(mddi_client,
+ mddi_tpo_init_table,
+ ARRAY_SIZE(mddi_tpo_init_table));
+ break;
+ default:
+ printk("unknown panel_id: %d\n", panel_id);
+ ret = -1;
+ };
+ mutex_lock(&trout_backlight_lock);
+ trout_set_backlight_level(trout_backlight_brightness);
+ trout_backlight_off = 0;
+ mutex_unlock(&trout_backlight_lock);
+ mddi_client->auto_hibernate(mddi_client, 1);
+ // reenable vsync
+ mddi_client->remote_write(mddi_client, GPIOSEL_VWAKEINT,
+ GPIOSEL);
+ mddi_client->remote_write(mddi_client, INTMASK_VWAKEOUT,
+ INTMASK);
+ return ret;
+
+}
+
+static int trout_mddi_panel_blank(struct msm_panel_data *panel_data)
+{
+ struct msm_mddi_panel_info *panel = container_of(panel_data,
+ struct msm_mddi_panel_info, panel_data);
+ struct msm_mddi_client_data *mddi_client = panel->client_data;
+ int panel_id, ret = 0;
+
+ panel_id = (mddi_client->remote_read(mddi_client, GPIODATA) >> 4) & 3;
+ mddi_client->auto_hibernate(mddi_client, 0);
+ switch(panel_id) {
+ case 0:
+ printk("deinit sharp panel\n");
+ trout_process_mddi_table(mddi_client,
+ mddi_sharp_deinit_table,
+ ARRAY_SIZE(mddi_sharp_deinit_table));
+ break;
+ case 1:
+ printk("deinit tpo panel\n");
+ trout_process_mddi_table(mddi_client,
+ mddi_tpo_deinit_table,
+ ARRAY_SIZE(mddi_tpo_deinit_table));
+ break;
+ default:
+ printk("unknown panel_id: %d\n", panel_id);
+ ret = -1;
+ };
+ mddi_client->auto_hibernate(mddi_client,1);
+ mutex_lock(&trout_backlight_lock);
+ trout_set_backlight_level(0);
+ trout_backlight_off = 1;
+ mutex_unlock(&trout_backlight_lock);
+ mddi_client->remote_write(mddi_client, 0, SYSCLKENA);
+ mddi_client->remote_write(mddi_client, 1, DPSUS);
+
+ return ret;
+}
+
+static void trout_brightness_set(struct led_classdev *led_cdev, enum led_brightness value)
+{
+ mutex_lock(&trout_backlight_lock);
+ trout_backlight_brightness = value;
+ if(!trout_backlight_off)
+ trout_set_backlight_level(trout_backlight_brightness);
+ mutex_unlock(&trout_backlight_lock);
+}
+
+static struct led_classdev trout_backlight_led = {
+ .name = "lcd-backlight",
+ .brightness = TROUT_DEFAULT_BACKLIGHT_BRIGHTNESS,
+ .brightness_set = trout_brightness_set,
+};
+
+static int trout_backlight_probe(struct platform_device *pdev)
+{
+ led_classdev_register(&pdev->dev, &trout_backlight_led);
+ return 0;
+}
+
+static int trout_backlight_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&trout_backlight_led);
+ return 0;
+}
+
+static struct platform_driver trout_backlight_driver = {
+ .probe = trout_backlight_probe,
+ .remove = trout_backlight_remove,
+ .driver = {
+ .name = "trout-backlight",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct resource resources_msm_fb[] = {
+ {
+ .start = MSM_FB_BASE,
+ .end = MSM_FB_BASE + MSM_FB_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct msm_mddi_toshiba_client_data toshiba_client_data = {
+ .init = trout_mddi_toshiba_client_init,
+ .uninit = trout_mddi_toshiba_client_uninit,
+ .blank = trout_mddi_panel_blank,
+ .unblank = trout_mddi_panel_unblank,
+ .fb_data = {
+ .xres = 320,
+ .yres = 480,
+ .width = 45,
+ .height = 67,
+ .output_format = 0,
+ },
+};
+
+struct msm_mddi_platform_data mddi_pdata = {
+ .clk_rate = 122880000,
+ .power_client = trout_mddi_power_client,
+ .fb_resource = resources_msm_fb,
+ .num_clients = 1,
+ .client_platform_data = {
+ {
+ .product_id = (0xd263 << 16 | 0),
+ .name = "mddi_c_d263_0000",
+ .id = 0,
+ .client_data = &toshiba_client_data,
+ .clk_rate = 0,
+ },
+ },
+};
+
+static struct platform_device trout_backlight = {
+ .name = "trout-backlight",
+};
+
+int __init trout_init_panel(void)
+{
+ int rc;
+
+ if (!machine_is_trout())
+ return 0;
+ vreg_mddi_1v5 = vreg_get(0, "gp2");
+ if (IS_ERR(vreg_mddi_1v5))
+ return PTR_ERR(vreg_mddi_1v5);
+ vreg_lcm_2v85 = vreg_get(0, "gp4");
+ if (IS_ERR(vreg_lcm_2v85))
+ return PTR_ERR(vreg_lcm_2v85);
+
+ trout_new_backlight = system_rev >= 5;
+ if (trout_new_backlight) {
+ uint32_t config = PCOM_GPIO_CFG(27, 0, GPIO_OUTPUT,
+ GPIO_NO_PULL, GPIO_8MA);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+ }
+ else {
+ uint32_t config = PCOM_GPIO_CFG(27, 1, GPIO_OUTPUT,
+ GPIO_NO_PULL, GPIO_8MA);
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, 0);
+
+ gp_clk = clk_get(NULL, "gp_clk");
+ if (IS_ERR(gp_clk)) {
+ printk(KERN_ERR "trout_init_panel: could not get gp"
+ "clock\n");
+ gp_clk = NULL;
+ }
+ rc = clk_set_rate(gp_clk, 19200000);
+ if (rc)
+ printk(KERN_ERR "trout_init_panel: set clock rate "
+ "failed\n");
+ }
+
+ rc = platform_device_register(&msm_device_mdp);
+ if (rc)
+ return rc;
+ msm_device_mddi0.dev.platform_data = &mddi_pdata;
+ rc = platform_device_register(&msm_device_mddi0);
+ if (rc)
+ return rc;
+ platform_device_register(&trout_backlight);
+ return platform_driver_register(&trout_backlight_driver);
+}
+
+device_initcall(trout_init_panel);
diff --git a/arch/arm/mach-msm/board-trout-rfkill.c b/arch/arm/mach-msm/board-trout-rfkill.c
new file mode 100644
index 000000000000..5212431dda82
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-rfkill.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Nick Pelly <npelly@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.
+ *
+ */
+
+/* Control bluetooth power for trout platform */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+
+#include "board-trout.h"
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+
+static struct rfkill *bt_rfk;
+static const char bt_name[] = "brf6300";
+
+static int bluetooth_set_power(void *data, enum rfkill_state state)
+{
+ switch (state) {
+ case RFKILL_STATE_UNBLOCKED:
+ gpio_set_value(TROUT_GPIO_BT_32K_EN, 1);
+ udelay(10);
+ gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
+ break;
+ case RFKILL_STATE_SOFT_BLOCKED:
+ gpio_configure(101, GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
+ gpio_set_value(TROUT_GPIO_BT_32K_EN, 0);
+ break;
+ default:
+ printk(KERN_ERR "bad bluetooth rfkill state %d\n", state);
+ }
+ return 0;
+}
+
+static int __init trout_rfkill_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ /* default to bluetooth off */
+ rfkill_switch_all(RFKILL_TYPE_BLUETOOTH, RFKILL_STATE_SOFT_BLOCKED);
+ bluetooth_set_power(NULL, RFKILL_STATE_SOFT_BLOCKED);
+
+ bt_rfk = rfkill_allocate(&pdev->dev, RFKILL_TYPE_BLUETOOTH);
+ if (!bt_rfk)
+ return -ENOMEM;
+
+ bt_rfk->name = bt_name;
+ bt_rfk->state = RFKILL_STATE_SOFT_BLOCKED;
+ /* userspace cannot take exclusive control */
+ bt_rfk->user_claim_unsupported = 1;
+ bt_rfk->user_claim = 0;
+ bt_rfk->data = NULL; // user data
+ bt_rfk->toggle_radio = bluetooth_set_power;
+
+ rc = rfkill_register(bt_rfk);
+
+ if (rc)
+ rfkill_free(bt_rfk);
+ return rc;
+}
+
+static struct platform_driver trout_rfkill_driver = {
+ .probe = trout_rfkill_probe,
+ .driver = {
+ .name = "trout_rfkill",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init trout_rfkill_init(void)
+{
+ return platform_driver_register(&trout_rfkill_driver);
+}
+
+module_init(trout_rfkill_init);
+MODULE_DESCRIPTION("trout rfkill");
+MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/board-trout-wifi.c b/arch/arm/mach-msm/board-trout-wifi.c
new file mode 100644
index 000000000000..51b26a405369
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-wifi.c
@@ -0,0 +1,74 @@
+/* arch/arm/mach-msm/board-trout-wifi.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@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.
+ *
+ */
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/wifi_tiwlan.h>
+
+extern int trout_wifi_set_carddetect(int val);
+extern int trout_wifi_power(int on);
+extern int trout_wifi_reset(int on);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+typedef struct wifi_mem_prealloc_struct {
+ void *mem_ptr;
+ unsigned long size;
+} wifi_mem_prealloc_t;
+
+static wifi_mem_prealloc_t wifi_mem_array[WMPA_NUMBER_OF_SECTIONS] = {
+ { NULL, (WMPA_SECTION_SIZE_0 + WMPA_SECTION_HEADER) },
+ { NULL, (WMPA_SECTION_SIZE_1 + WMPA_SECTION_HEADER) },
+ { NULL, (WMPA_SECTION_SIZE_2 + WMPA_SECTION_HEADER) }
+};
+
+static void *trout_wifi_mem_prealloc(int section, unsigned long size)
+{
+ if( (section < 0) || (section >= WMPA_NUMBER_OF_SECTIONS) )
+ return NULL;
+ if( wifi_mem_array[section].size < size )
+ return NULL;
+ return wifi_mem_array[section].mem_ptr;
+}
+
+int __init trout_init_wifi_mem( void )
+{
+ int i;
+
+ for(i=0;( i < WMPA_NUMBER_OF_SECTIONS );i++) {
+ wifi_mem_array[i].mem_ptr = vmalloc(wifi_mem_array[i].size);
+ if( wifi_mem_array[i].mem_ptr == NULL )
+ return -ENOMEM;
+ }
+ return 0;
+}
+#endif
+
+struct wifi_platform_data trout_wifi_control = {
+ .set_power = trout_wifi_power,
+ .set_reset = trout_wifi_reset,
+ .set_carddetect = trout_wifi_set_carddetect,
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+ .mem_prealloc = trout_wifi_mem_prealloc,
+#else
+ .mem_prealloc = NULL,
+#endif
+};
+
+#endif
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
new file mode 100644
index 000000000000..637253ec3f78
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout.c
@@ -0,0 +1,841 @@
+/* arch/arm/mach-msm/board-trout.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/keyreset.h>
+#include <linux/leds.h>
+#include <linux/switch.h>
+#include <linux/../../../drivers/staging/android/timed_gpio.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/akm8976.h>
+#include <linux/sysdev.h>
+#include <linux/android_pmem.h>
+
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+#include <asm/system.h>
+#include <mach/system.h>
+#include <mach/vreg.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/setup.h>
+
+#include <linux/gpio_event.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/mmc.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/msm_audio.h>
+
+#include "board-trout.h"
+
+#include "gpio_chip.h"
+#include "pm.h"
+
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_serial_hs.h>
+#include <mach/htc_pwrsink.h>
+#ifdef CONFIG_HTC_HEADSET
+#include <mach/htc_headset.h>
+#endif
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#include <linux/wifi_tiwlan.h>
+#endif
+
+#include "proc_comm.h"
+#include "devices.h"
+
+void msm_init_irq(void);
+void msm_init_gpio(void);
+
+extern int trout_init_mmc(unsigned int);
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+extern int trout_init_wifi_mem(void);
+#endif
+extern struct wifi_platform_data trout_wifi_control;
+#endif
+
+struct trout_axis_info {
+ struct gpio_event_axis_info info;
+ uint16_t in_state;
+ uint16_t out_state;
+};
+static bool nav_just_on;
+static int nav_on_jiffies;
+
+uint16_t trout_axis_map(struct gpio_event_axis_info *info, uint16_t in)
+{
+ struct trout_axis_info *ai = container_of(info, struct trout_axis_info, info);
+ uint16_t out = ai->out_state;
+
+ if (nav_just_on) {
+ if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1)
+ goto ignore;
+ nav_just_on = 0;
+ }
+ if((ai->in_state ^ in) & 1)
+ out--;
+ if((ai->in_state ^ in) & 2)
+ out++;
+ ai->out_state = out;
+ignore:
+ ai->in_state = in;
+ return out;
+}
+
+int trout_nav_power(const struct gpio_event_platform_data *pdata, bool on)
+{
+ gpio_set_value(TROUT_GPIO_JOG_EN, on);
+ if (on) {
+ nav_just_on = 1;
+ nav_on_jiffies = jiffies;
+ }
+ return 0;
+}
+
+static uint32_t trout_4_x_axis_gpios[] = {
+ TROUT_4_BALL_LEFT_0, TROUT_4_BALL_RIGHT_0
+};
+static uint32_t trout_5_x_axis_gpios[] = {
+ TROUT_5_BALL_LEFT_0, TROUT_5_BALL_RIGHT_0
+};
+
+static struct trout_axis_info trout_x_axis = {
+ .info = {
+ .info.func = gpio_event_axis_func,
+ .count = ARRAY_SIZE(trout_5_x_axis_gpios),
+ .type = EV_REL,
+ .code = REL_X,
+ .decoded_size = 1U << ARRAY_SIZE(trout_5_x_axis_gpios),
+ .map = trout_axis_map,
+ .gpio = trout_5_x_axis_gpios,
+ .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+ }
+};
+
+static uint32_t trout_4_y_axis_gpios[] = {
+ TROUT_4_BALL_UP_0, TROUT_4_BALL_DOWN_0
+};
+static uint32_t trout_5_y_axis_gpios[] = {
+ TROUT_5_BALL_UP_0, TROUT_5_BALL_DOWN_0
+};
+
+static struct trout_axis_info trout_y_axis = {
+ .info = {
+ .info.func = gpio_event_axis_func,
+ .count = ARRAY_SIZE(trout_5_y_axis_gpios),
+ .type = EV_REL,
+ .code = REL_Y,
+ .decoded_size = 1U << ARRAY_SIZE(trout_5_y_axis_gpios),
+ .map = trout_axis_map,
+ .gpio = trout_5_y_axis_gpios,
+ .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */
+ }
+};
+
+static struct gpio_event_direct_entry trout_nav_buttons[] = {
+ { TROUT_GPIO_NAVI_ACT_N, BTN_MOUSE }
+};
+
+static struct gpio_event_input_info trout_nav_button_info = {
+ .info.func = gpio_event_input_func,
+ .flags = 0,
+ .type = EV_KEY,
+ .keymap = trout_nav_buttons,
+ .keymap_size = ARRAY_SIZE(trout_nav_buttons)
+};
+
+static struct gpio_event_info *trout_nav_info[] = {
+ &trout_x_axis.info.info,
+ &trout_y_axis.info.info,
+ &trout_nav_button_info.info
+};
+
+static struct gpio_event_platform_data trout_nav_data = {
+ .name = "trout-nav",
+ .info = trout_nav_info,
+ .info_count = ARRAY_SIZE(trout_nav_info),
+ .power = trout_nav_power,
+};
+
+static struct platform_device trout_nav_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 2,
+ .dev = {
+ .platform_data = &trout_nav_data,
+ },
+};
+
+static int trout_reset_keys_up[] = {
+ BTN_MOUSE,
+ 0
+};
+
+static struct keyreset_platform_data trout_reset_keys_pdata = {
+ .keys_up = trout_reset_keys_up,
+ .keys_down = {
+ KEY_SEND,
+ KEY_MENU,
+ KEY_END,
+ 0
+ },
+};
+
+struct platform_device trout_reset_keys_device = {
+ .name = KEYRESET_NAME,
+ .dev.platform_data = &trout_reset_keys_pdata,
+};
+
+static int trout_ts_power(int on)
+{
+ int tp_ls_gpio = system_rev < 5 ? TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN;
+ if (on) {
+ gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 1);
+ gpio_set_value(TROUT_GPIO_TP_EN, 1);
+ /* touchscreen must be powered before we enable i2c pullup */
+ msleep(2);
+ /* enable touch panel level shift */
+ gpio_set_value(tp_ls_gpio, 1);
+ msleep(2);
+ }
+ else {
+ gpio_set_value(tp_ls_gpio, 0);
+ udelay(50);
+ gpio_set_value(TROUT_GPIO_TP_EN, 0);
+ gpio_set_value(TROUT_GPIO_TP_I2C_PULL, 0);
+ }
+ return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data trout_ts_data[] = {
+ {
+ .version = 0x010c,
+ .power = trout_ts_power,
+ .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+ .inactive_left = -100 * 0x10000 / 4334,
+ .inactive_right = -100 * 0x10000 / 4334,
+ .inactive_top = -40 * 0x10000 / 6696,
+ .inactive_bottom = -40 * 0x10000 / 6696,
+ .snap_left_on = 300 * 0x10000 / 4334,
+ .snap_left_off = 310 * 0x10000 / 4334,
+ .snap_right_on = 300 * 0x10000 / 4334,
+ .snap_right_off = 310 * 0x10000 / 4334,
+ .snap_top_on = 100 * 0x10000 / 6696,
+ .snap_top_off = 110 * 0x10000 / 6696,
+ .snap_bottom_on = 100 * 0x10000 / 6696,
+ .snap_bottom_off = 110 * 0x10000 / 6696,
+ },
+ {
+ .flags = SYNAPTICS_FLIP_Y | SYNAPTICS_SNAP_TO_INACTIVE_EDGE,
+ .inactive_left = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+ .inactive_right = ((4674 - 4334) / 2 + 200) * 0x10000 / 4334,
+ .inactive_top = ((6946 - 6696) / 2) * 0x10000 / 6696,
+ .inactive_bottom = ((6946 - 6696) / 2) * 0x10000 / 6696,
+ }
+};
+
+static struct akm8976_platform_data compass_platform_data = {
+ .reset = TROUT_GPIO_COMPASS_RST_N,
+ .clk_on = TROUT_GPIO_COMPASS_32K_EN,
+ .intr = TROUT_GPIO_COMPASS_IRQ,
+};
+
+static struct i2c_board_info i2c_devices[] = {
+ {
+ I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME, 0x20),
+ .platform_data = trout_ts_data,
+ .irq = TROUT_GPIO_TO_INT(TROUT_GPIO_TP_ATT_N)
+ },
+ {
+ I2C_BOARD_INFO("akm8976", 0x1C),
+ .platform_data = &compass_platform_data,
+ .irq = TROUT_GPIO_TO_INT(TROUT_GPIO_COMPASS_IRQ),
+ },
+ {
+ I2C_BOARD_INFO("pca963x", 0x62),
+ },
+};
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem",
+ .start = MSM_PMEM_MDP_BASE,
+ .size = MSM_PMEM_MDP_SIZE,
+ .no_allocator = 1,
+ .cached = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_adsp_pdata = {
+ .name = "pmem_adsp",
+ .start = MSM_PMEM_ADSP_BASE,
+ .size = MSM_PMEM_ADSP_SIZE,
+ .no_allocator = 0,
+ .cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_camera_pdata = {
+ .name = "pmem_camera",
+ .start = MSM_PMEM_CAMERA_BASE,
+ .size = MSM_PMEM_CAMERA_SIZE,
+ .no_allocator = 0,
+ .cached = 0,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu0_pdata = {
+ .name = "pmem_gpu0",
+ .start = MSM_PMEM_GPU0_BASE,
+ .size = MSM_PMEM_GPU0_SIZE,
+ .no_allocator = 1,
+ .cached = 0,
+ .buffered = 1,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu1_pdata = {
+ .name = "pmem_gpu1",
+ .start = MSM_PMEM_GPU1_BASE,
+ .size = MSM_PMEM_GPU1_SIZE,
+ .no_allocator = 1,
+ .cached = 0,
+ .buffered = 1,
+};
+
+static struct platform_device android_pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+ .dev = { .platform_data = &android_pmem_pdata },
+};
+
+static struct platform_device android_pmem_adsp_device = {
+ .name = "android_pmem",
+ .id = 1,
+ .dev = { .platform_data = &android_pmem_adsp_pdata },
+};
+
+static struct platform_device android_pmem_gpu0_device = {
+ .name = "android_pmem",
+ .id = 2,
+ .dev = { .platform_data = &android_pmem_gpu0_pdata },
+};
+
+static struct platform_device android_pmem_gpu1_device = {
+ .name = "android_pmem",
+ .id = 3,
+ .dev = { .platform_data = &android_pmem_gpu1_pdata },
+};
+
+static struct platform_device android_pmem_camera_device = {
+ .name = "android_pmem",
+ .id = 4,
+ .dev = { .platform_data = &android_pmem_camera_pdata },
+};
+
+static struct timed_gpio timed_gpios[] = {
+ {
+ .name = "vibrator",
+ .gpio = TROUT_GPIO_HAPTIC_PWM,
+ .max_timeout = 15000,
+ },
+ {
+ .name = "flash",
+ .gpio = TROUT_GPIO_FLASH_EN,
+ .max_timeout = 400,
+ },
+};
+
+static struct timed_gpio_platform_data timed_gpio_data = {
+ .num_gpios = ARRAY_SIZE(timed_gpios),
+ .gpios = timed_gpios,
+};
+
+static struct platform_device android_timed_gpios = {
+ .name = "timed-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &timed_gpio_data,
+ },
+};
+
+static struct gpio_led android_led_list[] = {
+ {
+ .name = "spotlight",
+ .gpio = TROUT_GPIO_SPOTLIGHT_EN,
+ },
+ {
+ .name = "keyboard-backlight",
+ .gpio = TROUT_GPIO_QTKEY_LED_EN,
+ },
+ {
+ .name = "button-backlight",
+ .gpio = TROUT_GPIO_UI_LED_EN,
+ },
+};
+
+static struct gpio_led_platform_data android_leds_data = {
+ .num_leds = ARRAY_SIZE(android_led_list),
+ .leds = android_led_list,
+};
+
+static struct platform_device android_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_leds_data,
+ },
+};
+
+static struct gpio_switch_platform_data sd_door_switch_data = {
+ .name = "sd-door",
+ .gpio = TROUT_GPIO_SD_DOOR_N,
+ .state_on = "open",
+ .state_off = "closed",
+};
+
+static struct platform_device sd_door_switch = {
+ .name = "switch-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &sd_door_switch_data,
+ },
+};
+
+#ifdef CONFIG_HTC_HEADSET
+static void h2w_config_cpld(int route)
+{
+ switch (route) {
+ case H2W_UART3:
+ gpio_set_value(TROUT_GPIO_H2W_SEL0, 0);
+ gpio_set_value(TROUT_GPIO_H2W_SEL1, 1);
+ break;
+ case H2W_GPIO:
+ gpio_set_value(TROUT_GPIO_H2W_SEL0, 0);
+ gpio_set_value(TROUT_GPIO_H2W_SEL1, 0);
+ break;
+ }
+}
+
+static void h2w_init_cpld(void)
+{
+ h2w_config_cpld(H2W_UART3);
+ gpio_set_value(TROUT_GPIO_H2W_CLK_DIR, 0);
+ gpio_set_value(TROUT_GPIO_H2W_DAT_DIR, 0);
+}
+
+static struct h2w_platform_data trout_h2w_data = {
+ .cable_in1 = TROUT_GPIO_CABLE_IN1,
+ .cable_in2 = TROUT_GPIO_CABLE_IN2,
+ .h2w_clk = TROUT_GPIO_H2W_CLK_GPI,
+ .h2w_data = TROUT_GPIO_H2W_DAT_GPI,
+ .debug_uart = H2W_UART3,
+ .config_cpld = h2w_config_cpld,
+ .init_cpld = h2w_init_cpld,
+};
+
+static struct platform_device trout_h2w = {
+ .name = "h2w",
+ .id = -1,
+ .dev = {
+ .platform_data = &trout_h2w_data,
+ },
+};
+#endif
+
+static void trout_phy_reset(void)
+{
+ gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 0);
+ mdelay(10);
+ gpio_set_value(TROUT_GPIO_USB_PHY_RST_N, 1);
+ mdelay(10);
+}
+
+static struct resource trout_ram_console_resource[] = {
+ {
+ .start = MSM_RAM_CONSOLE_BASE,
+ .end = MSM_RAM_CONSOLE_BASE + MSM_RAM_CONSOLE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device trout_ram_console_device = {
+ .name = "ram_console",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(trout_ram_console_resource),
+ .resource = trout_ram_console_resource,
+};
+
+static struct pwr_sink trout_pwrsink_table[] = {
+ {
+ .id = PWRSINK_AUDIO,
+ .ua_max = 90000,
+ },
+ {
+ .id = PWRSINK_BACKLIGHT,
+ .ua_max = 128000,
+ },
+ {
+ .id = PWRSINK_LED_BUTTON,
+ .ua_max = 17000,
+ },
+ {
+ .id = PWRSINK_LED_KEYBOARD,
+ .ua_max = 22000,
+ },
+ {
+ .id = PWRSINK_GP_CLK,
+ .ua_max = 30000,
+ },
+ {
+ .id = PWRSINK_BLUETOOTH,
+ .ua_max = 15000,
+ },
+ {
+ .id = PWRSINK_CAMERA,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_SDCARD,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_VIDEO,
+ .ua_max = 0,
+ },
+ {
+ .id = PWRSINK_WIFI,
+ .ua_max = 200000,
+ },
+ {
+ .id = PWRSINK_SYSTEM_LOAD,
+ .ua_max = 63000,
+ .percent_util = 100,
+ },
+};
+
+static struct pwr_sink_platform_data trout_pwrsink_data = {
+ .num_sinks = ARRAY_SIZE(trout_pwrsink_table),
+ .sinks = trout_pwrsink_table,
+ .suspend_late = NULL,
+ .resume_early = NULL,
+ .suspend_early = NULL,
+ .resume_late = NULL,
+};
+
+static struct platform_device trout_pwr_sink = {
+ .name = "htc_pwrsink",
+ .id = -1,
+ .dev = {
+ .platform_data = &trout_pwrsink_data,
+ },
+};
+
+static struct platform_device trout_rfkill = {
+ .name = "trout_rfkill",
+ .id = -1,
+};
+
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+static struct platform_device trout_wifi = {
+ .name = "msm_wifi",
+ .id = 1,
+ .num_resources = 0,
+ .resource = NULL,
+ .dev = {
+ .platform_data = &trout_wifi_control,
+ },
+};
+#endif
+
+#define SND(num, desc) { .name = desc, .id = num }
+static struct snd_endpoint snd_endpoints_list[] = {
+ SND(0, "HANDSET"),
+ SND(1, "SPEAKER"),
+ SND(2, "HEADSET"),
+ SND(3, "BT"),
+ SND(44, "BT_EC_OFF"),
+ SND(10, "HEADSET_AND_SPEAKER"),
+ SND(256, "CURRENT"),
+
+ /* Bluetooth accessories. */
+
+ SND(12, "HTC BH S100"),
+ SND(13, "HTC BH M100"),
+ SND(14, "Motorola H500"),
+ SND(15, "Nokia HS-36W"),
+ SND(16, "PLT 510v.D"),
+ SND(17, "M2500 by Plantronics"),
+ SND(18, "Nokia HDW-3"),
+ SND(19, "HBH-608"),
+ SND(20, "HBH-DS970"),
+ SND(21, "i.Tech BlueBAND"),
+ SND(22, "Nokia BH-800"),
+ SND(23, "Motorola H700"),
+ SND(24, "HTC BH M200"),
+ SND(25, "Jabra JX10"),
+ SND(26, "320Plantronics"),
+ SND(27, "640Plantronics"),
+ SND(28, "Jabra BT500"),
+ SND(29, "Motorola HT820"),
+ SND(30, "HBH-IV840"),
+ SND(31, "6XXPlantronics"),
+ SND(32, "3XXPlantronics"),
+ SND(33, "HBH-PV710"),
+ SND(34, "Motorola H670"),
+ SND(35, "HBM-300"),
+ SND(36, "Nokia BH-208"),
+ SND(37, "Samsung WEP410"),
+ SND(38, "Jabra BT8010"),
+ SND(39, "Motorola S9"),
+ SND(40, "Jabra BT620s"),
+ SND(41, "Nokia BH-902"),
+ SND(42, "HBH-DS220"),
+ SND(43, "HBH-DS980"),
+};
+#undef SND
+
+static struct msm_snd_endpoints trout_snd_endpoints = {
+ .endpoints = snd_endpoints_list,
+ .num = ARRAY_SIZE(snd_endpoints_list),
+};
+
+static struct platform_device trout_snd = {
+ .name = "msm_snd",
+ .id = -1,
+ .dev = {
+ .platform_data = &trout_snd_endpoints,
+ },
+};
+
+static struct platform_device *devices[] __initdata = {
+ &msm_device_smd,
+ &msm_device_dmov,
+ &msm_device_nand,
+ &msm_device_i2c,
+ &msm_device_uart1,
+#if !defined(CONFIG_MSM_SERIAL_DEBUGGER) && !defined(CONFIG_TROUT_H2W)
+ &msm_device_uart3,
+#endif
+#ifdef CONFIG_SERIAL_MSM_HS
+ &msm_device_uart_dm1,
+#endif
+ &trout_nav_device,
+ &trout_reset_keys_device,
+ &android_leds,
+ &sd_door_switch,
+ &android_timed_gpios,
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+ &android_pmem_gpu0_device,
+ &android_pmem_gpu1_device,
+ &android_pmem_camera_device,
+ &trout_ram_console_device,
+ &trout_rfkill,
+#ifdef CONFIG_WIFI_CONTROL_FUNC
+ &trout_wifi,
+#endif
+#ifdef CONFIG_HTC_HEADSET
+ &trout_h2w,
+#endif
+#ifdef CONFIG_HTC_PWRSINK
+ &trout_pwr_sink,
+#endif
+ &trout_snd,
+};
+
+extern struct sys_timer msm_timer;
+
+static void __init trout_init_irq(void)
+{
+ printk("trout_init_irq()\n");
+ msm_init_irq();
+}
+
+static uint opt_disable_uart3;
+
+module_param_named(disable_uart3, opt_disable_uart3, uint, 0);
+
+static void trout_reset(void)
+{
+ gpio_set_value(TROUT_GPIO_PS_HOLD, 0);
+}
+
+static uint32_t gpio_table[] = {
+ /* BLUETOOTH */
+#ifdef CONFIG_SERIAL_MSM_HS
+ PCOM_GPIO_CFG(43, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+ PCOM_GPIO_CFG(44, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+ PCOM_GPIO_CFG(45, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+ PCOM_GPIO_CFG(46, 3, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#else
+ PCOM_GPIO_CFG(43, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RTS */
+ PCOM_GPIO_CFG(44, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* CTS */
+ PCOM_GPIO_CFG(45, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* RX */
+ PCOM_GPIO_CFG(46, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* TX */
+#endif
+};
+
+static void config_gpio_table(uint32_t *table, int len)
+{
+ int n;
+ unsigned id;
+ for(n = 0; n < len; n++) {
+ id = table[n];
+ msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+ }
+}
+
+static void __init config_gpios(void)
+{
+ config_gpio_table(gpio_table, ARRAY_SIZE(gpio_table));
+}
+
+void msm_serial_debug_init(unsigned int base, int irq,
+ struct device *clk_device, int signal_irq);
+
+static struct msm_acpu_clock_platform_data trout_clock_data = {
+ .acpu_switch_time_us = 20,
+ .max_speed_delta_khz = 256000,
+ .vdd_switch_time_us = 62,
+ .power_collapse_khz = 19200000,
+ .wait_for_irq_khz = 128000000,
+};
+
+#ifdef CONFIG_SERIAL_MSM_HS
+static struct msm_serial_hs_platform_data msm_uart_dm1_pdata = {
+ .wakeup_irq = MSM_GPIO_TO_INT(45),
+ .inject_rx_on_wakeup = 1,
+ .rx_to_inject = 0x32,
+};
+#endif
+
+static struct msm_pm_platform_data msm_pm_data[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE].latency = 16000,
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN].latency = 12000,
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency = 2000,
+};
+
+static void __init trout_init(void)
+{
+ int rc;
+
+ printk("trout_init() revision=%d\n", system_rev);
+
+ /*
+ * Setup common MSM GPIOS
+ */
+ config_gpios();
+
+ msm_hw_reset_hook = trout_reset;
+
+ gpio_direction_output(system_rev < 5 ?
+ TROUT_4_TP_LS_EN : TROUT_5_TP_LS_EN, 0);
+
+ msm_acpu_clock_init(&trout_clock_data);
+
+#if defined(CONFIG_MSM_SERIAL_DEBUGGER)
+ if (!opt_disable_uart3)
+ msm_serial_debug_init(MSM_UART3_PHYS, INT_UART3,
+ &msm_device_uart3.dev, 1);
+#endif
+
+ /* gpio_configure(108, IRQF_TRIGGER_LOW); */
+
+ /* put the AF VCM in powerdown mode to avoid noise */
+ gpio_set_value(TROUT_GPIO_VCM_PWDN, 1);
+ mdelay(100);
+
+ if (system_rev < 5) {
+ trout_x_axis.info.gpio = trout_4_x_axis_gpios;
+ trout_y_axis.info.gpio = trout_4_y_axis_gpios;
+ }
+
+#ifdef CONFIG_SERIAL_MSM_HS
+ msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+#endif
+ msm_add_usb_devices(trout_phy_reset);
+
+ rc = trout_init_mmc(system_rev);
+ if (rc)
+ printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+
+#ifdef CONFIG_WIFI_MEM_PREALLOC
+ rc = trout_init_wifi_mem();
+ if (rc)
+ printk(KERN_CRIT "%s: WiFi Memory init failure (%d)\n", __func__, rc);
+#endif
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
+ msm_pm_set_platform_data(msm_pm_data);
+
+ /* SD card door should wake the device */
+ set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SD_DOOR_N), 1);
+}
+
+static struct map_desc trout_io_desc[] __initdata = {
+ {
+ .virtual = TROUT_CPLD_BASE,
+ .pfn = __phys_to_pfn(TROUT_CPLD_START),
+ .length = TROUT_CPLD_SIZE,
+ .type = MT_DEVICE_NONSHARED
+ }
+};
+
+static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
+ char **cmdline, struct meminfo *mi)
+{
+ mi->nr_banks=1;
+ mi->bank[0].start = PHYS_OFFSET;
+ mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+ mi->bank[0].size = (101*1024*1024);
+}
+
+static void __init trout_map_io(void)
+{
+ msm_shared_ram_phys = 0x01F00000;
+
+ msm_map_common_io();
+ iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc));
+ msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a);
+}
+
+MACHINE_START(TROUT, "trout")
+/* Maintainer: Brian Swetland <swetland@google.com> */
+
+/* this is broken... can we just opt out of specifying something here? */
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0x80000000) >> 18) & 0xfffc,
+
+ .boot_params = 0x10000100,
+ .fixup = trout_fixup,
+ .map_io = trout_map_io,
+ .init_irq = trout_init_irq,
+ .init_machine = trout_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-trout.h b/arch/arm/mach-msm/board-trout.h
new file mode 100644
index 000000000000..308c4df90189
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout.h
@@ -0,0 +1,162 @@
+/* linux/arch/arm/mach-msm/board-trout.h
+** Author: Brian Swetland <swetland@google.com>
+*/
+#ifndef __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+#define __ARCH_ARM_MACH_MSM_BOARD_TROUT_H
+
+#include <mach/board.h>
+
+#define MSM_SMI_BASE 0x00000000
+#define MSM_SMI_SIZE 0x00800000
+
+#define MSM_EBI_BASE 0x10000000
+#define MSM_EBI_SIZE 0x06e00000
+
+#define MSM_PMEM_GPU0_BASE 0x00000000
+#define MSM_PMEM_GPU0_SIZE 0x00700000
+
+#define MSM_PMEM_MDP_BASE 0x02000000
+#define MSM_PMEM_MDP_SIZE 0x00800000
+
+#define MSM_PMEM_ADSP_BASE 0x02800000
+#define MSM_PMEM_ADSP_SIZE 0x00800000
+
+#define MSM_PMEM_CAMERA_BASE 0x03000000
+#define MSM_PMEM_CAMERA_SIZE 0x00800000
+
+#define MSM_FB_BASE 0x03800000
+#define MSM_FB_SIZE 0x00100000
+
+#define MSM_LINUX_BASE MSM_EBI_BASE
+#define MSM_LINUX_SIZE 0x06500000
+
+#define MSM_PMEM_GPU1_SIZE 0x800000
+#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE
+
+#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000
+#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K
+
+#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE)
+#error invalid memory map
+#endif
+
+#define DECLARE_MSM_IOMAP
+#include <mach/msm_iomap.h>
+
+#define TROUT_4_BALL_UP_0 1
+#define TROUT_4_BALL_LEFT_0 18
+#define TROUT_4_BALL_DOWN_0 57
+#define TROUT_4_BALL_RIGHT_0 91
+
+#define TROUT_5_BALL_UP_0 94
+#define TROUT_5_BALL_LEFT_0 18
+#define TROUT_5_BALL_DOWN_0 90
+#define TROUT_5_BALL_RIGHT_0 19
+
+#define TROUT_POWER_KEY 20
+
+#define TROUT_4_TP_LS_EN 19
+#define TROUT_5_TP_LS_EN 1
+
+#define TROUT_CPLD_BASE 0xE8100000
+#define TROUT_CPLD_START 0x98000000
+#define TROUT_CPLD_SIZE SZ_4K
+
+#define TROUT_GPIO_CABLE_IN1 (83)
+#define TROUT_GPIO_CABLE_IN2 (49)
+
+#define TROUT_GPIO_START (128)
+
+#define TROUT_GPIO_INT_MASK0_REG (0x0c)
+#define TROUT_GPIO_INT_STAT0_REG (0x0e)
+#define TROUT_GPIO_INT_MASK1_REG (0x14)
+#define TROUT_GPIO_INT_STAT1_REG (0x10)
+
+#define TROUT_GPIO_HAPTIC_PWM (28)
+#define TROUT_GPIO_PS_HOLD (25)
+
+#define TROUT_GPIO_MISC2_BASE (TROUT_GPIO_START + 0x00)
+#define TROUT_GPIO_MISC3_BASE (TROUT_GPIO_START + 0x08)
+#define TROUT_GPIO_MISC4_BASE (TROUT_GPIO_START + 0x10)
+#define TROUT_GPIO_MISC5_BASE (TROUT_GPIO_START + 0x18)
+#define TROUT_GPIO_INT2_BASE (TROUT_GPIO_START + 0x20)
+#define TROUT_GPIO_MISC1_BASE (TROUT_GPIO_START + 0x28)
+#define TROUT_GPIO_VIRTUAL_BASE (TROUT_GPIO_START + 0x30)
+#define TROUT_GPIO_INT5_BASE (TROUT_GPIO_START + 0x48)
+
+#define TROUT_GPIO_CHARGER_EN (TROUT_GPIO_MISC2_BASE + 0)
+#define TROUT_GPIO_ISET (TROUT_GPIO_MISC2_BASE + 1)
+#define TROUT_GPIO_H2W_DAT_DIR (TROUT_GPIO_MISC2_BASE + 2)
+#define TROUT_GPIO_H2W_CLK_DIR (TROUT_GPIO_MISC2_BASE + 3)
+#define TROUT_GPIO_H2W_DAT_GPO (TROUT_GPIO_MISC2_BASE + 4)
+#define TROUT_GPIO_H2W_CLK_GPO (TROUT_GPIO_MISC2_BASE + 5)
+#define TROUT_GPIO_H2W_SEL0 (TROUT_GPIO_MISC2_BASE + 6)
+#define TROUT_GPIO_H2W_SEL1 (TROUT_GPIO_MISC2_BASE + 7)
+
+#define TROUT_GPIO_SPOTLIGHT_EN (TROUT_GPIO_MISC3_BASE + 0)
+#define TROUT_GPIO_FLASH_EN (TROUT_GPIO_MISC3_BASE + 1)
+#define TROUT_GPIO_I2C_PULL (TROUT_GPIO_MISC3_BASE + 2)
+#define TROUT_GPIO_TP_I2C_PULL (TROUT_GPIO_MISC3_BASE + 3)
+#define TROUT_GPIO_TP_EN (TROUT_GPIO_MISC3_BASE + 4)
+#define TROUT_GPIO_JOG_EN (TROUT_GPIO_MISC3_BASE + 5)
+#define TROUT_GPIO_UI_LED_EN (TROUT_GPIO_MISC3_BASE + 6)
+#define TROUT_GPIO_QTKEY_LED_EN (TROUT_GPIO_MISC3_BASE + 7)
+
+#define TROUT_GPIO_VCM_PWDN (TROUT_GPIO_MISC4_BASE + 0)
+#define TROUT_GPIO_USB_H2W_SW (TROUT_GPIO_MISC4_BASE + 1)
+#define TROUT_GPIO_COMPASS_RST_N (TROUT_GPIO_MISC4_BASE + 2)
+#define TROUT_GPIO_HAPTIC_EN_UP (TROUT_GPIO_MISC4_BASE + 3)
+#define TROUT_GPIO_HAPTIC_EN_MAIN (TROUT_GPIO_MISC4_BASE + 4)
+#define TROUT_GPIO_USB_PHY_RST_N (TROUT_GPIO_MISC4_BASE + 5)
+#define TROUT_GPIO_WIFI_PA_RESETX (TROUT_GPIO_MISC4_BASE + 6)
+#define TROUT_GPIO_WIFI_EN (TROUT_GPIO_MISC4_BASE + 7)
+
+#define TROUT_GPIO_BT_32K_EN (TROUT_GPIO_MISC5_BASE + 0)
+#define TROUT_GPIO_MAC_32K_EN (TROUT_GPIO_MISC5_BASE + 1)
+#define TROUT_GPIO_MDDI_32K_EN (TROUT_GPIO_MISC5_BASE + 2)
+#define TROUT_GPIO_COMPASS_32K_EN (TROUT_GPIO_MISC5_BASE + 3)
+
+#define TROUT_GPIO_NAVI_ACT_N (TROUT_GPIO_INT2_BASE + 0)
+#define TROUT_GPIO_COMPASS_IRQ (TROUT_GPIO_INT2_BASE + 1)
+#define TROUT_GPIO_SLIDING_DET (TROUT_GPIO_INT2_BASE + 2)
+#define TROUT_GPIO_AUD_HSMIC_DET_N (TROUT_GPIO_INT2_BASE + 3)
+#define TROUT_GPIO_SD_DOOR_N (TROUT_GPIO_INT2_BASE + 4)
+#define TROUT_GPIO_CAM_BTN_STEP1_N (TROUT_GPIO_INT2_BASE + 5)
+#define TROUT_GPIO_CAM_BTN_STEP2_N (TROUT_GPIO_INT2_BASE + 6)
+#define TROUT_GPIO_TP_ATT_N (TROUT_GPIO_INT2_BASE + 7)
+#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE (TROUT_GPIO_NAVI_ACT_N)
+#define TROUT_GPIO_BANK0_LAST_INT_SOURCE (TROUT_GPIO_TP_ATT_N)
+
+#define TROUT_GPIO_H2W_DAT_GPI (TROUT_GPIO_MISC1_BASE + 0)
+#define TROUT_GPIO_H2W_CLK_GPI (TROUT_GPIO_MISC1_BASE + 1)
+#define TROUT_GPIO_CPLD128_VER_0 (TROUT_GPIO_MISC1_BASE + 4)
+#define TROUT_GPIO_CPLD128_VER_1 (TROUT_GPIO_MISC1_BASE + 5)
+#define TROUT_GPIO_CPLD128_VER_2 (TROUT_GPIO_MISC1_BASE + 6)
+#define TROUT_GPIO_CPLD128_VER_3 (TROUT_GPIO_MISC1_BASE + 7)
+
+#define TROUT_GPIO_SDMC_CD_N (TROUT_GPIO_VIRTUAL_BASE + 0)
+#define TROUT_GPIO_END (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N)
+#define TROUT_GPIO_BANK1_LAST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N)
+
+#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \
+ (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE)
+
+#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS)
+#define TROUT_INT_BANK0_COUNT (8)
+#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_BANK1_COUNT (1)
+#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \
+ TROUT_INT_BANK1_COUNT - 1)
+#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \
+ (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \
+ (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n)))
+
+#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT)
+#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7))
+#define TROUT_BANK_TO_MASK_REG(bank) \
+ (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG)
+#define TROUT_BANK_TO_STAT_REG(bank) \
+ (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG)
+
+#endif /* GUARD */
diff --git a/arch/arm/mach-msm/clock-7x01a.c b/arch/arm/mach-msm/clock-7x01a.c
deleted file mode 100644
index 62230a3428ee..000000000000
--- a/arch/arm/mach-msm/clock-7x01a.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/* arch/arm/mach-msm/clock-7x01a.c
- *
- * Clock tables for MSM7X01A
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007 QUALCOMM Incorporated
- *
- * 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/platform_device.h>
-
-#include "clock.h"
-#include "devices.h"
-
-/* clock IDs used by the modem processor */
-
-#define ACPU_CLK 0 /* Applications processor clock */
-#define ADM_CLK 1 /* Applications data mover clock */
-#define ADSP_CLK 2 /* ADSP clock */
-#define EBI1_CLK 3 /* External bus interface 1 clock */
-#define EBI2_CLK 4 /* External bus interface 2 clock */
-#define ECODEC_CLK 5 /* External CODEC clock */
-#define EMDH_CLK 6 /* External MDDI host clock */
-#define GP_CLK 7 /* General purpose clock */
-#define GRP_CLK 8 /* Graphics clock */
-#define I2C_CLK 9 /* I2C clock */
-#define ICODEC_RX_CLK 10 /* Internal CODEX RX clock */
-#define ICODEC_TX_CLK 11 /* Internal CODEX TX clock */
-#define IMEM_CLK 12 /* Internal graphics memory clock */
-#define MDC_CLK 13 /* MDDI client clock */
-#define MDP_CLK 14 /* Mobile display processor clock */
-#define PBUS_CLK 15 /* Peripheral bus clock */
-#define PCM_CLK 16 /* PCM clock */
-#define PMDH_CLK 17 /* Primary MDDI host clock */
-#define SDAC_CLK 18 /* Stereo DAC clock */
-#define SDC1_CLK 19 /* Secure Digital Card clocks */
-#define SDC1_PCLK 20
-#define SDC2_CLK 21
-#define SDC2_PCLK 22
-#define SDC3_CLK 23
-#define SDC3_PCLK 24
-#define SDC4_CLK 25
-#define SDC4_PCLK 26
-#define TSIF_CLK 27 /* Transport Stream Interface clocks */
-#define TSIF_REF_CLK 28
-#define TV_DAC_CLK 29 /* TV clocks */
-#define TV_ENC_CLK 30
-#define UART1_CLK 31 /* UART clocks */
-#define UART2_CLK 32
-#define UART3_CLK 33
-#define UART1DM_CLK 34
-#define UART2DM_CLK 35
-#define USB_HS_CLK 36 /* High speed USB core clock */
-#define USB_HS_PCLK 37 /* High speed USB pbus clock */
-#define USB_OTG_CLK 38 /* Full speed USB clock */
-#define VDC_CLK 39 /* Video controller clock */
-#define VFE_CLK 40 /* Camera / Video Front End clock */
-#define VFE_MDC_CLK 41 /* VFE MDDI client clock */
-
-#define NR_CLKS 42
-
-#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) { \
- .name = clk_name, \
- .id = clk_id, \
- .flags = clk_flags, \
- .dev = clk_dev, \
- }
-
-#define OFF CLKFLAG_AUTO_OFF
-#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET
-
-struct clk msm_clocks[] = {
- CLOCK("adm_clk", ADM_CLK, NULL, 0),
- CLOCK("adsp_clk", ADSP_CLK, NULL, 0),
- CLOCK("ebi1_clk", EBI1_CLK, NULL, 0),
- CLOCK("ebi2_clk", EBI2_CLK, NULL, 0),
- CLOCK("ecodec_clk", ECODEC_CLK, NULL, 0),
- CLOCK("emdh_clk", EMDH_CLK, NULL, OFF),
- CLOCK("gp_clk", GP_CLK, NULL, 0),
- CLOCK("grp_clk", GRP_CLK, NULL, OFF),
- CLOCK("i2c_clk", I2C_CLK, &msm_device_i2c.dev, 0),
- CLOCK("icodec_rx_clk", ICODEC_RX_CLK, NULL, 0),
- CLOCK("icodec_tx_clk", ICODEC_TX_CLK, NULL, 0),
- CLOCK("imem_clk", IMEM_CLK, NULL, OFF),
- CLOCK("mdc_clk", MDC_CLK, NULL, 0),
- CLOCK("mdp_clk", MDP_CLK, NULL, OFF),
- CLOCK("pbus_clk", PBUS_CLK, NULL, 0),
- CLOCK("pcm_clk", PCM_CLK, NULL, 0),
- CLOCK("pmdh_clk", PMDH_CLK, NULL, OFF | MINMAX),
- CLOCK("sdac_clk", SDAC_CLK, NULL, OFF),
- CLOCK("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF),
- CLOCK("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
- CLOCK("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
- CLOCK("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
- CLOCK("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
- CLOCK("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
- CLOCK("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
- CLOCK("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF),
- CLOCK("tsif_clk", TSIF_CLK, NULL, 0),
- CLOCK("tsif_ref_clk", TSIF_REF_CLK, NULL, 0),
- CLOCK("tv_dac_clk", TV_DAC_CLK, NULL, 0),
- CLOCK("tv_enc_clk", TV_ENC_CLK, NULL, 0),
- CLOCK("uart_clk", UART1_CLK, &msm_device_uart1.dev, OFF),
- CLOCK("uart_clk", UART2_CLK, &msm_device_uart2.dev, 0),
- CLOCK("uart_clk", UART3_CLK, &msm_device_uart3.dev, OFF),
- CLOCK("uart1dm_clk", UART1DM_CLK, NULL, OFF),
- CLOCK("uart2dm_clk", UART2DM_CLK, NULL, 0),
- CLOCK("usb_hs_clk", USB_HS_CLK, &msm_device_hsusb.dev, OFF),
- CLOCK("usb_hs_pclk", USB_HS_PCLK, &msm_device_hsusb.dev, OFF),
- CLOCK("usb_otg_clk", USB_OTG_CLK, NULL, 0),
- CLOCK("vdc_clk", VDC_CLK, NULL, OFF | MINMAX),
- CLOCK("vfe_clk", VFE_CLK, NULL, OFF),
- CLOCK("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF),
-};
-
-unsigned msm_num_clocks = ARRAY_SIZE(msm_clocks);
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
new file mode 100644
index 000000000000..d1bab48c85fa
--- /dev/null
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -0,0 +1,957 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <mach/msm_iomap.h>
+#include <mach/clk.h>
+
+#include "clock.h"
+#include "clock-7x30.h"
+
+struct clk_freq_tbl {
+ uint32_t freq_hz;
+ uint32_t src;
+ uint32_t md_val;
+ uint32_t ns_val;
+ uint32_t mode;
+};
+
+struct clk_local {
+ uint32_t count;
+ uint32_t type;
+ uint32_t md_reg;
+ uint32_t ns_reg;
+ uint32_t freq_mask;
+ uint32_t br_en_mask;
+ uint32_t root_en_mask;
+ int parent;
+ uint32_t *children;
+ struct clk_freq_tbl *freq_tbl;
+ struct clk_freq_tbl *current_freq;
+};
+
+
+enum {
+ SRC_PLL0 = 4, /* Modem PLL */
+ SRC_PLL1 = 1, /* Global PLL */
+ SRC_PLL3 = 3, /* Multimedia/Peripheral PLL or Backup PLL1 */
+ SRC_PLL4 = 2, /* Display PLL */
+ SRC_LPXO = 6, /* Low power XO. */
+ SRC_MAX /* Used for sources that can't be turned on/off. */
+};
+
+static uint32_t src_pll_tbl[] = {
+ [SRC_PLL0] = PLL_0,
+ [SRC_PLL1] = PLL_1,
+ [SRC_PLL3] = PLL_3,
+ [SRC_PLL4] = PLL_4,
+};
+
+#define B(x) BIT(x)
+#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
+#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb))
+
+#define MD8(m, n) (BVAL(15, 8, m) | BVAL(7, 0, ~(n)))
+#define N8(msb, lsb, m, n) (BVAL(msb, lsb, ~(n-m)))
+#define MD16(m, n) (BVAL(31, 16, m) | BVAL(15, 0, ~(n)))
+#define N16(m, n) (BVAL(31, 16, ~(n-m)))
+#define SPDIV(s, d) (BVAL(4, 3, d-1) | BVAL(2, 0, s))
+#define SDIV(s, d) (BVAL(6, 3, d-1) | BVAL(2, 0, s))
+#define F_MASK_BASIC (BM(6, 3)|BM(2, 0))
+#define F_MASK_MND16 (BM(31, 16)|BM(4, 3)|BM(2, 0))
+#define F_MASK_MND8(m, l) (BM(m, l)|BM(4, 3)|BM(2, 0))
+
+#define F_RAW(f, s, m_v, n_v, mde) { \
+ .freq_hz = f, \
+ .src = s, \
+ .md_val = m_v, \
+ .ns_val = n_v, \
+ .mode = mde, \
+ }
+
+#define FREQ_END 0
+#define F_BASIC(f, s, div) F_RAW(f, s, 0, SDIV(s, div), 0)
+#define F_MND16(f, s, div, m, n) \
+ F_RAW(f, s, MD16(m, n), N16(m, n)|SPDIV(s, div), !!(n))
+#define F_MND8(f, nmsb, nlsb, s, div, m, n) \
+ F_RAW(f, s, MD8(m, n), N8(nmsb, nlsb, m, n)|SPDIV(s, div), !!(n))
+#define F_END F_RAW(FREQ_END, SRC_MAX, 0, 0, 0)
+
+static struct clk_freq_tbl clk_tbl_tcxo[] = {
+ F_RAW(19200000, SRC_MAX, 0, 0, 0),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_uartdm[] = {
+ F_MND16( 3686400, SRC_PLL3, 3, 3, 200),
+ F_MND16( 7372800, SRC_PLL3, 3, 3, 100),
+ F_MND16(14745600, SRC_PLL3, 3, 3, 50),
+ F_MND16(46400000, SRC_PLL3, 3, 145, 768),
+ F_MND16(51200000, SRC_PLL3, 3, 5, 24),
+ F_MND16(58982400, SRC_PLL3, 3, 6, 25),
+ F_MND16(64000000, SRC_PLL1, 4, 1, 3),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mdh[] = {
+ F_BASIC( 73728000, SRC_PLL3, 10),
+ F_BASIC( 92160000, SRC_PLL3, 8),
+ F_BASIC(122880000, SRC_PLL3, 6),
+ F_BASIC(184320000, SRC_PLL3, 4),
+ F_BASIC(245760000, SRC_PLL3, 3),
+ F_BASIC(368640000, SRC_PLL3, 2),
+ F_BASIC(384000000, SRC_PLL1, 2),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_grp[] = {
+ F_BASIC( 24576000, SRC_LPXO, 1),
+ F_BASIC( 46000000, SRC_PLL3, 16),
+ F_BASIC( 49000000, SRC_PLL3, 15),
+ F_BASIC( 52000000, SRC_PLL3, 14),
+ F_BASIC( 56000000, SRC_PLL3, 13),
+ F_BASIC( 61440000, SRC_PLL3, 12),
+ F_BASIC( 67000000, SRC_PLL3, 11),
+ F_BASIC( 73000000, SRC_PLL3, 10),
+ F_BASIC( 81000000, SRC_PLL3, 9),
+ F_BASIC( 92000000, SRC_PLL3, 8),
+ F_BASIC(105000000, SRC_PLL3, 7),
+ F_BASIC(120000000, SRC_PLL3, 6),
+ F_BASIC(150000000, SRC_PLL3, 5),
+ F_BASIC(183000000, SRC_PLL3, 4),
+ F_BASIC(192000000, SRC_PLL1, 4),
+ F_BASIC(245760000, SRC_PLL3, 3),
+ /* Sync to AXI. Hence this "rate" is not fixed. */
+ F_RAW(1, SRC_MAX, 0, B(14), 0),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_sdc1_3[] = {
+ F_MND8( 144000, 19, 12, SRC_LPXO, 1, 1, 171),
+ F_MND8( 400000, 19, 12, SRC_LPXO, 1, 2, 123),
+ F_MND8(16000000, 19, 12, SRC_PLL3, 3, 14, 215),
+ F_MND8(17000000, 19, 12, SRC_PLL3, 4, 19, 206),
+ F_MND8(20000000, 19, 12, SRC_PLL3, 4, 23, 212),
+ F_MND8(25000000, 19, 12, SRC_LPXO, 1, 0, 0),
+ F_MND8(50000000, 19, 12, SRC_PLL3, 3, 1, 5),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_sdc2_4[] = {
+ F_MND8( 144000, 20, 13, SRC_LPXO, 1, 1, 171),
+ F_MND8( 400000, 20, 13, SRC_LPXO, 1, 2, 123),
+ F_MND8(16000000, 20, 13, SRC_PLL3, 3, 14, 215),
+ F_MND8(17000000, 20, 13, SRC_PLL3, 4, 19, 206),
+ F_MND8(20000000, 20, 13, SRC_PLL3, 4, 23, 212),
+ F_MND8(25000000, 20, 13, SRC_LPXO, 1, 0, 0),
+ F_MND8(50000000, 20, 13, SRC_PLL3, 3, 1, 5),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_core[] = {
+ F_BASIC( 46000000, SRC_PLL3, 16),
+ F_BASIC( 49000000, SRC_PLL3, 15),
+ F_BASIC( 52000000, SRC_PLL3, 14),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_lcdc[] = {
+ F_MND16(25000000, SRC_LPXO, 1, 0, 0),
+ F_MND16(30000000, SRC_PLL3, 4, 1, 6),
+ F_MND16(40000000, SRC_PLL3, 2, 1, 9),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mdp_vsync[] = {
+ F_RAW(24576000, SRC_MAX, 0, 0, 0), /* Initialized to LPXO. */
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mi2s_codec[] = {
+ F_MND16( 2048000, SRC_LPXO, 4, 1, 3),
+ F_MND16(12288000, SRC_LPXO, 2, 0, 0),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mi2s[] = {
+ F_MND16(12288000, SRC_LPXO, 2, 0, 0),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_midi[] = {
+ F_MND8(98304000, 19, 12, SRC_PLL3, 3, 2, 5),
+ F_END,
+};
+static struct clk_freq_tbl clk_tbl_sdac[] = {
+ F_MND16( 256000, SRC_LPXO, 4, 1, 24),
+ F_MND16( 352800, SRC_LPXO, 1, 147, 10240),
+ F_MND16( 384000, SRC_LPXO, 4, 1, 16),
+ F_MND16( 512000, SRC_LPXO, 4, 1, 12),
+ F_MND16( 705600, SRC_LPXO, 1, 147, 5120),
+ F_MND16( 768000, SRC_LPXO, 4, 1, 8),
+ F_MND16(1024000, SRC_LPXO, 4, 1, 6),
+ F_MND16(1411200, SRC_LPXO, 1, 147, 2560),
+ F_MND16(1536000, SRC_LPXO, 4, 1, 4),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_tv[] = {
+ F_MND8(27000000, 23, 16, SRC_PLL4, 2, 2, 33),
+ F_MND8(74250000, 23, 16, SRC_PLL4, 2, 1, 6),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_usb[] = {
+ F_MND8(60000000, 23, 16, SRC_PLL1, 2, 5, 32),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_vfe_jpeg[] = {
+ F_MND16( 36000000, SRC_PLL3, 4, 1, 5),
+ F_MND16( 46000000, SRC_PLL3, 4, 1, 4),
+ F_MND16( 61440000, SRC_PLL3, 4, 1, 3),
+ F_MND16( 74000000, SRC_PLL3, 2, 1, 5),
+ F_MND16( 82000000, SRC_PLL3, 3, 1, 3),
+ F_MND16( 92000000, SRC_PLL3, 4, 1, 2),
+ F_MND16( 98000000, SRC_PLL3, 3, 2, 5),
+ F_MND16(105000000, SRC_PLL3, 2, 2, 7),
+ F_MND16(122880000, SRC_PLL3, 2, 1, 3),
+ F_MND16(148000000, SRC_PLL3, 2, 2, 5),
+ F_MND16(154000000, SRC_PLL1, 2, 2, 5),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_cam[] = {
+ F_MND16( 6000000, SRC_PLL1, 4, 1, 32),
+ F_MND16( 8000000, SRC_PLL1, 4, 1, 24),
+ F_MND16(12000000, SRC_PLL1, 4, 1, 16),
+ F_MND16(16000000, SRC_PLL1, 4, 1, 12),
+ F_MND16(19000000, SRC_PLL1, 4, 1, 10),
+ F_MND16(24000000, SRC_PLL1, 4, 1, 8),
+ F_MND16(32000000, SRC_PLL1, 4, 1, 6),
+ F_MND16(48000000, SRC_PLL1, 4, 1, 4),
+ F_MND16(64000000, SRC_PLL1, 4, 1, 3),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_vpe[] = {
+ F_MND8( 24576000, 22, 15, SRC_LPXO, 1, 0, 0),
+ F_MND8( 30720000, 22, 15, SRC_PLL3, 4, 1, 6),
+ F_MND8( 61440000, 22, 15, SRC_PLL3, 4, 1, 3),
+ F_MND8( 81920000, 22, 15, SRC_PLL3, 3, 1, 3),
+ F_MND8(122880000, 22, 15, SRC_PLL3, 3, 1, 2),
+ F_MND8(147000000, 22, 15, SRC_PLL3, 1, 1, 5),
+ F_MND8(153600000, 22, 15, SRC_PLL1, 1, 1, 5),
+ F_MND8(170667000, 22, 15, SRC_PLL1, 1, 2, 9),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_mfc[] = {
+ F_MND8( 24576000, 24, 17, SRC_LPXO, 1, 0, 0),
+ F_MND8( 30720000, 24, 17, SRC_PLL3, 4, 1, 6),
+ F_MND8( 61440000, 24, 17, SRC_PLL3, 4, 1, 3),
+ F_MND8( 81920000, 24, 17, SRC_PLL3, 3, 1, 3),
+ F_MND8(122880000, 24, 17, SRC_PLL3, 3, 1, 2),
+ F_MND8(147000000, 24, 17, SRC_PLL3, 1, 1, 5),
+ F_MND8(153600000, 24, 17, SRC_PLL1, 1, 1, 5),
+ F_MND8(170667000, 24, 17, SRC_PLL1, 1, 2, 9),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_spi[] = {
+ F_MND8(10000000, 19, 12, SRC_PLL3, 4, 7, 129),
+ F_MND8(26000000, 19, 12, SRC_PLL3, 4, 34, 241),
+ F_END,
+};
+
+static struct clk_freq_tbl clk_tbl_lpa_codec[] = {
+ F_RAW(1, SRC_MAX, 0, 0, 0), /* src = MI2S_CODEC_RX */
+ F_RAW(2, SRC_MAX, 0, 1, 0), /* src = ECODEC_CIF */
+ F_RAW(3, SRC_MAX, 0, 2, 0), /* src = MI2S */
+ F_RAW(4, SRC_MAX, 0, 3, 0), /* src = SDAC */
+ F_END,
+};
+
+static struct clk_freq_tbl dummy_freq = F_END;
+
+#define MND 1 /* Integer predivider and fractional MN:D divider. */
+#define BASIC 2 /* Integer divider. */
+#define NORATE 3 /* Just on/off. */
+
+#define C(x) L_7X30_##x##_CLK
+
+#define CLK_LOCAL(id, t, md, ns, f_msk, br, root, tbl, par, chld_lst) \
+ [C(id)] = { \
+ .type = t, \
+ .md_reg = md, \
+ .ns_reg = ns, \
+ .freq_mask = f_msk, \
+ .br_en_mask = br, \
+ .root_en_mask = root, \
+ .parent = C(par), \
+ .children = chld_lst, \
+ .freq_tbl = tbl, \
+ .current_freq = &dummy_freq, \
+ }
+
+#define CLK_BASIC(id, ns, br, root, tbl, par) \
+ CLK_LOCAL(id, BASIC, 0, ns, F_MASK_BASIC, br, root, tbl, \
+ par, NULL)
+#define CLK_MND8_P(id, ns, m, l, br, root, tbl, par, chld_lst) \
+ CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND8(m, l), br, root, \
+ tbl, par, chld_lst)
+#define CLK_MND8(id, ns, m, l, br, root, tbl, chld_lst) \
+ CLK_MND8_P(id, ns, m, l, br, root, tbl, NONE, chld_lst)
+#define CLK_MND16(id, ns, br, root, tbl, par, chld_lst) \
+ CLK_LOCAL(id, MND, (ns-4), ns, F_MASK_MND16, br, root, tbl, \
+ par, chld_lst)
+#define CLK_1RATE(id, ns, br, root, tbl) \
+ CLK_LOCAL(id, BASIC, 0, ns, 0, br, root, tbl, NONE, NULL)
+#define CLK_SLAVE(id, ns, br, par) \
+ CLK_LOCAL(id, NORATE, 0, ns, 0, br, 0, NULL, par, NULL)
+#define CLK_NORATE(id, ns, br, root) \
+ CLK_LOCAL(id, NORATE, 0, ns, 0, br, root, NULL, NONE, NULL)
+#define CLK_GLBL(id, glbl, root) \
+ CLK_LOCAL(id, NORATE, 0, glbl, 0, 0, root, NULL, NONE, NULL)
+#define CLK_BRIDGE(id, glbl, root, par) \
+ CLK_LOCAL(id, NORATE, 0, glbl, 0, 0, root, NULL, par, NULL)
+
+#define REG(off) (MSM_CLK_CTL_BASE + off)
+#define MNCNTR_EN_MASK B(8)
+#define MNCNTR_RST_MASK B(7)
+#define MNCNTR_MODE_MASK BM(6, 5)
+#define MNCNTR_MODE BVAL(6, 5, 0x2) /* Dual-edge mode. */
+
+/* Register offsets used more than once. */
+#define USBH_MD 0x02BC
+#define USBH_NS 0x02C0
+#define USBH2_NS 0x046C
+#define USBH3_NS 0x0470
+#define CAM_VFE_NS 0x0044
+#define GLBL_CLK_ENA_SC 0x03BC
+#define GLBL_CLK_ENA_2_SC 0x03C0
+#define SDAC_NS 0x009C
+#define TV_NS 0x00CC
+#define MI2S_RX_NS 0x0070
+#define MI2S_TX_NS 0x0078
+#define MI2S_NS 0x02E0
+#define LPA_NS 0x02E8
+#define MDC_NS 0x007C
+#define MDP_VSYNC_REG 0x0460
+#define PLL_ENA_REG 0x0260
+
+static uint32_t pll_count[NUM_PLL];
+
+static uint32_t chld_grp_3d_src[] = {C(IMEM), C(GRP_3D), C(NONE)};
+static uint32_t chld_mdp_lcdc_p[] = {C(MDP_LCDC_PAD_P), C(NONE)};
+static uint32_t chld_mi2s_codec_rx[] = {C(MI2S_CODEC_RX_S), C(NONE)};
+static uint32_t chld_mi2s_codec_tx[] = {C(MI2S_CODEC_TX_S), C(NONE)};
+static uint32_t chld_mi2s[] = {C(MI2S_S), C(NONE)};
+static uint32_t chld_sdac_m[] = {C(SDAC_S), C(NONE)};
+static uint32_t chld_tv[] = {C(TV_DAC), C(TV_ENC), C(TSIF_REF), C(NONE)};
+static uint32_t chld_usb_src[] = {
+ C(USB_HS), C(USB_HS_CORE),
+ C(USB_HS2), C(USB_HS2_CORE),
+ C(USB_HS3), C(USB_HS3_CORE),
+ C(NONE),
+};
+uint32_t chld_vfe[] = {C(VFE_MDC), C(VFE_CAMIF), C(NONE)};
+
+static struct clk_local clk_local_tbl[] = {
+ CLK_NORATE(MDC, MDC_NS, B(9), B(11)),
+ CLK_NORATE(LPA_CORE, LPA_NS, B(5), 0),
+
+ CLK_1RATE(I2C, 0x0068, B(9), B(11), clk_tbl_tcxo),
+ CLK_1RATE(I2C_2, 0x02D8, B(0), B(2), clk_tbl_tcxo),
+ CLK_1RATE(QUP_I2C, 0x04F0, B(0), B(2), clk_tbl_tcxo),
+ CLK_1RATE(UART1, 0x00E0, B(5), B(4), clk_tbl_tcxo),
+ CLK_1RATE(UART3, 0x0468, B(5), B(4), clk_tbl_tcxo),
+
+ CLK_BASIC(EMDH, 0x0050, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A),
+ CLK_BASIC(PMDH, 0x008C, 0, B(11), clk_tbl_mdh, AXI_LI_ADSP_A),
+ CLK_BASIC(MDP, 0x014C, B(9), B(11), clk_tbl_mdp_core, AXI_MDP),
+
+ CLK_MND8_P(VPE, 0x015C, 22, 15, B(9), B(11), clk_tbl_vpe,
+ AXI_VPE, NULL),
+ /* Combining MFC and MFC_DIV2 clocks. */
+ CLK_MND8_P(MFC, 0x0154, 24, 17, B(9)|B(15), B(11), clk_tbl_mfc,
+ AXI_MFC, NULL),
+
+ CLK_MND8(SDC1, 0x00A4, 19, 12, B(9), B(11), clk_tbl_sdc1_3, NULL),
+ CLK_MND8(SDC2, 0x00AC, 20, 13, B(9), B(11), clk_tbl_sdc2_4, NULL),
+ CLK_MND8(SDC3, 0x00B4, 19, 12, B(9), B(11), clk_tbl_sdc1_3, NULL),
+ CLK_MND8(SDC4, 0x00BC, 20, 13, B(9), B(11), clk_tbl_sdc2_4, NULL),
+ CLK_MND8(SPI, 0x02C8, 19, 12, B(9), B(11), clk_tbl_spi, NULL),
+ CLK_MND8(MIDI, 0x02D0, 19, 12, B(9), B(11), clk_tbl_midi, NULL),
+ CLK_MND8_P(USB_HS_SRC, USBH_NS, 23, 16, 0, B(11), clk_tbl_usb,
+ AXI_LI_ADSP_A, chld_usb_src),
+ CLK_SLAVE(USB_HS, USBH_NS, B(9), USB_HS_SRC),
+ CLK_SLAVE(USB_HS_CORE, USBH_NS, B(13), USB_HS_SRC),
+ CLK_SLAVE(USB_HS2, USBH2_NS, B(9), USB_HS_SRC),
+ CLK_SLAVE(USB_HS2_CORE, USBH2_NS, B(4), USB_HS_SRC),
+ CLK_SLAVE(USB_HS3, USBH3_NS, B(9), USB_HS_SRC),
+ CLK_SLAVE(USB_HS3_CORE, USBH3_NS, B(4), USB_HS_SRC),
+ CLK_MND8(TV, TV_NS, 23, 16, 0, B(11), clk_tbl_tv, chld_tv),
+ CLK_SLAVE(TV_DAC, TV_NS, B(12), TV),
+ CLK_SLAVE(TV_ENC, TV_NS, B(9), TV),
+ /* Hacking root & branch into one param. */
+ CLK_SLAVE(TSIF_REF, 0x00C4, B(9)|B(11), TV),
+
+ CLK_MND16(UART1DM, 0x00D4, B(9), B(11), clk_tbl_uartdm, NONE, NULL),
+ CLK_MND16(UART2DM, 0x00DC, B(9), B(11), clk_tbl_uartdm, NONE, NULL),
+ CLK_MND16(JPEG, 0x0164, B(9), B(11), clk_tbl_vfe_jpeg,
+ AXI_LI_JPEG, NULL),
+ CLK_MND16(CAM, 0x0374, 0, B(9), clk_tbl_cam, NONE, NULL),
+ CLK_MND16(VFE, CAM_VFE_NS, B(9), B(13), clk_tbl_vfe_jpeg,
+ AXI_LI_VFE, chld_vfe),
+ CLK_SLAVE(VFE_MDC, CAM_VFE_NS, B(11), VFE),
+ CLK_SLAVE(VFE_CAMIF, CAM_VFE_NS, B(15), VFE),
+
+ CLK_MND16(SDAC_M, SDAC_NS, B(12), B(11), clk_tbl_sdac,
+ NONE, chld_sdac_m),
+ CLK_SLAVE(SDAC_S, SDAC_NS, B(9), SDAC_M),
+
+ CLK_MND16(MDP_LCDC_P, 0x0390, B(9), B(11), clk_tbl_mdp_lcdc,
+ NONE, chld_mdp_lcdc_p),
+ CLK_SLAVE(MDP_LCDC_PAD_P, 0x0390, B(12), MDP_LCDC_P),
+ CLK_1RATE(MDP_VSYNC, MDP_VSYNC_REG, B(0), 0, clk_tbl_mdp_vsync),
+
+ CLK_MND16(MI2S_CODEC_RX_M, MI2S_RX_NS, B(12), B(11),
+ clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_rx),
+ CLK_SLAVE(MI2S_CODEC_RX_S, MI2S_RX_NS, B(9), MI2S_CODEC_RX_M),
+
+ CLK_MND16(MI2S_CODEC_TX_M, MI2S_TX_NS, B(12), B(11),
+ clk_tbl_mi2s_codec, NONE, chld_mi2s_codec_tx),
+ CLK_SLAVE(MI2S_CODEC_TX_S, MI2S_TX_NS, B(9), MI2S_CODEC_TX_M),
+
+ CLK_MND16(MI2S_M, MI2S_NS, B(12), B(11),
+ clk_tbl_mi2s, NONE, chld_mi2s),
+ CLK_SLAVE(MI2S_S, MI2S_NS, B(9), MI2S_M),
+
+ CLK_LOCAL(GRP_2D, BASIC, 0, 0x0034, F_MASK_BASIC | (7 << 12),
+ B(7), B(11), clk_tbl_grp, AXI_GRP_2D, NULL),
+ CLK_LOCAL(GRP_3D_SRC, BASIC, 0, 0x0084, F_MASK_BASIC | (7 << 12),
+ 0, B(11), clk_tbl_grp, AXI_LI_GRP, chld_grp_3d_src),
+ CLK_SLAVE(GRP_3D, 0x0084, B(7), GRP_3D_SRC),
+ CLK_SLAVE(IMEM, 0x0084, B(9), GRP_3D_SRC),
+ CLK_LOCAL(LPA_CODEC, BASIC, 0, LPA_NS, BM(1, 0), B(9), 0,
+ clk_tbl_lpa_codec, NONE, NULL),
+
+ /* Peripheral bus clocks. */
+ CLK_GLBL(ADM, GLBL_CLK_ENA_SC, B(5)),
+ CLK_GLBL(CAMIF_PAD_P, GLBL_CLK_ENA_SC, B(9)),
+ CLK_GLBL(EMDH_P, GLBL_CLK_ENA_2_SC, B(3)),
+ CLK_GLBL(GRP_2D_P, GLBL_CLK_ENA_SC, B(24)),
+ CLK_GLBL(GRP_3D_P, GLBL_CLK_ENA_2_SC, B(17)),
+ CLK_GLBL(JPEG_P, GLBL_CLK_ENA_2_SC, B(24)),
+ CLK_GLBL(LPA_P, GLBL_CLK_ENA_2_SC, B(7)),
+ CLK_GLBL(MDP_P, GLBL_CLK_ENA_2_SC, B(6)),
+ CLK_GLBL(MFC_P, GLBL_CLK_ENA_2_SC, B(26)),
+ CLK_GLBL(PMDH_P, GLBL_CLK_ENA_2_SC, B(4)),
+ CLK_GLBL(ROTATOR_IMEM, GLBL_CLK_ENA_2_SC, B(23)),
+ CLK_GLBL(ROTATOR_P, GLBL_CLK_ENA_2_SC, B(25)),
+ CLK_GLBL(SDC1_H, GLBL_CLK_ENA_SC, B(7)),
+ CLK_GLBL(SDC2_H, GLBL_CLK_ENA_SC, B(8)),
+ CLK_GLBL(SDC3_H, GLBL_CLK_ENA_SC, B(27)),
+ CLK_GLBL(SDC4_H, GLBL_CLK_ENA_SC, B(28)),
+ CLK_GLBL(SPI_P, GLBL_CLK_ENA_2_SC, B(10)),
+ CLK_GLBL(TSIF_P, GLBL_CLK_ENA_SC, B(18)),
+ CLK_GLBL(UART1DM_P, GLBL_CLK_ENA_SC, B(17)),
+ CLK_GLBL(UART2DM_P, GLBL_CLK_ENA_SC, B(26)),
+ CLK_GLBL(USB_HS2_P, GLBL_CLK_ENA_2_SC, B(8)),
+ CLK_GLBL(USB_HS3_P, GLBL_CLK_ENA_2_SC, B(9)),
+ CLK_GLBL(USB_HS_P, GLBL_CLK_ENA_SC, B(25)),
+ CLK_GLBL(VFE_P, GLBL_CLK_ENA_2_SC, B(27)),
+
+ /* AXI bridge clocks. */
+ CLK_BRIDGE(AXI_LI_APPS, GLBL_CLK_ENA_SC, B(2), NONE),
+ CLK_BRIDGE(AXI_LI_ADSP_A, GLBL_CLK_ENA_2_SC, B(14), AXI_LI_APPS),
+ CLK_BRIDGE(AXI_LI_JPEG, GLBL_CLK_ENA_2_SC, B(19), AXI_LI_APPS),
+ CLK_BRIDGE(AXI_LI_VFE, GLBL_CLK_ENA_SC, B(23), AXI_LI_APPS),
+ CLK_BRIDGE(AXI_MDP, GLBL_CLK_ENA_2_SC, B(29), AXI_LI_APPS),
+
+ CLK_BRIDGE(AXI_IMEM, GLBL_CLK_ENA_2_SC, B(18), NONE),
+
+ CLK_BRIDGE(AXI_LI_VG, GLBL_CLK_ENA_SC, B(3), NONE),
+ CLK_BRIDGE(AXI_GRP_2D, GLBL_CLK_ENA_SC, B(21), AXI_LI_VG),
+ CLK_BRIDGE(AXI_LI_GRP, GLBL_CLK_ENA_SC, B(22), AXI_LI_VG),
+ CLK_BRIDGE(AXI_MFC, GLBL_CLK_ENA_2_SC, B(20), AXI_LI_VG),
+ CLK_BRIDGE(AXI_ROTATOR, GLBL_CLK_ENA_2_SC, B(22), AXI_LI_VG),
+ CLK_BRIDGE(AXI_VPE, GLBL_CLK_ENA_2_SC, B(21), AXI_LI_VG),
+};
+
+static DEFINE_SPINLOCK(clock_reg_lock);
+static DEFINE_SPINLOCK(pll_vote_lock);
+
+void pll_enable(uint32_t pll)
+{
+ uint32_t reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pll_vote_lock, flags);
+ if (!pll_count[pll]) {
+ reg_val = readl(REG(PLL_ENA_REG));
+ reg_val |= (1 << pll);
+ writel(reg_val, REG(PLL_ENA_REG));
+ }
+ pll_count[pll]++;
+ spin_unlock_irqrestore(&pll_vote_lock, flags);
+}
+
+static void src_enable(uint32_t src)
+{
+ /* SRC_MAX is used as a placeholder for some freqencies that don't
+ * have any direct PLL dependency. */
+ if (src == SRC_MAX || src == SRC_LPXO)
+ return;
+
+ pll_enable(src_pll_tbl[src]);
+}
+
+void pll_disable(uint32_t pll)
+{
+ uint32_t reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pll_vote_lock, flags);
+ if (pll_count[pll])
+ pll_count[pll]--;
+ else
+ pr_warning("Reference count mismatch in PLL disable!\n");
+
+ if (pll_count[pll] == 0) {
+ reg_val = readl(REG(PLL_ENA_REG));
+ reg_val &= ~(1 << pll);
+ writel(reg_val, REG(PLL_ENA_REG));
+ }
+ spin_unlock_irqrestore(&pll_vote_lock, flags);
+}
+
+static void src_disable(uint32_t src)
+{
+ /* SRC_MAX is used as a placeholder for some freqencies that don't
+ * have any direct PLL dependency. */
+ if (src == SRC_MAX || src == SRC_LPXO)
+ return;
+
+ pll_disable(src_pll_tbl[src]);
+
+}
+
+/*
+ * SoC specific register-based control of clocks.
+ */
+static int _soc_clk_enable(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ void *ns_reg = REG(t->ns_reg);
+ uint32_t reg_val = 0;
+
+ reg_val = readl(ns_reg);
+ if (t->type == MND) {
+ /* mode can be either 0 or 1. So the R-value of the
+ * expression will evaluate to MNCNTR_EN_MASK or 0. This
+ * avoids the need for a "if(mode == 1)". A "&" will not work
+ * here. */
+ reg_val |= (MNCNTR_EN_MASK * t->current_freq->mode);
+ writel(reg_val, ns_reg);
+ }
+ if (t->root_en_mask) {
+ reg_val |= t->root_en_mask;
+ writel(reg_val, ns_reg);
+ }
+ if (t->br_en_mask) {
+ reg_val |= t->br_en_mask;
+ writel(reg_val, ns_reg);
+ }
+ return 0;
+}
+
+static void _soc_clk_disable(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ void *ns_reg = REG(t->ns_reg);
+ uint32_t reg_val = 0;
+
+ reg_val = readl(ns_reg);
+
+ if (t->br_en_mask) {
+ reg_val &= ~(t->br_en_mask);
+ writel(reg_val, ns_reg);
+ }
+ if (t->root_en_mask) {
+ reg_val &= ~(t->root_en_mask);
+ writel(reg_val, ns_reg);
+ }
+ if (t->type == MND) {
+ reg_val &= ~MNCNTR_EN_MASK;
+ writel(reg_val, ns_reg);
+ }
+}
+
+static int soc_clk_enable_nolock(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ int ret = 0;
+
+ if (!t->count) {
+ if (t->parent != C(NONE))
+ soc_clk_enable_nolock(t->parent);
+ src_enable(t->current_freq->src);
+ ret = _soc_clk_enable(id);
+ }
+ t->count++;
+
+ return ret;
+}
+
+static void soc_clk_disable_nolock(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+
+ if (!t->count) {
+ pr_warning("Reference count mismatch in clock disable!\n");
+ return;
+ }
+ if (t->count)
+ t->count--;
+ if (t->count == 0) {
+ _soc_clk_disable(id);
+ src_disable(t->current_freq->src);
+ if (t->parent != C(NONE))
+ soc_clk_disable_nolock(t->parent);
+ }
+
+ return;
+}
+
+static int soc_clk_enable(unsigned id)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+ ret = soc_clk_enable_nolock(id);
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+
+ return ret;
+}
+
+static void soc_clk_disable(unsigned id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+ soc_clk_disable_nolock(id);
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+
+ return;
+}
+
+static int soc_clk_reset(unsigned id, enum clk_reset_action action)
+{
+ return -EPERM;
+}
+
+static int soc_clk_set_rate(unsigned id, unsigned rate)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ struct clk_freq_tbl *cf = t->current_freq;
+ struct clk_freq_tbl *nf;
+ uint32_t *chld = t->children;
+ void *ns_reg = REG(t->ns_reg);
+ void *md_reg = REG(t->md_reg);
+ uint32_t reg_val = 0;
+ int i, ret = 0;
+ unsigned long flags;
+
+ if (t->type != MND && t->type != BASIC)
+ return -EPERM;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+
+ if (rate == cf->freq_hz)
+ goto release_lock;
+
+ for (nf = t->freq_tbl; nf->freq_hz != FREQ_END; nf++)
+ if (nf->freq_hz == rate)
+ break;
+
+ if (nf->freq_hz == FREQ_END) {
+ ret = -EINVAL;
+ goto release_lock;
+ }
+
+ if (t->freq_mask == 0) {
+ t->current_freq = nf;
+ goto release_lock;
+ }
+
+ /* Disable all branches before changing rate to prevent jitter. */
+ for (i = 0; chld && chld[i] != C(NONE); i++) {
+ struct clk_local *ch = &clk_local_tbl[chld[i]];
+ /* Don't bother turning off if it is already off.
+ * Checking ch->count is cheaper (cache) than reading and
+ * writing to a register (uncached/unbuffered). */
+ if (ch->count) {
+ reg_val = readl(REG(ch->ns_reg));
+ reg_val &= ~(ch->br_en_mask);
+ writel(reg_val, REG(ch->ns_reg));
+ }
+ }
+ if (t->count)
+ _soc_clk_disable(id);
+
+ /* Turn on PLL of the new freq. */
+ src_enable(nf->src);
+
+ /* Some clocks share the same register, so must be careful when
+ * assuming a register doesn't need to be re-read. */
+ reg_val = readl(ns_reg);
+ if (t->type == MND) {
+ reg_val |= MNCNTR_RST_MASK;
+ writel(reg_val, ns_reg);
+ /* TODO: Currently writing 0's into reserved bits for 8-bit
+ * MND. Can be avoided by adding md_mask. */
+ if (nf->mode)
+ writel(nf->md_val, md_reg);
+ reg_val &= ~MNCNTR_MODE_MASK;
+ reg_val |= (MNCNTR_MODE * nf->mode);
+ }
+ reg_val &= ~(t->freq_mask);
+ reg_val |= nf->ns_val;
+ writel(reg_val, ns_reg);
+
+ if (t->type == MND) {
+ reg_val &= ~MNCNTR_RST_MASK;
+ writel(reg_val, ns_reg);
+ }
+
+ /* Turn off PLL of the old freq. */
+ src_disable(cf->src);
+
+ /* Current freq must be updated before _soc_clk_enable() is called to
+ * make sure the MNCNTR_E bit is set correctly. */
+ t->current_freq = nf;
+
+ if (t->count)
+ _soc_clk_enable(id);
+ /* Enable only branches that were ON before. */
+ for (i = 0; chld && chld[i] != C(NONE); i++) {
+ struct clk_local *ch = &clk_local_tbl[chld[i]];
+ if (ch->count) {
+ reg_val = readl(REG(ch->ns_reg));
+ reg_val |= ch->br_en_mask;
+ writel(reg_val, REG(ch->ns_reg));
+ }
+ }
+
+release_lock:
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+ return ret;
+}
+
+static int soc_clk_set_min_rate(unsigned id, unsigned rate)
+{
+ return -EPERM;
+}
+
+static int soc_clk_set_max_rate(unsigned id, unsigned rate)
+{
+ return -EPERM;
+}
+
+static int soc_clk_set_flags(unsigned id, unsigned flags)
+{
+ return -EPERM;
+}
+
+static unsigned soc_clk_get_rate(unsigned id)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ unsigned long flags;
+ unsigned ret = 0;
+
+ spin_lock_irqsave(&clock_reg_lock, flags);
+ if (t->type == MND && t->type == BASIC)
+ ret = t->current_freq->freq_hz;
+ else {
+ /* Walk up the tree to see if any parent has a rate. */
+ while (t->type == NORATE && t->parent != C(NONE))
+ t = &clk_local_tbl[t->parent];
+ if (t->type == MND || t->type == BASIC)
+ ret = t->current_freq->freq_hz;
+ }
+ spin_unlock_irqrestore(&clock_reg_lock, flags);
+
+ /* Return 0 if the rate has never been set. Might not be correct,
+ * but it's good enough. */
+ if (ret == FREQ_END)
+ ret = 0;
+
+ return ret;
+}
+
+static unsigned soc_clk_is_enabled(unsigned id)
+{
+ return !!(clk_local_tbl[id].count);
+}
+
+static long soc_clk_round_rate(unsigned id, unsigned rate)
+{
+ struct clk_local *t = &clk_local_tbl[id];
+ struct clk_freq_tbl *f;
+
+ if (t->type != MND && t->type != BASIC)
+ return -EINVAL;
+
+ for (f = t->freq_tbl; f->freq_hz != FREQ_END; f++)
+ if (f->freq_hz >= rate)
+ return f->freq_hz;
+
+ return -EPERM;
+}
+
+struct clk_ops clk_ops_7x30 = {
+ .enable = soc_clk_enable,
+ .disable = soc_clk_disable,
+ .reset = soc_clk_reset,
+ .set_rate = soc_clk_set_rate,
+ .set_min_rate = soc_clk_set_min_rate,
+ .set_max_rate = soc_clk_set_max_rate,
+ .set_flags = soc_clk_set_flags,
+ .get_rate = soc_clk_get_rate,
+ .is_enabled = soc_clk_is_enabled,
+ .round_rate = soc_clk_round_rate,
+};
+
+#if 0
+static struct reg_init {
+ void *reg;
+ uint32_t mask;
+ uint32_t val;
+} ri_list[] __initdata = {
+ /* TODO: Remove next line from commercial code. */
+ {REG(PLL_ENA_REG), 0x7F, 0x7F}, /* Turn on all PLLs. */
+
+ /* Enable UMDX_P clock. Known to causes issues, so never turn off. */
+ {REG(GLBL_CLK_ENA_2_SC), B(2), B(2)},
+ {REG(0x0050), 0x3 << 17, 0x3}, /* EMDH RX div = div-4. */
+ {REG(0x008C), 0x3 << 17, 0x3}, /* PMDH RX div = div-4. */
+ /* MI2S_CODEC_RX_S src = MI2S_CODEC_RX_M. */
+ {REG(MI2S_RX_NS), B(14), 0x0},
+ /* MI2S_CODEC_TX_S src = MI2S_CODEC_TX_M. */
+ {REG(MI2S_TX_NS), B(14), 0x0},
+ {REG(MI2S_NS), B(14), 0x0}, /* MI2S_S src = MI2S_M. */
+ {REG(LPA_NS), B(4), B(4)}, /* LPA CORE src = LPA_CODEC. */
+ {REG(0x02EC), 0xF, 0xD}, /* MI2S_CODEC_RX_S div = div-8. */
+ {REG(0x02F0), 0xF, 0xD}, /* MI2S_CODEC_TX_S div = div-8. */
+ {REG(0x02E4), 0xF, 0x3}, /* MI2S_S div = div-4. */
+ {REG(MDC_NS), 0x3, 0x3}, /* MDC src = external MDH src. */
+ {REG(SDAC_NS), 0x3 << 14, 0x0}, /* SDAC div = div-1. */
+ /* Disable sources TCXO/5 & TCXO/6. UART1 src = TCXO*/
+ {REG(0x00E0), 0x3 << 25 | 0x7, 0x0},
+ {REG(0x0468), 0x7, 0x0}, /* UART3 src = TCXO. */
+ {REG(MDP_VSYNC_REG), 0xC, 0x4}, /* MDP VSYNC src = LPXO. */
+
+ /* USBH core clocks src = USB_HS_SRC. */
+ {REG(USBH_NS), B(15), B(15)},
+ {REG(USBH2_NS), B(6), B(6)},
+ {REG(USBH3_NS), B(6), B(6)},
+};
+
+#define set_1rate(clk) \
+ soc_clk_set_rate(C(clk), clk_local_tbl[C(clk)].freq_tbl->freq_hz)
+static __init int soc_clk_init(void)
+{
+ int i;
+ uint32_t val;
+
+ /* Disable all the child clocks of USB_HS_SRC. This needs to be done
+ * before the register init loop since it changes the source of the
+ * USB HS core clocks. */
+ for (i = 0; chld_usb_src[i] != C(NONE); i++)
+ _soc_clk_disable(chld_usb_src[i]);
+
+ soc_clk_set_rate(C(USB_HS_SRC), clk_tbl_usb[0].freq_hz);
+
+ for (i = 0; i < ARRAY_SIZE(ri_list); i++) {
+ val = readl(ri_list[i].reg);
+ val &= ~ri_list[i].mask;
+ val |= ri_list[i].val;
+ writel(val, ri_list[i].reg);
+ }
+
+ /* This is just to update the driver data structures. The actual
+ * register set up is taken care of in the register init loop. */
+ set_1rate(I2C);
+ set_1rate(I2C_2);
+ set_1rate(QUP_I2C);
+ set_1rate(UART1);
+ set_1rate(UART3);
+
+ return 0;
+}
+
+arch_initcall(soc_clk_init);
+#endif
diff --git a/arch/arm/mach-msm/clock-7x30.h b/arch/arm/mach-msm/clock-7x30.h
new file mode 100644
index 000000000000..7480ace1a986
--- /dev/null
+++ b/arch/arm/mach-msm/clock-7x30.h
@@ -0,0 +1,143 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_7X30_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_7X30_H
+
+enum {
+ L_7X30_NONE_CLK = -1,
+ L_7X30_ADM_CLK,
+ L_7X30_I2C_CLK,
+ L_7X30_I2C_2_CLK,
+ L_7X30_QUP_I2C_CLK,
+ L_7X30_UART1DM_CLK,
+ L_7X30_UART1DM_P_CLK,
+ L_7X30_UART2DM_CLK,
+ L_7X30_UART2DM_P_CLK,
+ L_7X30_EMDH_CLK,
+ L_7X30_EMDH_P_CLK,
+ L_7X30_PMDH_CLK,
+ L_7X30_PMDH_P_CLK,
+ L_7X30_GRP_2D_CLK,
+ L_7X30_GRP_2D_P_CLK,
+ L_7X30_GRP_3D_SRC_CLK,
+ L_7X30_GRP_3D_CLK,
+ L_7X30_GRP_3D_P_CLK,
+ L_7X30_IMEM_CLK,
+ L_7X30_SDC1_CLK,
+ L_7X30_SDC1_H_CLK,
+ L_7X30_SDC2_CLK,
+ L_7X30_SDC2_H_CLK,
+ L_7X30_SDC3_CLK,
+ L_7X30_SDC3_H_CLK,
+ L_7X30_SDC4_CLK,
+ L_7X30_SDC4_H_CLK,
+ L_7X30_MDP_CLK,
+ L_7X30_MDP_P_CLK,
+ L_7X30_MDP_LCDC_P_CLK,
+ L_7X30_MDP_LCDC_PAD_P_CLK,
+ L_7X30_MDP_VSYNC_CLK,
+ L_7X30_MI2S_CODEC_RX_M_CLK,
+ L_7X30_MI2S_CODEC_RX_S_CLK,
+ L_7X30_MI2S_CODEC_TX_M_CLK,
+ L_7X30_MI2S_CODEC_TX_S_CLK,
+ L_7X30_MI2S_M_CLK,
+ L_7X30_MI2S_S_CLK,
+ L_7X30_LPA_CODEC_CLK,
+ L_7X30_LPA_CORE_CLK,
+ L_7X30_LPA_P_CLK,
+ L_7X30_MIDI_CLK,
+ L_7X30_MDC_CLK,
+ L_7X30_ROTATOR_IMEM_CLK,
+ L_7X30_ROTATOR_P_CLK,
+ L_7X30_SDAC_M_CLK,
+ L_7X30_SDAC_S_CLK,
+ L_7X30_UART1_CLK,
+ L_7X30_UART3_CLK,
+ L_7X30_TV_CLK,
+ L_7X30_TV_DAC_CLK,
+ L_7X30_TV_ENC_CLK,
+ L_7X30_TSIF_REF_CLK,
+ L_7X30_TSIF_P_CLK,
+ L_7X30_USB_HS_SRC_CLK,
+ L_7X30_USB_HS_CLK,
+ L_7X30_USB_HS_CORE_CLK,
+ L_7X30_USB_HS_P_CLK,
+ L_7X30_USB_HS2_CLK,
+ L_7X30_USB_HS2_CORE_CLK,
+ L_7X30_USB_HS2_P_CLK,
+ L_7X30_USB_HS3_CLK,
+ L_7X30_USB_HS3_CORE_CLK,
+ L_7X30_USB_HS3_P_CLK,
+ L_7X30_VFE_CLK,
+ L_7X30_VFE_P_CLK,
+ L_7X30_VFE_MDC_CLK,
+ L_7X30_VFE_CAMIF_CLK,
+ L_7X30_CAMIF_PAD_P_CLK,
+ L_7X30_CAM_CLK,
+ L_7X30_JPEG_CLK,
+ L_7X30_JPEG_P_CLK,
+ L_7X30_VPE_CLK,
+ L_7X30_MFC_CLK,
+ L_7X30_MFC_P_CLK,
+ L_7X30_SPI_CLK,
+ L_7X30_SPI_P_CLK,
+
+ L_7X30_AXI_LI_VG_CLK,
+ L_7X30_AXI_LI_GRP_CLK,
+ L_7X30_AXI_LI_JPEG_CLK,
+ L_7X30_AXI_GRP_2D_CLK,
+ L_7X30_AXI_MFC_CLK,
+ L_7X30_AXI_VPE_CLK,
+ L_7X30_AXI_LI_VFE_CLK,
+ L_7X30_AXI_LI_APPS_CLK,
+ L_7X30_AXI_MDP_CLK,
+ L_7X30_AXI_IMEM_CLK,
+ L_7X30_AXI_LI_ADSP_A_CLK,
+ L_7X30_AXI_ROTATOR_CLK,
+
+ L_7X30_NR_CLKS
+};
+
+struct clk_ops;
+extern struct clk_ops clk_ops_7x30;
+
+void pll_enable(uint32_t pll);
+void pll_disable(uint32_t pll);
+
+#define CLK_7X30(clk_name, clk_id, clk_dev, clk_flags) { \
+ .name = clk_name, \
+ .id = L_7X30_##clk_id, \
+ .ops = &clk_ops_7x30, \
+ .flags = clk_flags, \
+ .dev = clk_dev, \
+ .dbg_name = #clk_id, \
+ }
+
+#endif
+
diff --git a/arch/arm/mach-msm/clock-pcom.c b/arch/arm/mach-msm/clock-pcom.c
new file mode 100644
index 000000000000..e4997254a279
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pcom.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, 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/err.h>
+#include <linux/ctype.h>
+#include <linux/stddef.h>
+#include <mach/clk.h>
+
+#include "proc_comm.h"
+#include "clock.h"
+
+/*
+ * glue for the proc_comm interface
+ */
+int pc_clk_enable(unsigned id)
+{
+ int rc = msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+void pc_clk_disable(unsigned id)
+{
+ msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
+}
+
+int pc_clk_reset(unsigned id, enum clk_reset_action action)
+{
+ int rc;
+
+ if (action == CLK_RESET_ASSERT)
+ rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_ASSERT, &id, NULL);
+ else
+ rc = msm_proc_comm(PCOM_CLKCTL_RPC_RESET_DEASSERT, &id, NULL);
+
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+int pc_clk_set_rate(unsigned id, unsigned rate)
+{
+ /* The rate _might_ be rounded off to the nearest KHz value by the
+ * remote function. So a return value of 0 doesn't necessarily mean
+ * that the exact rate was set successfully.
+ */
+ int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+int pc_clk_set_min_rate(unsigned id, unsigned rate)
+{
+ int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate);
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+int pc_clk_set_max_rate(unsigned id, unsigned rate)
+{
+ int rc = msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate);
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+int pc_clk_set_flags(unsigned id, unsigned flags)
+{
+ int rc = msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
+ if (rc < 0)
+ return rc;
+ else
+ return (int)id < 0 ? -EINVAL : 0;
+}
+
+unsigned pc_clk_get_rate(unsigned id)
+{
+ if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
+ return 0;
+ else
+ return id;
+}
+
+unsigned pc_clk_is_enabled(unsigned id)
+{
+ if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
+ return 0;
+ else
+ return id;
+}
+
+long pc_clk_round_rate(unsigned id, unsigned rate)
+{
+
+ /* Not supported. */
+ return -EPERM;
+}
+
+struct clk_ops clk_ops_pcom = {
+ .enable = pc_clk_enable,
+ .disable = pc_clk_disable,
+ .reset = pc_clk_reset,
+ .set_rate = pc_clk_set_rate,
+ .set_min_rate = pc_clk_set_min_rate,
+ .set_max_rate = pc_clk_set_max_rate,
+ .set_flags = pc_clk_set_flags,
+ .get_rate = pc_clk_get_rate,
+ .is_enabled = pc_clk_is_enabled,
+ .round_rate = pc_clk_round_rate,
+};
diff --git a/arch/arm/mach-msm/clock-pcom.h b/arch/arm/mach-msm/clock-pcom.h
new file mode 100644
index 000000000000..39a2976ae56b
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pcom.h
@@ -0,0 +1,147 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_PCOM_H
+
+/* clock IDs used by the modem processor */
+
+#define P_ACPU_CLK 0 /* Applications processor clock */
+#define P_ADM_CLK 1 /* Applications data mover clock */
+#define P_ADSP_CLK 2 /* ADSP clock */
+#define P_EBI1_CLK 3 /* External bus interface 1 clock */
+#define P_EBI2_CLK 4 /* External bus interface 2 clock */
+#define P_ECODEC_CLK 5 /* External CODEC clock */
+#define P_EMDH_CLK 6 /* External MDDI host clock */
+#define P_GP_CLK 7 /* General purpose clock */
+#define P_GRP_CLK 8 /* Graphics clock */
+#define P_I2C_CLK 9 /* I2C clock */
+#define P_ICODEC_RX_CLK 10 /* Internal CODEX RX clock */
+#define P_ICODEC_TX_CLK 11 /* Internal CODEX TX clock */
+#define P_IMEM_CLK 12 /* Internal graphics memory clock */
+#define P_MDC_CLK 13 /* MDDI client clock */
+#define P_MDP_CLK 14 /* Mobile display processor clock */
+#define P_PBUS_CLK 15 /* Peripheral bus clock */
+#define P_PCM_CLK 16 /* PCM clock */
+#define P_PMDH_CLK 17 /* Primary MDDI host clock */
+#define P_SDAC_CLK 18 /* Stereo DAC clock */
+#define P_SDC1_CLK 19 /* Secure Digital Card clocks */
+#define P_SDC1_PCLK 20
+#define P_SDC2_CLK 21
+#define P_SDC2_PCLK 22
+#define P_SDC3_CLK 23
+#define P_SDC3_PCLK 24
+#define P_SDC4_CLK 25
+#define P_SDC4_PCLK 26
+#define P_TSIF_CLK 27 /* Transport Stream Interface clocks */
+#define P_TSIF_REF_CLK 28
+#define P_TV_DAC_CLK 29 /* TV clocks */
+#define P_TV_ENC_CLK 30
+#define P_UART1_CLK 31 /* UART clocks */
+#define P_UART2_CLK 32
+#define P_UART3_CLK 33
+#define P_UART1DM_CLK 34
+#define P_UART2DM_CLK 35
+#define P_USB_HS_CLK 36 /* High speed USB core clock */
+#define P_USB_HS_PCLK 37 /* High speed USB pbus clock */
+#define P_USB_OTG_CLK 38 /* Full speed USB clock */
+#define P_VDC_CLK 39 /* Video controller clock */
+#if CONFIG_MSM_AMSS_VERSION >= 6350
+#define P_VFE_MDC_CLK 40 /* Camera / Video Front End clock */
+#define P_VFE_CLK 41 /* VFE MDDI client clock */
+#else/* For radio code base others */
+#define P_VFE_MDC_CLK 41 /* VFE MDDI client clock */
+#define P_VFE_CLK 40 /* Camera / Video Front End clock */
+#endif
+
+#define P_MDP_LCDC_PCLK_CLK 42
+#define P_MDP_LCDC_PAD_PCLK_CLK 43
+#define P_MDP_VSYNC_CLK 44
+#define P_SPI_CLK 45
+#define P_VFE_AXI_CLK 46
+#define P_USB_HS2_CLK 47 /* High speed USB 2 core clock */
+#define P_USB_HS2_PCLK 48 /* High speed USB 2 pbus clock */
+#define P_USB_HS3_CLK 49 /* High speed USB 3 core clock */
+#define P_USB_HS3_PCLK 50 /* High speed USB 3 pbus clock */
+#define P_GRP_PCLK 51 /* Graphics pbus clock */
+#define P_USB_PHY_CLK 52 /* USB PHY clock */
+#define P_USB_HS_CORE_CLK 53 /* High speed USB 1 core clock */
+#define P_USB_HS2_CORE_CLK 54 /* High speed USB 2 core clock */
+#define P_USB_HS3_CORE_CLK 55 /* High speed USB 3 core clock */
+#define P_CAM_MCLK_CLK 56
+#define P_CAMIF_PAD_PCLK 57
+#define P_GRP_2D_CLK 58
+#define P_GRP_2D_PCLK 59
+#define P_I2S_CLK 60
+#define P_JPEG_CLK 61
+#define P_JPEG_PCLK 62
+#define P_LPA_CODEC_CLK 63
+#define P_LPA_CORE_CLK 64
+#define P_LPA_PCLK 65
+#define P_MDC_IO_CLK 66
+#define P_MDC_PCLK 67
+#define P_MFC_CLK 68
+#define P_MFC_DIV2_CLK 69
+#define P_MFC_PCLK 70
+#define P_QUP_I2C_CLK 71
+#define P_ROTATOR_IMEM_CLK 72
+#define P_ROTATOR_PCLK 73
+#define P_VFE_CAMIF_CLK 74
+#define P_VFE_PCLK 75
+#define P_VPE_CLK 76
+#define P_I2C_2_CLK 77
+#define P_MI2S_CODEC_RX_SCLK 78
+#define P_MI2S_CODEC_RX_MCLK 79
+#define P_MI2S_CODEC_TX_SCLK 80
+#define P_MI2S_CODEC_TX_MCLK 81
+#define P_PMDH_PCLK 82
+#define P_EMDH_PCLK 83
+#define P_SPI_PCLK 84
+#define P_TSIF_PCLK 85
+#define P_MDP_PCLK 86
+#define P_SDAC_MCLK 87
+#define P_MI2S_HDMI_CLK 88
+#define P_MI2S_HDMI_MCLK 89
+#define P_AXI_ROTATOR_CLK 90
+#define P_HDMI_CLK 91
+
+#define P_NR_CLKS 92
+
+struct clk_ops;
+extern struct clk_ops clk_ops_pcom;
+
+#define CLK_PCOM(clk_name, clk_id, clk_dev, clk_flags) { \
+ .name = clk_name, \
+ .id = P_##clk_id, \
+ .ops = &clk_ops_pcom, \
+ .flags = clk_flags, \
+ .dev = clk_dev, \
+ .dbg_name = #clk_id, \
+ }
+
+#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 3b1ce36f1032..c7622f9c2169 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/clock.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007 QUALCOMM Incorporated
+ * Copyright (c) 2007-2009, 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
@@ -22,68 +22,28 @@
#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 "clock.h"
#include "proc_comm.h"
static DEFINE_MUTEX(clocks_mutex);
static DEFINE_SPINLOCK(clocks_lock);
+static DEFINE_SPINLOCK(ebi1_vote_lock);
static LIST_HEAD(clocks);
+struct clk *msm_clocks;
+unsigned msm_num_clocks;
/*
- * glue for the proc_comm interface
+ * Bitmap of enabled clocks, excluding ACPU which is always
+ * enabled
*/
-static inline int pc_clk_enable(unsigned id)
-{
- return msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
-}
-
-static inline void pc_clk_disable(unsigned id)
-{
- msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
-}
-
-static inline int pc_clk_set_rate(unsigned id, unsigned rate)
-{
- return msm_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
-}
-
-static inline int pc_clk_set_min_rate(unsigned id, unsigned rate)
-{
- return msm_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate);
-}
-
-static inline int pc_clk_set_max_rate(unsigned id, unsigned rate)
-{
- return msm_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate);
-}
-
-static inline int pc_clk_set_flags(unsigned id, unsigned flags)
-{
- return msm_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
-}
-
-static inline unsigned pc_clk_get_rate(unsigned id)
-{
- if (msm_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
- return 0;
- else
- return id;
-}
-
-static inline unsigned pc_clk_is_enabled(unsigned id)
-{
- if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
- return 0;
- else
- return id;
-}
-
-static inline int pc_pll_request(unsigned id, unsigned on)
-{
- on = !!on;
- return msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
-}
+static DECLARE_BITMAP(clock_map_enabled, NR_CLKS);
+static DEFINE_SPINLOCK(clock_map_lock);
+static struct notifier_block axi_freq_notifier_block;
/*
* Standard clock functions defined in include/linux/clk.h
@@ -119,8 +79,12 @@ int clk_enable(struct clk *clk)
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
clk->count++;
- if (clk->count == 1)
- pc_clk_enable(clk->id);
+ 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;
}
@@ -132,31 +96,52 @@ void clk_disable(struct clk *clk)
spin_lock_irqsave(&clocks_lock, flags);
BUG_ON(clk->count == 0);
clk->count--;
- if (clk->count == 0)
- pc_clk_disable(clk->id);
+ 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)
+{
+ return clk->ops->reset(clk->id, action);
+}
+EXPORT_SYMBOL(clk_reset);
+
unsigned long clk_get_rate(struct clk *clk)
{
- return pc_clk_get_rate(clk->id);
+ return clk->ops->get_rate(clk->id);
}
EXPORT_SYMBOL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- int ret;
- if (clk->flags & CLKFLAG_USE_MIN_MAX_TO_SET) {
- ret = pc_clk_set_max_rate(clk->id, rate);
- if (ret)
- return ret;
- return pc_clk_set_min_rate(clk->id, rate);
- }
- return pc_clk_set_rate(clk->id, rate);
+ return clk->ops->set_rate(clk->id, rate);
}
EXPORT_SYMBOL(clk_set_rate);
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return clk->ops->round_rate(clk->id, rate);
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_min_rate(struct clk *clk, unsigned long rate)
+{
+ return clk->ops->set_min_rate(clk->id, rate);
+}
+EXPORT_SYMBOL(clk_set_min_rate);
+
+int clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+ return clk->ops->set_max_rate(clk->id, rate);
+}
+EXPORT_SYMBOL(clk_set_max_rate);
+
int clk_set_parent(struct clk *clk, struct clk *parent)
{
return -ENOSYS;
@@ -173,22 +158,231 @@ int clk_set_flags(struct clk *clk, unsigned long flags)
{
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
- return pc_clk_set_flags(clk->id, flags);
+ return clk->ops->set_flags(clk->id, flags);
}
EXPORT_SYMBOL(clk_set_flags);
+/* EBI1 is the only shared clock that several clients want to vote on as of
+ * this commit. If this changes in the future, then it might be better to
+ * make clk_min_rate handle the voting or make ebi1_clk_set_min_rate more
+ * generic to support different clocks.
+ */
+static unsigned long ebi1_min_rate[CLKVOTE_MAX];
+static struct clk *ebi1_clk;
+
+/* Rate is in Hz to be consistent with the other clk APIs. */
+int ebi1_clk_set_min_rate(enum clkvote_client client, unsigned long rate)
+{
+ static unsigned long last_set_val = -1;
+ unsigned long new_val;
+ unsigned long flags;
+ int ret = 0, i;
+
+ spin_lock_irqsave(&ebi1_vote_lock, flags);
+
+ ebi1_min_rate[client] = (rate == MSM_AXI_MAX_FREQ) ?
+ (clk_get_max_axi_khz() * 1000) : rate;
+
+ new_val = ebi1_min_rate[0];
+ for (i = 1; i < CLKVOTE_MAX; i++)
+ if (ebi1_min_rate[i] > new_val)
+ new_val = ebi1_min_rate[i];
+
+ /* This check is to save a proc_comm call. */
+ if (last_set_val != new_val) {
+ ret = clk_set_min_rate(ebi1_clk, new_val);
+ if (ret < 0) {
+ pr_err("Setting EBI1 min rate to %lu Hz failed!\n",
+ new_val);
+ pr_err("Last successful value was %lu Hz.\n",
+ last_set_val);
+ } else {
+ last_set_val = new_val;
+ }
+ }
-void __init msm_clock_init(void)
+ spin_unlock_irqrestore(&ebi1_vote_lock, flags);
+
+ return ret;
+}
+
+static int axi_freq_notifier_handler(struct notifier_block *block,
+ unsigned long min_freq, void *v)
+{
+ /* convert min_freq from KHz to Hz, unless it's a magic value */
+ if (min_freq != MSM_AXI_MAX_FREQ)
+ min_freq *= 1000;
+
+ return ebi1_clk_set_min_rate(CLKVOTE_PMQOS, min_freq);
+}
+
+/*
+ * Find out whether any clock is enabled that needs the TCXO clock.
+ *
+ * On exit, the buffer 'reason' holds a bitmap of ids of all enabled
+ * clocks found that require TCXO.
+ *
+ * reason: buffer to hold the bitmap; must be compatible with
+ * linux/bitmap.h
+ * nbits: number of bits that the buffer can hold; 0 is ok
+ *
+ * Return value:
+ * 0: does not require the TCXO clock
+ * 1: requires the TCXO clock
+ */
+int msm_clock_require_tcxo(unsigned long *reason, int nbits)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&clock_map_lock, flags);
+ ret = !bitmap_empty(clock_map_enabled, NR_CLKS);
+ if (nbits > 0)
+ bitmap_copy(reason, clock_map_enabled, min(nbits, NR_CLKS));
+ spin_unlock_irqrestore(&clock_map_lock, flags);
+
+ return ret;
+}
+
+/*
+ * Find the clock matching the given id and copy its name to the
+ * provided buffer.
+ *
+ * Return value:
+ * -ENODEV: there is no clock matching the given id
+ * 0: success
+ */
+int msm_clock_get_name(uint32_t id, char *name, uint32_t size)
+{
+ struct clk *c_clk;
+ int ret = -ENODEV;
+
+ mutex_lock(&clocks_mutex);
+ list_for_each_entry(c_clk, &clocks, list) {
+ if (id == c_clk->id) {
+ strlcpy(name, c_clk->name, size);
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+
+void __init msm_clock_init(struct clk *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++)
list_add_tail(&msm_clocks[n].list, &clocks);
mutex_unlock(&clocks_mutex);
+
+ ebi1_clk = clk_get(NULL, "ebi1_clk");
+ BUG_ON(ebi1_clk == NULL);
+
+ axi_freq_notifier_block.notifier_call = axi_freq_notifier_handler;
+ pm_qos_add_notifier(PM_QOS_SYSTEM_BUS_FREQ, &axi_freq_notifier_block);
+
+}
+
+#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;
+}
+
+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");
+
+static int __init clock_debug_init(void)
+{
+ struct dentry *dent_rate;
+ struct dentry *dent_enable;
+ 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);
+
+ 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);
+ }
+ 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.
@@ -205,7 +399,7 @@ static int __init clock_late_init(void)
spin_lock_irqsave(&clocks_lock, flags);
if (!clk->count) {
count++;
- pc_clk_disable(clk->id);
+ clk->ops->disable(clk->id);
}
spin_unlock_irqrestore(&clocks_lock, flags);
}
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index f875e1544e5f..9608a6c6bbcb 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/clock.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007 QUALCOMM Incorporated
+ * Copyright (c) 2007-2009, 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
@@ -18,6 +18,10 @@
#define __ARCH_ARM_MACH_MSM_CLOCK_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
@@ -25,14 +29,30 @@
#define CLKFLAG_NORESET 0x00000008
#define CLK_FIRST_AVAILABLE_FLAG 0x00000100
-#define CLKFLAG_USE_MIN_MAX_TO_SET 0x00000200
-#define CLKFLAG_AUTO_OFF 0x00000400
+#define CLKFLAG_AUTO_OFF 0x00000200
+#define CLKFLAG_MIN 0x00000400
+#define CLKFLAG_MAX 0x00000800
+
+struct clk_ops {
+ int (*enable)(unsigned id);
+ void (*disable)(unsigned id);
+ int (*reset)(unsigned id, enum clk_reset_action action);
+ int (*set_rate)(unsigned id, unsigned rate);
+ int (*set_min_rate)(unsigned id, unsigned rate);
+ int (*set_max_rate)(unsigned id, unsigned rate);
+ int (*set_flags)(unsigned id, unsigned flags);
+ unsigned (*get_rate)(unsigned id);
+ unsigned (*is_enabled)(unsigned id);
+ long (*round_rate)(unsigned id, unsigned rate);
+};
struct clk {
uint32_t 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;
};
@@ -41,8 +61,47 @@ struct clk {
#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
-extern struct clk msm_clocks[];
-extern unsigned msm_num_clocks;
+#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);
#endif
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
new file mode 100644
index 000000000000..8c20add08267
--- /dev/null
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -0,0 +1,126 @@
+/* arch/arm/mach-msm/cpufreq.c
+ *
+ * MSM architecture cpufreq driver
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: Mike A. Chan <mikechan@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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include "acpuclock.h"
+
+#define dprintk(msg...) \
+ cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-msm", msg)
+
+#ifdef CONFIG_MSM_CPU_FREQ_SCREEN
+static void msm_early_suspend(struct early_suspend *handler)
+{
+ acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_OFF * 1000, SETRATE_CPUFREQ);
+}
+
+static void msm_late_resume(struct early_suspend *handler)
+{
+ acpuclk_set_rate(CONFIG_MSM_CPU_FREQ_SCREEN_ON * 1000, SETRATE_CPUFREQ);
+}
+
+static struct early_suspend msm_power_suspend = {
+ .suspend = msm_early_suspend,
+ .resume = msm_late_resume,
+};
+
+static int __init clock_late_init(void)
+{
+ register_early_suspend(&msm_power_suspend);
+ return 0;
+}
+
+late_initcall(clock_late_init);
+#elif defined(CONFIG_CPU_FREQ_MSM)
+
+static int msm_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int index;
+ int ret = 0;
+ struct cpufreq_freqs freqs;
+ struct cpufreq_frequency_table *table =
+ cpufreq_frequency_get_table(smp_processor_id());
+
+ if (cpufreq_frequency_table_target(policy, table, target_freq, relation,
+ &index)) {
+ pr_err("cpufreq: invalid target_freq: %d\n", target_freq);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ dprintk("target %d r %d (%d-%d) selected %d\n", target_freq,
+ relation, policy->min, policy->max, table[index].frequency);
+#endif
+ freqs.old = policy->cur;
+ freqs.new = table[index].frequency;
+ freqs.cpu = smp_processor_id();
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ ret = acpuclk_set_rate(table[index].frequency * 1000, SETRATE_CPUFREQ);
+ if (!ret)
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ return ret;
+}
+
+static int msm_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static int __init msm_cpufreq_init(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *table =
+ cpufreq_frequency_get_table(smp_processor_id());
+
+ policy->cur = acpuclk_get_rate();
+ if (cpufreq_frequency_table_cpuinfo(policy, table)) {
+#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
+ policy->cpuinfo.min_freq = CONFIG_MSM_CPU_FREQ_MIN;
+ policy->cpuinfo.max_freq = CONFIG_MSM_CPU_FREQ_MAX;
+#endif
+ }
+#ifdef CONFIG_MSM_CPU_FREQ_SET_MIN_MAX
+ policy->min = CONFIG_MSM_CPU_FREQ_MIN;
+ policy->max = CONFIG_MSM_CPU_FREQ_MAX;
+#endif
+
+ policy->cpuinfo.transition_latency =
+ acpuclk_get_switch_time() * NSEC_PER_USEC;
+ return 0;
+}
+
+static struct cpufreq_driver msm_cpufreq_driver = {
+ /* lps calculations are handled here. */
+ .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
+ .init = msm_cpufreq_init,
+ .verify = msm_cpufreq_verify,
+ .target = msm_cpufreq_target,
+ .name = "msm",
+};
+
+static int __init msm_cpufreq_register(void)
+{
+ return cpufreq_register_driver(&msm_cpufreq_driver);
+}
+
+late_initcall(msm_cpufreq_register);
+#endif
diff --git a/arch/arm/mach-msm/dal.c b/arch/arm/mach-msm/dal.c
new file mode 100644
index 000000000000..cefe03c5eb24
--- /dev/null
+++ b/arch/arm/mach-msm/dal.c
@@ -0,0 +1,1363 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * Device access library (DAL) implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+
+#include <mach/dal.h>
+#include <mach/msm_smd.h>
+
+#define DALRPC_PROTOCOL_VERSION 0x11
+#define DALRPC_SUCCESS 0
+#define DALRPC_MAX_PORTNAME_LEN 64
+#define DALRPC_MAX_ATTACH_PARAM_LEN 64
+#define DALRPC_MAX_SERVICE_NAME_LEN 32
+#define DALRPC_MAX_PARAMS 128
+#define DALRPC_MAX_PARAMS_SIZE (DALRPC_MAX_PARAMS * 4)
+#define DALRPC_MAX_MSG_SIZE (sizeof(struct dalrpc_msg_hdr) + \
+ DALRPC_MAX_PARAMS_SIZE)
+#define DALRPC_MSGID_DDI 0x0
+#define DALRPC_MSGID_DDI_REPLY 0x80
+#define DALRPC_MSGID_ATTACH_REPLY 0x81
+#define DALRPC_MSGID_DETACH_REPLY 0x82
+#define DALRPC_MSGID_ASYNCH 0xC0
+#define ROUND_BUFLEN(x) (((x + 3) & ~0x3))
+
+struct dalrpc_msg_hdr {
+ uint32_t len:16;
+ uint32_t proto_ver:8;
+ uint32_t prio:7;
+ uint32_t async:1;
+ uint32_t ddi_idx:16;
+ uint32_t proto_id:8;
+ uint32_t msgid:8;
+ void *from;
+ void *to;
+};
+
+struct dalrpc_msg {
+ struct dalrpc_msg_hdr hdr;
+ uint32_t param[DALRPC_MAX_PARAMS];
+};
+
+struct dalrpc_event_handle {
+ struct list_head list;
+
+ int flag;
+ spinlock_t lock;
+};
+
+struct dalrpc_cb_handle {
+ struct list_head list;
+
+ void (*fn)(void *, uint32_t, void *, uint32_t);
+ void *context;
+};
+
+struct daldevice_handle {;
+ struct list_head list;
+
+ void *remote_handle;
+ struct completion read_completion;
+ struct dalrpc_port *port;
+ struct dalrpc_msg msg;
+ struct mutex client_lock;
+};
+
+struct dalrpc_port {
+ struct list_head list;
+
+ char port[DALRPC_MAX_PORTNAME_LEN+1];
+ int refcount;
+
+ struct workqueue_struct *wq;
+ struct work_struct port_work;
+ struct mutex write_lock;
+
+ smd_channel_t *ch;
+
+ struct dalrpc_msg msg_in;
+ struct daldevice_handle *msg_owner;
+ unsigned msg_bytes_read;
+
+ struct list_head event_list;
+ struct mutex event_list_lock;
+
+ struct list_head cb_list;
+ struct mutex cb_list_lock;
+};
+
+static LIST_HEAD(port_list);
+static LIST_HEAD(client_list);
+static DEFINE_MUTEX(pc_lists_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(event_wq);
+
+static int client_exists(void *handle)
+{
+ struct daldevice_handle *h;
+
+ if (!handle)
+ return 0;
+
+ mutex_lock(&pc_lists_lock);
+
+ list_for_each_entry(h, &client_list, list)
+ if (h == handle) {
+ mutex_unlock(&pc_lists_lock);
+ return 1;
+ }
+
+ mutex_unlock(&pc_lists_lock);
+
+ return 0;
+}
+
+static int client_exists_locked(void *handle)
+{
+ struct daldevice_handle *h;
+
+ /* this function must be called with pc_lists_lock acquired */
+
+ if (!handle)
+ return 0;
+
+ list_for_each_entry(h, &client_list, list)
+ if (h == handle)
+ return 1;
+
+ return 0;
+}
+
+static int port_exists(struct dalrpc_port *p)
+{
+ struct dalrpc_port *p_iter;
+
+ /* this function must be called with pc_lists_lock acquired */
+
+ if (!p)
+ return 0;
+
+ list_for_each_entry(p_iter, &port_list, list)
+ if (p_iter == p)
+ return 1;
+
+ return 0;
+}
+
+static struct dalrpc_port *port_name_exists(char *port)
+{
+ struct dalrpc_port *p;
+
+ /* this function must be called with pc_lists_lock acquired */
+
+ list_for_each_entry(p, &port_list, list)
+ if (!strcmp(p->port, port))
+ return p;
+
+ return NULL;
+}
+
+static void port_close(struct dalrpc_port *p)
+{
+ mutex_lock(&pc_lists_lock);
+
+ p->refcount--;
+ if (p->refcount == 0)
+ list_del(&p->list);
+
+ mutex_unlock(&pc_lists_lock);
+
+ if (p->refcount == 0) {
+ destroy_workqueue(p->wq);
+ smd_close(p->ch);
+ kfree(p);
+ }
+}
+
+static int event_exists(struct dalrpc_port *p,
+ struct dalrpc_event_handle *ev)
+{
+ struct dalrpc_event_handle *ev_iter;
+
+ /* this function must be called with event_list_lock acquired */
+
+ list_for_each_entry(ev_iter, &p->event_list, list)
+ if (ev_iter == ev)
+ return 1;
+
+ return 0;
+}
+
+static int cb_exists(struct dalrpc_port *p,
+ struct dalrpc_cb_handle *cb)
+{
+ struct dalrpc_cb_handle *cb_iter;
+
+ /* this function must be called with the cb_list_lock acquired */
+
+ list_for_each_entry(cb_iter, &p->cb_list, list)
+ if (cb_iter == cb)
+ return 1;
+
+ return 0;
+}
+
+static int check_version(struct dalrpc_msg_hdr *msg_hdr)
+{
+ static int version_msg = 1;
+
+ /* disabled because asynch events currently have no version */
+ return 0;
+
+ if (msg_hdr->proto_ver != DALRPC_PROTOCOL_VERSION) {
+ if (version_msg) {
+ printk(KERN_ERR "dalrpc: incompatible verison\n");
+ version_msg = 0;
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static void process_asynch(struct dalrpc_port *p)
+{
+ struct dalrpc_event_handle *ev;
+ struct dalrpc_cb_handle *cb;
+
+ ev = (struct dalrpc_event_handle *)p->msg_in.param[0];
+ cb = (struct dalrpc_cb_handle *)p->msg_in.param[0];
+
+ mutex_lock(&p->event_list_lock);
+ if (event_exists(p, ev)) {
+ spin_lock(&ev->lock);
+ ev->flag = 1;
+ spin_unlock(&ev->lock);
+ smp_mb();
+ wake_up_all(&event_wq);
+ mutex_unlock(&p->event_list_lock);
+ return;
+ }
+ mutex_unlock(&p->event_list_lock);
+
+ mutex_lock(&p->cb_list_lock);
+ if (cb_exists(p, cb)) {
+ cb->fn(cb->context, p->msg_in.param[1],
+ &p->msg_in.param[3], p->msg_in.param[2]);
+ mutex_unlock(&p->cb_list_lock);
+ return;
+ }
+ mutex_unlock(&p->cb_list_lock);
+}
+
+static void process_msg(struct dalrpc_port *p)
+{
+ switch (p->msg_in.hdr.msgid) {
+
+ case DALRPC_MSGID_DDI_REPLY:
+ case DALRPC_MSGID_ATTACH_REPLY:
+ case DALRPC_MSGID_DETACH_REPLY:
+ complete(&p->msg_owner->read_completion);
+ break;
+
+ case DALRPC_MSGID_ASYNCH:
+ process_asynch(p);
+ break;
+
+ default:
+ printk(KERN_ERR "process_msg: bad msgid %#x\n",
+ p->msg_in.hdr.msgid);
+ }
+}
+
+static void flush_msg(struct dalrpc_port *p)
+{
+ int bytes_read, len;
+
+ len = p->msg_in.hdr.len - sizeof(struct dalrpc_msg_hdr);
+ while (len > 0) {
+ bytes_read = smd_read(p->ch, NULL, len);
+ if (bytes_read <= 0)
+ break;
+ len -= bytes_read;
+ }
+ p->msg_bytes_read = 0;
+}
+
+static int check_header(struct dalrpc_port *p)
+{
+ if (check_version(&p->msg_in.hdr) ||
+ p->msg_in.hdr.len > DALRPC_MAX_MSG_SIZE ||
+ (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH &&
+ !client_exists_locked(p->msg_in.hdr.to))) {
+ printk(KERN_ERR "dalrpc_read_msg: bad msg\n");
+ flush_msg(p);
+ return 1;
+ }
+ p->msg_owner = (struct daldevice_handle *)p->msg_in.hdr.to;
+
+ if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
+ memcpy(&p->msg_owner->msg.hdr, &p->msg_in.hdr,
+ sizeof(p->msg_in.hdr));
+
+ return 0;
+}
+
+static int dalrpc_read_msg(struct dalrpc_port *p)
+{
+ uint8_t *read_ptr;
+ int bytes_read;
+
+ /* read msg header */
+ while (p->msg_bytes_read < sizeof(p->msg_in.hdr)) {
+ read_ptr = (uint8_t *)&p->msg_in.hdr + p->msg_bytes_read;
+
+ bytes_read = smd_read(p->ch, read_ptr,
+ sizeof(p->msg_in.hdr) -
+ p->msg_bytes_read);
+ if (bytes_read <= 0)
+ return 0;
+ p->msg_bytes_read += bytes_read;
+
+ if (p->msg_bytes_read == sizeof(p->msg_in.hdr) &&
+ check_header(p))
+ return 1;
+ }
+
+ /* read remainder of msg */
+ if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
+ read_ptr = (uint8_t *)&p->msg_owner->msg;
+ else
+ read_ptr = (uint8_t *)&p->msg_in;
+ read_ptr += p->msg_bytes_read;
+
+ while (p->msg_bytes_read < p->msg_in.hdr.len) {
+ bytes_read = smd_read(p->ch, read_ptr,
+ p->msg_in.hdr.len - p->msg_bytes_read);
+ if (bytes_read <= 0)
+ return 0;
+ p->msg_bytes_read += bytes_read;
+ read_ptr += bytes_read;
+ }
+
+ process_msg(p);
+ p->msg_bytes_read = 0;
+ p->msg_owner = NULL;
+
+ return 1;
+}
+
+static void dalrpc_work(struct work_struct *work)
+{
+ struct dalrpc_port *p = container_of(work,
+ struct dalrpc_port,
+ port_work);
+
+ /* must lock port/client lists to ensure port doesn't disappear
+ under an asynch event */
+ mutex_lock(&pc_lists_lock);
+ if (port_exists(p))
+ while (dalrpc_read_msg(p))
+ ;
+ mutex_unlock(&pc_lists_lock);
+}
+
+static void dalrpc_smd_cb(void *priv, unsigned smd_flags)
+{
+ struct dalrpc_port *p = priv;
+
+ if (smd_flags != SMD_EVENT_DATA)
+ return;
+
+ queue_work(p->wq, &p->port_work);
+}
+
+static struct dalrpc_port *dalrpc_port_open(char *port, int cpu)
+{
+ struct dalrpc_port *p;
+ char wq_name[32];
+
+ p = port_name_exists(port);
+ if (p) {
+ p->refcount++;
+ return p;
+ }
+
+ p = kzalloc(sizeof(struct dalrpc_port), GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ strncpy(p->port, port, sizeof(p->port) - 1);
+ p->refcount = 1;
+
+ snprintf(wq_name, sizeof(wq_name), "dalrpc_rcv_%s", port);
+ p->wq = create_singlethread_workqueue(wq_name);
+ if (!p->wq) {
+ printk(KERN_ERR "dalrpc_init: unable to create workqueue\n");
+ goto no_wq;
+ }
+ INIT_WORK(&p->port_work, dalrpc_work);
+
+ mutex_init(&p->write_lock);
+ mutex_init(&p->event_list_lock);
+ mutex_init(&p->cb_list_lock);
+
+ INIT_LIST_HEAD(&p->event_list);
+ INIT_LIST_HEAD(&p->cb_list);
+
+ p->msg_owner = NULL;
+ p->msg_bytes_read = 0;
+
+ if (smd_named_open_on_edge(port, cpu, &p->ch, p,
+ dalrpc_smd_cb)) {
+ printk(KERN_ERR "dalrpc_port_init() failed to open port\n");
+ goto no_smd;
+ }
+
+ list_add(&p->list, &port_list);
+
+ return p;
+
+no_smd:
+ destroy_workqueue(p->wq);
+no_wq:
+ kfree(p);
+ return NULL;
+}
+
+static void dalrpc_sendwait(struct daldevice_handle *h)
+{
+ u8 *buf = (u8 *)&h->msg;
+ int len = h->msg.hdr.len;
+ int written;
+
+ mutex_lock(&h->port->write_lock);
+ do {
+ written = smd_write(h->port->ch, buf + (h->msg.hdr.len - len),
+ len);
+ if (written < 0)
+ break;
+ len -= written;
+ } while (len);
+ mutex_unlock(&h->port->write_lock);
+
+ wait_for_completion(&h->read_completion);
+}
+
+int daldevice_attach(uint32_t device_id, char *port, int cpu,
+ void **handle_ptr)
+{
+ struct daldevice_handle *h;
+ char dyn_port[DALRPC_MAX_PORTNAME_LEN + 1] = "DAL00";
+ int ret;
+ int tries = 0;
+
+ if (!port)
+ port = dyn_port;
+
+ if (strlen(port) > DALRPC_MAX_PORTNAME_LEN)
+ return -EINVAL;
+
+ h = kzalloc(sizeof(struct daldevice_handle), GFP_KERNEL);
+ if (!h) {
+ *handle_ptr = NULL;
+ return -ENOMEM;
+ }
+
+ init_completion(&h->read_completion);
+ mutex_init(&h->client_lock);
+
+ mutex_lock(&pc_lists_lock);
+ list_add(&h->list, &client_list);
+ mutex_unlock(&pc_lists_lock);
+
+ /* 3 attempts, enough for one each on the user specified port, the
+ * dynamic discovery port, and the port recommended by the dynamic
+ * discovery port */
+ while (tries < 3) {
+ tries++;
+
+ mutex_lock(&pc_lists_lock);
+ h->port = dalrpc_port_open(port, cpu);
+ if (!h->port) {
+ list_del(&h->list);
+ mutex_unlock(&pc_lists_lock);
+ printk(KERN_ERR "daldevice_attach: could not "
+ "open port\n");
+ kfree(h);
+ *handle_ptr = NULL;
+ return -EIO;
+ }
+ mutex_unlock(&pc_lists_lock);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
+ DALRPC_MAX_ATTACH_PARAM_LEN +
+ DALRPC_MAX_SERVICE_NAME_LEN;
+ h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
+ h->msg.hdr.ddi_idx = 0;
+ h->msg.hdr.msgid = 0x1;
+ h->msg.hdr.prio = 0;
+ h->msg.hdr.async = 0;
+ h->msg.hdr.from = h;
+ h->msg.hdr.to = 0;
+ h->msg.param[0] = device_id;
+
+ memset(&h->msg.param[1], 0,
+ DALRPC_MAX_ATTACH_PARAM_LEN +
+ DALRPC_MAX_SERVICE_NAME_LEN);
+
+ dalrpc_sendwait(h);
+ ret = h->msg.param[0];
+
+ if (ret == DALRPC_SUCCESS) {
+ h->remote_handle = h->msg.hdr.from;
+ *handle_ptr = h;
+ break;
+ } else if (strnlen((char *)&h->msg.param[1],
+ DALRPC_MAX_PORTNAME_LEN)) {
+ /* another port was recommended in the response. */
+ strncpy(dyn_port, (char *)&h->msg.param[1],
+ DALRPC_MAX_PORTNAME_LEN);
+ dyn_port[DALRPC_MAX_PORTNAME_LEN] = 0;
+ port = dyn_port;
+ } else if (port == dyn_port) {
+ /* the dynamic discovery port (or port that
+ * was recommended by it) did not recognize
+ * the device id, give up */
+ daldevice_detach(h);
+ break;
+ } else
+ /* the user specified port did not work, try
+ * the dynamic discovery port */
+ port = dyn_port;
+
+ port_close(h->port);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(daldevice_attach);
+
+static void dalrpc_ddi_prologue(uint32_t ddi_idx, struct daldevice_handle *h)
+{
+ h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
+ h->msg.hdr.prio = 0;
+ h->msg.hdr.async = 0;
+ h->msg.hdr.msgid = DALRPC_MSGID_DDI;
+ h->msg.hdr.from = h;
+ h->msg.hdr.to = h->remote_handle;
+ h->msg.hdr.ddi_idx = ddi_idx;
+}
+
+int daldevice_detach(void *handle)
+{
+ struct daldevice_handle *h = handle;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ dalrpc_ddi_prologue(0, h);
+
+ if (!h->remote_handle)
+ goto norpc;
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+ h->msg.hdr.msgid = 0x2;
+ h->msg.param[0] = 0;
+
+ dalrpc_sendwait(h);
+
+norpc:
+ mutex_lock(&pc_lists_lock);
+ list_del(&h->list);
+ mutex_unlock(&pc_lists_lock);
+
+ port_close(h->port);
+
+ kfree(h);
+
+ return 0;
+}
+EXPORT_SYMBOL(daldevice_detach);
+
+uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+ h->msg.hdr.proto_id = 0;
+ h->msg.param[0] = s1;
+
+ dalrpc_sendwait(h);
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_0);
+
+uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+ h->msg.hdr.proto_id = 1;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = s2;
+
+ dalrpc_sendwait(h);
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_1);
+
+uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t *p_s2)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+ h->msg.hdr.proto_id = 2;
+ h->msg.param[0] = s1;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS)
+ *p_s2 = h->msg.param[1];
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_2);
+
+uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2, uint32_t s3)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12;
+ h->msg.hdr.proto_id = 3;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = s2;
+ h->msg.param[2] = s3;
+
+ dalrpc_sendwait(h);
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_3);
+
+uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2, uint32_t *p_s3)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+ h->msg.hdr.proto_id = 4;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = s2;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS)
+ *p_s3 = h->msg.param[1];
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_4);
+
+uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if ((ilen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 5;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+
+ dalrpc_sendwait(h);
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_5);
+
+uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
+ const void *ibuf, uint32_t ilen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 6;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = ilen;
+ memcpy(&h->msg.param[2], ibuf, ilen);
+
+ dalrpc_sendwait(h);
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_6);
+
+uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen,
+ uint32_t *oalen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 7;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+ h->msg.param[param_idx] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ *oalen = h->msg.param[1];
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_7);
+
+uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 8;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+ h->msg.param[param_idx] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_8);
+
+uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
+ uint32_t olen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
+ h->msg.hdr.proto_id = 9;
+ h->msg.param[0] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_9);
+
+uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
+ const void *ibuf, uint32_t ilen, void *obuf,
+ uint32_t olen, uint32_t *oalen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 10;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = ilen;
+ memcpy(&h->msg.param[2], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 2;
+ h->msg.param[param_idx] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ *oalen = h->msg.param[1];
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_10);
+
+uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
+ void *obuf, uint32_t olen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+ h->msg.hdr.proto_id = 11;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_11);
+
+uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
+ void *obuf, uint32_t olen, uint32_t *oalen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+
+ if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
+ h->msg.hdr.proto_id = 12;
+ h->msg.param[0] = s1;
+ h->msg.param[1] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ *oalen = h->msg.param[1];
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_12);
+
+uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+ void *obuf, uint32_t olen)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + ilen2 + 12) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + 4) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+ ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
+ h->msg.hdr.proto_id = 13;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+ h->msg.param[param_idx++] = ilen2;
+ memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
+ param_idx += (ROUND_BUFLEN(ilen2) / 4);
+ h->msg.param[param_idx] = olen;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_13);
+
+uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen,
+ void *obuf2, uint32_t olen2, uint32_t *oalen2)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
+ ROUND_BUFLEN(ilen);
+ h->msg.hdr.proto_id = 14;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+ h->msg.param[param_idx++] = olen;
+ h->msg.param[param_idx] = olen2;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
+ if (h->msg.param[param_idx] > olen2) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ memcpy(obuf2, &h->msg.param[param_idx + 1],
+ h->msg.param[param_idx]);
+ *oalen2 = h->msg.param[param_idx];
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_14);
+
+uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+ void *obuf, uint32_t olen, uint32_t *oalen,
+ void *obuf2, uint32_t olen2)
+{
+ struct daldevice_handle *h = handle;
+ uint32_t ret;
+ int param_idx;
+
+ if ((ilen + ilen2 + 16) > DALRPC_MAX_PARAMS_SIZE ||
+ (olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
+ return -EINVAL;
+
+ if (!client_exists(h))
+ return -EINVAL;
+
+ mutex_lock(&h->client_lock);
+
+ dalrpc_ddi_prologue(ddi_idx, h);
+
+ h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 16 +
+ ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
+ h->msg.hdr.proto_id = 15;
+ h->msg.param[0] = ilen;
+ memcpy(&h->msg.param[1], ibuf, ilen);
+ param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
+ h->msg.param[param_idx++] = ilen2;
+ memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
+ param_idx += (ROUND_BUFLEN(ilen2) / 4);
+ h->msg.param[param_idx++] = olen;
+ h->msg.param[param_idx] = olen2;
+
+ dalrpc_sendwait(h);
+
+ if (h->msg.param[0] == DALRPC_SUCCESS) {
+ if (h->msg.param[1] > olen) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
+ if (h->msg.param[param_idx] > olen2) {
+ mutex_unlock(&h->client_lock);
+ return -EIO;
+ }
+ memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
+ memcpy(obuf2, &h->msg.param[param_idx + 1],
+ h->msg.param[param_idx]);
+ *oalen = h->msg.param[1];
+ }
+
+ ret = h->msg.param[0];
+ mutex_unlock(&h->client_lock);
+ return ret;
+}
+EXPORT_SYMBOL(dalrpc_fcn_15);
+
+void *dalrpc_alloc_event(void *handle)
+{
+ struct daldevice_handle *h;
+ struct dalrpc_event_handle *ev;
+
+ h = (struct daldevice_handle *)handle;
+
+ if (!client_exists(h))
+ return NULL;
+
+ ev = kmalloc(sizeof(struct dalrpc_event_handle), GFP_KERNEL);
+ if (!ev)
+ return NULL;
+
+ ev->flag = 0;
+ spin_lock_init(&ev->lock);
+
+ mutex_lock(&h->port->event_list_lock);
+ list_add(&ev->list, &h->port->event_list);
+ mutex_unlock(&h->port->event_list_lock);
+
+ return ev;
+}
+EXPORT_SYMBOL(dalrpc_alloc_event);
+
+void *dalrpc_alloc_cb(void *handle,
+ void (*fn)(void *, uint32_t, void *, uint32_t),
+ void *context)
+{
+ struct daldevice_handle *h;
+ struct dalrpc_cb_handle *cb;
+
+ h = (struct daldevice_handle *)handle;
+
+ if (!client_exists(h))
+ return NULL;
+
+ cb = kmalloc(sizeof(struct dalrpc_cb_handle), GFP_KERNEL);
+ if (!cb)
+ return NULL;
+
+ cb->fn = fn;
+ cb->context = context;
+
+ mutex_lock(&h->port->cb_list_lock);
+ list_add(&cb->list, &h->port->cb_list);
+ mutex_unlock(&h->port->cb_list_lock);
+
+ return cb;
+}
+EXPORT_SYMBOL(dalrpc_alloc_cb);
+
+void dalrpc_dealloc_event(void *handle,
+ void *ev_h)
+{
+ struct daldevice_handle *h;
+ struct dalrpc_event_handle *ev;
+
+ h = (struct daldevice_handle *)handle;
+ ev = (struct dalrpc_event_handle *)ev_h;
+
+ mutex_lock(&h->port->event_list_lock);
+ list_del(&ev->list);
+ mutex_unlock(&h->port->event_list_lock);
+ kfree(ev);
+}
+EXPORT_SYMBOL(dalrpc_dealloc_event);
+
+void dalrpc_dealloc_cb(void *handle,
+ void *cb_h)
+{
+ struct daldevice_handle *h;
+ struct dalrpc_cb_handle *cb;
+
+ h = (struct daldevice_handle *)handle;
+ cb = (struct dalrpc_cb_handle *)cb_h;
+
+ mutex_lock(&h->port->cb_list_lock);
+ list_del(&cb->list);
+ mutex_unlock(&h->port->cb_list_lock);
+ kfree(cb);
+}
+EXPORT_SYMBOL(dalrpc_dealloc_cb);
+
+static int event_occurred(int num_events, struct dalrpc_event_handle **events,
+ int *occurred)
+{
+ int i;
+
+ for (i = 0; i < num_events; i++) {
+ spin_lock(&events[i]->lock);
+ if (events[i]->flag) {
+ events[i]->flag = 0;
+ spin_unlock(&events[i]->lock);
+ *occurred = i;
+ return 1;
+ }
+ spin_unlock(&events[i]->lock);
+ }
+
+ return 0;
+}
+
+int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout)
+{
+ struct dalrpc_event_handle **events;
+ int ret, occurred;
+
+ events = (struct dalrpc_event_handle **)ev_h;
+
+ if (timeout == DALRPC_TIMEOUT_INFINITE) {
+ wait_event(event_wq,
+ event_occurred(num, events, &occurred));
+ return occurred;
+ }
+
+ ret = wait_event_timeout(event_wq,
+ event_occurred(num, events, &occurred),
+ timeout);
+ if (ret > 0)
+ return occurred;
+ else
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(dalrpc_event_wait_multiple);
diff --git a/arch/arm/mach-msm/dal_remotetest.c b/arch/arm/mach-msm/dal_remotetest.c
new file mode 100644
index 000000000000..bbe0f1a4475c
--- /dev/null
+++ b/arch/arm/mach-msm/dal_remotetest.c
@@ -0,0 +1,454 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * DAL remote test device test suite.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+
+#include "dal_remotetest.h"
+
+#define BYTEBUF_LEN 64
+
+#define rpc_error(num) \
+ do { \
+ errmask |= (1 << num); \
+ printk(KERN_INFO "%s: remote_unittest_%d failed (%d)\n", \
+ __func__, num, ret); \
+ } while (0)
+
+#define verify_error(num, field) \
+ do { \
+ errmask |= (1 << num); \
+ printk(KERN_INFO "%s: remote_unittest_%d failed (%s)\n", \
+ __func__, num, field); \
+ } while (0)
+
+
+static struct dentry *debugfs_dir_entry;
+static struct dentry *debugfs_modem_entry;
+static struct dentry *debugfs_dsp_entry;
+
+static uint8_t in_bytebuf[BYTEBUF_LEN];
+static uint8_t out_bytebuf[BYTEBUF_LEN];
+static uint8_t out_bytebuf2[BYTEBUF_LEN];
+static struct remote_test_data in_data;
+static struct remote_test_data out_data;
+static int block_until_cb = 1;
+
+static void init_data(struct remote_test_data *data)
+{
+ int i;
+ data->regular_event = REMOTE_UNITTEST_INPUT_HANDLE;
+ data->payload_event = REMOTE_UNITTEST_INPUT_HANDLE;
+ for (i = 0; i < 32; i++)
+ data->test[i] = i;
+}
+
+static int verify_data(struct remote_test_data *data)
+{
+ int i;
+ if (data->regular_event != REMOTE_UNITTEST_INPUT_HANDLE ||
+ data->payload_event != REMOTE_UNITTEST_INPUT_HANDLE)
+ return -1;
+ for (i = 0; i < 32; i++)
+ if (data->test[i] != i)
+ return -1;
+
+ return 0;
+}
+
+static int verify_uint32_buffer(uint32_t *buf)
+{
+ int i;
+ for (i = 0; i < 32; i++)
+ if (buf[i] != i)
+ return -1;
+
+ return 0;
+}
+
+static void init_bytebuf(uint8_t *bytebuf)
+{
+ int i;
+ for (i = 0; i < BYTEBUF_LEN; i++)
+ bytebuf[i] = i & 0xff;
+}
+
+static int verify_bytebuf(uint8_t *bytebuf)
+{
+ int i;
+ for (i = 0; i < BYTEBUF_LEN; i++)
+ if (bytebuf[i] != (i & 0xff))
+ return -1;
+
+ return 0;
+}
+
+static void test_cb(void *context, uint32_t param, void *data, uint32_t len)
+{
+ block_until_cb = 0;
+}
+
+static int remotetest_exec(int dest, u64 *val)
+{
+ void *dev_handle;
+ void *event_handles[3];
+ void *cb_handle;
+ int ret;
+ u64 errmask = 0;
+ uint32_t ouint;
+ uint32_t oalen;
+
+ /* test daldevice_attach */
+ ret = daldevice_attach(REMOTE_UNITTEST_DEVICEID, NULL,
+ dest, &dev_handle);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to attach (%d)\n", __func__, ret);
+ *val = 0xffffffff;
+ return 0;
+ }
+
+ /* test remote_unittest_0 */
+ ret = remote_unittest_0(dev_handle, REMOTE_UNITTEST_INARG_1);
+ if (ret)
+ rpc_error(0);
+
+ /* test remote_unittest_1 */
+ ret = remote_unittest_1(dev_handle, REMOTE_UNITTEST_INARG_1,
+ REMOTE_UNITTEST_INARG_2);
+ if (ret)
+ rpc_error(1);
+
+ /* test remote_unittest_2 */
+ ouint = 0;
+ ret = remote_unittest_2(dev_handle, REMOTE_UNITTEST_INARG_1, &ouint);
+ if (ret)
+ rpc_error(2);
+ else if (ouint != REMOTE_UNITTEST_OUTARG_1)
+ verify_error(2, "ouint");
+
+ /* test remote_unittest_3 */
+ ret = remote_unittest_3(dev_handle, REMOTE_UNITTEST_INARG_1,
+ REMOTE_UNITTEST_INARG_2,
+ REMOTE_UNITTEST_INARG_3);
+ if (ret)
+ rpc_error(3);
+
+ /* test remote_unittest_4 */
+ ouint = 0;
+ ret = remote_unittest_4(dev_handle, REMOTE_UNITTEST_INARG_1,
+ REMOTE_UNITTEST_INARG_2, &ouint);
+ if (ret)
+ rpc_error(4);
+ else if (ouint != REMOTE_UNITTEST_OUTARG_1)
+ verify_error(4, "ouint");
+
+ /* test remote_unittest_5 */
+ init_data(&in_data);
+ ret = remote_unittest_5(dev_handle, &in_data, sizeof(in_data));
+ if (ret)
+ rpc_error(5);
+
+ /* test remote_unittest_6 */
+ init_data(&in_data);
+ ret = remote_unittest_6(dev_handle, REMOTE_UNITTEST_INARG_1,
+ &in_data.test, sizeof(in_data.test));
+ if (ret)
+ rpc_error(6);
+
+ /* test remote_unittest_7 */
+ init_data(&in_data);
+ memset(&out_data, 0, sizeof(out_data));
+ ret = remote_unittest_7(dev_handle, &in_data, sizeof(in_data),
+ &out_data.test, sizeof(out_data.test),
+ &oalen);
+ if (ret)
+ rpc_error(7);
+ else if (oalen != sizeof(out_data.test))
+ verify_error(7, "oalen");
+ else if (verify_uint32_buffer(out_data.test))
+ verify_error(7, "obuf");
+
+ /* test remote_unittest_8 */
+ init_bytebuf(in_bytebuf);
+ memset(&out_data, 0, sizeof(out_data));
+ ret = remote_unittest_8(dev_handle, in_bytebuf, sizeof(in_bytebuf),
+ &out_data, sizeof(out_data));
+ if (ret)
+ rpc_error(8);
+ else if (verify_data(&out_data))
+ verify_error(8, "obuf");
+
+ /* test remote_unittest_9 */
+ memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+ ret = remote_unittest_9(dev_handle, out_bytebuf, sizeof(out_bytebuf));
+ if (ret)
+ rpc_error(9);
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(9, "obuf");
+
+ /* test remote_unittest_10 */
+ init_bytebuf(in_bytebuf);
+ memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+ ret = remote_unittest_10(dev_handle, REMOTE_UNITTEST_INARG_1,
+ in_bytebuf, sizeof(in_bytebuf),
+ out_bytebuf, sizeof(out_bytebuf), &oalen);
+ if (ret)
+ rpc_error(10);
+ else if (oalen != sizeof(out_bytebuf))
+ verify_error(10, "oalen");
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(10, "obuf");
+
+ /* test remote_unittest_11 */
+ memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+ ret = remote_unittest_11(dev_handle, REMOTE_UNITTEST_INARG_1,
+ out_bytebuf, sizeof(out_bytebuf));
+ if (ret)
+ rpc_error(11);
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(11, "obuf");
+
+ /* test remote_unittest_12 */
+ memset(&out_bytebuf, 0, sizeof(out_bytebuf));
+ ret = remote_unittest_12(dev_handle, REMOTE_UNITTEST_INARG_1,
+ out_bytebuf, sizeof(out_bytebuf), &oalen);
+ if (ret)
+ rpc_error(12);
+ else if (oalen != sizeof(out_bytebuf))
+ verify_error(12, "oalen");
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(12, "obuf");
+
+ /* test remote_unittest_13 */
+ init_data(&in_data);
+ memset(&out_data, 0, sizeof(out_data));
+ ret = remote_unittest_13(dev_handle, in_data.test, sizeof(in_data.test),
+ &in_data, sizeof(in_data),
+ &out_data, sizeof(out_data));
+ if (ret)
+ rpc_error(13);
+ else if (verify_data(&out_data))
+ verify_error(13, "obuf");
+
+ /* test remote_unittest_14 */
+ init_data(&in_data);
+ memset(out_bytebuf, 0, sizeof(out_bytebuf));
+ memset(out_bytebuf2, 0, sizeof(out_bytebuf2));
+ ret = remote_unittest_14(dev_handle,
+ in_data.test, sizeof(in_data.test),
+ out_bytebuf, sizeof(out_bytebuf),
+ out_bytebuf2, sizeof(out_bytebuf2), &oalen);
+ if (ret)
+ rpc_error(14);
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(14, "obuf");
+ else if (oalen != sizeof(out_bytebuf2))
+ verify_error(14, "oalen");
+ else if (verify_bytebuf(out_bytebuf2))
+ verify_error(14, "obuf2");
+
+ /* test remote_unittest_15 */
+ init_data(&in_data);
+ memset(out_bytebuf, 0, sizeof(out_bytebuf));
+ memset(&out_data, 0, sizeof(out_data));
+ ret = remote_unittest_15(dev_handle,
+ in_data.test, sizeof(in_data.test),
+ &in_data, sizeof(in_data),
+ &out_data, sizeof(out_data), &oalen,
+ out_bytebuf, sizeof(out_bytebuf));
+ if (ret)
+ rpc_error(15);
+ else if (oalen != sizeof(out_data))
+ verify_error(15, "oalen");
+ else if (verify_bytebuf(out_bytebuf))
+ verify_error(15, "obuf");
+ else if (verify_data(&out_data))
+ verify_error(15, "obuf2");
+
+ /* test setting up asynch events */
+ event_handles[0] = dalrpc_alloc_event(dev_handle);
+ event_handles[1] = dalrpc_alloc_event(dev_handle);
+ event_handles[2] = dalrpc_alloc_event(dev_handle);
+ cb_handle = dalrpc_alloc_cb(dev_handle, test_cb, &out_data);
+ in_data.regular_event = (uint32_t)event_handles[2];
+ in_data.payload_event = (uint32_t)cb_handle;
+ ret = remote_unittest_eventcfg(dev_handle, &in_data, sizeof(in_data));
+ if (ret) {
+ errmask |= (1 << 16);
+ printk(KERN_INFO "%s: failed to configure asynch (%d)\n",
+ __func__, ret);
+ }
+
+ /* test event */
+ ret = remote_unittest_eventtrig(dev_handle,
+ REMOTE_UNITTEST_REGULAR_EVENT);
+ if (ret) {
+ errmask |= (1 << 17);
+ printk(KERN_INFO "%s: failed to trigger event (%d)\n",
+ __func__, ret);
+ }
+ ret = dalrpc_event_wait(event_handles[2], 1000);
+ if (ret) {
+ errmask |= (1 << 18);
+ printk(KERN_INFO "%s: failed to receive event (%d)\n",
+ __func__, ret);
+ }
+
+ /* test event again */
+ ret = remote_unittest_eventtrig(dev_handle,
+ REMOTE_UNITTEST_REGULAR_EVENT);
+ if (ret) {
+ errmask |= (1 << 19);
+ printk(KERN_INFO "%s: failed to trigger event (%d)\n",
+ __func__, ret);
+ }
+ ret = dalrpc_event_wait_multiple(3, event_handles, 1000);
+ if (ret != 2) {
+ errmask |= (1 << 20);
+ printk(KERN_INFO "%s: failed to receive event (%d)\n",
+ __func__, ret);
+ }
+
+ /* test callback */
+ ret = remote_unittest_eventtrig(dev_handle,
+ REMOTE_UNITTEST_CALLBACK_EVENT);
+ if (ret) {
+ errmask |= (1 << 21);
+ printk(KERN_INFO "%s: failed to trigger callback (%d)\n",
+ __func__, ret);
+ } else
+ while (block_until_cb)
+ ;
+
+ dalrpc_dealloc_cb(dev_handle, cb_handle);
+ dalrpc_dealloc_event(dev_handle, event_handles[0]);
+ dalrpc_dealloc_event(dev_handle, event_handles[1]);
+ dalrpc_dealloc_event(dev_handle, event_handles[2]);
+
+ /* test daldevice_detach */
+ ret = daldevice_detach(dev_handle);
+ if (ret) {
+ errmask |= (1 << 22);
+ printk(KERN_INFO "%s: failed to detach (%d)\n", __func__, ret);
+ }
+
+ printk(KERN_INFO "%s: remote_unittest complete\n", __func__);
+
+ *val = errmask;
+ return 0;
+}
+
+static int remotetest_modem_exec(void *data, u64 *val)
+{
+ return remotetest_exec(DALRPC_DEST_MODEM, val);
+}
+
+static int remotetest_dsp_exec(void *data, u64 *val)
+{
+ return remotetest_exec(DALRPC_DEST_QDSP, val);
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(dal_modemtest_fops, remotetest_modem_exec,
+ NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(dal_dsptest_fops, remotetest_dsp_exec,
+ NULL, "%llu\n");
+
+static int __init remotetest_init(void)
+{
+ debugfs_dir_entry = debugfs_create_dir("dal", 0);
+ if (IS_ERR(debugfs_dir_entry))
+ return PTR_ERR(debugfs_dir_entry);
+
+ debugfs_modem_entry = debugfs_create_file("modem_test", 0444,
+ debugfs_dir_entry,
+ NULL, &dal_modemtest_fops);
+ if (IS_ERR(debugfs_modem_entry)) {
+ debugfs_remove(debugfs_dir_entry);
+ return PTR_ERR(debugfs_modem_entry);
+ }
+
+ debugfs_dsp_entry = debugfs_create_file("dsp_test", 0444,
+ debugfs_dir_entry,
+ NULL, &dal_dsptest_fops);
+ if (IS_ERR(debugfs_dsp_entry)) {
+ debugfs_remove(debugfs_modem_entry);
+ debugfs_remove(debugfs_dir_entry);
+ return PTR_ERR(debugfs_dsp_entry);
+ }
+
+ return 0;
+}
+
+static void __exit remotetest_exit(void)
+{
+ debugfs_remove(debugfs_modem_entry);
+ debugfs_remove(debugfs_dsp_entry);
+ debugfs_remove(debugfs_dir_entry);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Test for DAL RPC");
+MODULE_VERSION("1.0");
+
+module_init(remotetest_init);
+module_exit(remotetest_exit);
diff --git a/arch/arm/mach-msm/dal_remotetest.h b/arch/arm/mach-msm/dal_remotetest.h
new file mode 100644
index 000000000000..e24b480192ed
--- /dev/null
+++ b/arch/arm/mach-msm/dal_remotetest.h
@@ -0,0 +1,187 @@
+/* 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 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.
+ *
+ */
+/*
+ * DAL remote test device API.
+ */
+
+#include <linux/kernel.h>
+
+#include <mach/dal.h>
+
+#define REMOTE_UNITTEST_DEVICEID 0xDA1DA1DA
+
+enum {
+ DALRPC_TEST_API_0 = DALDEVICE_FIRST_DEVICE_API_IDX,
+ DALRPC_TEST_API_1,
+ DALRPC_TEST_API_2,
+ DALRPC_TEST_API_3,
+ DALRPC_TEST_API_4,
+ DALRPC_TEST_API_5,
+ DALRPC_TEST_API_6,
+ DALRPC_TEST_API_7,
+ DALRPC_TEST_API_8,
+ DALRPC_TEST_API_9,
+ DALRPC_TEST_API_10,
+ DALRPC_TEST_API_11,
+ DALRPC_TEST_API_12,
+ DALRPC_TEST_API_13,
+ DALRPC_TEST_API_14,
+ DALRPC_TEST_API_15,
+ DALRPC_TEST_API_16,
+ DALRPC_TEST_API_17
+};
+
+#define REMOTE_UNITTEST_INARG_1 0x01010101
+#define REMOTE_UNITTEST_INARG_2 0x20202020
+#define REMOTE_UNITTEST_INARG_3 0x12121212
+#define REMOTE_UNITTEST_INPUT_HANDLE 0xDA1FDA1F
+#define REMOTE_UNITTEST_OUTARG_1 0xBEEFDEAD
+
+#define REMOTE_UNITTEST_REGULAR_EVENT 0
+#define REMOTE_UNITTEST_CALLBACK_EVENT 1
+
+#define REMOTE_UNITTEST_BAD_PARAM 0x10
+
+struct remote_test_data {
+ uint32_t regular_event;
+ uint32_t test[32];
+ uint32_t payload_event;
+};
+
+static int remote_unittest_0(void *handle, uint32_t s1)
+{
+ return dalrpc_fcn_0(DALRPC_TEST_API_0, handle, s1);
+}
+
+static int remote_unittest_1(void *handle, uint32_t s1, uint32_t s2)
+{
+ return dalrpc_fcn_1(DALRPC_TEST_API_1, handle, s1, s2);
+}
+
+static int remote_unittest_2(void *handle, uint32_t s1, uint32_t *p_s2)
+{
+ return dalrpc_fcn_2(DALRPC_TEST_API_2, handle, s1, p_s2);
+}
+
+static int remote_unittest_3(void *handle, uint32_t s1, uint32_t s2,
+ uint32_t s3)
+{
+ return dalrpc_fcn_3(DALRPC_TEST_API_3, handle, s1, s2, s3);
+}
+
+static int remote_unittest_4(void *handle, uint32_t s1, uint32_t s2,
+ uint32_t *p_s3)
+{
+ return dalrpc_fcn_4(DALRPC_TEST_API_4, handle, s1, s2, p_s3);
+}
+
+static int remote_unittest_5(void *handle, const void *ibuf, uint32_t ilen)
+{
+ return dalrpc_fcn_5(DALRPC_TEST_API_5, handle, ibuf, ilen);
+}
+
+static int remote_unittest_6(void *handle, uint32_t s1, const void *ibuf,
+ uint32_t ilen)
+{
+ return dalrpc_fcn_6(DALRPC_TEST_API_6, handle, s1, ibuf, ilen);
+}
+
+static int remote_unittest_7(void *handle, const void *ibuf, uint32_t ilen,
+ void *obuf, uint32_t olen, uint32_t *oalen)
+{
+ return dalrpc_fcn_7(DALRPC_TEST_API_7, handle, ibuf, ilen, obuf,
+ olen, oalen);
+}
+
+static int remote_unittest_8(void *handle, const void *ibuf, uint32_t ilen,
+ void *obuf, uint32_t olen)
+{
+ return dalrpc_fcn_8(DALRPC_TEST_API_8, handle, ibuf, ilen, obuf, olen);
+}
+
+static int remote_unittest_9(void *handle, void *obuf, uint32_t olen)
+{
+ return dalrpc_fcn_9(DALRPC_TEST_API_9, handle, obuf, olen);
+}
+
+static int remote_unittest_10(void *handle, uint32_t s1, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen,
+ uint32_t *oalen)
+{
+ return dalrpc_fcn_10(DALRPC_TEST_API_10, handle, s1, ibuf, ilen, obuf,
+ olen, oalen);
+}
+
+static int remote_unittest_11(void *handle, uint32_t s1, void *obuf,
+ uint32_t olen)
+{
+ return dalrpc_fcn_11(DALRPC_TEST_API_11, handle, s1, obuf, olen);
+}
+
+static int remote_unittest_12(void *handle, uint32_t s1, void *obuf,
+ uint32_t olen, uint32_t *oalen)
+{
+ return dalrpc_fcn_12(DALRPC_TEST_API_12, handle, s1, obuf, olen,
+ oalen);
+}
+
+static int remote_unittest_13(void *handle, const void *ibuf, uint32_t ilen,
+ const void *ibuf2, uint32_t ilen2, void *obuf,
+ uint32_t olen)
+{
+ return dalrpc_fcn_13(DALRPC_TEST_API_13, handle, ibuf, ilen, ibuf2,
+ ilen2, obuf, olen);
+}
+
+static int remote_unittest_14(void *handle, const void *ibuf, uint32_t ilen,
+ void *obuf, uint32_t olen, void *obuf2,
+ uint32_t olen2, uint32_t *oalen2)
+{
+ return dalrpc_fcn_14(DALRPC_TEST_API_14, handle, ibuf, ilen, obuf,
+ olen, obuf2, olen2, oalen2);
+}
+
+static int remote_unittest_15(void *handle, const void *ibuf, uint32_t ilen,
+ const void *ibuf2, uint32_t ilen2, void *obuf,
+ uint32_t olen, uint32_t *oalen, void *obuf2,
+ uint32_t olen2)
+{
+ return dalrpc_fcn_15(DALRPC_TEST_API_15, handle, ibuf, ilen, ibuf2,
+ ilen2, obuf, olen, oalen, obuf2, olen2);
+}
+
+static int remote_unittest_eventcfg(void *handle, const void *ibuf,
+ uint32_t ilen)
+{
+ return dalrpc_fcn_5(DALRPC_TEST_API_16, handle, ibuf, ilen);
+}
+
+static int remote_unittest_eventtrig(void *handle, uint32_t event_idx)
+{
+ return dalrpc_fcn_0(DALRPC_TEST_API_17, handle, event_idx);
+}
diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c
index 31b6b30e98bf..a64578f1a032 100644
--- a/arch/arm/mach-msm/devices.c
+++ b/arch/arm/mach-msm/devices.c
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/devices.c
*
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2008-2009, 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
@@ -16,14 +17,20 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <mach/irqs.h>
#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
#include "devices.h"
#include <asm/mach/flash.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <asm/mach/mmc.h>
+
static struct resource resources_uart1[] = {
{
.start = INT_UART1,
@@ -84,48 +91,14 @@ struct platform_device msm_device_uart3 = {
.resource = resources_uart3,
};
-static struct resource resources_i2c[] = {
- {
- .start = MSM_I2C_PHYS,
- .end = MSM_I2C_PHYS + MSM_I2C_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = INT_PWB_I2C,
- .end = INT_PWB_I2C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device msm_device_i2c = {
- .name = "msm_i2c",
- .id = 0,
- .num_resources = ARRAY_SIZE(resources_i2c),
- .resource = resources_i2c,
-};
-
-static struct resource resources_hsusb[] = {
- {
- .start = MSM_HSUSB_PHYS,
- .end = MSM_HSUSB_PHYS + MSM_HSUSB_SIZE,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = INT_USB_HS,
- .end = INT_USB_HS,
- .flags = IORESOURCE_IRQ,
- },
-};
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define MSM_UART1DM_PHYS 0xA0200000
+#define MSM_UART2DM_PHYS 0xA0900000
+#else
+#define MSM_UART1DM_PHYS 0xA0200000
+#define MSM_UART2DM_PHYS 0xA0300000
+#endif
-struct platform_device msm_device_hsusb = {
- .name = "msm_hsusb",
- .id = -1,
- .num_resources = ARRAY_SIZE(resources_hsusb),
- .resource = resources_hsusb,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
struct flash_platform_data msm_nand_data = {
.parts = NULL,
@@ -155,10 +128,27 @@ struct platform_device msm_device_smd = {
.id = -1,
};
+struct platform_device msm_device_dmov = {
+ .name = "msm_dmov",
+ .id = -1,
+};
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define MSM_SDC1_BASE 0xA0300000
+#define MSM_SDC2_BASE 0xA0400000
+#define MSM_SDC3_BASE 0xA0500000
+#define MSM_SDC4_BASE 0xA0600000
+#else
+#define MSM_SDC1_BASE 0xA0400000
+#define MSM_SDC2_BASE 0xA0500000
+#define MSM_SDC3_BASE 0xA0600000
+#define MSM_SDC4_BASE 0xA0700000
+#endif
+
static struct resource resources_sdc1[] = {
{
- .start = MSM_SDC1_PHYS,
- .end = MSM_SDC1_PHYS + MSM_SDC1_SIZE - 1,
+ .start = MSM_SDC1_BASE,
+ .end = MSM_SDC1_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -175,8 +165,8 @@ static struct resource resources_sdc1[] = {
static struct resource resources_sdc2[] = {
{
- .start = MSM_SDC2_PHYS,
- .end = MSM_SDC2_PHYS + MSM_SDC2_SIZE - 1,
+ .start = MSM_SDC2_BASE,
+ .end = MSM_SDC2_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -193,8 +183,8 @@ static struct resource resources_sdc2[] = {
static struct resource resources_sdc3[] = {
{
- .start = MSM_SDC3_PHYS,
- .end = MSM_SDC3_PHYS + MSM_SDC3_SIZE - 1,
+ .start = MSM_SDC3_BASE,
+ .end = MSM_SDC3_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -211,8 +201,8 @@ static struct resource resources_sdc3[] = {
static struct resource resources_sdc4[] = {
{
- .start = MSM_SDC4_PHYS,
- .end = MSM_SDC4_PHYS + MSM_SDC4_SIZE - 1,
+ .start = MSM_SDC4_BASE,
+ .end = MSM_SDC4_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -266,3 +256,273 @@ struct platform_device msm_device_sdc4 = {
.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 mmc_platform_data *plat)
+{
+ struct platform_device *pdev;
+
+ if (controller < 1 || controller > 4)
+ return -EINVAL;
+
+ pdev = msm_sdcc_devices[controller-1];
+ pdev->dev.platform_data = plat;
+ return platform_device_register(pdev);
+}
+
+struct clk 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, 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_CLK, NULL, OFF),
+ 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),
+ CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0),
+ CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
+ CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF),
+ 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_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, 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("usb_hs_clk", USB_HS_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF),
+ CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
+ CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN),
+ CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF),
+ CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF),
+ CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0),
+};
+
+unsigned msm_num_clocks_7x01a = ARRAY_SIZE(msm_clocks_7x01a);
+
+struct clk msm_clocks_7x25[] = {
+ CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
+ CLK_PCOM("adsp_clk", ADSP_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("gp_clk", GP_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),
+ CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0),
+ CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
+ CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF),
+ CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0),
+ 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_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF),
+ 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("usb_hs_clk", USB_HS_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF),
+ CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
+ CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN),
+ CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF),
+ CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF),
+ CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0),
+};
+
+unsigned msm_num_clocks_7x25 = ARRAY_SIZE(msm_clocks_7x25);
+
+struct clk msm_clocks_7x27[] = {
+ CLK_PCOM("adm_clk", ADM_CLK, NULL, 0),
+ CLK_PCOM("adsp_clk", ADSP_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("gp_clk", GP_CLK, NULL, 0),
+ CLK_PCOM("grp_clk", GRP_CLK, NULL, 0),
+ CLK_PCOM("grp_pclk", GRP_PCLK, 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),
+ CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0),
+ CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
+ CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF),
+ CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0),
+ 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_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF),
+ 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("usb_hs_clk", USB_HS_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF),
+ CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
+ CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0),
+ CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN),
+ CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF),
+ CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF),
+};
+
+unsigned msm_num_clocks_7x27 = ARRAY_SIZE(msm_clocks_7x27);
+
+struct clk 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_MCLK_CLK, NULL, 0),
+ CLK_PCOM("camif_pad_pclk", CAMIF_PAD_PCLK, NULL, OFF),
+ 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("gp_clk", GP_CLK, NULL, 0),
+ CLK_PCOM("grp_2d_clk", GRP_2D_CLK, NULL, 0),
+ CLK_PCOM("grp_2d_pclk", GRP_2D_PCLK, NULL, 0),
+ CLK_PCOM("grp_clk", GRP_CLK, NULL, 0),
+ CLK_PCOM("grp_pclk", GRP_PCLK, NULL, 0),
+ CLK_PCOM("hdmi_clk", HDMI_CLK, NULL, 0),
+ CLK_PCOM("imem_clk", IMEM_CLK, NULL, OFF),
+ CLK_PCOM("lpa_codec_clk", LPA_CODEC_CLK, NULL, 0),
+ CLK_PCOM("lpa_core_clk", LPA_CORE_CLK, NULL, 0),
+ CLK_PCOM("lpa_pclk", LPA_PCLK, NULL, 0),
+ CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0),
+ CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
+ CLK_PCOM("mddi_pclk", PMDH_PCLK, NULL, 0),
+ CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF),
+ CLK_PCOM("mdp_pclk", MDP_PCLK, NULL, 0),
+ CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0),
+ CLK_PCOM("mfc_clk", MFC_CLK, NULL, 0),
+ CLK_PCOM("mfc_div2_clk", MFC_DIV2_CLK, NULL, 0),
+ CLK_PCOM("mfc_pclk", MFC_PCLK, NULL, 0),
+ CLK_PCOM("mi2s_codec_rx_m_clk", MI2S_CODEC_RX_MCLK, NULL, 0),
+ CLK_PCOM("mi2s_codec_rx_s_clk", MI2S_CODEC_RX_SCLK, NULL, 0),
+ CLK_PCOM("mi2s_codec_tx_m_clk", MI2S_CODEC_TX_MCLK, NULL, 0),
+ CLK_PCOM("mi2s_codec_tx_s_clk", MI2S_CODEC_TX_SCLK, NULL, 0),
+ CLK_PCOM("pbus_clk", PBUS_CLK, NULL, CLK_MIN),
+ CLK_PCOM("pcm_clk", PCM_CLK, NULL, 0),
+ CLK_PCOM("rotator_clk", AXI_ROTATOR_CLK, NULL, 0),
+ CLK_PCOM("rotator_imem_clk", ROTATOR_IMEM_CLK, NULL, OFF),
+ CLK_PCOM("rotator_pclk", ROTATOR_PCLK, NULL, OFF),
+ CLK_PCOM("sdac_clk", SDAC_CLK, NULL, OFF),
+ CLK_PCOM("sdc_clk", SDC1_CLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("spi_clk", SPI_CLK, NULL, 0),
+ CLK_PCOM("spi_pclk", SPI_PCLK, 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("usb_hs_clk", USB_HS_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF),
+ CLK_PCOM("usb_hs_core_clk", USB_HS_CORE_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF),
+ CLK_PCOM("usb_hs2_core_clk", USB_HS2_CORE_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF),
+ CLK_PCOM("usb_hs3_core_clk", USB_HS3_CORE_CLK, NULL, OFF),
+ CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
+ CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN),
+ CLK_PCOM("vfe_camif_clk", VFE_CAMIF_CLK, NULL, 0),
+ CLK_PCOM("vfe_clk", VFE_CLK, NULL, 0),
+ CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, 0),
+ CLK_PCOM("vfe_pclk", VFE_PCLK, NULL, OFF),
+};
+
+unsigned msm_num_clocks_7x30 = ARRAY_SIZE(msm_clocks_7x30);
+
+struct clk msm_clocks_8x50[] = {
+ CLK_PCOM("adm_clk", ADM_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_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),
+ CLK_PCOM("mdc_clk", MDC_CLK, NULL, 0),
+ CLK_PCOM("mddi_clk", PMDH_CLK, NULL, OFF | CLK_MINMAX),
+ CLK_PCOM("mdp_clk", MDP_CLK, NULL, OFF),
+ CLK_PCOM("mdp_lcdc_pclk_clk", MDP_LCDC_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_lcdc_pad_pclk_clk", MDP_LCDC_PAD_PCLK_CLK, NULL, 0),
+ CLK_PCOM("mdp_vsync_clk", MDP_VSYNC_CLK, NULL, 0),
+ 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_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC1_PCLK, &msm_device_sdc1.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC2_CLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC2_PCLK, &msm_device_sdc2.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC3_CLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC3_PCLK, &msm_device_sdc3.dev, OFF),
+ CLK_PCOM("sdc_clk", SDC4_CLK, &msm_device_sdc4.dev, OFF),
+ CLK_PCOM("sdc_pclk", SDC4_PCLK, &msm_device_sdc4.dev, 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", 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("usb_hs_clk", USB_HS_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs_pclk", USB_HS_PCLK, NULL, OFF),
+ CLK_PCOM("usb_otg_clk", USB_OTG_CLK, NULL, 0),
+ CLK_PCOM("vdc_clk", VDC_CLK, NULL, OFF | CLK_MIN),
+ CLK_PCOM("vfe_clk", VFE_CLK, NULL, OFF),
+ CLK_PCOM("vfe_mdc_clk", VFE_MDC_CLK, NULL, OFF),
+ CLK_PCOM("vfe_axi_clk", VFE_AXI_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs2_clk", USB_HS2_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs2_pclk", USB_HS2_PCLK, NULL, OFF),
+ CLK_PCOM("usb_hs3_clk", USB_HS3_CLK, NULL, OFF),
+ CLK_PCOM("usb_hs3_pclk", USB_HS3_PCLK, NULL, OFF),
+ CLK_PCOM("usb_phy_clk", USB_PHY_CLK, NULL, 0),
+};
+
+unsigned msm_num_clocks_8x50 = ARRAY_SIZE(msm_clocks_8x50);
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 0744c4a27d6a..9dd8d9b698c8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/devices.h
*
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, 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
@@ -16,6 +17,8 @@
#ifndef __ARCH_ARM_MACH_MSM_DEVICES_H
#define __ARCH_ARM_MACH_MSM_DEVICES_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;
@@ -25,12 +28,31 @@ extern struct platform_device msm_device_sdc2;
extern struct platform_device msm_device_sdc3;
extern struct platform_device msm_device_sdc4;
-extern struct platform_device msm_device_hsusb;
+extern struct platform_device msm_device_hsusb_otg;
+extern struct platform_device msm_device_hsusb_peripheral;
+extern struct platform_device msm_device_hsusb_host;
extern struct platform_device msm_device_i2c;
extern struct platform_device msm_device_smd;
+extern struct platform_device msm_device_dmov;
extern struct platform_device msm_device_nand;
+extern struct clk msm_clocks_7x01a[];
+extern unsigned msm_num_clocks_7x01a;
+
+extern struct clk msm_clocks_7x25[];
+extern unsigned msm_num_clocks_7x25;
+
+extern struct clk msm_clocks_7x27[];
+extern unsigned msm_num_clocks_7x27;
+
+extern struct clk msm_clocks_7x30[];
+extern unsigned msm_num_clocks_7x30;
+
+extern struct clk msm_clocks_8x50[];
+extern unsigned msm_num_clocks_8x50;
+
+
#endif
diff --git a/arch/arm/mach-msm/devices_htc.c b/arch/arm/mach-msm/devices_htc.c
new file mode 100644
index 000000000000..fad7dfb1bcc4
--- /dev/null
+++ b/arch/arm/mach-msm/devices_htc.c
@@ -0,0 +1,450 @@
+/* linux/arch/arm/mach-msm/devices.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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/platform_device.h>
+
+#include <linux/dma-mapping.h>
+#include <mach/msm_iomap.h>
+#include <mach/dma.h>
+#include "gpio_chip.h"
+#include "devices.h"
+#include <mach/board.h>
+#include <mach/board_htc.h>
+#include <mach/msm_hsusb.h>
+#include <linux/usb/mass_storage_function.h>
+#include <linux/usb/android.h>
+
+#include <asm/mach/flash.h>
+#include <asm/setup.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+#include <asm/mach/mmc.h>
+
+static char *df_serialno = "000000000000";
+
+#if 0
+struct platform_device *devices[] __initdata = {
+ &msm_device_nand,
+ &msm_device_smd,
+ &msm_device_i2c,
+};
+
+void __init msm_add_devices(void)
+{
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+#endif
+
+#define HSUSB_API_INIT_PHY_PROC 2
+#define HSUSB_API_PROG 0x30000064
+#define HSUSB_API_VERS 0x10001
+static void internal_phy_reset(void)
+{
+ struct msm_rpc_endpoint *usb_ep;
+ int rc;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ printk(KERN_INFO "msm_hsusb_phy_reset\n");
+
+ usb_ep = msm_rpc_connect(HSUSB_API_PROG, HSUSB_API_VERS, 0);
+ if (IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: init rpc failed! error: %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ goto close;
+ }
+ rc = msm_rpc_call(usb_ep, HSUSB_API_INIT_PHY_PROC,
+ &req, sizeof(req), 5 * HZ);
+ if (rc < 0)
+ printk(KERN_ERR "%s: rpc call failed! (%d)\n", __func__, rc);
+
+close:
+ msm_rpc_close(usb_ep);
+}
+
+/* adjust eye diagram, disable vbusvalid interrupts */
+static int hsusb_phy_init_seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 };
+
+#ifdef CONFIG_USB_FUNCTION
+static char *usb_functions[] = {
+#if defined(CONFIG_USB_FUNCTION_MASS_STORAGE) || defined(CONFIG_USB_FUNCTION_UMS)
+ "usb_mass_storage",
+#endif
+#ifdef CONFIG_USB_FUNCTION_ADB
+ "adb",
+#endif
+};
+
+static struct msm_hsusb_product usb_products[] = {
+ {
+ .product_id = 0x0c01,
+ .functions = 0x00000041, /* usb_mass_storage */
+ },
+ {
+ .product_id = 0x0c02,
+ .functions = 0x00000043, /* usb_mass_storage + adb */
+ },
+};
+#endif
+
+struct msm_hsusb_platform_data msm_hsusb_pdata = {
+ .phy_reset = internal_phy_reset,
+ .phy_init_seq = hsusb_phy_init_seq,
+#ifdef CONFIG_USB_FUNCTION
+ .vendor_id = 0x0bb4,
+ .product_id = 0x0c02,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "HTC",
+
+ .functions = usb_functions,
+ .num_functions = ARRAY_SIZE(usb_functions),
+ .products = usb_products,
+ .num_products = ARRAY_SIZE(usb_products),
+#endif
+};
+
+#ifdef CONFIG_USB_FUNCTION
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+ .nluns = 1,
+ .buf_size = 16384,
+ .vendor = "HTC ",
+ .product = "Android Phone ",
+ .release = 0x0100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+ .name = "usb_mass_storage",
+ .id = -1,
+ .dev = {
+ .platform_data = &mass_storage_pdata,
+ },
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x0bb4,
+ .product_id = 0x0c01,
+ .adb_product_id = 0x0c02,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "HTC",
+ .nluns = 1,
+};
+
+static struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+#endif
+
+void __init msm_add_usb_devices(void (*phy_reset) (void))
+{
+ /* setup */
+ if (phy_reset)
+ msm_hsusb_pdata.phy_reset = phy_reset;
+ msm_device_hsusb.dev.platform_data = &msm_hsusb_pdata;
+ platform_device_register(&msm_device_hsusb);
+#ifdef CONFIG_USB_FUNCTION_MASS_STORAGE
+ platform_device_register(&usb_mass_storage_device);
+#endif
+#ifdef CONFIG_USB_ANDROID
+ platform_device_register(&android_usb_device);
+#endif
+}
+
+static struct android_pmem_platform_data pmem_pdata = {
+ .name = "pmem",
+ .no_allocator = 1,
+ .cached = 1,
+};
+
+static struct android_pmem_platform_data pmem_adsp_pdata = {
+ .name = "pmem_adsp",
+ .no_allocator = 0,
+ .cached = 0,
+};
+
+static struct android_pmem_platform_data pmem_camera_pdata = {
+ .name = "pmem_camera",
+ .no_allocator = 0,
+ .cached = 0,
+};
+
+static struct android_pmem_platform_data pmem_gpu0_pdata = {
+ .name = "pmem_gpu0",
+ .no_allocator = 1,
+ .cached = 0,
+ .buffered = 1,
+};
+
+static struct android_pmem_platform_data pmem_gpu1_pdata = {
+ .name = "pmem_gpu1",
+ .no_allocator = 1,
+ .cached = 0,
+ .buffered = 1,
+};
+
+static struct platform_device pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+ .dev = { .platform_data = &pmem_pdata },
+};
+
+static struct platform_device pmem_adsp_device = {
+ .name = "android_pmem",
+ .id = 1,
+ .dev = { .platform_data = &pmem_adsp_pdata },
+};
+
+static struct platform_device pmem_gpu0_device = {
+ .name = "android_pmem",
+ .id = 2,
+ .dev = { .platform_data = &pmem_gpu0_pdata },
+};
+
+static struct platform_device pmem_gpu1_device = {
+ .name = "android_pmem",
+ .id = 3,
+ .dev = { .platform_data = &pmem_gpu1_pdata },
+};
+
+static struct platform_device pmem_camera_device = {
+ .name = "android_pmem",
+ .id = 4,
+ .dev = { .platform_data = &pmem_camera_pdata },
+};
+
+static struct resource ram_console_resource[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device ram_console_device = {
+ .name = "ram_console",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ram_console_resource),
+ .resource = ram_console_resource,
+};
+
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting)
+{
+ if (setting->pmem_size) {
+ pmem_pdata.start = setting->pmem_start;
+ pmem_pdata.size = setting->pmem_size;
+ platform_device_register(&pmem_device);
+ }
+
+ if (setting->pmem_adsp_size) {
+ pmem_adsp_pdata.start = setting->pmem_adsp_start;
+ pmem_adsp_pdata.size = setting->pmem_adsp_size;
+ platform_device_register(&pmem_adsp_device);
+ }
+
+ if (setting->pmem_gpu0_size) {
+ pmem_gpu0_pdata.start = setting->pmem_gpu0_start;
+ pmem_gpu0_pdata.size = setting->pmem_gpu0_size;
+ platform_device_register(&pmem_gpu0_device);
+ }
+
+ if (setting->pmem_gpu1_size) {
+ pmem_gpu1_pdata.start = setting->pmem_gpu1_start;
+ pmem_gpu1_pdata.size = setting->pmem_gpu1_size;
+ platform_device_register(&pmem_gpu1_device);
+ }
+
+ if (setting->pmem_camera_size) {
+ pmem_camera_pdata.start = setting->pmem_camera_start;
+ pmem_camera_pdata.size = setting->pmem_camera_size;
+ platform_device_register(&pmem_camera_device);
+ }
+
+ if (setting->ram_console_size) {
+ ram_console_resource[0].start = setting->ram_console_start;
+ ram_console_resource[0].end = setting->ram_console_start
+ + setting->ram_console_size - 1;
+ platform_device_register(&ram_console_device);
+ }
+}
+
+#define PM_LIBPROG 0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS 0xfb837d0b
+#else
+#define PM_LIBVERS 0x10001
+#endif
+
+#if 0
+static struct platform_device *msm_serial_devices[] __initdata = {
+ &msm_device_uart1,
+ &msm_device_uart2,
+ &msm_device_uart3,
+ #ifdef CONFIG_SERIAL_MSM_HS
+ &msm_device_uart_dm1,
+ &msm_device_uart_dm2,
+ #endif
+};
+
+int __init msm_add_serial_devices(unsigned num)
+{
+ if (num > MSM_SERIAL_NUM)
+ return -EINVAL;
+
+ return platform_device_register(msm_serial_devices[num]);
+}
+#endif
+
+#define ATAG_SMI 0x4d534D71
+/* setup calls mach->fixup, then parse_tags, parse_cmdline
+ * We need to setup meminfo in mach->fixup, so this function
+ * will need to traverse each tag to find smi tag.
+ */
+int __init parse_tag_smi(const struct tag *tags)
+{
+ int smi_sz = 0, find = 0;
+ struct tag *t = (struct tag *)tags;
+
+ for (; t->hdr.size; t = tag_next(t)) {
+ if (t->hdr.tag == ATAG_SMI) {
+ printk(KERN_DEBUG "find the smi tag\n");
+ find = 1;
+ break;
+ }
+ }
+ if (!find)
+ return -1;
+
+ printk(KERN_DEBUG "parse_tag_smi: smi size = %d\n", t->u.mem.size);
+ smi_sz = t->u.mem.size;
+ return smi_sz;
+}
+__tagtable(ATAG_SMI, parse_tag_smi);
+
+
+#define ATAG_HWID 0x4d534D72
+int __init parse_tag_hwid(const struct tag *tags)
+{
+ int hwid = 0, find = 0;
+ struct tag *t = (struct tag *)tags;
+
+ for (; t->hdr.size; t = tag_next(t)) {
+ if (t->hdr.tag == ATAG_HWID) {
+ printk(KERN_DEBUG "find the hwid tag\n");
+ find = 1;
+ break;
+ }
+ }
+
+ if (find)
+ hwid = t->u.revision.rev;
+ printk(KERN_DEBUG "parse_tag_hwid: hwid = 0x%x\n", hwid);
+ return hwid;
+}
+__tagtable(ATAG_HWID, parse_tag_hwid);
+
+#define ATAG_SKUID 0x4d534D73
+int __init parse_tag_skuid(const struct tag *tags)
+{
+ int skuid = 0, find = 0;
+ struct tag *t = (struct tag *)tags;
+
+ for (; t->hdr.size; t = tag_next(t)) {
+ if (t->hdr.tag == ATAG_SKUID) {
+ printk(KERN_DEBUG "find the skuid tag\n");
+ find = 1;
+ break;
+ }
+ }
+
+ if (find)
+ skuid = t->u.revision.rev;
+ printk(KERN_DEBUG "parse_tag_skuid: hwid = 0x%x\n", skuid);
+ return skuid;
+}
+__tagtable(ATAG_SKUID, parse_tag_skuid);
+
+#define ATAG_ENGINEERID 0x4d534D75
+int __init parse_tag_engineerid(const struct tag *tags)
+{
+ int engineerid = 0, find = 0;
+ struct tag *t = (struct tag *)tags;
+
+ for (; t->hdr.size; t = tag_next(t)) {
+ if (t->hdr.tag == ATAG_ENGINEERID) {
+ printk(KERN_DEBUG "find the engineer tag\n");
+ find = 1;
+ break;
+ }
+ }
+
+ if (find)
+ engineerid = t->u.revision.rev;
+ printk(KERN_DEBUG "parse_tag_engineerid: hwid = 0x%x\n", engineerid);
+ return engineerid;
+}
+__tagtable(ATAG_ENGINEERID, parse_tag_engineerid);
+
+static int mfg_mode;
+int __init board_mfg_mode_init(char *s)
+{
+ if (!strcmp(s, "normal"))
+ mfg_mode = 0;
+ else if (!strcmp(s, "factory2"))
+ mfg_mode = 1;
+ else if (!strcmp(s, "recovery"))
+ mfg_mode = 2;
+ else if (!strcmp(s, "charge"))
+ mfg_mode = 3;
+
+ return 1;
+}
+__setup("androidboot.mode=", board_mfg_mode_init);
+
+
+int board_mfg_mode(void)
+{
+ return mfg_mode;
+}
+
+static int __init board_serialno_setup(char *serialno)
+{
+ char *str;
+
+ if (board_mfg_mode() || !strlen(serialno))
+ str = df_serialno;
+ else
+ str = serialno;
+#ifdef CONFIG_USB_FUNCTION
+ msm_hsusb_pdata.serial_number = str;
+#endif
+#ifdef CONFIG_USB_ANDROID
+ android_usb_pdata.serial_number = str;
+#endif
+ return 1;
+}
+
+__setup("androidboot.serialno=", board_serialno_setup);
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index f5420f9585c5..bbfab84938c6 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/dma.c
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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
@@ -13,10 +14,15 @@
*
*/
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include <mach/dma.h>
+#define MODULE_NAME "msm_dmov"
#define MSM_DMOV_CHANNEL_COUNT 16
enum {
@@ -25,11 +31,19 @@ enum {
MSM_DMOV_PRINT_FLOW = 4
};
+enum {
+ CLK_DIS,
+ CLK_TO_BE_DIS,
+ CLK_EN
+};
+
static DEFINE_SPINLOCK(msm_dmov_lock);
+static struct clk *msm_dmov_clk;
static unsigned int channel_active;
static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS;
+unsigned int clk_ctl = CLK_DIS;
#define MSM_DMOV_DPRINTF(mask, format, args...) \
do { \
@@ -48,12 +62,32 @@ void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful)
writel((graceful << 31), DMOV_FLUSH0(id));
}
+static void timer_func(unsigned long func_paramter)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+ if (clk_ctl == CLK_TO_BE_DIS) {
+ BUG_ON(channel_active);
+ clk_disable(msm_dmov_clk);
+ clk_ctl = CLK_DIS;
+ }
+ spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+}
+DEFINE_TIMER(timer, timer_func, 0, 0);
+
void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
{
unsigned long irq_flags;
unsigned int status;
spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+ if (clk_ctl == CLK_DIS)
+ clk_enable(msm_dmov_clk);
+ else if (clk_ctl == CLK_TO_BE_DIS)
+ del_timer(&timer);
+ clk_ctl = CLK_EN;
+
status = readl(DMOV_STATUS(id));
if (list_empty(&ready_commands[id]) &&
(status & DMOV_STATUS_CMD_PTR_RDY)) {
@@ -70,6 +104,10 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd)
channel_active |= 1U << id;
writel(cmd->cmdptr, DMOV_CMD_PTR(id));
} else {
+ if (!channel_active) {
+ clk_ctl = CLK_TO_BE_DIS;
+ mod_timer(&timer, jiffies + HZ);
+ }
if (list_empty(&active_commands[id]))
PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status);
@@ -123,6 +161,7 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr)
PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr);
return 0;
}
+EXPORT_SYMBOL(msm_dmov_exec_cmd);
static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
@@ -219,28 +258,64 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
}
- if (!channel_active)
- disable_irq(INT_ADM_AARM);
+ if (!channel_active) {
+ disable_irq_nosync(INT_ADM_AARM);
+ clk_ctl = CLK_TO_BE_DIS;
+ mod_timer(&timer, jiffies + HZ);
+ }
spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
return IRQ_HANDLED;
}
+static int msm_dmov_suspend_noirq(struct device *dev)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&msm_dmov_lock, irq_flags);
+ if (clk_ctl == CLK_TO_BE_DIS) {
+ BUG_ON(channel_active);
+ del_timer(&timer);
+ clk_disable(msm_dmov_clk);
+ clk_ctl = CLK_DIS;
+ }
+ spin_unlock_irqrestore(&msm_dmov_lock, irq_flags);
+ return 0;
+}
+
+static struct dev_pm_ops dmov_pm = {
+ .suspend_noirq = msm_dmov_suspend_noirq,
+};
+
+static struct platform_driver msm_dmov_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &dmov_pm,
+ },
+};
+
static int __init msm_init_datamover(void)
{
int i;
int ret;
+
for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
INIT_LIST_HEAD(&ready_commands[i]);
INIT_LIST_HEAD(&active_commands[i]);
writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i));
}
+ msm_dmov_clk = clk_get(NULL, "adm_clk");
+ if (IS_ERR(msm_dmov_clk))
+ return PTR_ERR(msm_dmov_clk);
ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL);
if (ret)
return ret;
disable_irq(INT_ADM_AARM);
+ ret = platform_driver_register(&msm_dmov_driver);
+ if (ret)
+ return ret;
return 0;
}
arch_initcall(msm_init_datamover);
-
diff --git a/arch/arm/mach-msm/dma_test.c b/arch/arm/mach-msm/dma_test.c
new file mode 100644
index 000000000000..c4967f97f832
--- /dev/null
+++ b/arch/arm/mach-msm/dma_test.c
@@ -0,0 +1,404 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <mach/dma.h>
+#include <mach/dma_test.h>
+
+
+/**********************************************************************
+ * User-space testing of the DMA driver.
+ * Intended to be loaded as a module. We have a bunch of static
+ * buffers that the user-side can refer to. The main DMA is simply
+ * used memory-to-memory. Device DMA is best tested with the specific
+ * device driver in question.
+ */
+#define MAX_TEST_BUFFERS 40
+#define MAX_TEST_BUFFER_SIZE 65536
+static void *(buffers[MAX_TEST_BUFFERS]);
+static int sizes[MAX_TEST_BUFFERS];
+
+/* Anything that allocates or deallocates buffers must lock with this
+ * mutex. */
+static DECLARE_MUTEX(buffer_lock);
+
+/* Each buffer has a semaphore associated with it that will be held
+ * for the duration of any operations on that buffer. It also must be
+ * available to free the given buffer. */
+static struct semaphore buffer_sems[MAX_TEST_BUFFERS];
+
+#define buffer_up(num) up(&buffer_sems[num])
+#define buffer_down(num) down(&buffer_sems[num])
+
+/* Use the General Purpose DMA channel as our test channel. This channel
+ * should be available on any target. */
+#define TEST_CHANNEL DMOV_GP_CHAN
+
+struct private {
+ /* Each open instance is allowed a single pending
+ * operation. */
+ struct semaphore sem;
+
+ /* Simple command buffer. Allocated and freed by driver. */
+ /* TODO: Allocate these together. */
+ dmov_s *command_ptr;
+
+ /* Indirect. */
+ u32 *command_ptr_ptr;
+
+ /* Indicates completion with pending request. */
+ struct completion complete;
+};
+
+static void free_buffers(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_TEST_BUFFERS; i++) {
+ if (sizes[i] > 0) {
+ kfree(buffers[i]);
+ sizes[i] = 0;
+ }
+ }
+}
+
+/* Copy between two buffers, using the DMA. */
+
+/* Allocate a buffer of a requested size. */
+static int buffer_req(struct msm_dma_alloc_req *req)
+{
+ int i;
+
+ if (req->size <= 0 || req->size > MAX_TEST_BUFFER_SIZE)
+ return -EINVAL;
+
+ down(&buffer_lock);
+
+ /* Find a free buffer. */
+ for (i = 0; i < MAX_TEST_BUFFERS; i++)
+ if (sizes[i] == 0)
+ break;
+
+ if (i >= MAX_TEST_BUFFERS)
+ goto error;
+
+ buffers[i] = kmalloc(req->size, GFP_KERNEL | __GFP_DMA);
+ if (buffers[i] == 0)
+ goto error;
+ sizes[i] = req->size;
+
+ req->bufnum = i;
+
+ up(&buffer_lock);
+ return 0;
+
+error:
+ up(&buffer_lock);
+ return -ENOSPC;
+}
+
+static int dma_scopy(struct msm_dma_scopy *scopy, struct private *priv)
+{
+ int err = 0;
+ dma_addr_t mapped_cmd;
+ dma_addr_t mapped_cmd_ptr;
+
+ buffer_down(scopy->srcbuf);
+ if (scopy->srcbuf != scopy->destbuf)
+ buffer_down(scopy->destbuf);
+
+ priv->command_ptr->cmd = CMD_PTR_LP | CMD_MODE_SINGLE;
+ priv->command_ptr->src = dma_map_single(NULL, buffers[scopy->srcbuf],
+ scopy->size, DMA_TO_DEVICE);
+ priv->command_ptr->dst = dma_map_single(NULL, buffers[scopy->destbuf],
+ scopy->size, DMA_FROM_DEVICE);
+ priv->command_ptr->len = scopy->size;
+
+ mapped_cmd =
+ dma_map_single(NULL, priv->command_ptr, sizeof(*priv->command_ptr),
+ DMA_TO_DEVICE);
+ *(priv->command_ptr_ptr) = CMD_PTR_ADDR(mapped_cmd) | CMD_PTR_LP;
+
+ mapped_cmd_ptr = dma_map_single(NULL, priv->command_ptr_ptr,
+ sizeof(*priv->command_ptr_ptr),
+ DMA_TO_DEVICE);
+
+ msm_dmov_exec_cmd(TEST_CHANNEL,
+ DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(mapped_cmd_ptr));
+
+ dma_unmap_single(NULL, (dma_addr_t) mapped_cmd_ptr,
+ sizeof(*priv->command_ptr_ptr), DMA_TO_DEVICE);
+ dma_unmap_single(NULL, (dma_addr_t) mapped_cmd,
+ sizeof(*priv->command_ptr), DMA_TO_DEVICE);
+ dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->dst,
+ scopy->size, DMA_FROM_DEVICE);
+ dma_unmap_single(NULL, (dma_addr_t) priv->command_ptr->src,
+ scopy->size, DMA_TO_DEVICE);
+
+ if (scopy->srcbuf != scopy->destbuf)
+ buffer_up(scopy->destbuf);
+ buffer_up(scopy->srcbuf);
+
+ return err;
+}
+
+static int dma_test_open(struct inode *inode, struct file *file)
+{
+ struct private *priv;
+
+ printk(KERN_ALERT "%s\n", __func__);
+
+ priv = kmalloc(sizeof(struct private), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ file->private_data = priv;
+
+ init_MUTEX(&priv->sem);
+
+ /* Note, that these should be allocated together so we don't
+ * waste 32 bytes for each. */
+
+ /* Allocate the command pointer. */
+ priv->command_ptr = kmalloc(sizeof(&priv->command_ptr),
+ GFP_KERNEL | __GFP_DMA);
+ if (priv->command_ptr == NULL) {
+ kfree(priv);
+ return -ENOSPC;
+ }
+
+ /* And the indirect pointer. */
+ priv->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
+ if (priv->command_ptr_ptr == NULL) {
+ kfree(priv->command_ptr);
+ kfree(priv);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int dma_test_release(struct inode *inode, struct file *file)
+{
+ struct private *priv;
+
+ printk(KERN_ALERT "%s\n", __func__);
+
+ if (file->private_data != NULL) {
+ priv = file->private_data;
+ kfree(priv->command_ptr_ptr);
+ kfree(priv->command_ptr);
+ }
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static int dma_test_ioctl(struct inode *inode, struct file *file,
+ unsigned cmd, unsigned long arg)
+{
+ int err = 0;
+ int tmp;
+ struct msm_dma_alloc_req alloc_req;
+ struct msm_dma_bufxfer xfer;
+ struct msm_dma_scopy scopy;
+ struct private *priv = file->private_data;
+
+ /* Verify user arguments. */
+ if (_IOC_TYPE(cmd) != MSM_DMA_IOC_MAGIC)
+ return -ENOTTY;
+
+ switch (cmd) {
+ case MSM_DMA_IOALLOC:
+ if (!access_ok(VERIFY_WRITE, (void __user *)arg,
+ sizeof(alloc_req)))
+ return -EFAULT;
+ if (__copy_from_user(&alloc_req, (void __user *)arg,
+ sizeof(alloc_req)))
+ return -EFAULT;
+ err = buffer_req(&alloc_req);
+ if (err < 0)
+ return err;
+ if (__copy_to_user((void __user *)arg, &alloc_req,
+ sizeof(alloc_req)))
+ return -EFAULT;
+ break;
+
+ case MSM_DMA_IOFREEALL:
+ down(&buffer_lock);
+ for (tmp = 0; tmp < MAX_TEST_BUFFERS; tmp++) {
+ buffer_down(tmp);
+ if (sizes[tmp] > 0) {
+ kfree(buffers[tmp]);
+ sizes[tmp] = 0;
+ }
+ buffer_up(tmp);
+ }
+ up(&buffer_lock);
+ break;
+
+ case MSM_DMA_IOWBUF:
+ if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer)))
+ return -EFAULT;
+ if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS)
+ return -EINVAL;
+ buffer_down(xfer.bufnum);
+ if (sizes[xfer.bufnum] == 0 ||
+ xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) {
+ buffer_up(xfer.bufnum);
+ return -EINVAL;
+ }
+ if (copy_from_user(buffers[xfer.bufnum],
+ (void __user *)xfer.data, xfer.size))
+ err = -EFAULT;
+ buffer_up(xfer.bufnum);
+ break;
+
+ case MSM_DMA_IORBUF:
+ if (copy_from_user(&xfer, (void __user *)arg, sizeof(xfer)))
+ return -EFAULT;
+ if (xfer.bufnum < 0 || xfer.bufnum >= MAX_TEST_BUFFERS)
+ return -EINVAL;
+ buffer_down(xfer.bufnum);
+ if (sizes[xfer.bufnum] == 0 ||
+ xfer.size <= 0 || xfer.size > sizes[xfer.bufnum]) {
+ buffer_up(xfer.bufnum);
+ return -EINVAL;
+ }
+ if (copy_to_user((void __user *)xfer.data, buffers[xfer.bufnum],
+ xfer.size))
+ err = -EFAULT;
+ buffer_up(xfer.bufnum);
+ break;
+
+ case MSM_DMA_IOSCOPY:
+ if (copy_from_user(&scopy, (void __user *)arg, sizeof(scopy)))
+ return -EFAULT;
+ if (scopy.srcbuf < 0 || scopy.srcbuf >= MAX_TEST_BUFFERS ||
+ sizes[scopy.srcbuf] == 0 ||
+ scopy.destbuf < 0 || scopy.destbuf >= MAX_TEST_BUFFERS ||
+ sizes[scopy.destbuf] == 0 ||
+ scopy.size > sizes[scopy.destbuf] ||
+ scopy.size > sizes[scopy.srcbuf])
+ return -EINVAL;
+#if 0
+ /* Test interface using memcpy. */
+ memcpy(buffers[scopy.destbuf],
+ buffers[scopy.srcbuf], scopy.size);
+#else
+ err = dma_scopy(&scopy, priv);
+#endif
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return err;
+}
+
+/**********************************************************************
+ * Register ourselves as a misc device to be able to test the DMA code
+ * from userspace. */
+
+static const struct file_operations dma_test_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dma_test_ioctl,
+ .open = dma_test_open,
+ .release = dma_test_release,
+};
+
+static struct miscdevice dma_test_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msmdma",
+ .fops = &dma_test_fops,
+};
+static int dma_test_init(void)
+{
+ int ret, i;
+
+ ret = misc_register(&dma_test_dev);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < MAX_TEST_BUFFERS; i++)
+ init_MUTEX(&buffer_sems[i]);
+
+ printk(KERN_ALERT "%s\n", __func__);
+ return 0;
+}
+
+static void dma_test_exit(void)
+{
+ free_buffers();
+ misc_deregister(&dma_test_dev);
+ printk(KERN_ALERT "%s\n", __func__);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Brown, Qualcomm, Incorporated");
+MODULE_DESCRIPTION("Test for MSM DMA driver");
+MODULE_VERSION("1.01");
+
+module_init(dma_test_init);
+module_exit(dma_test_exit);
diff --git a/arch/arm/mach-msm/fiq_glue.S b/arch/arm/mach-msm/fiq_glue.S
new file mode 100644
index 000000000000..9ded61cc0de8
--- /dev/null
+++ b/arch/arm/mach-msm/fiq_glue.S
@@ -0,0 +1,64 @@
+/* arch/arm/mach-msm/fiq_glue.S
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+ .text
+
+ .global fiq_glue_end
+
+ENTRY(fiq_glue)
+ adr r12, fiq_glue_ctxt_addr
+ ldr r8, [r12]
+ ldmia r8, {r9, r10, sp}
+
+ /* store pc, cpsr from previous mode */
+ sub r11, lr, #4
+ mrs r12, spsr
+ stmfd sp!, {r11-r12,lr}
+
+ /* store r8-r14 from previous mode */
+ sub sp, sp, #(7 * 4)
+ stmia sp, {r8-r14}^
+ nop
+
+ /* store r0-r7 from previous mode */
+ stmfd sp!, {r0-r7}
+
+ /* call func(data,regs) */
+ mov r0, r10
+ mov r1, sp
+ blx r9
+
+ /* restore/discard saved state */
+ ldmfd sp!, {r0-r7}
+ add sp, sp, #(9 * 4)
+ ldmfd sp!, {lr}
+
+ subs pc, lr, #4
+
+fiq_glue_ctxt_addr:
+ .long fiq_glue_ctxt
+fiq_glue_end:
+
+ENTRY(fiq_glue_setup) /* func, data, sp */
+ ldr r3, =fiq_glue_ctxt
+ stmia r3, {r0-r2}
+ bx lr
+
+ .data
+fiq_glue_ctxt:
+ .long 0, 0, 0
diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c
new file mode 100644
index 000000000000..fe24d38345d0
--- /dev/null
+++ b/arch/arm/mach-msm/generic_gpio.c
@@ -0,0 +1,274 @@
+/* arch/arm/mach-msm/generic_gpio.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * 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/errno.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/gpio.h>
+#include "gpio_chip.h"
+
+#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5)
+
+struct gpio_state {
+ unsigned long flags;
+ int refcount;
+};
+
+static DEFINE_SPINLOCK(gpio_chips_lock);
+static LIST_HEAD(gpio_chip_list);
+static struct gpio_chip **gpio_chip_array;
+static unsigned long gpio_chip_array_size;
+
+int register_gpio_chip(struct gpio_chip *new_gpio_chip)
+{
+ int err = 0;
+ struct gpio_chip *gpio_chip;
+ int i;
+ unsigned long irq_flags;
+ unsigned int chip_array_start_index, chip_array_end_index;
+
+ new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL);
+ if (new_gpio_chip->state == NULL) {
+ printk(KERN_ERR "register_gpio_chip: failed to allocate state\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start);
+ chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end);
+ if (chip_array_end_index >= gpio_chip_array_size) {
+ struct gpio_chip **new_gpio_chip_array;
+ unsigned long new_gpio_chip_array_size = chip_array_end_index + 1;
+
+ new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC);
+ if (new_gpio_chip_array == NULL) {
+ printk(KERN_ERR "register_gpio_chip: failed to allocate array\n");
+ err = -ENOMEM;
+ goto failed;
+ }
+ for (i = 0; i < gpio_chip_array_size; i++)
+ new_gpio_chip_array[i] = gpio_chip_array[i];
+ for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++)
+ new_gpio_chip_array[i] = NULL;
+ gpio_chip_array = new_gpio_chip_array;
+ gpio_chip_array_size = new_gpio_chip_array_size;
+ }
+ list_for_each_entry(gpio_chip, &gpio_chip_list, list) {
+ if (gpio_chip->start > new_gpio_chip->end) {
+ list_add_tail(&new_gpio_chip->list, &gpio_chip->list);
+ goto added;
+ }
+ if (gpio_chip->end >= new_gpio_chip->start) {
+ printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n",
+ new_gpio_chip->start, new_gpio_chip->end,
+ gpio_chip->start, gpio_chip->end);
+ err = -EBUSY;
+ goto failed;
+ }
+ }
+ list_add_tail(&new_gpio_chip->list, &gpio_chip_list);
+added:
+ for (i = chip_array_start_index; i <= chip_array_end_index; i++) {
+ if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start)
+ gpio_chip_array[i] = new_gpio_chip;
+ }
+failed:
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ if (err)
+ kfree(new_gpio_chip->state);
+ return err;
+}
+
+static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio)
+{
+ unsigned long i;
+ struct gpio_chip *chip;
+
+ i = GPIO_NUM_TO_CHIP_INDEX(gpio);
+ if (i >= gpio_chip_array_size)
+ return NULL;
+ chip = gpio_chip_array[i];
+ if (chip == NULL)
+ return NULL;
+ list_for_each_entry_from(chip, &gpio_chip_list, list) {
+ if (gpio < chip->start)
+ return NULL;
+ if (gpio <= chip->end)
+ return chip;
+ }
+ return NULL;
+}
+
+static int request_gpio(unsigned int gpio, unsigned long flags)
+{
+ int err = 0;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+ unsigned long chip_index;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip == NULL) {
+ err = -EINVAL;
+ goto err;
+ }
+ chip_index = gpio - chip->start;
+ if (chip->state[chip_index].refcount == 0) {
+ chip->configure(chip, gpio, flags);
+ chip->state[chip_index].flags = flags;
+ chip->state[chip_index].refcount++;
+ } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED))
+ chip->state[chip_index].refcount++;
+ else
+ err = -EBUSY;
+err:
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return err;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return request_gpio(gpio, 0);
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+ unsigned long chip_index;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip) {
+ chip_index = gpio - chip->start;
+ chip->state[chip_index].refcount--;
+ }
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+}
+EXPORT_SYMBOL(gpio_free);
+
+static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip && chip->get_irq_num)
+ ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return ret;
+}
+
+int gpio_to_irq(unsigned gpio)
+{
+ int ret, irq;
+ ret = gpio_get_irq_num(gpio, &irq, NULL);
+ if (ret)
+ return ret;
+ return irq;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int gpio_configure(unsigned int gpio, unsigned long flags)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip)
+ ret = chip->configure(chip, gpio, flags);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_configure);
+
+int gpio_direction_input(unsigned gpio)
+{
+ return gpio_configure(gpio, GPIOF_INPUT);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ gpio_set_value(gpio, value);
+ return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT);
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned gpio)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip && chip->read)
+ ret = chip->read(chip, gpio);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned gpio, int on)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip && chip->write)
+ ret = chip->write(chip, gpio, on);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_read_detect_status(unsigned int gpio)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip && chip->read_detect_status)
+ ret = chip->read_detect_status(chip, gpio);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_read_detect_status);
+
+int gpio_clear_detect_status(unsigned int gpio)
+{
+ int ret = -ENOTSUPP;
+ struct gpio_chip *chip;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&gpio_chips_lock, irq_flags);
+ chip = get_gpio_chip_locked(gpio);
+ if (chip && chip->clear_detect_status)
+ ret = chip->clear_detect_status(chip, gpio);
+ spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_clear_detect_status);
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
new file mode 100644
index 000000000000..598022906be6
--- /dev/null
+++ b/arch/arm/mach-msm/gpio.c
@@ -0,0 +1,746 @@
+/* linux/arch/arm/mach-msm/gpio.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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 <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include "gpio_chip.h"
+#include "gpio_hw.h"
+#include "proc_comm.h"
+
+#include "smd_private.h"
+
+enum {
+ GPIO_DEBUG_SLEEP = 1U << 0,
+};
+static int msm_gpio_debug_mask = 0;
+module_param_named(debug_mask, msm_gpio_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* private gpio_configure flags */
+#define MSM_GPIOF_ENABLE_INTERRUPT 0x10000000
+#define MSM_GPIOF_DISABLE_INTERRUPT 0x20000000
+#define MSM_GPIOF_ENABLE_WAKE 0x40000000
+#define MSM_GPIOF_DISABLE_WAKE 0x80000000
+
+static int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags);
+static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp);
+static int msm_gpio_read(struct gpio_chip *chip, unsigned n);
+static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on);
+static int msm_gpio_read_detect_status(struct gpio_chip *chip, unsigned int gpio);
+static int msm_gpio_clear_detect_status(struct gpio_chip *chip, unsigned int gpio);
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+ {
+ .regs = {
+ .out = GPIO_OUT_0,
+ .in = GPIO_IN_0,
+ .int_status = GPIO_INT_STATUS_0,
+ .int_clear = GPIO_INT_CLEAR_0,
+ .int_en = GPIO_INT_EN_0,
+ .int_edge = GPIO_INT_EDGE_0,
+ .int_pos = GPIO_INT_POS_0,
+ .oe = GPIO_OE_0,
+ },
+ .chip = {
+ .start = 0,
+ .end = 15,
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_1,
+ .in = GPIO_IN_1,
+ .int_status = GPIO_INT_STATUS_1,
+ .int_clear = GPIO_INT_CLEAR_1,
+ .int_en = GPIO_INT_EN_1,
+ .int_edge = GPIO_INT_EDGE_1,
+ .int_pos = GPIO_INT_POS_1,
+ .oe = GPIO_OE_1,
+ },
+ .chip = {
+ .start = 16,
+#if defined(CONFIG_ARCH_MSM7X30)
+ .end = 43,
+#else
+ .end = 42,
+#endif
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_2,
+ .in = GPIO_IN_2,
+ .int_status = GPIO_INT_STATUS_2,
+ .int_clear = GPIO_INT_CLEAR_2,
+ .int_en = GPIO_INT_EN_2,
+ .int_edge = GPIO_INT_EDGE_2,
+ .int_pos = GPIO_INT_POS_2,
+ .oe = GPIO_OE_2,
+ },
+ .chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+ .start = 44,
+#else
+ .start = 43,
+#endif
+ .end = 67,
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_3,
+ .in = GPIO_IN_3,
+ .int_status = GPIO_INT_STATUS_3,
+ .int_clear = GPIO_INT_CLEAR_3,
+ .int_en = GPIO_INT_EN_3,
+ .int_edge = GPIO_INT_EDGE_3,
+ .int_pos = GPIO_INT_POS_3,
+ .oe = GPIO_OE_3,
+ },
+ .chip = {
+ .start = 68,
+ .end = 94,
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_4,
+ .in = GPIO_IN_4,
+ .int_status = GPIO_INT_STATUS_4,
+ .int_clear = GPIO_INT_CLEAR_4,
+ .int_en = GPIO_INT_EN_4,
+ .int_edge = GPIO_INT_EDGE_4,
+ .int_pos = GPIO_INT_POS_4,
+ .oe = GPIO_OE_4,
+ },
+ .chip = {
+ .start = 95,
+#if defined(CONFIG_ARCH_QSD8X50)
+ .end = 103,
+#else
+ .end = 106,
+#endif
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_5,
+ .in = GPIO_IN_5,
+ .int_status = GPIO_INT_STATUS_5,
+ .int_clear = GPIO_INT_CLEAR_5,
+ .int_en = GPIO_INT_EN_5,
+ .int_edge = GPIO_INT_EDGE_5,
+ .int_pos = GPIO_INT_POS_5,
+ .oe = GPIO_OE_5,
+ },
+ .chip = {
+#if defined(CONFIG_ARCH_QSD8X50)
+ .start = 104,
+ .end = 121,
+#elif defined(CONFIG_ARCH_MSM7X30)
+ .start = 107,
+ .end = 133,
+#else
+ .start = 107,
+ .end = 132,
+#endif
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+ {
+ .regs = {
+ .out = GPIO_OUT_6,
+ .in = GPIO_IN_6,
+ .int_status = GPIO_INT_STATUS_6,
+ .int_clear = GPIO_INT_CLEAR_6,
+ .int_en = GPIO_INT_EN_6,
+ .int_edge = GPIO_INT_EDGE_6,
+ .int_pos = GPIO_INT_POS_6,
+ .oe = GPIO_OE_6,
+ },
+ .chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+ .start = 134,
+ .end = 150,
+#else
+ .start = 122,
+ .end = 152,
+#endif
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+ {
+ .regs = {
+ .out = GPIO_OUT_7,
+ .in = GPIO_IN_7,
+ .int_status = GPIO_INT_STATUS_7,
+ .int_clear = GPIO_INT_CLEAR_7,
+ .int_en = GPIO_INT_EN_7,
+ .int_edge = GPIO_INT_EDGE_7,
+ .int_pos = GPIO_INT_POS_7,
+ .oe = GPIO_OE_7,
+ },
+ .chip = {
+#if defined(CONFIG_ARCH_MSM7X30)
+ .start = 151,
+ .end = 181,
+#else
+ .start = 153,
+ .end = 164,
+#endif
+ .configure = msm_gpio_configure,
+ .get_irq_num = msm_gpio_get_irq_num,
+ .read = msm_gpio_read,
+ .write = msm_gpio_write,
+ .read_detect_status = msm_gpio_read_detect_status,
+ .clear_detect_status = msm_gpio_clear_detect_status
+ }
+ },
+#endif
+};
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+ int loop_limit = 100;
+ unsigned pol, val, val2, intstat;
+ do {
+ val = readl(msm_chip->regs.in);
+ pol = readl(msm_chip->regs.int_pos);
+ pol = (pol & ~msm_chip->both_edge_detect) | (~val & msm_chip->both_edge_detect);
+ writel(pol, msm_chip->regs.int_pos);
+ intstat = readl(msm_chip->regs.int_status);
+ val2 = readl(msm_chip->regs.in);
+ if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+ return;
+ } while (loop_limit-- > 0);
+ printk(KERN_ERR "msm_gpio_update_both_edge_detect, failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+ struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+ unsigned b = 1U << (n - chip->start);
+ unsigned v;
+
+ v = readl(msm_chip->regs.out);
+ if (on) {
+ writel(v | b, msm_chip->regs.out);
+ } else {
+ writel(v & (~b), msm_chip->regs.out);
+ }
+ return 0;
+}
+
+static int msm_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+ struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+ unsigned b = 1U << (n - chip->start);
+
+ return (readl(msm_chip->regs.in) & b) ? 1 : 0;
+}
+
+static int msm_gpio_read_detect_status(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+ unsigned b = 1U << (gpio - chip->start);
+ unsigned v;
+
+ v = readl(msm_chip->regs.int_status);
+#if MSM_GPIO_BROKEN_INT_CLEAR
+ v |= msm_chip->int_status_copy;
+#endif
+ return (v & b) ? 1 : 0;
+}
+
+static int msm_gpio_clear_detect_status(struct gpio_chip *chip, unsigned int gpio)
+{
+ struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+ unsigned b = 1U << (gpio - chip->start);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+ /* Save interrupts that already triggered before we loose them. */
+ /* Any interrupt that triggers between the read of int_status */
+ /* and the write to int_clear will still be lost though. */
+ msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+ msm_chip->int_status_copy &= ~b;
+#endif
+ writel(b, msm_chip->regs.int_clear);
+ msm_gpio_update_both_edge_detect(msm_chip);
+ return 0;
+}
+
+int msm_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags)
+{
+ struct msm_gpio_chip *msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+ unsigned b = 1U << (gpio - chip->start);
+ unsigned v;
+
+ if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH))
+ msm_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH);
+
+ if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) {
+ v = readl(msm_chip->regs.oe);
+ if (flags & GPIOF_DRIVE_OUTPUT) {
+ writel(v | b, msm_chip->regs.oe);
+ } else {
+ writel(v & (~b), msm_chip->regs.oe);
+ }
+ }
+
+ if (flags & (IRQF_TRIGGER_MASK | GPIOF_IRQF_TRIGGER_NONE)) {
+ v = readl(msm_chip->regs.int_edge);
+ if (flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+ writel(v | b, msm_chip->regs.int_edge);
+ irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq = handle_edge_irq;
+ } else {
+ writel(v & (~b), msm_chip->regs.int_edge);
+ irq_desc[MSM_GPIO_TO_INT(gpio)].handle_irq = handle_level_irq;
+ }
+ if ((flags & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) == (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING)) {
+ msm_chip->both_edge_detect |= b;
+ msm_gpio_update_both_edge_detect(msm_chip);
+ } else {
+ msm_chip->both_edge_detect &= ~b;
+ v = readl(msm_chip->regs.int_pos);
+ if (flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) {
+ writel(v | b, msm_chip->regs.int_pos);
+ } else {
+ writel(v & (~b), msm_chip->regs.int_pos);
+ }
+ }
+ }
+
+ /* used by msm_gpio_irq_mask and msm_gpio_irq_unmask */
+ if (flags & (MSM_GPIOF_ENABLE_INTERRUPT | MSM_GPIOF_DISABLE_INTERRUPT)) {
+ v = readl(msm_chip->regs.int_edge);
+ /* level triggered interrupts are also latched */
+ if (!(v & b))
+ msm_gpio_clear_detect_status(chip, gpio);
+ if (flags & MSM_GPIOF_ENABLE_INTERRUPT) {
+ msm_chip->int_enable[0] |= b;
+ } else {
+ msm_chip->int_enable[0] &= ~b;
+ }
+ writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+ }
+
+ if (flags & (MSM_GPIOF_ENABLE_WAKE | MSM_GPIOF_DISABLE_WAKE)) {
+ if (flags & MSM_GPIOF_ENABLE_WAKE)
+ msm_chip->int_enable[1] |= b;
+ else
+ msm_chip->int_enable[1] &= ~b;
+ }
+
+ return 0;
+}
+
+static int msm_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
+{
+ *irqp = MSM_GPIO_TO_INT(gpio);
+ if (irqnumflagsp)
+ *irqnumflagsp = 0;
+ return 0;
+}
+
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+ gpio_clear_detect_status(irq - NR_MSM_IRQS);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+ gpio_configure(irq - NR_MSM_IRQS, MSM_GPIOF_DISABLE_INTERRUPT);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+ gpio_configure(irq - NR_MSM_IRQS, MSM_GPIOF_ENABLE_INTERRUPT);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ return gpio_configure(irq - NR_MSM_IRQS, on ? MSM_GPIOF_ENABLE_WAKE : MSM_GPIOF_DISABLE_WAKE);
+}
+
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+ return gpio_configure(irq - NR_MSM_IRQS, flow_type);
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int i, j, m;
+ unsigned v;
+
+ for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+ struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+ v = readl(msm_chip->regs.int_status);
+ v &= msm_chip->int_enable[0];
+ while (v) {
+ m = v & -v;
+ j = fls(m) - 1;
+ /* printk("msm_gpio_irq_handler %08x %08x bit %d gpio %d irq %d\n", v, m, j, msm_chip->chip.start + j, NR_MSM_IRQS + msm_chip->chip.start + j); */
+ v &= ~m;
+ generic_handle_irq(NR_MSM_IRQS + msm_chip->chip.start + j);
+ }
+ }
+ desc->chip->ack(irq);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+ .name = "msmgpio",
+ .ack = msm_gpio_irq_ack,
+ .mask = msm_gpio_irq_mask,
+ .unmask = msm_gpio_irq_unmask,
+ .set_wake = msm_gpio_irq_set_wake,
+ .set_type = msm_gpio_irq_set_type,
+};
+
+#define NUM_GPIO_SMEM_BANKS 6
+#define GPIO_SMEM_NUM_GROUPS 2
+#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
+struct tramp_gpio_smem
+{
+ uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
+ uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
+ uint32_t enabled[NUM_GPIO_SMEM_BANKS];
+ uint32_t detection[NUM_GPIO_SMEM_BANKS];
+ uint32_t polarity[NUM_GPIO_SMEM_BANKS];
+};
+
+static void msm_gpio_sleep_int(unsigned long arg)
+{
+ int i, j;
+ struct tramp_gpio_smem *smem_gpio;
+
+ BUILD_BUG_ON(NR_GPIO_IRQS > NUM_GPIO_SMEM_BANKS * 32);
+
+#ifdef CONFIG_MACH_SMD
+ smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+#else
+ smem_gpio = NULL;
+#endif
+ if (smem_gpio == NULL)
+ return;
+
+ local_irq_disable();
+ for(i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
+ int count = smem_gpio->num_fired[i];
+ for(j = 0; j < count; j++) {
+ /* TODO: Check mask */
+ generic_handle_irq(MSM_GPIO_TO_INT(smem_gpio->fired[i][j]));
+ }
+ }
+ local_irq_enable();
+}
+
+static DECLARE_TASKLET(msm_gpio_sleep_int_tasklet, msm_gpio_sleep_int, 0);
+
+void msm_gpio_enter_sleep(int from_idle)
+{
+ int i;
+ struct tramp_gpio_smem *smem_gpio;
+
+#ifdef CONFIG_MSM_SMD
+ smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+#else
+ smem_gpio = NULL;
+#endif
+
+ if (smem_gpio) {
+ for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
+ smem_gpio->enabled[i] = 0;
+ smem_gpio->detection[i] = 0;
+ smem_gpio->polarity[i] = 0;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+ writel(msm_gpio_chips[i].int_enable[!from_idle], msm_gpio_chips[i].regs.int_en);
+ if (smem_gpio) {
+ uint32_t tmp;
+ int start, index, shiftl, shiftr;
+ start = msm_gpio_chips[i].chip.start;
+ index = start / 32;
+ shiftl = start % 32;
+ shiftr = 32 - shiftl;
+ tmp = msm_gpio_chips[i].int_enable[!from_idle];
+ smem_gpio->enabled[index] |= tmp << shiftl;
+ smem_gpio->enabled[index+1] |= tmp >> shiftr;
+ smem_gpio->detection[index] |= readl(msm_gpio_chips[i].regs.int_edge) << shiftl;
+ smem_gpio->detection[index+1] |= readl(msm_gpio_chips[i].regs.int_edge) >> shiftr;
+ smem_gpio->polarity[index] |= readl(msm_gpio_chips[i].regs.int_pos) << shiftl;
+ smem_gpio->polarity[index+1] |= readl(msm_gpio_chips[i].regs.int_pos) >> shiftr;
+ }
+ }
+
+ if (smem_gpio) {
+ if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
+ for (i = 0; i < ARRAY_SIZE(smem_gpio->enabled); i++) {
+ printk("msm_gpio_enter_sleep gpio %d-%d: enable"
+ " %08x, edge %08x, polarity %08x\n",
+ i * 32, i * 32 + 31,
+ smem_gpio->enabled[i],
+ smem_gpio->detection[i],
+ smem_gpio->polarity[i]);
+ }
+ for(i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
+ smem_gpio->num_fired[i] = 0;
+ }
+}
+
+void msm_gpio_exit_sleep(void)
+{
+ int i;
+ struct tramp_gpio_smem *smem_gpio;
+
+#ifdef CONFIG_MSM_SMD
+ smem_gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*smem_gpio));
+#else
+ smem_gpio = NULL;
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+ writel(msm_gpio_chips[i].int_enable[0], msm_gpio_chips[i].regs.int_en);
+ }
+
+ if (smem_gpio && (smem_gpio->num_fired[0] || smem_gpio->num_fired[1])) {
+ if (msm_gpio_debug_mask & GPIO_DEBUG_SLEEP)
+ printk(KERN_INFO "gpio: fired %x %x\n",
+ smem_gpio->num_fired[0], smem_gpio->num_fired[1]);
+ tasklet_schedule(&msm_gpio_sleep_int_tasklet);
+ }
+}
+
+static int __init msm_init_gpio(void)
+{
+ int i;
+
+ for (i = NR_MSM_IRQS; i < NR_MSM_IRQS + NR_GPIO_IRQS; i++) {
+ set_irq_chip(i, &msm_gpio_irq_chip);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+ writel(0, msm_gpio_chips[i].regs.int_en);
+ register_gpio_chip(&msm_gpio_chips[i].chip);
+ }
+
+ set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+ set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+ set_irq_wake(INT_GPIO_GROUP1, 1);
+ set_irq_wake(INT_GPIO_GROUP2, 2);
+ return 0;
+}
+
+postcore_initcall(msm_init_gpio);
+
+int gpio_tlmm_config(unsigned config, unsigned disable)
+{
+ return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
+}
+EXPORT_SYMBOL(gpio_tlmm_config);
+
+int msm_gpios_request_enable(const struct msm_gpio *table, int size)
+{
+ int rc = msm_gpios_request(table, size);
+ if (rc)
+ return rc;
+ rc = msm_gpios_enable(table, size);
+ if (rc)
+ msm_gpios_free(table, size);
+ return rc;
+}
+EXPORT_SYMBOL(msm_gpios_request_enable);
+
+void msm_gpios_disable_free(const struct msm_gpio *table, int size)
+{
+ msm_gpios_disable(table, size);
+ msm_gpios_free(table, size);
+}
+EXPORT_SYMBOL(msm_gpios_disable_free);
+
+int msm_gpios_request(const struct msm_gpio *table, int size)
+{
+ int rc;
+ int i;
+ const struct msm_gpio *g;
+ for (i = 0; i < size; i++) {
+ g = table + i;
+ rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
+ if (rc) {
+ pr_err("gpio_request(%d) <%s> failed: %d\n",
+ GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
+ goto err;
+ }
+ }
+ return 0;
+err:
+ msm_gpios_free(table, i);
+ return rc;
+}
+EXPORT_SYMBOL(msm_gpios_request);
+
+void msm_gpios_free(const struct msm_gpio *table, int size)
+{
+ int i;
+ const struct msm_gpio *g;
+ for (i = size-1; i >= 0; i--) {
+ g = table + i;
+ gpio_free(GPIO_PIN(g->gpio_cfg));
+ }
+}
+EXPORT_SYMBOL(msm_gpios_free);
+
+int msm_gpios_enable(const struct msm_gpio *table, int size)
+{
+ int rc;
+ int i;
+ const struct msm_gpio *g;
+ for (i = 0; i < size; i++) {
+ g = table + i;
+ rc = gpio_tlmm_config(g->gpio_cfg, GPIO_ENABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config(0x%08x, GPIO_ENABLE)"
+ " <%s> failed: %d\n",
+ g->gpio_cfg, g->label ?: "?", rc);
+ pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
+ GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
+ GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
+ GPIO_DRVSTR(g->gpio_cfg));
+ goto err;
+ }
+ }
+ return 0;
+err:
+ msm_gpios_disable(table, i);
+ return rc;
+}
+EXPORT_SYMBOL(msm_gpios_enable);
+
+void msm_gpios_disable(const struct msm_gpio *table, int size)
+{
+ int rc;
+ int i;
+ const struct msm_gpio *g;
+ for (i = size-1; i >= 0; i--) {
+ g = table + i;
+ rc = gpio_tlmm_config(g->gpio_cfg, GPIO_DISABLE);
+ if (rc) {
+ pr_err("gpio_tlmm_config(0x%08x, GPIO_DISABLE)"
+ " <%s> failed: %d\n",
+ g->gpio_cfg, g->label ?: "?", rc);
+ pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
+ GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
+ GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
+ GPIO_DRVSTR(g->gpio_cfg));
+ }
+ }
+}
+EXPORT_SYMBOL(msm_gpios_disable);
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int msm_gpio_debug_result = 1;
+
+static int gpio_enable_set(void *data, u64 val)
+{
+ msm_gpio_debug_result = gpio_tlmm_config(val, 0);
+ return 0;
+}
+static int gpio_disable_set(void *data, u64 val)
+{
+ msm_gpio_debug_result = gpio_tlmm_config(val, 1);
+ return 0;
+}
+
+static int gpio_debug_get(void *data, u64 *val)
+{
+ unsigned int result = msm_gpio_debug_result;
+ msm_gpio_debug_result = 1;
+ if (result)
+ *val = 1;
+ else
+ *val = 0;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(gpio_enable_fops, gpio_debug_get,
+ gpio_enable_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(gpio_disable_fops, gpio_debug_get,
+ gpio_disable_set, "%llu\n");
+
+static int __init gpio_debug_init(void)
+{
+ struct dentry *dent;
+ dent = debugfs_create_dir("gpio", 0);
+ if (IS_ERR(dent))
+ return 0;
+
+ debugfs_create_file("enable", 0644, dent, 0, &gpio_enable_fops);
+ debugfs_create_file("disable", 0644, dent, 0, &gpio_disable_fops);
+ return 0;
+}
+
+device_initcall(gpio_debug_init);
+#endif
+
diff --git a/arch/arm/mach-msm/gpio.h b/arch/arm/mach-msm/gpio.h
new file mode 100644
index 000000000000..b411bc1e3c8f
--- /dev/null
+++ b/arch/arm/mach-msm/gpio.h
@@ -0,0 +1,35 @@
+/* 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 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_GPIO_H_
+#define _ARCH_ARM_MACH_MSM_GPIO_H_
+
+void msm_gpio_enter_sleep(int from_idle);
+void msm_gpio_exit_sleep(void);
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h
new file mode 100644
index 000000000000..39ccc0f0ed8e
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_chip.h
@@ -0,0 +1,61 @@
+/* arch/arm/mach-msm/gpio_chip.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * 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_GPIO_CHIP_H
+#define _LINUX_GPIO_CHIP_H
+
+#include <linux/list.h>
+
+struct gpio_chip {
+ struct list_head list;
+ struct gpio_state *state;
+
+ unsigned int start;
+ unsigned int end;
+
+ int (*configure)(struct gpio_chip *chip, unsigned int gpio, unsigned long flags);
+ int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp);
+ int (*read)(struct gpio_chip *chip, unsigned int gpio);
+ int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on);
+ int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+ int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio);
+};
+
+struct msm_gpio_regs {
+ void __iomem *out;
+ void __iomem *in;
+ void __iomem *int_status;
+ void __iomem *int_clear;
+ void __iomem *int_en;
+ void __iomem *int_edge;
+ void __iomem *int_pos;
+ void __iomem *oe;
+};
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+struct msm_gpio_chip {
+ struct gpio_chip chip;
+ struct msm_gpio_regs regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+ unsigned int_status_copy;
+#endif
+ unsigned int both_edge_detect;
+ unsigned int int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+int register_gpio_chip(struct gpio_chip *gpio_chip);
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_hw-7x30.h b/arch/arm/mach-msm/gpio_hw-7x30.h
new file mode 100644
index 000000000000..9142e7e6045c
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw-7x30.h
@@ -0,0 +1,112 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_7X30_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_7X30_H
+
+/* output value */
+#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */
+#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 43-16 */
+#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-44 */
+#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */
+#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */
+#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 133-107 */
+#define GPIO_OUT_6 GPIO1_REG(0xC4) /* gpio 150-134 */
+#define GPIO_OUT_7 GPIO1_REG(0x214) /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0 GPIO1_REG(0x10)
+#define GPIO_OE_1 GPIO2_REG(0x08)
+#define GPIO_OE_2 GPIO1_REG(0x14)
+#define GPIO_OE_3 GPIO1_REG(0x18)
+#define GPIO_OE_4 GPIO1_REG(0x1C)
+#define GPIO_OE_5 GPIO1_REG(0x54)
+#define GPIO_OE_6 GPIO1_REG(0xC8)
+#define GPIO_OE_7 GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0 GPIO1_REG(0x34)
+#define GPIO_IN_1 GPIO2_REG(0x20)
+#define GPIO_IN_2 GPIO1_REG(0x38)
+#define GPIO_IN_3 GPIO1_REG(0x3C)
+#define GPIO_IN_4 GPIO1_REG(0x40)
+#define GPIO_IN_5 GPIO1_REG(0x44)
+#define GPIO_IN_6 GPIO1_REG(0xCC)
+#define GPIO_IN_7 GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0 GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1 GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2 GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3 GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0)
+#define GPIO_INT_EDGE_6 GPIO1_REG(0xD0)
+#define GPIO_INT_EDGE_7 GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0 GPIO1_REG(0x70)
+#define GPIO_INT_POS_1 GPIO2_REG(0x58)
+#define GPIO_INT_POS_2 GPIO1_REG(0x74)
+#define GPIO_INT_POS_3 GPIO1_REG(0x78)
+#define GPIO_INT_POS_4 GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5 GPIO1_REG(0xBC)
+#define GPIO_INT_POS_6 GPIO1_REG(0xD4)
+#define GPIO_INT_POS_7 GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0 GPIO1_REG(0x80)
+#define GPIO_INT_EN_1 GPIO2_REG(0x60)
+#define GPIO_INT_EN_2 GPIO1_REG(0x84)
+#define GPIO_INT_EN_3 GPIO1_REG(0x88)
+#define GPIO_INT_EN_4 GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5 GPIO1_REG(0xB8)
+#define GPIO_INT_EN_6 GPIO1_REG(0xD8)
+#define GPIO_INT_EN_7 GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4)
+#define GPIO_INT_CLEAR_6 GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_7 GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1 GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0)
+#define GPIO_INT_STATUS_6 GPIO1_REG(0xE0)
+#define GPIO_INT_STATUS_7 GPIO1_REG(0x234)
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_hw-7xxx.h b/arch/arm/mach-msm/gpio_hw-7xxx.h
new file mode 100644
index 000000000000..17b4d80c2310
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw-7xxx.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_7XXX_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_7XXX_H
+
+/* output value */
+#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */
+#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */
+#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */
+#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */
+#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */
+#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0 GPIO1_REG(0x10)
+#define GPIO_OE_1 GPIO2_REG(0x08)
+#define GPIO_OE_2 GPIO1_REG(0x14)
+#define GPIO_OE_3 GPIO1_REG(0x18)
+#define GPIO_OE_4 GPIO1_REG(0x1C)
+#define GPIO_OE_5 GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0 GPIO1_REG(0x34)
+#define GPIO_IN_1 GPIO2_REG(0x20)
+#define GPIO_IN_2 GPIO1_REG(0x38)
+#define GPIO_IN_3 GPIO1_REG(0x3C)
+#define GPIO_IN_4 GPIO1_REG(0x40)
+#define GPIO_IN_5 GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0 GPIO1_REG(0x60)
+#define GPIO_INT_EDGE_1 GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2 GPIO1_REG(0x64)
+#define GPIO_INT_EDGE_3 GPIO1_REG(0x68)
+#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0 GPIO1_REG(0x70)
+#define GPIO_INT_POS_1 GPIO2_REG(0x58)
+#define GPIO_INT_POS_2 GPIO1_REG(0x74)
+#define GPIO_INT_POS_3 GPIO1_REG(0x78)
+#define GPIO_INT_POS_4 GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5 GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0 GPIO1_REG(0x80)
+#define GPIO_INT_EN_1 GPIO2_REG(0x60)
+#define GPIO_INT_EN_2 GPIO1_REG(0x84)
+#define GPIO_INT_EN_3 GPIO1_REG(0x88)
+#define GPIO_INT_EN_4 GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5 GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90)
+#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94)
+#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98)
+#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0)
+#define GPIO_INT_STATUS_1 GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4)
+#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8)
+#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0)
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_hw-8xxx.h b/arch/arm/mach-msm/gpio_hw-8xxx.h
new file mode 100644
index 000000000000..91b1a43298fd
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw-8xxx.h
@@ -0,0 +1,112 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_8XXX_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_8XXX_H
+
+/* output value */
+#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */
+#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */
+#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */
+#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */
+#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 103-95 */
+#define GPIO_OUT_5 GPIO1_REG(0x10) /* gpio 121-104 */
+#define GPIO_OUT_6 GPIO1_REG(0x14) /* gpio 152-122 */
+#define GPIO_OUT_7 GPIO1_REG(0x18) /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define GPIO_OE_0 GPIO1_REG(0x20)
+#define GPIO_OE_1 GPIO2_REG(0x08)
+#define GPIO_OE_2 GPIO1_REG(0x24)
+#define GPIO_OE_3 GPIO1_REG(0x28)
+#define GPIO_OE_4 GPIO1_REG(0x2C)
+#define GPIO_OE_5 GPIO1_REG(0x30)
+#define GPIO_OE_6 GPIO1_REG(0x34)
+#define GPIO_OE_7 GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define GPIO_IN_0 GPIO1_REG(0x50)
+#define GPIO_IN_1 GPIO2_REG(0x20)
+#define GPIO_IN_2 GPIO1_REG(0x54)
+#define GPIO_IN_3 GPIO1_REG(0x58)
+#define GPIO_IN_4 GPIO1_REG(0x5C)
+#define GPIO_IN_5 GPIO1_REG(0x60)
+#define GPIO_IN_6 GPIO1_REG(0x64)
+#define GPIO_IN_7 GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define GPIO_INT_EDGE_0 GPIO1_REG(0x70)
+#define GPIO_INT_EDGE_1 GPIO2_REG(0x50)
+#define GPIO_INT_EDGE_2 GPIO1_REG(0x74)
+#define GPIO_INT_EDGE_3 GPIO1_REG(0x78)
+#define GPIO_INT_EDGE_4 GPIO1_REG(0x7C)
+#define GPIO_INT_EDGE_5 GPIO1_REG(0x80)
+#define GPIO_INT_EDGE_6 GPIO1_REG(0x84)
+#define GPIO_INT_EDGE_7 GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define GPIO_INT_POS_0 GPIO1_REG(0x90)
+#define GPIO_INT_POS_1 GPIO2_REG(0x58)
+#define GPIO_INT_POS_2 GPIO1_REG(0x94)
+#define GPIO_INT_POS_3 GPIO1_REG(0x98)
+#define GPIO_INT_POS_4 GPIO1_REG(0x9C)
+#define GPIO_INT_POS_5 GPIO1_REG(0xA0)
+#define GPIO_INT_POS_6 GPIO1_REG(0xA4)
+#define GPIO_INT_POS_7 GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define GPIO_INT_EN_0 GPIO1_REG(0xB0)
+#define GPIO_INT_EN_1 GPIO2_REG(0x60)
+#define GPIO_INT_EN_2 GPIO1_REG(0xB4)
+#define GPIO_INT_EN_3 GPIO1_REG(0xB8)
+#define GPIO_INT_EN_4 GPIO1_REG(0xBC)
+#define GPIO_INT_EN_5 GPIO1_REG(0xC0)
+#define GPIO_INT_EN_6 GPIO1_REG(0xC4)
+#define GPIO_INT_EN_7 GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define GPIO_INT_CLEAR_0 GPIO1_REG(0xD0)
+#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68)
+#define GPIO_INT_CLEAR_2 GPIO1_REG(0xD4)
+#define GPIO_INT_CLEAR_3 GPIO1_REG(0xD8)
+#define GPIO_INT_CLEAR_4 GPIO1_REG(0xDC)
+#define GPIO_INT_CLEAR_5 GPIO1_REG(0xE0)
+#define GPIO_INT_CLEAR_6 GPIO1_REG(0xE4)
+#define GPIO_INT_CLEAR_7 GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define GPIO_INT_STATUS_0 GPIO1_REG(0xF0)
+#define GPIO_INT_STATUS_1 GPIO2_REG(0x70)
+#define GPIO_INT_STATUS_2 GPIO1_REG(0xF4)
+#define GPIO_INT_STATUS_3 GPIO1_REG(0xF8)
+#define GPIO_INT_STATUS_4 GPIO1_REG(0xFC)
+#define GPIO_INT_STATUS_5 GPIO1_REG(0x100)
+#define GPIO_INT_STATUS_6 GPIO1_REG(0x104)
+#define GPIO_INT_STATUS_7 GPIO1_REG(0x108)
+
+#endif
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
new file mode 100644
index 000000000000..cc6b036c1dbc
--- /dev/null
+++ b/arch/arm/mach-msm/gpio_hw.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#else
+#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+#include "gpio_hw-8xxx.h"
+#elif defined(CONFIG_ARCH_MSM7X30)
+#include "gpio_hw-7x30.h"
+#else
+#include "gpio_hw-7xxx.h"
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/htc_acoustic.c b/arch/arm/mach-msm/htc_acoustic.c
new file mode 100644
index 000000000000..3de71dddb589
--- /dev/null
+++ b/arch/arm/mach-msm/htc_acoustic.c
@@ -0,0 +1,239 @@
+/* arch/arm/mach-msm/htc_acoustic.c
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Laurence Chen <Laurence_Chen@htc.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/device.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/msm_iomap.h>
+
+#include "smd_private.h"
+
+#define ACOUSTIC_IOCTL_MAGIC 'p'
+#define ACOUSTIC_ARM11_DONE _IOW(ACOUSTIC_IOCTL_MAGIC, 22, unsigned int)
+
+#define HTCRPOG 0x30100002
+#define HTCVERS 0
+#define ONCRPC_SET_MIC_BIAS_PROC (1)
+#define ONCRPC_ACOUSTIC_INIT_PROC (5)
+#define ONCRPC_ALLOC_ACOUSTIC_MEM_PROC (6)
+
+#define HTC_ACOUSTIC_TABLE_SIZE (0x10000)
+
+#define D(fmt, args...) printk(KERN_INFO "htc-acoustic: "fmt, ##args)
+#define E(fmt, args...) printk(KERN_ERR "htc-acoustic: "fmt, ##args)
+
+struct set_smem_req {
+ struct rpc_request_hdr hdr;
+ uint32_t size;
+};
+
+struct set_smem_rep {
+ struct rpc_reply_hdr hdr;
+ int n;
+};
+
+struct set_acoustic_req {
+ struct rpc_request_hdr hdr;
+};
+
+struct set_acoustic_rep {
+ struct rpc_reply_hdr hdr;
+ int n;
+};
+
+static uint32_t htc_acoustic_vir_addr;
+static struct msm_rpc_endpoint *endpoint;
+static struct mutex api_lock;
+
+static int acoustic_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long pgoff, delta;
+ int rc = -EINVAL;
+ size_t size;
+
+ D("mmap\n");
+
+ mutex_lock(&api_lock);
+
+ size = vma->vm_end - vma->vm_start;
+
+ if (vma->vm_pgoff != 0) {
+ E("mmap failed: page offset %lx\n", vma->vm_pgoff);
+ goto done;
+ }
+
+ if (!htc_acoustic_vir_addr) {
+ E("mmap failed: smem region not allocated\n");
+ rc = -EIO;
+ goto done;
+ }
+
+ pgoff = MSM_SHARED_RAM_PHYS +
+ (htc_acoustic_vir_addr - (uint32_t)MSM_SHARED_RAM_BASE);
+ delta = PAGE_ALIGN(pgoff) - pgoff;
+
+ if (size + delta > HTC_ACOUSTIC_TABLE_SIZE) {
+ E("mmap failed: size %d\n", size);
+ goto done;
+ }
+
+ pgoff += delta;
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ rc = io_remap_pfn_range(vma, vma->vm_start, pgoff >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+
+ if (rc < 0)
+ E("mmap failed: remap error %d\n", rc);
+
+done: mutex_unlock(&api_lock);
+ return rc;
+}
+
+static int acoustic_open(struct inode *inode, struct file *file)
+{
+ int rc = -EIO;
+ struct set_smem_req req_smem;
+ struct set_smem_rep rep_smem;
+
+ D("open\n");
+
+ mutex_lock(&api_lock);
+
+ if (!htc_acoustic_vir_addr) {
+ if (endpoint == NULL) {
+ endpoint = msm_rpc_connect(HTCRPOG, HTCVERS, 0);
+ if (IS_ERR(endpoint)) {
+ E("init rpc failed! rc = %ld\n",
+ PTR_ERR(endpoint));
+ endpoint = NULL;
+ goto done;
+ }
+ }
+
+ req_smem.size = cpu_to_be32(HTC_ACOUSTIC_TABLE_SIZE);
+ rc = msm_rpc_call_reply(endpoint,
+ ONCRPC_ALLOC_ACOUSTIC_MEM_PROC,
+ &req_smem, sizeof(req_smem),
+ &rep_smem, sizeof(rep_smem),
+ 5 * HZ);
+
+ if (rep_smem.n != 0 || rc < 0) {
+ E("open failed: ALLOC_ACOUSTIC_MEM_PROC error %d.\n",
+ rc);
+ goto done;
+ }
+ htc_acoustic_vir_addr =
+ (uint32_t)smem_alloc(SMEM_ID_VENDOR1,
+ HTC_ACOUSTIC_TABLE_SIZE);
+ if (!htc_acoustic_vir_addr) {
+ E("open failed: smem_alloc error\n");
+ goto done;
+ }
+ }
+
+ rc = 0;
+done:
+ mutex_unlock(&api_lock);
+ return rc;
+}
+
+static int acoustic_release(struct inode *inode, struct file *file)
+{
+ D("release\n");
+ return 0;
+}
+
+static long acoustic_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc, reply_value;
+ struct set_acoustic_req req;
+ struct set_acoustic_rep rep;
+
+ D("ioctl\n");
+
+ mutex_lock(&api_lock);
+
+ switch (cmd) {
+ case ACOUSTIC_ARM11_DONE:
+ D("ioctl: ACOUSTIC_ARM11_DONE called %d.\n", current->pid);
+ rc = msm_rpc_call_reply(endpoint,
+ ONCRPC_ACOUSTIC_INIT_PROC, &req,
+ sizeof(req), &rep, sizeof(rep),
+ 5 * HZ);
+
+ reply_value = be32_to_cpu(rep.n);
+ if (reply_value != 0 || rc < 0) {
+ E("ioctl failed: ONCRPC_ACOUSTIC_INIT_PROC "\
+ "error %d.\n", rc);
+ if (rc >= 0)
+ rc = -EIO;
+ break;
+ }
+ D("ioctl: ONCRPC_ACOUSTIC_INIT_PROC success.\n");
+ break;
+ default:
+ E("ioctl: invalid command\n");
+ rc = -EINVAL;
+ }
+
+ mutex_unlock(&api_lock);
+ return 0;
+}
+
+
+static struct file_operations acoustic_fops = {
+ .owner = THIS_MODULE,
+ .open = acoustic_open,
+ .release = acoustic_release,
+ .mmap = acoustic_mmap,
+ .unlocked_ioctl = acoustic_ioctl,
+};
+
+static struct miscdevice acoustic_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "htc-acoustic",
+ .fops = &acoustic_fops,
+};
+
+static int __init acoustic_init(void)
+{
+ mutex_init(&api_lock);
+ return misc_register(&acoustic_misc);
+}
+
+static void __exit acoustic_exit(void)
+{
+ misc_deregister(&acoustic_misc);
+}
+
+module_init(acoustic_init);
+module_exit(acoustic_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC acoustic driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_akm_cal.c b/arch/arm/mach-msm/htc_akm_cal.c
new file mode 100644
index 000000000000..943083fe0fbe
--- /dev/null
+++ b/arch/arm/mach-msm/htc_akm_cal.c
@@ -0,0 +1,64 @@
+/* arch/arm/mach-msm/htc_akm_cal.c
+ *
+ * Code to extract compass calibration information from ATAG set up
+ * by the bootloader.
+ *
+ * Copyright (C) 2007-2008 HTC Corporation
+ * Author: Farmer Tseng <farmer_tseng@htc.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 <asm/setup.h>
+
+/* configuration tags specific to AKM8976 */
+#define ATAG_AKM8976 0x89768976 /* AKM8976 */
+
+#define MAX_CALI_SIZE 0x1000U
+
+static char akm_cal_ram[MAX_CALI_SIZE];
+
+char *get_akm_cal_ram(void)
+{
+ return(akm_cal_ram);
+}
+EXPORT_SYMBOL(get_akm_cal_ram);
+
+static int __init parse_tag_akm(const struct tag *tag)
+{
+ unsigned char *dptr = (unsigned char *)(&tag->u);
+ unsigned size;
+
+ size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_CALI_SIZE);
+
+ printk(KERN_INFO "AKM Data size = %d , 0x%x, size = %d\n",
+ tag->hdr.size, tag->hdr.tag, size);
+
+#ifdef ATAG_COMPASS_DEBUG
+ unsigned i;
+ unsigned char *ptr;
+
+ ptr = dptr;
+ printk(KERN_INFO
+ "AKM Data size = %d , 0x%x\n",
+ tag->hdr.size, tag->hdr.tag);
+ for (i = 0; i < size; i++)
+ printk(KERN_INFO "%02x ", *ptr++);
+#endif
+ memcpy((void *)akm_cal_ram, (void *)dptr, size);
+ return 0;
+}
+
+__tagtable(ATAG_AKM8976, parse_tag_akm);
diff --git a/arch/arm/mach-msm/htc_battery.c b/arch/arm/mach-msm/htc_battery.c
new file mode 100644
index 000000000000..7320edbff1a9
--- /dev/null
+++ b/arch/arm/mach-msm/htc_battery.c
@@ -0,0 +1,769 @@
+/* arch/arm/mach-msm/htc_battery.c
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/wakelock.h>
+#include <asm/gpio.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+static struct wake_lock vbus_wake_lock;
+
+#define TRACE_BATT 0
+
+#if TRACE_BATT
+#define BATT(x...) printk(KERN_INFO "[BATT] " x)
+#else
+#define BATT(x...) do {} while (0)
+#endif
+
+/* rpc related */
+#define APP_BATT_PDEV_NAME "rs30100001:00000000"
+#define APP_BATT_PROG 0x30100001
+#define APP_BATT_VER 0
+#define HTC_PROCEDURE_BATTERY_NULL 0
+#define HTC_PROCEDURE_GET_BATT_LEVEL 1
+#define HTC_PROCEDURE_GET_BATT_INFO 2
+#define HTC_PROCEDURE_GET_CABLE_STATUS 3
+#define HTC_PROCEDURE_SET_BATT_DELTA 4
+
+/* module debugger */
+#define HTC_BATTERY_DEBUG 1
+#define BATTERY_PREVENTION 1
+
+/* Enable this will shut down if no battery */
+#define ENABLE_BATTERY_DETECTION 0
+
+#define GPIO_BATTERY_DETECTION 21
+#define GPIO_BATTERY_CHARGER_EN 128
+
+/* Charge current selection */
+#define GPIO_BATTERY_CHARGER_CURRENT 129
+
+typedef enum {
+ DISABLE = 0,
+ ENABLE_SLOW_CHG,
+ ENABLE_FAST_CHG
+} batt_ctl_t;
+
+/* This order is the same as htc_power_supplies[]
+ * And it's also the same as htc_cable_status_update()
+ */
+typedef enum {
+ CHARGER_BATTERY = 0,
+ CHARGER_USB,
+ CHARGER_AC
+} charger_type_t;
+
+struct battery_info_reply {
+ u32 batt_id; /* Battery ID from ADC */
+ u32 batt_vol; /* Battery voltage from ADC */
+ u32 batt_temp; /* Battery Temperature (C) from formula and ADC */
+ u32 batt_current; /* Battery current from ADC */
+ u32 level; /* formula */
+ u32 charging_source; /* 0: no cable, 1:usb, 2:AC */
+ u32 charging_enabled; /* 0: Disable, 1: Enable */
+ u32 full_bat; /* Full capacity of battery (mAh) */
+};
+
+struct htc_battery_info {
+ int present;
+ unsigned long update_time;
+
+ /* lock to protect the battery info */
+ struct mutex lock;
+
+ /* lock held while calling the arm9 to query the battery info */
+ struct mutex rpc_lock;
+ struct battery_info_reply rep;
+};
+
+static struct msm_rpc_endpoint *endpoint;
+
+static struct htc_battery_info htc_batt_info;
+
+static unsigned int cache_time = 1000;
+
+static int htc_battery_initial = 0;
+
+static enum power_supply_property htc_battery_properties[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static enum power_supply_property htc_power_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static char *supply_list[] = {
+ "battery",
+};
+
+/* HTC dedicated attributes */
+static ssize_t htc_battery_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+
+static int htc_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val);
+
+static int htc_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val);
+
+static struct power_supply htc_power_supplies[] = {
+ {
+ .name = "battery",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = htc_battery_properties,
+ .num_properties = ARRAY_SIZE(htc_battery_properties),
+ .get_property = htc_battery_get_property,
+ },
+ {
+ .name = "usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .supplied_to = supply_list,
+ .num_supplicants = ARRAY_SIZE(supply_list),
+ .properties = htc_power_properties,
+ .num_properties = ARRAY_SIZE(htc_power_properties),
+ .get_property = htc_power_get_property,
+ },
+ {
+ .name = "ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .supplied_to = supply_list,
+ .num_supplicants = ARRAY_SIZE(supply_list),
+ .properties = htc_power_properties,
+ .num_properties = ARRAY_SIZE(htc_power_properties),
+ .get_property = htc_power_get_property,
+ },
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+#if defined(CONFIG_DEBUG_FS)
+int htc_battery_set_charging(batt_ctl_t ctl);
+static int batt_debug_set(void *data, u64 val)
+{
+ return htc_battery_set_charging((batt_ctl_t) val);
+}
+
+static int batt_debug_get(void *data, u64 *val)
+{
+ return -ENOSYS;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(batt_debug_fops, batt_debug_get, batt_debug_set, "%llu\n");
+static int __init batt_debug_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("htc_battery", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("charger_state", 0644, dent, NULL, &batt_debug_fops);
+
+ return 0;
+}
+
+device_initcall(batt_debug_init);
+#endif
+
+static int init_batt_gpio(void)
+{
+ if (gpio_request(GPIO_BATTERY_DETECTION, "batt_detect") < 0)
+ goto gpio_failed;
+ if (gpio_request(GPIO_BATTERY_CHARGER_EN, "charger_en") < 0)
+ goto gpio_failed;
+ if (gpio_request(GPIO_BATTERY_CHARGER_CURRENT, "charge_current") < 0)
+ goto gpio_failed;
+
+ return 0;
+
+gpio_failed:
+ return -EINVAL;
+
+}
+
+/*
+ * battery_charging_ctrl - battery charing control.
+ * @ctl: battery control command
+ *
+ */
+static int battery_charging_ctrl(batt_ctl_t ctl)
+{
+ int result = 0;
+
+ switch (ctl) {
+ case DISABLE:
+ BATT("charger OFF\n");
+ /* 0 for enable; 1 disable */
+ result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 1);
+ break;
+ case ENABLE_SLOW_CHG:
+ BATT("charger ON (SLOW)\n");
+ result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 0);
+ result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+ break;
+ case ENABLE_FAST_CHG:
+ BATT("charger ON (FAST)\n");
+ result = gpio_direction_output(GPIO_BATTERY_CHARGER_CURRENT, 1);
+ result = gpio_direction_output(GPIO_BATTERY_CHARGER_EN, 0);
+ break;
+ default:
+ printk(KERN_ERR "Not supported battery ctr called.!\n");
+ result = -EINVAL;
+ break;
+ }
+
+ return result;
+}
+
+int htc_battery_set_charging(batt_ctl_t ctl)
+{
+ int rc;
+
+ if ((rc = battery_charging_ctrl(ctl)) < 0)
+ goto result;
+
+ if (!htc_battery_initial) {
+ htc_batt_info.rep.charging_enabled = ctl & 0x3;
+ } else {
+ mutex_lock(&htc_batt_info.lock);
+ htc_batt_info.rep.charging_enabled = ctl & 0x3;
+ mutex_unlock(&htc_batt_info.lock);
+ }
+result:
+ return rc;
+}
+
+int htc_battery_status_update(u32 curr_level)
+{
+ int notify;
+ if (!htc_battery_initial)
+ return 0;
+
+ mutex_lock(&htc_batt_info.lock);
+ notify = (htc_batt_info.rep.level != curr_level);
+ htc_batt_info.rep.level = curr_level;
+ mutex_unlock(&htc_batt_info.lock);
+
+ if (notify)
+ power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+ return 0;
+}
+
+int htc_cable_status_update(int status)
+{
+ int rc = 0;
+ unsigned source;
+
+ if (!htc_battery_initial)
+ return 0;
+
+ mutex_lock(&htc_batt_info.lock);
+ switch(status) {
+ case CHARGER_BATTERY:
+ BATT("cable NOT PRESENT\n");
+ htc_batt_info.rep.charging_source = CHARGER_BATTERY;
+ break;
+ case CHARGER_USB:
+ BATT("cable USB\n");
+ htc_batt_info.rep.charging_source = CHARGER_USB;
+ break;
+ case CHARGER_AC:
+ BATT("cable AC\n");
+ htc_batt_info.rep.charging_source = CHARGER_AC;
+ break;
+ default:
+ printk(KERN_ERR "%s: Not supported cable status received!\n",
+ __FUNCTION__);
+ rc = -EINVAL;
+ }
+ source = htc_batt_info.rep.charging_source;
+ mutex_unlock(&htc_batt_info.lock);
+
+ msm_hsusb_set_vbus_state(source == CHARGER_USB);
+ if (source == CHARGER_USB) {
+ wake_lock(&vbus_wake_lock);
+ } else {
+ /* give userspace some time to see the uevent and update
+ * LED state or whatnot...
+ */
+ wake_lock_timeout(&vbus_wake_lock, HZ / 2);
+ }
+
+ /* if the power source changes, all power supplies may change state */
+ power_supply_changed(&htc_power_supplies[CHARGER_BATTERY]);
+ power_supply_changed(&htc_power_supplies[CHARGER_USB]);
+ power_supply_changed(&htc_power_supplies[CHARGER_AC]);
+
+ return rc;
+}
+
+static int htc_get_batt_info(struct battery_info_reply *buffer)
+{
+ struct rpc_request_hdr req;
+
+ struct htc_get_batt_info_rep {
+ struct rpc_reply_hdr hdr;
+ struct battery_info_reply info;
+ } rep;
+
+ int rc;
+
+ if (buffer == NULL)
+ return -EINVAL;
+
+ rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_BATT_INFO,
+ &req, sizeof(req),
+ &rep, sizeof(rep),
+ 5 * HZ);
+ if ( rc < 0 )
+ return rc;
+
+ mutex_lock(&htc_batt_info.lock);
+ buffer->batt_id = be32_to_cpu(rep.info.batt_id);
+ buffer->batt_vol = be32_to_cpu(rep.info.batt_vol);
+ buffer->batt_temp = be32_to_cpu(rep.info.batt_temp);
+ buffer->batt_current = be32_to_cpu(rep.info.batt_current);
+ buffer->level = be32_to_cpu(rep.info.level);
+ buffer->charging_source = be32_to_cpu(rep.info.charging_source);
+ buffer->charging_enabled = be32_to_cpu(rep.info.charging_enabled);
+ buffer->full_bat = be32_to_cpu(rep.info.full_bat);
+ mutex_unlock(&htc_batt_info.lock);
+
+ return 0;
+}
+
+#if 0
+static int htc_get_cable_status(void)
+{
+
+ struct rpc_request_hdr req;
+
+ struct htc_get_cable_status_rep {
+ struct rpc_reply_hdr hdr;
+ int status;
+ } rep;
+
+ int rc;
+
+ rc = msm_rpc_call_reply(endpoint, HTC_PROCEDURE_GET_CABLE_STATUS,
+ &req, sizeof(req),
+ &rep, sizeof(rep),
+ 5 * HZ);
+ if (rc < 0)
+ return rc;
+
+ return be32_to_cpu(rep.status);
+}
+#endif
+
+/* -------------------------------------------------------------------------- */
+static int htc_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ charger_type_t charger;
+
+ mutex_lock(&htc_batt_info.lock);
+ charger = htc_batt_info.rep.charging_source;
+ mutex_unlock(&htc_batt_info.lock);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+ val->intval = (charger == CHARGER_AC ? 1 : 0);
+ else if (psy->type == POWER_SUPPLY_TYPE_USB)
+ val->intval = (charger == CHARGER_USB ? 1 : 0);
+ else
+ val->intval = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int htc_battery_get_charging_status(void)
+{
+ u32 level;
+ charger_type_t charger;
+ int ret;
+
+ mutex_lock(&htc_batt_info.lock);
+ charger = htc_batt_info.rep.charging_source;
+
+ switch (charger) {
+ case CHARGER_BATTERY:
+ ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHARGER_USB:
+ case CHARGER_AC:
+ level = htc_batt_info.rep.level;
+ if (level == 100)
+ ret = POWER_SUPPLY_STATUS_FULL;
+ else
+ ret = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ default:
+ ret = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+ mutex_unlock(&htc_batt_info.lock);
+ return ret;
+}
+
+static int htc_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = htc_battery_get_charging_status();
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = htc_batt_info.present;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ mutex_lock(&htc_batt_info.lock);
+ val->intval = htc_batt_info.rep.level;
+ mutex_unlock(&htc_batt_info.lock);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define HTC_BATTERY_ATTR(_name) \
+{ \
+ .attr = { .name = #_name, .mode = S_IRUGO, .owner = THIS_MODULE }, \
+ .show = htc_battery_show_property, \
+ .store = NULL, \
+}
+
+static struct device_attribute htc_battery_attrs[] = {
+ HTC_BATTERY_ATTR(batt_id),
+ HTC_BATTERY_ATTR(batt_vol),
+ HTC_BATTERY_ATTR(batt_temp),
+ HTC_BATTERY_ATTR(batt_current),
+ HTC_BATTERY_ATTR(charging_source),
+ HTC_BATTERY_ATTR(charging_enabled),
+ HTC_BATTERY_ATTR(full_bat),
+};
+
+enum {
+ BATT_ID = 0,
+ BATT_VOL,
+ BATT_TEMP,
+ BATT_CURRENT,
+ CHARGING_SOURCE,
+ CHARGING_ENABLED,
+ FULL_BAT,
+};
+
+static int htc_rpc_set_delta(unsigned delta)
+{
+ struct set_batt_delta_req {
+ struct rpc_request_hdr hdr;
+ uint32_t data;
+ } req;
+
+ req.data = cpu_to_be32(delta);
+ return msm_rpc_call(endpoint, HTC_PROCEDURE_SET_BATT_DELTA,
+ &req, sizeof(req), 5 * HZ);
+}
+
+
+static ssize_t htc_battery_set_delta(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ unsigned long delta = 0;
+
+ delta = simple_strtoul(buf, NULL, 10);
+
+ if (delta > 100)
+ return -EINVAL;
+
+ mutex_lock(&htc_batt_info.rpc_lock);
+ rc = htc_rpc_set_delta(delta);
+ mutex_unlock(&htc_batt_info.rpc_lock);
+ if (rc < 0)
+ return rc;
+ return count;
+}
+
+static struct device_attribute htc_set_delta_attrs[] = {
+ __ATTR(delta, S_IWUSR | S_IWGRP, NULL, htc_battery_set_delta),
+};
+
+static int htc_battery_create_attrs(struct device * dev)
+{
+ int i, j, rc;
+
+ for (i = 0; i < ARRAY_SIZE(htc_battery_attrs); i++) {
+ rc = device_create_file(dev, &htc_battery_attrs[i]);
+ if (rc)
+ goto htc_attrs_failed;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(htc_set_delta_attrs); j++) {
+ rc = device_create_file(dev, &htc_set_delta_attrs[j]);
+ if (rc)
+ goto htc_delta_attrs_failed;
+ }
+
+ goto succeed;
+
+htc_attrs_failed:
+ while (i--)
+ device_remove_file(dev, &htc_battery_attrs[i]);
+htc_delta_attrs_failed:
+ while (j--)
+ device_remove_file(dev, &htc_set_delta_attrs[i]);
+succeed:
+ return rc;
+}
+
+static ssize_t htc_battery_show_property(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 0;
+ const ptrdiff_t off = attr - htc_battery_attrs;
+
+ /* rpc lock is used to prevent two threads from calling
+ * into the get info rpc at the same time
+ */
+
+ mutex_lock(&htc_batt_info.rpc_lock);
+ /* check cache time to decide if we need to update */
+ if (htc_batt_info.update_time &&
+ time_before(jiffies, htc_batt_info.update_time +
+ msecs_to_jiffies(cache_time)))
+ goto dont_need_update;
+
+ if (htc_get_batt_info(&htc_batt_info.rep) < 0) {
+ printk(KERN_ERR "%s: rpc failed!!!\n", __FUNCTION__);
+ } else {
+ htc_batt_info.update_time = jiffies;
+ }
+dont_need_update:
+ mutex_unlock(&htc_batt_info.rpc_lock);
+
+ mutex_lock(&htc_batt_info.lock);
+ switch (off) {
+ case BATT_ID:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.batt_id);
+ break;
+ case BATT_VOL:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.batt_vol);
+ break;
+ case BATT_TEMP:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.batt_temp);
+ break;
+ case BATT_CURRENT:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.batt_current);
+ break;
+ case CHARGING_SOURCE:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.charging_source);
+ break;
+ case CHARGING_ENABLED:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.charging_enabled);
+ break;
+ case FULL_BAT:
+ i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n",
+ htc_batt_info.rep.full_bat);
+ break;
+ default:
+ i = -EINVAL;
+ }
+ mutex_unlock(&htc_batt_info.lock);
+
+ return i;
+}
+
+static int htc_battery_probe(struct platform_device *pdev)
+{
+ int i, rc;
+
+ /* init battery gpio */
+ if ((rc = init_batt_gpio()) < 0) {
+ printk(KERN_ERR "%s: init battery gpio failed!\n", __FUNCTION__);
+ return rc;
+ }
+
+ /* init structure data member */
+ htc_batt_info.update_time = jiffies;
+ htc_batt_info.present = gpio_get_value(GPIO_BATTERY_DETECTION);
+
+ /* init rpc */
+ endpoint = msm_rpc_connect(APP_BATT_PROG, APP_BATT_VER, 0);
+ if (IS_ERR(endpoint)) {
+ printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
+ __FUNCTION__, PTR_ERR(endpoint));
+ return rc;
+ }
+
+ /* init power supplier framework */
+ for (i = 0; i < ARRAY_SIZE(htc_power_supplies); i++) {
+ rc = power_supply_register(&pdev->dev, &htc_power_supplies[i]);
+ if (rc)
+ printk(KERN_ERR "Failed to register power supply (%d)\n", rc);
+ }
+
+ /* create htc detail attributes */
+ htc_battery_create_attrs(htc_power_supplies[CHARGER_BATTERY].dev);
+
+ /* After battery driver gets initialized, send rpc request to inquiry
+ * the battery status in case of we lost some info
+ */
+ htc_battery_initial = 1;
+
+ mutex_lock(&htc_batt_info.rpc_lock);
+ if (htc_get_batt_info(&htc_batt_info.rep) < 0)
+ printk(KERN_ERR "%s: get info failed\n", __FUNCTION__);
+
+ htc_cable_status_update(htc_batt_info.rep.charging_source);
+ battery_charging_ctrl(htc_batt_info.rep.charging_enabled ?
+ ENABLE_SLOW_CHG : DISABLE);
+
+ if (htc_rpc_set_delta(1) < 0)
+ printk(KERN_ERR "%s: set delta failed\n", __FUNCTION__);
+ htc_batt_info.update_time = jiffies;
+ mutex_unlock(&htc_batt_info.rpc_lock);
+
+ if (htc_batt_info.rep.charging_enabled == 0)
+ battery_charging_ctrl(DISABLE);
+
+ return 0;
+}
+
+static struct platform_driver htc_battery_driver = {
+ .probe = htc_battery_probe,
+ .driver = {
+ .name = APP_BATT_PDEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/* batt_mtoa server definitions */
+#define BATT_MTOA_PROG 0x30100000
+#define BATT_MTOA_VERS 0
+#define RPC_BATT_MTOA_NULL 0
+#define RPC_BATT_MTOA_SET_CHARGING_PROC 1
+#define RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC 2
+#define RPC_BATT_MTOA_LEVEL_UPDATE_PROC 3
+
+struct rpc_batt_mtoa_set_charging_args {
+ int enable;
+};
+
+struct rpc_batt_mtoa_cable_status_update_args {
+ int status;
+};
+
+struct rpc_dem_battery_update_args {
+ uint32_t level;
+};
+
+static int handle_battery_call(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len)
+{
+ switch (req->procedure) {
+ case RPC_BATT_MTOA_NULL:
+ return 0;
+
+ case RPC_BATT_MTOA_SET_CHARGING_PROC: {
+ struct rpc_batt_mtoa_set_charging_args *args;
+ args = (struct rpc_batt_mtoa_set_charging_args *)(req + 1);
+ args->enable = be32_to_cpu(args->enable);
+ BATT("set_charging: enable=%d\n",args->enable);
+ htc_battery_set_charging(args->enable);
+ return 0;
+ }
+ case RPC_BATT_MTOA_CABLE_STATUS_UPDATE_PROC: {
+ struct rpc_batt_mtoa_cable_status_update_args *args;
+ args = (struct rpc_batt_mtoa_cable_status_update_args *)(req + 1);
+ args->status = be32_to_cpu(args->status);
+ BATT("cable_status_update: status=%d\n",args->status);
+ htc_cable_status_update(args->status);
+ return 0;
+ }
+ case RPC_BATT_MTOA_LEVEL_UPDATE_PROC: {
+ struct rpc_dem_battery_update_args *args;
+ args = (struct rpc_dem_battery_update_args *)(req + 1);
+ args->level = be32_to_cpu(args->level);
+ BATT("dem_battery_update: level=%d\n",args->level);
+ htc_battery_status_update(args->level);
+ return 0;
+ }
+ default:
+ printk(KERN_ERR "%s: program 0x%08x:%d: unknown procedure %d\n",
+ __FUNCTION__, req->prog, req->vers, req->procedure);
+ return -ENODEV;
+ }
+}
+
+static struct msm_rpc_server battery_server = {
+ .prog = BATT_MTOA_PROG,
+ .vers = BATT_MTOA_VERS,
+ .rpc_call = handle_battery_call,
+};
+
+static int __init htc_battery_init(void)
+{
+ wake_lock_init(&vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
+ mutex_init(&htc_batt_info.lock);
+ mutex_init(&htc_batt_info.rpc_lock);
+ msm_rpc_create_server(&battery_server);
+ platform_driver_register(&htc_battery_driver);
+ return 0;
+}
+
+module_init(htc_battery_init);
+MODULE_DESCRIPTION("HTC Battery Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/htc_headset.c b/arch/arm/mach-msm/htc_headset.c
new file mode 100644
index 000000000000..a69a2e1ca5f8
--- /dev/null
+++ b/arch/arm/mach-msm/htc_headset.c
@@ -0,0 +1,1246 @@
+/*
+ * H2W device detection driver.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC, Inc.
+ *
+ * Authors:
+ * Laurence Chen <Laurence_Chen@htc.com>
+ * Nick Pelly <npelly@google.com>
+ * Thomas Tsai <thomas_tsai@htc.com>
+ * Farmer Tseng <farmer_tseng@htc.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.
+ */
+
+/* For detecting HTC 2 Wire devices, such as wired headset.
+
+ Logically, the H2W driver is always present, and H2W state (hi->state)
+ indicates what is currently plugged into the H2W interface.
+
+ When the headset is plugged in, CABLE_IN1 is pulled low. When the headset
+ button is pressed, CABLE_IN2 is pulled low. These two lines are shared with
+ the TX and RX (respectively) of UART3 - used for serial debugging.
+
+ This headset driver keeps the CPLD configured as UART3 for as long as
+ possible, so that we can do serial FIQ debugging even when the kernel is
+ locked and this driver no longer runs. So it only configures the CPLD to
+ GPIO while the headset is plugged in, and for 10ms during detection work.
+
+ Unfortunately we can't leave the CPLD as UART3 while a headset is plugged
+ in, UART3 is pullup on TX but the headset is pull-down, causing a 55 mA
+ drain on trout.
+
+ The headset detection work involves setting CPLD to GPIO, and then pulling
+ CABLE_IN1 high with a stronger pullup than usual. A H2W headset will still
+ pull this line low, whereas other attachments such as a serial console
+ would get pulled up by this stronger pullup.
+
+ Headset insertion/removal causes UEvent's to be sent, and
+ /sys/class/switch/h2w/state to be updated.
+
+ Button presses are interpreted as input event (KEY_MEDIA). Button presses
+ are ignored if the headset is plugged in, so the buttons on 11 pin -> 3.5mm
+ jack adapters do not work until a headset is plugged into the adapter. This
+ is to avoid serial RX traffic causing spurious button press events.
+
+ We tend to check the status of CABLE_IN1 a few more times than strictly
+ necessary during headset detection, to avoid spurious headset insertion
+ events caused by serial debugger TX traffic.
+*/
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/switch.h>
+#include <linux/input.h>
+#include <linux/debugfs.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <mach/board.h>
+#include <mach/vreg.h>
+#include <asm/mach-types.h>
+
+#include <mach/htc_headset.h>
+
+#define H2WI(fmt, arg...) \
+ printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#define H2WE(fmt, arg...) \
+ printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
+
+#ifdef CONFIG_DEBUG_H2W
+#define H2W_DBG(fmt, arg...) printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
+#else
+#define H2W_DBG(fmt, arg...) do {} while (0)
+#endif
+
+static struct workqueue_struct *g_detection_work_queue;
+static void detection_work(struct work_struct *work);
+static DECLARE_WORK(g_detection_work, detection_work);
+
+struct h2w_info {
+ struct switch_dev sdev;
+ struct input_dev *input;
+ struct mutex mutex_lock;
+
+ atomic_t btn_state;
+ int ignore_btn;
+
+ unsigned int irq;
+ unsigned int irq_btn;
+
+ int cable_in1;
+ int cable_in2;
+ int h2w_clk;
+ int h2w_data;
+ int debug_uart;
+
+ void (*config_cpld) (int);
+ void (*init_cpld) (void);
+ /* for h2w */
+ void (*set_dat)(int);
+ void (*set_clk)(int);
+ void (*set_dat_dir)(int);
+ void (*set_clk_dir)(int);
+ int (*get_dat)(void);
+ int (*get_clk)(void);
+
+ int htc_headset_flag;
+
+ struct hrtimer timer;
+ ktime_t debounce_time;
+
+ struct hrtimer btn_timer;
+ ktime_t btn_debounce_time;
+
+ H2W_INFO h2w_info;
+ H2W_SPEED speed;
+ struct vreg *vreg_h2w;
+};
+static struct h2w_info *hi;
+
+static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
+{
+ switch (switch_get_state(&hi->sdev)) {
+ case H2W_NO_DEVICE:
+ return sprintf(buf, "No Device\n");
+ case H2W_HTC_HEADSET:
+ return sprintf(buf, "Headset\n");
+ }
+ return -EINVAL;
+}
+
+static void button_pressed(void)
+{
+ H2W_DBG("button_pressed \n");
+ atomic_set(&hi->btn_state, 1);
+ input_report_key(hi->input, KEY_MEDIA, 1);
+ input_sync(hi->input);
+}
+
+static void button_released(void)
+{
+ H2W_DBG("button_released \n");
+ atomic_set(&hi->btn_state, 0);
+ input_report_key(hi->input, KEY_MEDIA, 0);
+ input_sync(hi->input);
+}
+
+/*****************
+ * H2W proctocol *
+ *****************/
+static inline void h2w_begin_command(void)
+{
+ /* Disable H2W interrupt */
+ set_irq_type(hi->irq_btn, IRQF_TRIGGER_HIGH);
+ disable_irq(hi->irq);
+ disable_irq(hi->irq_btn);
+
+ /* Set H2W_CLK as output low */
+ hi->set_clk(0);
+ hi->set_clk_dir(1);
+}
+
+static inline void h2w_end_command(void)
+{
+ /* Set H2W_CLK as input */
+ hi->set_clk_dir(0);
+
+ /* Enable H2W interrupt */
+ enable_irq(hi->irq);
+ enable_irq(hi->irq_btn);
+ set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+}
+
+/*
+ * One bit write data
+ * ________
+ * SCLK O ______| |______O(L)
+ *
+ *
+ * SDAT I <XXXXXXXXXXXXXXXXXXXX>
+ */
+static inline void one_clock_write(unsigned short flag)
+{
+ if (flag)
+ hi->set_dat(1);
+ else
+ hi->set_dat(0);
+
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(hi->speed);
+ hi->set_clk(0);
+}
+
+/*
+ * One bit write data R/W bit
+ * ________
+ * SCLK ______| |______O(L)
+ * 1----> 1----->
+ * 2-------> ______
+ * SDAT <XXXXXXXXXXXXXX> I
+ * O(H/L)
+ */
+static inline void one_clock_write_RWbit(unsigned short flag)
+{
+ if (flag)
+ hi->set_dat(1);
+ else
+ hi->set_dat(0);
+
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(hi->speed);
+ hi->set_clk(0);
+ hi->set_dat_dir(0);
+ udelay(hi->speed);
+}
+
+/*
+ * H2W Reset
+ * ___________
+ * SCLK O(L)______| |___O(L)
+ * 1---->
+ * 4-->1-->1-->1us-->
+ * ____
+ * SDAT O(L)________ | |_______O(L)
+ *
+ * H2w reset command needs to be issued before every access
+ */
+static inline void h2w_reset(void)
+{
+ /* Set H2W_DAT as output low */
+ hi->set_dat(0);
+ hi->set_dat_dir(1);
+
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(4 * hi->speed);
+ hi->set_dat(1);
+ udelay(hi->speed);
+ hi->set_dat(0);
+ udelay(hi->speed);
+ hi->set_clk(0);
+ udelay(hi->speed);
+}
+
+/*
+ * H2W Start
+ * ___________
+ * SCLK O(L)______| |___O(L)
+ * 1---->
+ * 2----------->1-->
+ *
+ * SDAT O(L)______________________O(L)
+ */
+static inline void h2w_start(void)
+{
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(2 * hi->speed);
+ hi->set_clk(0);
+ udelay(hi->speed);
+}
+
+/*
+ * H2W Ack
+ * __________
+ * SCLK _____| |_______O(L)
+ * 1----> 1------>
+ * 2--------->
+ * ________________________
+ * SDAT become Input mode here I
+ */
+static inline int h2w_ack(void)
+{
+ int retry_times = 0;
+
+ack_resend:
+ if (retry_times == MAX_ACK_RESEND_TIMES)
+ return -1;
+
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(2 * hi->speed);
+
+ if (!hi->get_dat()) {
+ retry_times++;
+ hi->set_clk(0);
+ udelay(hi->speed);
+ goto ack_resend;
+ }
+
+ hi->set_clk(0);
+ udelay(hi->speed);
+ return 0;
+}
+
+/*
+ * One bit read data
+ * ________
+ * SCLK ______| |______O(L)
+ * 2----> 2----->
+ * 2------->
+ * SDAT <XXXXXXXXXXXXXXXXXXXX>I
+ */
+static unsigned char h2w_readc(void)
+{
+ unsigned char h2w_read_data = 0x0;
+ int index;
+
+ for (index = 0; index < 8; index++) {
+ hi->set_clk(0);
+ udelay(hi->speed);
+ hi->set_clk(1);
+ udelay(hi->speed);
+ if (hi->get_dat())
+ h2w_read_data |= (1 << (7 - index));
+ }
+ hi->set_clk(0);
+ udelay(hi->speed);
+
+ return h2w_read_data;
+}
+
+static int h2w_readc_cmd(H2W_ADDR address)
+{
+ int ret = -1, retry_times = 0;
+ unsigned char read_data;
+
+read_resend:
+ if (retry_times == MAX_HOST_RESEND_TIMES)
+ goto err_read;
+
+ h2w_reset();
+ h2w_start();
+ /* Write address */
+ one_clock_write(address & 0x1000);
+ one_clock_write(address & 0x0800);
+ one_clock_write(address & 0x0400);
+ one_clock_write(address & 0x0200);
+ one_clock_write(address & 0x0100);
+ one_clock_write(address & 0x0080);
+ one_clock_write(address & 0x0040);
+ one_clock_write(address & 0x0020);
+ one_clock_write(address & 0x0010);
+ one_clock_write(address & 0x0008);
+ one_clock_write(address & 0x0004);
+ one_clock_write(address & 0x0002);
+ one_clock_write(address & 0x0001);
+ one_clock_write_RWbit(1);
+ if (h2w_ack() < 0) {
+ H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+ retry_times++;
+ hi->set_clk(0);
+ mdelay(RESEND_DELAY);
+ goto read_resend;
+ }
+
+ read_data = h2w_readc();
+
+ if (h2w_ack() < 0) {
+ H2W_DBG("Data NO ACK(%d).\n", retry_times);
+ retry_times++;
+ hi->set_clk(0);
+ mdelay(RESEND_DELAY);
+ goto read_resend;
+ }
+ ret = (int)read_data;
+
+err_read:
+ if (ret < 0)
+ H2WE("NO ACK.\n");
+
+ return ret;
+}
+
+static int h2w_writec_cmd(H2W_ADDR address, unsigned char data)
+{
+ int ret = -1;
+ int retry_times = 0;
+
+write_resend:
+ if (retry_times == MAX_HOST_RESEND_TIMES)
+ goto err_write;
+
+ h2w_reset();
+ h2w_start();
+
+ /* Write address */
+ one_clock_write(address & 0x1000);
+ one_clock_write(address & 0x0800);
+ one_clock_write(address & 0x0400);
+ one_clock_write(address & 0x0200);
+ one_clock_write(address & 0x0100);
+ one_clock_write(address & 0x0080);
+ one_clock_write(address & 0x0040);
+ one_clock_write(address & 0x0020);
+ one_clock_write(address & 0x0010);
+ one_clock_write(address & 0x0008);
+ one_clock_write(address & 0x0004);
+ one_clock_write(address & 0x0002);
+ one_clock_write(address & 0x0001);
+ one_clock_write_RWbit(0);
+ if (h2w_ack() < 0) {
+ H2W_DBG("Addr NO ACK(%d).\n", retry_times);
+ retry_times++;
+ hi->set_clk(0);
+ mdelay(RESEND_DELAY);
+ goto write_resend;
+ }
+
+ /* Write data */
+ hi->set_dat_dir(1);
+ one_clock_write(data & 0x0080);
+ one_clock_write(data & 0x0040);
+ one_clock_write(data & 0x0020);
+ one_clock_write(data & 0x0010);
+ one_clock_write(data & 0x0008);
+ one_clock_write(data & 0x0004);
+ one_clock_write(data & 0x0002);
+ one_clock_write_RWbit(data & 0x0001);
+ if (h2w_ack() < 0) {
+ H2W_DBG("Data NO ACK(%d).\n", retry_times);
+ retry_times++;
+ hi->set_clk(0);
+ mdelay(RESEND_DELAY);
+ goto write_resend;
+ }
+ ret = 0;
+
+err_write:
+ if (ret < 0)
+ H2WE("NO ACK.\n");
+
+ return ret;
+}
+
+static int h2w_get_fnkey(void)
+{
+ int ret;
+ h2w_begin_command();
+ ret = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+ h2w_end_command();
+ return ret;
+}
+
+static int h2w_dev_init(H2W_INFO *ph2w_info)
+{
+ int ret = -1;
+ unsigned char ascr0 = 0;
+ int h2w_sys = 0, maxgpadd = 0, maxadd = 0, key = 0;
+
+ hi->speed = H2W_50KHz;
+ h2w_begin_command();
+
+ /* read H2W_SYSTEM */
+ h2w_sys = h2w_readc_cmd(H2W_SYSTEM);
+ if (h2w_sys == -1) {
+ H2WE("read H2W_SYSTEM(0x0000) failed.\n");
+ goto err_plugin;
+ }
+ ph2w_info->ACC_CLASS = (h2w_sys & 0x03);
+ ph2w_info->AUDIO_DEVICE = (h2w_sys & 0x04) > 0 ? 1 : 0;
+ ph2w_info->HW_REV = (h2w_sys & 0x18) >> 3;
+ ph2w_info->SLEEP_PR = (h2w_sys & 0x20) >> 5;
+ ph2w_info->CLK_SP = (h2w_sys & 0xC0) >> 6;
+
+ /* enter init mode */
+ if (h2w_writec_cmd(H2W_ASCR0, H2W_ASCR_DEVICE_INI) < 0) {
+ H2WE("write H2W_ASCR0(0x0002) failed.\n");
+ goto err_plugin;
+ }
+ udelay(10);
+
+ /* read H2W_MAX_GP_ADD */
+ maxgpadd = h2w_readc_cmd(H2W_MAX_GP_ADD);
+ if (maxgpadd == -1) {
+ H2WE("write H2W_MAX_GP_ADD(0x0001) failed.\n");
+ goto err_plugin;
+ }
+ ph2w_info->CLK_SP += (maxgpadd & 0x60) >> 3;
+ ph2w_info->MAX_GP_ADD = (maxgpadd & 0x1F);
+
+ /* read key group */
+ if (ph2w_info->MAX_GP_ADD >= 1) {
+ ph2w_info->KEY_MAXADD = h2w_readc_cmd(H2W_KEY_MAXADD);
+ if (ph2w_info->KEY_MAXADD == -1)
+ goto err_plugin;
+ if (ph2w_info->KEY_MAXADD >= 1) {
+ key = h2w_readc_cmd(H2W_ASCII_DOWN);
+ if (key < 0)
+ goto err_plugin;
+ ph2w_info->ASCII_DOWN = (key == 0xFF) ? 1 : 0;
+ }
+ if (ph2w_info->KEY_MAXADD >= 2) {
+ key = h2w_readc_cmd(H2W_ASCII_UP);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->ASCII_UP = (key == 0xFF) ? 1 : 0;
+ }
+ if (ph2w_info->KEY_MAXADD >= 3) {
+ key = h2w_readc_cmd(H2W_FNKEY_UPDOWN);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->FNKEY_UPDOWN = (key == 0xFF) ? 1 : 0;
+ }
+ if (ph2w_info->KEY_MAXADD >= 4) {
+ key = h2w_readc_cmd(H2W_KD_STATUS);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->KD_STATUS = (key == 0x01) ? 1 : 0;
+ }
+ }
+
+ /* read led group */
+ if (ph2w_info->MAX_GP_ADD >= 2) {
+ ph2w_info->LED_MAXADD = h2w_readc_cmd(H2W_LED_MAXADD);
+ if (ph2w_info->LED_MAXADD == -1)
+ goto err_plugin;
+ if (ph2w_info->LED_MAXADD >= 1) {
+ key = h2w_readc_cmd(H2W_LEDCT0);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->LEDCT0 = (key == 0x02) ? 1 : 0;
+ }
+ }
+
+ /* read group 3, 4, 5 */
+ if (ph2w_info->MAX_GP_ADD >= 3) {
+ maxadd = h2w_readc_cmd(H2W_CRDL_MAXADD);
+ if (maxadd == -1)
+ goto err_plugin;
+ }
+ if (ph2w_info->MAX_GP_ADD >= 4) {
+ maxadd = h2w_readc_cmd(H2W_CARKIT_MAXADD);
+ if (maxadd == -1)
+ goto err_plugin;
+ }
+ if (ph2w_info->MAX_GP_ADD >= 5) {
+ maxadd = h2w_readc_cmd(H2W_USBHOST_MAXADD);
+ if (maxadd == -1)
+ goto err_plugin;
+ }
+
+ /* read medical group */
+ if (ph2w_info->MAX_GP_ADD >= 6) {
+ ph2w_info->MED_MAXADD = h2w_readc_cmd(H2W_MED_MAXADD);
+ if (ph2w_info->MED_MAXADD == -1)
+ goto err_plugin;
+ if (ph2w_info->MED_MAXADD >= 1) {
+ key = h2w_readc_cmd(H2W_MED_CONTROL);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->DATA_EN = (key & 0x01);
+ ph2w_info->AP_EN = (key & 0x02) >> 1;
+ ph2w_info->AP_ID = (key & 0x1c) >> 2;
+ }
+ if (ph2w_info->MED_MAXADD >= 2) {
+ key = h2w_readc_cmd(H2W_MED_IN_DATA);
+ if (key == -1)
+ goto err_plugin;
+ }
+ }
+
+ if (ph2w_info->AUDIO_DEVICE)
+ ascr0 = H2W_ASCR_AUDIO_IN | H2W_ASCR_ACT_EN;
+ else
+ ascr0 = H2W_ASCR_ACT_EN;
+
+ if (h2w_writec_cmd(H2W_ASCR0, ascr0) < 0)
+ goto err_plugin;
+ udelay(10);
+
+ ret = 0;
+
+ /* adjust speed */
+ if (ph2w_info->MAX_GP_ADD == 2) {
+ /* Remote control */
+ hi->speed = H2W_250KHz;
+ } else if (ph2w_info->MAX_GP_ADD == 6) {
+ if (ph2w_info->MED_MAXADD >= 1) {
+ key = h2w_readc_cmd(H2W_MED_CONTROL);
+ if (key == -1)
+ goto err_plugin;
+ ph2w_info->DATA_EN = (key & 0x01);
+ ph2w_info->AP_EN = (key & 0x02) >> 1;
+ ph2w_info->AP_ID = (key & 0x1c) >> 2;
+ }
+ }
+
+err_plugin:
+ h2w_end_command();
+
+ return ret;
+}
+
+static inline void h2w_dev_power_on(int on)
+{
+ if (!hi->vreg_h2w)
+ return;
+
+ if (on)
+ vreg_enable(hi->vreg_h2w);
+ else
+ vreg_disable(hi->vreg_h2w);
+}
+
+static int h2w_dev_detect(void)
+{
+ int ret = -1;
+ int retry_times;
+
+ for (retry_times = 5; retry_times; retry_times--) {
+ /* Enable H2W Power */
+ h2w_dev_power_on(1);
+ msleep(100);
+ memset(&hi->h2w_info, 0, sizeof(H2W_INFO));
+ if (h2w_dev_init(&hi->h2w_info) < 0) {
+ h2w_dev_power_on(0);
+ msleep(100);
+ } else if (hi->h2w_info.MAX_GP_ADD == 2) {
+ ret = 0;
+ break;
+ } else {
+ printk(KERN_INFO "h2w_detect: detect error(%d)\n"
+ , hi->h2w_info.MAX_GP_ADD);
+ h2w_dev_power_on(0);
+ msleep(100);
+ }
+ printk(KERN_INFO "h2w_detect(%d)\n"
+ , hi->h2w_info.MAX_GP_ADD);
+ }
+ H2W_DBG("h2w_detect:(%d)\n", retry_times);
+ return ret;
+}
+
+static void remove_headset(void)
+{
+ unsigned long irq_flags;
+
+ H2W_DBG("");
+
+ mutex_lock(&hi->mutex_lock);
+ switch_set_state(&hi->sdev, switch_get_state(&hi->sdev) &
+ ~(BIT_HEADSET | BIT_HEADSET_NO_MIC));
+ mutex_unlock(&hi->mutex_lock);
+ hi->init_cpld();
+
+ /* Disable button */
+ switch (hi->htc_headset_flag) {
+ case H2W_HTC_HEADSET:
+ local_irq_save(irq_flags);
+ disable_irq(hi->irq_btn);
+ local_irq_restore(irq_flags);
+
+ if (atomic_read(&hi->btn_state))
+ button_released();
+ break;
+ case H2W_DEVICE:
+ h2w_dev_power_on(0);
+ set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+ disable_irq(hi->irq_btn);
+ /* 10ms (5-15 with 10ms tick) */
+ hi->btn_debounce_time = ktime_set(0, 10000000);
+ hi->set_clk_dir(0);
+ hi->set_dat_dir(0);
+ break;
+ }
+
+ hi->htc_headset_flag = 0;
+ hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */
+
+}
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+extern void msm_serial_debug_enable(int);
+#endif
+
+static void insert_headset(int type)
+{
+ unsigned long irq_flags;
+ int state;
+
+ H2W_DBG("");
+
+ hi->htc_headset_flag = type;
+ state = BIT_HEADSET | BIT_HEADSET_NO_MIC;
+
+ state = switch_get_state(&hi->sdev);
+ state &= ~(BIT_HEADSET_NO_MIC | BIT_HEADSET);
+ switch (type) {
+ case H2W_HTC_HEADSET:
+ printk(KERN_INFO "insert_headset H2W_HTC_HEADSET\n");
+ state |= BIT_HEADSET;
+ hi->ignore_btn = !gpio_get_value(hi->cable_in2);
+ /* Enable button irq */
+ local_irq_save(irq_flags);
+ enable_irq(hi->irq_btn);
+ local_irq_restore(irq_flags);
+ hi->debounce_time = ktime_set(0, 200000000); /* 20 ms */
+ break;
+ case H2W_DEVICE:
+ if (h2w_dev_detect() < 0) {
+ printk(KERN_INFO "H2W_DEVICE -- Non detect\n");
+ remove_headset();
+ } else {
+ printk(KERN_INFO "H2W_DEVICE -- detect\n");
+ hi->btn_debounce_time = ktime_set(0, 0);
+ local_irq_save(irq_flags);
+ enable_irq(hi->irq_btn);
+ set_irq_type(hi->irq_btn, IRQF_TRIGGER_RISING);
+ local_irq_restore(irq_flags);
+ state |= BIT_HEADSET;
+ }
+ break;
+ case H2W_USB_CRADLE:
+ state |= BIT_HEADSET_NO_MIC;
+ break;
+ case H2W_UART_DEBUG:
+ hi->config_cpld(hi->debug_uart);
+ printk(KERN_INFO "switch to H2W_UART_DEBUG\n");
+ default:
+ return;
+ }
+ mutex_lock(&hi->mutex_lock);
+ switch_set_state(&hi->sdev, state);
+ mutex_unlock(&hi->mutex_lock);
+
+#ifdef CONFIG_MSM_SERIAL_DEBUGGER
+ msm_serial_debug_enable(false);
+#endif
+
+}
+#if 0
+static void remove_headset(void)
+{
+ unsigned long irq_flags;
+
+ H2W_DBG("");
+
+ switch_set_state(&hi->sdev, H2W_NO_DEVICE);
+
+ hi->init_cpld();
+
+ /* Disable button */
+ local_irq_save(irq_flags);
+ disable_irq(hi->irq_btn);
+ local_irq_restore(irq_flags);
+
+ if (atomic_read(&hi->btn_state))
+ button_released();
+
+ hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */
+}
+#endif
+static int is_accessary_pluged_in(void)
+{
+ int type = 0;
+ int clk1 = 0, dat1 = 0, clk2 = 0, dat2 = 0, clk3 = 0, dat3 = 0;
+
+ /* Step1: save H2W_CLK and H2W_DAT */
+ /* Delay 10ms for pin stable. */
+ msleep(10);
+ clk1 = gpio_get_value(hi->h2w_clk);
+ dat1 = gpio_get_value(hi->h2w_data);
+
+ /*
+ * Step2: set GPIO_CABLE_IN1 as output high and GPIO_CABLE_IN2 as
+ * input
+ */
+ gpio_direction_output(hi->cable_in1, 1);
+ gpio_direction_input(hi->cable_in2);
+ /* Delay 10ms for pin stable. */
+ msleep(10);
+ /* Step 3: save H2W_CLK and H2W_DAT */
+ clk2 = gpio_get_value(hi->h2w_clk);
+ dat2 = gpio_get_value(hi->h2w_data);
+
+ /*
+ * Step 4: set GPIO_CABLE_IN1 as input and GPIO_CABLE_IN2 as output
+ * high
+ */
+ gpio_direction_input(hi->cable_in1);
+ gpio_direction_output(hi->cable_in2, 1);
+ /* Delay 10ms for pin stable. */
+ msleep(10);
+ /* Step 5: save H2W_CLK and H2W_DAT */
+ clk3 = gpio_get_value(hi->h2w_clk);
+ dat3 = gpio_get_value(hi->h2w_data);
+
+ /* Step 6: set both GPIO_CABLE_IN1 and GPIO_CABLE_IN2 as input */
+ gpio_direction_input(hi->cable_in1);
+ gpio_direction_input(hi->cable_in2);
+
+ H2W_DBG("(%d,%d) (%d,%d) (%d,%d)\n",
+ clk1, dat1, clk2, dat2, clk3, dat3);
+
+ if ((clk1 == 0) && (dat1 == 1) &&
+ (clk2 == 0) && (dat2 == 1) &&
+ (clk3 == 0) && (dat3 == 1))
+ type = H2W_HTC_HEADSET;
+ else if ((clk1 == 0) && (dat1 == 0) &&
+ (clk2 == 0) && (dat2 == 0) &&
+ (clk3 == 0) && (dat3 == 0))
+ type = NORMAL_HEARPHONE;
+ else if ((clk1 == 0) && (dat1 == 0) &&
+ (clk2 == 1) && (dat2 == 0) &&
+ (clk3 == 0) && (dat3 == 1))
+ type = H2W_DEVICE;
+ else if ((clk1 == 0) && (dat1 == 0) &&
+ (clk2 == 1) && (dat2 == 1) &&
+ (clk3 == 1) && (dat3 == 1))
+ type = H2W_USB_CRADLE;
+ else if ((clk1 == 0) && (dat1 == 1) &&
+ (clk2 == 1) && (dat2 == 1) &&
+ (clk3 == 0) && (dat3 == 1))
+ type = H2W_UART_DEBUG;
+ else
+ type = H2W_NO_DEVICE;
+
+ return type;
+}
+
+
+static void detection_work(struct work_struct *work)
+{
+ unsigned long irq_flags;
+ int type;
+
+ H2W_DBG("");
+
+ if (gpio_get_value(hi->cable_in1) != 0) {
+ /* Headset not plugged in */
+ if (switch_get_state(&hi->sdev) != H2W_NO_DEVICE)
+ remove_headset();
+ return;
+ }
+
+ /* Something plugged in, lets make sure its a headset */
+
+ /* Switch CPLD to GPIO to do detection */
+ hi->config_cpld(H2W_GPIO);
+
+ /* Disable headset interrupt while detecting.*/
+ local_irq_save(irq_flags);
+ disable_irq(hi->irq);
+ local_irq_restore(irq_flags);
+
+ /* Something plugged in, lets make sure its a headset */
+ type = is_accessary_pluged_in();
+
+ /* Restore IRQs */
+ local_irq_save(irq_flags);
+ enable_irq(hi->irq);
+ local_irq_restore(irq_flags);
+
+ insert_headset(type);
+}
+
+static enum hrtimer_restart button_event_timer_func(struct hrtimer *data)
+{
+ int key, press, keyname, h2w_key = 1;
+
+ H2W_DBG("");
+
+ if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET) {
+ switch (hi->htc_headset_flag) {
+ case H2W_HTC_HEADSET:
+ if (gpio_get_value(hi->cable_in2)) {
+ if (hi->ignore_btn)
+ hi->ignore_btn = 0;
+ else if (atomic_read(&hi->btn_state))
+ button_released();
+ } else {
+ if (!hi->ignore_btn &&
+ !atomic_read(&hi->btn_state))
+ button_pressed();
+ }
+ break;
+ case H2W_DEVICE:
+ if ((hi->get_dat() == 1) && (hi->get_clk() == 1)) {
+ /* Don't do anything because H2W pull out. */
+ H2WE("Remote Control pull out.\n");
+ } else {
+ key = h2w_get_fnkey();
+ press = (key > 0x7F) ? 0 : 1;
+ keyname = key & 0x7F;
+ /* H2WI("key = %d, press = %d,
+ keyname = %d \n",
+ key, press, keyname); */
+ switch (keyname) {
+ case H2W_KEY_PLAY:
+ H2WI("H2W_KEY_PLAY");
+ key = KEY_PLAYPAUSE;
+ break;
+ case H2W_KEY_FORWARD:
+ H2WI("H2W_KEY_FORWARD");
+ key = KEY_NEXTSONG;
+ break;
+ case H2W_KEY_BACKWARD:
+ H2WI("H2W_KEY_BACKWARD");
+ key = KEY_PREVIOUSSONG;
+ break;
+ case H2W_KEY_VOLUP:
+ H2WI("H2W_KEY_VOLUP");
+ key = KEY_VOLUMEUP;
+ break;
+ case H2W_KEY_VOLDOWN:
+ H2WI("H2W_KEY_VOLDOWN");
+ key = KEY_VOLUMEDOWN;
+ break;
+ case H2W_KEY_PICKUP:
+ H2WI("H2W_KEY_PICKUP");
+ key = KEY_SEND;
+ break;
+ case H2W_KEY_HANGUP:
+ H2WI("H2W_KEY_HANGUP");
+ key = KEY_END;
+ break;
+ case H2W_KEY_MUTE:
+ H2WI("H2W_KEY_MUTE");
+ key = KEY_MUTE;
+ break;
+ case H2W_KEY_HOLD:
+ H2WI("H2W_KEY_HOLD");
+ break;
+ default:
+ H2WI("default");
+ h2w_key = 0;
+ }
+ if (h2w_key) {
+ if (press)
+ H2WI("Press\n");
+ else
+ H2WI("Release\n");
+ input_report_key(hi->input, key, press);
+ }
+ }
+ break;
+ } /* end switch */
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart detect_event_timer_func(struct hrtimer *data)
+{
+ H2W_DBG("");
+
+ queue_work(g_detection_work_queue, &g_detection_work);
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t detect_irq_handler(int irq, void *dev_id)
+{
+ int value1, value2;
+ int retry_limit = 10;
+
+ H2W_DBG("");
+ set_irq_type(hi->irq_btn, IRQF_TRIGGER_LOW);
+ do {
+ value1 = gpio_get_value(hi->cable_in1);
+ set_irq_type(hi->irq, value1 ?
+ IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+ value2 = gpio_get_value(hi->cable_in1);
+ } while (value1 != value2 && retry_limit-- > 0);
+
+ H2W_DBG("value2 = %d (%d retries), device=%d",
+ value2, (10-retry_limit), switch_get_state(&hi->sdev));
+
+ if ((switch_get_state(&hi->sdev) == H2W_NO_DEVICE) ^ value2) {
+ if (switch_get_state(&hi->sdev) == H2W_HTC_HEADSET)
+ hi->ignore_btn = 1;
+ /* Do the rest of the work in timer context */
+ hrtimer_start(&hi->timer, hi->debounce_time, HRTIMER_MODE_REL);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t button_irq_handler(int irq, void *dev_id)
+{
+ int value1, value2;
+ int retry_limit = 10;
+
+ H2W_DBG("");
+ do {
+ value1 = gpio_get_value(hi->cable_in2);
+ if (hi->htc_headset_flag != H2W_DEVICE)
+ set_irq_type(hi->irq_btn, value1 ?
+ IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+ value2 = gpio_get_value(hi->cable_in2);
+ } while (value1 != value2 && retry_limit-- > 0);
+
+ H2W_DBG("value2 = %d (%d retries)", value2, (10-retry_limit));
+
+ hrtimer_start(&hi->btn_timer, hi->btn_debounce_time, HRTIMER_MODE_REL);
+
+ return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+static int h2w_debug_set(void *data, u64 val)
+{
+ mutex_lock(&hi->mutex_lock);
+ switch_set_state(&hi->sdev, (int)val);
+ mutex_unlock(&hi->mutex_lock);
+ return 0;
+}
+
+static int h2w_debug_get(void *data, u64 *val)
+{
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(h2w_debug_fops, h2w_debug_get, h2w_debug_set, "%llu\n");
+static int __init h2w_debug_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("h2w", 0);
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ debugfs_create_file("state", 0644, dent, NULL, &h2w_debug_fops);
+
+ return 0;
+}
+
+device_initcall(h2w_debug_init);
+#endif
+
+static int h2w_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct h2w_platform_data *pdata = pdev->dev.platform_data;
+
+ printk(KERN_INFO "H2W: Registering H2W (headset) driver\n");
+ hi = kzalloc(sizeof(struct h2w_info), GFP_KERNEL);
+ if (!hi)
+ return -ENOMEM;
+
+ atomic_set(&hi->btn_state, 0);
+ hi->ignore_btn = 0;
+
+ hi->debounce_time = ktime_set(0, 100000000); /* 100 ms */
+ hi->btn_debounce_time = ktime_set(0, 10000000); /* 10 ms */
+
+ hi->htc_headset_flag = 0;
+ hi->cable_in1 = pdata->cable_in1;
+ hi->cable_in2 = pdata->cable_in2;
+ hi->h2w_clk = pdata->h2w_clk;
+ hi->h2w_data = pdata->h2w_data;
+ hi->debug_uart = pdata->debug_uart;
+ hi->config_cpld = pdata->config_cpld;
+ hi->init_cpld = pdata->init_cpld;
+ hi->set_dat = pdata->set_dat;
+ hi->set_clk = pdata->set_clk;
+ hi->set_dat_dir = pdata->set_dat_dir;
+ hi->set_clk_dir = pdata->set_clk_dir;
+ hi->get_dat = pdata->get_dat;
+ hi->get_clk = pdata->get_clk;
+ hi->speed = H2W_50KHz;
+ /* obtain needed VREGs */
+ if (pdata->power_name)
+ hi->vreg_h2w = vreg_get(0, pdata->power_name);
+
+ mutex_init(&hi->mutex_lock);
+
+ hi->sdev.name = "h2w";
+ hi->sdev.print_name = h2w_print_name;
+
+ ret = switch_dev_register(&hi->sdev);
+ if (ret < 0)
+ goto err_switch_dev_register;
+
+ g_detection_work_queue = create_workqueue("detection");
+ if (g_detection_work_queue == NULL) {
+ ret = -ENOMEM;
+ goto err_create_work_queue;
+ }
+
+ ret = gpio_request(hi->cable_in1, "h2w_detect");
+ if (ret < 0)
+ goto err_request_detect_gpio;
+
+ ret = gpio_request(hi->cable_in2, "h2w_button");
+ if (ret < 0)
+ goto err_request_button_gpio;
+
+ ret = gpio_direction_input(hi->cable_in1);
+ if (ret < 0)
+ goto err_set_detect_gpio;
+
+ ret = gpio_direction_input(hi->cable_in2);
+ if (ret < 0)
+ goto err_set_button_gpio;
+
+ hi->irq = gpio_to_irq(hi->cable_in1);
+ if (hi->irq < 0) {
+ ret = hi->irq;
+ goto err_get_h2w_detect_irq_num_failed;
+ }
+
+ hi->irq_btn = gpio_to_irq(hi->cable_in2);
+ if (hi->irq_btn < 0) {
+ ret = hi->irq_btn;
+ goto err_get_button_irq_num_failed;
+ }
+
+ /* Set CPLD MUX to H2W <-> CPLD GPIO */
+ hi->init_cpld();
+
+ hrtimer_init(&hi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hi->timer.function = detect_event_timer_func;
+ hrtimer_init(&hi->btn_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hi->btn_timer.function = button_event_timer_func;
+
+ ret = request_irq(hi->irq, detect_irq_handler,
+ IRQF_TRIGGER_LOW, "h2w_detect", NULL);
+ if (ret < 0)
+ goto err_request_detect_irq;
+
+ /* Disable button until plugged in */
+ set_irq_flags(hi->irq_btn, IRQF_VALID | IRQF_NOAUTOEN);
+ ret = request_irq(hi->irq_btn, button_irq_handler,
+ IRQF_TRIGGER_LOW, "h2w_button", NULL);
+ if (ret < 0)
+ goto err_request_h2w_headset_button_irq;
+
+ ret = set_irq_wake(hi->irq, 1);
+ if (ret < 0)
+ goto err_request_input_dev;
+
+ ret = set_irq_wake(hi->irq_btn, 1);
+ if (ret < 0)
+ goto err_request_input_dev;
+
+
+
+ hi->input = input_allocate_device();
+ if (!hi->input) {
+ ret = -ENOMEM;
+ goto err_request_input_dev;
+ }
+
+ hi->input->name = "h2w headset";
+ set_bit(EV_SYN, hi->input->evbit);
+ set_bit(EV_KEY, hi->input->evbit);
+ set_bit(KEY_MEDIA, hi->input->keybit);
+ set_bit(KEY_NEXTSONG, hi->input->keybit);
+ set_bit(KEY_PLAYPAUSE, hi->input->keybit);
+ set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
+ set_bit(KEY_MUTE, hi->input->keybit);
+ set_bit(KEY_VOLUMEUP, hi->input->keybit);
+ set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
+ set_bit(KEY_END, hi->input->keybit);
+ set_bit(KEY_SEND, hi->input->keybit);
+
+ ret = input_register_device(hi->input);
+ if (ret < 0)
+ goto err_register_input_dev;
+
+ return 0;
+
+err_register_input_dev:
+ input_free_device(hi->input);
+err_request_input_dev:
+ free_irq(hi->irq_btn, 0);
+err_request_h2w_headset_button_irq:
+ free_irq(hi->irq, 0);
+err_request_detect_irq:
+err_get_button_irq_num_failed:
+err_get_h2w_detect_irq_num_failed:
+err_set_button_gpio:
+err_set_detect_gpio:
+ gpio_free(hi->cable_in2);
+err_request_button_gpio:
+ gpio_free(hi->cable_in1);
+err_request_detect_gpio:
+ destroy_workqueue(g_detection_work_queue);
+err_create_work_queue:
+ switch_dev_unregister(&hi->sdev);
+err_switch_dev_register:
+ printk(KERN_ERR "H2W: Failed to register driver\n");
+
+ return ret;
+}
+
+static int h2w_remove(struct platform_device *pdev)
+{
+ H2W_DBG("");
+ if (switch_get_state(&hi->sdev))
+ remove_headset();
+ input_unregister_device(hi->input);
+ gpio_free(hi->cable_in2);
+ gpio_free(hi->cable_in1);
+ free_irq(hi->irq_btn, 0);
+ free_irq(hi->irq, 0);
+ destroy_workqueue(g_detection_work_queue);
+ switch_dev_unregister(&hi->sdev);
+
+ return 0;
+}
+
+
+static struct platform_driver h2w_driver = {
+ .probe = h2w_probe,
+ .remove = h2w_remove,
+ .driver = {
+ .name = "h2w",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init h2w_init(void)
+{
+ H2W_DBG("");
+ return platform_driver_register(&h2w_driver);
+}
+
+static void __exit h2w_exit(void)
+{
+ platform_driver_unregister(&h2w_driver);
+}
+
+module_init(h2w_init);
+module_exit(h2w_exit);
+
+MODULE_AUTHOR("Laurence Chen <Laurence_Chen@htc.com>");
+MODULE_DESCRIPTION("HTC 2 Wire detection driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/htc_pwrsink.c b/arch/arm/mach-msm/htc_pwrsink.c
new file mode 100644
index 000000000000..2ec2c7f4bb1b
--- /dev/null
+++ b/arch/arm/mach-msm/htc_pwrsink.c
@@ -0,0 +1,281 @@
+/* arch/arm/mach-msm/htc_pwrsink.c
+ *
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (C) 2008 Google, Inc.
+ * Author: San Mehat <san@google.com>
+ * Kant Kang <kant_kang@htc.com>
+ * Eiven Peng <eiven_peng@htc.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/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/earlysuspend.h>
+#include <mach/msm_smd.h>
+#include <mach/htc_pwrsink.h>
+
+#include "smd_private.h"
+
+enum {
+ PWRSINK_DEBUG_CURR_CHANGE = 1U << 0,
+ PWRSINK_DEBUG_CURR_CHANGE_AUDIO = 1U << 1,
+};
+static int pwrsink_debug_mask;
+module_param_named(debug_mask, pwrsink_debug_mask, int,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int initialized;
+static unsigned audio_path = 1; /* HTC_SND_DEVICE_SPEAKER = 1 */
+static struct pwr_sink_audio audio_sink_array[PWRSINK_AUDIO_LAST + 1];
+static struct pwr_sink *sink_array[PWRSINK_LAST + 1];
+static DEFINE_SPINLOCK(sink_lock);
+static DEFINE_SPINLOCK(audio_sink_lock);
+static unsigned long total_sink;
+static uint32_t *smem_total_sink;
+
+int htc_pwrsink_set(pwrsink_id_type id, unsigned percent_utilized)
+{
+ unsigned long flags;
+
+ if (!smem_total_sink)
+ smem_total_sink = smem_alloc(SMEM_ID_VENDOR0, sizeof(uint32_t));
+
+ if (!initialized)
+ return -EAGAIN;
+
+ if (id < 0 || id > PWRSINK_LAST)
+ return -EINVAL;
+
+ spin_lock_irqsave(&sink_lock, flags);
+
+ if (!sink_array[id]) {
+ spin_unlock_irqrestore(&sink_lock, flags);
+ return -ENOENT;
+ }
+
+ if (sink_array[id]->percent_util == percent_utilized) {
+ spin_unlock_irqrestore(&sink_lock, flags);
+ return 0;
+ }
+
+ total_sink -= (sink_array[id]->ua_max *
+ sink_array[id]->percent_util / 100);
+ sink_array[id]->percent_util = percent_utilized;
+ total_sink += (sink_array[id]->ua_max *
+ sink_array[id]->percent_util / 100);
+
+ if (smem_total_sink)
+ *smem_total_sink = total_sink / 1000;
+
+ pr_debug("htc_pwrsink: ID %d, Util %d%%, Total %lu uA %s\n",
+ id, percent_utilized, total_sink,
+ smem_total_sink ? "SET" : "");
+
+ spin_unlock_irqrestore(&sink_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_set);
+
+static void compute_audio_current(void)
+{
+ /* unsigned long flags; */
+ unsigned max_percent = 0;
+ int i, active_audio_sinks = 0;
+ pwrsink_audio_id_type last_active_audio_sink = 0;
+
+ /* Make sure this segment will be spinlocked
+ before computing by calling function. */
+ /* spin_lock_irqsave(&audio_sink_lock, flags); */
+ for (i = 0; i <= PWRSINK_AUDIO_LAST; ++i) {
+ max_percent = (audio_sink_array[i].percent > max_percent) ?
+ audio_sink_array[i].percent : max_percent;
+ if (audio_sink_array[i].percent > 0) {
+ active_audio_sinks++;
+ last_active_audio_sink = i;
+ }
+ }
+ if (active_audio_sinks == 0)
+ htc_pwrsink_set(PWRSINK_AUDIO, 0);
+ else if (active_audio_sinks == 1) {
+ pwrsink_audio_id_type laas = last_active_audio_sink;
+ /* TODO: add volume and routing path current. */
+ if (audio_path == 1) /* Speaker */
+ htc_pwrsink_set(PWRSINK_AUDIO,
+ audio_sink_array[laas].percent);
+ else
+ htc_pwrsink_set(PWRSINK_AUDIO,
+ audio_sink_array[laas].percent * 9 / 10);
+ } else if (active_audio_sinks > 1) {
+ /* TODO: add volume and routing path current. */
+ if (audio_path == 1) /* Speaker */
+ htc_pwrsink_set(PWRSINK_AUDIO, max_percent);
+ else
+ htc_pwrsink_set(PWRSINK_AUDIO, max_percent * 9 / 10);
+ }
+ /* spin_unlock_irqrestore(&audio_sink_lock, flags); */
+
+ if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+ pr_info("%s: active_audio_sinks=%d, audio_path=%d\n", __func__,
+ active_audio_sinks, audio_path);
+}
+
+int htc_pwrsink_audio_set(pwrsink_audio_id_type id, unsigned percent_utilized)
+{
+ unsigned long flags;
+
+ if (id < 0 || id > PWRSINK_AUDIO_LAST)
+ return -EINVAL;
+
+ if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+ pr_info("%s: id=%d, percent=%d, percent_old=%d\n", __func__,
+ id, percent_utilized, audio_sink_array[id].percent);
+
+ spin_lock_irqsave(&audio_sink_lock, flags);
+ if (audio_sink_array[id].percent == percent_utilized) {
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ return 0;
+ }
+ audio_sink_array[id].percent = percent_utilized;
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ compute_audio_current();
+ return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_set);
+
+int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id, unsigned volume)
+{
+ unsigned long flags;
+
+ if (id < 0 || id > PWRSINK_AUDIO_LAST)
+ return -EINVAL;
+
+ if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+ pr_info("%s: id=%d, volume=%d, volume_old=%d\n", __func__,
+ id, volume, audio_sink_array[id].volume);
+
+ spin_lock_irqsave(&audio_sink_lock, flags);
+ if (audio_sink_array[id].volume == volume) {
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ return 0;
+ }
+ audio_sink_array[id].volume = volume;
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ compute_audio_current();
+ return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_volume_set);
+
+int htc_pwrsink_audio_path_set(unsigned path)
+{
+ unsigned long flags;
+
+ if (pwrsink_debug_mask & PWRSINK_DEBUG_CURR_CHANGE_AUDIO)
+ pr_info("%s: path=%d, path_old=%d\n",
+ __func__, path, audio_path);
+
+ spin_lock_irqsave(&audio_sink_lock, flags);
+ if (audio_path == path) {
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ return 0;
+ }
+ audio_path = path;
+ spin_unlock_irqrestore(&audio_sink_lock, flags);
+ compute_audio_current();
+ return 0;
+}
+EXPORT_SYMBOL(htc_pwrsink_audio_path_set);
+
+void htc_pwrsink_suspend_early(struct early_suspend *h)
+{
+ htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70);
+}
+
+int htc_pwrsink_suspend_late(struct platform_device *pdev, pm_message_t state)
+{
+ struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+
+ if (pdata && pdata->suspend_late)
+ pdata->suspend_late(pdev, state);
+ else
+ htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 13);
+ return 0;
+}
+
+int htc_pwrsink_resume_early(struct platform_device *pdev)
+{
+ struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+
+ if (pdata && pdata->resume_early)
+ pdata->resume_early(pdev);
+ else
+ htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 70);
+ return 0;
+}
+
+void htc_pwrsink_resume_late(struct early_suspend *h)
+{
+ htc_pwrsink_set(PWRSINK_SYSTEM_LOAD, 100);
+}
+
+struct early_suspend htc_pwrsink_early_suspend = {
+ .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
+ .suspend = htc_pwrsink_suspend_early,
+ .resume = htc_pwrsink_resume_late,
+};
+
+static int __init htc_pwrsink_probe(struct platform_device *pdev)
+{
+ struct pwr_sink_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (!pdata)
+ return -EINVAL;
+
+ total_sink = 0;
+ for (i = 0; i < pdata->num_sinks; i++) {
+ sink_array[pdata->sinks[i].id] = &pdata->sinks[i];
+ total_sink += (pdata->sinks[i].ua_max *
+ pdata->sinks[i].percent_util / 100);
+ }
+
+ initialized = 1;
+
+ if (pdata->suspend_early)
+ htc_pwrsink_early_suspend.suspend = pdata->suspend_early;
+ if (pdata->resume_late)
+ htc_pwrsink_early_suspend.resume = pdata->resume_late;
+ register_early_suspend(&htc_pwrsink_early_suspend);
+
+ return 0;
+}
+
+static struct platform_driver htc_pwrsink_driver = {
+ .probe = htc_pwrsink_probe,
+ .suspend_late = htc_pwrsink_suspend_late,
+ .resume_early = htc_pwrsink_resume_early,
+ .driver = {
+ .name = "htc_pwrsink",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init htc_pwrsink_init(void)
+{
+ initialized = 0;
+ memset(sink_array, 0, sizeof(sink_array));
+ return platform_driver_register(&htc_pwrsink_driver);
+}
+
+module_init(htc_pwrsink_init);
diff --git a/arch/arm/mach-msm/htc_wifi_nvs.c b/arch/arm/mach-msm/htc_wifi_nvs.c
new file mode 100644
index 000000000000..95b8c3bbae9d
--- /dev/null
+++ b/arch/arm/mach-msm/htc_wifi_nvs.c
@@ -0,0 +1,56 @@
+/* arch/arm/mach-msm/htc_wifi_nvs.c
+ *
+ * Code to extract WiFi calibration information from ATAG set up
+ * by the bootloader.
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Dmitry Shmidt <dimitrysh@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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+
+/* configuration tags specific to msm */
+#define ATAG_MSM_WIFI 0x57494649 /* MSM WiFi */
+
+#define MAX_NVS_SIZE 0x800U
+static unsigned char wifi_nvs_ram[MAX_NVS_SIZE];
+
+unsigned char *get_wifi_nvs_ram( void )
+{
+ return( wifi_nvs_ram );
+}
+EXPORT_SYMBOL(get_wifi_nvs_ram);
+
+static int __init parse_tag_msm_wifi(const struct tag *tag)
+{
+ unsigned char *dptr = (unsigned char *)(&tag->u);
+ unsigned size;
+
+ size = min((tag->hdr.size - 2) * sizeof(__u32), MAX_NVS_SIZE);
+#ifdef ATAG_MSM_WIFI_DEBUG
+ unsigned i;
+
+ printk("WiFi Data size = %d , 0x%x\n", tag->hdr.size, tag->hdr.tag);
+ for(i=0;( i < size );i++) {
+ printk("%02x ", *dptr++);
+ }
+#endif
+ memcpy( (void *)wifi_nvs_ram, (void *)dptr, size );
+ return 0;
+}
+
+__tagtable(ATAG_MSM_WIFI, parse_tag_msm_wifi);
diff --git a/arch/arm/mach-msm/idle-v6.S b/arch/arm/mach-msm/idle-v6.S
new file mode 100644
index 000000000000..1c74c6436a4e
--- /dev/null
+++ b/arch/arm/mach-msm/idle-v6.S
@@ -0,0 +1,177 @@
+/*
+ * Idle processing for ARMv6-based Qualcomm SoCs.
+ * Work around bugs with SWFI.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, 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/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(msm_arch_idle)
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */
+ mrc p15, 0, r1, c1, c0, 0 /* read current CR */
+ bic r0, r1, #(1 << 2) /* clear dcache bit */
+ bic r0, r0, #(1 << 12) /* clear icache bit */
+ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 /* dsb */
+ mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */
+
+ mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+
+ mov pc, lr
+
+ENTRY(msm_pm_collapse)
+ ldr r0, =saved_state
+ stmia r0!, {r4-r14}
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+ cpsid f
+#endif
+ mrc p15, 0, r1, c1, c0, 0 /* MMU control */
+ mrc p15, 0, r2, c2, c0, 0 /* ttb */
+ mrc p15, 0, r3, c3, c0, 0 /* dacr */
+ mrc p15, 0, ip, c13, c0, 1 /* context ID */
+ stmia r0!, {r1-r3, ip}
+#if defined(CONFIG_OPROFILE)
+ mrc p15, 0, r1, c15, c12, 0 /* pmnc */
+ mrc p15, 0, r2, c15, c12, 1 /* ccnt */
+ mrc p15, 0, r3, c15, c12, 2 /* pmn0 */
+ mrc p15, 0, ip, c15, c12, 3 /* pmn1 */
+ stmia r0!, {r1-r3, ip}
+#endif
+ mrc p15, 0, r1, c1, c0, 2 /* read CACR */
+ stmia r0!, {r1}
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */
+ mrc p15, 0, r1, c1, c0, 0 /* read current CR */
+ bic r0, r1, #(1 << 2) /* clear dcache bit */
+ bic r0, r0, #(1 << 12) /* clear icache bit */
+ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 /* dsb */
+ mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */
+
+ mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+ cpsie f
+#endif
+
+ ldr r0, =saved_state /* restore registers */
+ ldmfd r0, {r4-r14}
+ mov r0, #0 /* return power collapse failed */
+ mov pc, lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+ mov r0, #0x80000016
+ mcr p15, 0, r0, c15, c2, 4
+ mov r0, #0xA9000000
+ add r0, r0, #0x00A00000 /* UART1 */
+ /*add r0, r0, #0x00C00000*/ /* UART3 */
+ mov r1, #'A'
+ str r1, [r0, #0x00C]
+#endif
+ ldr r1, =saved_state_end
+ ldr r2, =msm_pm_collapse_exit
+ adr r3, msm_pm_collapse_exit
+ add r1, r1, r3
+ sub r1, r1, r2
+
+ ldmdb r1!, {r2}
+ mcr p15, 0, r2, c1, c0, 2 /* restore CACR */
+#if defined(CONFIG_OPROFILE)
+ ldmdb r1!, {r2-r5}
+ mcr p15, 0, r3, c15, c12, 1 /* ccnt */
+ mcr p15, 0, r4, c15, c12, 2 /* pmn0 */
+ mcr p15, 0, r5, c15, c12, 3 /* pmn1 */
+ mcr p15, 0, r2, c15, c12, 0 /* pmnc */
+#endif
+ ldmdb r1!, {r2-r5}
+ mcr p15, 0, r4, c3, c0, 0 /* dacr */
+ mcr p15, 0, r3, c2, c0, 0 /* ttb */
+ mcr p15, 0, r5, c13, c0, 1 /* context ID */
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+ ldmdb r1!, {r4-r14}
+
+ /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */
+ and r3, r3, #~0x7F /* mask off lower 7 bits of TTB */
+ adr r0, msm_pm_mapped_pa /* get address of the mapped instr */
+ lsr r1, r0, #20 /* get the addr range of addr in MB */
+ lsl r1, r1, #2 /* multiply by 4 to get to the pg index */
+ add r3, r3, r1 /* pgd + pgd_index(addr) */
+ ldr r1, [r3] /* save current entry to r1 */
+ lsr r0, #20 /* align current addr to 1MB boundary */
+ lsl r0, #20
+ /* Create new entry for this 1MB page */
+ orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */
+ orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */
+ str r0, [r3] /* put new entry into the MMU table */
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 /* dsb */
+ mcr p15, 0, r2, c1, c0, 0 /* MMU control */
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+msm_pm_mapped_pa:
+ /* Switch to virtual */
+ adr r2, msm_pm_pa_to_va
+ ldr r0, =msm_pm_pa_to_va
+ mov pc, r0
+msm_pm_pa_to_va:
+ sub r0, r0, r2
+ /* Restore r1 in MMU table */
+ add r3, r3, r0
+ str r1, [r3]
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 0 /* flush entire data cache */
+ mcr p15, 0, r0, c7, c10, 4 /* dsb */
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+ mcr p15, 0, r0, c8, c7, 0 /* invalidate entire unified TLB */
+ mcr p15, 0, r0, c7, c5, 6 /* invalidate entire branch target
+ * cache */
+ mcr p15, 0, r0, c7, c7, 0 /* invalidate both data and instruction
+ * cache */
+ mcr p15, 0, r0, c7, c10, 4 /* dsb */
+ mcr p15, 0, r0, c7, c5, 4 /* isb */
+
+ mov r0, #1
+ mov pc, lr
+ nop
+ nop
+ nop
+ nop
+ nop
+1: b 1b
+
+
+ .data
+
+saved_state:
+ .space 4 * 11 /* r4-14 */
+ .space 4 * 4 /* cp15 - MMU control, ttb, dacr, context ID */
+#if defined(CONFIG_OPROFILE)
+ .space 4 * 4 /* more cp15 - pmnc, ccnt, pmn0, pmn1 */
+#endif
+ .space 4 /* cacr */
+saved_state_end:
+
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
new file mode 100644
index 000000000000..588062813e78
--- /dev/null
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -0,0 +1,175 @@
+/*
+ * Idle processing for ARMv7-based Qualcomm SoCs.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, 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/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(msm_arch_idle)
+ wfi
+ bx lr
+
+ENTRY(msm_pm_collapse)
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+ cpsid f
+#endif
+
+ ldr r0, =saved_state
+ stmia r0!, {r4-r14}
+ mrc p15, 0, r1, c1, c0, 0 /* MMU control */
+ mrc p15, 0, r2, c2, c0, 0 /* TTBR0 */
+ mrc p15, 0, r3, c3, c0, 0 /* dacr */
+ mrc p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */
+ mrc p15, 0, r5, c10, c2, 0 /* PRRR */
+ mrc p15, 0, r6, c10, c2, 1 /* NMRR */
+ mrc p15, 0, r7, c1, c0, 1 /* ACTLR */
+ mrc p15, 0, r8, c2, c0, 1 /* TTBR1 */
+ mrc p15, 0, r9, c13, c0, 3 /* TPIDRURO */
+ mrc p15, 0, ip, c13, c0, 1 /* context ID */
+ stmia r0!, {r1-r9, ip}
+#ifdef CONFIG_MSM_CPU_AVS
+ mrc p15, 7, r1, c15, c1, 7 /* AVSCSR is the Adaptive Voltage Scaling
+ * Control and Status Register */
+ mrc p15, 7, r2, c15, c0, 6 /* AVSDSCR is the Adaptive Voltage
+ * Scaling Delay Synthesizer Control
+ * Register */
+ mrc p15, 7, r3, c15, c1, 0 /* TSCSR is the Temperature Status and
+ * Control Register
+ */
+ stmia r0!, {r1-r3}
+#endif
+
+#ifdef CONFIG_MSM_JTAG_V7
+ bl msm_save_jtag_debug
+#endif
+ bl v7_flush_dcache_all
+
+ mrc p15, 0, r1, c1, c0, 0 /* read current CR */
+ bic r0, r1, #(1 << 2) /* clear dcache bit */
+ bic r0, r0, #(1 << 12) /* clear icache bit */
+ mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
+
+ dsb
+ wfi
+
+ mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */
+ isb
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+ cpsie f
+#endif
+
+ ldr r0, =saved_state /* restore registers */
+ ldmfd r0, {r4-r14}
+ mov r0, #0 /* return power collapse failed */
+ bx lr
+
+ENTRY(msm_pm_collapse_exit)
+#if 0 /* serial debug */
+ mov r0, #0x80000016
+ mcr p15, 0, r0, c15, c2, 4
+ mov r0, #0xA9000000
+ add r0, r0, #0x00A00000 /* UART1 */
+ /*add r0, r0, #0x00C00000*/ /* UART3 */
+ mov r1, #'A'
+ str r1, [r0, #0x00C]
+#endif
+ ldr r1, =saved_state_end
+ ldr r2, =msm_pm_collapse_exit
+ adr r3, msm_pm_collapse_exit
+ add r1, r1, r3
+ sub r1, r1, r2
+#ifdef CONFIG_MSM_CPU_AVS
+ ldmdb r1!, {r2-r4}
+ mcr p15, 7, r4, c15, c1, 0 /* TSCSR */
+ mcr p15, 7, r3, c15, c0, 6 /* AVSDSCR */
+ mcr p15, 7, r2, c15, c1, 7 /* AVSCSR */
+#endif
+ ldmdb r1!, {r2-r11}
+ mcr p15, 0, r4, c3, c0, 0 /* dacr */
+ mcr p15, 0, r3, c2, c0, 0 /* TTBR0 */
+ mcr p15, 3, r5, c15, c0, 3 /* L2CR1 */
+ mcr p15, 0, r6, c10, c2, 0 /* PRRR */
+ mcr p15, 0, r7, c10, c2, 1 /* NMRR */
+ mcr p15, 0, r8, c1, c0, 1 /* ACTLR */
+ mcr p15, 0, r9, c2, c0, 1 /* TTBR1 */
+ mcr p15, 0, r10, c13, c0, 3 /* TPIDRURO */
+ mcr p15, 0, r11, c13, c0, 1 /* context ID */
+ isb
+ ldmdb r1!, {r4-r14}
+ /* Add 1:1 map in the PMD to allow smooth switch when turning on MMU */
+ and r3, r3, #~0x7F /* mask off lower 7 bits of TTB */
+ adr r0, msm_pm_mapped_pa /* get address of the mapped instr */
+ lsr r1, r0, #20 /* get the addr range of addr in MB */
+ lsl r1, r1, #2 /* multiply by 4 to get to the pg index */
+ add r3, r3, r1 /* pgd + pgd_index(addr) */
+ ldr r1, [r3] /* save current entry to r1 */
+ lsr r0, #20 /* align current addr to 1MB boundary */
+ lsl r0, #20
+ /* Create new entry for this 1MB page */
+ orr r0, r0, #0x4 /* PMD_SECT_BUFFERED */
+ orr r0, r0, #0x400 /* PMD_SECT_AP_WRITE */
+ orr r0, r0, #0x2 /* PMD_TYPE_SECT|PMD_DOMAIN(DOMAIN_KERNEL) */
+ str r0, [r3] /* put new entry into the MMU table */
+ mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */
+ dsb
+ isb
+ mcr p15, 0, r2, c1, c0, 0 /* MMU control */
+ isb
+msm_pm_mapped_pa:
+ /* Switch to virtual */
+ adr r2, msm_pm_pa_to_va
+ ldr r0, =msm_pm_pa_to_va
+ mov pc, r0
+msm_pm_pa_to_va:
+ sub r0, r0, r2
+ /* Restore r1 in MMU table */
+ add r3, r3, r0
+ str r1, [r3]
+ mcr p15, 0, r3, c7, c10, 1 /* flush_pmd */
+ dsb
+ isb
+ mcr p15, 0, r3, c8, c7, 0 /* UTLBIALL */
+ mcr p15, 0, r3, c7, c5, 6 /* BPIALL */
+ dsb
+ isb
+ stmfd sp!, {lr}
+ bl v7_flush_kern_cache_all
+#ifdef CONFIG_MSM_JTAG_V7
+ bl msm_restore_jtag_debug
+#endif
+ ldmfd sp!, {lr}
+ mov r0, #1
+ bx lr
+ nop
+ nop
+ nop
+ nop
+ nop
+1: b 1b
+
+
+ .data
+
+saved_state:
+ .space 4 * 11 /* r4-14 */
+ .space 4 * 10 /* cp15 */
+#ifdef CONFIG_MSM_CPU_AVS
+ .space 4 * 3 /* AVS control registers */
+#endif
+saved_state_end:
+
+
diff --git a/arch/arm/mach-msm/idle.S b/arch/arm/mach-msm/idle.S
deleted file mode 100644
index 6a94f0527137..000000000000
--- a/arch/arm/mach-msm/idle.S
+++ /dev/null
@@ -1,36 +0,0 @@
-/* arch/arm/mach-msm/include/mach/idle.S
- *
- * Idle processing for MSM7K - work around bugs with SWFI.
- *
- * Copyright (c) 2007 QUALCOMM Incorporated.
- * Copyright (C) 2007 Google, Inc.
- *
- * 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/linkage.h>
-#include <asm/assembler.h>
-
-ENTRY(arch_idle)
-#ifdef CONFIG_MSM7X00A_IDLE
- mrc p15, 0, r1, c1, c0, 0 /* read current CR */
- bic r0, r1, #(1 << 2) /* clear dcache bit */
- bic r0, r0, #(1 << 12) /* clear icache bit */
- mcr p15, 0, r0, c1, c0, 0 /* disable d/i cache */
-
- mov r0, #0 /* prepare wfi value */
- mcr p15, 0, r0, c7, c10, 0 /* flush the cache */
- mcr p15, 0, r0, c7, c10, 4 /* memory barrier */
- mcr p15, 0, r0, c7, c0, 4 /* wait for interrupt */
-
- mcr p15, 0, r1, c1, c0, 0 /* restore d/i cache */
-#endif
- mov pc, lr
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
new file mode 100644
index 000000000000..2e0371ed5b59
--- /dev/null
+++ b/arch/arm/mach-msm/idle.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2007-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 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
+#define _ARCH_ARM_MACH_MSM_IDLE_H_
+
+int msm_arch_idle(void);
+int msm_pm_collapse(void);
+void msm_pm_collapse_exit(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 264d62e519f3..163dffe87923 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/board.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -18,6 +19,8 @@
#define __ASM_ARCH_MSM_BOARD_H
#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/clk.h>
/* platform device data structures */
@@ -27,12 +30,35 @@ struct msm_mddi_platform_data
unsigned has_vsync_irq:1;
};
+struct msm_acpu_clock_platform_data
+{
+ uint32_t acpu_switch_time_us;
+ uint32_t max_speed_delta_khz;
+ uint32_t vdd_switch_time_us;
+ unsigned long power_collapse_khz;
+ unsigned long wait_for_irq_khz;
+ unsigned int max_axi_khz;
+ unsigned int max_vdd;
+ int (*acpu_set_vdd) (int mvolts);
+};
+
/* common init routines for use by arch/arm/mach-msm/board-*.c */
void __init msm_add_devices(void);
void __init msm_map_common_io(void);
+void __init msm_map_qsd8x50_io(void);
+void __init msm_map_msm7x30_io(void);
+void __init msm_map_comet_io(void);
void __init msm_init_irq(void);
-void __init msm_init_gpio(void);
-void __init msm_clock_init(void);
+void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks);
+void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
+
+#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB)
+void msm_hsusb_set_vbus_state(int online);
+#else
+static inline void msm_hsusb_set_vbus_state(int online) {}
+#endif
+
+extern int msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
#endif
diff --git a/arch/arm/mach-msm/include/mach/board_htc.h b/arch/arm/mach-msm/include/mach/board_htc.h
new file mode 100644
index 000000000000..b537c91b957a
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/board_htc.h
@@ -0,0 +1,78 @@
+/* arch/arm/mach-msm/include/mach/BOARD_HTC.h
+ * Copyright (C) 2007-2009 HTC Corporation.
+ * Author: Thomas Tsai <thomas_tsai@htc.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 __ASM_ARCH_MSM_BOARD_HTC_H
+#define __ASM_ARCH_MSM_BOARD_HTC_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/setup.h>
+
+struct msm_pmem_setting{
+ resource_size_t pmem_start;
+ resource_size_t pmem_size;
+ resource_size_t pmem_adsp_start;
+ resource_size_t pmem_adsp_size;
+ resource_size_t pmem_gpu0_start;
+ resource_size_t pmem_gpu0_size;
+ resource_size_t pmem_gpu1_start;
+ resource_size_t pmem_gpu1_size;
+ resource_size_t pmem_camera_start;
+ resource_size_t pmem_camera_size;
+ resource_size_t ram_console_start;
+ resource_size_t ram_console_size;
+};
+
+enum {
+ MSM_SERIAL_UART1 = 0,
+ MSM_SERIAL_UART2,
+ MSM_SERIAL_UART3,
+#ifdef CONFIG_SERIAL_MSM_HS
+ MSM_SERIAL_UART1DM,
+ MSM_SERIAL_UART2DM,
+#endif
+ MSM_SERIAL_NUM,
+};
+
+
+/* common init routines for use by arch/arm/mach-msm/board-*.c */
+
+void __init msm_add_usb_devices(void (*phy_reset) (void));
+void __init msm_add_mem_devices(struct msm_pmem_setting *setting);
+void __init msm_init_pmic_vibrator(void);
+
+struct mmc_platform_data;
+int __init msm_add_sdcc_devices(unsigned int controller, struct mmc_platform_data *plat);
+int __init msm_add_serial_devices(unsigned uart);
+
+#if defined(CONFIG_USB_FUNCTION_MSM_HSUSB)
+/* START: add USB connected notify function */
+struct t_usb_status_notifier{
+ struct list_head notifier_link;
+ const char *name;
+ void (*func)(int online);
+};
+ int usb_register_notifier(struct t_usb_status_notifier *);
+ static LIST_HEAD(g_lh_usb_notifier_list);
+/* END: add USB connected notify function */
+#endif
+
+int __init board_mfg_mode(void);
+int __init parse_tag_smi(const struct tag *tags);
+int __init parse_tag_hwid(const struct tag * tags);
+int __init parse_tag_skuid(const struct tag * tags);
+int parse_tag_engineerid(const struct tag * tags);
+
+char *board_serialno(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
new file mode 100644
index 000000000000..220fca53c7e5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -0,0 +1,297 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ASM__ARCH_CAMERA_H
+#define __ASM__ARCH_CAMERA_H
+
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include "linux/types.h"
+
+#include <mach/board.h>
+#include <media/msm_camera.h>
+
+#undef CDBG
+#ifdef CAMERA_DBG_MSG
+#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args)
+#else
+#define CDBG(fmt, args...)
+#endif
+
+#define MSM_CAMERA_MSG 0
+#define MSM_CAMERA_EVT 1
+#define NUM_WB_EXP_NEUTRAL_REGION_LINES 4
+#define NUM_WB_EXP_STAT_OUTPUT_BUFFERS 3
+#define NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS 16
+#define NUM_AF_STAT_OUTPUT_BUFFERS 3
+
+enum msm_queut_t {
+ MSM_CAM_Q_IVALID,
+ MSM_CAM_Q_CTRL,
+ MSM_CAM_Q_VFE_EVT,
+ MSM_CAM_Q_VFE_MSG,
+ MSM_CAM_Q_V4L2_REQ,
+
+ MSM_CAM_Q_MAX
+};
+
+enum vfe_resp_msg_t {
+ VFE_EVENT,
+ VFE_MSG_GENERAL,
+ VFE_MSG_SNAPSHOT,
+ VFE_MSG_OUTPUT1,
+ VFE_MSG_OUTPUT2,
+ VFE_MSG_STATS_AF,
+ VFE_MSG_STATS_WE,
+
+ VFE_MSG_INVALID
+};
+
+struct msm_vfe_phy_info {
+ uint32_t sbuf_phy;
+ uint32_t y_phy;
+ uint32_t cbcr_phy;
+};
+
+struct msm_vfe_resp_t {
+ enum vfe_resp_msg_t type;
+ struct msm_vfe_evt_msg_t evt_msg;
+ struct msm_vfe_phy_info phy;
+ void *extdata;
+ int32_t extlen;
+};
+
+struct msm_vfe_resp {
+ void (*vfe_resp)(struct msm_vfe_resp_t *,
+ enum msm_queut_t, void *syncdata);
+};
+
+struct msm_camvfe_fn_t {
+ int (*vfe_init) (struct msm_vfe_resp *, struct platform_device *);
+ int (*vfe_enable) (struct camera_enable_cmd_t *);
+ int (*vfe_config) (struct msm_vfe_cfg_cmd_t *, void *);
+ int (*vfe_disable) (struct camera_enable_cmd_t *,
+ struct platform_device *dev);
+ void (*vfe_release) (struct platform_device *);
+};
+
+struct msm_sensor_ctrl_t {
+ int (*s_init)(struct msm_camera_sensor_info *);
+ int (*s_release)(void);
+ int (*s_config)(void __user *);
+};
+
+struct msm_sync_t {
+ spinlock_t msg_event_queue_lock;
+ struct list_head msg_event_queue;
+ wait_queue_head_t msg_event_wait;
+
+ spinlock_t prev_frame_q_lock;
+ struct list_head prev_frame_q;
+ wait_queue_head_t prev_frame_wait;
+
+ spinlock_t pict_frame_q_lock;
+ struct list_head pict_frame_q;
+ wait_queue_head_t pict_frame_wait;
+
+ spinlock_t ctrl_status_lock;
+ struct list_head ctrl_status_queue;
+ wait_queue_head_t ctrl_status_wait;
+
+ struct hlist_head frame;
+ struct hlist_head stats;
+};
+
+struct msm_device_t {
+ struct msm_camvfe_fn_t vfefn;
+ struct device *device;
+ struct cdev cdev;
+ struct platform_device *pdev;
+
+ struct mutex msm_lock;
+ uint8_t opencnt;
+
+ const char *apps_id;
+
+ void *cropinfo;
+ int croplen;
+
+ struct mutex pict_pp_lock;
+ uint8_t pict_pp;
+
+ int sidx;
+ struct msm_sensor_ctrl_t sctrl;
+
+ struct mutex msm_sem;
+ struct msm_sync_t sync;
+};
+
+/* this structure is used in kernel */
+struct msm_queue_cmd_t {
+ struct list_head list;
+
+ /* 1 - control command or control command status;
+ * 2 - adsp event;
+ * 3 - adsp message;
+ * 4 - v4l2 request;
+ */
+ enum msm_queut_t type;
+ void *command;
+};
+
+struct register_address_value_pair_t {
+ uint16_t register_address;
+ uint16_t register_value;
+};
+
+struct msm_pmem_region {
+ struct hlist_node list;
+ enum msm_pmem_t type;
+ void *vaddr;
+ unsigned long paddr;
+ unsigned long len;
+ struct file *file;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+ int fd;
+ uint8_t active;
+};
+
+struct axidata_t {
+ uint32_t bufnum1;
+ uint32_t bufnum2;
+ struct msm_pmem_region *region;
+};
+
+int32_t mt9d112_probe_init(void *, void *);
+int32_t mt9t013_probe_init(void *, void *);
+int32_t mt9p012_probe_init(void *, void *);
+int32_t s5k3e2fx_probe_init(void *, void *);
+
+int32_t flash_set_led_state(enum msm_camera_led_state_t led_state);
+
+/* Below functions are added for V4L2 kernel APIs */
+struct msm_driver {
+ struct msm_device_t *vmsm;
+ long (*init)(struct msm_device_t *);
+ long (*ctrl)(struct msm_ctrl_cmd_t *,
+ struct msm_device_t *);
+
+ long (*reg_pmem)(struct msm_pmem_info_t *,
+ struct msm_device_t *);
+
+ long (*get_frame) (struct msm_frame_t *,
+ struct msm_device_t *);
+
+ long (*put_frame) (struct msm_frame_t *,
+ struct msm_device_t *msm);
+
+ long (*get_pict) (struct msm_ctrl_cmd_t *,
+ struct msm_device_t *msm);
+
+ unsigned int (*drv_poll) (struct file *, struct poll_table_struct *,
+ struct msm_device_t *msm);
+};
+
+unsigned int msm_poll(struct file *, struct poll_table_struct *);
+
+long msm_register(struct msm_driver *,
+ const char *);
+long msm_unregister(struct msm_driver *,
+ const char *);
+
+void msm_camvfe_init(void);
+int msm_camvfe_check(void *);
+void msm_camvfe_fn_init(struct msm_camvfe_fn_t *);
+int msm_camera_drv_start(struct platform_device *);
+int msm_camera_drv_remove(struct platform_device *);
+
+enum msm_camio_clk_type {
+ CAMIO_VFE_MDC_CLK,
+ CAMIO_MDC_CLK,
+ CAMIO_VFE_CLK,
+ CAMIO_VFE_AXI_CLK,
+
+ CAMIO_MAX_CLK
+};
+
+enum msm_camio_clk_src_type {
+ MSM_CAMIO_CLK_SRC_INTERNAL,
+ MSM_CAMIO_CLK_SRC_EXTERNAL,
+ MSM_CAMIO_CLK_SRC_MAX
+};
+
+enum msm_s_test_mode_t {
+ S_TEST_OFF,
+ S_TEST_1,
+ S_TEST_2,
+ S_TEST_3
+};
+
+enum msm_s_resolution_t {
+ S_QTR_SIZE,
+ S_FULL_SIZE,
+ S_INVALID_SIZE
+};
+
+enum msm_s_reg_update_t {
+ /* Sensor egisters that need to be updated during initialization */
+ S_REG_INIT,
+ /* Sensor egisters that needs periodic I2C writes */
+ S_UPDATE_PERIODIC,
+ /* All the sensor Registers will be updated */
+ S_UPDATE_ALL,
+ /* Not valid update */
+ S_UPDATE_INVALID
+};
+
+enum msm_s_setting_t {
+ S_RES_PREVIEW,
+ S_RES_CAPTURE
+};
+
+int msm_camio_enable(struct platform_device *dev);
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clk);
+int msm_camio_clk_disable(enum msm_camio_clk_type clk);
+int msm_camio_clk_config(uint32_t freq);
+void msm_camio_clk_rate_set(int rate);
+void msm_camio_clk_axi_rate_set(int rate);
+
+void msm_camio_camif_pad_reg_reset(void);
+void msm_camio_camif_pad_reg_reset_2(void);
+
+void msm_camio_vfe_blk_reset(void);
+
+void msm_camio_clk_sel(enum msm_camio_clk_src_type);
+void msm_camio_disable(struct platform_device *);
+int msm_camio_probe_on(struct platform_device *);
+int msm_camio_probe_off(struct platform_device *);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/clk.h b/arch/arm/mach-msm/include/mach/clk.h
new file mode 100644
index 000000000000..ac70550cb41c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clk.h
@@ -0,0 +1,53 @@
+/* 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 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.
+ *
+ */
+#ifndef __MACH_CLK_H
+#define __MACH_CLK_H
+
+/* Magic rate value for use with PM QOS to request the board's maximum
+ * supported AXI rate. PM QOS will only pass positive s32 rate values
+ * through to the clock driver, so INT_MAX is used.
+ */
+#define MSM_AXI_MAX_FREQ LONG_MAX
+
+enum clk_reset_action {
+ CLK_RESET_DEASSERT = 0,
+ CLK_RESET_ASSERT = 1
+};
+
+struct clk;
+
+/* Rate is minimum clock rate in Hz */
+int clk_set_min_rate(struct clk *clk, unsigned long rate);
+
+/* Rate is maximum clock rate in Hz */
+int clk_set_max_rate(struct clk *clk, unsigned long rate);
+
+/* Assert/Deassert reset to a hardware block associated with a clock */
+int clk_reset(struct clk *clk, enum clk_reset_action action);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/dal.h b/arch/arm/mach-msm/include/mach/dal.h
new file mode 100644
index 000000000000..a864f1469063
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dal.h
@@ -0,0 +1,155 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __DAL_H__
+#define __DAL_H__
+
+#include <linux/kernel.h>
+#include <mach/msm_smd.h>
+
+#define DALRPC_DEST_MODEM SMD_APPS_MODEM
+#define DALRPC_DEST_QDSP SMD_APPS_QDSP
+
+#define DALRPC_TIMEOUT_INFINITE -1
+
+enum {
+ DALDEVICE_ATTACH_IDX = 0,
+ DALDEVICE_DETACH_IDX,
+ DALDEVICE_INIT_IDX,
+ DALDEVICE_DEINIT_IDX,
+ DALDEVICE_OPEN_IDX,
+ DALDEVICE_CLOSE_IDX,
+ DALDEVICE_INFO_IDX,
+ DALDEVICE_POWEREVENT_IDX,
+ DALDEVICE_SYSREQUEST_IDX,
+ DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+struct daldevice_info_t {
+ uint32_t size;
+ uint32_t version;
+ char name[32];
+};
+
+int daldevice_attach(uint32_t device_id, char *port, int cpu,
+ void **handle_ptr);
+
+/* The caller must ensure there are no outstanding dalrpc calls on
+ * the client before (and while) calling daldevice_detach. */
+int daldevice_detach(void *handle);
+
+uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1);
+uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2);
+uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t *p_s2);
+uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2, uint32_t s3);
+uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
+ uint32_t s2, uint32_t *p_s3);
+uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen);
+uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
+ const void *ibuf, uint32_t ilen);
+uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen,
+ uint32_t *oalen);
+uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
+ uint32_t olen);
+uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
+ const void *ibuf, uint32_t ilen, void *obuf,
+ uint32_t olen, uint32_t *oalen);
+uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
+ void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
+ void *obuf, uint32_t olen, uint32_t *oalen);
+uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+ void *obuf, uint32_t olen);
+uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, void *obuf1, uint32_t olen1,
+ void *obuf2, uint32_t olen2, uint32_t *oalen2);
+uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
+ uint32_t ilen, const void *ibuf2, uint32_t ilen2,
+ void *obuf, uint32_t olen, uint32_t *oalen,
+ void *obuf2, uint32_t olen2);
+
+static inline uint32_t daldevice_info(void *handle,
+ struct daldevice_info_t *info,
+ uint32_t info_size)
+{
+ return dalrpc_fcn_9(DALDEVICE_INFO_IDX, handle, info, info_size);
+}
+
+static inline uint32_t daldevice_sysrequest(void *handle, uint32_t req_id,
+ const void *src_ptr,
+ uint32_t src_len, void *dest_ptr,
+ uint32_t dest_len,
+ uint32_t *dest_alen)
+{
+ return dalrpc_fcn_10(DALDEVICE_SYSREQUEST_IDX, handle, req_id,
+ src_ptr, src_len, dest_ptr, dest_len, dest_alen);
+}
+
+static inline uint32_t daldevice_init(void *handle)
+{
+ return dalrpc_fcn_0(DALDEVICE_INIT_IDX, handle, 0);
+}
+
+static inline uint32_t daldevice_deinit(void *handle)
+{
+ return dalrpc_fcn_0(DALDEVICE_DEINIT_IDX, handle, 0);
+}
+
+static inline uint32_t daldevice_open(void *handle, uint32_t mode)
+{
+ return dalrpc_fcn_0(DALDEVICE_OPEN_IDX, handle, mode);
+}
+
+static inline uint32_t daldevice_close(void *handle)
+{
+ return dalrpc_fcn_0(DALDEVICE_CLOSE_IDX, handle, 0);
+}
+
+void *dalrpc_alloc_event(void *handle);
+void *dalrpc_alloc_cb(void *handle,
+ void (*fn)(void *, uint32_t, void *, uint32_t),
+ void *context);
+void dalrpc_dealloc_event(void *handle,
+ void *ev_h);
+void dalrpc_dealloc_cb(void *handle,
+ void *cb_h);
+
+#define dalrpc_event_wait(ev_h, timeout) \
+ dalrpc_event_wait_multiple(1, &ev_h, timeout)
+
+int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout);
+
+#endif /* __DAL_H__ */
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 5ab5bdffab07..7a2fc563333b 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -1,6 +1,7 @@
/* linux/include/asm-arm/arch-msm/dma.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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
@@ -41,46 +42,55 @@ int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2))
#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2))
-/* only security domain 3 is available to the ARM11
- * SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM
- */
+#if defined(CONFIG_ARCH_MSM7X30)
+#define DMOV_SD_AARM DMOV_SD2
+#else
+#define DMOV_SD_AARM DMOV_SD3
+#endif
-#define DMOV_CMD_PTR(ch) DMOV_SD3(0x000, ch)
+#define DMOV_CMD_PTR(ch) DMOV_SD_AARM(0x000, ch)
#define DMOV_CMD_LIST (0 << 29) /* does not work */
#define DMOV_CMD_PTR_LIST (1 << 29) /* works */
#define DMOV_CMD_INPUT_CFG (2 << 29) /* untested */
#define DMOV_CMD_OUTPUT_CFG (3 << 29) /* untested */
#define DMOV_CMD_ADDR(addr) ((addr) >> 3)
-#define DMOV_RSLT(ch) DMOV_SD3(0x040, ch)
+#define DMOV_RSLT(ch) DMOV_SD_AARM(0x040, ch)
#define DMOV_RSLT_VALID (1 << 31) /* 0 == host has empties result fifo */
#define DMOV_RSLT_ERROR (1 << 3)
#define DMOV_RSLT_FLUSH (1 << 2)
#define DMOV_RSLT_DONE (1 << 1) /* top pointer done */
#define DMOV_RSLT_USER (1 << 0) /* command with FR force result */
-#define DMOV_FLUSH0(ch) DMOV_SD3(0x080, ch)
-#define DMOV_FLUSH1(ch) DMOV_SD3(0x0C0, ch)
-#define DMOV_FLUSH2(ch) DMOV_SD3(0x100, ch)
-#define DMOV_FLUSH3(ch) DMOV_SD3(0x140, ch)
-#define DMOV_FLUSH4(ch) DMOV_SD3(0x180, ch)
-#define DMOV_FLUSH5(ch) DMOV_SD3(0x1C0, ch)
+#define DMOV_FLUSH0(ch) DMOV_SD_AARM(0x080, ch)
+#define DMOV_FLUSH1(ch) DMOV_SD_AARM(0x0C0, ch)
+#define DMOV_FLUSH2(ch) DMOV_SD_AARM(0x100, ch)
+#define DMOV_FLUSH3(ch) DMOV_SD_AARM(0x140, ch)
+#define DMOV_FLUSH4(ch) DMOV_SD_AARM(0x180, ch)
+#define DMOV_FLUSH5(ch) DMOV_SD_AARM(0x1C0, ch)
-#define DMOV_STATUS(ch) DMOV_SD3(0x200, ch)
+#define DMOV_STATUS(ch) DMOV_SD_AARM(0x200, ch)
#define DMOV_STATUS_RSLT_COUNT(n) (((n) >> 29))
#define DMOV_STATUS_CMD_COUNT(n) (((n) >> 27) & 3)
#define DMOV_STATUS_RSLT_VALID (1 << 1)
#define DMOV_STATUS_CMD_PTR_RDY (1 << 0)
+#define DMOV_ISR DMOV_SD_AARM(0x380, 0)
-#define DMOV_ISR DMOV_SD3(0x380, 0)
-
-#define DMOV_CONFIG(ch) DMOV_SD3(0x300, ch)
+#define DMOV_CONFIG(ch) DMOV_SD_AARM(0x300, ch)
#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2)
#define DMOV_CONFIG_FORCE_FLUSH_RSLT (1 << 1)
#define DMOV_CONFIG_IRQ_EN (1 << 0)
/* channel assignments */
+#define DMOV_GP_CHAN 4
+
+#define DMOV_CE_IN_CHAN 5
+#define DMOV_CE_IN_CRCI 1
+
+#define DMOV_CE_OUT_CHAN 6
+#define DMOV_CE_OUT_CRCI 2
+
#define DMOV_NAND_CHAN 7
#define DMOV_NAND_CRCI_CMD 5
#define DMOV_NAND_CRCI_DATA 4
diff --git a/arch/arm/mach-msm/include/mach/dma_test.h b/arch/arm/mach-msm/include/mach/dma_test.h
new file mode 100644
index 000000000000..7f7dfe38a350
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/dma_test.h
@@ -0,0 +1,67 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __MSM_DMA_TEST__
+#define __MSM_DMA_TEST__
+
+#include <linux/ioctl.h>
+
+#define MSM_DMA_IOC_MAGIC 0x83
+
+/* The testing driver can manage a series of buffers. These are
+ * allocated and freed using these calls. */
+struct msm_dma_alloc_req {
+ int size; /* Size of this request, in bytes. */
+ int bufnum; /* OUT: Number of buffer allocated. */
+};
+#define MSM_DMA_IOALLOC _IOWR(MSM_DMA_IOC_MAGIC, 2, struct msm_dma_alloc_req)
+
+/* Free the specified buffer. */
+#define MSM_DMA_IOFREE _IOW(MSM_DMA_IOC_MAGIC, 3, int)
+
+/* Free all used buffers. */
+#define MSM_DMA_IOFREEALL _IO(MSM_DMA_IOC_MAGIC, 7)
+
+/* Read/write data into kernel buffer. */
+struct msm_dma_bufxfer {
+ void *data;
+ int size;
+ int bufnum;
+};
+#define MSM_DMA_IOWBUF _IOW(MSM_DMA_IOC_MAGIC, 4, struct msm_dma_bufxfer)
+#define MSM_DMA_IORBUF _IOW(MSM_DMA_IOC_MAGIC, 5, struct msm_dma_bufxfer)
+
+/* Use the data mover to copy from one buffer to another. */
+struct msm_dma_scopy {
+ int srcbuf;
+ int destbuf;
+ int size;
+};
+#define MSM_DMA_IOSCOPY _IOW(MSM_DMA_IOC_MAGIC, 6, struct msm_dma_scopy)
+
+#endif /* __MSM_DMA_TEST__ */
diff --git a/arch/arm/mach-msm/include/mach/fiq.h b/arch/arm/mach-msm/include/mach/fiq.h
new file mode 100644
index 000000000000..29a3ba1f33f3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/fiq.h
@@ -0,0 +1,33 @@
+/* linux/include/asm-arm/arch-msm/irqs.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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 __ASM_ARCH_MSM_FIQ_H
+#define __ASM_ARCH_MSM_FIQ_H
+
+/* cause an interrupt to be an FIQ instead of a regular IRQ */
+void msm_fiq_select(int number);
+void msm_fiq_unselect(int number);
+
+/* enable/disable an interrupt that is an FIQ (not safe from FIQ context) */
+void msm_fiq_enable(int number);
+void msm_fiq_disable(int number);
+
+/* install an FIQ handler */
+int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data);
+
+/* cause an edge triggered interrupt to fire (safe from FIQ context */
+void msm_trigger_irq(int number);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
new file mode 100644
index 000000000000..713afb930d2d
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -0,0 +1,167 @@
+/* linux/include/asm-arm/arch-msm/gpio.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Mike Lockwood <lockwood@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 __ASM_ARCH_MSM_GPIO_H
+#define __ASM_ARCH_MSM_GPIO_H
+
+#include <linux/interrupt.h>
+
+/**
+ * struct msm_gpio - GPIO pin description
+ * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
+ * @label - textual label
+ *
+ * Usually, GPIO's are operated by sets.
+ * This struct accumulate all GPIO information in single source
+ * and facilitete group operations provided by msm_gpios_xxx()
+ */
+struct msm_gpio {
+ u32 gpio_cfg;
+ const char *label;
+};
+
+/**
+ * msm_gpios_request_enable() - request and enable set of GPIOs
+ *
+ * Request and configure set of GPIO's
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+int msm_gpios_request_enable(const struct msm_gpio *table, int size);
+/**
+ * msm_gpios_disable_free() - disable and free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+void msm_gpios_disable_free(const struct msm_gpio *table, int size);
+/**
+ * msm_gpios_request() - request set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+int msm_gpios_request(const struct msm_gpio *table, int size);
+/**
+ * msm_gpios_free() - free set of GPIOs
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+void msm_gpios_free(const struct msm_gpio *table, int size);
+/**
+ * msm_gpios_enable() - enable set of GPIOs
+ * In case of error, all operations rolled back.
+ * Return error code.
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+int msm_gpios_enable(const struct msm_gpio *table, int size);
+/**
+ * msm_gpios_disable() - disable set of GPIOs
+ *
+ * @table: GPIO table
+ * @size: number of entries in @table
+ */
+void msm_gpios_disable(const struct msm_gpio *table, int size);
+
+int gpio_request(unsigned gpio, const char *label);
+void gpio_free(unsigned gpio);
+int gpio_direction_input(unsigned gpio);
+int gpio_direction_output(unsigned gpio, int value);
+int gpio_get_value(unsigned gpio);
+void gpio_set_value(unsigned gpio, int value);
+int gpio_to_irq(unsigned gpio);
+
+#include <asm-generic/gpio.h>
+
+/* extended gpio api */
+
+#define GPIOF_IRQF_MASK 0x0000ffff /* use to specify edge detection without */
+#define GPIOF_IRQF_TRIGGER_NONE 0x00010000 /* IRQF_TRIGGER_NONE is 0 which also means "as already configured" */
+#define GPIOF_INPUT 0x00020000
+#define GPIOF_DRIVE_OUTPUT 0x00040000
+#define GPIOF_OUTPUT_LOW 0x00080000
+#define GPIOF_OUTPUT_HIGH 0x00100000
+
+#define GPIOIRQF_SHARED 0x00000001 /* the irq line is shared with other inputs */
+
+extern int gpio_configure(unsigned int gpio, unsigned long flags);
+extern int gpio_read_detect_status(unsigned int gpio);
+extern int gpio_clear_detect_status(unsigned int gpio);
+
+/* GPIO TLMM (Top Level Multiplexing) Definitions */
+
+/* GPIO TLMM: Function -- GPIO specific */
+
+/* GPIO TLMM: Direction */
+enum {
+ GPIO_INPUT,
+ GPIO_OUTPUT,
+};
+
+/* GPIO TLMM: Pullup/Pulldown */
+enum {
+ GPIO_NO_PULL,
+ GPIO_PULL_DOWN,
+ GPIO_KEEPER,
+ GPIO_PULL_UP,
+};
+
+/* GPIO TLMM: Drive Strength */
+enum {
+ GPIO_2MA,
+ GPIO_4MA,
+ GPIO_6MA,
+ GPIO_8MA,
+ GPIO_10MA,
+ GPIO_12MA,
+ GPIO_14MA,
+ GPIO_16MA,
+};
+
+enum {
+ GPIO_ENABLE,
+ GPIO_DISABLE,
+};
+
+#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
+ ((((gpio) & 0x3FF) << 4) | \
+ ((func) & 0xf) | \
+ (((dir) & 0x1) << 14) | \
+ (((pull) & 0x3) << 15) | \
+ (((drvstr) & 0xF) << 17))
+
+/**
+ * extract GPIO pin from bit-field used for gpio_tlmm_config
+ */
+#define GPIO_PIN(gpio_cfg) (((gpio_cfg) >> 4) & 0x3ff)
+#define GPIO_FUNC(gpio_cfg) (((gpio_cfg) >> 0) & 0xf)
+#define GPIO_DIR(gpio_cfg) (((gpio_cfg) >> 14) & 0x1)
+#define GPIO_PULL(gpio_cfg) (((gpio_cfg) >> 15) & 0x3)
+#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
+
+int gpio_tlmm_config(unsigned config, unsigned disable);
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/htc_headset.h b/arch/arm/mach-msm/include/mach/htc_headset.h
new file mode 100644
index 000000000000..2f4c18db2625
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_headset.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 HTC, Inc.
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * 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 __ASM_ARCH_HTC_HEADSET_H
+#define __ASM_ARCH_HTC_HEADSET_H
+
+struct h2w_platform_data {
+ char *power_name;
+ int cable_in1;
+ int cable_in2;
+ int h2w_clk;
+ int h2w_data;
+ int debug_uart;
+ void (*config_cpld)(int);
+ void (*init_cpld)(void);
+ void (*set_dat)(int);
+ void (*set_clk)(int);
+ void (*set_dat_dir)(int);
+ void (*set_clk_dir)(int);
+ int (*get_dat)(void);
+ int (*get_clk)(void);
+};
+
+#define BIT_HEADSET (1 << 0)
+#define BIT_HEADSET_NO_MIC (1 << 1)
+#define BIT_TTY (1 << 2)
+#define BIT_FM_HEADSET (1 << 3)
+#define BIT_FM_SPEAKER (1 << 4)
+
+enum {
+ H2W_NO_DEVICE = 0,
+ H2W_HTC_HEADSET = 1,
+/* H2W_TTY_DEVICE = 2,*/
+ NORMAL_HEARPHONE= 2,
+ H2W_DEVICE = 3,
+ H2W_USB_CRADLE = 4,
+ H2W_UART_DEBUG = 5,
+};
+
+enum {
+ H2W_GPIO = 0,
+ H2W_UART1 = 1,
+ H2W_UART3 = 2,
+ H2W_BT = 3
+};
+
+#define RESEND_DELAY (3) /* ms */
+#define MAX_ACK_RESEND_TIMES (6) /* follow spec */
+#define MAX_HOST_RESEND_TIMES (3) /* follow spec */
+#define MAX_HYGEIA_RESEND_TIMES (5)
+
+#define H2W_ASCR_DEVICE_INI (0x01)
+#define H2W_ASCR_ACT_EN (0x02)
+#define H2W_ASCR_PHONE_IN (0x04)
+#define H2W_ASCR_RESET (0x08)
+#define H2W_ASCR_AUDIO_IN (0x10)
+
+#define H2W_LED_OFF (0x0)
+#define H2W_LED_BKL (0x1)
+#define H2W_LED_MTL (0x2)
+
+typedef enum {
+ /* === system group 0x0000~0x00FF === */
+ /* (R) Accessory type register */
+ H2W_SYSTEM = 0x0000,
+ /* (R) Maximum group address */
+ H2W_MAX_GP_ADD = 0x0001,
+ /* (R/W) Accessory system control register0 */
+ H2W_ASCR0 = 0x0002,
+
+ /* === key group 0x0100~0x01FF === */
+ /* (R) Key group maximum sub address */
+ H2W_KEY_MAXADD = 0x0100,
+ /* (R) ASCII key press down flag */
+ H2W_ASCII_DOWN = 0x0101,
+ /* (R) ASCII key release up flag */
+ H2W_ASCII_UP = 0x0102,
+ /* (R) Function key status flag */
+ H2W_FNKEY_UPDOWN = 0x0103,
+ /* (R/W) Key device status */
+ H2W_KD_STATUS = 0x0104,
+
+ /* === led group 0x0200~0x02FF === */
+ /* (R) LED group maximum sub address */
+ H2W_LED_MAXADD = 0x0200,
+ /* (R/W) LED control register0 */
+ H2W_LEDCT0 = 0x0201,
+
+ /* === crdl group 0x0300~0x03FF === */
+ /* (R) Cardle group maximum sub address */
+ H2W_CRDL_MAXADD = 0x0300,
+ /* (R/W) Cardle group function control register0 */
+ H2W_CRDLCT0 = 0x0301,
+
+ /* === car kit group 0x0400~0x04FF === */
+ H2W_CARKIT_MAXADD = 0x0400,
+
+ /* === usb host group 0x0500~0x05FF === */
+ H2W_USBHOST_MAXADD = 0x0500,
+
+ /* === medical group 0x0600~0x06FF === */
+ H2W_MED_MAXADD = 0x0600,
+ H2W_MED_CONTROL = 0x0601,
+ H2W_MED_IN_DATA = 0x0602,
+} H2W_ADDR;
+
+
+typedef struct H2W_INFO {
+ /* system group */
+ unsigned char CLK_SP;
+ int SLEEP_PR;
+ unsigned char HW_REV;
+ int AUDIO_DEVICE;
+ unsigned char ACC_CLASS;
+ unsigned char MAX_GP_ADD;
+
+ /* key group */
+ int KEY_MAXADD;
+ int ASCII_DOWN;
+ int ASCII_UP;
+ int FNKEY_UPDOWN;
+ int KD_STATUS;
+
+ /* led group */
+ int LED_MAXADD;
+ int LEDCT0;
+
+ /* medical group */
+ int MED_MAXADD;
+ unsigned char AP_ID;
+ unsigned char AP_EN;
+ unsigned char DATA_EN;
+} H2W_INFO;
+
+typedef enum {
+ H2W_500KHz = 1,
+ H2W_250KHz = 2,
+ H2W_166KHz = 3,
+ H2W_125KHz = 4,
+ H2W_100KHz = 5,
+ H2W_83KHz = 6,
+ H2W_71KHz = 7,
+ H2W_62KHz = 8,
+ H2W_55KHz = 9,
+ H2W_50KHz = 10,
+} H2W_SPEED;
+
+typedef enum {
+ H2W_KEY_INVALID = -1,
+ H2W_KEY_PLAY = 0,
+ H2W_KEY_FORWARD = 1,
+ H2W_KEY_BACKWARD = 2,
+ H2W_KEY_VOLUP = 3,
+ H2W_KEY_VOLDOWN = 4,
+ H2W_KEY_PICKUP = 5,
+ H2W_KEY_HANGUP = 6,
+ H2W_KEY_MUTE = 7,
+ H2W_KEY_HOLD = 8,
+ H2W_NUM_KEYFUNC = 9,
+} KEYFUNC;
+#endif
diff --git a/arch/arm/mach-msm/include/mach/htc_pwrsink.h b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
new file mode 100644
index 000000000000..c7a91f1d906c
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/htc_pwrsink.h
@@ -0,0 +1,87 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation.
+ *
+ * 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 _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+#define _ARCH_ARM_MACH_MSM_HTC_PWRSINK_H_
+
+#include <linux/platform_device.h>
+#include <linux/earlysuspend.h>
+
+typedef enum {
+ PWRSINK_AUDIO_PCM = 0,
+ PWRSINK_AUDIO_MP3,
+ PWRSINK_AUDIO_AAC,
+
+ PWRSINK_AUDIO_LAST = PWRSINK_AUDIO_AAC,
+ PWRSINK_AUDIO_INVALID
+} pwrsink_audio_id_type;
+
+struct pwr_sink_audio {
+ unsigned volume;
+ unsigned percent;
+};
+
+typedef enum {
+ PWRSINK_SYSTEM_LOAD = 0,
+ PWRSINK_AUDIO,
+ PWRSINK_BACKLIGHT,
+ PWRSINK_LED_BUTTON,
+ PWRSINK_LED_KEYBOARD,
+ PWRSINK_GP_CLK,
+ PWRSINK_BLUETOOTH,
+ PWRSINK_CAMERA,
+ PWRSINK_SDCARD,
+ PWRSINK_VIDEO,
+ PWRSINK_WIFI,
+
+ PWRSINK_LAST = PWRSINK_WIFI,
+ PWRSINK_INVALID
+} pwrsink_id_type;
+
+struct pwr_sink {
+ pwrsink_id_type id;
+ unsigned ua_max;
+ unsigned percent_util;
+};
+
+struct pwr_sink_platform_data {
+ unsigned num_sinks;
+ struct pwr_sink *sinks;
+ int (*suspend_late)(struct platform_device *, pm_message_t state);
+ int (*resume_early)(struct platform_device *);
+ void (*suspend_early)(struct early_suspend *);
+ void (*resume_late)(struct early_suspend *);
+};
+
+#ifndef CONFIG_HTC_PWRSINK
+static inline int htc_pwrsink_set(pwrsink_id_type id, unsigned percent)
+{
+ return 0;
+}
+static inline int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+ unsigned percent_utilized) { return 0; }
+static inline int htc_pwrsink_audio_volume_set(
+ pwrsink_audio_id_type id, unsigned volume) { return 0; }
+static inline int htc_pwrsink_audio_path_set(unsigned path) { return 0; }
+#else
+extern int htc_pwrsink_set(pwrsink_id_type id, unsigned percent);
+extern int htc_pwrsink_audio_set(pwrsink_audio_id_type id,
+ unsigned percent_utilized);
+extern int htc_pwrsink_audio_volume_set(pwrsink_audio_id_type id,
+ unsigned volume);
+extern int htc_pwrsink_audio_path_set(unsigned path);
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/internal_power_rail.h b/arch/arm/mach-msm/include/mach/internal_power_rail.h
new file mode 100644
index 000000000000..cd7ca765bde6
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/internal_power_rail.h
@@ -0,0 +1,46 @@
+/* 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 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.
+ */
+
+#ifndef _INTERNAL_POWER_RAIL_H
+#define _INTERNAL_POWER_RAIL_H
+
+/* Clock power rail IDs */
+#define PWR_RAIL_GRP_CLK 8
+#define PWR_RAIL_VDC_CLK 39
+#define PWR_RAIL_VFE_CLK 41
+#define PWR_RAIL_MFC_CLK 68
+
+enum rail_ctl_mode {
+ PWR_RAIL_CTL_AUTO = 0,
+ PWR_RAIL_CTL_MANUAL,
+};
+
+int internal_pwr_rail_ctl(unsigned rail_id, bool enable);
+int internal_pwr_rail_mode(unsigned rail_id, enum rail_ctl_mode mode);
+
+#endif /* _INTERNAL_POWER_RAIL_H */
+
diff --git a/arch/arm/mach-msm/include/mach/io.h b/arch/arm/mach-msm/include/mach/io.h
index aab964591db4..bdac617f4204 100644
--- a/arch/arm/mach-msm/include/mach/io.h
+++ b/arch/arm/mach-msm/include/mach/io.h
@@ -23,7 +23,7 @@
void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype);
-#define __io(a) __typesafe_io(a)
+#define __io(a) __typesafe_io(a)
#define __mem_pci(a) (a)
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-7x30.h b/arch/arm/mach-msm/include/mach/irqs-7x30.h
new file mode 100644
index 000000000000..cd9b58572be3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-7x30.h
@@ -0,0 +1,158 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_7X30_H
+#define __ASM_ARCH_MSM_IRQS_7X30_H
+
+/* MSM ACPU Interrupt Numbers */
+
+#define INT_DEBUG_TIMER_EXP 0
+#define INT_GPT0_TIMER_EXP 1
+#define INT_GPT1_TIMER_EXP 2
+#define INT_WDT0_ACCSCSSBARK 3
+#define INT_WDT1_ACCSCSSBARK 4
+#define INT_AVS_SVIC 5
+#define INT_AVS_SVIC_SW_DONE 6
+#define INT_SC_DBG_RX_FULL 7
+#define INT_SC_DBG_TX_EMPTY 8
+#define INT_SC_PERF_MON 9
+#define INT_AVS_REQ_DOWN 10
+#define INT_AVS_REQ_UP 11
+#define INT_SC_ACG 12
+/* SCSS_VICFIQSTS1[13:15] are RESERVED */
+#define INT_L2_SVICCPUIRPTREQ 16
+#define INT_L2_SVICDMANSIRPTREQ 17
+#define INT_L2_SVICDMASIRPTREQ 18
+#define INT_L2_SVICSLVIRPTREQ 19
+#define INT_AD5A_MPROC_APPS_0 20
+#define INT_AD5A_MPROC_APPS_1 21
+#define INT_A9_M2A_0 22
+#define INT_A9_M2A_1 23
+#define INT_A9_M2A_2 24
+#define INT_A9_M2A_3 25
+#define INT_A9_M2A_4 26
+#define INT_A9_M2A_5 27
+#define INT_A9_M2A_6 28
+#define INT_A9_M2A_7 29
+#define INT_A9_M2A_8 30
+#define INT_A9_M2A_9 31
+
+#define INT_AXI_EBI1_SC (32 + 0)
+#define INT_IMEM_ERR (32 + 1)
+#define INT_AXI_EBI0_SC (32 + 2)
+#define INT_PBUS_SC_IRQC (32 + 3)
+#define INT_PERPH_BUS_BPM (32 + 4)
+#define INT_CC_TEMP_SENSE (32 + 5)
+#define INT_UXMC_EBI0 (32 + 6)
+#define INT_UXMC_EBI1 (32 + 7)
+#define INT_EBI2_OP_DONE (32 + 8)
+#define INT_EBI2_WR_ER_DONE (32 + 9)
+#define INT_TCSR_SPSS_CE (32 + 10)
+#define INT_EMDH (32 + 11)
+#define INT_PMDH (32 + 12)
+#define INT_MDC (32 + 13)
+#define INT_MIDI_TO_SUPSS (32 + 14)
+#define INT_LPA_2 (32 + 15)
+#define INT_GPIO_GROUP1_SECURE (32 + 16)
+#define INT_GPIO_GROUP2_SECURE (32 + 17)
+#define INT_GPIO_GROUP1 (32 + 18)
+#define INT_GPIO_GROUP2 (32 + 19)
+#define INT_MPRPH_SOFTRESET (32 + 20)
+#define INT_PWB_I2C (32 + 21)
+#define INT_PWB_I2C_2 (32 + 22)
+#define INT_TSSC_SAMPLE (32 + 23)
+#define INT_TSSC_PENUP (32 + 24)
+#define INT_TCHSCRN_SSBI (32 + 25)
+#define INT_FM_RDS (32 + 26)
+#define INT_KEYSENSE (32 + 27)
+#define INT_USB_OTG_HS (32 + 28)
+#define INT_USB_OTG_HS2 (32 + 29)
+#define INT_USB_OTG_HS3 (32 + 30)
+#define INT_RESERVED_BIT31 (32 + 31)
+
+#define INT_SPI_OUTPUT (64 + 0)
+#define INT_SPI_INPUT (64 + 1)
+#define INT_SPI_ERROR (64 + 2)
+#define INT_UART1 (64 + 3)
+#define INT_UART1_RX (64 + 4)
+#define INT_UART2 (64 + 5)
+#define INT_UART2_RX (64 + 6)
+#define INT_UART3 (64 + 7)
+#define INT_UART3_RX (64 + 8)
+#define INT_UART1DM_IRQ (64 + 9)
+#define INT_UART1DM_RX (64 + 10)
+#define INT_UART2DM_IRQ (64 + 11)
+#define INT_UART2DM_RX (64 + 12)
+#define INT_TSIF (64 + 13)
+#define INT_ADM_SC1 (64 + 14)
+#define INT_ADM_SC2 (64 + 15)
+#define INT_MDP (64 + 16)
+#define INT_VPE (64 + 17)
+#define INT_GRP_2D (64 + 18)
+#define INT_GRP_3D (64 + 19)
+#define INT_ROTATOR (64 + 20)
+#define INT_MFC720 (64 + 21)
+#define INT_JPEG (64 + 22)
+#define INT_VFE (64 + 23)
+#define INT_TV_ENC (64 + 24)
+#define INT_PMIC_SSBI (64 + 25)
+#define INT_MPM_1 (64 + 26)
+#define INT_TCSR_SPSS_SAMPLE (64 + 27)
+#define INT_TCSR_SPSS_PENUP (64 + 28)
+#define INT_MPM_2 (64 + 29)
+#define INT_SDC1_0 (64 + 30)
+#define INT_SDC1_1 (64 + 31)
+
+#define INT_SDC3_0 (96 + 0)
+#define INT_SDC3_1 (96 + 1)
+#define INT_SDC2_0 (96 + 2)
+#define INT_SDC2_1 (96 + 3)
+#define INT_SDC4_0 (96 + 4)
+#define INT_SDC4_1 (96 + 5)
+/* SCSS_VICFIQSTS3[6:31] are RESERVED */
+
+/* Retrofit universal macro names */
+#define INT_ADM_AARM INT_ADM_SC2
+#define INT_USB_HS INT_USB_OTG_HS
+#define INT_USB_OTG INT_USB_OTG_HS
+#define INT_TCHSCRN1 INT_TSSC_PENUP
+#define INT_TCHSCRN2 INT_TSSC_SAMPLE
+#define INT_GP_TIMER_EXP INT_GPT0_TIMER_EXP
+#define INT_ADSP_A11 INT_AD5A_MPROC_APPS_0
+#define INT_ADSP_A9_A11 INT_AD5A_MPROC_APPS_1
+#define INT_MDDI_EXT INT_EMDH
+#define INT_MDDI_PRI INT_PMDH
+#define INT_MDDI_CLIENT INT_MDC
+#define INT_NAND_WR_ER_DONE INT_EBI2_WR_ER_DONE
+#define INT_NAND_OP_DONE INT_EBI2_OP_DONE
+
+#define NR_GPIO_IRQS 181
+#define NR_MSM_IRQS 128
+#define NR_BOARD_IRQS 128
+
+#endif /* __ASM_ARCH_MSM_IRQS_7X30_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs-7xxx.h b/arch/arm/mach-msm/include/mach/irqs-7xxx.h
new file mode 100644
index 000000000000..1b3c73d38073
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-7xxx.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_7XXX_H
+#define __ASM_ARCH_MSM_IRQS_7XXX_H
+
+/* MSM ARM11 Interrupt Numbers */
+/* See 80-VE113-1 A, pp219-221 */
+
+#define INT_A9_M2A_0 0
+#define INT_A9_M2A_1 1
+#define INT_A9_M2A_2 2
+#define INT_A9_M2A_3 3
+#define INT_A9_M2A_4 4
+#define INT_A9_M2A_5 5
+#define INT_A9_M2A_6 6
+#define INT_GP_TIMER_EXP 7
+#define INT_DEBUG_TIMER_EXP 8
+#define INT_UART1 9
+#define INT_UART2 10
+#define INT_UART3 11
+#define INT_UART1_RX 12
+#define INT_UART2_RX 13
+#define INT_UART3_RX 14
+#define INT_USB_OTG 15
+#define INT_MDDI_PRI 16
+#define INT_MDDI_EXT 17
+#define INT_MDDI_CLIENT 18
+#define INT_MDP 19
+#define INT_GRAPHICS 20
+#define INT_ADM_AARM 21
+#define INT_ADSP_A11 22
+#define INT_ADSP_A9_A11 23
+#define INT_SDC1_0 24
+#define INT_SDC1_1 25
+#define INT_SDC2_0 26
+#define INT_SDC2_1 27
+#define INT_KEYSENSE 28
+#define INT_TCHSCRN_SSBI 29
+#define INT_TCHSCRN1 30
+#define INT_TCHSCRN2 31
+
+#define INT_GPIO_GROUP1 (32 + 0)
+#define INT_GPIO_GROUP2 (32 + 1)
+#define INT_PWB_I2C (32 + 2)
+#define INT_SOFTRESET (32 + 3)
+#define INT_NAND_WR_ER_DONE (32 + 4)
+#define INT_NAND_OP_DONE (32 + 5)
+#define INT_PBUS_ARM11 (32 + 6)
+#define INT_AXI_MPU_SMI (32 + 7)
+#define INT_AXI_MPU_EBI1 (32 + 8)
+#define INT_AD_HSSD (32 + 9)
+#define INT_ARM11_PMU (32 + 10)
+#define INT_ARM11_DMA (32 + 11)
+#define INT_TSIF_IRQ (32 + 12)
+#define INT_UART1DM_IRQ (32 + 13)
+#define INT_UART1DM_RX (32 + 14)
+#define INT_USB_HS (32 + 15)
+#define INT_SDC3_0 (32 + 16)
+#define INT_SDC3_1 (32 + 17)
+#define INT_SDC4_0 (32 + 18)
+#define INT_SDC4_1 (32 + 19)
+#define INT_UART2DM_IRQ (32 + 20)
+#define INT_UART2DM_RX (32 + 21)
+
+/* 22-31 are reserved */
+
+/* 7x00A uses 122, but 7x25 has up to 132. */
+#define NR_GPIO_IRQS 133
+#define NR_MSM_IRQS 64
+#define NR_BOARD_IRQS 64
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8xxx.h b/arch/arm/mach-msm/include/mach/irqs-8xxx.h
new file mode 100644
index 000000000000..3ce01e9d01fa
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8xxx.h
@@ -0,0 +1,104 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8XXX_H
+#define __ASM_ARCH_MSM_IRQS_8XXX_H
+
+/* MSM ACPU Interrupt Numbers */
+
+#define INT_A9_M2A_0 0
+#define INT_A9_M2A_1 1
+#define INT_A9_M2A_2 2
+#define INT_A9_M2A_3 3
+#define INT_A9_M2A_4 4
+#define INT_A9_M2A_5 5
+#define INT_A9_M2A_6 6
+#define INT_GP_TIMER_EXP 7
+#define INT_DEBUG_TIMER_EXP 8
+#define INT_SIRC_0 9
+#define INT_SDC3_0 10
+#define INT_SDC3_1 11
+#define INT_SDC4_0 12
+#define INT_SDC4_1 13
+#define INT_AD6_EXT_VFR 14
+#define INT_USB_OTG 15
+#define INT_MDDI_PRI 16
+#define INT_MDDI_EXT 17
+#define INT_MDDI_CLIENT 18
+#define INT_MDP 19
+#define INT_GRAPHICS 20
+#define INT_ADM_AARM 21
+#define INT_ADSP_A11 22
+#define INT_ADSP_A9_A11 23
+#define INT_SDC1_0 24
+#define INT_SDC1_1 25
+#define INT_SDC2_0 26
+#define INT_SDC2_1 27
+#define INT_KEYSENSE 28
+#define INT_TCHSCRN_SSBI 29
+#define INT_TCHSCRN1 30
+#define INT_TCHSCRN2 31
+
+#define INT_TCSR_MPRPH_SC1 (32 + 0)
+#define INT_USB_FS2 (32 + 1)
+#define INT_PWB_I2C (32 + 2)
+#define INT_SOFTRESET (32 + 3)
+#define INT_NAND_WR_ER_DONE (32 + 4)
+#define INT_NAND_OP_DONE (32 + 5)
+#define INT_TCSR_MPRPH_SC2 (32 + 6)
+#define INT_OP_PEN (32 + 7)
+#define INT_AD_HSSD (32 + 8)
+#define INT_ARM11_PM (32 + 9)
+#define INT_SDMA_NON_SECURE (32 + 10)
+#define INT_TSIF_IRQ (32 + 11)
+#define INT_UART1DM_IRQ (32 + 12)
+#define INT_UART1DM_RX (32 + 13)
+#define INT_SDMA_SECURE (32 + 14)
+#define INT_SI2S_SLAVE (32 + 15)
+#define INT_SC_I2CPU (32 + 16)
+#define INT_SC_DBG_RDTRFULL (32 + 17)
+#define INT_SC_DBG_WDTRFULL (32 + 18)
+#define INT_SCPLL_CTL_DONE (32 + 19)
+#define INT_UART2DM_IRQ (32 + 20)
+#define INT_UART2DM_RX (32 + 21)
+#define INT_VDC_MEC (32 + 22)
+#define INT_VDC_DB (32 + 23)
+#define INT_VDC_AXI (32 + 24)
+#define INT_VFE (32 + 25)
+#define INT_USB_HS (32 + 26)
+#define INT_AUDIO_OUT0 (32 + 27)
+#define INT_AUDIO_OUT1 (32 + 28)
+#define INT_CRYPTO (32 + 29)
+#define INT_AD6M_IDLE (32 + 30)
+#define INT_SIRC_1 (32 + 31)
+
+#define NR_GPIO_IRQS 165
+#define NR_MSM_IRQS 64
+#define NR_BOARD_IRQS 64
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index 9dd4cf8a2693..902910ad3b16 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -1,6 +1,6 @@
-/* arch/arm/mach-msm/include/mach/irqs.h
- *
+/*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -17,74 +17,21 @@
#ifndef __ASM_ARCH_MSM_IRQS_H
#define __ASM_ARCH_MSM_IRQS_H
-/* MSM ARM11 Interrupt Numbers */
-/* See 80-VE113-1 A, pp219-221 */
-
-#define INT_A9_M2A_0 0
-#define INT_A9_M2A_1 1
-#define INT_A9_M2A_2 2
-#define INT_A9_M2A_3 3
-#define INT_A9_M2A_4 4
-#define INT_A9_M2A_5 5
-#define INT_A9_M2A_6 6
-#define INT_GP_TIMER_EXP 7
-#define INT_DEBUG_TIMER_EXP 8
-#define INT_UART1 9
-#define INT_UART2 10
-#define INT_UART3 11
-#define INT_UART1_RX 12
-#define INT_UART2_RX 13
-#define INT_UART3_RX 14
-#define INT_USB_OTG 15
-#define INT_MDDI_PRI 16
-#define INT_MDDI_EXT 17
-#define INT_MDDI_CLIENT 18
-#define INT_MDP 19
-#define INT_GRAPHICS 20
-#define INT_ADM_AARM 21
-#define INT_ADSP_A11 22
-#define INT_ADSP_A9_A11 23
-#define INT_SDC1_0 24
-#define INT_SDC1_1 25
-#define INT_SDC2_0 26
-#define INT_SDC2_1 27
-#define INT_KEYSENSE 28
-#define INT_TCHSCRN_SSBI 29
-#define INT_TCHSCRN1 30
-#define INT_TCHSCRN2 31
-
-#define INT_GPIO_GROUP1 (32 + 0)
-#define INT_GPIO_GROUP2 (32 + 1)
-#define INT_PWB_I2C (32 + 2)
-#define INT_SOFTRESET (32 + 3)
-#define INT_NAND_WR_ER_DONE (32 + 4)
-#define INT_NAND_OP_DONE (32 + 5)
-#define INT_PBUS_ARM11 (32 + 6)
-#define INT_AXI_MPU_SMI (32 + 7)
-#define INT_AXI_MPU_EBI1 (32 + 8)
-#define INT_AD_HSSD (32 + 9)
-#define INT_ARM11_PMU (32 + 10)
-#define INT_ARM11_DMA (32 + 11)
-#define INT_TSIF_IRQ (32 + 12)
-#define INT_UART1DM_IRQ (32 + 13)
-#define INT_UART1DM_RX (32 + 14)
-#define INT_USB_HS (32 + 15)
-#define INT_SDC3_0 (32 + 16)
-#define INT_SDC3_1 (32 + 17)
-#define INT_SDC4_0 (32 + 18)
-#define INT_SDC4_1 (32 + 19)
-#define INT_UART2DM_RX (32 + 20)
-#define INT_UART2DM_IRQ (32 + 21)
-
-/* 22-31 are reserved */
-
#define MSM_IRQ_BIT(irq) (1 << ((irq) & 31))
-#define NR_MSM_IRQS 64
-#define NR_GPIO_IRQS 122
-#define NR_BOARD_IRQS 64
-#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
+#if defined(CONFIG_ARCH_MSM7X30)
+#include "irqs-7x30.h"
+#elif defined(CONFIG_ARCH_QSD8X50)
+#include "irqs-8xxx.h"
+#include "sirc.h"
+#elif defined(CONFIG_ARCH_MSM_ARM11)
+#include "irqs-7xxx.h"
+#else
+#error "Unknown architecture specification"
+#endif
+#define NR_IRQS (NR_MSM_IRQS + NR_GPIO_IRQS + NR_BOARD_IRQS)
#define MSM_GPIO_TO_INT(n) (NR_MSM_IRQS + (n))
+#define MSM_INT_TO_REG(base, irq) (base + irq / 32)
#endif
diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h
index f4698baec976..dc278487c217 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/memory.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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
@@ -12,12 +13,38 @@
* GNU General Public License for more details.
*
*/
-
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
/* physical offset of RAM */
+#ifdef CONFIG_MSM_STACKED_MEMORY
+
+#ifdef CONFIG_ARCH_MSM_SCORPION
+#define PHYS_OFFSET UL(0x20000000)
+#else
#define PHYS_OFFSET UL(0x10000000)
+#endif
+
+#else /* !CONFIG_MSM_STACKED_MEMORY */
+
+#define PHYS_OFFSET UL(0x00200000)
+
+#endif
+
+#ifndef __ASSEMBLY__
+void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
+
+#ifdef CONFIG_ARCH_MSM_ARM11
+void write_to_strongly_ordered_memory(void);
+
+#include <asm/mach-types.h>
+
+#define arch_barrier_extra() do \
+ { if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \
+ write_to_strongly_ordered_memory(); \
+ } while (0)
+#endif
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/mmc.h b/arch/arm/mach-msm/include/mach/mmc.h
index 0ecf25426284..306de3d73fff 100644
--- a/arch/arm/mach-msm/include/mach/mmc.h
+++ b/arch/arm/mach-msm/include/mach/mmc.h
@@ -1,26 +1,16 @@
/*
- * arch/arm/include/asm/mach/mmc.h
+ * arch/arm/mach-msm/include/mach/mmc.h
*/
-#ifndef ASMARM_MACH_MMC_H
-#define ASMARM_MACH_MMC_H
+#ifndef ASM_ARCH_MACH_MMC_H
+#define ASM_ARCH_MACH_MMC_H
#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-
-struct embedded_sdio_data {
- struct sdio_cis cis;
- struct sdio_cccr cccr;
- struct sdio_embedded_func *funcs;
- int num_funcs;
-};
struct 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);
+ unsigned long irq_flags;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/mpp.h b/arch/arm/mach-msm/include/mach/mpp.h
new file mode 100644
index 000000000000..7af853bdca49
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/mpp.h
@@ -0,0 +1,73 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_MPP_H
+#define __ARCH_ARM_MACH_MSM_MPP_H
+
+struct mpp {
+ const char *name;
+ unsigned id;
+ int is_input;
+ int status;
+};
+
+/* Digital Logical Output Level */
+enum {
+ MPP_DLOGIC_LVL_MSME,
+ MPP_DLOGIC_LVL_MSMP,
+ MPP_DLOGIC_LVL_RUIM,
+ MPP_DLOGIC_LVL_MMC,
+ MPP_DLOGIC_LVL_VDD,
+};
+
+/* Digital Logical Output Control Value */
+enum {
+ MPP_DLOGIC_OUT_CTRL_LOW,
+ MPP_DLOGIC_OUT_CTRL_HIGH,
+ MPP_DLOGIC_OUT_CTRL_MPP, /* MPP Output = MPP Input */
+ MPP_DLOGIC_OUT_CTRL_NOT_MPP, /* MPP Output = Inverted MPP Input */
+};
+
+/* Digital Logical Input Value */
+enum {
+ MPP_DLOGIC_IN_DBUS_NONE,
+ MPP_DLOGIC_IN_DBUS_1,
+ MPP_DLOGIC_IN_DBUS_2,
+ MPP_DLOGIC_IN_DBUS_3,
+};
+
+#define MPP_CFG(level, control) ((((level) & 0x0FFFF) << 16) | \
+ ((control) & 0x0FFFFF))
+#define MPP_CFG_INPUT(level, dbus) ((((level) & 0x0FFFF) << 16) | \
+ ((control) & 0x0FFFFF))
+
+struct mpp *mpp_get(struct device *dev, const char *id);
+int mpp_config_digital_out(struct mpp *mpp, unsigned config);
+int mpp_config_digital_in(struct mpp *mpp, unsigned config);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_handset.h b/arch/arm/mach-msm/include/mach/msm_handset.h
new file mode 100644
index 000000000000..6947e03b8986
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_handset.h
@@ -0,0 +1,34 @@
+/* arch/arm/mach-msm/include/mach/msm_handset.h
+ *
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#ifndef _MSM_HANDSET_H
+#define _MSM_HANDSET_H
+
+#include <linux/input.h>
+
+#if defined(CONFIG_INPUT_MSM_HANDSET)
+struct input_dev *msm_get_handset_input_dev(void);
+#else
+struct input_dev *msm_get_handset_input_dev(void)
+{
+ return NULL;
+}
+#endif
+
+struct msm_handset {
+ struct input_dev *ip_dev;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_i2ckbd.h b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h
new file mode 100644
index 000000000000..2ca51f261cac
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_i2ckbd.h
@@ -0,0 +1,41 @@
+/* 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 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.
+ *
+ */
+
+#ifndef _MSM_I2CKBD_H_
+#define _MSM_I2CKBD_H_
+
+struct msm_i2ckbd_platform_data {
+ uint8_t hwrepeat;
+ uint8_t scanset1;
+ int gpioreset;
+ int gpioirq;
+ int (*gpio_setup) (void);
+ void (*gpio_shutdown)(void);
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 9dae1a98c77a..2f54547e1890 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/msm_iomap.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -44,44 +45,98 @@
#endif
#define MSM_VIC_BASE IOMEM(0xE0000000)
+#if defined(CONFIG_ARCH_QSD8X50)
+#define MSM_VIC_PHYS 0xAC000000
+#elif defined(CONFIG_ARCH_MSM7X30)
+#define MSM_VIC_PHYS 0xC0080000
+#else
#define MSM_VIC_PHYS 0xC0000000
+#endif
#define MSM_VIC_SIZE SZ_4K
#define MSM_CSR_BASE IOMEM(0xE0001000)
+#if defined(CONFIG_ARCH_QSD8X50)
+#define MSM_CSR_PHYS 0xAC100000
+#else
#define MSM_CSR_PHYS 0xC0100000
+#endif
#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 MSM_TMR_PHYS MSM_CSR_PHYS
+#define MSM_TMR_BASE MSM_CSR_BASE
+#define MSM_TMR_SIZE SZ_4K
#define MSM_DMOV_BASE IOMEM(0xE0002000)
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_DMOV_PHYS 0xAC400000
+#else
#define MSM_DMOV_PHYS 0xA9700000
+#endif
#define MSM_DMOV_SIZE SZ_4K
#define MSM_GPIO1_BASE IOMEM(0xE0003000)
+#if defined(CONFIG_ARCH_QSD8X50)
+#define MSM_GPIO1_PHYS 0xA9000000
+#elif defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GPIO1_PHYS 0xAC001000
+#else
#define MSM_GPIO1_PHYS 0xA9200000
+#endif
#define MSM_GPIO1_SIZE SZ_4K
#define MSM_GPIO2_BASE IOMEM(0xE0004000)
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GPIO2_PHYS 0xAC101000
+#elif defined(CONFIG_ARCH_QSD8X50)
+#define MSM_GPIO2_PHYS 0xA9100000
+#else
#define MSM_GPIO2_PHYS 0xA9300000
+#endif
#define MSM_GPIO2_SIZE SZ_4K
#define MSM_CLK_CTL_BASE IOMEM(0xE0005000)
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_CLK_CTL_PHYS 0xAB800000
+#else
#define MSM_CLK_CTL_PHYS 0xA8600000
+#endif
#define MSM_CLK_CTL_SIZE SZ_4K
+#define MSM_L2CC_BASE IOMEM(0xE0006000)
+#define MSM_L2CC_PHYS 0xC0400000
+#define MSM_L2CC_SIZE SZ_4K
+
+#define MSM_SIRC_BASE IOMEM(0xE1006000)
+#define MSM_SIRC_PHYS 0xAC200000
+#define MSM_SIRC_SIZE SZ_4K
+
+#define MSM_SCPLL_BASE IOMEM(0xE1007000)
+#define MSM_SCPLL_PHYS 0xA8800000
+#define MSM_SCPLL_SIZE SZ_4K
+
+#define MSM_ACC_BASE IOMEM(0xE0007000)
+#define MSM_ACC_PHYS 0xC0101000
+#define MSM_ACC_SIZE SZ_4K
+
+#define MSM_GCC_BASE IOMEM(0xE0008000)
+#define MSM_GCC_PHYS 0xC0182000
+#define MSM_GCC_SIZE SZ_4K
+
#define MSM_SHARED_RAM_BASE IOMEM(0xE0100000)
-#define MSM_SHARED_RAM_PHYS 0x01F00000
#define MSM_SHARED_RAM_SIZE SZ_1M
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_UART1_PHYS 0xACA00000
+#define MSM_UART2_PHYS 0xACB00000
+#define MSM_UART3_PHYS 0xACC00000
+#else
#define MSM_UART1_PHYS 0xA9A00000
-#define MSM_UART1_SIZE SZ_4K
-
#define MSM_UART2_PHYS 0xA9B00000
-#define MSM_UART2_SIZE SZ_4K
-
#define MSM_UART3_PHYS 0xA9C00000
+#endif
+#define MSM_UART1_SIZE SZ_4K
+#define MSM_UART2_SIZE SZ_4K
#define MSM_UART3_SIZE SZ_4K
#ifdef CONFIG_MSM_DEBUG_UART
@@ -96,38 +151,27 @@
#define MSM_DEBUG_UART_SIZE SZ_4K
#endif
-#define MSM_SDC1_PHYS 0xA0400000
-#define MSM_SDC1_SIZE SZ_4K
-
-#define MSM_SDC2_PHYS 0xA0500000
-#define MSM_SDC2_SIZE SZ_4K
-
-#define MSM_SDC3_PHYS 0xA0600000
-#define MSM_SDC3_SIZE SZ_4K
-
-#define MSM_SDC4_PHYS 0xA0700000
-#define MSM_SDC4_SIZE SZ_4K
-
#define MSM_I2C_PHYS 0xA9900000
#define MSM_I2C_SIZE SZ_4K
#define MSM_HSUSB_PHYS 0xA0800000
+#define MSM_HSUSB_BASE IOMEM(0xE0009000)
#define MSM_HSUSB_SIZE SZ_4K
-#define MSM_PMDH_PHYS 0xAA600000
-#define MSM_PMDH_SIZE SZ_4K
-
-#define MSM_EMDH_PHYS 0xAA700000
-#define MSM_EMDH_SIZE SZ_4K
-
-#define MSM_MDP_PHYS 0xAA200000
-#define MSM_MDP_SIZE 0x000F0000
-
+#define MSM_MDC_BASE IOMEM(0xE0200000)
#define MSM_MDC_PHYS 0xAA500000
#define MSM_MDC_SIZE SZ_1M
+#define MSM_AD5_BASE IOMEM(0xE0300000)
#define MSM_AD5_PHYS 0xAC000000
#define MSM_AD5_SIZE (SZ_1M*13)
+#define MSM_SSBI_BASE IOMEM(0xE1004000)
+#define MSM_SSBI_PHYS 0xA8100000
+#define MSM_SSBI_SIZE SZ_4K
+
+#define MSM_TSSC_BASE IOMEM(0xE1005000)
+#define MSM_TSSC_PHYS 0xAA300000
+#define MSM_TSSC_SIZE SZ_4K
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_otg.h b/arch/arm/mach-msm/include/mach/msm_otg.h
new file mode 100644
index 000000000000..6ab662921fee
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_otg.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2009, 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_OTG_H
+#define __ARCH_ARM_MACH_MSM_OTG_H
+
+/*
+ * The otg driver needs to interact with both device side and host side
+ * usb controllers. it decides which controller is active at a given
+ * moment, using the transceiver, ID signal.
+ */
+
+struct msm_otg_transceiver {
+ struct device *dev;
+ struct clk *clk;
+ struct clk *pclk;
+ int in_lpm;
+ struct msm_otg_ops *dcd_ops;
+ struct msm_otg_ops *hcd_ops;
+ int irq;
+ int flags;
+ int state;
+ int active;
+ void __iomem *regs; /* device memory/io */
+ struct work_struct work;
+ spinlock_t lock;
+
+ /* bind/unbind the host controller */
+ int (*set_host)(struct msm_otg_transceiver *otg,
+ struct msm_otg_ops *hcd_ops);
+
+ /* bind/unbind the peripheral controller */
+ int (*set_peripheral)(struct msm_otg_transceiver *otg,
+ struct msm_otg_ops *dcd_ops);
+ void (*set_suspend) (int on);
+
+};
+
+struct msm_otg_ops {
+ void (*status_change)(int);
+};
+
+/* for usb host and peripheral controller drivers */
+#ifdef CONFIG_USB_MSM_OTG
+
+extern struct msm_otg_transceiver *msm_otg_get_transceiver(void);
+extern void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv);
+
+#else
+
+static inline struct msm_otg_transceiver *msm_otg_get_transceiver(void)
+{
+ return NULL;
+}
+
+static inline void msm_otg_put_transceiver(struct msm_otg_transceiver *xceiv)
+{
+}
+
+#endif /*CONFIG_USB_MSM_OTG*/
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_rpcrouter.h b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
new file mode 100644
index 000000000000..d0c01fb53047
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_rpcrouter.h
@@ -0,0 +1,296 @@
+/** include/asm-arm/arch-msm/msm_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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 __ASM__ARCH_MSM_RPCROUTER_H
+#define __ASM__ARCH_MSM_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/ioctl.h>
+
+struct rpcrouter_ioctl_server_args {
+ uint32_t prog;
+ uint32_t vers;
+};
+
+#define RPC_ROUTER_VERSION_V1 0x00010000
+
+#define RPC_ROUTER_IOCTL_MAGIC (0xC1)
+
+#define RPC_ROUTER_IOCTL_GET_VERSION \
+ _IOR(RPC_ROUTER_IOCTL_MAGIC, 0, unsigned int)
+
+#define RPC_ROUTER_IOCTL_GET_MTU \
+ _IOR(RPC_ROUTER_IOCTL_MAGIC, 1, unsigned int)
+
+#define RPC_ROUTER_IOCTL_REGISTER_SERVER \
+ _IOWR(RPC_ROUTER_IOCTL_MAGIC, 2, unsigned int)
+
+#define RPC_ROUTER_IOCTL_UNREGISTER_SERVER \
+ _IOWR(RPC_ROUTER_IOCTL_MAGIC, 3, unsigned int)
+
+#define RPC_ROUTER_IOCTL_CLEAR_NETRESET \
+ _IOWR(RPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+
+/* RPC API version structure
+ * Version bit 31 : 1->hashkey versioning,
+ * 0->major-minor (backward compatible) versioning
+ * hashkey versioning:
+ * Version bits 31-0 hashkey
+ * major-minor (backward compatible) versioning
+ * Version bits 30-28 reserved (no match)
+ * Version bits 27-16 major (must match)
+ * Version bits 15-0 minor (greater or equal)
+ */
+#define RPC_VERSION_MODE_MASK 0x80000000
+#define RPC_VERSION_MAJOR_MASK 0x0fff0000
+#define RPC_VERSION_MINOR_MASK 0x0000ffff
+
+/* callback ID for NULL callback function is -1 */
+#define MSM_RPC_CLIENT_NULL_CB_ID 0xffffffff
+
+struct msm_rpc_endpoint;
+
+struct rpcsvr_platform_device
+{
+ struct platform_device base;
+ uint32_t prog;
+ uint32_t vers;
+};
+
+#define RPC_DATA_IN 0
+/*
+ * Structures for sending / receiving direct RPC requests
+ * XXX: Any cred/verif lengths > 0 not supported
+ */
+
+struct rpc_request_hdr
+{
+ uint32_t xid;
+ uint32_t type; /* 0 */
+ uint32_t rpc_vers; /* 2 */
+ uint32_t prog;
+ uint32_t vers;
+ uint32_t procedure;
+ uint32_t cred_flavor;
+ uint32_t cred_length;
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+};
+
+typedef struct
+{
+ uint32_t low;
+ uint32_t high;
+} rpc_reply_progmismatch_data;
+
+typedef struct
+{
+} rpc_denied_reply_hdr;
+
+typedef struct
+{
+ uint32_t verf_flavor;
+ uint32_t verf_length;
+ uint32_t accept_stat;
+#define RPC_ACCEPTSTAT_SUCCESS 0
+#define RPC_ACCEPTSTAT_PROG_UNAVAIL 1
+#define RPC_ACCEPTSTAT_PROG_MISMATCH 2
+#define RPC_ACCEPTSTAT_PROC_UNAVAIL 3
+#define RPC_ACCEPTSTAT_GARBAGE_ARGS 4
+#define RPC_ACCEPTSTAT_SYSTEM_ERR 5
+#define RPC_ACCEPTSTAT_PROG_LOCKED 6
+ /*
+ * Following data is dependant on accept_stat
+ * If ACCEPTSTAT == PROG_MISMATCH then there is a
+ * 'rpc_reply_progmismatch_data' structure following the header.
+ * Otherwise the data is procedure specific
+ */
+} rpc_accepted_reply_hdr;
+
+struct rpc_reply_hdr
+{
+ uint32_t xid;
+ uint32_t type;
+ uint32_t reply_stat;
+#define RPCMSG_REPLYSTAT_ACCEPTED 0
+#define RPCMSG_REPLYSTAT_DENIED 1
+ union {
+ rpc_accepted_reply_hdr acc_hdr;
+ rpc_denied_reply_hdr dny_hdr;
+ } data;
+};
+
+/* flags for msm_rpc_connect() */
+#define MSM_RPC_UNINTERRUPTIBLE 0x0001
+
+/* use IS_ERR() to check for failure */
+struct msm_rpc_endpoint *msm_rpc_open(void);
+/* Connect with the specified server version */
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags);
+/* Connect with a compatible server version */
+struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
+ uint32_t vers, unsigned flags);
+int msm_rpc_get_compatible_server(uint32_t prog, uint32_t vers,
+ uint32_t *found_vers);
+/* check if server version can handle client requested version */
+int msm_rpc_is_compatible_version(uint32_t server_version,
+ uint32_t client_version);
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept);
+int msm_rpc_write(struct msm_rpc_endpoint *ept,
+ void *data, int len);
+int msm_rpc_read(struct msm_rpc_endpoint *ept,
+ void **data, unsigned len, long timeout);
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr,
+ uint32_t prog, uint32_t vers, uint32_t proc);
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers);
+
+int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept);
+/* simple blocking rpc call
+ *
+ * request is mandatory and must have a rpc_request_hdr
+ * at the start. The header will be filled out for you.
+ *
+ * reply provides a buffer for replies of reply_max_size
+ */
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ void *reply, int reply_max_size,
+ long timeout);
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *request, int request_size,
+ long timeout);
+
+struct msm_rpc_server
+{
+ struct list_head list;
+ uint32_t flags;
+
+ uint32_t prog;
+ uint32_t vers;
+
+ struct mutex cb_req_lock;
+ struct mutex reply_lock;
+ char *cb_req;
+ char *reply;
+
+ struct msm_rpc_endpoint *cb_ept;
+
+ int (*rpc_call)(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len);
+};
+
+int msm_rpc_create_server(struct msm_rpc_server *server);
+
+#define MSM_RPC_MSGSIZE_MAX 8192
+
+struct msm_rpc_client;
+
+struct msm_rpc_client {
+ struct task_struct *read_thread;
+ struct task_struct *cb_thread;
+
+ struct msm_rpc_endpoint *ept;
+ wait_queue_head_t reply_wait;
+
+ uint32_t prog, ver;
+
+ void *buf;
+ int read_avail;
+
+ int (*cb_func)(struct msm_rpc_client *, void *, int);
+ void *cb_buf;
+ int cb_size;
+
+ struct list_head cb_item_list;
+ struct mutex cb_item_list_lock;
+
+ wait_queue_head_t cb_wait;
+ int cb_avail;
+
+ atomic_t next_cb_id;
+ struct mutex cb_list_lock;
+ struct list_head cb_list;
+
+ uint32_t exit_flag;
+ struct completion complete;
+ struct completion cb_complete;
+
+ struct mutex req_lock;
+ struct mutex reply_lock;
+ char *req;
+ char *reply;
+};
+
+struct msm_rpc_client_info {
+ uint32_t pid;
+ uint32_t cid;
+ uint32_t prog;
+ uint32_t vers;
+};
+
+struct msm_rpc_client *msm_rpc_register_client(
+ const char *name,
+ uint32_t prog, uint32_t ver,
+ uint32_t create_cb_thread,
+ int (*cb_func)(struct msm_rpc_client *, void *, int));
+
+int msm_rpc_unregister_client(struct msm_rpc_client *client);
+
+int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
+ int (*arg_func)(struct msm_rpc_client *,
+ void *, void *), void *arg_data,
+ int (*result_func)(struct msm_rpc_client *,
+ void *, void *), void *result_data,
+ long timeout);
+
+void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
+ uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size);
+
+void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server,
+ uint32_t xid, uint32_t accept_status);
+
+int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server,
+ uint32_t size);
+
+int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id);
+
+void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func);
+
+int msm_rpc_server_cb_req(struct msm_rpc_server *server,
+ struct msm_rpc_client_info *clnt_info,
+ uint32_t cb_proc,
+ int (*arg_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *arg_data,
+ int (*ret_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *ret_data, long timeout);
+
+void msm_rpc_server_get_requesting_client(
+ struct msm_rpc_client_info *clnt_info);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
new file mode 100644
index 000000000000..8ef65c04ea85
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -0,0 +1,82 @@
+/* linux/include/asm-arm/arch-msm/msm_smd.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SMD_H
+#define __ASM_ARCH_MSM_SMD_H
+
+typedef struct smd_channel smd_channel_t;
+
+/* warning: notify() may be called before open returns */
+int smd_open(const char *name, smd_channel_t **ch, void *priv,
+ void (*notify)(void *priv, unsigned event));
+
+#define SMD_EVENT_DATA 1
+#define SMD_EVENT_OPEN 2
+#define SMD_EVENT_CLOSE 3
+
+int smd_close(smd_channel_t *ch);
+
+/* passing a null pointer for data reads and discards */
+int smd_read(smd_channel_t *ch, void *data, int len);
+int smd_read_from_cb(smd_channel_t *ch, void *data, int len);
+
+/* Write to stream channels may do a partial write and return
+** the length actually written.
+** Write to packet channels will never do a partial write --
+** it will return the requested length written or an error.
+*/
+int smd_write(smd_channel_t *ch, const void *data, int len);
+
+int smd_write_avail(smd_channel_t *ch);
+int smd_read_avail(smd_channel_t *ch);
+
+/* Returns the total size of the current packet being read.
+** Returns 0 if no packets available or a stream channel.
+*/
+int smd_cur_packet_size(smd_channel_t *ch);
+
+
+#if 0
+/* these are interruptable waits which will block you until the specified
+** number of bytes are readable or writable.
+*/
+int smd_wait_until_readable(smd_channel_t *ch, int bytes);
+int smd_wait_until_writable(smd_channel_t *ch, int bytes);
+#endif
+
+/* these are used to get and set the IF sigs of a channel.
+ * DTR and RTS can be set; DSR, CTS, CD and RI can be read.
+ */
+int smd_tiocmget(smd_channel_t *ch);
+int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear);
+
+#if defined(CONFIG_MSM_N_WAY_SMD)
+enum {
+ SMD_APPS_MODEM = 0,
+ SMD_APPS_QDSP,
+ SMD_MODEM_QDSP
+};
+#else
+enum {
+ SMD_APPS_MODEM = 0
+};
+#endif
+
+int smd_named_open_on_edge(const char *name, uint32_t edge, smd_channel_t **_ch,
+ void *priv, void (*notify)(void *, unsigned));
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_touch.h b/arch/arm/mach-msm/include/mach/msm_touch.h
new file mode 100644
index 000000000000..763d6a8f1113
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_touch.h
@@ -0,0 +1,26 @@
+/* arch/arm/mach-msm/include/mach/msm_touch.h
+ *
+ * Platform data for MSM touchscreen driver.
+ *
+ * Copyright (c) 2008-2009, 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.
+ */
+
+#ifndef _MACH_MSM_TOUCH_H_
+#define _MACH_MSM_TOUCH_H_
+
+struct msm_ts_platform_data {
+ unsigned int x_max;
+ unsigned int y_max;
+ unsigned int pressure_max;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_touchpad.h b/arch/arm/mach-msm/include/mach/msm_touchpad.h
new file mode 100644
index 000000000000..5c02f15c5ca5
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_touchpad.h
@@ -0,0 +1,37 @@
+/* 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 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.
+ *
+ */
+/*
+ * Touchpad driver for QSD platform.
+ */
+
+struct msm_touchpad_platform_data {
+ int gpioirq;
+ int gpiosuspend;
+ int (*gpio_setup) (void);
+ void (*gpio_shutdown)(void);
+};
diff --git a/arch/arm/mach-msm/include/mach/oem_rapi_client.h b/arch/arm/mach-msm/include/mach/oem_rapi_client.h
new file mode 100644
index 000000000000..4b340eb814c9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/oem_rapi_client.h
@@ -0,0 +1,91 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ASM__ARCH_OEM_RAPI_CLIENT_H
+#define __ASM__ARCH_OEM_RAPI_CLIENT_H
+
+/*
+ * OEM RAPI CLIENT Driver header file
+ */
+
+#include <linux/types.h>
+#include <mach/msm_rpcrouter.h>
+
+enum {
+ OEM_RAPI_CLIENT_EVENT_NONE = 0,
+
+ /*
+ * list of oem rapi client events
+ */
+
+ OEM_RAPI_CLIENT_EVENT_MAX
+
+};
+
+struct oem_rapi_client_streaming_func_cb_arg {
+ uint32_t event;
+ void *handle;
+ uint32_t in_len;
+ char *input;
+ uint32_t out_len_valid;
+ uint32_t output_valid;
+ uint32_t output_size;
+};
+
+struct oem_rapi_client_streaming_func_cb_ret {
+ uint32_t *out_len;
+ char *output;
+};
+
+struct oem_rapi_client_streaming_func_arg {
+ uint32_t event;
+ int (*cb_func)(struct oem_rapi_client_streaming_func_cb_arg *,
+ struct oem_rapi_client_streaming_func_cb_ret *);
+ void *handle;
+ uint32_t in_len;
+ char *input;
+ uint32_t out_len_valid;
+ uint32_t output_valid;
+ uint32_t output_size;
+};
+
+struct oem_rapi_client_streaming_func_ret {
+ uint32_t *out_len;
+ char *output;
+};
+
+int oem_rapi_client_streaming_function(
+ struct msm_rpc_client *client,
+ struct oem_rapi_client_streaming_func_arg *arg,
+ struct oem_rapi_client_streaming_func_ret *ret);
+
+int oem_rapi_client_close(void);
+
+struct msm_rpc_client *oem_rapi_client_init(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/pmic.h b/arch/arm/mach-msm/include/mach/pmic.h
new file mode 100644
index 000000000000..c339e743c032
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/pmic.h
@@ -0,0 +1,557 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_PMIC_H
+#define __ARCH_ARM_MACH_PMIC_H
+
+
+enum spkr_left_right {
+ LEFT_SPKR,
+ RIGHT_SPKR,
+};
+
+enum spkr_gain {
+ SPKR_GAIN_MINUS16DB, /* -16 db */
+ SPKR_GAIN_MINUS12DB, /* -12 db */
+ SPKR_GAIN_MINUS08DB, /* -08 db */
+ SPKR_GAIN_MINUS04DB, /* -04 db */
+ SPKR_GAIN_00DB, /* 00 db */
+ SPKR_GAIN_PLUS04DB, /* +04 db */
+ SPKR_GAIN_PLUS08DB, /* +08 db */
+ SPKR_GAIN_PLUS12DB, /* +12 db */
+};
+
+enum spkr_dly {
+ SPKR_DLY_10MS, /* ~10 ms delay */
+ SPKR_DLY_100MS, /* ~100 ms delay */
+};
+
+enum spkr_hpf_corner_freq {
+ SPKR_FREQ_1_39KHZ, /* 1.39 kHz */
+ SPKR_FREQ_0_64KHZ, /* 0.64 kHz */
+ SPKR_FREQ_0_86KHZ, /* 0.86 kHz */
+ SPKR_FREQ_0_51KHZ, /* 0.51 kHz */
+ SPKR_FREQ_1_06KHZ, /* 1.06 kHz */
+ SPKR_FREQ_0_57KHZ, /* 0.57 kHz */
+ SPKR_FREQ_0_73KHZ, /* 0.73 kHz */
+ SPKR_FREQ_0_47KHZ, /* 0.47 kHz */
+ SPKR_FREQ_1_20KHZ, /* 1.20 kHz */
+ SPKR_FREQ_0_60KHZ, /* 0.60 kHz */
+ SPKR_FREQ_0_76KHZ, /* 0.76 kHz */
+ SPKR_FREQ_0_49KHZ, /* 0.49 kHz */
+ SPKR_FREQ_0_95KHZ, /* 0.95 kHz */
+ SPKR_FREQ_0_54KHZ, /* 0.54 kHz */
+ SPKR_FREQ_0_68KHZ, /* 0.68 kHz */
+ SPKR_FREQ_0_45KHZ, /* 0.45 kHz */
+};
+
+/* Turn the speaker on or off and enables or disables mute.*/
+enum spkr_cmd {
+ SPKR_DISABLE, /* Enable Speaker */
+ SPKR_ENABLE, /* Disable Speaker */
+ SPKR_MUTE_OFF, /* turn speaker mute off, SOUND ON */
+ SPKR_MUTE_ON, /* turn speaker mute on, SOUND OFF */
+ SPKR_OFF, /* turn speaker OFF (speaker disable and mute on) */
+ SPKR_ON, /* turn speaker ON (speaker enable and mute off) */
+ SPKR_SET_FREQ_CMD, /* set speaker frequency */
+ SPKR_GET_FREQ_CMD, /* get speaker frequency */
+ SPKR_SET_GAIN_CMD, /* set speaker gain */
+ SPKR_GET_GAIN_CMD, /* get speaker gain */
+ SPKR_SET_DELAY_CMD, /* set speaker delay */
+ SPKR_GET_DELAY_CMD, /* get speaker delay */
+ SPKR_SET_PDM_MODE,
+ SPKR_SET_PWM_MODE,
+};
+
+struct spkr_config_mode {
+ uint32_t is_right_chan_en;
+ uint32_t is_left_chan_en;
+ uint32_t is_right_left_chan_added;
+ uint32_t is_stereo_en;
+ uint32_t is_usb_with_hpf_20hz;
+ uint32_t is_mux_bypassed;
+ uint32_t is_hpf_en;
+ uint32_t is_sink_curr_from_ref_volt_cir_en;
+};
+
+enum mic_volt {
+ MIC_VOLT_2_00V, /* 2.00 V */
+ MIC_VOLT_1_93V, /* 1.93 V */
+ MIC_VOLT_1_80V, /* 1.80 V */
+ MIC_VOLT_1_73V, /* 1.73 V */
+};
+
+enum ledtype {
+ LED_LCD,
+ LED_KEYPAD,
+};
+
+enum flash_led_mode {
+ FLASH_LED_MODE__MANUAL,
+ FLASH_LED_MODE__DBUS1,
+ FLASH_LED_MODE__DBUS2,
+ FLASH_LED_MODE__DBUS3,
+};
+
+enum flash_led_pol {
+ FLASH_LED_POL__ACTIVE_HIGH,
+ FLASH_LED_POL__ACTIVE_LOW,
+};
+
+enum switch_cmd {
+ OFF_CMD,
+ ON_CMD
+};
+
+enum vreg_lp_id {
+ PM_VREG_LP_MSMA_ID,
+ PM_VREG_LP_MSMP_ID,
+ PM_VREG_LP_MSME1_ID,
+ PM_VREG_LP_GP3_ID,
+ PM_VREG_LP_MSMC_ID,
+ PM_VREG_LP_MSME2_ID,
+ PM_VREG_LP_GP4_ID,
+ PM_VREG_LP_GP1_ID,
+ PM_VREG_LP_RFTX_ID,
+ PM_VREG_LP_RFRX1_ID,
+ PM_VREG_LP_RFRX2_ID,
+ PM_VREG_LP_WLAN_ID,
+ PM_VREG_LP_MMC_ID,
+ PM_VREG_LP_RUIM_ID,
+ PM_VREG_LP_MSMC0_ID,
+ PM_VREG_LP_GP2_ID,
+ PM_VREG_LP_GP5_ID,
+ PM_VREG_LP_GP6_ID,
+ PM_VREG_LP_MPLL_ID,
+ PM_VREG_LP_RFUBM_ID,
+ PM_VREG_LP_RFA_ID,
+ PM_VREG_LP_CDC2_ID,
+ PM_VREG_LP_RFTX2_ID,
+ PM_VREG_LP_USIM_ID,
+ PM_VREG_LP_USB2P6_ID,
+ PM_VREG_LP_TCXO_ID,
+ PM_VREG_LP_USB3P3_ID,
+
+ PM_VREG_LP_MSME_ID = PM_VREG_LP_MSME1_ID,
+ /* backward compatible enums only */
+ PM_VREG_LP_CAM_ID = PM_VREG_LP_GP1_ID,
+ PM_VREG_LP_MDDI_ID = PM_VREG_LP_GP2_ID,
+ PM_VREG_LP_RUIM2_ID = PM_VREG_LP_GP3_ID,
+ PM_VREG_LP_AUX_ID = PM_VREG_LP_GP4_ID,
+ PM_VREG_LP_AUX2_ID = PM_VREG_LP_GP5_ID,
+ PM_VREG_LP_BT_ID = PM_VREG_LP_GP6_ID,
+ PM_VREG_LP_MSMC_LDO_ID = PM_VREG_LP_MSMC_ID,
+ PM_VREG_LP_MSME1_LDO_ID = PM_VREG_LP_MSME1_ID,
+ PM_VREG_LP_MSME2_LDO_ID = PM_VREG_LP_MSME2_ID,
+ PM_VREG_LP_RFA1_ID = PM_VREG_LP_RFRX2_ID,
+ PM_VREG_LP_RFA2_ID = PM_VREG_LP_RFTX2_ID,
+ PM_VREG_LP_XO_ID = PM_VREG_LP_TCXO_ID
+};
+
+enum vreg_id {
+ PM_VREG_MSMA_ID = 0,
+ PM_VREG_MSMP_ID,
+ PM_VREG_MSME1_ID,
+ PM_VREG_MSMC1_ID,
+ PM_VREG_MSMC2_ID,
+ PM_VREG_GP3_ID,
+ PM_VREG_MSME2_ID,
+ PM_VREG_GP4_ID,
+ PM_VREG_GP1_ID,
+ PM_VREG_TCXO_ID,
+ PM_VREG_PA_ID,
+ PM_VREG_RFTX_ID,
+ PM_VREG_RFRX1_ID,
+ PM_VREG_RFRX2_ID,
+ PM_VREG_SYNT_ID,
+ PM_VREG_WLAN_ID,
+ PM_VREG_USB_ID,
+ PM_VREG_BOOST_ID,
+ PM_VREG_MMC_ID,
+ PM_VREG_RUIM_ID,
+ PM_VREG_MSMC0_ID,
+ PM_VREG_GP2_ID,
+ PM_VREG_GP5_ID,
+ PM_VREG_GP6_ID,
+ PM_VREG_RF_ID,
+ PM_VREG_RF_VCO_ID,
+ PM_VREG_MPLL_ID,
+ PM_VREG_S2_ID,
+ PM_VREG_S3_ID,
+ PM_VREG_RFUBM_ID,
+ PM_VREG_NCP_ID,
+ PM_VREG_RF2_ID,
+ PM_VREG_RFA_ID,
+ PM_VREG_CDC2_ID,
+ PM_VREG_RFTX2_ID,
+ PM_VREG_USIM_ID,
+ PM_VREG_USB2P6_ID,
+ PM_VREG_USB3P3_ID,
+ PM_VREG_EXTCDC1_ID,
+ PM_VREG_EXTCDC2_ID,
+
+ /* backward compatible enums only */
+ PM_VREG_MSME_ID = PM_VREG_MSME1_ID,
+ PM_VREG_MSME_BUCK_SMPS_ID = PM_VREG_MSME1_ID,
+ PM_VREG_MSME1_LDO_ID = PM_VREG_MSME1_ID,
+ PM_VREG_MSMC_ID = PM_VREG_MSMC1_ID,
+ PM_VREG_MSMC_LDO_ID = PM_VREG_MSMC1_ID,
+ PM_VREG_MSMC1_BUCK_SMPS_ID = PM_VREG_MSMC1_ID,
+ PM_VREG_MSME2_LDO_ID = PM_VREG_MSME2_ID,
+ PM_VREG_CAM_ID = PM_VREG_GP1_ID,
+ PM_VREG_MDDI_ID = PM_VREG_GP2_ID,
+ PM_VREG_RUIM2_ID = PM_VREG_GP3_ID,
+ PM_VREG_AUX_ID = PM_VREG_GP4_ID,
+ PM_VREG_AUX2_ID = PM_VREG_GP5_ID,
+ PM_VREG_BT_ID = PM_VREG_GP6_ID,
+ PM_VREG_RF1_ID = PM_VREG_RF_ID,
+ PM_VREG_S1_ID = PM_VREG_RF1_ID,
+ PM_VREG_5V_ID = PM_VREG_BOOST_ID,
+ PM_VREG_RFA1_ID = PM_VREG_RFRX2_ID,
+ PM_VREG_RFA2_ID = PM_VREG_RFTX2_ID,
+ PM_VREG_XO_ID = PM_VREG_TCXO_ID
+};
+
+enum vreg_pdown_id {
+ PM_VREG_PDOWN_MSMA_ID,
+ PM_VREG_PDOWN_MSMP_ID,
+ PM_VREG_PDOWN_MSME1_ID,
+ PM_VREG_PDOWN_MSMC1_ID,
+ PM_VREG_PDOWN_MSMC2_ID,
+ PM_VREG_PDOWN_GP3_ID,
+ PM_VREG_PDOWN_MSME2_ID,
+ PM_VREG_PDOWN_GP4_ID,
+ PM_VREG_PDOWN_GP1_ID,
+ PM_VREG_PDOWN_TCXO_ID,
+ PM_VREG_PDOWN_PA_ID,
+ PM_VREG_PDOWN_RFTX_ID,
+ PM_VREG_PDOWN_RFRX1_ID,
+ PM_VREG_PDOWN_RFRX2_ID,
+ PM_VREG_PDOWN_SYNT_ID,
+ PM_VREG_PDOWN_WLAN_ID,
+ PM_VREG_PDOWN_USB_ID,
+ PM_VREG_PDOWN_MMC_ID,
+ PM_VREG_PDOWN_RUIM_ID,
+ PM_VREG_PDOWN_MSMC0_ID,
+ PM_VREG_PDOWN_GP2_ID,
+ PM_VREG_PDOWN_GP5_ID,
+ PM_VREG_PDOWN_GP6_ID,
+ PM_VREG_PDOWN_RF_ID,
+ PM_VREG_PDOWN_RF_VCO_ID,
+ PM_VREG_PDOWN_MPLL_ID,
+ PM_VREG_PDOWN_S2_ID,
+ PM_VREG_PDOWN_S3_ID,
+ PM_VREG_PDOWN_RFUBM_ID,
+ /* new for HAN */
+ PM_VREG_PDOWN_RF1_ID,
+ PM_VREG_PDOWN_RF2_ID,
+ PM_VREG_PDOWN_RFA_ID,
+ PM_VREG_PDOWN_CDC2_ID,
+ PM_VREG_PDOWN_RFTX2_ID,
+ PM_VREG_PDOWN_USIM_ID,
+ PM_VREG_PDOWN_USB2P6_ID,
+ PM_VREG_PDOWN_USB3P3_ID,
+
+ /* backward compatible enums only */
+ PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID,
+ PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID,
+ PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID,
+ PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID,
+ PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID,
+ PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID,
+ PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID,
+ PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID,
+ PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID,
+ PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID,
+ PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID
+};
+
+enum mpp_which {
+ PM_MPP_1,
+ PM_MPP_2,
+ PM_MPP_3,
+ PM_MPP_4,
+ PM_MPP_5,
+ PM_MPP_6,
+ PM_MPP_7,
+ PM_MPP_8,
+ PM_MPP_9,
+ PM_MPP_10,
+ PM_MPP_11,
+ PM_MPP_12,
+ PM_MPP_13,
+ PM_MPP_14,
+ PM_MPP_15,
+ PM_MPP_16,
+ PM_MPP_17,
+ PM_MPP_18,
+ PM_MPP_19,
+ PM_MPP_20,
+ PM_MPP_21,
+ PM_MPP_22,
+
+ PM_NUM_MPP_HAN = PM_MPP_4 + 1,
+ PM_NUM_MPP_KIP = PM_MPP_4 + 1,
+ PM_NUM_MPP_EPIC = PM_MPP_4 + 1,
+ PM_NUM_MPP_PM7500 = PM_MPP_22 + 1,
+ PM_NUM_MPP_PM6650 = PM_MPP_12 + 1,
+ PM_NUM_MPP_PM6658 = PM_MPP_12 + 1,
+ PM_NUM_MPP_PANORAMIX = PM_MPP_2 + 1,
+ PM_NUM_MPP_PM6640 = PM_NUM_MPP_PANORAMIX,
+ PM_NUM_MPP_PM6620 = PM_NUM_MPP_PANORAMIX
+};
+
+enum mpp_dlogic_level {
+ PM_MPP__DLOGIC__LVL_MSME,
+ PM_MPP__DLOGIC__LVL_MSMP,
+ PM_MPP__DLOGIC__LVL_RUIM,
+ PM_MPP__DLOGIC__LVL_MMC,
+ PM_MPP__DLOGIC__LVL_VDD,
+};
+
+enum mpp_dlogic_in_dbus {
+ PM_MPP__DLOGIC_IN__DBUS_NONE,
+ PM_MPP__DLOGIC_IN__DBUS1,
+ PM_MPP__DLOGIC_IN__DBUS2,
+ PM_MPP__DLOGIC_IN__DBUS3,
+};
+
+enum mpp_dlogic_out_ctrl {
+ PM_MPP__DLOGIC_OUT__CTRL_LOW,
+ PM_MPP__DLOGIC_OUT__CTRL_HIGH,
+ PM_MPP__DLOGIC_OUT__CTRL_MPP,
+ PM_MPP__DLOGIC_OUT__CTRL_NOT_MPP,
+};
+
+enum mpp_i_sink_level {
+ PM_MPP__I_SINK__LEVEL_5mA,
+ PM_MPP__I_SINK__LEVEL_10mA,
+ PM_MPP__I_SINK__LEVEL_15mA,
+ PM_MPP__I_SINK__LEVEL_20mA,
+ PM_MPP__I_SINK__LEVEL_25mA,
+ PM_MPP__I_SINK__LEVEL_30mA,
+ PM_MPP__I_SINK__LEVEL_35mA,
+ PM_MPP__I_SINK__LEVEL_40mA,
+};
+
+enum mpp_i_sink_switch {
+ PM_MPP__I_SINK__SWITCH_DIS,
+ PM_MPP__I_SINK__SWITCH_ENA,
+ PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_HIGH,
+ PM_MPP__I_SINK__SWITCH_ENA_IF_MPP_LOW,
+};
+
+enum pm_vib_mot_mode {
+ PM_VIB_MOT_MODE__MANUAL,
+ PM_VIB_MOT_MODE__DBUS1,
+ PM_VIB_MOT_MODE__DBUS2,
+ PM_VIB_MOT_MODE__DBUS3,
+};
+
+enum pm_vib_mot_pol {
+ PM_VIB_MOT_POL__ACTIVE_HIGH,
+ PM_VIB_MOT_POL__ACTIVE_LOW,
+};
+
+struct rtc_time {
+ uint sec;
+};
+
+enum rtc_alarm {
+ PM_RTC_ALARM_1,
+};
+
+enum hsed_controller {
+ PM_HSED_CONTROLLER_0,
+ PM_HSED_CONTROLLER_1,
+ PM_HSED_CONTROLLER_2,
+};
+
+enum hsed_switch {
+ PM_HSED_SC_SWITCH_TYPE,
+ PM_HSED_OC_SWITCH_TYPE,
+};
+
+enum hsed_enable {
+ PM_HSED_ENABLE_OFF,
+ PM_HSED_ENABLE_TCXO,
+ PM_HSED_ENABLE_PWM_TCXO,
+ PM_HSED_ENABLE_ALWAYS,
+};
+
+enum hsed_hyst_pre_div {
+ PM_HSED_HYST_PRE_DIV_1,
+ PM_HSED_HYST_PRE_DIV_2,
+ PM_HSED_HYST_PRE_DIV_4,
+ PM_HSED_HYST_PRE_DIV_8,
+ PM_HSED_HYST_PRE_DIV_16,
+ PM_HSED_HYST_PRE_DIV_32,
+ PM_HSED_HYST_PRE_DIV_64,
+ PM_HSED_HYST_PRE_DIV_128,
+};
+
+enum hsed_hyst_time {
+ PM_HSED_HYST_TIME_1_CLK_CYCLES,
+ PM_HSED_HYST_TIME_2_CLK_CYCLES,
+ PM_HSED_HYST_TIME_3_CLK_CYCLES,
+ PM_HSED_HYST_TIME_4_CLK_CYCLES,
+ PM_HSED_HYST_TIME_5_CLK_CYCLES,
+ PM_HSED_HYST_TIME_6_CLK_CYCLES,
+ PM_HSED_HYST_TIME_7_CLK_CYCLES,
+ PM_HSED_HYST_TIME_8_CLK_CYCLES,
+ PM_HSED_HYST_TIME_9_CLK_CYCLES,
+ PM_HSED_HYST_TIME_10_CLK_CYCLES,
+ PM_HSED_HYST_TIME_11_CLK_CYCLES,
+ PM_HSED_HYST_TIME_12_CLK_CYCLES,
+ PM_HSED_HYST_TIME_13_CLK_CYCLES,
+ PM_HSED_HYST_TIME_14_CLK_CYCLES,
+ PM_HSED_HYST_TIME_15_CLK_CYCLES,
+ PM_HSED_HYST_TIME_16_CLK_CYCLES,
+};
+
+enum hsed_period_pre_div {
+ PM_HSED_PERIOD_PRE_DIV_2,
+ PM_HSED_PERIOD_PRE_DIV_4,
+ PM_HSED_PERIOD_PRE_DIV_8,
+ PM_HSED_PERIOD_PRE_DIV_16,
+ PM_HSED_PERIOD_PRE_DIV_32,
+ PM_HSED_PERIOD_PRE_DIV_64,
+ PM_HSED_PERIOD_PRE_DIV_128,
+ PM_HSED_PERIOD_PRE_DIV_256,
+};
+
+enum hsed_period_time {
+ PM_HSED_PERIOD_TIME_1_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_2_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_3_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_4_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_5_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_6_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_7_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_8_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_9_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_10_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_11_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_12_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_13_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_14_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_15_CLK_CYCLES,
+ PM_HSED_PERIOD_TIME_16_CLK_CYCLES,
+};
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id);
+int pmic_vreg_set_level(enum vreg_id vreg, int level);
+int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id);
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+ enum mpp_dlogic_level level, enum mpp_dlogic_out_ctrl out);
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+ enum mpp_i_sink_level level, enum mpp_i_sink_switch onoff);
+int pmic_secure_mpp_config_digital_input(enum mpp_which which,
+ enum mpp_dlogic_level level, enum mpp_dlogic_in_dbus dbus);
+int pmic_rtc_start(struct rtc_time *time);
+int pmic_rtc_stop(void);
+int pmic_rtc_get_time(struct rtc_time *time);
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+ struct rtc_time *time);
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm);
+int pmic_rtc_get_alarm_time(enum rtc_alarm alarm,
+ struct rtc_time *time);
+int pmic_rtc_get_alarm_status(uint *status);
+int pmic_rtc_set_time_adjust(uint adjust);
+int pmic_rtc_get_time_adjust(uint *adjust);
+int pmic_speaker_cmd(const enum spkr_cmd cmd);
+int pmic_set_spkr_configuration(struct spkr_config_mode *cfg);
+int pmic_get_spkr_configuration(struct spkr_config_mode *cfg);
+int pmic_spkr_en_right_chan(uint enable);
+int pmic_spkr_is_right_chan_en(uint *enabled);
+int pmic_spkr_en_left_chan(uint enable);
+int pmic_spkr_is_left_chan_en(uint *enabled);
+int pmic_spkr_en(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled);
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain);
+int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain);
+int pmic_set_speaker_gain(enum spkr_gain gain);
+int pmic_set_speaker_delay(enum spkr_dly delay);
+int pmic_speaker_1k6_zin_enable(uint enable);
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq freq);
+int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq *freq);
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable);
+int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled);
+int pmic_spkr_bypass_mux(uint enable);
+int pmic_spkr_is_mux_bypassed(uint *enabled);
+int pmic_spkr_en_hpf(uint enable);
+int pmic_spkr_is_hpf_en(uint *enabled);
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable);
+int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled);
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay);
+int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay);
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled);
+int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled);
+int pmic_mic_en(uint enable);
+int pmic_mic_is_en(uint *enabled);
+int pmic_mic_set_volt(enum mic_volt vol);
+int pmic_mic_get_volt(enum mic_volt *voltage);
+int pmic_set_led_intensity(enum ledtype type, int level);
+int pmic_flash_led_set_current(uint16_t milliamps);
+int pmic_flash_led_set_mode(enum flash_led_mode mode);
+int pmic_flash_led_set_polarity(enum flash_led_pol pol);
+int pmic_spkr_add_right_left_chan(uint enable);
+int pmic_spkr_is_right_left_chan_added(uint *enabled);
+int pmic_spkr_en_stereo(uint enable);
+int pmic_spkr_is_stereo_en(uint *enabled);
+int pmic_vib_mot_set_volt(uint vol);
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode);
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol);
+int pmic_vid_en(uint enable);
+int pmic_vid_is_en(uint *enabled);
+int pmic_vid_load_detect_en(uint enable);
+
+int pmic_hsed_set_period(
+ enum hsed_controller controller,
+ enum hsed_period_pre_div period_pre_div,
+ enum hsed_period_time period_time
+);
+
+int pmic_hsed_set_hysteresis(
+ enum hsed_controller controller,
+ enum hsed_hyst_pre_div hyst_pre_div,
+ enum hsed_hyst_time hyst_time
+);
+
+int pmic_hsed_set_current_threshold(
+ enum hsed_controller controller,
+ enum hsed_switch switch_hsed,
+ uint32_t current_threshold
+);
+
+int pmic_hsed_enable(
+ enum hsed_controller controller,
+ enum hsed_enable enable
+);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/remote_spinlock.h b/arch/arm/mach-msm/include/mach/remote_spinlock.h
new file mode 100644
index 000000000000..8d8a5ddb8a4e
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/remote_spinlock.h
@@ -0,0 +1,115 @@
+/* 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 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.
+ *
+ */
+
+/*
+ * Part of this this code is based on the standard ARM spinlock
+ * implementation (asm/spinlock.h) found in the 2.6.29 kernel.
+ */
+
+#ifndef __ASM__ARCH_QC_REMOTE_SPINLOCK_H
+#define __ASM__ARCH_QC_REMOTE_SPINLOCK_H
+
+#include <linux/types.h>
+
+typedef struct {
+ volatile uint32_t lock;
+} raw_remote_spinlock_t;
+
+typedef raw_remote_spinlock_t *_remote_spinlock_t;
+
+#define remote_spin_lock_id_t uint32_t
+
+static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+"1: ldrex %0, [%1]\n"
+" teq %0, #0\n"
+" strexeq %0, %2, [%1]\n"
+" teqeq %0, #0\n"
+" bne 1b"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (1)
+ : "cc");
+
+ smp_mb();
+}
+
+static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
+{
+ smp_mb();
+
+ __asm__ __volatile__(
+" str %1, [%0]\n"
+ :
+ : "r" (&lock->lock), "r" (0)
+ : "cc");
+}
+
+static inline void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock)
+{
+ unsigned long tmp;
+
+ __asm__ __volatile__(
+"1: swp %0, %2, [%1]\n"
+" teq %0, #0\n"
+" bne 1b"
+ : "=&r" (tmp)
+ : "r" (&lock->lock), "r" (1)
+ : "cc");
+
+ smp_mb();
+}
+
+static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
+{
+ smp_mb();
+
+ __asm__ __volatile__(
+" str %1, [%0]"
+ :
+ : "r" (&lock->lock), "r" (0)
+ : "cc");
+}
+
+
+int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock);
+
+/* Only use SWP-based spinlocks for ARM11 apps processors where the LDREX/STREX
+ * instructions are unable to lock shared memory for exclusive access. */
+#if defined(CONFIG_ARCH_MSM_ARM11)
+#define _remote_spin_lock(lock) __raw_remote_swp_spin_lock(*lock)
+#define _remote_spin_unlock(lock) __raw_remote_swp_spin_unlock(*lock)
+#else
+#define _remote_spin_lock(lock) __raw_remote_ex_spin_lock(*lock)
+#define _remote_spin_unlock(lock) __raw_remote_ex_spin_unlock(*lock)
+#endif /* CONFIG_ARCH_MSM_ARM11 */
+
+#endif /* __ASM__ARCH_QC_REMOTE_SPINLOCK_H */
+
diff --git a/arch/arm/mach-msm/include/mach/rpc_hsusb.h b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
new file mode 100644
index 000000000000..9ef304be2189
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpc_hsusb.h
@@ -0,0 +1,45 @@
+/* linux/include/mach/rpc_hsusb.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * 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, you can find it at http://www.fsf.org
+ */
+
+#ifndef __ASM_ARCH_MSM_RPC_HSUSB_H
+#define __ASM_ARCH_MSM_RPC_HSUSB_H
+
+#include <mach/msm_rpcrouter.h>
+
+int msm_hsusb_rpc_connect(void);
+int msm_hsusb_phy_reset(void);
+int msm_hsusb_vbus_powerup(void);
+int msm_hsusb_vbus_shutdown(void);
+int msm_hsusb_send_productID(uint32_t product_id);
+int msm_hsusb_send_serial_number(char *serial_number);
+int msm_hsusb_is_serial_num_null(uint32_t val);
+int msm_hsusb_reset_rework_installed(void);
+int msm_hsusb_enable_pmic_ulpidata0(void);
+int msm_hsusb_disable_pmic_ulpidata0(void);
+int msm_hsusb_rpc_close(void);
+
+int msm_chg_rpc_connect(void);
+int msm_chg_usb_charger_connected(uint32_t type);
+int msm_chg_usb_i_is_available(uint32_t sample);
+int msm_chg_usb_i_is_not_available(void);
+int msm_chg_usb_charger_disconnected(void);
+int msm_chg_rpc_close(void);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/sirc.h b/arch/arm/mach-msm/include/mach/sirc.h
new file mode 100644
index 000000000000..133f37ef1546
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/sirc.h
@@ -0,0 +1,103 @@
+/* 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 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SIRC_H
+#define __ASM_ARCH_MSM_SIRC_H
+
+struct sirc_regs_t {
+ void *int_enable;
+ void *int_enable_clear;
+ void *int_enable_set;
+ void *int_type;
+ void *int_polarity;
+ void *int_clear;
+};
+
+struct sirc_cascade_regs {
+ void *int_status;
+ unsigned int cascade_irq;
+};
+
+void msm_init_sirc(void);
+void msm_sirc_enter_sleep(void);
+void msm_sirc_exit_sleep(void);
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+
+#include <mach/msm_iomap.h>
+
+/*
+ * Secondary interrupt controller interrupts
+ */
+
+#define FIRST_SIRC_IRQ (NR_MSM_IRQS + NR_GPIO_IRQS)
+
+#define INT_UART1 (FIRST_SIRC_IRQ + 0)
+#define INT_UART2 (FIRST_SIRC_IRQ + 1)
+#define INT_UART3 (FIRST_SIRC_IRQ + 2)
+#define INT_UART1_RX (FIRST_SIRC_IRQ + 3)
+#define INT_UART2_RX (FIRST_SIRC_IRQ + 4)
+#define INT_UART3_RX (FIRST_SIRC_IRQ + 5)
+#define INT_SPI_INPUT (FIRST_SIRC_IRQ + 6)
+#define INT_SPI_OUTPUT (FIRST_SIRC_IRQ + 7)
+#define INT_SPI_ERROR (FIRST_SIRC_IRQ + 8)
+#define INT_GPIO_GROUP1 (FIRST_SIRC_IRQ + 9)
+#define INT_GPIO_GROUP2 (FIRST_SIRC_IRQ + 10)
+#define INT_GPIO_GROUP1_SECURE (FIRST_SIRC_IRQ + 11)
+#define INT_GPIO_GROUP2_SECURE (FIRST_SIRC_IRQ + 12)
+#define INT_AVS_SVIC (FIRST_SIRC_IRQ + 13)
+#define INT_AVS_REQ_UP (FIRST_SIRC_IRQ + 14)
+#define INT_AVS_REQ_DOWN (FIRST_SIRC_IRQ + 15)
+#define INT_PBUS_ERR (FIRST_SIRC_IRQ + 16)
+#define INT_AXI_ERR (FIRST_SIRC_IRQ + 17)
+#define INT_SMI_ERR (FIRST_SIRC_IRQ + 18)
+#define INT_EBI1_ERR (FIRST_SIRC_IRQ + 19)
+#define INT_IMEM_ERR (FIRST_SIRC_IRQ + 20)
+#define INT_SC_TEMP_SENSOR (FIRST_SIRC_IRQ + 21)
+#define INT_TV_ENC (FIRST_SIRC_IRQ + 22)
+
+#define NR_SIRC_IRQS 23
+#define SIRC_MASK 0x007FFFFF
+#define LAST_SIRC_IRQ (FIRST_SIRC_IRQ + NR_SIRC_IRQS - 1)
+
+#define SPSS_SIRC_INT_SELECT (MSM_SIRC_BASE + 0x00)
+#define SPSS_SIRC_INT_ENABLE (MSM_SIRC_BASE + 0x04)
+#define SPSS_SIRC_INT_ENABLE_CLEAR (MSM_SIRC_BASE + 0x08)
+#define SPSS_SIRC_INT_ENABLE_SET (MSM_SIRC_BASE + 0x0C)
+#define SPSS_SIRC_INT_TYPE (MSM_SIRC_BASE + 0x10)
+#define SPSS_SIRC_INT_POLARITY (MSM_SIRC_BASE + 0x14)
+#define SPSS_SIRC_SECURITY (MSM_SIRC_BASE + 0x18)
+#define SPSS_SIRC_IRQ_STATUS (MSM_SIRC_BASE + 0x1C)
+#define SPSS_SIRC_IRQ1_STATUS (MSM_SIRC_BASE + 0x20)
+#define SPSS_SIRC_RAW_STATUS (MSM_SIRC_BASE + 0x24)
+#define SPSS_SIRC_INT_CLEAR (MSM_SIRC_BASE + 0x28)
+#define SPSS_SIRC_SOFT_INT (MSM_SIRC_BASE + 0x2C)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/smem_log.h b/arch/arm/mach-msm/include/mach/smem_log.h
new file mode 100644
index 000000000000..bd94bacc4809
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/smem_log.h
@@ -0,0 +1,245 @@
+/* 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 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.
+ *
+ */
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define SMEM_LOG_BASE 0x30
+
+#define SMIOC_SETMODE _IOW(SMEM_LOG_BASE, 1, int)
+#define SMIOC_SETLOG _IOW(SMEM_LOG_BASE, 2, int)
+
+#define SMIOC_TEXT 0x00000001
+#define SMIOC_BINARY 0x00000002
+#define SMIOC_LOG 0x00000003
+#define SMIOC_STATIC_LOG 0x00000004
+
+/* Event indentifier format:
+ * bit 31-28 is processor ID 8 => apps, 4 => Q6, 0 => modem
+ * bits 27-16 are subsystem id (event base)
+ * bits 15-0 are event id
+ */
+
+#define PROC 0xF0000000
+#define SUB 0x0FFF0000
+#define ID 0x0000FFFF
+
+#define SMEM_LOG_PROC_ID_MODEM 0x00000000
+#define SMEM_LOG_PROC_ID_Q6 0x40000000
+#define SMEM_LOG_PROC_ID_APPS 0x80000000
+
+#define SMEM_LOG_CONT 0x10000000
+
+#define SMEM_LOG_DEBUG_EVENT_BASE 0x00000000
+#define SMEM_LOG_ONCRPC_EVENT_BASE 0x00010000
+#define SMEM_LOG_SMEM_EVENT_BASE 0x00020000
+#define SMEM_LOG_TMC_EVENT_BASE 0x00030000
+#define SMEM_LOG_TIMETICK_EVENT_BASE 0x00040000
+#define SMEM_LOG_DEM_EVENT_BASE 0x00050000
+#define SMEM_LOG_ERROR_EVENT_BASE 0x00060000
+#define SMEM_LOG_DCVS_EVENT_BASE 0x00070000
+#define SMEM_LOG_SLEEP_EVENT_BASE 0x00080000
+#define SMEM_LOG_RPC_ROUTER_EVENT_BASE 0x00090000
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+#define DEM_SMSM_ISR (SMEM_LOG_DEM_EVENT_BASE + 0x1)
+#define DEM_STATE_CHANGE (SMEM_LOG_DEM_EVENT_BASE + 0x2)
+#define DEM_STATE_MACHINE_ENTER (SMEM_LOG_DEM_EVENT_BASE + 0x3)
+#define DEM_ENTER_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x4)
+#define DEM_END_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x5)
+#define DEM_SETUP_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x6)
+#define DEM_SETUP_POWER_COLLAPSE (SMEM_LOG_DEM_EVENT_BASE + 0x7)
+#define DEM_SETUP_SUSPEND (SMEM_LOG_DEM_EVENT_BASE + 0x8)
+#define DEM_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 0x9)
+#define DEM_WAKEUP_REASON (SMEM_LOG_DEM_EVENT_BASE + 0xA)
+#define DEM_DETECT_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0xB)
+#define DEM_DETECT_RESET (SMEM_LOG_DEM_EVENT_BASE + 0xC)
+#define DEM_DETECT_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 0xD)
+#define DEM_DETECT_RUN (SMEM_LOG_DEM_EVENT_BASE + 0xE)
+#define DEM_APPS_SWFI (SMEM_LOG_DEM_EVENT_BASE + 0xF)
+#define DEM_SEND_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0x10)
+#define DEM_ASSERT_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x11)
+#define DEM_NEGATE_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x12)
+#define DEM_PROC_COMM_CMD (SMEM_LOG_DEM_EVENT_BASE + 0x13)
+#define DEM_REMOVE_PROC_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x14)
+#define DEM_RESTORE_PROC_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x15)
+#define DEM_SMI_CLK_DISABLED (SMEM_LOG_DEM_EVENT_BASE + 0x16)
+#define DEM_SMI_CLK_ENABLED (SMEM_LOG_DEM_EVENT_BASE + 0x17)
+#define DEM_MAO_INTS (SMEM_LOG_DEM_EVENT_BASE + 0x18)
+#define DEM_APPS_WAKEUP_INT (SMEM_LOG_DEM_EVENT_BASE + 0x19)
+#define DEM_PROC_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0x1A)
+#define DEM_PROC_POWERUP (SMEM_LOG_DEM_EVENT_BASE + 0x1B)
+#define DEM_TIMER_EXPIRED (SMEM_LOG_DEM_EVENT_BASE + 0x1C)
+#define DEM_SEND_BATTERY_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x1D)
+#define DEM_REMOTE_PWR_CB (SMEM_LOG_DEM_EVENT_BASE + 0x24)
+#define DEM_TIME_SYNC_START (SMEM_LOG_DEM_EVENT_BASE + 0x1E)
+#define DEM_TIME_SYNC_SEND_VALUE (SMEM_LOG_DEM_EVENT_BASE + 0x1F)
+#define DEM_TIME_SYNC_DONE (SMEM_LOG_DEM_EVENT_BASE + 0x20)
+#define DEM_TIME_SYNC_REQUEST (SMEM_LOG_DEM_EVENT_BASE + 0x21)
+#define DEM_TIME_SYNC_POLL (SMEM_LOG_DEM_EVENT_BASE + 0x22)
+#define DEM_TIME_SYNC_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x23)
+#define DEM_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x25)
+#else
+#define DEM_NO_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 1)
+#define DEM_INSUF_TIME (SMEM_LOG_DEM_EVENT_BASE + 2)
+#define DEMAPPS_ENTER_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 3)
+#define DEMAPPS_DETECT_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 4)
+#define DEMAPPS_END_APPS_TCXO (SMEM_LOG_DEM_EVENT_BASE + 5)
+#define DEMAPPS_ENTER_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 6)
+#define DEMAPPS_END_APPS_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 7)
+#define DEMAPPS_SETUP_APPS_PWRCLPS (SMEM_LOG_DEM_EVENT_BASE + 8)
+#define DEMAPPS_PWRCLPS_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 9)
+#define DEMMOD_SEND_WAKEUP (SMEM_LOG_DEM_EVENT_BASE + 0xA)
+#define DEMMOD_NO_APPS_VOTE (SMEM_LOG_DEM_EVENT_BASE + 0xB)
+#define DEMMOD_NO_TCXO_SLEEP (SMEM_LOG_DEM_EVENT_BASE + 0xC)
+#define DEMMOD_BT_CLOCK (SMEM_LOG_DEM_EVENT_BASE + 0xD)
+#define DEMMOD_UART_CLOCK (SMEM_LOG_DEM_EVENT_BASE + 0xE)
+#define DEMMOD_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0xF)
+#define DEM_SLEEP_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x10)
+#define DEMMOD_TCXO_END (SMEM_LOG_DEM_EVENT_BASE + 0x11)
+#define DEMMOD_END_SLEEP_SIG (SMEM_LOG_DEM_EVENT_BASE + 0x12)
+#define DEMMOD_SETUP_APPSSLEEP (SMEM_LOG_DEM_EVENT_BASE + 0x13)
+#define DEMMOD_ENTER_TCXO (SMEM_LOG_DEM_EVENT_BASE + 0x14)
+#define DEMMOD_WAKE_APPS (SMEM_LOG_DEM_EVENT_BASE + 0x15)
+#define DEMMOD_POWER_COLLAPSE_APPS (SMEM_LOG_DEM_EVENT_BASE + 0x16)
+#define DEMMOD_RESTORE_APPS_PWR (SMEM_LOG_DEM_EVENT_BASE + 0x17)
+#define DEMAPPS_ASSERT_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x18)
+#define DEMAPPS_RESTART_START_TIMER (SMEM_LOG_DEM_EVENT_BASE + 0x19)
+#define DEMAPPS_ENTER_RUN (SMEM_LOG_DEM_EVENT_BASE + 0x1A)
+#define DEMMOD_MAO_INTS (SMEM_LOG_DEM_EVENT_BASE + 0x1B)
+#define DEMMOD_POWERUP_APPS_CALLED (SMEM_LOG_DEM_EVENT_BASE + 0x1C)
+#define DEMMOD_PC_TIMER_EXPIRED (SMEM_LOG_DEM_EVENT_BASE + 0x1D)
+#define DEM_DETECT_SLEEPEXIT (SMEM_LOG_DEM_EVENT_BASE + 0x1E)
+#define DEM_DETECT_RUN (SMEM_LOG_DEM_EVENT_BASE + 0x1F)
+#define DEM_SET_APPS_TIMER (SMEM_LOG_DEM_EVENT_BASE + 0x20)
+#define DEM_NEGATE_OKTS (SMEM_LOG_DEM_EVENT_BASE + 0x21)
+#define DEMMOD_APPS_WAKEUP_INT (SMEM_LOG_DEM_EVENT_BASE + 0x22)
+#define DEMMOD_APPS_SWFI (SMEM_LOG_DEM_EVENT_BASE + 0x23)
+#define DEM_SEND_BATTERY_INFO (SMEM_LOG_DEM_EVENT_BASE + 0x24)
+#define DEM_SMI_CLK_DISABLED (SMEM_LOG_DEM_EVENT_BASE + 0x25)
+#define DEM_SMI_CLK_ENABLED (SMEM_LOG_DEM_EVENT_BASE + 0x26)
+#define DEMAPPS_SETUP_APPS_SUSPEND (SMEM_LOG_DEM_EVENT_BASE + 0x27)
+#define DEM_RPC_EARLY_EXIT (SMEM_LOG_DEM_EVENT_BASE + 0x28)
+#define DEMAPPS_WAKEUP_REASON (SMEM_LOG_DEM_EVENT_BASE + 0x29)
+#define DEM_INIT (SMEM_LOG_DEM_EVENT_BASE + 0x30)
+#endif
+#define DEMMOD_UMTS_BASE (SMEM_LOG_DEM_EVENT_BASE + 0x8000)
+#define DEMMOD_GL1_GO_TO_SLEEP (DEMMOD_UMTS_BASE + 0x0000)
+#define DEMMOD_GL1_SLEEP_START (DEMMOD_UMTS_BASE + 0x0001)
+#define DEMMOD_GL1_AFTER_GSM_CLK_ON (DEMMOD_UMTS_BASE + 0x0002)
+#define DEMMOD_GL1_BEFORE_RF_ON (DEMMOD_UMTS_BASE + 0x0003)
+#define DEMMOD_GL1_AFTER_RF_ON (DEMMOD_UMTS_BASE + 0x0004)
+#define DEMMOD_GL1_FRAME_TICK (DEMMOD_UMTS_BASE + 0x0005)
+#define DEMMOD_GL1_WCDMA_START (DEMMOD_UMTS_BASE + 0x0006)
+#define DEMMOD_GL1_WCDMA_ENDING (DEMMOD_UMTS_BASE + 0x0007)
+#define DEMMOD_UMTS_NOT_OKTS (DEMMOD_UMTS_BASE + 0x0008)
+#define DEMMOD_UMTS_START_TCXO_SHUTDOWN (DEMMOD_UMTS_BASE + 0x0009)
+#define DEMMOD_UMTS_END_TCXO_SHUTDOWN (DEMMOD_UMTS_BASE + 0x000A)
+#define DEMMOD_UMTS_START_ARM_HALT (DEMMOD_UMTS_BASE + 0x000B)
+#define DEMMOD_UMTS_END_ARM_HALT (DEMMOD_UMTS_BASE + 0x000C)
+#define DEMMOD_UMTS_NEXT_WAKEUP_SCLK (DEMMOD_UMTS_BASE + 0x000D)
+#define TIME_REMOTE_LOG_EVENT_START (SMEM_LOG_TIMETICK_EVENT_BASE + 0)
+#define TIME_REMOTE_LOG_EVENT_GOTO_WAIT (SMEM_LOG_TIMETICK_EVENT_BASE + 1)
+#define TIME_REMOTE_LOG_EVENT_GOTO_INIT (SMEM_LOG_TIMETICK_EVENT_BASE + 2)
+#define ERR_ERROR_FATAL (SMEM_LOG_ERROR_EVENT_BASE + 1)
+#define ERR_ERROR_FATAL_TASK (SMEM_LOG_ERROR_EVENT_BASE + 2)
+#define DCVSAPPS_LOG_IDLE (SMEM_LOG_DCVS_EVENT_BASE + 0x0)
+#define DCVSAPPS_LOG_ERR (SMEM_LOG_DCVS_EVENT_BASE + 0x1)
+#define DCVSAPPS_LOG_CHG (SMEM_LOG_DCVS_EVENT_BASE + 0x2)
+#define DCVSAPPS_LOG_REG (SMEM_LOG_DCVS_EVENT_BASE + 0x3)
+#define DCVSAPPS_LOG_DEREG (SMEM_LOG_DCVS_EVENT_BASE + 0x4)
+#define SMEM_LOG_EVENT_CB (SMEM_LOG_SMEM_EVENT_BASE + 0)
+#define SMEM_LOG_EVENT_START (SMEM_LOG_SMEM_EVENT_BASE + 1)
+#define SMEM_LOG_EVENT_INIT (SMEM_LOG_SMEM_EVENT_BASE + 2)
+#define SMEM_LOG_EVENT_RUNNING (SMEM_LOG_SMEM_EVENT_BASE + 3)
+#define SMEM_LOG_EVENT_STOP (SMEM_LOG_SMEM_EVENT_BASE + 4)
+#define SMEM_LOG_EVENT_RESTART (SMEM_LOG_SMEM_EVENT_BASE + 5)
+#define SMEM_LOG_EVENT_SS (SMEM_LOG_SMEM_EVENT_BASE + 6)
+#define SMEM_LOG_EVENT_READ (SMEM_LOG_SMEM_EVENT_BASE + 7)
+#define SMEM_LOG_EVENT_WRITE (SMEM_LOG_SMEM_EVENT_BASE + 8)
+#define SMEM_LOG_EVENT_SIGS1 (SMEM_LOG_SMEM_EVENT_BASE + 9)
+#define SMEM_LOG_EVENT_SIGS2 (SMEM_LOG_SMEM_EVENT_BASE + 10)
+#define SMEM_LOG_EVENT_WRITE_DM (SMEM_LOG_SMEM_EVENT_BASE + 11)
+#define SMEM_LOG_EVENT_READ_DM (SMEM_LOG_SMEM_EVENT_BASE + 12)
+#define SMEM_LOG_EVENT_SKIP_DM (SMEM_LOG_SMEM_EVENT_BASE + 13)
+#define SMEM_LOG_EVENT_STOP_DM (SMEM_LOG_SMEM_EVENT_BASE + 14)
+#define SMEM_LOG_EVENT_ISR (SMEM_LOG_SMEM_EVENT_BASE + 15)
+#define SMEM_LOG_EVENT_TASK (SMEM_LOG_SMEM_EVENT_BASE + 16)
+#define SMEM_LOG_EVENT_RS (SMEM_LOG_SMEM_EVENT_BASE + 17)
+#define ONCRPC_LOG_EVENT_SMD_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 0)
+#define ONCRPC_LOG_EVENT_RPC_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 1)
+#define ONCRPC_LOG_EVENT_RPC_BOTH_WAIT (SMEM_LOG_ONCRPC_EVENT_BASE + 2)
+#define ONCRPC_LOG_EVENT_RPC_INIT (SMEM_LOG_ONCRPC_EVENT_BASE + 3)
+#define ONCRPC_LOG_EVENT_RUNNING (SMEM_LOG_ONCRPC_EVENT_BASE + 4)
+#define ONCRPC_LOG_EVENT_APIS_INITED (SMEM_LOG_ONCRPC_EVENT_BASE + 5)
+#define ONCRPC_LOG_EVENT_AMSS_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 6)
+#define ONCRPC_LOG_EVENT_SMD_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 7)
+#define ONCRPC_LOG_EVENT_ONCRPC_RESET (SMEM_LOG_ONCRPC_EVENT_BASE + 8)
+#define ONCRPC_LOG_EVENT_CB (SMEM_LOG_ONCRPC_EVENT_BASE + 9)
+#define ONCRPC_LOG_EVENT_STD_CALL (SMEM_LOG_ONCRPC_EVENT_BASE + 10)
+#define ONCRPC_LOG_EVENT_STD_REPLY (SMEM_LOG_ONCRPC_EVENT_BASE + 11)
+#define ONCRPC_LOG_EVENT_STD_CALL_ASYNC (SMEM_LOG_ONCRPC_EVENT_BASE + 12)
+#define NO_SLEEP_OLD (SMEM_LOG_SLEEP_EVENT_BASE + 0x1)
+#define INSUF_TIME (SMEM_LOG_SLEEP_EVENT_BASE + 0x2)
+#define MOD_UART_CLOCK (SMEM_LOG_SLEEP_EVENT_BASE + 0x3)
+#define SLEEP_INFO (SMEM_LOG_SLEEP_EVENT_BASE + 0x4)
+#define MOD_TCXO_END (SMEM_LOG_SLEEP_EVENT_BASE + 0x5)
+#define MOD_ENTER_TCXO (SMEM_LOG_SLEEP_EVENT_BASE + 0x6)
+#define NO_SLEEP_NEW (SMEM_LOG_SLEEP_EVENT_BASE + 0x7)
+#define RPC_ROUTER_LOG_EVENT_UNKNOWN (SMEM_LOG_RPC_ROUTER_EVENT_BASE)
+#define RPC_ROUTER_LOG_EVENT_MSG_READ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 1)
+#define RPC_ROUTER_LOG_EVENT_MSG_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 2)
+#define RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 3)
+#define RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 4)
+#define RPC_ROUTER_LOG_EVENT_MID_READ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 5)
+#define RPC_ROUTER_LOG_EVENT_MID_WRITTEN (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 6)
+#define RPC_ROUTER_LOG_EVENT_MID_CFM_REQ (SMEM_LOG_RPC_ROUTER_EVENT_BASE + 7)
+
+#ifdef CONFIG_MSM_SMD_LOGGING
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3);
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6);
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3);
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6);
+#else
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3) { }
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6) { }
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3) { }
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6) { }
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/system.h b/arch/arm/mach-msm/include/mach/system.h
index 574ccc493daf..d2e83f42ba16 100644
--- a/arch/arm/mach-msm/include/mach/system.h
+++ b/arch/arm/mach-msm/include/mach/system.h
@@ -21,3 +21,8 @@ static inline void arch_reset(char mode, const char *cmd)
{
for (;;) ; /* depends on IPC w/ other core */
}
+
+/* low level hardware reset hook -- for example, hitting the
+ * PSHOLD line on the PMIC to hard reset the system
+ */
+extern void (*msm_hw_reset_hook)(void);
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index d94292c29d8e..6d1a2e82fc3f 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -15,7 +15,6 @@
#ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
-#include "hardware.h"
#include "linux/io.h"
#include "mach/msm_iomap.h"
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
new file mode 100644
index 000000000000..a2b89650f4c9
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -0,0 +1,44 @@
+/* include/asm-arm/arch-msm/usbdiag.h
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * 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, you can find it at http://www.fsf.org
+ */
+
+#ifndef _DRIVERS_USB_DIAG_H_
+#define _DRIVERS_USB_DIAG_H_
+#define ENOREQ -1
+struct diag_operations {
+
+ int (*diag_connect)(void);
+ int (*diag_disconnect)(void);
+ int (*diag_char_write_complete)(unsigned char * , int, int);
+ int (*diag_char_read_complete)(unsigned char *, int , int);
+};
+
+struct diag_request {
+ char *buf;
+ int length;
+};
+int diag_open(int);
+void diag_close(void);
+int diag_read(unsigned char *, int);
+int diag_write(unsigned char *, int);
+
+int diag_usb_register(struct diag_operations *);
+int diag_usb_unregister(void);
+int diag_read_from_cb(unsigned char * , int);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/vmalloc.h b/arch/arm/mach-msm/include/mach/vmalloc.h
index 05f81fd8623c..9d8c8375b206 100644
--- a/arch/arm/mach-msm/include/mach/vmalloc.h
+++ b/arch/arm/mach-msm/include/mach/vmalloc.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/vmalloc.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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
@@ -16,7 +17,11 @@
#ifndef __ASM_ARCH_MSM_VMALLOC_H
#define __ASM_ARCH_MSM_VMALLOC_H
-#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
+#ifdef CONFIG_VMSPLIT_2G
+#define VMALLOC_END (PAGE_OFFSET + 0x60000000)
+#else
+#define VMALLOC_END (PAGE_OFFSET + 0x20000000)
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/vreg.h b/arch/arm/mach-msm/include/mach/vreg.h
index 9f9e25cb718e..6626e7864e28 100644
--- a/arch/arm/mach-msm/include/mach/vreg.h
+++ b/arch/arm/mach-msm/include/mach/vreg.h
@@ -23,7 +23,7 @@ struct vreg *vreg_get(struct device *dev, const char *id);
void vreg_put(struct vreg *vreg);
int vreg_enable(struct vreg *vreg);
-void vreg_disable(struct vreg *vreg);
+int vreg_disable(struct vreg *vreg);
int vreg_set_level(struct vreg *vreg, unsigned mv);
#endif
diff --git a/arch/arm/mach-msm/internal_power_rail.c b/arch/arm/mach-msm/internal_power_rail.c
new file mode 100644
index 000000000000..c2c5e5bed9ce
--- /dev/null
+++ b/arch/arm/mach-msm/internal_power_rail.c
@@ -0,0 +1,90 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <mach/internal_power_rail.h>
+
+#include "proc_comm.h"
+
+/* Enable or disable an internal power rail */
+int internal_pwr_rail_ctl(unsigned rail_id, bool enable)
+{
+ int cmd, rc;
+
+ cmd = enable ? PCOM_CLKCTL_RPC_RAIL_ENABLE :
+ PCOM_CLKCTL_RPC_RAIL_DISABLE;
+
+ rc = msm_proc_comm(cmd, &rail_id, NULL);
+
+ return rc;
+
+}
+EXPORT_SYMBOL(internal_pwr_rail_ctl);
+
+/* Specify an internal power rail control mode (ex. auto, manual) */
+int internal_pwr_rail_mode(unsigned rail_id, enum rail_ctl_mode mode)
+{
+ int rc;
+
+ rc = msm_proc_comm(PCOM_CLKCTL_RPC_RAIL_CONTROL, &rail_id, &mode);
+
+ return rc;
+}
+EXPORT_SYMBOL(internal_pwr_rail_mode);
+
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1c5e7dac086f..39a99a3a0f6b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -1,8 +1,9 @@
/* arch/arm/mach-msm/io.c
*
- * MSM7K io support
+ * MSM7K, QSD io support
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -19,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <mach/hardware.h>
#include <asm/page.h>
@@ -34,10 +36,28 @@
.type = MT_DEVICE_NONSHARED, \
}
+/* msm_shared_ram_phys default value of 0x00100000 is the most common value
+ * and should work as-is for any target without stacked memory.
+ */
+int msm_shared_ram_phys = 0x00100000;
+
+static void msm_map_io(struct map_desc *io_desc, int size)
+{
+ int i;
+
+ BUG_ON(!size);
+ for (i = 0; i < size; i++)
+ if (io_desc[i].virtual == (unsigned long)MSM_SHARED_RAM_BASE)
+ io_desc[i].pfn = __phys_to_pfn(msm_shared_ram_phys);
+
+ iotable_init(io_desc, size);
+}
+
+#if defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7X27)
static struct map_desc msm_io_desc[] __initdata = {
MSM_DEVICE(VIC),
MSM_DEVICE(CSR),
- MSM_DEVICE(GPT),
+ MSM_DEVICE(TMR),
MSM_DEVICE(DMOV),
MSM_DEVICE(GPIO1),
MSM_DEVICE(GPIO2),
@@ -45,9 +65,16 @@ static struct map_desc msm_io_desc[] __initdata = {
#ifdef CONFIG_MSM_DEBUG_UART
MSM_DEVICE(DEBUG_UART),
#endif
+#ifdef CONFIG_CACHE_L2X0
+ {
+ .virtual = (unsigned long) MSM_L2CC_BASE,
+ .pfn = __phys_to_pfn(MSM_L2CC_PHYS),
+ .length = MSM_L2CC_SIZE,
+ .type = MT_DEVICE,
+ },
+#endif
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
- .pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
.length = MSM_SHARED_RAM_SIZE,
.type = MT_DEVICE,
},
@@ -60,9 +87,98 @@ void __init msm_map_common_io(void)
* pages are peripheral interface or not.
*/
asm("mcr p15, 0, %0, c15, c2, 4" : : "r" (0));
+ msm_map_io(msm_io_desc, ARRAY_SIZE(msm_io_desc));
+}
+#endif
+
+#ifdef CONFIG_ARCH_QSD8X50
+static struct map_desc qsd8x50_io_desc[] __initdata = {
+ MSM_DEVICE(VIC),
+ MSM_DEVICE(CSR),
+ MSM_DEVICE(TMR),
+ MSM_DEVICE(DMOV),
+ MSM_DEVICE(GPIO1),
+ MSM_DEVICE(GPIO2),
+ MSM_DEVICE(CLK_CTL),
+ MSM_DEVICE(SIRC),
+ MSM_DEVICE(SCPLL),
+ MSM_DEVICE(AD5),
+ MSM_DEVICE(MDC),
+#ifdef CONFIG_MSM_DEBUG_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_qsd8x50_io(void)
+{
+ msm_map_io(qsd8x50_io_desc, ARRAY_SIZE(qsd8x50_io_desc));
+}
+#endif /* CONFIG_ARCH_QSD8X50 */
+
+#ifdef CONFIG_ARCH_MSM7X30
+static struct map_desc msm7x30_io_desc[] __initdata = {
+ MSM_DEVICE(VIC),
+ MSM_DEVICE(CSR),
+ MSM_DEVICE(TMR),
+ MSM_DEVICE(DMOV),
+ MSM_DEVICE(GPIO1),
+ MSM_DEVICE(GPIO2),
+ MSM_DEVICE(CLK_CTL),
+ MSM_DEVICE(SIRC),
+ MSM_DEVICE(SCPLL),
+ MSM_DEVICE(AD5),
+ MSM_DEVICE(MDC),
+ MSM_DEVICE(ACC),
+ MSM_DEVICE(GCC),
+#ifdef CONFIG_MSM_DEBUG_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_msm7x30_io(void)
+{
+ msm_map_io(msm7x30_io_desc, ARRAY_SIZE(msm7x30_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM7X30 */
- iotable_init(msm_io_desc, ARRAY_SIZE(msm_io_desc));
+#ifdef CONFIG_MACH_QSD8X50_COMET
+static struct map_desc comet_io_desc[] __initdata = {
+ MSM_DEVICE(VIC),
+ MSM_DEVICE(CSR),
+ MSM_DEVICE(TMR),
+ MSM_DEVICE(DMOV),
+ MSM_DEVICE(GPIO1),
+ MSM_DEVICE(GPIO2),
+ MSM_DEVICE(CLK_CTL),
+ MSM_DEVICE(SIRC),
+ MSM_DEVICE(SCPLL),
+ MSM_DEVICE(AD5),
+ MSM_DEVICE(MDC),
+#ifdef CONFIG_MSM_DEBUG_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_comet_io(void)
+{
+ msm_map_io(comet_io_desc, ARRAY_SIZE(comet_io_desc));
}
+#endif /* CONFIG_MACH_QSD8X50_COMET */
void __iomem *
__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
@@ -76,5 +192,7 @@ __msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
mtype = MT_DEVICE_NONSHARED;
}
- return __arm_ioremap(phys_addr, size, mtype);
+ return __arm_ioremap_caller(phys_addr, size, mtype,
+ __builtin_return_address(0));
}
+EXPORT_SYMBOL(__msm_ioremap);
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
index 69ca0dd79bdf..03687ab2c223 100644
--- a/arch/arm/mach-msm/irq.c
+++ b/arch/arm/mach-msm/irq.c
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/irq.c
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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
@@ -22,96 +23,504 @@
#include <linux/irq.h>
#include <linux/io.h>
+#include <asm/cacheflush.h>
+
#include <mach/hardware.h>
#include <mach/msm_iomap.h>
+#include <mach/fiq.h>
+
+#include "smd_private.h"
+
+enum {
+ IRQ_DEBUG_SLEEP_INT_TRIGGER = 1U << 0,
+ IRQ_DEBUG_SLEEP_INT = 1U << 1,
+ IRQ_DEBUG_SLEEP_ABORT = 1U << 2,
+ IRQ_DEBUG_SLEEP = 1U << 3,
+ IRQ_DEBUG_SLEEP_REQUEST = 1U << 4,
+};
+static int msm_irq_debug_mask;
+module_param_named(debug_mask, msm_irq_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
#define VIC_REG(off) (MSM_VIC_BASE + (off))
+#define VIC_INT_TO_REG_ADDR(base, irq) (base + (irq / 32) * 4)
+#define VIC_INT_TO_REG_INDEX(irq) ((irq >> 5) & 3)
#define VIC_INT_SELECT0 VIC_REG(0x0000) /* 1: FIQ, 0: IRQ */
#define VIC_INT_SELECT1 VIC_REG(0x0004) /* 1: FIQ, 0: IRQ */
+#define VIC_INT_SELECT2 VIC_REG(0x0008) /* 1: FIQ, 0: IRQ */
+#define VIC_INT_SELECT3 VIC_REG(0x000C) /* 1: FIQ, 0: IRQ */
#define VIC_INT_EN0 VIC_REG(0x0010)
#define VIC_INT_EN1 VIC_REG(0x0014)
+#define VIC_INT_EN2 VIC_REG(0x0018)
+#define VIC_INT_EN3 VIC_REG(0x001C)
#define VIC_INT_ENCLEAR0 VIC_REG(0x0020)
#define VIC_INT_ENCLEAR1 VIC_REG(0x0024)
+#define VIC_INT_ENCLEAR2 VIC_REG(0x0028)
+#define VIC_INT_ENCLEAR3 VIC_REG(0x002C)
#define VIC_INT_ENSET0 VIC_REG(0x0030)
#define VIC_INT_ENSET1 VIC_REG(0x0034)
+#define VIC_INT_ENSET2 VIC_REG(0x0038)
+#define VIC_INT_ENSET3 VIC_REG(0x003C)
#define VIC_INT_TYPE0 VIC_REG(0x0040) /* 1: EDGE, 0: LEVEL */
#define VIC_INT_TYPE1 VIC_REG(0x0044) /* 1: EDGE, 0: LEVEL */
+#define VIC_INT_TYPE2 VIC_REG(0x0048) /* 1: EDGE, 0: LEVEL */
+#define VIC_INT_TYPE3 VIC_REG(0x004C) /* 1: EDGE, 0: LEVEL */
#define VIC_INT_POLARITY0 VIC_REG(0x0050) /* 1: NEG, 0: POS */
#define VIC_INT_POLARITY1 VIC_REG(0x0054) /* 1: NEG, 0: POS */
+#define VIC_INT_POLARITY2 VIC_REG(0x0058) /* 1: NEG, 0: POS */
+#define VIC_INT_POLARITY3 VIC_REG(0x005C) /* 1: NEG, 0: POS */
#define VIC_NO_PEND_VAL VIC_REG(0x0060)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define VIC_NO_PEND_VAL_FIQ VIC_REG(0x0064)
+#define VIC_INT_MASTEREN VIC_REG(0x0068) /* 1: IRQ, 2: FIQ */
+#define VIC_CONFIG VIC_REG(0x006C) /* 1: USE SC VIC */
+#else
#define VIC_INT_MASTEREN VIC_REG(0x0064) /* 1: IRQ, 2: FIQ */
#define VIC_PROTECTION VIC_REG(0x006C) /* 1: ENABLE */
#define VIC_CONFIG VIC_REG(0x0068) /* 1: USE ARM1136 VIC */
+#endif
+
#define VIC_IRQ_STATUS0 VIC_REG(0x0080)
#define VIC_IRQ_STATUS1 VIC_REG(0x0084)
+#define VIC_IRQ_STATUS2 VIC_REG(0x0088)
+#define VIC_IRQ_STATUS3 VIC_REG(0x008C)
#define VIC_FIQ_STATUS0 VIC_REG(0x0090)
#define VIC_FIQ_STATUS1 VIC_REG(0x0094)
+#define VIC_FIQ_STATUS2 VIC_REG(0x0098)
+#define VIC_FIQ_STATUS3 VIC_REG(0x009C)
#define VIC_RAW_STATUS0 VIC_REG(0x00A0)
#define VIC_RAW_STATUS1 VIC_REG(0x00A4)
+#define VIC_RAW_STATUS2 VIC_REG(0x00A8)
+#define VIC_RAW_STATUS3 VIC_REG(0x00AC)
#define VIC_INT_CLEAR0 VIC_REG(0x00B0)
#define VIC_INT_CLEAR1 VIC_REG(0x00B4)
+#define VIC_INT_CLEAR2 VIC_REG(0x00B8)
+#define VIC_INT_CLEAR3 VIC_REG(0x00BC)
#define VIC_SOFTINT0 VIC_REG(0x00C0)
#define VIC_SOFTINT1 VIC_REG(0x00C4)
+#define VIC_SOFTINT2 VIC_REG(0x00C8)
+#define VIC_SOFTINT3 VIC_REG(0x00CC)
#define VIC_IRQ_VEC_RD VIC_REG(0x00D0) /* pending int # */
#define VIC_IRQ_VEC_PEND_RD VIC_REG(0x00D4) /* pending vector addr */
#define VIC_IRQ_VEC_WR VIC_REG(0x00D8)
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+#define VIC_FIQ_VEC_RD VIC_REG(0x00DC)
+#define VIC_FIQ_VEC_PEND_RD VIC_REG(0x00E0)
+#define VIC_FIQ_VEC_WR VIC_REG(0x00E4)
+#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E8)
+#define VIC_IRQ_IN_STACK VIC_REG(0x00EC)
+#define VIC_FIQ_IN_SERVICE VIC_REG(0x00F0)
+#define VIC_FIQ_IN_STACK VIC_REG(0x00F4)
+#define VIC_TEST_BUS_SEL VIC_REG(0x00F8)
+#define VIC_IRQ_CTRL_CONFIG VIC_REG(0x00FC)
+#else
#define VIC_IRQ_IN_SERVICE VIC_REG(0x00E0)
#define VIC_IRQ_IN_STACK VIC_REG(0x00E4)
#define VIC_TEST_BUS_SEL VIC_REG(0x00E8)
+#endif
#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
#define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4))
+#if defined(CONFIG_ARCH_MSM7X30)
+#define VIC_NUM_REGS 4
+#else
+#define VIC_NUM_REGS 2
+#endif
+
+#if VIC_NUM_REGS == 2
+#define DPRINT_REGS(base_reg, format, ...) \
+ printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \
+ readl(base_reg ## 0), readl(base_reg ## 1))
+#define DPRINT_ARRAY(array, format, ...) \
+ printk(KERN_INFO format " %x %x\n", ##__VA_ARGS__, \
+ array[0], array[1])
+#elif VIC_NUM_REGS == 4
+#define DPRINT_REGS(base_reg, format, ...) \
+ printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \
+ readl(base_reg ## 0), readl(base_reg ## 1), \
+ readl(base_reg ## 2), readl(base_reg ## 3))
+#define DPRINT_ARRAY(array, format, ...) \
+ printk(KERN_INFO format " %x %x %x %x\n", ##__VA_ARGS__, \
+ array[0], array[1], \
+ array[2], array[3])
+#else
+#error "VIC_NUM_REGS set to illegal value"
+#endif
+
+static uint32_t msm_irq_smsm_wake_enable[2];
+static struct {
+ uint32_t int_en[2];
+ uint32_t int_type;
+ uint32_t int_polarity;
+ uint32_t int_select;
+} msm_irq_shadow_reg[VIC_NUM_REGS];
+static uint32_t msm_irq_idle_disable[VIC_NUM_REGS];
+
+#define SMSM_FAKE_IRQ (0xff)
+static uint8_t msm_irq_to_smsm[NR_IRQS] = {
+ [INT_MDDI_EXT] = 1,
+ [INT_MDDI_PRI] = 2,
+ [INT_MDDI_CLIENT] = 3,
+ [INT_USB_OTG] = 4,
+
+ [INT_PWB_I2C] = 5,
+ [INT_SDC1_0] = 6,
+ [INT_SDC1_1] = 7,
+ [INT_SDC2_0] = 8,
+
+ [INT_SDC2_1] = 9,
+ [INT_ADSP_A9_A11] = 10,
+ [INT_UART1] = 11,
+ [INT_UART2] = 12,
+
+ [INT_UART3] = 13,
+ [INT_UART1_RX] = 14,
+ [INT_UART2_RX] = 15,
+ [INT_UART3_RX] = 16,
+
+ [INT_UART1DM_IRQ] = 17,
+ [INT_UART1DM_RX] = 18,
+ [INT_KEYSENSE] = 19,
+#if !defined(CONFIG_ARCH_MSM7X30)
+ [INT_AD_HSSD] = 20,
+#endif
+
+ [INT_NAND_WR_ER_DONE] = 21,
+ [INT_NAND_OP_DONE] = 22,
+ [INT_TCHSCRN1] = 23,
+ [INT_TCHSCRN2] = 24,
+
+ [INT_TCHSCRN_SSBI] = 25,
+ [INT_USB_HS] = 26,
+ [INT_UART2DM_RX] = 27,
+ [INT_UART2DM_IRQ] = 28,
+
+ [INT_SDC4_1] = 29,
+ [INT_SDC4_0] = 30,
+ [INT_SDC3_1] = 31,
+ [INT_SDC3_0] = 32,
+
+ /* fake wakeup interrupts */
+ [INT_GPIO_GROUP1] = SMSM_FAKE_IRQ,
+ [INT_GPIO_GROUP2] = SMSM_FAKE_IRQ,
+ [INT_A9_M2A_0] = SMSM_FAKE_IRQ,
+ [INT_A9_M2A_1] = SMSM_FAKE_IRQ,
+ [INT_A9_M2A_5] = SMSM_FAKE_IRQ,
+ [INT_GP_TIMER_EXP] = SMSM_FAKE_IRQ,
+ [INT_DEBUG_TIMER_EXP] = SMSM_FAKE_IRQ,
+ [INT_ADSP_A11] = SMSM_FAKE_IRQ,
+#ifdef CONFIG_ARCH_QSD8X50
+ [INT_SIRC_0] = SMSM_FAKE_IRQ,
+ [INT_SIRC_1] = SMSM_FAKE_IRQ,
+#endif
+};
+
+static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val)
+{
+ int i;
+
+ for (i = 0; i < VIC_NUM_REGS; i++)
+ writel(val, base + (i * 4));
+}
+
static void msm_irq_ack(unsigned int irq)
{
- void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, irq);
irq = 1 << (irq & 31);
writel(irq, reg);
}
static void msm_irq_mask(unsigned int irq)
{
- void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
- writel(1 << (irq & 31), reg);
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
+ uint32_t mask = 1UL << (irq & 31);
+ int smsm_irq = msm_irq_to_smsm[irq];
+
+ msm_irq_shadow_reg[index].int_en[0] &= ~mask;
+ writel(mask, reg);
+ if (smsm_irq == 0)
+ msm_irq_idle_disable[index] &= ~mask;
+ else {
+ mask = 1UL << (smsm_irq - 1);
+ msm_irq_smsm_wake_enable[0] &= ~mask;
+ }
}
static void msm_irq_unmask(unsigned int irq)
{
- void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
- writel(1 << (irq & 31), reg);
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
+ uint32_t mask = 1UL << (irq & 31);
+ int smsm_irq = msm_irq_to_smsm[irq];
+
+ msm_irq_shadow_reg[index].int_en[0] |= mask;
+ writel(mask, reg);
+
+ if (smsm_irq == 0)
+ msm_irq_idle_disable[index] |= mask;
+ else {
+ mask = 1UL << (smsm_irq - 1);
+ msm_irq_smsm_wake_enable[0] |= mask;
+ }
}
static int msm_irq_set_wake(unsigned int irq, unsigned int on)
{
- return -EINVAL;
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
+ uint32_t mask = 1UL << (irq & 31);
+ int smsm_irq = msm_irq_to_smsm[irq];
+
+ if (smsm_irq == 0) {
+ printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
+ return -EINVAL;
+ }
+ if (on)
+ msm_irq_shadow_reg[index].int_en[1] |= mask;
+ else
+ msm_irq_shadow_reg[index].int_en[1] &= ~mask;
+
+ if (smsm_irq == SMSM_FAKE_IRQ)
+ return 0;
+
+ mask = 1UL << (smsm_irq - 1);
+ if (on)
+ msm_irq_smsm_wake_enable[1] |= mask;
+ else
+ msm_irq_smsm_wake_enable[1] &= ~mask;
+ return 0;
}
static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
{
- void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
- void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
+ void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, irq);
+ void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
int b = 1 << (irq & 31);
+ uint32_t polarity;
+ uint32_t type;
+ polarity = msm_irq_shadow_reg[index].int_polarity;
if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
- writel(readl(preg) | b, preg);
+ polarity |= b;
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
- writel(readl(preg) & (~b), preg);
+ polarity &= ~b;
+ writel(polarity, preg);
+ msm_irq_shadow_reg[index].int_polarity = polarity;
+ type = msm_irq_shadow_reg[index].int_type;
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
- writel(readl(treg) | b, treg);
- set_irq_handler(irq, handle_edge_irq);
+ type |= b;
+ irq_desc[irq].handle_irq = handle_edge_irq;
}
if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
- writel(readl(treg) & (~b), treg);
- set_irq_handler(irq, handle_level_irq);
+ type &= ~b;
+ irq_desc[irq].handle_irq = handle_level_irq;
+ }
+ writel(type, treg);
+ msm_irq_shadow_reg[index].int_type = type;
+ return 0;
+}
+
+unsigned int msm_irq_pending(void)
+{
+ unsigned int i, pending = 0;
+
+ for (i = 0; (i < VIC_NUM_REGS) && !pending; i++)
+ pending |= readl(VIC_IRQ_STATUS0 + (i * 4));
+
+ return pending;
+}
+
+int msm_irq_idle_sleep_allowed(void)
+{
+ uint32_t i, disable = 0;
+
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_REQUEST)
+ DPRINT_ARRAY(msm_irq_idle_disable,
+ "msm_irq_idle_sleep_allowed: disable");
+
+ for (i = 0; i < VIC_NUM_REGS; i++)
+ disable |= msm_irq_idle_disable[i];
+
+ return !disable;
+}
+
+/*
+ * Prepare interrupt subsystem for entering sleep -- phase 1.
+ * If modem_wake is true, return currently enabled interrupts in *irq_mask.
+ */
+void msm_irq_enter_sleep1(bool modem_wake, int from_idle, uint32_t *irq_mask)
+{
+ if (modem_wake) {
+ *irq_mask = msm_irq_smsm_wake_enable[!from_idle];
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+ printk(KERN_INFO
+ "%s irq_mask %x\n", __func__, *irq_mask);
+ }
+}
+
+/*
+ * Prepare interrupt subsystem for entering sleep -- phase 2.
+ * Detect any pending interrupts and configure interrupt hardware.
+ *
+ * Return value:
+ * -EAGAIN: there are pending interrupt(s); interrupt configuration
+ * is not changed.
+ * 0: success
+ */
+int msm_irq_enter_sleep2(bool modem_wake, int from_idle)
+{
+ int i, limit = 10;
+ uint32_t pending[VIC_NUM_REGS];
+
+ if (from_idle && !modem_wake)
+ return 0;
+
+ /* edge triggered interrupt may get lost if this mode is used */
+ WARN_ON_ONCE(!modem_wake && !from_idle);
+
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+ DPRINT_REGS(VIC_IRQ_STATUS, "%s change irq, pend", __func__);
+
+ for (i = 0; i < VIC_NUM_REGS; i++) {
+ pending[i] = readl(VIC_IRQ_STATUS0 + (i * 4));
+ pending[i] &= msm_irq_shadow_reg[i].int_en[!from_idle];
}
+
+ /* Clear INT_A9_M2A_5 since requesting sleep triggers it */
+ pending[0] &= ~(1U << INT_A9_M2A_5);
+
+ for (i = 0; i < VIC_NUM_REGS; i++) {
+ if (pending[i]) {
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_ABORT)
+ DPRINT_ARRAY(pending, "%s abort",
+ __func__);
+ return -EAGAIN;
+ }
+ }
+
+ msm_irq_write_all_regs(VIC_INT_EN0, 0);
+
+ while (limit-- > 0) {
+ int pend_irq;
+ int irq = readl(VIC_IRQ_VEC_RD);
+ if (irq == -1)
+ break;
+ pend_irq = readl(VIC_IRQ_VEC_PEND_RD);
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+ printk(KERN_INFO "%s cleared int %d (%d)\n",
+ __func__, irq, pend_irq);
+ }
+
+ if (modem_wake) {
+ msm_irq_set_type(INT_A9_M2A_6, IRQF_TRIGGER_RISING);
+ writel(1U << INT_A9_M2A_6, VIC_INT_ENSET0);
+ } else {
+ for (i = 0; i < VIC_NUM_REGS; i++)
+ writel(msm_irq_shadow_reg[i].int_en[1],
+ VIC_INT_ENSET0 + (i * 4));
+ }
+
return 0;
}
+/*
+ * Restore interrupt subsystem from sleep -- phase 1.
+ * Configure interrupt hardware.
+ */
+void msm_irq_exit_sleep1(uint32_t irq_mask, uint32_t wakeup_reason,
+ uint32_t pending_irqs)
+{
+ int i;
+
+ msm_irq_ack(INT_A9_M2A_6);
+
+ for (i = 0; i < VIC_NUM_REGS; i++) {
+ writel(msm_irq_shadow_reg[i].int_type,
+ VIC_INT_TYPE0 + i * 4);
+ writel(msm_irq_shadow_reg[i].int_polarity,
+ VIC_INT_POLARITY0 + i * 4);
+ writel(msm_irq_shadow_reg[i].int_en[0],
+ VIC_INT_EN0 + i * 4);
+ writel(msm_irq_shadow_reg[i].int_select,
+ VIC_INT_SELECT0 + i * 4);
+ }
+
+ writel(3, VIC_INT_MASTEREN);
+
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+ DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now",
+ __func__, irq_mask, pending_irqs, wakeup_reason);
+}
+
+/*
+ * Restore interrupt subsystem from sleep -- phase 2.
+ * Poke the specified pending interrupts into interrupt hardware.
+ */
+void msm_irq_exit_sleep2(uint32_t irq_mask, uint32_t wakeup_reason,
+ uint32_t pending)
+{
+ int i;
+
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+ DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x now",
+ __func__, irq_mask, pending, wakeup_reason);
+
+ for (i = 0; pending && i < ARRAY_SIZE(msm_irq_to_smsm); i++) {
+ unsigned reg_offset = VIC_INT_TO_REG_ADDR(0, i);
+ uint32_t reg_mask = 1UL << (i & 31);
+ int smsm_irq = msm_irq_to_smsm[i];
+ uint32_t smsm_mask;
+
+ if (smsm_irq == 0)
+ continue;
+
+ smsm_mask = 1U << (smsm_irq - 1);
+ if (!(pending & smsm_mask))
+ continue;
+
+ pending &= ~smsm_mask;
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT)
+ DPRINT_REGS(VIC_IRQ_STATUS,
+ "%s: irq %d still pending %x now",
+ __func__, i, pending);
+#if 0 /* debug intetrrupt trigger */
+ if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+ writel(reg_mask, VIC_INT_CLEAR0 + reg_offset);
+#endif
+ if (readl(VIC_IRQ_STATUS0 + reg_offset) & reg_mask)
+ continue;
+
+ writel(reg_mask, VIC_SOFTINT0 + reg_offset);
+
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP_INT_TRIGGER)
+ DPRINT_REGS(VIC_IRQ_STATUS,
+ "%s: irq %d need trigger, now",
+ __func__, i);
+ }
+}
+
+/*
+ * Restore interrupt subsystem from sleep -- phase 3.
+ * Print debug information.
+ */
+void msm_irq_exit_sleep3(uint32_t irq_mask, uint32_t wakeup_reason,
+ uint32_t pending_irqs)
+{
+ if (msm_irq_debug_mask & IRQ_DEBUG_SLEEP)
+ DPRINT_REGS(VIC_IRQ_STATUS, "%s %x %x %x state %x now",
+ __func__, irq_mask, pending_irqs, wakeup_reason,
+ smsm_get_state(SMSM_MODEM_STATE));
+}
+
static struct irq_chip msm_irq_chip = {
.name = "msm",
+ .disable = msm_irq_mask,
.ack = msm_irq_ack,
.mask = msm_irq_mask,
.unmask = msm_irq_unmask,
@@ -124,26 +533,22 @@ void __init msm_init_irq(void)
unsigned n;
/* select level interrupts */
- writel(0, VIC_INT_TYPE0);
- writel(0, VIC_INT_TYPE1);
+ msm_irq_write_all_regs(VIC_INT_TYPE0, 0);
/* select highlevel interrupts */
- writel(0, VIC_INT_POLARITY0);
- writel(0, VIC_INT_POLARITY1);
+ msm_irq_write_all_regs(VIC_INT_POLARITY0, 0);
/* select IRQ for all INTs */
- writel(0, VIC_INT_SELECT0);
- writel(0, VIC_INT_SELECT1);
+ msm_irq_write_all_regs(VIC_INT_SELECT0, 0);
/* disable all INTs */
- writel(0, VIC_INT_EN0);
- writel(0, VIC_INT_EN1);
+ msm_irq_write_all_regs(VIC_INT_EN0, 0);
- /* don't use 1136 vic */
+ /* don't use vic */
writel(0, VIC_CONFIG);
/* enable interrupt controller */
- writel(1, VIC_INT_MASTEREN);
+ writel(3, VIC_INT_MASTEREN);
for (n = 0; n < NR_MSM_IRQS; n++) {
set_irq_chip(n, &msm_irq_chip);
@@ -151,3 +556,85 @@ void __init msm_init_irq(void)
set_irq_flags(n, IRQF_VALID);
}
}
+
+#if defined(CONFIG_MSM_FIQ_SUPPORT)
+void msm_trigger_irq(int irq)
+{
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_SOFTINT0, irq);
+ uint32_t mask = 1UL << (irq & 31);
+ writel(mask, reg);
+}
+
+void msm_fiq_enable(int irq)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ msm_irq_unmask(irq);
+ local_irq_restore(flags);
+}
+
+void msm_fiq_disable(int irq)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ msm_irq_mask(irq);
+ local_irq_restore(flags);
+}
+
+void msm_fiq_select(int irq)
+{
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
+ uint32_t mask = 1UL << (irq & 31);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ msm_irq_shadow_reg[index].int_select |= mask;
+ writel(msm_irq_shadow_reg[index].int_select, reg);
+ local_irq_restore(flags);
+}
+
+void msm_fiq_unselect(int irq)
+{
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_SELECT0, irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(irq);
+ uint32_t mask = 1UL << (irq & 31);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ msm_irq_shadow_reg[index].int_select &= (!mask);
+ writel(msm_irq_shadow_reg[index].int_select, reg);
+ local_irq_restore(flags);
+}
+/* set_fiq_handler originally from arch/arm/kernel/fiq.c */
+static void set_fiq_handler(void *start, unsigned int length)
+{
+ memcpy((void *)0xffff001c, start, length);
+ flush_icache_range(0xffff001c, 0xffff001c + length);
+ if (!vectors_high())
+ flush_icache_range(0x1c, 0x1c + length);
+}
+
+extern unsigned char fiq_glue, fiq_glue_end;
+
+static void (*fiq_func)(void *data, void *regs);
+static unsigned long long fiq_stack[256];
+
+void fiq_glue_setup(void *func, void *data, void *sp);
+
+int msm_fiq_set_handler(void (*func)(void *data, void *regs), void *data)
+{
+ unsigned long flags;
+ int ret = -ENOMEM;
+
+ local_irq_save(flags);
+ if (fiq_func == 0) {
+ fiq_func = func;
+ fiq_glue_setup(func, data, fiq_stack + 255);
+ set_fiq_handler(&fiq_glue, (&fiq_glue_end - &fiq_glue));
+ ret = 0;
+ }
+ local_irq_restore(flags);
+ return ret;
+}
+#endif
diff --git a/arch/arm/mach-msm/irq.h b/arch/arm/mach-msm/irq.h
new file mode 100644
index 000000000000..ad4cb92ca570
--- /dev/null
+++ b/arch/arm/mach-msm/irq.h
@@ -0,0 +1,43 @@
+/* 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 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_IRQ_H_
+#define _ARCH_ARM_MACH_MSM_IRQ_H_
+
+int msm_irq_idle_sleep_allowed(void);
+unsigned int msm_irq_pending(void);
+void msm_irq_enter_sleep1(bool arm9_wake, int from_idle, uint32_t *irq_mask);
+int msm_irq_enter_sleep2(bool arm9_wake, int from_idle);
+void msm_irq_exit_sleep1
+ (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void msm_irq_exit_sleep2
+ (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending);
+void msm_irq_exit_sleep3
+ (uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+
+#endif
diff --git a/arch/arm/mach-msm/jtag-v7.S b/arch/arm/mach-msm/jtag-v7.S
new file mode 100644
index 000000000000..ebac7b254549
--- /dev/null
+++ b/arch/arm/mach-msm/jtag-v7.S
@@ -0,0 +1,117 @@
+/* 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 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.
+ *
+ */
+
+/*
+ * JTAG support functions for ARMv7-based Qualcomm SoCs.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+ENTRY(msm_save_jtag_debug)
+ /* lock debug and preserve registers through power collapse */
+ ldr r3, =dbg_state /* store state at dbg_state */
+
+ ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */
+ mcr p14,0,r1,c1,c0,4
+ isb
+
+ mrc p14,0,r1,c1,c2,4 /* DBGOSSRR state register count */
+
+ cmp r1, #(0x20-1) /* check for state overflow */
+ movge r1, #0 /* if not enough space, don't save */
+
+ str r1,[r3],#4 /* save count for restore */
+
+1: cmp r1,#0
+ mrcne p14,0,r2,c1,c2,4 /* DBGOSSRR state value */
+ strne r2,[r3],#4 /* push value */
+ subne r1,r1,#1
+ bne 1b
+
+ /* unlock JTAG. Works better than leaving locked. */
+ stmfd sp!, {lr}
+ bl msm_unlock_jtag_debug
+ ldmfd sp!, {lr}
+ bx lr
+
+ENTRY(msm_unlock_jtag_debug)
+ mov r0, #0 /* unlock value */
+ mcr p14,0,r0,c1,c0,4 /* unlock DBGOSLAR */
+ isb
+ bx lr
+
+ENTRY(msm_restore_jtag_debug)
+ /* restore debug registers after power collapse */
+ ldr r3, =dbg_state /* load state from dbg_state */
+
+ ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */
+ mcr p14,0,r1,c1,c0,4
+ isb
+
+ mrc p14,0,r1,c1,c2,4 /* DBGOSSRR dummy read (required)*/
+ ldr r1,[r3],#4 /* load saved count */
+ cmp r1,#0 /* skip if none stored
+ beq msm_pm_dbg_restore_end
+
+ /* restores debug state except DBGDSCR */
+1: ldr r2,[r3],#4
+ cmp r1,#0x10 /* DBGDSCR special case */
+ biceq r2,r2,#0xc000 /* DBGDSCR = DBGDSCR & ~0xc000 */
+ mcr p14,0,r2,c1,c2,4 /* DBGOSSRR write state value */
+ subs r1,r1,#1
+ bne 1b
+ isb
+
+ /* second loop to restore DBGDSCR after other state restored */
+ ldr r3, =dbg_state /* load state from dbg_state */
+
+ ldr r1, =0xc5ACCE55 /* set DBGOSLAR lock */
+ mcr p14,0,r1,c1,c0,4
+ isb
+
+ mrc p14,0,r1,c1,c5,4 /* clear sticky power down bit */
+ isb
+
+ mrc p14,0,r1,c1,c2,4 /* DBGOSSRR dummy read (required)*/
+ ldr r1,[r3],#4 /* load saved count */
+
+1: ldr r2,[r3],#4
+ mcr p14,0,r2,c1,c2,4 /* DBGOSSRR write state value */
+ subs r1,r1,#1
+ bne 1b
+msm_pm_dbg_restore_end:
+ mcr p14,0,r1,c1,c0,4 /* unlock DBGOSLAR */
+ isb
+ bx lr
+
+
+ .data
+
+dbg_state:
+ .space 4 * 0x20
+
diff --git a/arch/arm/mach-msm/keypad-surf-ffa.c b/arch/arm/mach-msm/keypad-surf-ffa.c
new file mode 100644
index 000000000000..1ea72af71a47
--- /dev/null
+++ b/arch/arm/mach-msm/keypad-surf-ffa.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio_event.h>
+
+#include <asm/mach-types.h>
+
+/* don't turn this on without updating the ffa support */
+#define SCAN_FUNCTION_KEYS 0
+
+/* FFA:
+ 36: KEYSENSE_N(0)
+ 37: KEYSENSE_N(1)
+ 38: KEYSENSE_N(2)
+ 39: KEYSENSE_N(3)
+ 40: KEYSENSE_N(4)
+
+ 31: KYPD_17
+ 32: KYPD_15
+ 33: KYPD_13
+ 34: KYPD_11
+ 35: KYPD_9
+ 41: KYPD_MEMO
+*/
+
+static unsigned int keypad_row_gpios[] = {
+ 31, 32, 33, 34, 35, 41
+#if SCAN_FUNCTION_KEYS
+ , 42
+#endif
+};
+
+static unsigned int keypad_col_gpios[] = { 36, 37, 38, 39, 40 };
+
+static unsigned int keypad_row_gpios_8k_ffa[] = {31, 32, 33, 34, 35, 36};
+static unsigned int keypad_col_gpios_8k_ffa[] = {38, 39, 40, 41, 42};
+
+#define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(keypad_col_gpios) + (col))
+#define FFA_8K_KEYMAP_INDEX(row, col) ((row)* \
+ ARRAY_SIZE(keypad_col_gpios_8k_ffa) + (col))
+
+static const unsigned short keypad_keymap_surf[ARRAY_SIZE(keypad_col_gpios) *
+ ARRAY_SIZE(keypad_row_gpios)] = {
+ [KEYMAP_INDEX(0, 0)] = KEY_5,
+ [KEYMAP_INDEX(0, 1)] = KEY_9,
+ [KEYMAP_INDEX(0, 2)] = 229, /* SOFT1 */
+ [KEYMAP_INDEX(0, 3)] = KEY_6,
+ [KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_0,
+ [KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+ [KEYMAP_INDEX(1, 2)] = KEY_1,
+ [KEYMAP_INDEX(1, 3)] = 228, /* KEY_SHARP */
+ [KEYMAP_INDEX(1, 4)] = KEY_SEND,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
+ [KEYMAP_INDEX(2, 1)] = KEY_HOME, /* FA */
+ [KEYMAP_INDEX(2, 2)] = KEY_F8, /* QCHT */
+ [KEYMAP_INDEX(2, 3)] = KEY_F6, /* R+ */
+ [KEYMAP_INDEX(2, 4)] = KEY_F7, /* R- */
+
+ [KEYMAP_INDEX(3, 0)] = KEY_UP,
+ [KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
+ [KEYMAP_INDEX(3, 2)] = KEY_4,
+ [KEYMAP_INDEX(3, 3)] = KEY_MUTE, /* SPKR */
+ [KEYMAP_INDEX(3, 4)] = KEY_2,
+
+ [KEYMAP_INDEX(4, 0)] = 230, /* SOFT2 */
+ [KEYMAP_INDEX(4, 1)] = 232, /* KEY_CENTER */
+ [KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+ [KEYMAP_INDEX(4, 3)] = KEY_BACK, /* FB */
+ [KEYMAP_INDEX(4, 4)] = KEY_8,
+
+ [KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */
+ [KEYMAP_INDEX(5, 2)] = KEY_MAIL, /* MESG */
+ [KEYMAP_INDEX(5, 3)] = KEY_3,
+ [KEYMAP_INDEX(5, 4)] = KEY_7,
+
+#if SCAN_FUNCTION_KEYS
+ [KEYMAP_INDEX(6, 0)] = KEY_F5,
+ [KEYMAP_INDEX(6, 1)] = KEY_F4,
+ [KEYMAP_INDEX(6, 2)] = KEY_F3,
+ [KEYMAP_INDEX(6, 3)] = KEY_F2,
+ [KEYMAP_INDEX(6, 4)] = KEY_F1
+#endif
+};
+
+static const unsigned short keypad_keymap_ffa[ARRAY_SIZE(keypad_col_gpios) *
+ ARRAY_SIZE(keypad_row_gpios)] = {
+ /*[KEYMAP_INDEX(0, 0)] = ,*/
+ /*[KEYMAP_INDEX(0, 1)] = ,*/
+ [KEYMAP_INDEX(0, 2)] = KEY_1,
+ [KEYMAP_INDEX(0, 3)] = KEY_SEND,
+ [KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+
+ [KEYMAP_INDEX(1, 0)] = KEY_3,
+ [KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+ [KEYMAP_INDEX(1, 2)] = KEY_VOLUMEUP,
+ /*[KEYMAP_INDEX(1, 3)] = ,*/
+ [KEYMAP_INDEX(1, 4)] = KEY_6,
+
+ [KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */
+ [KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */
+ [KEYMAP_INDEX(2, 2)] = KEY_0,
+ [KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */
+ [KEYMAP_INDEX(2, 4)] = KEY_9,
+
+ [KEYMAP_INDEX(3, 0)] = KEY_UP,
+ [KEYMAP_INDEX(3, 1)] = 232, /* KEY_CENTER */ /* i */
+ [KEYMAP_INDEX(3, 2)] = KEY_4,
+ /*[KEYMAP_INDEX(3, 3)] = ,*/
+ [KEYMAP_INDEX(3, 4)] = KEY_2,
+
+ [KEYMAP_INDEX(4, 0)] = KEY_VOLUMEDOWN,
+ [KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+ [KEYMAP_INDEX(4, 2)] = KEY_DOWN,
+ [KEYMAP_INDEX(4, 3)] = KEY_8,
+ [KEYMAP_INDEX(4, 4)] = KEY_5,
+
+ /*[KEYMAP_INDEX(5, 0)] = ,*/
+ [KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */
+ [KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+ [KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */
+ [KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+#define QSD8x50_FFA_KEYMAP_SIZE (ARRAY_SIZE(keypad_col_gpios_8k_ffa) * \
+ ARRAY_SIZE(keypad_row_gpios_8k_ffa))
+
+static const unsigned short keypad_keymap_8k_ffa[QSD8x50_FFA_KEYMAP_SIZE] = {
+
+ [FFA_8K_KEYMAP_INDEX(0, 0)] = KEY_VOLUMEDOWN,
+ /*[KEYMAP_INDEX(0, 1)] = ,*/
+ [FFA_8K_KEYMAP_INDEX(0, 2)] = KEY_DOWN,
+ [FFA_8K_KEYMAP_INDEX(0, 3)] = KEY_8,
+ [FFA_8K_KEYMAP_INDEX(0, 4)] = KEY_5,
+
+ [FFA_8K_KEYMAP_INDEX(1, 0)] = KEY_UP,
+ [FFA_8K_KEYMAP_INDEX(1, 1)] = KEY_CLEAR,
+ [FFA_8K_KEYMAP_INDEX(1, 2)] = KEY_4,
+ /*[KEYMAP_INDEX(1, 3)] = ,*/
+ [FFA_8K_KEYMAP_INDEX(1, 4)] = KEY_2,
+
+ [FFA_8K_KEYMAP_INDEX(2, 0)] = KEY_HOME, /* A */
+ [FFA_8K_KEYMAP_INDEX(2, 1)] = KEY_BACK, /* B */
+ [FFA_8K_KEYMAP_INDEX(2, 2)] = KEY_0,
+ [FFA_8K_KEYMAP_INDEX(2, 3)] = 228, /* KEY_SHARP */
+ [FFA_8K_KEYMAP_INDEX(2, 4)] = KEY_9,
+
+ [FFA_8K_KEYMAP_INDEX(3, 0)] = KEY_3,
+ [FFA_8K_KEYMAP_INDEX(3, 1)] = KEY_RIGHT,
+ [FFA_8K_KEYMAP_INDEX(3, 2)] = KEY_VOLUMEUP,
+ /*[KEYMAP_INDEX(3, 3)] = ,*/
+ [FFA_8K_KEYMAP_INDEX(3, 4)] = KEY_6,
+
+ [FFA_8K_KEYMAP_INDEX(4, 0)] = 232, /* OK */
+ [FFA_8K_KEYMAP_INDEX(4, 1)] = KEY_SOUND,
+ [FFA_8K_KEYMAP_INDEX(4, 2)] = KEY_1,
+ [FFA_8K_KEYMAP_INDEX(4, 3)] = KEY_SEND,
+ [FFA_8K_KEYMAP_INDEX(4, 4)] = KEY_LEFT,
+
+ /*[KEYMAP_INDEX(5, 0)] = ,*/
+ [FFA_8K_KEYMAP_INDEX(5, 1)] = 227, /* KEY_STAR */
+ [FFA_8K_KEYMAP_INDEX(5, 2)] = 230, /*SOFT2*/ /* 2 */
+ [FFA_8K_KEYMAP_INDEX(5, 3)] = KEY_MENU, /* 1 */
+ [FFA_8K_KEYMAP_INDEX(5, 4)] = KEY_7,
+};
+
+static const unsigned short keypad_virtual_keys[] = {
+ KEY_END,
+ KEY_POWER
+};
+
+static int keypad_gpio_event_matrix_func(struct input_dev *input_dev,
+ struct gpio_event_info *info,
+ void **data, int func);
+
+/* SURF keypad platform device information */
+static struct gpio_event_matrix_info surf_keypad_matrix_info = {
+ .info.func = keypad_gpio_event_matrix_func,
+ .keymap = keypad_keymap_surf,
+ .output_gpios = keypad_row_gpios,
+ .input_gpios = keypad_col_gpios,
+ .noutputs = ARRAY_SIZE(keypad_row_gpios),
+ .ninputs = ARRAY_SIZE(keypad_col_gpios),
+ .settle_time.tv.nsec = 0,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *surf_keypad_info[] = {
+ &surf_keypad_matrix_info.info
+};
+
+static struct gpio_event_platform_data surf_keypad_data = {
+ .name = "surf_keypad",
+ .info = surf_keypad_info,
+ .info_count = ARRAY_SIZE(surf_keypad_info)
+};
+
+struct platform_device keypad_device_surf = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &surf_keypad_data,
+ },
+};
+
+/* 8k FFA keypad platform device information */
+static struct gpio_event_matrix_info keypad_matrix_info_8k_ffa = {
+ .info.func = keypad_gpio_event_matrix_func,
+ .keymap = keypad_keymap_8k_ffa,
+ .output_gpios = keypad_row_gpios_8k_ffa,
+ .input_gpios = keypad_col_gpios_8k_ffa,
+ .noutputs = ARRAY_SIZE(keypad_row_gpios_8k_ffa),
+ .ninputs = ARRAY_SIZE(keypad_col_gpios_8k_ffa),
+ .settle_time.tv.nsec = 0,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *keypad_info_8k_ffa[] = {
+ &keypad_matrix_info_8k_ffa.info
+};
+
+static struct gpio_event_platform_data keypad_data_8k_ffa = {
+ .name = "8k_ffa_keypad",
+ .info = keypad_info_8k_ffa,
+ .info_count = ARRAY_SIZE(keypad_info_8k_ffa)
+};
+
+struct platform_device keypad_device_8k_ffa = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &keypad_data_8k_ffa,
+ },
+};
+
+/* 7k FFA keypad platform device information */
+static struct gpio_event_matrix_info keypad_matrix_info_7k_ffa = {
+ .info.func = keypad_gpio_event_matrix_func,
+ .keymap = keypad_keymap_ffa,
+ .output_gpios = keypad_row_gpios,
+ .input_gpios = keypad_col_gpios,
+ .noutputs = ARRAY_SIZE(keypad_row_gpios),
+ .ninputs = ARRAY_SIZE(keypad_col_gpios),
+ .settle_time.tv.nsec = 0,
+ .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
+ .flags = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+ GPIOKPF_PRINT_UNMAPPED_KEYS
+};
+
+static struct gpio_event_info *keypad_info_7k_ffa[] = {
+ &keypad_matrix_info_7k_ffa.info
+};
+
+static struct gpio_event_platform_data keypad_data_7k_ffa = {
+ .name = "7k_ffa_keypad",
+ .info = keypad_info_7k_ffa,
+ .info_count = ARRAY_SIZE(keypad_info_7k_ffa)
+};
+
+struct platform_device keypad_device_7k_ffa = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = -1,
+ .dev = {
+ .platform_data = &keypad_data_7k_ffa,
+ },
+};
+
+static struct input_dev *keypad_dev;
+
+static int keypad_gpio_event_matrix_func(struct input_dev *input_dev,
+ struct gpio_event_info *info,
+ void **data, int func)
+{
+ int err;
+ int i;
+
+ err = gpio_event_matrix_func(input_dev, info, data, func);
+
+ if (func == GPIO_EVENT_FUNC_INIT && !err) {
+ keypad_dev = input_dev;
+ for (i = 0; i < ARRAY_SIZE(keypad_virtual_keys); i++)
+ set_bit(keypad_virtual_keys[i] & KEY_MAX,
+ input_dev->keybit);
+ } else if (func == GPIO_EVENT_FUNC_UNINIT) {
+ keypad_dev = NULL;
+ }
+
+ return err;
+}
+
+struct input_dev *msm_keypad_get_input_dev(void)
+{
+ return keypad_dev;
+}
+
diff --git a/arch/arm/mach-msm/keypad-surf-ffa.h b/arch/arm/mach-msm/keypad-surf-ffa.h
new file mode 100644
index 000000000000..2a29307fddfb
--- /dev/null
+++ b/arch/arm/mach-msm/keypad-surf-ffa.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#ifndef _KEYPAD_SURF_FFA_H
+#define _KEYPAD_SURF_FFA_H
+
+#include <linux/input.h>
+
+#if defined(CONFIG_SURF_FFA_GPIO_KEYPAD)
+struct input_dev *msm_keypad_get_input_dev(void);
+#else
+static struct input_dev *msm_keypad_get_input_dev(void)
+{
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
new file mode 100644
index 000000000000..e87bbddc58b0
--- /dev/null
+++ b/arch/arm/mach-msm/memory.c
@@ -0,0 +1,86 @@
+/* arch/arm/mach-msm/memory.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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/mm.h>
+#include <linux/mm_types.h>
+#include <linux/bootmem.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+
+int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ unsigned long pfn_addr = pfn << PAGE_SHIFT;
+ if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
+ prot = pgprot_device(prot);
+ printk("remapping device %lx\n", prot);
+ }
+ return remap_pfn_range(vma, addr, pfn, size, prot);
+}
+
+void *zero_page_strongly_ordered;
+
+static void map_zero_page_strongly_ordered(void)
+{
+ if (zero_page_strongly_ordered)
+ return;
+
+ zero_page_strongly_ordered =
+ ioremap_strongly_ordered(page_to_pfn(empty_zero_page)
+ << PAGE_SHIFT, PAGE_SIZE);
+}
+
+void write_to_strongly_ordered_memory(void)
+{
+ map_zero_page_strongly_ordered();
+ *(int *)zero_page_strongly_ordered = 0;
+}
+
+void flush_axi_bus_buffer(void)
+{
+ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
+ : : "r" (0) : "memory");
+ write_to_strongly_ordered_memory();
+}
+
+void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
+{
+ void *unused_addr = NULL;
+ unsigned long addr, tmp_size, unused_size;
+
+ /* Allocate maximum size needed, see where it ends up.
+ * Then free it -- in this path there are no other allocators
+ * so we can depend on getting the same address back
+ * when we allocate a smaller piece that is aligned
+ * at the end (if necessary) and the piece we really want,
+ * then free the unused first piece.
+ */
+
+ tmp_size = size + alignment - PAGE_SIZE;
+ addr = (unsigned long)alloc_bootmem(tmp_size);
+ free_bootmem(__pa(addr), tmp_size);
+
+ unused_size = alignment - (addr % alignment);
+ if (unused_size)
+ unused_addr = alloc_bootmem(unused_size);
+
+ addr = (unsigned long)alloc_bootmem(size);
+ if (unused_size)
+ free_bootmem(__pa(unused_addr), unused_size);
+
+ return (void *)addr;
+}
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
new file mode 100644
index 000000000000..532757065aa9
--- /dev/null
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -0,0 +1,237 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * Modem Restart Notifier -- Provides notification
+ * of modem restart events.
+ */
+
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+
+#include "modem_notifier.h"
+
+#define DEBUG
+
+static struct srcu_notifier_head modem_notifier_list;
+static struct workqueue_struct *modem_notifier_wq;
+
+static void notify_work_start_reset(struct work_struct *work)
+{
+ modem_notify(0, MODEM_NOTIFIER_START_RESET);
+}
+static DECLARE_WORK(modem_notifier_start_reset_work, &notify_work_start_reset);
+
+void modem_queue_start_reset_notify(void)
+{
+ int ret;
+
+ ret = queue_work(modem_notifier_wq, &modem_notifier_start_reset_work);
+
+ if (!ret)
+ printk(KERN_ERR "%s\n", __func__);
+}
+EXPORT_SYMBOL(modem_queue_start_reset_notify);
+
+static void notify_work_end_reset(struct work_struct *work)
+{
+ modem_notify(0, MODEM_NOTIFIER_END_RESET);
+}
+static DECLARE_WORK(modem_notifier_end_reset_work, &notify_work_end_reset);
+
+void modem_queue_end_reset_notify(void)
+{
+ int ret;
+
+ ret = queue_work(modem_notifier_wq, &modem_notifier_end_reset_work);
+
+ if (!ret)
+ printk(KERN_ERR "%s\n", __func__);
+}
+EXPORT_SYMBOL(modem_queue_end_reset_notify);
+
+int modem_register_notifier(struct notifier_block *nb)
+{
+ int ret;
+
+ ret = srcu_notifier_chain_register(
+ &modem_notifier_list, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL(modem_register_notifier);
+
+int modem_unregister_notifier(struct notifier_block *nb)
+{
+ int ret;
+
+ ret = srcu_notifier_chain_unregister(
+ &modem_notifier_list, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL(modem_unregister_notifier);
+
+void modem_notify(void *data, unsigned int state)
+{
+ srcu_notifier_call_chain(&modem_notifier_list, state, data);
+}
+EXPORT_SYMBOL(modem_notify);
+
+#if defined(CONFIG_DEBUG_FS)
+static int debug_reset_start(const char __user *buf, int count)
+{
+ modem_queue_start_reset_notify();
+ return 0;
+}
+
+static int debug_reset_end(const char __user *buf, int count)
+{
+ modem_queue_end_reset_notify();
+ return 0;
+}
+
+static ssize_t debug_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fling)(const char __user *buf, int max) = file->private_data;
+ fling(buf, count);
+ return count;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .write = debug_write,
+ .open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fling)(const char __user *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fling, &debug_ops);
+}
+
+static void modem_notifier_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("modem_notifier", 0);
+ if (IS_ERR(dent))
+ return;
+
+ debug_create("reset_start", 0444, dent, debug_reset_start);
+ debug_create("reset_end", 0444, dent, debug_reset_end);
+}
+#else
+static void modem_notifier_debugfs_init(void) {}
+#endif
+
+#if defined(DEBUG)
+static int modem_notifier_test_call(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
+{
+ switch (code) {
+ case MODEM_NOTIFIER_START_RESET:
+ printk(KERN_ERR "Notify: start reset\n");
+ break;
+ case MODEM_NOTIFIER_END_RESET:
+ printk(KERN_ERR "Notify: end reset\n");
+ break;
+ default:
+ printk(KERN_ERR "Notify: general\n");
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = modem_notifier_test_call,
+};
+
+static void register_test_notifier(void)
+{
+ modem_register_notifier(&nb);
+}
+#endif
+
+static int __init init_modem_notifier_list(void)
+{
+ srcu_init_notifier_head(&modem_notifier_list);
+ modem_notifier_debugfs_init();
+#if defined(DEBUG)
+ register_test_notifier();
+#endif
+
+ /* Create the workqueue */
+ modem_notifier_wq = create_singlethread_workqueue("modem_notifier");
+ if (!modem_notifier_wq) {
+ srcu_cleanup_notifier_head(&modem_notifier_list);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+module_init(init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
new file mode 100644
index 000000000000..627f5a142b73
--- /dev/null
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -0,0 +1,48 @@
+/* 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 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.
+ *
+ */
+/*
+ * Modem Restart Notifier API
+ *
+ */
+
+#ifndef _MODEM_NOTIFIER_H
+#define _MODEM_NOTIFIER_H
+
+#include <linux/notifier.h>
+
+#define MODEM_NOTIFIER_START_RESET 0x1
+#define MODEM_NOTIFIER_END_RESET 0x2
+
+extern int modem_register_notifier(struct notifier_block *nb);
+extern int modem_unregister_notifier(struct notifier_block *nb);
+extern void modem_notify(void *data, unsigned int state);
+extern void modem_queue_start_reset_notify(void);
+extern void modem_queue_end_reset_notify(void);
+
+
+#endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/mpp.c b/arch/arm/mach-msm/mpp.c
new file mode 100644
index 000000000000..eb6f533d61d0
--- /dev/null
+++ b/arch/arm/mach-msm/mpp.c
@@ -0,0 +1,176 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+/* Qualcomm PMIC Multi-Purpose Pin Configurations */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+
+#include <mach/mpp.h>
+
+#include "proc_comm.h"
+
+#define MPP(_name, _id, _is_input, _status) \
+ { .name = _name, .id = _id, .is_input = _is_input, .status = _status}
+
+static struct mpp mpps[] = {
+ MPP("mpp1", 0, 0, 0),
+ MPP("mpp2", 1, 0, 0),
+ MPP("mpp3", 2, 0, 0),
+ MPP("mpp4", 3, 0, 0),
+ MPP("mpp5", 4, 0, 0),
+ MPP("mpp6", 5, 0, 0),
+ MPP("mpp7", 6, 0, 0),
+ MPP("mpp8", 7, 0, 0),
+ MPP("mpp9", 8, 0, 0),
+ MPP("mpp10", 9, 0, 0),
+ MPP("mpp11", 10, 0, 0),
+ MPP("mpp12", 11, 0, 0),
+ MPP("mpp13", 12, 0, 0),
+ MPP("mpp14", 13, 0, 0),
+ MPP("mpp15", 14, 0, 0),
+ MPP("mpp16", 15, 0, 0),
+ MPP("mpp17", 16, 0, 0),
+ MPP("mpp18", 17, 0, 0),
+ MPP("mpp19", 18, 0, 0),
+ MPP("mpp20", 19, 0, 0),
+ MPP("mpp21", 20, 0, 0),
+ MPP("mpp22", 21, 0, 0),
+};
+
+struct mpp *mpp_get(struct device *dev, const char *id)
+{
+ int n;
+ for (n = 0; n < ARRAY_SIZE(mpps); n++) {
+ if (!strcmp(mpps[n].name, id))
+ return mpps + n;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(mpp_get);
+
+int mpp_config_digital_out(struct mpp *mpp, unsigned config)
+{
+ unsigned id = mpp->id;
+ int err;
+ err = msm_proc_comm(PCOM_PM_MPP_CONFIG, &id, &config);
+ mpp->status = err;
+ mpp->is_input = 0;
+ return err;
+}
+EXPORT_SYMBOL(mpp_config_digital_out);
+
+int mpp_config_digital_in(struct mpp *mpp, unsigned config)
+{
+ unsigned id = mpp->id;
+ int err;
+ err = msm_proc_comm(PCOM_PM_MPP_CONFIG_DIGITAL_INPUT, &id, &config);
+ mpp->status = err;
+ mpp->is_input = 1;
+ return err;
+}
+EXPORT_SYMBOL(mpp_config_digital_in);
+
+#if defined(CONFIG_DEBUG_FS)
+static int mpp_debug_set(void *data, u64 val)
+{
+ int err;
+ struct mpp *mpp = data;
+
+ err = mpp_config_digital_out(mpp, (unsigned)val);
+ if (err) {
+ printk(KERN_ERR
+ "%s: mpp_config_digital_out \
+ [%s(%d) = 0x%x] failed\n",
+ __func__, mpp->name, mpp->id, (unsigned)val);
+ }
+ return 0;
+}
+
+static int mpp_debug_get(void *data, u64 *val)
+{
+ struct mpp *mpp = data;
+ int status = mpp->status;
+ if (!status)
+ *val = 0;
+ else
+ *val = 1;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mpp_fops, mpp_debug_get, mpp_debug_set, "%llu\n");
+
+static int __init mpp_debug_init(void)
+{
+ struct dentry *dent;
+ int n;
+
+ dent = debugfs_create_dir("mpp", 0);
+ if (IS_ERR(dent))
+ return 0;
+
+ for (n = 0; n < ARRAY_SIZE(mpps); n++)
+ debugfs_create_file(mpps[n].name, 0644, dent, mpps + n,
+ &mpp_fops);
+
+ return 0;
+}
+
+device_initcall(mpp_debug_init);
+#endif
diff --git a/arch/arm/mach-msm/msm-keypad-devices.h b/arch/arm/mach-msm/msm-keypad-devices.h
new file mode 100644
index 000000000000..469564a754ad
--- /dev/null
+++ b/arch/arm/mach-msm/msm-keypad-devices.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2009, 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.
+ *
+ */
+
+#ifndef _MSM_KEYPAD_DEVICES_H
+#define _MSM_KEYPAD_DEVICES_H
+
+extern struct platform_device keypad_device_7k_ffa;
+extern struct platform_device keypad_device_8k_ffa;
+extern struct platform_device keypad_device_surf;
+
+#endif
diff --git a/arch/arm/mach-msm/msm_vibrator.c b/arch/arm/mach-msm/msm_vibrator.c
new file mode 100644
index 000000000000..f4da4363aa98
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vibrator.c
@@ -0,0 +1,137 @@
+/* include/asm/mach-msm/htc_pwrsink.h
+ *
+ * Copyright (C) 2008 HTC Corporation.
+ * Copyright (C) 2007 Google, Inc.
+ *
+ * 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/platform_device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <../../../drivers/staging/android/timed_output.h>
+#include <linux/sched.h>
+
+#include <mach/msm_rpcrouter.h>
+
+#define PM_LIBPROG 0x30000061
+#if (CONFIG_MSM_AMSS_VERSION == 6220) || (CONFIG_MSM_AMSS_VERSION == 6225)
+#define PM_LIBVERS 0xfb837d0b
+#else
+#define PM_LIBVERS 0x10001
+#endif
+
+#define HTC_PROCEDURE_SET_VIB_ON_OFF 21
+#define PMIC_VIBRATOR_LEVEL (3000)
+
+static struct work_struct work_vibrator_on;
+static struct work_struct work_vibrator_off;
+static struct hrtimer vibe_timer;
+
+static void set_pmic_vibrator(int on)
+{
+ static struct msm_rpc_endpoint *vib_endpoint;
+ struct set_vib_on_off_req {
+ struct rpc_request_hdr hdr;
+ uint32_t data;
+ } req;
+
+ if (!vib_endpoint) {
+ vib_endpoint = msm_rpc_connect(PM_LIBPROG, PM_LIBVERS, 0);
+ if (IS_ERR(vib_endpoint)) {
+ printk(KERN_ERR "init vib rpc failed!\n");
+ vib_endpoint = 0;
+ return;
+ }
+ }
+
+
+ if (on)
+ req.data = cpu_to_be32(PMIC_VIBRATOR_LEVEL);
+ else
+ req.data = cpu_to_be32(0);
+
+ msm_rpc_call(vib_endpoint, HTC_PROCEDURE_SET_VIB_ON_OFF, &req,
+ sizeof(req), 5 * HZ);
+}
+
+static void pmic_vibrator_on(struct work_struct *work)
+{
+ set_pmic_vibrator(1);
+}
+
+static void pmic_vibrator_off(struct work_struct *work)
+{
+ set_pmic_vibrator(0);
+}
+
+static void timed_vibrator_on(struct timed_output_dev *sdev)
+{
+ schedule_work(&work_vibrator_on);
+}
+
+static void timed_vibrator_off(struct timed_output_dev *sdev)
+{
+ schedule_work(&work_vibrator_off);
+}
+
+static void vibrator_enable(struct timed_output_dev *dev, int value)
+{
+ hrtimer_cancel(&vibe_timer);
+
+ if (value == 0)
+ timed_vibrator_off(dev);
+ else {
+ value = (value > 15000 ? 15000 : value);
+
+ timed_vibrator_on(dev);
+
+ hrtimer_start(&vibe_timer,
+ ktime_set(value / 1000, (value % 1000) * 1000000),
+ HRTIMER_MODE_REL);
+ }
+}
+
+static int vibrator_get_time(struct timed_output_dev *dev)
+{
+ if (hrtimer_active(&vibe_timer)) {
+ ktime_t r = hrtimer_get_remaining(&vibe_timer);
+ return r.tv.sec * 1000 + r.tv.nsec / 1000000;
+ } else
+ return 0;
+}
+
+static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer)
+{
+ timed_vibrator_off(NULL);
+ return HRTIMER_NORESTART;
+}
+
+static struct timed_output_dev pmic_vibrator = {
+ .name = "vibrator",
+ .get_time = vibrator_get_time,
+ .enable = vibrator_enable,
+};
+
+void __init msm_init_pmic_vibrator(void)
+{
+ INIT_WORK(&work_vibrator_on, pmic_vibrator_on);
+ INIT_WORK(&work_vibrator_off, pmic_vibrator_off);
+
+ hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ vibe_timer.function = vibrator_timer_func;
+
+ timed_output_dev_register(&pmic_vibrator);
+}
+
+MODULE_DESCRIPTION("timed output pmic vibrator device");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
new file mode 100644
index 000000000000..fc874470339b
--- /dev/null
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -0,0 +1,187 @@
+/* arch/arm/mach-msm/nand_partitions.c
+ *
+ * Code to extract partition information from ATAG set up by the
+ * bootloader.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/flash.h>
+#include <linux/io.h>
+
+#include <asm/setup.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <mach/msm_iomap.h>
+
+#include <mach/board.h>
+#include "smd_private.h"
+
+/* configuration tags specific to msm */
+
+#define ATAG_MSM_PARTITION 0x4d534D70 /* MSMp */
+
+struct msm_ptbl_entry {
+ char name[16];
+ __u32 offset;
+ __u32 size;
+ __u32 flags;
+};
+
+#define MSM_MAX_PARTITIONS 8
+
+static struct mtd_partition msm_nand_partitions[MSM_MAX_PARTITIONS];
+static char msm_nand_names[MSM_MAX_PARTITIONS * 16];
+
+extern struct flash_platform_data msm_nand_data;
+
+static int __init parse_tag_msm_partition(const struct tag *tag)
+{
+ struct mtd_partition *ptn = msm_nand_partitions;
+ char *name = msm_nand_names;
+ struct msm_ptbl_entry *entry = (void *) &tag->u;
+ unsigned count, n;
+
+ count = (tag->hdr.size - 2) /
+ (sizeof(struct msm_ptbl_entry) / sizeof(__u32));
+
+ if (count > MSM_MAX_PARTITIONS)
+ count = MSM_MAX_PARTITIONS;
+
+ for (n = 0; n < count; n++) {
+ memcpy(name, entry->name, 15);
+ name[15] = 0;
+
+ ptn->name = name;
+ ptn->offset = entry->offset * 64 * 2048;
+ ptn->size = entry->size * 64 * 2048;
+
+ printk(KERN_INFO "Partition (from atag) %s "
+ "-- Offset:%llx Size:%llx\n",
+ ptn->name, ptn->offset, ptn->size);
+
+ name += 16;
+ entry++;
+ ptn++;
+ }
+
+ msm_nand_data.nr_parts = count;
+ msm_nand_data.parts = msm_nand_partitions;
+
+ return 0;
+}
+
+__tagtable(ATAG_MSM_PARTITION, parse_tag_msm_partition);
+
+#define FLASH_PART_MAGIC1 0x55EE73AA
+#define FLASH_PART_MAGIC2 0xE35EBDDB
+#define FLASH_PARTITION_VERSION 0x3
+
+#define LINUX_FS_PARTITION_NAME "0:EFS2APPS"
+
+struct flash_partition_entry {
+ char name[16];
+ u32 offset; /* Offset in blocks from beginning of device */
+ u32 length; /* Length of the partition in blocks */
+ u8 attrib1;
+ u8 attrib2;
+ u8 attrib3;
+ u8 which_flash; /* Numeric ID (first = 0, second = 1) */
+};
+struct flash_partition_table {
+ u32 magic1;
+ u32 magic2;
+ u32 version;
+ u32 numparts;
+ struct flash_partition_entry part_entry[16];
+};
+
+static int get_nand_partitions(void)
+{
+ struct flash_partition_table *partition_table;
+ struct flash_partition_entry *part_entry;
+ struct mtd_partition *ptn = msm_nand_partitions;
+ char *name = msm_nand_names;
+ int part;
+
+ if (msm_nand_data.nr_parts)
+ return 0;
+
+ partition_table = (struct flash_partition_table *)
+ smem_alloc(SMEM_AARM_PARTITION_TABLE,
+ sizeof(struct flash_partition_table));
+
+ if (!partition_table) {
+ printk(KERN_WARNING "%s: no flash partition table in shared "
+ "memory\n", __func__);
+ return -ENOENT;
+ }
+
+ if ((partition_table->magic1 != (u32) FLASH_PART_MAGIC1) ||
+ (partition_table->magic2 != (u32) FLASH_PART_MAGIC2) ||
+ (partition_table->version != (u32) FLASH_PARTITION_VERSION)) {
+ printk(KERN_WARNING "%s: version mismatch -- magic1=%#x, "
+ "magic2=%#x, version=%#x\n", __func__,
+ partition_table->magic1,
+ partition_table->magic2,
+ partition_table->version);
+ return -EFAULT;
+ }
+
+ msm_nand_data.nr_parts = 0;
+
+ /* Get the LINUX FS partition info */
+ for (part = 0; part < partition_table->numparts; part++) {
+ part_entry = &partition_table->part_entry[part];
+
+ /* Find a match for the Linux file system partition */
+ if (strcmp(part_entry->name, LINUX_FS_PARTITION_NAME) == 0) {
+ strcpy(name, part_entry->name);
+ ptn->name = name;
+
+ /*TODO: Get block count and size info */
+ ptn->offset = part_entry->offset * 64 * 2048;
+
+ /* For SMEM, -1 indicates remaining space in flash,
+ * but for MTD it is 0
+ */
+ if (part_entry->length == (u32)-1)
+ ptn->size = 0;
+ else
+ ptn->size = part_entry->length * 64 * 2048;
+
+ msm_nand_data.nr_parts = 1;
+ msm_nand_data.parts = msm_nand_partitions;
+
+ printk(KERN_INFO "Partition(from smem) %s "
+ "-- Offset:%llx Size:%llx\n",
+ ptn->name, ptn->offset, ptn->size);
+
+ return 0;
+ }
+ }
+
+ printk(KERN_WARNING "%s: no partition table found!", __func__);
+
+ return -ENODEV;
+}
+
+device_initcall(get_nand_partitions);
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
new file mode 100644
index 000000000000..a680fbb8f82d
--- /dev/null
+++ b/arch/arm/mach-msm/nohlt.c
@@ -0,0 +1,86 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * MSM architecture driver to control arm halt behavior
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_DEBUG_FS
+static int set_nohalt(void *data, u64 val)
+{
+ if (val)
+ disable_hlt();
+ else
+ enable_hlt();
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+
+static int __init init_hlt_debug(void)
+{
+ debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+
+ return 0;
+}
+
+late_initcall(init_hlt_debug);
+#endif
diff --git a/arch/arm/mach-msm/oem_rapi_client.c b/arch/arm/mach-msm/oem_rapi_client.c
new file mode 100644
index 000000000000..e31de45f2920
--- /dev/null
+++ b/arch/arm/mach-msm/oem_rapi_client.c
@@ -0,0 +1,489 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+/*
+ * OEM RAPI CLIENT Driver source file
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/oem_rapi_client.h>
+
+#define OEM_RAPI_PROG 0x3000006B
+#define OEM_RAPI_VERS 0x00010001
+
+#define OEM_RAPI_NULL_PROC 0
+#define OEM_RAPI_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define OEM_RAPI_STREAMING_FUNCTION_PROC 2
+
+#define OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE 128
+
+static struct msm_rpc_client *rpc_client;
+static uint32_t open_count;
+static DEFINE_MUTEX(oem_rapi_client_lock);
+
+static int oem_rapi_client_cb(struct msm_rpc_client *client,
+ void *buffer, int in_size)
+{
+ struct rpc_request_hdr *req;
+ void *buf, *cb_func, *reply;
+ uint32_t cb_id, accept_status, size;
+ int rc;
+
+ struct oem_rapi_client_streaming_func_cb_arg arg;
+ struct oem_rapi_client_streaming_func_cb_ret ret;
+
+ arg.input = NULL;
+ ret.out_len = NULL;
+ ret.output = NULL;
+
+ req = (struct rpc_request_hdr *)buffer;
+ buf = (void *)(req + 1);
+
+ /* cb_id */
+ cb_id = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ /* enum */
+ arg.event = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ /* handle */
+ arg.handle = (void *)be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ /* in_len */
+ arg.in_len = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ /* input */
+ size = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (size) {
+ arg.input = kmalloc(size, GFP_KERNEL);
+ if (arg.input)
+ memcpy(arg.input, buf, size);
+ else {
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ goto oem_rapi_send_ack;
+ }
+ }
+ buf += size;
+ if (size & 0x3)
+ buf += 4 - (size & 0x3);
+
+ /* out_len */
+ arg.out_len_valid = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (arg.out_len_valid) {
+ ret.out_len = kmalloc(sizeof(*ret.out_len), GFP_KERNEL);
+ if (!ret.out_len) {
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ goto oem_rapi_send_ack;
+ }
+ }
+
+ /* out */
+ arg.output_valid = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (arg.output_valid) {
+ arg.output_size = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ ret.output = kmalloc(arg.output_size, GFP_KERNEL);
+ if (!ret.output) {
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ goto oem_rapi_send_ack;
+ }
+ }
+
+ cb_func = msm_rpc_get_cb_func(client, cb_id);
+ if (cb_func) {
+ rc = ((int (*)(struct oem_rapi_client_streaming_func_cb_arg *,
+ struct oem_rapi_client_streaming_func_cb_ret *))
+ cb_func)(&arg, &ret);
+ if (rc)
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ else
+ accept_status = RPC_ACCEPTSTAT_SUCCESS;
+ } else
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+ oem_rapi_send_ack:
+ reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+ accept_status);
+
+ size = 0;
+ if (accept_status == RPC_ACCEPTSTAT_SUCCESS) {
+ *(uint32_t *)reply = cpu_to_be32((uint32_t)(ret.out_len != 0));
+ reply += sizeof(uint32_t);
+ size += sizeof(uint32_t);
+
+ if (ret.out_len) {
+ *(uint32_t *)reply = cpu_to_be32(*ret.out_len);
+ reply += sizeof(uint32_t);
+ size += sizeof(uint32_t);
+ }
+
+ if (ret.output && ret.out_len) {
+ *(uint32_t *)reply =
+ cpu_to_be32((uint32_t)(*ret.out_len));
+ reply += sizeof(uint32_t);
+ size += sizeof(uint32_t);
+
+ memcpy(reply, ret.output, *ret.out_len);
+ reply += *ret.out_len;
+ size += *ret.out_len;
+ if (*ret.out_len & 0x3) {
+ memset(reply, 0, 4 - (*ret.out_len & 0x3));
+ reply += 4 - (*ret.out_len & 0x3);
+ size += 4 - (*ret.out_len & 0x3);
+ }
+ } else {
+ *(uint32_t *)reply = cpu_to_be32(0);
+ reply += sizeof(uint32_t);
+ size += sizeof(uint32_t);
+ }
+ }
+ rc = msm_rpc_send_accepted_reply(client, size);
+ if (rc)
+ pr_err("%s: sending reply failed: %d\n", __func__, rc);
+
+ kfree(arg.input);
+ kfree(ret.out_len);
+ kfree(ret.output);
+
+ return 0;
+}
+
+static int oem_rapi_client_streaming_function_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ int size = 0;
+ int cb_id;
+ struct oem_rapi_client_streaming_func_arg *arg = data;
+
+ /* enum */
+ *((uint32_t *)buf) = cpu_to_be32(arg->event);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ /* cb_id */
+ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+ if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+ return cb_id;
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ /* handle */
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)arg->handle);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ /* in_len */
+ *((uint32_t *)buf) = cpu_to_be32(arg->in_len);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ /* input */
+ *((uint32_t *)buf) = cpu_to_be32(arg->in_len);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+ memcpy(buf, arg->input, arg->in_len);
+ size += arg->in_len;
+ buf += arg->in_len;
+ if (arg->in_len & 0x3) {
+ memset(buf, 0, 4 - (arg->in_len & 0x3));
+ buf += 4 - (arg->in_len & 0x3);
+ size += 4 - (arg->in_len & 0x3);
+ }
+
+ /* out_len */
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->out_len_valid));
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ /* output */
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)(arg->output_valid));
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+ if (arg->output_valid) {
+ *((uint32_t *)buf) = cpu_to_be32(arg->output_size);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+ }
+
+ return size;
+}
+
+static int oem_rapi_client_streaming_function_ret(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ uint32_t data_present, size;
+ struct oem_rapi_client_streaming_func_ret *ret = data;
+
+ /* out_len */
+ data_present = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (data_present && ret->out_len) {
+ *ret->out_len = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ }
+
+ /* output */
+ size = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (size && ret->output)
+ memcpy(ret->output, buf, size);
+ buf += size;
+ if (size & 0x3)
+ buf += 4 - (size & 0x3);
+
+ return 0;
+}
+
+int oem_rapi_client_streaming_function(
+ struct msm_rpc_client *client,
+ struct oem_rapi_client_streaming_func_arg *arg,
+ struct oem_rapi_client_streaming_func_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ OEM_RAPI_STREAMING_FUNCTION_PROC,
+ oem_rapi_client_streaming_function_arg, arg,
+ oem_rapi_client_streaming_function_ret,
+ ret, -1);
+}
+EXPORT_SYMBOL(oem_rapi_client_streaming_function);
+
+int oem_rapi_client_close(void)
+{
+ mutex_lock(&oem_rapi_client_lock);
+ if (--open_count == 0) {
+ msm_rpc_unregister_client(rpc_client);
+ pr_info("%s: disconnected from remote oem rapi server\n",
+ __func__);
+ }
+ mutex_unlock(&oem_rapi_client_lock);
+ return 0;
+}
+EXPORT_SYMBOL(oem_rapi_client_close);
+
+struct msm_rpc_client *oem_rapi_client_init(void)
+{
+ mutex_lock(&oem_rapi_client_lock);
+ if (open_count == 0) {
+ rpc_client = msm_rpc_register_client("oemrapiclient",
+ OEM_RAPI_PROG,
+ OEM_RAPI_VERS, 0,
+ oem_rapi_client_cb);
+ if (!IS_ERR(rpc_client))
+ open_count++;
+ }
+ mutex_unlock(&oem_rapi_client_lock);
+ return rpc_client;
+}
+EXPORT_SYMBOL(oem_rapi_client_init);
+
+#if defined(CONFIG_DEBUG_FS)
+
+static struct dentry *dent;
+static int oem_rapi_client_test_res;
+
+static int oem_rapi_client_null(struct msm_rpc_client *client,
+ void *arg, void *ret)
+{
+ return msm_rpc_client_req(client, OEM_RAPI_NULL_PROC,
+ NULL, NULL, NULL, NULL, -1);
+}
+
+static int oem_rapi_client_test_streaming_cb_func(
+ struct oem_rapi_client_streaming_func_cb_arg *arg,
+ struct oem_rapi_client_streaming_func_cb_ret *ret)
+{
+ uint32_t size;
+ pr_info("oem rapi client test cb func\n");
+
+ size = (arg->in_len < OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE) ?
+ arg->in_len : OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
+
+ if (ret->out_len != 0)
+ *ret->out_len = size;
+
+ if (ret->output != 0)
+ memcpy(ret->output, arg->input, size);
+
+ return 0;
+}
+
+static ssize_t debug_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char _buf[16];
+
+ snprintf(_buf, sizeof(_buf), "%i\n", oem_rapi_client_test_res);
+
+ return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t debug_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char input[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE];
+ char output[OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE];
+ uint32_t out_len;
+ struct oem_rapi_client_streaming_func_arg arg;
+ struct oem_rapi_client_streaming_func_ret ret;
+
+ unsigned char cmd[64];
+ int len;
+
+ if (count < 1)
+ return 0;
+
+ len = count > 63 ? 63 : count;
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "null", 64)) {
+ oem_rapi_client_test_res = oem_rapi_client_null(rpc_client,
+ NULL, NULL);
+ } else if (!strncmp(cmd, "streaming_func", 64)) {
+ memset(input, 5, 16);
+ arg.event = 0;
+ arg.cb_func = oem_rapi_client_test_streaming_cb_func;
+ arg.handle = (void *)20;
+ arg.in_len = 16;
+ arg.input = input;
+ arg.out_len_valid = 1;
+ arg.output_valid = 1;
+ arg.output_size = OEM_RAPI_CLIENT_MAX_OUT_BUFF_SIZE;
+
+ ret.out_len = &out_len;
+ ret.output = output;
+ oem_rapi_client_test_res = oem_rapi_client_streaming_function(
+ rpc_client, &arg, &ret);
+ } else
+ oem_rapi_client_test_res = -EINVAL;
+
+ if (oem_rapi_client_test_res)
+ pr_err("oem rapi client test fail %d\n",
+ oem_rapi_client_test_res);
+ else
+ pr_info("oem rapi client test passed\n");
+
+ return count;
+}
+
+static int debug_release(struct inode *ip, struct file *fp)
+{
+ return oem_rapi_client_close();
+}
+
+static int debug_open(struct inode *ip, struct file *fp)
+{
+ struct msm_rpc_client *client;
+ client = oem_rapi_client_init();
+ if (IS_ERR(client)) {
+ pr_err("%s: couldn't open oem rapi client\n", __func__);
+ return PTR_ERR(client);
+ } else
+ pr_info("%s: connected to remote oem rapi server\n", __func__);
+
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .owner = THIS_MODULE,
+ .open = debug_open,
+ .release = debug_release,
+ .read = debug_read,
+ .write = debug_write,
+};
+
+static void __exit oem_rapi_client_mod_exit(void)
+{
+ debugfs_remove(dent);
+}
+
+static int __init oem_rapi_client_mod_init(void)
+{
+ dent = debugfs_create_file("oem_rapi", 0444, 0, NULL, &debug_ops);
+ open_count = 0;
+ oem_rapi_client_test_res = -1;
+ return 0;
+}
+
+module_init(oem_rapi_client_mod_init);
+module_exit(oem_rapi_client_mod_exit);
+
+#endif
+
+MODULE_DESCRIPTION("OEM RAPI CLIENT Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/arch/arm/mach-msm/ping_mdm_rpc_client.c b/arch/arm/mach-msm/ping_mdm_rpc_client.c
new file mode 100644
index 000000000000..b70527e4875d
--- /dev/null
+++ b/arch/arm/mach-msm/ping_mdm_rpc_client.c
@@ -0,0 +1,772 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+/*
+ * SMD RPC PING MODEM Driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <mach/msm_rpcrouter.h>
+
+#define PING_TEST_BASE 0x31
+
+#define PTIOC_NULL_TEST _IO(PING_TEST_BASE, 1)
+#define PTIOC_REG_TEST _IO(PING_TEST_BASE, 2)
+#define PTIOC_DATA_REG_TEST _IO(PING_TEST_BASE, 3)
+#define PTIOC_DATA_CB_REG_TEST _IO(PING_TEST_BASE, 4)
+
+#define PING_MDM_PROG 0x30000081
+#define PING_MDM_VERS 0x00010001
+#define PING_MDM_CB_PROG 0x31000081
+#define PING_MDM_CB_VERS 0x00010001
+
+#define PING_MDM_NULL_PROC 0
+#define PING_MDM_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define PING_MDM_REGISTER_PROC 2
+#define PING_MDM_UNREGISTER_PROC 3
+#define PING_MDM_REGISTER_DATA_PROC 4
+#define PING_MDM_UNREGISTER_DATA_CB_PROC 5
+#define PING_MDM_REGISTER_DATA_CB_PROC 6
+
+#define PING_MDM_DATA_CB_PROC 1
+#define PING_MDM_CB_PROC 2
+
+static struct msm_rpc_client *rpc_client;
+static uint32_t open_count;
+static DEFINE_MUTEX(ping_mdm_lock);
+
+struct ping_mdm_register_cb_arg {
+ uint32_t cb_id;
+ int val;
+};
+
+struct ping_mdm_register_data_cb_cb_arg {
+ uint32_t cb_id;
+ uint32_t *data;
+ uint32_t size;
+ uint32_t sum;
+};
+
+struct ping_mdm_register_data_cb_cb_ret {
+ uint32_t result;
+};
+
+static int ping_mdm_register_cb(struct msm_rpc_client *client,
+ void *buffer, int in_size)
+{
+ int rc;
+ uint32_t accept_status;
+ struct rpc_request_hdr *req;
+ struct ping_mdm_register_cb_arg arg, *buf_ptr;
+ void *cb_func;
+
+ req = (struct rpc_request_hdr *)buffer;
+ buf_ptr = (struct ping_mdm_register_cb_arg *)(req + 1);
+
+ arg.cb_id = be32_to_cpu(buf_ptr->cb_id);
+ arg.val = be32_to_cpu(buf_ptr->val);
+
+ cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
+ if (cb_func) {
+ rc = ((int (*)(struct ping_mdm_register_cb_arg *, void *))
+ cb_func)(&arg, NULL);
+ if (rc)
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ else
+ accept_status = RPC_ACCEPTSTAT_SUCCESS;
+ } else
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+ msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+ accept_status);
+ rc = msm_rpc_send_accepted_reply(client, 0);
+ if (rc)
+ pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+ return rc;
+}
+
+static int ping_mdm_data_cb(struct msm_rpc_client *client,
+ void *buffer, int in_size)
+{
+ struct rpc_request_hdr *req;
+ int rc, i;
+ void *buf, *cb_func, *reply;
+ uint32_t size, accept_status;
+ struct ping_mdm_register_data_cb_cb_arg arg;
+ struct ping_mdm_register_data_cb_cb_ret ret;
+
+ req = (struct rpc_request_hdr *)buffer;
+ buf = (void *)(req + 1);
+
+ arg.cb_id = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ size = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+ if (size) {
+ arg.data = kmalloc((size * sizeof(*arg.data)), GFP_KERNEL);
+ if (arg.data)
+ for (i = 0; i < size; i++)
+ arg.data[i] =
+ be32_to_cpu(*((uint32_t *)buf + i));
+ }
+ buf += sizeof(uint32_t) * size;
+
+ arg.size = be32_to_cpu(*(uint32_t *)buf);
+ buf += sizeof(uint32_t);
+
+ arg.sum = be32_to_cpu(*(uint32_t *)buf);
+
+ cb_func = msm_rpc_get_cb_func(client, arg.cb_id);
+ if (cb_func) {
+ rc = ((int (*)
+ (struct ping_mdm_register_data_cb_cb_arg *,
+ struct ping_mdm_register_data_cb_cb_ret *))
+ cb_func)(&arg, &ret);
+ if (rc)
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+ else
+ accept_status = RPC_ACCEPTSTAT_SUCCESS;
+ } else
+ accept_status = RPC_ACCEPTSTAT_SYSTEM_ERR;
+
+ reply = msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+ accept_status);
+
+ size = 0;
+ if (accept_status == RPC_ACCEPTSTAT_SUCCESS) {
+ *(uint32_t *)reply = cpu_to_be32(ret.result);
+ size = sizeof(uint32_t);
+ }
+ rc = msm_rpc_send_accepted_reply(client, size);
+ if (rc)
+ pr_err("%s: send accepted reply failed: %d\n", __func__, rc);
+
+ return rc;
+}
+
+static int ping_mdm_cb_func(struct msm_rpc_client *client,
+ void *buffer, int in_size)
+{
+ int rc = 0;
+ struct rpc_request_hdr *req;
+
+ req = (struct rpc_request_hdr *)buffer;
+
+ switch (be32_to_cpu(req->procedure)) {
+ case PING_MDM_CB_PROC:
+ rc = ping_mdm_register_cb(client, buffer, in_size);
+ break;
+ case PING_MDM_DATA_CB_PROC:
+ rc = ping_mdm_data_cb(client, buffer, in_size);
+ break;
+ default:
+ pr_err("%s: procedure not supported %d\n", __func__,
+ be32_to_cpu(req->procedure));
+ msm_rpc_start_accepted_reply(client, be32_to_cpu(req->xid),
+ RPC_ACCEPTSTAT_PROC_UNAVAIL);
+ rc = msm_rpc_send_accepted_reply(client, 0);
+ if (rc)
+ pr_err("%s: sending reply failed: %d\n", __func__, rc);
+ break;
+ }
+ return rc;
+}
+
+struct ping_mdm_unregister_data_cb_arg {
+ int (*cb_func)(
+ struct ping_mdm_register_data_cb_cb_arg *arg,
+ struct ping_mdm_register_data_cb_cb_ret *ret);
+};
+
+struct ping_mdm_register_data_cb_arg {
+ int (*cb_func)(
+ struct ping_mdm_register_data_cb_cb_arg *arg,
+ struct ping_mdm_register_data_cb_cb_ret *ret);
+ uint32_t num;
+ uint32_t size;
+ uint32_t interval_ms;
+ uint32_t num_tasks;
+};
+
+struct ping_mdm_register_data_cb_ret {
+ uint32_t result;
+};
+
+struct ping_mdm_unregister_data_cb_ret {
+ uint32_t result;
+};
+
+static int ping_mdm_data_cb_register_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_register_data_cb_arg *arg;
+ int cb_id, size = 0;
+
+ arg = (struct ping_mdm_register_data_cb_arg *)data;
+
+ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+ if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+ return cb_id;
+
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ *((uint32_t *)buf) = cpu_to_be32(arg->num);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ *((uint32_t *)buf) = cpu_to_be32(arg->size);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ *((uint32_t *)buf) = cpu_to_be32(arg->interval_ms);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ *((uint32_t *)buf) = cpu_to_be32(arg->num_tasks);
+ size += sizeof(uint32_t);
+
+ return size;
+}
+
+static int ping_mdm_data_cb_unregister_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_unregister_data_cb_arg *arg;
+ int cb_id;
+
+ arg = (struct ping_mdm_unregister_data_cb_arg *)data;
+
+ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+ if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+ return cb_id;
+
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id);
+
+ return sizeof(uint32_t);
+}
+
+static int ping_mdm_data_cb_register_ret(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_register_data_cb_ret *data_ptr, *buf_ptr;
+
+ data_ptr = (struct ping_mdm_register_data_cb_ret *)data;
+ buf_ptr = (struct ping_mdm_register_data_cb_ret *)buf;
+
+ data_ptr->result = be32_to_cpu(buf_ptr->result);
+ return 0;
+}
+
+static int ping_mdm_register_data_cb(
+ struct msm_rpc_client *client,
+ struct ping_mdm_register_data_cb_arg *arg,
+ struct ping_mdm_register_data_cb_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ PING_MDM_REGISTER_DATA_CB_PROC,
+ ping_mdm_data_cb_register_arg, arg,
+ ping_mdm_data_cb_register_ret, ret, -1);
+}
+
+static int ping_mdm_unregister_data_cb(
+ struct msm_rpc_client *client,
+ struct ping_mdm_unregister_data_cb_arg *arg,
+ struct ping_mdm_unregister_data_cb_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ PING_MDM_UNREGISTER_DATA_CB_PROC,
+ ping_mdm_data_cb_unregister_arg, arg,
+ ping_mdm_data_cb_register_ret, ret, -1);
+}
+
+struct ping_mdm_data_arg {
+ uint32_t *data;
+ uint32_t size;
+};
+
+struct ping_mdm_data_ret {
+ uint32_t result;
+};
+
+static int ping_mdm_data_register_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ int i;
+ struct ping_mdm_data_arg *data_ptr;
+
+ data_ptr = (struct ping_mdm_data_arg *)data;
+
+ *((uint32_t *)buf) = cpu_to_be32(data_ptr->size);
+ buf += sizeof(data_ptr->size);
+ for (i = 0; i < data_ptr->size; i++) {
+ *((uint32_t *)buf) = cpu_to_be32(data_ptr->data[i]);
+ buf += sizeof(*data_ptr->data);
+ }
+
+ *((uint32_t *)buf) = cpu_to_be32(data_ptr->size);
+
+ return (data_ptr->size * sizeof(uint32_t)) +
+ (sizeof(data_ptr->size) * 2);
+}
+
+static int ping_mdm_data_register_ret(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_data_ret *data_ptr, *buf_ptr;
+
+ data_ptr = (struct ping_mdm_data_ret *)data;
+ buf_ptr = (struct ping_mdm_data_ret *)buf;
+
+ data_ptr->result = be32_to_cpu(buf_ptr->result);
+ return 0;
+}
+
+static int ping_mdm_data_register(
+ struct msm_rpc_client *client,
+ struct ping_mdm_data_arg *arg,
+ struct ping_mdm_data_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ PING_MDM_REGISTER_DATA_PROC,
+ ping_mdm_data_register_arg, arg,
+ ping_mdm_data_register_ret, ret, -1);
+}
+
+struct ping_mdm_register_arg {
+ int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
+ int num;
+};
+
+struct ping_mdm_unregister_arg {
+ int (*cb_func)(struct ping_mdm_register_cb_arg *, void *);
+};
+
+struct ping_mdm_register_ret {
+ uint32_t result;
+};
+
+struct ping_mdm_unregister_ret {
+ uint32_t result;
+};
+
+static int ping_mdm_register_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_register_arg *arg;
+ int cb_id, size = 0;
+
+ arg = (struct ping_mdm_register_arg *)data;
+
+ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+ if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+ return cb_id;
+
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id);
+ size += sizeof(uint32_t);
+ buf += sizeof(uint32_t);
+
+ *((int32_t *)buf) = cpu_to_be32(arg->num);
+ size += sizeof(uint32_t);
+
+ return size;
+}
+
+static int ping_mdm_unregister_arg(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_unregister_arg *arg;
+ int cb_id;
+
+ arg = (struct ping_mdm_unregister_arg *)data;
+
+ cb_id = msm_rpc_add_cb_func(client, (void *)arg->cb_func);
+ if ((cb_id < 0) && (cb_id != MSM_RPC_CLIENT_NULL_CB_ID))
+ return cb_id;
+
+ *((uint32_t *)buf) = cpu_to_be32((uint32_t)cb_id);
+
+ return sizeof(uint32_t);
+}
+
+static int ping_mdm_register_ret(struct msm_rpc_client *client,
+ void *buf, void *data)
+{
+ struct ping_mdm_register_ret *data_ptr, *buf_ptr;
+
+ data_ptr = (struct ping_mdm_register_ret *)data;
+ buf_ptr = (struct ping_mdm_register_ret *)buf;
+
+ data_ptr->result = be32_to_cpu(buf_ptr->result);
+
+ return 0;
+}
+
+static int ping_mdm_register(
+ struct msm_rpc_client *client,
+ struct ping_mdm_register_arg *arg,
+ struct ping_mdm_register_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ PING_MDM_REGISTER_PROC,
+ ping_mdm_register_arg, arg,
+ ping_mdm_register_ret, ret, -1);
+}
+
+static int ping_mdm_unregister(
+ struct msm_rpc_client *client,
+ struct ping_mdm_unregister_arg *arg,
+ struct ping_mdm_unregister_ret *ret)
+{
+ return msm_rpc_client_req(client,
+ PING_MDM_UNREGISTER_PROC,
+ ping_mdm_unregister_arg, arg,
+ ping_mdm_register_ret, ret, -1);
+}
+
+static int ping_mdm_null(struct msm_rpc_client *client,
+ void *arg, void *ret)
+{
+ return msm_rpc_client_req(client, PING_MDM_NULL_PROC,
+ NULL, NULL, NULL, NULL, -1);
+}
+
+static int ping_mdm_close(void)
+{
+ mutex_lock(&ping_mdm_lock);
+ if (--open_count == 0) {
+ msm_rpc_unregister_client(rpc_client);
+ pr_info("%s: disconnected from remote ping server\n",
+ __func__);
+ }
+ mutex_unlock(&ping_mdm_lock);
+ return 0;
+}
+
+static struct msm_rpc_client *ping_mdm_init(void)
+{
+ mutex_lock(&ping_mdm_lock);
+ if (open_count == 0) {
+ rpc_client = msm_rpc_register_client("pingdef",
+ PING_MDM_PROG,
+ PING_MDM_VERS, 1,
+ ping_mdm_cb_func);
+ if (!IS_ERR(rpc_client))
+ open_count++;
+ }
+ mutex_unlock(&ping_mdm_lock);
+ return rpc_client;
+}
+
+static struct dentry *dent;
+
+static DEFINE_MUTEX(ping_mdm_cb_lock);
+static LIST_HEAD(ping_mdm_cb_list);
+static uint32_t test_res;
+
+static int reg_cb_num, reg_cb_num_req;
+static int data_cb_num, data_cb_num_req;
+static int reg_done_flag, data_cb_done_flag;
+static DECLARE_WAIT_QUEUE_HEAD(reg_test_wait);
+static DECLARE_WAIT_QUEUE_HEAD(data_cb_test_wait);
+
+static int ping_mdm_data_register_test(void)
+{
+ int i, rc = 0;
+ uint32_t my_data[64];
+ uint32_t my_sum = 0;
+ struct ping_mdm_data_arg data_arg;
+ struct ping_mdm_data_ret data_ret;
+
+ for (i = 0; i < 64; i++) {
+ my_data[i] = (42 + i);
+ my_sum ^= (42 + i);
+ }
+
+ data_arg.data = my_data;
+ data_arg.size = 64;
+
+ rc = ping_mdm_data_register(rpc_client, &data_arg, &data_ret);
+ if (rc)
+ return rc;
+
+ if (my_sum != data_ret.result) {
+ pr_err("%s: sum mismatch %d %d\n",
+ __func__, my_sum, data_ret.result);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static int ping_mdm_test_register_data_cb(
+ struct ping_mdm_register_data_cb_cb_arg *arg,
+ struct ping_mdm_register_data_cb_cb_ret *ret)
+{
+ uint32_t i, sum = 0;
+
+ pr_info("%s: received cb_id %d, size = %d, sum = %u\n",
+ __func__, arg->cb_id, arg->size, arg->sum);
+
+ if (arg->data)
+ for (i = 0; i < arg->size; i++)
+ sum ^= arg->data[i];
+
+ if (sum != arg->sum)
+ pr_err("%s: sum mismatch %d %d\n", __func__, sum, arg->sum);
+
+ data_cb_num++;
+ if (data_cb_num == data_cb_num_req) {
+ data_cb_done_flag = 1;
+ wake_up(&data_cb_test_wait);
+ }
+
+ ret->result = 1;
+ return 0;
+}
+
+static int ping_mdm_data_cb_register_test(void)
+{
+ int rc = 0;
+ struct ping_mdm_register_data_cb_arg reg_arg;
+ struct ping_mdm_unregister_data_cb_arg unreg_arg;
+ struct ping_mdm_register_data_cb_ret reg_ret;
+ struct ping_mdm_unregister_data_cb_ret unreg_ret;
+
+ data_cb_num = 0;
+ data_cb_num_req = 10;
+ data_cb_done_flag = 0;
+
+ reg_arg.cb_func = ping_mdm_test_register_data_cb;
+ reg_arg.num = 10;
+ reg_arg.size = 64;
+ reg_arg.interval_ms = 10;
+ reg_arg.num_tasks = 1;
+
+ rc = ping_mdm_register_data_cb(rpc_client, &reg_arg, &reg_ret);
+ if (rc)
+ return rc;
+
+ pr_info("%s: data_cb_register result: 0x%x\n",
+ __func__, reg_ret.result);
+ wait_event(data_cb_test_wait, data_cb_done_flag);
+
+ unreg_arg.cb_func = reg_arg.cb_func;
+ rc = ping_mdm_unregister_data_cb(rpc_client, &unreg_arg, &unreg_ret);
+ if (rc)
+ return rc;
+
+ pr_info("%s: data_cb_unregister result: 0x%x\n",
+ __func__, unreg_ret.result);
+
+ return 0;
+}
+
+static int ping_mdm_test_register_cb(
+ struct ping_mdm_register_cb_arg *arg, void *ret)
+{
+ pr_info("%s: received cb_id %d, val = %d\n",
+ __func__, arg->cb_id, arg->val);
+
+ reg_cb_num++;
+ if (reg_cb_num == reg_cb_num_req) {
+ reg_done_flag = 1;
+ wake_up(&reg_test_wait);
+ }
+ return 0;
+}
+
+static int ping_mdm_register_test(void)
+{
+ int rc = 0;
+ struct ping_mdm_register_arg reg_arg;
+ struct ping_mdm_unregister_arg unreg_arg;
+ struct ping_mdm_register_ret reg_ret;
+ struct ping_mdm_unregister_ret unreg_ret;
+
+ reg_cb_num = 0;
+ reg_cb_num_req = 10;
+ reg_done_flag = 0;
+
+ reg_arg.num = 10;
+ reg_arg.cb_func = ping_mdm_test_register_cb;
+
+ rc = ping_mdm_register(rpc_client, &reg_arg, &reg_ret);
+ if (rc)
+ return rc;
+
+ pr_info("%s: register result: 0x%x\n",
+ __func__, reg_ret.result);
+
+ wait_event(reg_test_wait, reg_done_flag);
+
+ unreg_arg.cb_func = ping_mdm_test_register_cb;
+ rc = ping_mdm_unregister(rpc_client, &unreg_arg, &unreg_ret);
+ if (rc)
+ return rc;
+
+ pr_info("%s: unregister result: 0x%x\n",
+ __func__, unreg_ret.result);
+
+ return 0;
+}
+
+static int ping_mdm_null_test(void)
+{
+ return ping_mdm_null(rpc_client, NULL, NULL);
+}
+
+static int ping_test_release(struct inode *ip, struct file *fp)
+{
+ return ping_mdm_close();
+}
+
+static int ping_test_open(struct inode *ip, struct file *fp)
+{
+ struct msm_rpc_client *client;
+
+ client = ping_mdm_init();
+ if (IS_ERR(client)) {
+ pr_err("%s: couldn't open ping client\n", __func__);
+ return PTR_ERR(client);
+ } else
+ pr_info("%s: connected to remote ping server\n",
+ __func__);
+
+ return 0;
+}
+
+static ssize_t ping_test_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char _buf[16];
+
+ snprintf(_buf, sizeof(_buf), "%i\n", test_res);
+
+ return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t ping_test_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ unsigned char cmd[64];
+ int len;
+
+ if (count < 1)
+ return 0;
+
+ len = count > 63 ? 63 : count;
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ /* lazy */
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "null_test", 64))
+ test_res = ping_mdm_null_test();
+ else if (!strncmp(cmd, "reg_test", 64))
+ test_res = ping_mdm_register_test();
+ else if (!strncmp(cmd, "data_reg_test", 64))
+ test_res = ping_mdm_data_register_test();
+ else if (!strncmp(cmd, "data_cb_reg_test", 64))
+ test_res = ping_mdm_data_cb_register_test();
+ else
+ test_res = -EINVAL;
+
+ return count;
+}
+
+static const struct file_operations debug_ops = {
+ .owner = THIS_MODULE,
+ .open = ping_test_open,
+ .read = ping_test_read,
+ .write = ping_test_write,
+ .release = ping_test_release,
+};
+
+static void __exit ping_test_exit(void)
+{
+ debugfs_remove(dent);
+}
+
+static int __init ping_test_init(void)
+{
+ dent = debugfs_create_file("ping_mdm", 0444, 0, NULL, &debug_ops);
+ test_res = 0;
+ open_count = 0;
+ return 0;
+}
+
+module_init(ping_test_init);
+module_exit(ping_test_exit);
+
+MODULE_DESCRIPTION("PING TEST Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
new file mode 100644
index 000000000000..d5d26cc021ed
--- /dev/null
+++ b/arch/arm/mach-msm/pm.c
@@ -0,0 +1,954 @@
+/* arch/arm/mach-msm/pm.c
+ *
+ * MSM Power Management Routines
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/pm_qos_params.h>
+#include <linux/proc_fs.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <mach/msm_iomap.h>
+#include <mach/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+
+#include "smd_private.h"
+#include "acpuclock.h"
+#include "clock.h"
+#include "proc_comm.h"
+#include "idle.h"
+#include "irq.h"
+#include "gpio.h"
+#include "timer.h"
+#include "pm.h"
+
+enum {
+ MSM_PM_DEBUG_SUSPEND = 1U << 0,
+ MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
+ MSM_PM_DEBUG_STATE = 1U << 2,
+ MSM_PM_DEBUG_CLOCK = 1U << 3,
+ MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
+ MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
+ MSM_PM_DEBUG_IDLE = 1U << 6,
+};
+static int msm_pm_debug_mask;
+module_param_named(debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#endif
+
+static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
+module_param_named(sleep_mode, msm_pm_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
+module_param_named(idle_sleep_mode, msm_pm_idle_sleep_mode, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
+module_param_named(idle_sleep_min_time, msm_pm_idle_sleep_min_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int msm_pm_idle_spin_time = CONFIG_MSM7X00A_IDLE_SPIN_TIME;
+module_param_named(idle_spin_time, msm_pm_idle_spin_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define A11S_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
+#define A11S_PWRDOWN (MSM_CSR_BASE + 0x440)
+#define A11S_STANDBY_CTL (MSM_CSR_BASE + 0x108)
+#define A11RAMBACKBIAS (MSM_CSR_BASE + 0x508)
+
+enum {
+ SLEEP_LIMIT_NONE = 0,
+ SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2
+};
+
+static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
+struct smsm_interrupt_info_ext {
+ uint32_t aArm_en_mask;
+ uint32_t aArm_interrupts_pending;
+ uint32_t aArm_wakeup_reason;
+ uint32_t aArm_rpc_prog;
+ uint32_t aArm_rpc_proc;
+ char aArm_smd_port_name[20];
+ uint32_t aArm_gpio_info;
+};
+static struct msm_pm_smem_addr_t {
+ uint32_t *sleep_delay;
+ uint32_t *limit_sleep;
+ struct smsm_interrupt_info *int_info;
+ struct smsm_interrupt_info_ext *int_info_ext;
+} msm_pm_sma;
+
+static uint32_t *msm_pm_reset_vector;
+static uint32_t msm_pm_max_sleep_time;
+static struct msm_pm_platform_data *msm_pm_modes;
+
+#ifdef CONFIG_MSM_IDLE_STATS
+enum msm_pm_time_stats_id {
+ MSM_PM_STAT_REQUESTED_IDLE,
+ MSM_PM_STAT_IDLE_SPIN,
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_IDLE_SLEEP,
+ MSM_PM_STAT_IDLE_FAILED_SLEEP,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ MSM_PM_STAT_FAILED_SUSPEND,
+ MSM_PM_STAT_NOT_IDLE,
+ MSM_PM_STAT_COUNT
+};
+
+static struct msm_pm_time_stats {
+ const char *name;
+ int64_t first_bucket_time;
+ int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int count;
+ int64_t total_time;
+} msm_pm_stats[MSM_PM_STAT_COUNT] = {
+ [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
+ [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
+ [MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
+ [MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
+ [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
+ [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
+ [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+ "idle-failed-power-collapse",
+ [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_SUSPEND].name = "suspend",
+ [MSM_PM_STAT_SUSPEND].first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
+ [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_NOT_IDLE].name = "not-idle",
+ [MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+};
+
+static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ int i;
+ int64_t bt;
+ msm_pm_stats[id].total_time += t;
+ msm_pm_stats[id].count++;
+ bt = t;
+ do_div(bt, msm_pm_stats[id].first_bucket_time);
+ if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ i = DIV_ROUND_UP(fls((uint32_t)bt),
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ else
+ i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+ msm_pm_stats[id].bucket[i]++;
+ if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
+ msm_pm_stats[id].min_time[i] = t;
+ if (t > msm_pm_stats[id].max_time[i])
+ msm_pm_stats[id].max_time[i] = t;
+}
+
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
+static DECLARE_BITMAP(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS);
+#endif
+
+static int
+msm_pm_wait_state(uint32_t wait_state_all_set, uint32_t wait_state_all_clear,
+ uint32_t wait_state_any_set, uint32_t wait_state_any_clear)
+{
+ int i;
+ uint32_t state;
+
+ for (i = 0; i < 2000000; i++) {
+ state = smsm_get_state(SMSM_MODEM_STATE);
+ if (((state & wait_state_all_set) == wait_state_all_set) &&
+ ((~state & wait_state_all_clear) == wait_state_all_clear) &&
+ (wait_state_any_set == 0 || (state & wait_state_any_set) ||
+ wait_state_any_clear == 0 || (state & wait_state_any_clear)))
+ return 0;
+ }
+ printk(KERN_ERR "msm_pm_wait_state(%x, %x, %x, %x) failed %x\n",
+ wait_state_all_set, wait_state_all_clear,
+ wait_state_any_set, wait_state_any_clear, state);
+ return -ETIMEDOUT;
+}
+
+/*
+ * Respond to timing out waiting for Modem
+ *
+ * NOTE: The function never returns.
+ */
+static void msm_pm_timeout(void)
+{
+#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
+ printk(KERN_EMERG "%s(): resetting chip\n", __func__);
+ msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
+#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
+ printk(KERN_EMERG "%s(): resetting modem\n", __func__);
+ msm_proc_comm_reset_modem_now();
+#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
+ printk(KERN_EMERG "%s(): halting\n", __func__);
+#endif
+ for (;;)
+ ;
+}
+
+static int msm_sleep(int sleep_mode, uint32_t sleep_delay,
+ uint32_t sleep_limit, int from_idle)
+{
+ uint32_t saved_vector[2];
+ int collapsed;
+ uint32_t enter_state;
+ uint32_t enter_wait_set = 0;
+ uint32_t enter_wait_clear = 0;
+ uint32_t exit_state;
+ uint32_t exit_wait_clear = 0;
+ uint32_t exit_wait_set = 0;
+ unsigned long pm_saved_acpu_clk_rate = 0;
+ int ret;
+ int rv = -EINTR;
+
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+ printk(KERN_INFO "msm_sleep(): "
+ "mode %d delay %u limit %u idle %d\n",
+ sleep_mode, sleep_delay, sleep_limit, from_idle);
+
+ switch (sleep_mode) {
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ enter_state = SMSM_PWRC;
+ enter_wait_set = SMSM_RSA;
+ exit_state = SMSM_WFPI;
+ exit_wait_clear = SMSM_RSA;
+ break;
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+ enter_state = SMSM_PWRC_SUSPEND;
+ enter_wait_set = SMSM_RSA;
+ exit_state = SMSM_WFPI;
+ exit_wait_clear = SMSM_RSA;
+ break;
+ case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+ enter_state = SMSM_SLEEP;
+ exit_state = SMSM_SLEEPEXIT;
+ exit_wait_set = SMSM_SLEEPEXIT;
+ break;
+ default:
+ enter_state = 0;
+ exit_state = 0;
+ }
+
+ if (enter_state && !(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RUN)) {
+ if ((MSM_PM_DEBUG_POWER_COLLAPSE | MSM_PM_DEBUG_SUSPEND) &
+ msm_pm_debug_mask)
+ printk(KERN_INFO "msm_sleep(): modem not ready\n");
+ rv = -EBUSY;
+ goto check_failed;
+ }
+
+ memset(msm_pm_sma.int_info, 0, sizeof(*msm_pm_sma.int_info));
+ msm_irq_enter_sleep1(!!enter_state, from_idle,
+ &msm_pm_sma.int_info->aArm_en_mask);
+ msm_gpio_enter_sleep(from_idle);
+
+ if (enter_state) {
+ if (sleep_delay == 0 && sleep_mode >= MSM_PM_SLEEP_MODE_APPS_SLEEP)
+ sleep_delay = 192000*5; /* APPS_SLEEP does not allow infinite timeout */
+
+ *msm_pm_sma.sleep_delay = sleep_delay;
+ *msm_pm_sma.limit_sleep = sleep_limit;
+ ret = smsm_change_state(SMSM_APPS_STATE, SMSM_RUN, enter_state);
+ if (ret) {
+ printk(KERN_ERR "msm_sleep(): smsm_change_state %x failed\n", enter_state);
+ enter_state = 0;
+ exit_state = 0;
+ }
+ ret = msm_pm_wait_state(enter_wait_set, enter_wait_clear, 0, 0);
+ if (ret) {
+ printk(KERN_EMERG "msm_sleep(): power collapse entry "
+ "timed out waiting for Modem's response\n");
+ msm_pm_timeout();
+ }
+ }
+ if (msm_irq_enter_sleep2(!!enter_state, from_idle))
+ goto enter_failed;
+
+ if (enter_state) {
+ writel(0x1f, A11S_CLK_SLEEP_EN);
+ writel(1, A11S_PWRDOWN);
+
+ writel(0, A11S_STANDBY_CTL);
+ writel(0, A11RAMBACKBIAS);
+
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+ printk(KERN_INFO "msm_sleep(): enter "
+ "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+ "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+ readl(A11S_PWRDOWN),
+ smsm_get_state(SMSM_MODEM_STATE));
+ }
+
+ if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
+ pm_saved_acpu_clk_rate = acpuclk_power_collapse();
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+ printk(KERN_INFO "msm_sleep(): %ld enter power collapse"
+ "\n", pm_saved_acpu_clk_rate);
+ if (pm_saved_acpu_clk_rate == 0)
+ goto ramp_down_failed;
+ }
+ if (sleep_mode < MSM_PM_SLEEP_MODE_APPS_SLEEP) {
+#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE
+ /* XXX: Temp workaround that needs to be removed soon. The
+ * right fix will probably involve the DMA driver taking
+ * ownership of the ADM clock. */
+ /* id is set to denote ADM clock. */
+ unsigned id = 1;
+ msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
+#endif
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+ smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
+ *msm_pm_sma.limit_sleep,
+ msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+ saved_vector[0] = msm_pm_reset_vector[0];
+ saved_vector[1] = msm_pm_reset_vector[1];
+ msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+ msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_RESET_VECTOR)
+ printk(KERN_INFO "msm_sleep(): vector %x %x -> "
+ "%x %x\n", saved_vector[0], saved_vector[1],
+ msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+ collapsed = msm_pm_collapse();
+ msm_pm_reset_vector[0] = saved_vector[0];
+ msm_pm_reset_vector[1] = saved_vector[1];
+ if (collapsed) {
+ cpu_init();
+ local_fiq_enable();
+ rv = 0;
+ }
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_POWER_COLLAPSE)
+ printk(KERN_INFO "msm_pm_collapse(): returned %d\n",
+ collapsed);
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+ smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
+ *msm_pm_sma.limit_sleep,
+ msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE
+ /* id is set to denote ADM clock. */
+ id = 1;
+ if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 ||
+ id < 0)
+ printk(KERN_ERR
+ "msm_sleep(): failed to turn on ADM clock\n");
+#endif
+ } else {
+ msm_arch_idle();
+ rv = 0;
+ }
+
+ if (sleep_mode <= MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT) {
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+ printk(KERN_INFO "msm_sleep(): exit power collapse %ld"
+ "\n", pm_saved_acpu_clk_rate);
+ if (acpuclk_set_rate(pm_saved_acpu_clk_rate, SETRATE_PC) < 0)
+ printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
+ "failed\n", pm_saved_acpu_clk_rate);
+ }
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+ printk(KERN_INFO "msm_sleep(): exit A11S_CLK_SLEEP_EN %x, "
+ "A11S_PWRDOWN %x, smsm_get_state %x\n",
+ readl(A11S_CLK_SLEEP_EN), readl(A11S_PWRDOWN),
+ smsm_get_state(SMSM_MODEM_STATE));
+ramp_down_failed:
+ msm_irq_exit_sleep1(msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+enter_failed:
+ if (enter_state) {
+ writel(0x00, A11S_CLK_SLEEP_EN);
+ writel(0, A11S_PWRDOWN);
+ smsm_change_state(SMSM_APPS_STATE, enter_state, exit_state);
+ if (msm_pm_wait_state(exit_wait_set, exit_wait_clear, 0, 0)) {
+ printk(KERN_EMERG "msm_sleep(): power collapse exit "
+ "timed out waiting for Modem's response\n");
+ msm_pm_timeout();
+ }
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+ printk(KERN_INFO "msm_sleep(): sleep exit "
+ "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+ "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+ readl(A11S_PWRDOWN),
+ smsm_get_state(SMSM_MODEM_STATE));
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE)
+ smsm_print_sleep_info(*msm_pm_sma.sleep_delay,
+ *msm_pm_sma.limit_sleep,
+ msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+ }
+ msm_irq_exit_sleep2(msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+ if (enter_state) {
+ smsm_change_state(SMSM_APPS_STATE, exit_state, SMSM_RUN);
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_STATE)
+ printk(KERN_INFO "msm_sleep(): sleep exit "
+ "A11S_CLK_SLEEP_EN %x, A11S_PWRDOWN %x, "
+ "smsm_get_state %x\n", readl(A11S_CLK_SLEEP_EN),
+ readl(A11S_PWRDOWN),
+ smsm_get_state(SMSM_MODEM_STATE));
+ }
+ msm_irq_exit_sleep3(msm_pm_sma.int_info->aArm_en_mask,
+ msm_pm_sma.int_info->aArm_wakeup_reason,
+ msm_pm_sma.int_info->aArm_interrupts_pending);
+ msm_gpio_exit_sleep();
+ smd_sleep_exit();
+
+check_failed:
+ return rv;
+}
+
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
+{
+ int64_t max_sleep_time_bs = max_sleep_time_ns;
+
+ /* Convert from ns -> BS units */
+ do_div(max_sleep_time_bs, NSEC_PER_SEC / 32768);
+
+ if (max_sleep_time_bs > 0x6DDD000)
+ msm_pm_max_sleep_time = (uint32_t) 0x6DDD000;
+ else
+ msm_pm_max_sleep_time = (uint32_t) max_sleep_time_bs;
+
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+ printk(KERN_INFO "%s: Requested %lldns (%lldbs), Giving %ubs\n",
+ __func__, max_sleep_time_ns,
+ max_sleep_time_bs,
+ msm_pm_max_sleep_time);
+}
+EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+void arch_idle(void)
+{
+ int ret;
+ int spin;
+ int64_t sleep_time;
+ int low_power = 0;
+ struct msm_pm_platform_data *mode;
+#ifdef CONFIG_MSM_IDLE_STATS
+ DECLARE_BITMAP(clk_ids, NR_CLKS);
+ int64_t t1;
+ static int64_t t2;
+ int exit_stat;
+#endif
+ int latency_qos = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY);
+ uint32_t sleep_limit = SLEEP_LIMIT_NONE;
+ int allow_sleep =
+ msm_pm_idle_sleep_mode < MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT &&
+#ifdef CONFIG_HAS_WAKELOCK
+ !has_wake_lock(WAKE_LOCK_IDLE) &&
+#endif
+ msm_irq_idle_sleep_allowed();
+
+ if (!atomic_read(&msm_pm_init_done))
+ return;
+
+ sleep_time = msm_timer_enter_idle();
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ t1 = ktime_to_ns(ktime_get());
+ msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
+ msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, sleep_time);
+#endif
+
+ mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE];
+ if (mode->latency >= latency_qos)
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+
+ mode = &msm_pm_modes[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN];
+ if (mode->latency >= latency_qos)
+ allow_sleep = false;
+
+ mode = &msm_pm_modes[
+ MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT];
+ if (mode->latency >= latency_qos) {
+ /* no time even for SWFI */
+ while (!msm_irq_pending())
+ udelay(1);
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif
+ goto abort_idle;
+ }
+
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_IDLE)
+ printk(KERN_INFO "arch_idle: sleep time %llu, allow_sleep %d\n",
+ sleep_time, allow_sleep);
+ spin = msm_pm_idle_spin_time >> 10;
+ while (spin-- > 0) {
+ if (msm_irq_pending()) {
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif
+ goto abort_idle;
+ }
+ udelay(1);
+ }
+ if (sleep_time < msm_pm_idle_sleep_min_time || !allow_sleep) {
+ unsigned long saved_rate;
+ saved_rate = acpuclk_wait_for_irq();
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+ printk(KERN_DEBUG "arch_idle: clk %ld -> swfi\n",
+ saved_rate);
+ if (saved_rate) {
+ msm_arch_idle();
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_WFI;
+#endif
+ } else {
+ while (!msm_irq_pending())
+ udelay(1);
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif
+ }
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_CLOCK)
+ printk(KERN_DEBUG "msm_sleep: clk swfi -> %ld\n",
+ saved_rate);
+ if (saved_rate
+ && acpuclk_set_rate(saved_rate, SETRATE_SWFI) < 0)
+ printk(KERN_ERR "msm_sleep(): clk_set_rate %ld "
+ "failed\n", saved_rate);
+ } else {
+#ifdef CONFIG_MSM_IDLE_STATS
+ ret = msm_clock_require_tcxo(clk_ids, NR_CLKS);
+#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT)
+ ret = msm_clock_require_tcxo(NULL, 0);
+#endif
+
+#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT
+ if (ret)
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+#endif
+
+ low_power = 1;
+ do_div(sleep_time, NSEC_PER_SEC / 32768);
+ if (sleep_time > 0x6DDD000) {
+ printk("sleep_time too big %lld\n", sleep_time);
+ sleep_time = 0x6DDD000;
+ }
+ ret = msm_sleep(msm_pm_idle_sleep_mode, sleep_time,
+ sleep_limit, 1);
+#ifdef CONFIG_MSM_IDLE_STATS
+ switch (msm_pm_idle_sleep_mode) {
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ if (ret)
+ exit_stat =
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+ else {
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_sleep_limit = sleep_limit;
+ bitmap_copy(msm_pm_clocks_no_tcxo_shutdown,
+ clk_ids, NR_CLKS);
+ }
+ break;
+ case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+ if (ret)
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
+ else
+ exit_stat = MSM_PM_STAT_IDLE_SLEEP;
+ break;
+ default:
+ exit_stat = MSM_PM_STAT_IDLE_WFI;
+ }
+#endif
+ }
+abort_idle:
+ msm_timer_exit_idle(low_power);
+#ifdef CONFIG_MSM_IDLE_STATS
+ t2 = ktime_to_ns(ktime_get());
+ msm_pm_add_stat(exit_stat, t2 - t1);
+#endif
+}
+
+static int msm_pm_enter(suspend_state_t state)
+{
+ uint32_t sleep_limit;
+ int ret;
+#ifdef CONFIG_MSM_IDLE_STATS
+ DECLARE_BITMAP(clk_ids, NR_CLKS);
+ int64_t period = 0;
+ int64_t time = 0;
+
+ time = msm_timer_get_sclk_time(&period);
+ ret = msm_clock_require_tcxo(clk_ids, NR_CLKS);
+#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT)
+ ret = msm_clock_require_tcxo(NULL, 0);
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT
+ sleep_limit = ret ? SLEEP_LIMIT_NO_TCXO_SHUTDOWN : SLEEP_LIMIT_NONE;
+#else
+ sleep_limit = SLEEP_LIMIT_NONE;
+#endif
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+ if (msm_pm_sleep_time_override > 0) {
+ int64_t ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
+ msm_pm_set_max_sleep_time(ns);
+ msm_pm_sleep_time_override = 0;
+ }
+#endif
+
+ ret = msm_sleep(msm_pm_sleep_mode,
+ msm_pm_max_sleep_time, sleep_limit, 0);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ if (msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND ||
+ msm_pm_sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ enum msm_pm_time_stats_id id;
+ int64_t end_time;
+
+ if (ret)
+ id = MSM_PM_STAT_FAILED_SUSPEND;
+ else {
+ id = MSM_PM_STAT_SUSPEND;
+ msm_pm_sleep_limit = sleep_limit;
+ bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids,
+ NR_CLKS);
+ }
+
+ if (time != 0) {
+ end_time = msm_timer_get_sclk_time(NULL);
+ if (end_time != 0) {
+ time = end_time - time;
+ if (time < 0)
+ time += period;
+ } else
+ time = 0;
+ }
+
+ msm_pm_add_stat(id, time);
+ }
+#endif
+
+ return 0;
+}
+
+static struct platform_suspend_ops msm_pm_ops = {
+ .enter = msm_pm_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static uint32_t restart_reason = 0x776655AA;
+
+static void msm_pm_power_off(void)
+{
+ msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
+ for (;;) ;
+}
+
+static void msm_pm_restart(char str, const char *cmd)
+{
+ msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
+
+ for (;;) ;
+}
+
+static int msm_reboot_call(struct notifier_block *this, unsigned long code, void *_cmd)
+{
+ if((code == SYS_RESTART) && _cmd) {
+ char *cmd = _cmd;
+ if (!strcmp(cmd, "bootloader")) {
+ restart_reason = 0x77665500;
+ } else if (!strcmp(cmd, "recovery")) {
+ restart_reason = 0x77665502;
+ } else if (!strcmp(cmd, "eraseflash")) {
+ restart_reason = 0x776655EF;
+ } else if (!strncmp(cmd, "oem-", 4)) {
+ unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
+ restart_reason = 0x6f656d00 | code;
+ } else {
+ restart_reason = 0x77665501;
+ }
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_reboot_notifier =
+{
+ .notifier_call = msm_reboot_call,
+};
+
+#ifdef CONFIG_MSM_IDLE_STATS
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+ do { \
+ if (size > 0) { \
+ int ret; \
+ ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+ if (ret > size) { \
+ buf += size; \
+ size = 0; \
+ } else { \
+ buf += ret; \
+ size -= ret; \
+ } \
+ } \
+ } while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc(
+ char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int i;
+ char *p = page;
+ char clk_name[16];
+
+ if (count < 1024) {
+ *start = (char *) 0;
+ *eof = 0;
+ return 0;
+ }
+
+ if (!off) {
+ SNPRINTF(p, count, "Clocks against last TCXO shutdown:\n");
+ for_each_bit(i, msm_pm_clocks_no_tcxo_shutdown, NR_CLKS) {
+ clk_name[0] = '\0';
+ msm_clock_get_name(i, clk_name, sizeof(clk_name));
+ SNPRINTF(p, count, " %s (id=%d)\n", clk_name, i);
+ }
+
+ SNPRINTF(p, count, "Last power collapse voted ");
+ if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE)
+ SNPRINTF(p, count, "for TCXO shutdown\n\n");
+ else
+ SNPRINTF(p, count, "against TCXO shutdown\n\n");
+
+ *start = (char *) 1;
+ *eof = 0;
+ } else if (--off < ARRAY_SIZE(msm_pm_stats)) {
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+
+ s = msm_pm_stats[off].total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ "%s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ msm_pm_stats[off].name,
+ msm_pm_stats[off].count,
+ s, ns);
+
+ bucket_time = msm_pm_stats[off].first_bucket_time;
+ for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, msm_pm_stats[off].bucket[i],
+ msm_pm_stats[off].min_time[i],
+ msm_pm_stats[off].max_time[i]);
+
+ bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+ }
+
+ SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, msm_pm_stats[off].bucket[i],
+ msm_pm_stats[off].min_time[i],
+ msm_pm_stats[off].max_time[i]);
+
+ *start = (char *) 1;
+ *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
+ }
+
+ return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char buf[sizeof(MSM_PM_STATS_RESET)];
+ int ret;
+ unsigned long flags;
+ int i;
+
+ if (count < strlen(MSM_PM_STATS_RESET)) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
+ ret = -EFAULT;
+ goto write_proc_failed;
+ }
+
+ if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ local_irq_save(flags);
+ for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
+ memset(msm_pm_stats[i].bucket,
+ 0, sizeof(msm_pm_stats[i].bucket));
+ memset(msm_pm_stats[i].min_time,
+ 0, sizeof(msm_pm_stats[i].min_time));
+ memset(msm_pm_stats[i].max_time,
+ 0, sizeof(msm_pm_stats[i].max_time));
+ msm_pm_stats[i].count = 0;
+ msm_pm_stats[i].total_time = 0;
+ }
+
+ msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
+ bitmap_zero(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS);
+ local_irq_restore(flags);
+
+ return count;
+
+write_proc_failed:
+ return ret;
+}
+#undef MSM_PM_STATS_RESET
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+static int __init msm_pm_init(void)
+{
+#ifdef CONFIG_MSM_IDLE_STATS
+ struct proc_dir_entry *d_entry;
+#endif
+
+ pm_power_off = msm_pm_power_off;
+ arm_pm_restart = msm_pm_restart;
+ msm_pm_max_sleep_time = 0;
+
+ register_reboot_notifier(&msm_reboot_notifier);
+
+ msm_pm_sma.sleep_delay = smem_alloc(SMEM_SMSM_SLEEP_DELAY,
+ sizeof(*msm_pm_sma.sleep_delay));
+ if (msm_pm_sma.sleep_delay == NULL) {
+ printk(KERN_ERR "msm_pm_init: failed get SLEEP_DELAY\n");
+ return -ENODEV;
+ }
+
+ msm_pm_sma.limit_sleep = smem_alloc(SMEM_SMSM_LIMIT_SLEEP,
+ sizeof(*msm_pm_sma.limit_sleep));
+ if (msm_pm_sma.limit_sleep == NULL) {
+ printk(KERN_ERR "msm_pm_init: failed get LIMIT_SLEEP\n");
+ return -ENODEV;
+ }
+
+ msm_pm_sma.int_info_ext = smem_alloc(SMEM_SMSM_INT_INFO,
+ sizeof(*msm_pm_sma.int_info_ext));
+
+ if (msm_pm_sma.int_info_ext)
+ msm_pm_sma.int_info = (struct smsm_interrupt_info *)
+ msm_pm_sma.int_info_ext;
+ else
+ msm_pm_sma.int_info = smem_alloc(SMEM_SMSM_INT_INFO,
+ sizeof(*msm_pm_sma.int_info));
+
+ if (msm_pm_sma.int_info == NULL) {
+ printk(KERN_ERR "msm_pm_init: failed get INT_INFO\n");
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+ /* The bootloader is responsible for initializing many of Scorpion's
+ * coprocessor registers for things like cache timing. The state of
+ * these coprocessor registers is lost on reset, so part of the
+ * bootloader must be re-executed. Do not overwrite the reset vector
+ * or bootloader area.
+ */
+ msm_pm_reset_vector = PAGE_OFFSET;
+#else
+ msm_pm_reset_vector = ioremap(0, PAGE_SIZE);
+ if (msm_pm_reset_vector == NULL) {
+ printk(KERN_ERR "msm_pm_init: failed to map reset vector\n");
+ return -ENODEV;
+ }
+#endif /* CONFIG_ARCH_MSM_SCORPION */
+
+ BUG_ON(msm_pm_modes == NULL);
+
+ atomic_set(&msm_pm_init_done, 1);
+ suspend_set_ops(&msm_pm_ops);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ d_entry = create_proc_entry("msm_pm_stats",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+ if (d_entry) {
+ d_entry->read_proc = msm_pm_read_proc;
+ d_entry->write_proc = msm_pm_write_proc;
+ d_entry->data = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+void __init msm_pm_set_platform_data(struct msm_pm_platform_data *data)
+{
+ msm_pm_modes = data;
+}
+
+late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
new file mode 100644
index 000000000000..b6e60e9683ce
--- /dev/null
+++ b/arch/arm/mach-msm/pm.h
@@ -0,0 +1,42 @@
+/* arch/arm/mach-msm/pm.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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 __ARCH_ARM_MACH_MSM_PM_H
+#define __ARCH_ARM_MACH_MSM_PM_H
+
+enum {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_PM_SLEEP_MODE_APPS_SLEEP,
+ MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
+ MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
+ MSM_PM_SLEEP_MODE_NR
+};
+
+struct msm_pm_platform_data {
+ u8 supported;
+ u8 suspend_enabled; /* enabled for suspend */
+ u8 idle_enabled; /* enabled for idle low power */
+ u32 latency; /* interrupt latency in microseconds when entering
+ and exiting the low power mode */
+ u32 residency; /* time threshold in microseconds beyond which
+ staying in the low power mode saves power */
+};
+
+void msm_pm_set_platform_data(struct msm_pm_platform_data *data);
+#endif
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
new file mode 100644
index 000000000000..dd5d690b76a5
--- /dev/null
+++ b/arch/arm/mach-msm/pm2.c
@@ -0,0 +1,1666 @@
+/* arch/arm/mach-msm/pm2.c
+ *
+ * MSM Power Management Routines
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/pm_qos_params.h>
+#include <linux/proc_fs.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include <mach/system.h>
+#ifdef CONFIG_CACHE_L2X0
+#include <asm/hardware/cache-l2x0.h>
+#endif
+#ifdef CONFIG_VFP
+#include <asm/vfp.h>
+#endif
+
+#include "smd_private.h"
+#include "acpuclock.h"
+#include "clock.h"
+#include "proc_comm.h"
+#include "idle.h"
+#include "irq.h"
+#include "gpio.h"
+#include "timer.h"
+#include "pm.h"
+
+/******************************************************************************
+ * Debug Definitions
+ *****************************************************************************/
+
+enum {
+ MSM_PM_DEBUG_SUSPEND = 1U << 0,
+ MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
+ MSM_PM_DEBUG_STATE = 1U << 2,
+ MSM_PM_DEBUG_CLOCK = 1U << 3,
+ MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
+ MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
+ MSM_PM_DEBUG_IDLE = 1U << 6,
+};
+
+static int msm_pm_debug_mask;
+module_param_named(
+ debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+#define MSM_PM_DPRINTK(mask, level, message, ...) \
+ do { \
+ if ((mask) & msm_pm_debug_mask) \
+ printk(level message, ## __VA_ARGS__); \
+ } while (0)
+
+#define MSM_PM_DEBUG_PRINT_STATE(tag) \
+ do { \
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_STATE, \
+ KERN_INFO, "%s: " \
+ "APPS_CLK_SLEEP_EN %x, APPS_PWRDOWN %x, " \
+ "SMSM_POWER_MASTER_DEM %x, SMSM_MODEM_STATE %x, " \
+ "SMSM_APPS_DEM %x\n", \
+ tag, \
+ readl(APPS_CLK_SLEEP_EN), readl(APPS_PWRDOWN), \
+ smsm_get_state(SMSM_POWER_MASTER_DEM), \
+ smsm_get_state(SMSM_MODEM_STATE), \
+ smsm_get_state(SMSM_APPS_DEM)); \
+ } while (0)
+
+#define MSM_PM_DEBUG_PRINT_SLEEP_INFO() \
+ do { \
+ if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) \
+ smsm_print_sleep_info(msm_pm_smem_data->sleep_time, \
+ msm_pm_smem_data->resources_used, \
+ msm_pm_smem_data->irq_mask, \
+ msm_pm_smem_data->wakeup_reason, \
+ msm_pm_smem_data->pending_irqs); \
+ } while (0)
+
+
+/******************************************************************************
+ * Sleep Modes and Parameters
+ *****************************************************************************/
+
+static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
+module_param_named(
+ sleep_mode, msm_pm_sleep_mode,
+ int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
+module_param_named(
+ idle_sleep_mode, msm_pm_idle_sleep_mode,
+ int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
+module_param_named(
+ idle_sleep_min_time, msm_pm_idle_sleep_min_time,
+ int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+#define MSM_PM_MODE_ATTR_SUSPEND_ENABLED "suspend_enabled"
+#define MSM_PM_MODE_ATTR_IDLE_ENABLED "idle_enabled"
+#define MSM_PM_MODE_ATTR_LATENCY "latency"
+#define MSM_PM_MODE_ATTR_RESIDENCY "residency"
+#define MSM_PM_MODE_ATTR_NR (4)
+
+static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
+ [MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep",
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
+ "ramp_down_and_wfi",
+ [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+ [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] =
+ "power_collapse_no_xo_shutdown",
+};
+
+static struct msm_pm_platform_data *msm_pm_modes;
+
+static struct kobject *msm_pm_mode_kobjs[MSM_PM_SLEEP_MODE_NR];
+static struct attribute_group *msm_pm_mode_attr_group[MSM_PM_SLEEP_MODE_NR];
+static struct attribute **msm_pm_mode_attrs[MSM_PM_SLEEP_MODE_NR];
+static struct kobj_attribute *msm_pm_mode_kobj_attrs[MSM_PM_SLEEP_MODE_NR];
+
+/*
+ * Write out the attribute.
+ */
+static ssize_t msm_pm_mode_attr_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct kernel_param kp;
+
+ if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+ continue;
+
+ if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_SUSPEND_ENABLED)) {
+ u32 arg = msm_pm_modes[i].suspend_enabled;
+ kp.arg = &arg;
+ ret = param_get_ulong(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_IDLE_ENABLED)) {
+ u32 arg = msm_pm_modes[i].idle_enabled;
+ kp.arg = &arg;
+ ret = param_get_ulong(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_LATENCY)) {
+ kp.arg = &msm_pm_modes[i].latency;
+ ret = param_get_ulong(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_RESIDENCY)) {
+ kp.arg = &msm_pm_modes[i].residency;
+ ret = param_get_ulong(buf, &kp);
+ }
+
+ break;
+ }
+
+ if (ret > 0) {
+ strcat(buf, "\n");
+ ret++;
+ }
+
+ return ret;
+}
+
+/*
+ * Read in the new attribute value.
+ */
+static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int ret = -EINVAL;
+ int i;
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct kernel_param kp;
+
+ if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+ continue;
+
+ if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_SUSPEND_ENABLED)) {
+ kp.arg = &msm_pm_modes[i].suspend_enabled;
+ ret = param_set_byte(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_IDLE_ENABLED)) {
+ kp.arg = &msm_pm_modes[i].idle_enabled;
+ ret = param_set_byte(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_LATENCY)) {
+ kp.arg = &msm_pm_modes[i].latency;
+ ret = param_set_ulong(buf, &kp);
+ } else if (!strcmp(attr->attr.name,
+ MSM_PM_MODE_ATTR_RESIDENCY)) {
+ kp.arg = &msm_pm_modes[i].residency;
+ ret = param_set_ulong(buf, &kp);
+ }
+
+ break;
+ }
+
+ return ret ? ret : count;
+}
+
+/*
+ * Add sysfs entries for the sleep modes.
+ */
+static int __init msm_pm_mode_sysfs_add(void)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *modes_kobj = NULL;
+
+ struct kobject *kobj;
+ struct attribute_group *attr_group;
+ struct attribute **attrs;
+ struct kobj_attribute *kobj_attrs;
+
+ int i, k;
+ int ret;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ printk(KERN_ERR "%s: cannot find kobject for module %s\n",
+ __func__, KBUILD_MODNAME);
+ ret = -ENOENT;
+ goto mode_sysfs_add_cleanup;
+ }
+
+ modes_kobj = kobject_create_and_add("modes", module_kobj);
+ if (!modes_kobj) {
+ printk(KERN_ERR "%s: cannot create modes kobject\n", __func__);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_cleanup;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_pm_mode_kobjs); i++) {
+ if (!msm_pm_modes[i].supported)
+ continue;
+
+ kobj = kobject_create_and_add(
+ msm_pm_sleep_mode_labels[i], modes_kobj);
+ attr_group = kzalloc(sizeof(*attr_group), GFP_KERNEL);
+ attrs = kzalloc(sizeof(*attrs) * (MSM_PM_MODE_ATTR_NR + 1),
+ GFP_KERNEL);
+ kobj_attrs = kzalloc(sizeof(*kobj_attrs) * MSM_PM_MODE_ATTR_NR,
+ GFP_KERNEL);
+
+ if (!kobj || !attr_group || !attrs || !kobj_attrs) {
+ printk(KERN_ERR
+ "%s: cannot create kobject or attributes\n",
+ __func__);
+ ret = -ENOMEM;
+ goto mode_sysfs_add_abort;
+ }
+
+ kobj_attrs[0].attr.name = MSM_PM_MODE_ATTR_SUSPEND_ENABLED;
+ kobj_attrs[1].attr.name = MSM_PM_MODE_ATTR_IDLE_ENABLED;
+ kobj_attrs[2].attr.name = MSM_PM_MODE_ATTR_LATENCY;
+ kobj_attrs[3].attr.name = MSM_PM_MODE_ATTR_RESIDENCY;
+
+ for (k = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
+ kobj_attrs[k].attr.mode = 0644;
+ kobj_attrs[k].show = msm_pm_mode_attr_show;
+ kobj_attrs[k].store = msm_pm_mode_attr_store;
+
+ attrs[k] = &kobj_attrs[k].attr;
+ }
+ attrs[MSM_PM_MODE_ATTR_NR] = NULL;
+
+ attr_group->attrs = attrs;
+ ret = sysfs_create_group(kobj, attr_group);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: cannot create kobject attribute group\n",
+ __func__);
+ goto mode_sysfs_add_abort;
+ }
+
+ msm_pm_mode_kobjs[i] = kobj;
+ msm_pm_mode_attr_group[i] = attr_group;
+ msm_pm_mode_attrs[i] = attrs;
+ msm_pm_mode_kobj_attrs[i] = kobj_attrs;
+ }
+
+ return 0;
+
+mode_sysfs_add_abort:
+ kfree(kobj_attrs);
+ kfree(attrs);
+ kfree(attr_group);
+ kobject_put(kobj);
+
+mode_sysfs_add_cleanup:
+ for (i = ARRAY_SIZE(msm_pm_mode_kobjs) - 1; i >= 0; i--) {
+ if (!msm_pm_mode_kobjs[i])
+ continue;
+
+ sysfs_remove_group(
+ msm_pm_mode_kobjs[i], msm_pm_mode_attr_group[i]);
+
+ kfree(msm_pm_mode_kobj_attrs[i]);
+ kfree(msm_pm_mode_attrs[i]);
+ kfree(msm_pm_mode_attr_group[i]);
+ kobject_put(msm_pm_mode_kobjs[i]);
+ }
+
+ return ret;
+}
+
+void __init msm_pm_set_platform_data(struct msm_pm_platform_data *data)
+{
+ msm_pm_modes = data;
+}
+
+
+/******************************************************************************
+ * Sleep Limitations
+ *****************************************************************************/
+enum {
+ SLEEP_LIMIT_NONE = 0,
+ SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2
+};
+
+
+/******************************************************************************
+ * Configure Hardware for Power Down/Up
+ *****************************************************************************/
+
+#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
+#define APPS_PWRDOWN (MSM_CSR_BASE + 0x440)
+#define APPS_STANDBY_CTL (MSM_CSR_BASE + 0x108)
+
+/*
+ * Configure hardware registers in preparation for Apps power down.
+ */
+static void msm_pm_config_hw_before_power_down(void)
+{
+ writel(0x1f, APPS_CLK_SLEEP_EN);
+ writel(1, APPS_PWRDOWN);
+ writel(0, APPS_STANDBY_CTL);
+}
+
+/*
+ * Clear hardware registers after Apps powers up.
+ */
+static void msm_pm_config_hw_after_power_up(void)
+{
+ writel(0, APPS_PWRDOWN);
+ writel(0, APPS_CLK_SLEEP_EN);
+}
+
+/*
+ * Configure hardware registers in preparation for SWFI.
+ */
+static void msm_pm_config_hw_before_swfi(void)
+{
+#ifdef CONFIG_ARCH_MSM_SCORPION
+ writel(0x1f, APPS_CLK_SLEEP_EN);
+#else
+ writel(0x0f, APPS_CLK_SLEEP_EN);
+#endif
+}
+
+/*
+ * Respond to timing out waiting for Modem
+ *
+ * NOTE: The function never returns.
+ */
+static void msm_pm_timeout(void)
+{
+#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
+ printk(KERN_EMERG "%s(): resetting chip\n", __func__);
+ msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
+#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
+ printk(KERN_EMERG "%s(): resetting modem\n", __func__);
+ msm_proc_comm_reset_modem_now();
+#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
+ printk(KERN_EMERG "%s(): halting\n", __func__);
+#endif
+ for (;;)
+ ;
+}
+
+
+/******************************************************************************
+ * State Polling Definitions
+ *****************************************************************************/
+
+struct msm_pm_polled_group {
+ uint32_t group_id;
+
+ uint32_t bits_all_set;
+ uint32_t bits_all_clear;
+ uint32_t bits_any_set;
+ uint32_t bits_any_clear;
+
+ uint32_t value_read;
+};
+
+/*
+ * Return true if all bits indicated by flag are set in source.
+ */
+static inline bool msm_pm_all_set(uint32_t source, uint32_t flag)
+{
+ return (source & flag) == flag;
+}
+
+/*
+ * Return true if any bit indicated by flag are set in source.
+ */
+static inline bool msm_pm_any_set(uint32_t source, uint32_t flag)
+{
+ return !flag || (source & flag);
+}
+
+/*
+ * Return true if all bits indicated by flag are cleared in source.
+ */
+static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag)
+{
+ return (~source & flag) == flag;
+}
+
+/*
+ * Return true if any bit indicated by flag are cleared in source.
+ */
+static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag)
+{
+ return !flag || (~source & flag);
+}
+
+/*
+ * Poll the shared memory states as indicated by the poll groups.
+ *
+ * nr_grps: number of groups in the array
+ * grps: array of groups
+ *
+ * The function returns when conditions specified by any of the poll
+ * groups become true. The conditions specified by a poll group are
+ * deemed true when 1) at least one bit from bits_any_set is set OR one
+ * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set
+ * are set; and 3) all bits in bits_all_clear are cleared.
+ *
+ * Return value:
+ * >=0: index of the poll group whose conditions have become true
+ * -ETIMEDOUT: timed out
+ */
+static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps)
+{
+ int i, k;
+
+ for (i = 0; i < 500000; i++)
+ for (k = 0; k < nr_grps; k++) {
+ bool all_set, all_clear;
+ bool any_set, any_clear;
+
+ grps[k].value_read = smsm_get_state(grps[k].group_id);
+
+ all_set = msm_pm_all_set(grps[k].value_read,
+ grps[k].bits_all_set);
+ all_clear = msm_pm_all_clear(grps[k].value_read,
+ grps[k].bits_all_clear);
+ any_set = msm_pm_any_set(grps[k].value_read,
+ grps[k].bits_any_set);
+ any_clear = msm_pm_any_clear(grps[k].value_read,
+ grps[k].bits_any_clear);
+
+ if (all_set && all_clear && (any_set || any_clear))
+ return k;
+ }
+
+ printk(KERN_ERR "%s failed:\n", __func__);
+ for (k = 0; k < nr_grps; k++)
+ printk(KERN_ERR "(%x, %x, %x, %x) %x\n",
+ grps[k].bits_all_set, grps[k].bits_all_clear,
+ grps[k].bits_any_set, grps[k].bits_any_clear,
+ grps[k].value_read);
+
+ return -ETIMEDOUT;
+}
+
+
+/******************************************************************************
+ * Suspend Max Sleep Time
+ *****************************************************************************/
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#endif
+
+static uint32_t msm_pm_max_sleep_time;
+
+/*
+ * Convert time from nanoseconds to slow clock ticks, then cap it to the
+ * specified limit
+ */
+static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
+{
+ do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
+ return (time_ns > limit) ? limit : time_ns;
+}
+
+/*
+ * Set the sleep time for suspend. 0 means infinite sleep time.
+ */
+void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (max_sleep_time_ns == 0) {
+ msm_pm_max_sleep_time = 0;
+ } else {
+ msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+ max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
+
+ if (msm_pm_max_sleep_time == 0)
+ msm_pm_max_sleep_time = 1;
+ }
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+ "%s(): Requested %lld ns Giving %u sclk ticks\n", __func__,
+ max_sleep_time_ns, msm_pm_max_sleep_time);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+
+
+/******************************************************************************
+ * CONFIG_MSM_IDLE_STATS
+ *****************************************************************************/
+
+#ifdef CONFIG_MSM_IDLE_STATS
+enum msm_pm_time_stats_id {
+ MSM_PM_STAT_REQUESTED_IDLE,
+ MSM_PM_STAT_IDLE_SPIN,
+ MSM_PM_STAT_IDLE_WFI,
+ MSM_PM_STAT_IDLE_SLEEP,
+ MSM_PM_STAT_IDLE_FAILED_SLEEP,
+ MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+ MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+ MSM_PM_STAT_SUSPEND,
+ MSM_PM_STAT_FAILED_SUSPEND,
+ MSM_PM_STAT_NOT_IDLE,
+ MSM_PM_STAT_COUNT
+};
+
+static struct msm_pm_time_stats {
+ const char *name;
+ int64_t first_bucket_time;
+ int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
+ int count;
+ int64_t total_time;
+} msm_pm_stats[MSM_PM_STAT_COUNT] = {
+ [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
+ [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
+ [MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
+ [MSM_PM_STAT_IDLE_WFI].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
+ [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
+ [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
+ [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
+ "idle-failed-power-collapse",
+ [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_SUSPEND].name = "suspend",
+ [MSM_PM_STAT_SUSPEND].first_bucket_time =
+ CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
+ [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+
+ [MSM_PM_STAT_NOT_IDLE].name = "not-idle",
+ [MSM_PM_STAT_NOT_IDLE].first_bucket_time =
+ CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
+};
+
+static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
+static DECLARE_BITMAP(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS);
+
+/*
+ * Add the given time data to the statistics collection.
+ */
+static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
+{
+ int i;
+ int64_t bt;
+
+ msm_pm_stats[id].total_time += t;
+ msm_pm_stats[id].count++;
+
+ bt = t;
+ do_div(bt, msm_pm_stats[id].first_bucket_time);
+
+ if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
+ (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
+ i = DIV_ROUND_UP(fls((uint32_t)bt),
+ CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
+ else
+ i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
+
+ msm_pm_stats[id].bucket[i]++;
+
+ if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
+ msm_pm_stats[id].min_time[i] = t;
+ if (t > msm_pm_stats[id].max_time[i])
+ msm_pm_stats[id].max_time[i] = t;
+}
+
+/*
+ * Helper function of snprintf where buf is auto-incremented, size is auto-
+ * decremented, and there is no return value.
+ *
+ * NOTE: buf and size must be l-values (e.g. variables)
+ */
+#define SNPRINTF(buf, size, format, ...) \
+ do { \
+ if (size > 0) { \
+ int ret; \
+ ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+ if (ret > size) { \
+ buf += size; \
+ size = 0; \
+ } else { \
+ buf += ret; \
+ size -= ret; \
+ } \
+ } \
+ } while (0)
+
+/*
+ * Write out the power management statistics.
+ */
+static int msm_pm_read_proc
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int i;
+ char *p = page;
+ char clk_name[16];
+
+ if (count < 1024) {
+ *start = (char *) 0;
+ *eof = 0;
+ return 0;
+ }
+
+ if (!off) {
+ SNPRINTF(p, count, "Clocks against last TCXO shutdown:\n");
+ for_each_bit(i, msm_pm_clocks_no_tcxo_shutdown, NR_CLKS) {
+ clk_name[0] = '\0';
+ msm_clock_get_name(i, clk_name, sizeof(clk_name));
+ SNPRINTF(p, count, " %s (id=%d)\n", clk_name, i);
+ }
+
+ SNPRINTF(p, count, "Last power collapse voted ");
+ if (msm_pm_sleep_limit == SLEEP_LIMIT_NONE)
+ SNPRINTF(p, count, "for TCXO shutdown\n\n");
+ else
+ SNPRINTF(p, count, "against TCXO shutdown\n\n");
+
+ *start = (char *) 1;
+ *eof = 0;
+ } else if (--off < ARRAY_SIZE(msm_pm_stats)) {
+ int64_t bucket_time;
+ int64_t s;
+ uint32_t ns;
+
+ s = msm_pm_stats[off].total_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ "%s:\n"
+ " count: %7d\n"
+ " total_time: %lld.%09u\n",
+ msm_pm_stats[off].name,
+ msm_pm_stats[off].count,
+ s, ns);
+
+ bucket_time = msm_pm_stats[off].first_bucket_time;
+ for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
+ s = bucket_time;
+ ns = do_div(s, NSEC_PER_SEC);
+ SNPRINTF(p, count,
+ " <%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, msm_pm_stats[off].bucket[i],
+ msm_pm_stats[off].min_time[i],
+ msm_pm_stats[off].max_time[i]);
+
+ bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
+ }
+
+ SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
+ s, ns, msm_pm_stats[off].bucket[i],
+ msm_pm_stats[off].min_time[i],
+ msm_pm_stats[off].max_time[i]);
+
+ *start = (char *) 1;
+ *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
+ }
+
+ return p - page;
+}
+#undef SNPRINTF
+
+#define MSM_PM_STATS_RESET "reset"
+
+/*
+ * Reset the power management statistics values.
+ */
+static int msm_pm_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char buf[sizeof(MSM_PM_STATS_RESET)];
+ int ret;
+ unsigned long flags;
+ int i;
+
+ if (count < strlen(MSM_PM_STATS_RESET)) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
+ ret = -EFAULT;
+ goto write_proc_failed;
+ }
+
+ if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
+ ret = -EINVAL;
+ goto write_proc_failed;
+ }
+
+ local_irq_save(flags);
+ for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
+ memset(msm_pm_stats[i].bucket,
+ 0, sizeof(msm_pm_stats[i].bucket));
+ memset(msm_pm_stats[i].min_time,
+ 0, sizeof(msm_pm_stats[i].min_time));
+ memset(msm_pm_stats[i].max_time,
+ 0, sizeof(msm_pm_stats[i].max_time));
+ msm_pm_stats[i].count = 0;
+ msm_pm_stats[i].total_time = 0;
+ }
+
+ msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
+ bitmap_zero(msm_pm_clocks_no_tcxo_shutdown, NR_CLKS);
+ local_irq_restore(flags);
+
+ return count;
+
+write_proc_failed:
+ return ret;
+}
+#undef MSM_PM_STATS_RESET
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+
+/******************************************************************************
+ * Shared Memory Bits
+ *****************************************************************************/
+
+#define DEM_MASTER_BITS_PER_CPU 6
+
+/* Power Master State Bits - Per CPU */
+#define DEM_MASTER_SMSM_RUN \
+ (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_RSA \
+ (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
+ (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_SLEEP_EXIT \
+ (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_READY \
+ (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+#define DEM_MASTER_SMSM_SLEEP \
+ (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+
+/* Power Slave State Bits */
+#define DEM_SLAVE_SMSM_RUN (0x0001)
+#define DEM_SLAVE_SMSM_PWRC (0x0002)
+#define DEM_SLAVE_SMSM_PWRC_DELAY (0x0004)
+#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT (0x0008)
+#define DEM_SLAVE_SMSM_WFPI (0x0010)
+#define DEM_SLAVE_SMSM_SLEEP (0x0020)
+#define DEM_SLAVE_SMSM_SLEEP_EXIT (0x0040)
+#define DEM_SLAVE_SMSM_MSGS_REDUCED (0x0080)
+#define DEM_SLAVE_SMSM_RESET (0x0100)
+#define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200)
+
+
+/******************************************************************************
+ * Shared Memory Data
+ *****************************************************************************/
+
+#define DEM_MAX_PORT_NAME_LEN (20)
+
+struct msm_pm_smem_t {
+ uint32_t sleep_time;
+ uint32_t irq_mask;
+ uint32_t resources_used;
+ uint32_t reserved1;
+
+ uint32_t wakeup_reason;
+ uint32_t pending_irqs;
+ uint32_t rpc_prog;
+ uint32_t rpc_proc;
+ char smd_port_name[DEM_MAX_PORT_NAME_LEN];
+ uint32_t reserved2;
+};
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+static struct msm_pm_smem_t *msm_pm_smem_data;
+static uint32_t *msm_pm_reset_vector;
+static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
+
+/*
+ * Power collapse the Apps processor. This function executes the handshake
+ * protocol with Modem.
+ *
+ * Return value:
+ * -EAGAIN: modem reset occurred or early exit from power collapse
+ * -EBUSY: modem not ready for our power collapse -- no power loss
+ * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss
+ * 0: success
+ */
+static int msm_pm_power_collapse
+ (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit)
+{
+ struct msm_pm_polled_group state_grps[2];
+ unsigned long saved_acpuclk_rate;
+ uint32_t saved_vector[2];
+ int collapsed = 0;
+ int ret;
+#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE
+ unsigned id;
+#endif
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
+ (int)from_idle, sleep_delay, sleep_limit);
+
+ if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO, "%s(): master not ready\n", __func__);
+ ret = -EBUSY;
+ goto power_collapse_bail;
+ }
+
+ memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
+
+ msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
+ msm_gpio_enter_sleep(from_idle);
+
+ msm_pm_smem_data->sleep_time = sleep_delay;
+ msm_pm_smem_data->resources_used = sleep_limit;
+
+ /* Enter PWRC/PWRC_SUSPEND */
+
+ if (from_idle)
+ smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
+ DEM_SLAVE_SMSM_PWRC);
+ else
+ smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
+ DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND);
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC");
+ MSM_PM_DEBUG_PRINT_SLEEP_INFO();
+
+ memset(state_grps, 0, sizeof(state_grps));
+ state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+ state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA;
+ state_grps[1].group_id = SMSM_MODEM_STATE;
+ state_grps[1].bits_all_set = SMSM_RESET;
+
+ ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+ if (ret < 0) {
+ printk(KERN_EMERG "%s(): power collapse entry "
+ "timed out waiting for Modem's response\n", __func__);
+ msm_pm_timeout();
+ }
+
+ if (ret == 1) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_pm_poll_state detected Modem reset\n",
+ __func__);
+ goto power_collapse_early_exit;
+ }
+
+ /* DEM Master in RSA */
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
+
+ ret = msm_irq_enter_sleep2(true, from_idle);
+ if (ret < 0) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__,
+ ret);
+ goto power_collapse_early_exit;
+ }
+
+#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE
+ /* XXX: Temp workaround that needs to be removed soon. The
+ * right fix will probably involve the DMA driver taking
+ * ownership of the ADM clock. */
+ /* id is set to denote ADM clock. */
+ id = 1;
+ msm_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
+#endif
+
+ msm_pm_config_hw_before_power_down();
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down");
+
+ saved_acpuclk_rate = acpuclk_power_collapse();
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+ "%s(): change clock rate (old rate = %lu)\n", __func__,
+ saved_acpuclk_rate);
+
+ if (saved_acpuclk_rate == 0) {
+ msm_pm_config_hw_after_power_up();
+ goto power_collapse_early_exit;
+ }
+
+ saved_vector[0] = msm_pm_reset_vector[0];
+ saved_vector[1] = msm_pm_reset_vector[1];
+ msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+ msm_pm_reset_vector[1] = virt_to_phys(msm_pm_collapse_exit);
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_RESET_VECTOR, KERN_INFO,
+ "%s(): vector %x %x -> %x %x\n", __func__,
+ saved_vector[0], saved_vector[1],
+ msm_pm_reset_vector[0], msm_pm_reset_vector[1]);
+
+#ifdef CONFIG_VFP
+ if (from_idle)
+ vfp_flush_context();
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+ l2x0_suspend();
+#endif
+
+ collapsed = msm_pm_collapse();
+
+#ifdef CONFIG_CACHE_L2X0
+ l2x0_resume(collapsed);
+#endif
+
+ msm_pm_reset_vector[0] = saved_vector[0];
+ msm_pm_reset_vector[1] = saved_vector[1];
+
+ if (collapsed) {
+#ifdef CONFIG_VFP
+ if (from_idle)
+ vfp_reinit();
+#endif
+ cpu_init();
+ local_fiq_enable();
+ }
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+ "%s(): restore clock rate to %lu\n", __func__,
+ saved_acpuclk_rate);
+ if (acpuclk_set_rate(saved_acpuclk_rate, SETRATE_PC) < 0)
+ printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
+ __func__, saved_acpuclk_rate);
+
+#ifdef CONFIG_MSM_ADM_OFF_AT_POWER_COLLAPSE
+ /* id is set to denote ADM clock. */
+ id = 1;
+ if (msm_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL) < 0 || id < 0)
+ printk(KERN_ERR
+ "%s(): failed to turn on ADM clock\n", __func__);
+#endif
+
+ msm_irq_exit_sleep1(msm_pm_smem_data->irq_mask,
+ msm_pm_smem_data->wakeup_reason,
+ msm_pm_smem_data->pending_irqs);
+
+ msm_pm_config_hw_after_power_up();
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up");
+
+ memset(state_grps, 0, sizeof(state_grps));
+ state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+ state_grps[0].bits_any_set =
+ DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+ state_grps[1].group_id = SMSM_MODEM_STATE;
+ state_grps[1].bits_all_set = SMSM_RESET;
+
+ ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+ if (ret < 0) {
+ printk(KERN_EMERG "%s(): power collapse exit "
+ "timed out waiting for Modem's response\n", __func__);
+ msm_pm_timeout();
+ }
+
+ if (ret == 1) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_pm_poll_state detected Modem reset\n",
+ __func__);
+ goto power_collapse_early_exit;
+ }
+
+ /* Sanity check */
+ if (collapsed) {
+ BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
+ } else {
+ BUG_ON(!(state_grps[0].value_read &
+ DEM_MASTER_SMSM_PWRC_EARLY_EXIT));
+ goto power_collapse_early_exit;
+ }
+
+ /* Enter WFPI */
+
+ smsm_change_state(SMSM_APPS_DEM,
+ DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
+ DEM_SLAVE_SMSM_WFPI);
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI");
+
+ memset(state_grps, 0, sizeof(state_grps));
+ state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+ state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN;
+ state_grps[1].group_id = SMSM_MODEM_STATE;
+ state_grps[1].bits_all_set = SMSM_RESET;
+
+ ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+
+ if (ret < 0) {
+ printk(KERN_EMERG "%s(): power collapse WFPI "
+ "timed out waiting for Modem's response\n", __func__);
+ msm_pm_timeout();
+ }
+
+ if (ret == 1) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_pm_poll_state detected Modem reset\n",
+ __func__);
+ ret = -EAGAIN;
+ goto power_collapse_restore_gpio_bail;
+ }
+
+ /* DEM Master == RUN */
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
+ MSM_PM_DEBUG_PRINT_SLEEP_INFO();
+
+ msm_irq_exit_sleep2(msm_pm_smem_data->irq_mask,
+ msm_pm_smem_data->wakeup_reason,
+ msm_pm_smem_data->pending_irqs);
+ msm_irq_exit_sleep3(msm_pm_smem_data->irq_mask,
+ msm_pm_smem_data->wakeup_reason,
+ msm_pm_smem_data->pending_irqs);
+ msm_gpio_exit_sleep();
+
+ smsm_change_state(SMSM_APPS_DEM,
+ DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN);
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
+
+ smd_sleep_exit();
+ return 0;
+
+power_collapse_early_exit:
+ /* Enter PWRC_EARLY_EXIT */
+
+ smsm_change_state(SMSM_APPS_DEM,
+ DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
+ DEM_SLAVE_SMSM_PWRC_EARLY_EXIT);
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT");
+
+ memset(state_grps, 0, sizeof(state_grps));
+ state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
+ state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
+ state_grps[1].group_id = SMSM_MODEM_STATE;
+ state_grps[1].bits_all_set = SMSM_RESET;
+
+ ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE");
+
+ if (ret < 0) {
+ printk(KERN_EMERG "%s(): power collapse EARLY_EXIT "
+ "timed out waiting for Modem's response\n", __func__);
+ msm_pm_timeout();
+ }
+
+ if (ret == 1) {
+ MSM_PM_DPRINTK(
+ MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
+ KERN_INFO,
+ "%s(): msm_pm_poll_state detected Modem reset\n",
+ __func__);
+ }
+
+ /* DEM Master == RESET or PWRC_EARLY_EXIT */
+
+ ret = -EAGAIN;
+
+power_collapse_restore_gpio_bail:
+ msm_gpio_exit_sleep();
+
+ /* Enter RUN */
+ smsm_change_state(SMSM_APPS_DEM,
+ DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND |
+ DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN);
+
+ MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
+
+ if (collapsed)
+ smd_sleep_exit();
+
+power_collapse_bail:
+ return ret;
+}
+
+/*
+ * Apps-sleep the Apps processor. This function execute the handshake
+ * protocol with Modem.
+ *
+ * Return value:
+ * -ENOSYS: function not implemented yet
+ */
+static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
+{
+ return -ENOSYS;
+}
+
+/*
+ * Bring the Apps processor to SWFI.
+ *
+ * Return value:
+ * -EIO: could not ramp Apps processor clock
+ * 0: success
+ */
+static int msm_pm_swfi(bool ramp_acpu)
+{
+ unsigned long saved_acpuclk_rate = 0;
+
+ if (ramp_acpu) {
+ saved_acpuclk_rate = acpuclk_wait_for_irq();
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+ "%s(): change clock rate (old rate = %lu)\n", __func__,
+ saved_acpuclk_rate);
+
+ if (!saved_acpuclk_rate)
+ return -EIO;
+ }
+
+ msm_pm_config_hw_before_swfi();
+ msm_arch_idle();
+
+ if (ramp_acpu) {
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
+ "%s(): restore clock rate to %lu\n", __func__,
+ saved_acpuclk_rate);
+ if (acpuclk_set_rate(saved_acpuclk_rate, SETRATE_SWFI) < 0)
+ printk(KERN_ERR
+ "%s(): failed to restore clock rate(%lu)\n",
+ __func__, saved_acpuclk_rate);
+ }
+
+ return 0;
+}
+
+
+/******************************************************************************
+ * External Idle/Suspend Functions
+ *****************************************************************************/
+
+/*
+ * Put CPU in low power mode.
+ */
+void arch_idle(void)
+{
+ bool allow[MSM_PM_SLEEP_MODE_NR];
+ uint32_t sleep_limit = SLEEP_LIMIT_NONE;
+
+ int latency_qos;
+ int64_t timer_expiration;
+
+ int low_power;
+ int ret;
+ int i;
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ DECLARE_BITMAP(clk_ids, NR_CLKS);
+ int64_t t1;
+ static int64_t t2;
+ int exit_stat;
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+ if (!atomic_read(&msm_pm_init_done))
+ return;
+
+ latency_qos = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY);
+ timer_expiration = msm_timer_enter_idle();
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ t1 = ktime_to_ns(ktime_get());
+ msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
+ msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+ for (i = 0; i < ARRAY_SIZE(allow); i++)
+ allow[i] = true;
+
+ switch (msm_pm_idle_sleep_mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
+ false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
+ allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ break;
+ default:
+ printk(KERN_ERR "idle sleep mode is invalid: %d\n",
+ msm_pm_idle_sleep_mode);
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif /* CONFIG_MSM_IDLE_STATS */
+ low_power = 0;
+ goto arch_idle_exit;
+ }
+
+ if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
+ !msm_irq_idle_sleep_allowed()) {
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
+ allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(allow); i++) {
+ struct msm_pm_platform_data *mode = &msm_pm_modes[i];
+ if (!mode->supported || !mode->idle_enabled ||
+ mode->latency >= latency_qos ||
+ mode->residency * 1000ULL >= timer_expiration)
+ allow[i] = false;
+ }
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ ret = msm_clock_require_tcxo(clk_ids, NR_CLKS);
+#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT)
+ ret = msm_clock_require_tcxo(NULL, 0);
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT
+ if (ret)
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+#endif
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
+ "%s(): latency qos %d, next timer %lld, sleep limit %u\n",
+ __func__, latency_qos, timer_expiration, sleep_limit);
+
+ for (i = 0; i < ARRAY_SIZE(allow); i++)
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
+ "%s(): allow %s: %d\n", __func__,
+ msm_pm_sleep_mode_labels[i], (int)allow[i]);
+
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+ uint32_t sleep_delay;
+
+ sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+ timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ if (sleep_delay == 0) /* 0 would mean infinite time */
+ sleep_delay = 1;
+
+ if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+
+ ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
+ low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ if (ret)
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+ else {
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_sleep_limit = sleep_limit;
+ bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids,
+ NR_CLKS);
+ }
+#endif /* CONFIG_MSM_IDLE_STATS */
+ } else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
+ uint32_t sleep_delay;
+
+ sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+ timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ if (sleep_delay == 0) /* 0 would mean infinite time */
+ sleep_delay = 1;
+
+ ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
+ low_power = 0;
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ if (ret)
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
+ else
+ exit_stat = MSM_PM_STAT_IDLE_SLEEP;
+#endif /* CONFIG_MSM_IDLE_STATS */
+ } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
+ ret = msm_pm_swfi(true);
+ if (ret)
+ while (!msm_irq_pending())
+ udelay(1);
+ low_power = 0;
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
+#endif /* CONFIG_MSM_IDLE_STATS */
+ } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+ msm_pm_swfi(false);
+ low_power = 0;
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_WFI;
+#endif /* CONFIG_MSM_IDLE_STATS */
+ } else {
+ while (!msm_irq_pending())
+ udelay(1);
+ low_power = 0;
+#ifdef CONFIG_MSM_IDLE_STATS
+ exit_stat = MSM_PM_STAT_IDLE_SPIN;
+#endif /* CONFIG_MSM_IDLE_STATS */
+ }
+
+arch_idle_exit:
+ msm_timer_exit_idle(low_power);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ t2 = ktime_to_ns(ktime_get());
+ msm_pm_add_stat(exit_stat, t2 - t1);
+#endif /* CONFIG_MSM_IDLE_STATS */
+}
+
+/*
+ * Suspend the Apps processor.
+ *
+ * Return value:
+ * -EAGAIN: modem reset occurred or early exit from suspend
+ * -EBUSY: modem not ready for our suspend
+ * -EINVAL: invalid sleep mode
+ * -EIO: could not ramp Apps processor clock
+ * -ETIMEDOUT: timed out waiting for modem's handshake
+ * 0: success
+ */
+static int msm_pm_enter(suspend_state_t state)
+{
+ bool allow[MSM_PM_SLEEP_MODE_NR];
+ uint32_t sleep_limit = SLEEP_LIMIT_NONE;
+ int ret;
+ int i;
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ DECLARE_BITMAP(clk_ids, NR_CLKS);
+ int64_t period = 0;
+ int64_t time = 0;
+
+ time = msm_timer_get_sclk_time(&period);
+ ret = msm_clock_require_tcxo(clk_ids, NR_CLKS);
+#elif defined(CONFIG_CLOCK_BASED_SLEEP_LIMIT)
+ ret = msm_clock_require_tcxo(NULL, 0);
+#endif /* CONFIG_MSM_IDLE_STATS */
+
+#ifdef CONFIG_CLOCK_BASED_SLEEP_LIMIT
+ if (ret)
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+#endif
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+ "%s(): sleep limit %u\n", __func__, sleep_limit);
+
+ for (i = 0; i < ARRAY_SIZE(allow); i++)
+ allow[i] = true;
+
+ switch (msm_pm_sleep_mode) {
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
+ false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
+ allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_APPS_SLEEP:
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
+ /* fall through */
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ break;
+ default:
+ printk(KERN_ERR "suspend sleep mode is invalid: %d\n",
+ msm_pm_sleep_mode);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(allow); i++) {
+ struct msm_pm_platform_data *mode = &msm_pm_modes[i];
+ if (!mode->supported || !mode->suspend_enabled)
+ allow[i] = false;
+ }
+
+ ret = 0;
+
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
+ allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
+#ifdef CONFIG_MSM_IDLE_STATS
+ enum msm_pm_time_stats_id id;
+ int64_t end_time;
+#endif
+
+#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
+ if (msm_pm_sleep_time_override > 0) {
+ int64_t ns;
+ ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
+ msm_pm_set_max_sleep_time(ns);
+ msm_pm_sleep_time_override = 0;
+ }
+#endif
+ if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+ sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
+
+ ret = msm_pm_power_collapse(
+ false, msm_pm_max_sleep_time, sleep_limit);
+
+#ifdef CONFIG_MSM_IDLE_STATS
+ if (ret)
+ id = MSM_PM_STAT_FAILED_SUSPEND;
+ else {
+ id = MSM_PM_STAT_SUSPEND;
+ msm_pm_sleep_limit = sleep_limit;
+ bitmap_copy(msm_pm_clocks_no_tcxo_shutdown, clk_ids,
+ NR_CLKS);
+ }
+
+ if (time != 0) {
+ end_time = msm_timer_get_sclk_time(NULL);
+ if (end_time != 0) {
+ time = end_time - time;
+ if (time < 0)
+ time += period;
+ } else
+ time = 0;
+ }
+
+ msm_pm_add_stat(id, time);
+#endif
+ } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
+ ret = msm_pm_swfi(true);
+ if (ret)
+ while (!msm_irq_pending())
+ udelay(1);
+ } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+ msm_pm_swfi(false);
+ }
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
+ "%s(): return %d\n", __func__, ret);
+
+ return ret;
+}
+
+static struct platform_suspend_ops msm_pm_ops = {
+ .enter = msm_pm_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+
+/******************************************************************************
+ * Restart Definitions
+ *****************************************************************************/
+
+static uint32_t restart_reason = 0x776655AA;
+
+static void msm_pm_power_off(void)
+{
+ msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
+ for (;;)
+ ;
+}
+
+static void msm_pm_restart(char str, const char *cmd )
+{
+ msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
+
+ for (;;)
+ ;
+}
+
+static int msm_reboot_call
+ (struct notifier_block *this, unsigned long code, void *_cmd)
+{
+ if ((code == SYS_RESTART) && _cmd) {
+ char *cmd = _cmd;
+ if (!strcmp(cmd, "bootloader")) {
+ restart_reason = 0x77665500;
+ } else if (!strcmp(cmd, "recovery")) {
+ restart_reason = 0x77665502;
+ } else if (!strcmp(cmd, "eraseflash")) {
+ restart_reason = 0x776655EF;
+ } else if (!strncmp(cmd, "oem-", 4)) {
+ unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
+ restart_reason = 0x6f656d00 | code;
+ } else {
+ restart_reason = 0x77665501;
+ }
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_reboot_notifier = {
+ .notifier_call = msm_reboot_call,
+};
+
+
+/******************************************************************************
+ *
+ *****************************************************************************/
+
+/*
+ * Initialize the power management subsystem.
+ *
+ * Return value:
+ * -ENODEV: initialization failed
+ * 0: success
+ */
+static int __init msm_pm_init(void)
+{
+#ifdef CONFIG_MSM_IDLE_STATS
+ struct proc_dir_entry *d_entry;
+#endif
+ int ret;
+
+ pm_power_off = msm_pm_power_off;
+ arm_pm_restart = msm_pm_restart;
+ register_reboot_notifier(&msm_reboot_notifier);
+
+ msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA,
+ sizeof(*msm_pm_smem_data));
+ if (msm_pm_smem_data == NULL) {
+ printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_ARCH_MSM_SCORPION
+ /* The bootloader is responsible for initializing many of Scorpion's
+ * coprocessor registers for things like cache timing. The state of
+ * these coprocessor registers is lost on reset, so part of the
+ * bootloader must be re-executed. Do not overwrite the reset vector
+ * or bootloader area.
+ */
+ msm_pm_reset_vector = (uint32_t *) PAGE_OFFSET;
+#else
+ msm_pm_reset_vector = ioremap(0, PAGE_SIZE);
+ if (msm_pm_reset_vector == NULL) {
+ printk(KERN_ERR "%s: failed to map reset vector\n", __func__);
+ return -ENODEV;
+ }
+#endif /* CONFIG_ARCH_MSM_SCORPION */
+
+ ret = msm_timer_init_time_sync();
+ if (ret)
+ return ret;
+
+ ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ BUG_ON(msm_pm_modes == NULL);
+
+ atomic_set(&msm_pm_init_done, 1);
+ suspend_set_ops(&msm_pm_ops);
+
+ msm_pm_mode_sysfs_add();
+#ifdef CONFIG_MSM_IDLE_STATS
+ d_entry = create_proc_entry("msm_pm_stats",
+ S_IRUGO | S_IWUSR | S_IWGRP, NULL);
+ if (d_entry) {
+ d_entry->read_proc = msm_pm_read_proc;
+ d_entry->write_proc = msm_pm_write_proc;
+ d_entry->data = NULL;
+ }
+#endif
+
+ return 0;
+}
+
+late_initcall(msm_pm_init);
diff --git a/arch/arm/mach-msm/pmic.c b/arch/arm/mach-msm/pmic.c
new file mode 100644
index 000000000000..3c481a6bc180
--- /dev/null
+++ b/arch/arm/mach-msm/pmic.c
@@ -0,0 +1,1095 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include <mach/pmic.h>
+
+#include "smd_rpcrouter.h"
+
+#define TRACE_PMIC 0
+
+#if TRACE_PMIC
+#define PMIC(x...) printk(KERN_INFO "[PMIC] " x)
+#else
+#define PMIC(x...) do {} while (0)
+#endif
+
+
+#define LIB_NULL_PROC 0
+#define LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC 1
+#define LP_MODE_CONTROL_PROC 2
+#define VREG_SET_LEVEL_PROC 3
+#define VREG_PULL_DOWN_SWITCH_PROC 4
+#define SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC 5
+#define SECURE_MPP_CONFIG_I_SINK_PROC 6
+#define RTC_START_PROC 7
+#define RTC_STOP_PROC 8
+#define RTC_GET_TIME_PROC 9
+#define RTC_ENABLE_ALARM_PROC 10
+#define RTC_DISABLE_ALARM_PROC 11
+#define RTC_GET_ALARM_TIME_PROC 12
+#define RTC_GET_ALARM_STATUS_PROC 13
+#define RTC_SET_TIME_ADJUST_PROC 14
+#define RTC_GET_TIME_ADJUST_PROC 15
+#define SET_LED_INTENSITY_PROC 16
+#define FLASH_LED_SET_CURRENT_PROC 17
+#define FLASH_LED_SET_MODE_PROC 18
+#define FLASH_LED_SET_POLARITY_PROC 19
+#define SPEAKER_CMD_PROC 20
+#define SET_SPEAKER_GAIN_PROC 21
+#define VIB_MOT_SET_VOLT_PROC 22
+#define VIB_MOT_SET_MODE_PROC 23
+#define VIB_MOT_SET_POLARITY_PROC 24
+#define VID_EN_PROC 25
+#define VID_IS_EN_PROC 26
+#define VID_LOAD_DETECT_EN_PROC 27
+#define MIC_EN_PROC 28
+#define MIC_IS_EN_PROC 29
+#define MIC_SET_VOLT_PROC 30
+#define MIC_GET_VOLT_PROC 31
+#define SPKR_EN_RIGHT_CHAN_PROC 32
+#define SPKR_IS_RIGHT_CHAN_EN_PROC 33
+#define SPKR_EN_LEFT_CHAN_PROC 34
+#define SPKR_IS_LEFT_CHAN_EN_PROC 35
+#define SET_SPKR_CONFIGURATION_PROC 36
+#define GET_SPKR_CONFIGURATION_PROC 37
+#define SPKR_GET_GAIN_PROC 38
+#define SPKR_IS_EN_PROC 39
+#define SPKR_EN_MUTE_PROC 40
+#define SPKR_IS_MUTE_EN_PROC 41
+#define SPKR_SET_DELAY_PROC 42
+#define SPKR_GET_DELAY_PROC 43
+#define SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC 44
+#define SET_SPEAKER_DELAY_PROC 45
+#define SPEAKER_1K6_ZIN_ENABLE_PROC 46
+#define SPKR_SET_MUX_HPF_CORNER_FREQ_PROC 47
+#define SPKR_GET_MUX_HPF_CORNER_FREQ_PROC 48
+#define SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC 49
+#define SPKR_EN_STEREO_PROC 50
+#define SPKR_IS_STEREO_EN_PROC 51
+#define SPKR_SELECT_USB_WITH_HPF_20HZ_PROC 52
+#define SPKR_IS_USB_WITH_HPF_20HZ_PROC 53
+#define SPKR_BYPASS_MUX_PROC 54
+#define SPKR_IS_MUX_BYPASSED_PROC 55
+#define SPKR_EN_HPF_PROC 56
+#define SPKR_IS_HPF_EN_PROC 57
+#define SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC 58
+#define SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC 59
+#define SPKR_ADD_RIGHT_LEFT_CHAN_PROC 60
+#define SPKR_SET_GAIN_PROC 61
+#define SPKR_EN_PROC 62
+#define HSED_SET_PERIOD_PROC 63
+#define HSED_SET_HYSTERESIS_PROC 64
+#define HSED_SET_CURRENT_THRESHOLD_PROC 65
+#define HSED_ENABLE_PROC 66
+
+
+/* rpc related */
+#define PMIC_RPC_TIMEOUT (5*HZ)
+
+#define PMIC_PDEV_NAME "rs00010001:00000000"
+#define PMIC_RPC_PROG 0x30000061
+#define PMIC_RPC_VER_1_1 0x00010001
+#define PMIC_RPC_VER_2_1 0x00020001
+
+/* error bit flags defined by modem side */
+#define PM_ERR_FLAG__PAR1_OUT_OF_RANGE (0x0001)
+#define PM_ERR_FLAG__PAR2_OUT_OF_RANGE (0x0002)
+#define PM_ERR_FLAG__PAR3_OUT_OF_RANGE (0x0004)
+#define PM_ERR_FLAG__PAR4_OUT_OF_RANGE (0x0008)
+#define PM_ERR_FLAG__PAR5_OUT_OF_RANGE (0x0010)
+
+#define PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE (0x001F) /* all 5 previous */
+
+#define PM_ERR_FLAG__SBI_OPT_ERR (0x0080)
+#define PM_ERR_FLAG__FEATURE_NOT_SUPPORTED (0x0100)
+
+#define PMIC_BUFF_SIZE 256
+
+struct pmic_buf {
+ char *start; /* buffer start addr */
+ char *end; /* buffer end addr */
+ int size; /* buffer size */
+ char *data; /* payload begin addr */
+ int len; /* payload len */
+};
+
+static DEFINE_MUTEX(pmic_mtx);
+
+struct pmic_ctrl {
+ int inited;
+ struct pmic_buf tbuf;
+ struct pmic_buf rbuf;
+ struct msm_rpc_endpoint *endpoint;
+};
+
+static struct pmic_ctrl pmic_ctrl = {
+ .inited = -1,
+};
+
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf,
+ struct pmic_buf *rbuf, int proc);
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2,
+ uint data3, int num, int proc);
+static int pmic_rpc_set_struct(int, uint, uint *data, uint size, int proc);
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc);
+static int pmic_rpc_get_only(uint *getdata, int size, int proc);
+
+static int pmic_buf_init(void)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+
+ memset(&pmic_ctrl, 0, sizeof(pmic_ctrl));
+
+ pm->tbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+ if (pm->tbuf.start == NULL) {
+ printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pm->tbuf.data = pm->tbuf.start;
+ pm->tbuf.size = PMIC_BUFF_SIZE;
+ pm->tbuf.end = pm->tbuf.start + PMIC_BUFF_SIZE;
+ pm->tbuf.len = 0;
+
+ pm->rbuf.start = kmalloc(PMIC_BUFF_SIZE, GFP_KERNEL);
+ if (pm->rbuf.start == NULL) {
+ kfree(pm->tbuf.start);
+ printk(KERN_ERR "%s:%u\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ pm->rbuf.data = pm->rbuf.start;
+ pm->rbuf.size = PMIC_BUFF_SIZE;
+ pm->rbuf.end = pm->rbuf.start + PMIC_BUFF_SIZE;
+ pm->rbuf.len = 0;
+
+ pm->inited = 1;
+
+ return 0;
+}
+
+static inline void pmic_buf_reserve(struct pmic_buf *bp, int len)
+{
+ bp->data += len;
+}
+
+static inline void pmic_buf_reset(struct pmic_buf *bp)
+{
+ bp->data = bp->start;
+ bp->len = 0;
+}
+
+static int modem_to_linux_err(uint err)
+{
+ if (err == 0)
+ return 0;
+
+ if (err & PM_ERR_FLAG__ALL_PARMS_OUT_OF_RANGE)
+ return -EINVAL; /* PM_ERR_FLAG__PAR[1..5]_OUT_OF_RANGE */
+
+ if (err & PM_ERR_FLAG__SBI_OPT_ERR)
+ return -EIO;
+
+ if (err & PM_ERR_FLAG__FEATURE_NOT_SUPPORTED)
+ return -ENOSYS;
+
+ return -EPERM;
+}
+
+static int pmic_put_tx_data(struct pmic_buf *tp, uint datav)
+{
+ uint *lp;
+
+ if ((tp->size - tp->len) < sizeof(datav)) {
+ printk(KERN_ERR "%s: OVERFLOW size=%d len=%d\n",
+ __func__, tp->size, tp->len);
+ return -1;
+ }
+
+ lp = (uint *)tp->data;
+ *lp = cpu_to_be32(datav);
+ tp->data += sizeof(datav);
+ tp->len += sizeof(datav);
+
+ return sizeof(datav);
+}
+
+static int pmic_pull_rx_data(struct pmic_buf *rp, uint *datap)
+{
+ uint *lp;
+
+ if (rp->len < sizeof(*datap)) {
+ printk(KERN_ERR "%s: UNDERRUN len=%d\n", __func__, rp->len);
+ return -1;
+ }
+ lp = (uint *)rp->data;
+ *datap = be32_to_cpu(*lp);
+ rp->data += sizeof(*datap);
+ rp->len -= sizeof(*datap);
+
+ return sizeof(*datap);
+}
+
+
+/*
+ *
+ * +-------------------+
+ * | PROC cmd layer |
+ * +-------------------+
+ * | RPC layer |
+ * +-------------------+
+ *
+ * 1) network byte order
+ * 2) RPC request header(40 bytes) and RPC reply header (24 bytes)
+ * 3) each transaction consists of a request and reply
+ * 3) PROC (comamnd) layer has its own sub-protocol defined
+ * 4) sub-protocol can be grouped to follwoing 7 cases:
+ * a) set one argument, no get
+ * b) set two argument, no get
+ * c) set three argument, no get
+ * d) set a struct, no get
+ * e) set a argument followed by a struct, no get
+ * f) set a argument, get a argument
+ * g) no set, get either a argument or a struct
+ */
+
+/**
+ * pmic_rpc_req_reply() - send request and wait for reply
+ * @tbuf: buffer contains arguments
+ * @rbuf: buffer to be filled with arguments at reply
+ * @proc: command/request id
+ *
+ * This function send request to modem and wait until reply received
+ */
+static int pmic_rpc_req_reply(struct pmic_buf *tbuf, struct pmic_buf *rbuf,
+ int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ int ans, len;
+
+
+ if ((pm->endpoint == NULL) || IS_ERR(pm->endpoint)) {
+ pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG,
+ PMIC_RPC_VER_2_1, 0);
+ if (IS_ERR(pm->endpoint)) {
+ pm->endpoint = msm_rpc_connect_compatible(PMIC_RPC_PROG,
+ PMIC_RPC_VER_1_1, 0);
+ }
+
+ if (IS_ERR(pm->endpoint)) {
+ ans = PTR_ERR(pm->endpoint);
+ printk(KERN_ERR "%s: init rpc failed! ans = %d\n",
+ __func__, ans);
+ return ans;
+ }
+ }
+
+ /*
+ * data is point to next available space at this moment,
+ * move it back to beginning of request header and increase
+ * the length
+ */
+ tbuf->data = tbuf->start;
+ tbuf->len += sizeof(struct rpc_request_hdr);
+
+ len = msm_rpc_call_reply(pm->endpoint, proc,
+ tbuf->data, tbuf->len,
+ rbuf->data, rbuf->size,
+ PMIC_RPC_TIMEOUT);
+
+ if (len <= 0) {
+ printk(KERN_ERR "%s: rpc failed! len = %d\n", __func__, len);
+ pm->endpoint = NULL; /* re-connect later ? */
+ return len;
+ }
+
+ rbuf->len = len;
+ /* strip off rpc_reply_hdr */
+ rbuf->data += sizeof(struct rpc_reply_hdr);
+ rbuf->len -= sizeof(struct rpc_reply_hdr);
+
+ return rbuf->len;
+}
+
+/**
+ * pmic_rpc_set_only() - set arguments and no get
+ * @data0: first argumrnt
+ * @data1: second argument
+ * @data2: third argument
+ * @data3: fourth argument
+ * @num: number of argument
+ * @proc: command/request id
+ *
+ * This function covers case a, b, and c
+ */
+static int pmic_rpc_set_only(uint data0, uint data1, uint data2, uint data3,
+ int num, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ int stat;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ if (num > 0)
+ pmic_put_tx_data(tp, data0);
+
+ if (num > 1)
+ pmic_put_tx_data(tp, data1);
+
+ if (num > 2)
+ pmic_put_tx_data(tp, data2);
+
+ if (num > 3)
+ pmic_put_tx_data(tp, data3);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_struct() - set the whole struct
+ * @xflag: indicates an extra argument
+ * @xdata: the extra argument
+ * @*data: starting address of struct
+ * @size: size of struct
+ * @proc: command/request id
+ *
+ * This fucntion covers case d and e
+ */
+static int pmic_rpc_set_struct(int xflag, uint xdata, uint *data, uint size,
+ int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ if (xflag)
+ pmic_put_tx_data(tp, xdata);
+
+ more_data = 1; /* tell server there have more data followed */
+ pmic_put_tx_data(tp, more_data);
+
+ size >>= 2;
+ for (i = 0; i < size; i++) {
+ pmic_put_tx_data(tp, *data);
+ data++;
+ }
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_set_get() - set one argument and get one argument
+ * @setdata: set argument
+ * @*getdata: memory to store argumnet
+ * @size: size of memory
+ * @proc: command/request id
+ *
+ * This function covers case f
+ */
+static int pmic_rpc_set_get(uint setdata, uint *getdata, int size, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ unsigned int *lp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ pmic_put_tx_data(tp, setdata);
+
+ /*
+ * more_data = TRUE to ask server reply with requested datum
+ * otherwise, server will reply without datum
+ */
+ more_data = (getdata != NULL);
+ pmic_put_tx_data(tp, more_data);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+ pmic_pull_rx_data(rp, &more_data);
+
+ if (more_data) { /* more data followed */
+ size >>= 2;
+ lp = getdata;
+ for (i = 0; i < size; i++) {
+ if (pmic_pull_rx_data(rp, lp++) < 0)
+ break; /* not supposed to happen */
+ }
+ }
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+/**
+ * pmic_rpc_get_only() - get one or more than one arguments
+ * @*getdata: memory to store arguments
+ * @size: size of mmory
+ * @proc: command/request id
+ *
+ * This function covers case g
+ */
+static int pmic_rpc_get_only(uint *getdata, int size, int proc)
+{
+ struct pmic_ctrl *pm = &pmic_ctrl;
+ struct pmic_buf *tp;
+ struct pmic_buf *rp;
+ unsigned int *lp;
+ int i, stat, more_data;
+
+
+ if (mutex_lock_interruptible(&pmic_mtx))
+ return -ERESTARTSYS;
+
+ if (pm->inited <= 0) {
+ stat = pmic_buf_init();
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+ }
+
+ tp = &pm->tbuf;
+ rp = &pm->rbuf;
+
+ pmic_buf_reset(tp);
+ pmic_buf_reserve(tp, sizeof(struct rpc_request_hdr));
+ pmic_buf_reset(rp);
+
+ /*
+ * more_data = TRUE to ask server reply with requested datum
+ * otherwise, server will reply without datum
+ */
+ more_data = (getdata != NULL);
+ pmic_put_tx_data(tp, more_data);
+
+ stat = pmic_rpc_req_reply(tp, rp, proc);
+ if (stat < 0) {
+ mutex_unlock(&pmic_mtx);
+ return stat;
+ }
+
+ pmic_pull_rx_data(rp, &stat); /* result from server */
+ pmic_pull_rx_data(rp, &more_data);
+
+ if (more_data) { /* more data followed */
+ size >>= 2;
+ lp = getdata;
+ for (i = 0; i < size; i++) {
+ if (pmic_pull_rx_data(rp, lp++) < 0)
+ break; /* not supposed to happen */
+ }
+ }
+
+ mutex_unlock(&pmic_mtx);
+
+ return modem_to_linux_err(stat);
+}
+
+
+int pmic_lp_mode_control(enum switch_cmd cmd, enum vreg_lp_id id)
+{
+ return pmic_rpc_set_only(cmd, id, 0, 0, 2, LP_MODE_CONTROL_PROC);
+}
+EXPORT_SYMBOL(pmic_lp_mode_control);
+
+int pmic_vreg_set_level(enum vreg_id vreg, int level)
+{
+ return pmic_rpc_set_only(vreg, level, 0, 0, 2, VREG_SET_LEVEL_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_set_level);
+
+int pmic_vreg_pull_down_switch(enum switch_cmd cmd, enum vreg_pdown_id id)
+{
+ return pmic_rpc_set_only(cmd, id, 0, 0, 2, VREG_PULL_DOWN_SWITCH_PROC);
+}
+EXPORT_SYMBOL(pmic_vreg_pull_down_switch);
+
+int pmic_secure_mpp_control_digital_output(enum mpp_which which,
+ enum mpp_dlogic_level level,
+ enum mpp_dlogic_out_ctrl out)
+{
+ return pmic_rpc_set_only(which, level, out, 0, 3,
+ SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_control_digital_output);
+
+int pmic_secure_mpp_config_i_sink(enum mpp_which which,
+ enum mpp_i_sink_level level,
+ enum mpp_i_sink_switch onoff)
+{
+ return pmic_rpc_set_only(which, level, onoff, 0, 3,
+ SECURE_MPP_CONFIG_I_SINK_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_i_sink);
+
+int pmic_secure_mpp_config_digital_input(enum mpp_which which,
+ enum mpp_dlogic_level level,
+ enum mpp_dlogic_in_dbus dbus)
+{
+ return pmic_rpc_set_only(which, level, dbus, 0, 3,
+ SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC);
+}
+EXPORT_SYMBOL(pmic_secure_mpp_config_digital_input);
+
+int pmic_rtc_start(struct rtc_time *time)
+{
+ return pmic_rpc_set_struct(0, 0, (uint *)time, sizeof(*time),
+ RTC_START_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_start);
+
+int pmic_rtc_stop(void)
+{
+ return pmic_rpc_set_only(0, 0, 0, 0, 0, RTC_STOP_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_stop);
+
+int pmic_rtc_get_time(struct rtc_time *time)
+{
+ return pmic_rpc_get_only((uint *)time, sizeof(*time),
+ RTC_GET_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time);
+
+int pmic_rtc_enable_alarm(enum rtc_alarm alarm,
+ struct rtc_time *time)
+{
+ return pmic_rpc_set_struct(1, alarm, (uint *)time, sizeof(*time),
+ RTC_ENABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_enable_alarm);
+
+int pmic_rtc_disable_alarm(enum rtc_alarm alarm)
+{
+ return pmic_rpc_set_only(alarm, 0, 0, 0, 1, RTC_DISABLE_ALARM_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_disable_alarm);
+
+int pmic_rtc_get_alarm_time(enum rtc_alarm alarm,
+ struct rtc_time *time)
+{
+ return pmic_rpc_set_get(alarm, (uint *)time, sizeof(*time),
+ RTC_GET_ALARM_TIME_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_time);
+
+int pmic_rtc_get_alarm_status(uint *status)
+{
+ return pmic_rpc_get_only(status, sizeof(*status),
+ RTC_GET_ALARM_STATUS_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_alarm_status);
+
+int pmic_rtc_set_time_adjust(uint adjust)
+{
+ return pmic_rpc_set_only(adjust, 0, 0, 0, 1,
+ RTC_SET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_set_time_adjust);
+
+int pmic_rtc_get_time_adjust(uint *adjust)
+{
+ return pmic_rpc_get_only(adjust, sizeof(*adjust),
+ RTC_GET_TIME_ADJUST_PROC);
+}
+EXPORT_SYMBOL(pmic_rtc_get_time_adjust);
+
+/*
+ * generic speaker
+ */
+int pmic_speaker_cmd(const enum spkr_cmd cmd)
+{
+ return pmic_rpc_set_only(cmd, 0, 0, 0, 1, SPEAKER_CMD_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_cmd);
+
+int pmic_set_spkr_configuration(struct spkr_config_mode *cfg)
+{
+ return pmic_rpc_set_struct(0, 0, (uint *)cfg, sizeof(*cfg),
+ SET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_set_spkr_configuration);
+
+int pmic_get_spkr_configuration(struct spkr_config_mode *cfg)
+{
+ return pmic_rpc_get_only((uint *)cfg, sizeof(*cfg),
+ GET_SPKR_CONFIGURATION_PROC);
+}
+EXPORT_SYMBOL(pmic_get_spkr_configuration);
+
+int pmic_spkr_en_right_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_RIGHT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_right_chan);
+
+int pmic_spkr_is_right_chan_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_RIGHT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_chan_en);
+
+int pmic_spkr_en_left_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_left_chan);
+
+int pmic_spkr_is_left_chan_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_LEFT_CHAN_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_left_chan_en);
+
+int pmic_set_speaker_gain(enum spkr_gain gain)
+{
+ return pmic_rpc_set_only(gain, 0, 0, 0, 1, SET_SPEAKER_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_gain);
+
+int pmic_set_speaker_delay(enum spkr_dly delay)
+{
+ return pmic_rpc_set_only(delay, 0, 0, 0, 1, SET_SPEAKER_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_speaker_delay);
+
+int pmic_speaker_1k6_zin_enable(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPEAKER_1K6_ZIN_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_speaker_1k6_zin_enable);
+
+int pmic_spkr_set_mux_hpf_corner_freq(enum spkr_hpf_corner_freq freq)
+{
+ return pmic_rpc_set_only(freq, 0, 0, 0, 1,
+ SPKR_SET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_mux_hpf_corner_freq);
+
+int pmic_spkr_get_mux_hpf_corner_freq(enum spkr_hpf_corner_freq *freq)
+{
+ return pmic_rpc_get_only(freq, sizeof(*freq),
+ SPKR_GET_MUX_HPF_CORNER_FREQ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_mux_hpf_corner_freq);
+
+int pmic_spkr_select_usb_with_hpf_20hz(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_SELECT_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_select_usb_with_hpf_20hz);
+
+int pmic_spkr_is_usb_with_hpf_20hz(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_USB_WITH_HPF_20HZ_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_usb_with_hpf_20hz);
+
+int pmic_spkr_bypass_mux(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_BYPASS_MUX_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_bypass_mux);
+
+int pmic_spkr_is_mux_bypassed(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_MUX_BYPASSED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mux_bypassed);
+
+int pmic_spkr_en_hpf(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_HPF_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_hpf);
+
+int pmic_spkr_is_hpf_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_HPF_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_hpf_en);
+
+int pmic_spkr_en_sink_curr_from_ref_volt_cir(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_sink_curr_from_ref_volt_cir);
+
+int pmic_spkr_is_sink_curr_from_ref_volt_cir_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_sink_curr_from_ref_volt_cir_en);
+
+/*
+ * speaker indexed by left_right
+ */
+int pmic_spkr_en(enum spkr_left_right left_right, uint enable)
+{
+ return pmic_rpc_set_only(left_right, enable, 0, 0, 2, SPKR_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en);
+
+int pmic_spkr_is_en(enum spkr_left_right left_right, uint *enabled)
+{
+ return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+ SPKR_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_en);
+
+int pmic_spkr_set_gain(enum spkr_left_right left_right, enum spkr_gain gain)
+{
+ return pmic_rpc_set_only(left_right, gain, 0, 0, 2, SPKR_SET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_gain);
+
+int pmic_spkr_get_gain(enum spkr_left_right left_right, enum spkr_gain *gain)
+{
+ return pmic_rpc_set_get(left_right, gain, sizeof(*gain),
+ SPKR_GET_GAIN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_gain);
+
+int pmic_spkr_set_delay(enum spkr_left_right left_right, enum spkr_dly delay)
+{
+ return pmic_rpc_set_only(left_right, delay, 0, 0, 2,
+ SPKR_SET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_set_delay);
+
+int pmic_spkr_get_delay(enum spkr_left_right left_right, enum spkr_dly *delay)
+{
+ return pmic_rpc_set_get(left_right, delay, sizeof(*delay),
+ SPKR_GET_DELAY_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_get_delay);
+
+int pmic_spkr_en_mute(enum spkr_left_right left_right, uint enabled)
+{
+ return pmic_rpc_set_only(left_right, enabled, 0, 0, 2,
+ SPKR_EN_MUTE_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_mute);
+
+int pmic_spkr_is_mute_en(enum spkr_left_right left_right, uint *enabled)
+{
+ return pmic_rpc_set_get(left_right, enabled, sizeof(*enabled),
+ SPKR_IS_MUTE_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_mute_en);
+
+/*
+ * mic
+ */
+int pmic_mic_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, MIC_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_en);
+
+int pmic_mic_is_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled), MIC_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_is_en);
+
+int pmic_mic_set_volt(enum mic_volt vol)
+{
+ return pmic_rpc_set_only(vol, 0, 0, 0, 1, MIC_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_set_volt);
+
+int pmic_mic_get_volt(enum mic_volt *voltage)
+{
+ return pmic_rpc_get_only(voltage, sizeof(*voltage), MIC_GET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_mic_get_volt);
+
+int pmic_vib_mot_set_volt(uint vol)
+{
+ return pmic_rpc_set_only(vol, 0, 0, 0, 1, VIB_MOT_SET_VOLT_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_volt);
+
+int pmic_vib_mot_set_mode(enum pm_vib_mot_mode mode)
+{
+ return pmic_rpc_set_only(mode, 0, 0, 0, 1, VIB_MOT_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_mode);
+
+int pmic_vib_mot_set_polarity(enum pm_vib_mot_pol pol)
+{
+ return pmic_rpc_set_only(pol, 0, 0, 0, 1, VIB_MOT_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_vib_mot_set_polarity);
+
+int pmic_vid_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_en);
+
+int pmic_vid_is_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled), VID_IS_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_is_en);
+
+int pmic_vid_load_detect_en(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, VID_LOAD_DETECT_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_vid_load_detect_en);
+
+int pmic_set_led_intensity(enum ledtype type, int level)
+{
+ return pmic_rpc_set_only(type, level, 0, 0, 2, SET_LED_INTENSITY_PROC);
+}
+EXPORT_SYMBOL(pmic_set_led_intensity);
+
+int pmic_flash_led_set_current(const uint16_t milliamps)
+{
+ return pmic_rpc_set_only(milliamps, 0, 0, 0, 1,
+ FLASH_LED_SET_CURRENT_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_current);
+
+int pmic_flash_led_set_mode(enum flash_led_mode mode)
+{
+ return pmic_rpc_set_only((int)mode, 0, 0, 0, 1,
+ FLASH_LED_SET_MODE_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_mode);
+
+int pmic_flash_led_set_polarity(enum flash_led_pol pol)
+{
+ return pmic_rpc_set_only((int)pol, 0, 0, 0, 1,
+ FLASH_LED_SET_POLARITY_PROC);
+}
+EXPORT_SYMBOL(pmic_flash_led_set_polarity);
+
+int pmic_spkr_add_right_left_chan(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1,
+ SPKR_ADD_RIGHT_LEFT_CHAN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_add_right_left_chan);
+
+int pmic_spkr_is_right_left_chan_added(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_right_left_chan_added);
+
+int pmic_spkr_en_stereo(uint enable)
+{
+ return pmic_rpc_set_only(enable, 0, 0, 0, 1, SPKR_EN_STEREO_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_en_stereo);
+
+int pmic_spkr_is_stereo_en(uint *enabled)
+{
+ return pmic_rpc_get_only(enabled, sizeof(*enabled),
+ SPKR_IS_STEREO_EN_PROC);
+}
+EXPORT_SYMBOL(pmic_spkr_is_stereo_en);
+
+int pmic_hsed_set_period(
+ enum hsed_controller controller,
+ enum hsed_period_pre_div period_pre_div,
+ enum hsed_period_time period_time
+)
+{
+ return pmic_rpc_set_only(controller, period_pre_div, period_time, 0,
+ 3,
+ HSED_SET_PERIOD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_period);
+
+int pmic_hsed_set_hysteresis(
+ enum hsed_controller controller,
+ enum hsed_hyst_pre_div hyst_pre_div,
+ enum hsed_hyst_time hyst_time
+)
+{
+ return pmic_rpc_set_only(controller, hyst_pre_div, hyst_time, 0,
+ 3,
+ HSED_SET_HYSTERESIS_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_hysteresis);
+
+int pmic_hsed_set_current_threshold(
+ enum hsed_controller controller,
+ enum hsed_switch switch_hsed,
+ uint32_t current_threshold
+)
+{
+ return pmic_rpc_set_only(controller, switch_hsed, current_threshold, 0,
+ 3,
+ HSED_SET_CURRENT_THRESHOLD_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_set_current_threshold);
+
+int pmic_hsed_enable(
+ enum hsed_controller controller,
+ enum hsed_enable enable_hsed
+)
+{
+ return pmic_rpc_set_only(controller, enable_hsed, 0, 0,
+ 2,
+ HSED_ENABLE_PROC);
+}
+EXPORT_SYMBOL(pmic_hsed_enable);
diff --git a/arch/arm/mach-msm/pmic8058-gpio.c b/arch/arm/mach-msm/pmic8058-gpio.c
new file mode 100644
index 000000000000..09a465d028d9
--- /dev/null
+++ b/arch/arm/mach-msm/pmic8058-gpio.c
@@ -0,0 +1,150 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * Qualcomm PMIC8058 GPIO driver
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/mfd/pmic8058.h>
+#include "gpio_chip.h"
+
+#define PM8058_GPIO_TO_INT(n) (PMIC8058_IRQ_BASE + (n))
+
+static int pm8058_gpio_configure(struct gpio_chip *chip,
+ unsigned int gpio,
+ unsigned long flags)
+{
+ int rc = 0, direction;
+
+ gpio -= chip->start;
+
+ if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) {
+ direction = 0;
+ if (flags & GPIOF_INPUT)
+ direction |= PM_GPIO_DIR_IN;
+ if (flags & GPIOF_DRIVE_OUTPUT)
+ direction |= PM_GPIO_DIR_OUT;
+
+ if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) {
+ if (flags & GPIOF_OUTPUT_HIGH)
+ rc = pm8058_gpio_set(gpio, 1);
+ else
+ rc = pm8058_gpio_set(gpio, 0);
+
+ if (rc) {
+ pr_err("%s: FAIL pm8058_gpio_set(): rc=%d.\n",
+ __func__, rc);
+ goto bail_out;
+ }
+ }
+
+ rc = pm8058_gpio_set_direction(gpio, direction);
+ if (rc)
+ pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
+ __func__, rc);
+ }
+
+bail_out:
+ return rc;
+}
+
+static int pm8058_gpio_get_irq_num(struct gpio_chip *chip,
+ unsigned int gpio,
+ unsigned int *irqp,
+ unsigned long *irqnumflagsp)
+{
+ gpio -= chip->start;
+ *irqp = PM8058_GPIO_TO_INT(gpio);
+ if (irqnumflagsp)
+ *irqnumflagsp = 0;
+ return 0;
+}
+
+static int pm8058_gpio_read(struct gpio_chip *chip, unsigned n)
+{
+ n -= chip->start;
+ return pm8058_gpio_get(n);
+}
+
+static int pm8058_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
+{
+ n -= chip->start;
+ return pm8058_gpio_set(n, on);
+}
+
+struct msm_gpio_chip pm8058_gpio_chip = {
+ .chip = {
+ .start = NR_GPIO_IRQS,
+ .end = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS - 1,
+ .configure = pm8058_gpio_configure,
+ .get_irq_num = pm8058_gpio_get_irq_num,
+ .read = pm8058_gpio_read,
+ .write = pm8058_gpio_write,
+ }
+};
+
+static int __init pm8058_gpio_init(void)
+{
+ int rc;
+
+ rc = register_gpio_chip(&pm8058_gpio_chip.chip);
+ pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
+
+ return rc;
+}
+device_initcall(pm8058_gpio_init);
diff --git a/arch/arm/mach-msm/pmic8058-mpp.c b/arch/arm/mach-msm/pmic8058-mpp.c
new file mode 100644
index 000000000000..5c4f396c544b
--- /dev/null
+++ b/arch/arm/mach-msm/pmic8058-mpp.c
@@ -0,0 +1,105 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * Qualcomm PMIC8058 MPP driver
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/mfd/pmic8058.h>
+#include "gpio_chip.h"
+
+#define PM8058_MPP_TO_INT(n) (PMIC8058_IRQ_BASE + NR_PMIC8058_GPIO_IRQS + (n))
+
+static int pm8058_mpp_get_irq_num(struct gpio_chip *chip,
+ unsigned int gpio,
+ unsigned int *irqp,
+ unsigned long *irqnumflagsp)
+{
+ gpio -= chip->start;
+ *irqp = PM8058_MPP_TO_INT(gpio);
+ if (irqnumflagsp)
+ *irqnumflagsp = 0;
+ return 0;
+}
+
+static int pm8058_mpp_read(struct gpio_chip *chip, unsigned n)
+{
+ n -= chip->start;
+ return pm8058_mpp_get(n);
+}
+
+struct msm_gpio_chip pm8058_mpp_chip = {
+ .chip = {
+ .start = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS,
+ .end = NR_GPIO_IRQS + NR_PMIC8058_GPIO_IRQS +
+ NR_PMIC8058_MPP_IRQS - 1,
+ .get_irq_num = pm8058_mpp_get_irq_num,
+ .read = pm8058_mpp_read,
+ }
+};
+
+static int __init pm8058_mpp_init(void)
+{
+ int rc;
+
+ rc = register_gpio_chip(&pm8058_mpp_chip.chip);
+ pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
+
+ return rc;
+}
+device_initcall(pm8058_mpp_init);
diff --git a/arch/arm/mach-msm/pmic_debugfs.c b/arch/arm/mach-msm/pmic_debugfs.c
new file mode 100644
index 000000000000..3614c3bcde0e
--- /dev/null
+++ b/arch/arm/mach-msm/pmic_debugfs.c
@@ -0,0 +1,1200 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+
+#include <mach/pmic.h>
+
+
+static int debug_lp_mode_control(char *buf, int size)
+{
+ enum switch_cmd cmd;
+ enum vreg_lp_id id;
+ int cnt;
+
+
+ cnt = sscanf(buf, "%u %u", &cmd, &id);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+ return -EINVAL;
+ }
+
+ if (pmic_lp_mode_control(cmd, id) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_vreg_set_level(char *buf, int size)
+{
+ enum vreg_id vreg;
+ int level;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %u", &vreg, &level);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vreg_set_level(vreg, level) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_vreg_pull_down_switch(char *buf, int size)
+{
+ enum switch_cmd cmd;
+ enum vreg_pdown_id id;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %u", &cmd, &id);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d", __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vreg_pull_down_switch(cmd, id) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_secure_mpp_control_digital_output(char *buf, int size)
+{
+ enum mpp_which which;
+ enum mpp_dlogic_level level;
+ enum mpp_dlogic_out_ctrl out;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %u %u", &which, &level, &out);
+ if (cnt < 3) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+
+ if (pmic_secure_mpp_control_digital_output(which, level, out) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_secure_mpp_config_i_sink(char *buf, int size)
+{
+ enum mpp_which which;
+ enum mpp_i_sink_level level;
+ enum mpp_i_sink_switch onoff;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %u %u", &which, &level, &onoff);
+ if (cnt < 3) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+
+ if (pmic_secure_mpp_config_i_sink(which, level, onoff) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_secure_mpp_config_digital_input(char *buf, int size)
+{
+ enum mpp_which which;
+ enum mpp_dlogic_level level;
+ enum mpp_dlogic_in_dbus dbus;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %u %u", &which, &level, &dbus);
+ if (cnt < 3) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_secure_mpp_config_digital_input(which, level, dbus) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_rtc_start(char *buf, int size)
+{
+ uint time;
+ struct rtc_time *hal;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &time);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ hal = (struct rtc_time *)&time;
+ if (pmic_rtc_start(hal) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_rtc_stop(char *buf, int size)
+{
+ if (pmic_rtc_stop() < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_rtc_get_time(char *buf, int size)
+{
+ uint time;
+ struct rtc_time *hal;
+
+ hal = (struct rtc_time *)&time;
+ if (pmic_rtc_get_time(hal) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", time);
+}
+
+static int debug_rtc_alarm_ndx;
+
+int debug_rtc_enable_alarm(char *buf, int size)
+{
+ enum rtc_alarm alarm;
+ struct rtc_time *hal;
+ uint time;
+ int cnt;
+
+
+ cnt = sscanf(buf, "%u %u", &alarm, &time);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ hal = (struct rtc_time *)&time;
+
+ if (pmic_rtc_enable_alarm(alarm, hal) < 0)
+ return -EFAULT;
+
+ debug_rtc_alarm_ndx = alarm;
+ return size;
+}
+
+static int debug_rtc_disable_alarm(char *buf, int size)
+{
+
+ enum rtc_alarm alarm;
+ int cnt;
+
+ cnt = sscanf(buf, "%u", &alarm);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_rtc_disable_alarm(alarm) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_rtc_get_alarm_time(char *buf, int size)
+{
+ uint time;
+ struct rtc_time *hal;
+
+ hal = (struct rtc_time *)&time;
+ if (pmic_rtc_get_alarm_time(debug_rtc_alarm_ndx, hal) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", time);
+}
+static int debug_rtc_get_alarm_status(char *buf, int size)
+{
+ int status;;
+
+ if (pmic_rtc_get_alarm_status(&status) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", status);
+
+}
+
+static int debug_rtc_set_time_adjust(char *buf, int size)
+{
+ uint adjust;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &adjust);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_rtc_set_time_adjust(adjust) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_rtc_get_time_adjust(char *buf, int size)
+{
+ int adjust;;
+
+ if (pmic_rtc_get_time_adjust(&adjust) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", adjust);
+}
+
+static int debug_set_led_intensity(char *buf, int size)
+{
+ enum ledtype type;
+ int level;
+ int cnt;
+
+ cnt = sscanf(buf, "%u %d", &type, &level);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_set_led_intensity(type, level) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_flash_led_set_current(char *buf, int size)
+{
+ int milliamps;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &milliamps);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_flash_led_set_current(milliamps) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_flash_led_set_mode(char *buf, int size)
+{
+
+ uint mode;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &mode);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_flash_led_set_mode(mode) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_flash_led_set_polarity(char *buf, int size)
+{
+ int pol;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &pol);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_flash_led_set_polarity(pol) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_speaker_cmd(char *buf, int size)
+{
+ int cmd;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &cmd);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_speaker_cmd(cmd) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_set_speaker_gain(char *buf, int size)
+{
+ int gain;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &gain);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_set_speaker_gain(gain) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_mic_en(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_mic_en(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_mic_is_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_mic_is_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_mic_set_volt(char *buf, int size)
+{
+ int vol;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &vol);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_mic_set_volt(vol) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_mic_get_volt(char *buf, int size)
+{
+ uint vol;
+
+ if (pmic_mic_get_volt(&vol) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", vol);
+}
+
+static int debug_spkr_en_right_chan(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_right_chan(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_is_right_chan_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_right_chan_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+static int debug_spkr_en_left_chan(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_left_chan(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_is_left_chan_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_left_chan_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_set_spkr_configuration(char *buf, int size)
+{
+
+ struct spkr_config_mode cfg;
+ int cnt;
+
+ cnt = sscanf(buf, "%d %d %d %d %d %d %d %d",
+ &cfg.is_right_chan_en,
+ &cfg.is_left_chan_en,
+ &cfg.is_right_left_chan_added,
+ &cfg.is_stereo_en,
+ &cfg.is_usb_with_hpf_20hz,
+ &cfg.is_mux_bypassed,
+ &cfg.is_hpf_en,
+ &cfg.is_sink_curr_from_ref_volt_cir_en);
+
+ if (cnt < 8) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+
+ if (pmic_set_spkr_configuration(&cfg) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_get_spkr_configuration(char *buf, int size)
+{
+ struct spkr_config_mode cfg;
+
+ if (pmic_get_spkr_configuration(&cfg) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d %d %d %d %d %d %d %d\n",
+ cfg.is_right_chan_en,
+ cfg.is_left_chan_en,
+ cfg.is_right_left_chan_added,
+ cfg.is_stereo_en,
+ cfg.is_usb_with_hpf_20hz,
+ cfg.is_mux_bypassed,
+ cfg.is_hpf_en,
+ cfg.is_sink_curr_from_ref_volt_cir_en);
+
+}
+
+static int debug_set_speaker_delay(char *buf, int size)
+{
+ int delay;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &delay);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_set_speaker_delay(delay) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_speaker_1k6_zin_enable(char *buf, int size)
+{
+ uint enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%u", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_speaker_1k6_zin_enable(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_set_mux_hpf_corner_freq(char *buf, int size)
+{
+ int freq;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &freq);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_set_mux_hpf_corner_freq(freq) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_get_mux_hpf_corner_freq(char *buf, int size)
+{
+ uint freq;
+
+ if (pmic_spkr_get_mux_hpf_corner_freq(&freq) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", freq);
+}
+
+static int debug_spkr_add_right_left_chan(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_add_right_left_chan(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_is_right_left_chan_added(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_right_left_chan_added(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_stereo(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_stereo(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_spkr_is_stereo_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_stereo_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_select_usb_with_hpf_20hz(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_select_usb_with_hpf_20hz(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_spkr_is_usb_with_hpf_20hz(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_usb_with_hpf_20hz(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_bypass_mux(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_bypass_mux(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_spkr_is_mux_bypassed(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_mux_bypassed(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_hpf(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_hpf(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_spkr_is_hpf_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_hpf_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_en_sink_curr_from_ref_volt_cir(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_sink_curr_from_ref_volt_cir(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_spkr_is_sink_curr_from_ref_volt_cir_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_sink_curr_from_ref_volt_cir_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_vib_mot_set_volt(char *buf, int size)
+{
+ int vol;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &vol);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vib_mot_set_volt(vol) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_vib_mot_set_mode(char *buf, int size)
+{
+ int mode;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &mode);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vib_mot_set_mode(mode) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+static int debug_vib_mot_set_polarity(char *buf, int size)
+{
+ int pol;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &pol);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vib_mot_set_polarity(pol) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_vid_en(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vid_en(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+static int debug_vid_is_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_vid_is_en(&enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_vid_load_detect_en(char *buf, int size)
+{
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_vid_load_detect_en(enable) < 0)
+ return -EFAULT;
+
+ return size;
+}
+
+/**************************************************
+ * speaker indexed by left_right
+**************************************************/
+static enum spkr_left_right debug_spkr_left_right = LEFT_SPKR;
+
+static int debug_spkr_en(char *buf, int size)
+{
+ int left_right;
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d %d", &left_right, &enable);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en(left_right, enable) >= 0) {
+ debug_spkr_left_right = left_right;
+ return size;
+ }
+ return -EFAULT;
+}
+
+static int debug_spkr_is_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_en(debug_spkr_left_right, &enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+static int debug_spkr_set_gain(char *buf, int size)
+{
+ int left_right;
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d %d", &left_right, &enable);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_set_gain(left_right, enable) >= 0) {
+ debug_spkr_left_right = left_right;
+ return size;
+ }
+ return -EFAULT;
+}
+
+static int debug_spkr_get_gain(char *buf, int size)
+{
+ uint gain;
+
+ if (pmic_spkr_get_gain(debug_spkr_left_right, &gain) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", gain);
+}
+static int debug_spkr_set_delay(char *buf, int size)
+{
+ int left_right;
+ int delay;
+ int cnt;
+
+ cnt = sscanf(buf, "%d %d", &left_right, &delay);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_set_delay(left_right, delay) >= 0) {
+ debug_spkr_left_right = left_right;
+ return size;
+ }
+ return -EFAULT;
+}
+
+static int debug_spkr_get_delay(char *buf, int size)
+{
+ uint delay;
+
+ if (pmic_spkr_get_delay(debug_spkr_left_right, &delay) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", delay);
+}
+
+static int debug_spkr_en_mute(char *buf, int size)
+{
+ int left_right;
+ int enable;
+ int cnt;
+
+ cnt = sscanf(buf, "%d %d", &left_right, &enable);
+ if (cnt < 2) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+ if (pmic_spkr_en_mute(left_right, enable) >= 0) {
+ debug_spkr_left_right = left_right;
+ return size;
+ }
+ return -EFAULT;
+}
+
+static int debug_spkr_is_mute_en(char *buf, int size)
+{
+ int enabled;
+
+ if (pmic_spkr_is_mute_en(debug_spkr_left_right, &enabled) < 0)
+ return -EFAULT;
+
+ return snprintf(buf, size, "%d\n", enabled);
+}
+
+/*******************************************************************
+ * debug function table
+*******************************************************************/
+
+struct pmic_debug_desc {
+ int (*get) (char *, int);
+ int (*set) (char *, int);
+};
+
+struct pmic_debug_desc pmic_debug[] = {
+ {NULL, NULL}, /*LIB_NULL_PROC */
+ {NULL, NULL}, /* LIB_RPC_GLUE_CODE_INFO_REMOTE_PROC */
+ {NULL, debug_lp_mode_control}, /* LP_MODE_CONTROL_PROC */
+ {NULL, debug_vreg_set_level}, /*VREG_SET_LEVEL_PROC */
+ {NULL, debug_vreg_pull_down_switch}, /*VREG_PULL_DOWN_SWITCH_PROC */
+ {NULL, debug_secure_mpp_control_digital_output},
+ /* SECURE_MPP_CONFIG_DIGITAL_OUTPUT_PROC */
+ /*SECURE_MPP_CONFIG_I_SINK_PROC */
+ {NULL, debug_secure_mpp_config_i_sink},
+ {NULL, debug_rtc_start}, /*RTC_START_PROC */
+ {NULL, debug_rtc_stop}, /* RTC_STOP_PROC */
+ {debug_rtc_get_time, NULL}, /* RTC_GET_TIME_PROC */
+ {NULL, debug_rtc_enable_alarm}, /* RTC_ENABLE_ALARM_PROC */
+ {NULL , debug_rtc_disable_alarm}, /*RTC_DISABLE_ALARM_PROC */
+ {debug_rtc_get_alarm_time, NULL}, /* RTC_GET_ALARM_TIME_PROC */
+ {debug_rtc_get_alarm_status, NULL}, /* RTC_GET_ALARM_STATUS_PROC */
+ {NULL, debug_rtc_set_time_adjust}, /* RTC_SET_TIME_ADJUST_PROC */
+ {debug_rtc_get_time_adjust, NULL}, /* RTC_GET_TIME_ADJUST_PROC */
+ {NULL, debug_set_led_intensity}, /* SET_LED_INTENSITY_PROC */
+ {NULL, debug_flash_led_set_current}, /* FLASH_LED_SET_CURRENT_PROC */
+ {NULL, debug_flash_led_set_mode}, /* FLASH_LED_SET_MODE_PROC */
+ {NULL, debug_flash_led_set_polarity}, /* FLASH_LED_SET_POLARITY_PROC */
+ {NULL, debug_speaker_cmd}, /* SPEAKER_CMD_PROC */
+ {NULL, debug_set_speaker_gain}, /* SET_SPEAKER_GAIN_PROC */
+ {NULL, debug_vib_mot_set_volt}, /* VIB_MOT_SET_VOLT_PROC */
+ {NULL, debug_vib_mot_set_mode}, /* VIB_MOT_SET_MODE_PROC */
+ {NULL, debug_vib_mot_set_polarity}, /* VIB_MOT_SET_POLARITY_PROC */
+ {NULL, debug_vid_en}, /* VID_EN_PROC */
+ {debug_vid_is_en, NULL}, /* VID_IS_EN_PROC */
+ {NULL, debug_vid_load_detect_en}, /* VID_LOAD_DETECT_EN_PROC */
+ {NULL, debug_mic_en}, /* MIC_EN_PROC */
+ {debug_mic_is_en, NULL}, /* MIC_IS_EN_PROC */
+ {NULL, debug_mic_set_volt}, /* MIC_SET_VOLT_PROC */
+ {debug_mic_get_volt, NULL}, /* MIC_GET_VOLT_PROC */
+ {NULL, debug_spkr_en_right_chan}, /* SPKR_EN_RIGHT_CHAN_PROC */
+ {debug_spkr_is_right_chan_en, NULL}, /* SPKR_IS_RIGHT_CHAN_EN_PROC */
+ {NULL, debug_spkr_en_left_chan}, /* SPKR_EN_LEFT_CHAN_PROC */
+ {debug_spkr_is_left_chan_en, NULL}, /* SPKR_IS_LEFT_CHAN_EN_PROC */
+ {NULL, debug_set_spkr_configuration}, /* SET_SPKR_CONFIGURATION_PROC */
+ {debug_get_spkr_configuration, NULL}, /* GET_SPKR_CONFIGURATION_PROC */
+ {debug_spkr_get_gain, NULL}, /* SPKR_GET_GAIN_PROC */
+ {debug_spkr_is_en, NULL}, /* SPKR_IS_EN_PROC */
+ {NULL, debug_spkr_en_mute}, /* SPKR_EN_MUTE_PROC */
+ {debug_spkr_is_mute_en, NULL}, /* SPKR_IS_MUTE_EN_PROC */
+ {NULL, debug_spkr_set_delay}, /* SPKR_SET_DELAY_PROC */
+ {debug_spkr_get_delay, NULL}, /* SPKR_GET_DELAY_PROC */
+ /* SECURE_MPP_CONFIG_DIGITAL_INPUT_PROC */
+ {NULL, debug_secure_mpp_config_digital_input},
+ {NULL, debug_set_speaker_delay}, /* SET_SPEAKER_DELAY_PROC */
+ {NULL, debug_speaker_1k6_zin_enable}, /* SPEAKER_1K6_ZIN_ENABLE_PROC */
+ /* SPKR_SET_MUX_HPF_CORNER_FREQ_PROC */
+ {NULL, debug_spkr_set_mux_hpf_corner_freq},
+ /* SPKR_GET_MUX_HPF_CORNER_FREQ_PROC */
+ {debug_spkr_get_mux_hpf_corner_freq, NULL},
+ /* SPKR_IS_RIGHT_LEFT_CHAN_ADDED_PROC */
+ {debug_spkr_is_right_left_chan_added, NULL},
+ {NULL, debug_spkr_en_stereo}, /* SPKR_EN_STEREO_PROC */
+ {debug_spkr_is_stereo_en, NULL}, /* SPKR_IS_STEREO_EN_PROC */
+ /* SPKR_SELECT_USB_WITH_HPF_20HZ_PROC */
+ {NULL, debug_spkr_select_usb_with_hpf_20hz},
+ /* SPKR_IS_USB_WITH_HPF_20HZ_PROC */
+ {debug_spkr_is_usb_with_hpf_20hz, NULL},
+ {NULL, debug_spkr_bypass_mux}, /* SPKR_BYPASS_MUX_PROC */
+ {debug_spkr_is_mux_bypassed, NULL}, /* SPKR_IS_MUX_BYPASSED_PROC */
+ {NULL, debug_spkr_en_hpf}, /* SPKR_EN_HPF_PROC */
+ { debug_spkr_is_hpf_en, NULL}, /* SPKR_IS_HPF_EN_PROC */
+ /* SPKR_EN_SINK_CURR_FROM_REF_VOLT_CIR_PROC */
+ {NULL, debug_spkr_en_sink_curr_from_ref_volt_cir},
+ /* SPKR_IS_SINK_CURR_FROM_REF_VOLT_CIR_EN_PROC */
+ {debug_spkr_is_sink_curr_from_ref_volt_cir_en, NULL},
+ /* SPKR_ADD_RIGHT_LEFT_CHAN_PROC */
+ {NULL, debug_spkr_add_right_left_chan},
+ {NULL, debug_spkr_set_gain}, /* SPKR_SET_GAIN_PROC */
+ {NULL , debug_spkr_en}, /* SPKR_EN_PROC */
+};
+
+/***********************************************************************/
+
+#define PROC_END (sizeof(pmic_debug)/sizeof(struct pmic_debug_desc))
+
+
+#define PMIC_DEBUG_BUF 512
+
+static int debug_proc; /* PROC's index */
+
+static char debug_buf[PMIC_DEBUG_BUF];
+
+static int proc_index_set(void *data, u64 val)
+{
+ int ndx;
+
+ ndx = (int)val;
+
+ if (ndx >= 0 && ndx <= PROC_END)
+ debug_proc = ndx;
+
+ return 0;
+}
+
+static int proc_index_get(void *data, u64 *val)
+{
+ *val = (u64)debug_proc;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(
+ proc_index_fops,
+ proc_index_get,
+ proc_index_set,
+ "%llu\n");
+
+
+static int pmic_debugfs_open(struct inode *inode, struct file *file)
+{
+ /* non-seekable */
+ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+ return 0;
+}
+
+static int pmic_debugfs_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t pmic_debugfs_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct pmic_debug_desc *pd;
+ int len = 0;
+
+ printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n",
+ __func__, debug_proc, count, (uint)*ppos);
+
+ if (count > sizeof(debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(debug_buf, buff, count))
+ return -EFAULT;
+
+
+ debug_buf[count] = 0; /* end of string */
+
+ pd = &pmic_debug[debug_proc];
+
+ if (pd->set) {
+ len = pd->set(debug_buf, count);
+ printk(KERN_INFO "%s: len=%d\n", __func__, len);
+ return len;
+ }
+
+ return 0;
+}
+
+static ssize_t pmic_debugfs_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct pmic_debug_desc *pd;
+ int len = 0;
+
+ printk(KERN_INFO "%s: proc=%d count=%d *ppos=%d\n",
+ __func__, debug_proc, count, (uint)*ppos);
+
+ pd = &pmic_debug[debug_proc];
+
+ if (*ppos)
+ return 0; /* the end */
+
+ if (pd->get) {
+ len = pd->get(debug_buf, sizeof(debug_buf));
+ if (len > 0) {
+ if (len > count)
+ len = count;
+ if (copy_to_user(buff, debug_buf, len))
+ return -EFAULT;
+ }
+ }
+
+ printk(KERN_INFO "%s: len=%d\n", __func__, len);
+
+ if (len < 0)
+ return 0;
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+static const struct file_operations pmic_debugfs_fops = {
+ .open = pmic_debugfs_open,
+ .release = pmic_debugfs_release,
+ .read = pmic_debugfs_read,
+ .write = pmic_debugfs_write,
+};
+
+static int __init pmic_debugfs_init(void)
+{
+ struct dentry *dent = debugfs_create_dir("pmic", NULL);
+
+ if (IS_ERR(dent)) {
+ printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
+ __FILE__, __LINE__, PTR_ERR(dent));
+ return -1;
+ }
+
+ if (debugfs_create_file("index", 0644, dent, 0, &proc_index_fops)
+ == NULL) {
+ printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (debugfs_create_file("debug", 0644, dent, 0, &pmic_debugfs_fops)
+ == NULL) {
+ printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ debug_proc = 0;
+ debug_rtc_alarm_ndx = 0;
+
+ return 0;
+}
+
+late_initcall(pmic_debugfs_init);
diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c
index 915ee704ed3c..937e59b46dfe 100644
--- a/arch/arm/mach-msm/proc_comm.c
+++ b/arch/arm/mach-msm/proc_comm.c
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/proc_comm.c
*
* Copyright (C) 2007-2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -18,16 +19,21 @@
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <linux/module.h>
#include <mach/msm_iomap.h>
#include <mach/system.h>
#include "proc_comm.h"
-#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4)
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_TRIG_A2M_INT(n) (writel(1 << n, MSM_GCC_BASE + 0x8))
+#else
+#define MSM_TRIG_A2M_INT(n) (writel(1, MSM_CSR_BASE + 0x400 + (n) * 4))
+#endif
static inline void notify_other_proc_comm(void)
{
- writel(1, MSM_A2M_INT(6));
+ MSM_TRIG_A2M_INT(6);
}
#define APP_COMMAND 0x00
@@ -43,68 +49,89 @@ static inline void notify_other_proc_comm(void)
static DEFINE_SPINLOCK(proc_comm_lock);
/* The higher level SMD support will install this to
- * provide a way to check for and handle modem restart.
+ * provide a way to check for and handle modem restart?
*/
int (*msm_check_for_modem_crash)(void);
/* Poll for a state change, checking for possible
* modem crashes along the way (so we don't wait
- * forever while the ARM9 is blowing up).
+ * forever while the ARM9 is blowing up.
*
* Return an error in the event of a modem crash and
* restart so the msm_proc_comm() routine can restart
* the operation from the beginning.
*/
-static int proc_comm_wait_for(void __iomem *addr, unsigned value)
+static int proc_comm_wait_for(unsigned addr, unsigned value)
{
- for (;;) {
+ while (1) {
if (readl(addr) == value)
return 0;
if (msm_check_for_modem_crash)
if (msm_check_for_modem_crash())
return -EAGAIN;
+
+ udelay(5);
}
}
+void msm_proc_comm_reset_modem_now(void)
+{
+ unsigned base = (unsigned)MSM_SHARED_RAM_BASE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&proc_comm_lock, flags);
+
+again:
+ if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
+ goto again;
+
+ writel(PCOM_RESET_MODEM, base + APP_COMMAND);
+ writel(0, base + APP_DATA1);
+ writel(0, base + APP_DATA2);
+
+ spin_unlock_irqrestore(&proc_comm_lock, flags);
+
+ notify_other_proc_comm();
+
+ return;
+}
+EXPORT_SYMBOL(msm_proc_comm_reset_modem_now);
+
int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
{
- void __iomem *base = MSM_SHARED_RAM_BASE;
+ unsigned base = (unsigned)MSM_SHARED_RAM_BASE;
unsigned long flags;
int ret;
spin_lock_irqsave(&proc_comm_lock, flags);
- for (;;) {
- if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
- continue;
-
- writel(cmd, base + APP_COMMAND);
- writel(data1 ? *data1 : 0, base + APP_DATA1);
- writel(data2 ? *data2 : 0, base + APP_DATA2);
-
- notify_other_proc_comm();
-
- if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE))
- continue;
-
- if (readl(base + APP_STATUS) != PCOM_CMD_FAIL) {
- if (data1)
- *data1 = readl(base + APP_DATA1);
- if (data2)
- *data2 = readl(base + APP_DATA2);
- ret = 0;
- } else {
- ret = -EIO;
- }
- break;
+again:
+ if (proc_comm_wait_for(base + MDM_STATUS, PCOM_READY))
+ goto again;
+
+ writel(cmd, base + APP_COMMAND);
+ writel(data1 ? *data1 : 0, base + APP_DATA1);
+ writel(data2 ? *data2 : 0, base + APP_DATA2);
+
+ notify_other_proc_comm();
+
+ if (proc_comm_wait_for(base + APP_COMMAND, PCOM_CMD_DONE))
+ goto again;
+
+ if (readl(base + APP_STATUS) == PCOM_CMD_SUCCESS) {
+ if (data1)
+ *data1 = readl(base + APP_DATA1);
+ if (data2)
+ *data2 = readl(base + APP_DATA2);
+ ret = 0;
+ } else {
+ ret = -EIO;
}
writel(PCOM_CMD_IDLE, base + APP_COMMAND);
spin_unlock_irqrestore(&proc_comm_lock, flags);
-
return ret;
}
-
-
+EXPORT_SYMBOL(msm_proc_comm);
diff --git a/arch/arm/mach-msm/proc_comm.h b/arch/arm/mach-msm/proc_comm.h
index 834760f25692..5e08f050d07a 100644
--- a/arch/arm/mach-msm/proc_comm.h
+++ b/arch/arm/mach-msm/proc_comm.h
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/proc_comm.h
*
- * Copyright (c) 2007 QUALCOMM Incorporated
+ * Copyright (c) 2007-2009, 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
@@ -13,8 +13,8 @@
*
*/
-#ifndef _ARCH_ARM_MACH_MSM_PROC_COMM_H_
-#define _ARCH_ARM_MACH_MSM_PROC_COMM_H_
+#ifndef _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_
+#define _ARCH_ARM_MACH_MSM_MSM_PROC_COMM_H_
enum {
PCOM_CMD_IDLE = 0x0,
@@ -62,104 +62,110 @@ enum {
PCOM_RESET_CHIP_IMM,
PCOM_PM_VID_EN,
PCOM_VREG_PULLDOWN,
- PCOM_NUM_CMDS,
+ PCOM_GET_MODEM_VERSION,
+ PCOM_CLK_REGIME_SEC_RESET,
+ PCOM_CLK_REGIME_SEC_RESET_ASSERT,
+ PCOM_CLK_REGIME_SEC_RESET_DEASSERT,
+ PCOM_CLK_REGIME_SEC_PLL_REQUEST_WRP,
+ PCOM_CLK_REGIME_SEC_ENABLE,
+ PCOM_CLK_REGIME_SEC_DISABLE,
+ PCOM_CLK_REGIME_SEC_IS_ON,
+ PCOM_CLK_REGIME_SEC_SEL_CLK_INV,
+ PCOM_CLK_REGIME_SEC_SEL_CLK_SRC,
+ PCOM_CLK_REGIME_SEC_SEL_CLK_DIV,
+ PCOM_CLK_REGIME_SEC_ICODEC_CLK_ENABLE,
+ PCOM_CLK_REGIME_SEC_ICODEC_CLK_DISABLE,
+ PCOM_CLK_REGIME_SEC_SEL_SPEED,
+ PCOM_CLK_REGIME_SEC_CONFIG_GP_CLK_WRP,
+ PCOM_CLK_REGIME_SEC_CONFIG_MDH_CLK_WRP,
+ PCOM_CLK_REGIME_SEC_USB_XTAL_ON,
+ PCOM_CLK_REGIME_SEC_USB_XTAL_OFF,
+ PCOM_CLK_REGIME_SEC_SET_QDSP_DME_MODE,
+ PCOM_CLK_REGIME_SEC_SWITCH_ADSP_CLK,
+ PCOM_CLK_REGIME_SEC_GET_MAX_ADSP_CLK_KHZ,
+ PCOM_CLK_REGIME_SEC_GET_I2C_CLK_KHZ,
+ PCOM_CLK_REGIME_SEC_MSM_GET_CLK_FREQ_KHZ,
+ PCOM_CLK_REGIME_SEC_SEL_VFE_SRC,
+ PCOM_CLK_REGIME_SEC_MSM_SEL_CAMCLK,
+ PCOM_CLK_REGIME_SEC_MSM_SEL_LCDCLK,
+ PCOM_CLK_REGIME_SEC_VFE_RAIL_OFF,
+ PCOM_CLK_REGIME_SEC_VFE_RAIL_ON,
+ PCOM_CLK_REGIME_SEC_GRP_RAIL_OFF,
+ PCOM_CLK_REGIME_SEC_GRP_RAIL_ON,
+ PCOM_CLK_REGIME_SEC_VDC_RAIL_OFF,
+ PCOM_CLK_REGIME_SEC_VDC_RAIL_ON,
+ PCOM_CLK_REGIME_SEC_LCD_CTRL,
+ PCOM_CLK_REGIME_SEC_REGISTER_FOR_CPU_RESOURCE,
+ PCOM_CLK_REGIME_SEC_DEREGISTER_FOR_CPU_RESOURCE,
+ PCOM_CLK_REGIME_SEC_RESOURCE_REQUEST_WRP,
+ PCOM_CLK_REGIME_MSM_SEC_SEL_CLK_OWNER,
+ PCOM_CLK_REGIME_SEC_DEVMAN_REQUEST_WRP,
+ PCOM_GPIO_CONFIG,
+ PCOM_GPIO_CONFIGURE_GROUP,
+ PCOM_GPIO_TLMM_SET_PORT,
+ PCOM_GPIO_TLMM_CONFIG_EX,
+ PCOM_SET_FTM_BOOT_COUNT,
+ PCOM_RESERVED0,
+ PCOM_RESERVED1,
+ PCOM_CUSTOMER_CMD1,
+ PCOM_CUSTOMER_CMD2,
+ PCOM_CUSTOMER_CMD3,
+ PCOM_CLK_REGIME_ENTER_APPSBL_CHG_MODE,
+ PCOM_CLK_REGIME_EXIT_APPSBL_CHG_MODE,
+ PCOM_CLK_REGIME_SEC_RAIL_DISABLE,
+ PCOM_CLK_REGIME_SEC_RAIL_ENABLE,
+ PCOM_CLK_REGIME_SEC_RAIL_CONTROL,
+ PCOM_SET_SW_WATCHDOG_STATE,
+ PCOM_PM_MPP_CONFIG_DIGITAL_INPUT,
+ PCOM_PM_MPP_CONFIG_I_SINK,
+ PCOM_RESERVED_101,
+ PCOM_MSM_HSUSB_PHY_RESET,
+ PCOM_GET_BATT_MV_LEVEL,
+ PCOM_CHG_USB_IS_PC_CONNECTED,
+ PCOM_CHG_USB_IS_CHARGER_CONNECTED,
+ PCOM_CHG_USB_IS_DISCONNECTED,
+ PCOM_CHG_USB_IS_AVAILABLE,
+ PCOM_CLK_REGIME_SEC_MSM_SEL_FREQ,
+ PCOM_CLK_REGIME_SEC_SET_PCLK_AXI_POLICY,
+ PCOM_CLKCTL_RPC_RESET_ASSERT,
+ PCOM_CLKCTL_RPC_RESET_DEASSERT,
+ PCOM_CLKCTL_RPC_RAIL_ON,
+ PCOM_CLKCTL_RPC_RAIL_OFF,
+ PCOM_CLKCTL_RPC_RAIL_ENABLE,
+ PCOM_CLKCTL_RPC_RAIL_DISABLE,
+ PCOM_CLKCTL_RPC_RAIL_CONTROL,
+ PCOM_CLKCTL_RPC_MIN_MSMC1,
};
enum {
- PCOM_INVALID_STATUS = 0x0,
- PCOM_READY,
- PCOM_CMD_RUNNING,
- PCOM_CMD_SUCCESS,
- PCOM_CMD_FAIL,
-};
-
-/* List of VREGs that support the Pull Down Resistor setting. */
-enum {
- PM_VREG_PDOWN_MSMA_ID,
- PM_VREG_PDOWN_MSMP_ID,
- PM_VREG_PDOWN_MSME1_ID, /* Not supported in Panoramix */
- PM_VREG_PDOWN_MSMC1_ID, /* Not supported in PM6620 */
- PM_VREG_PDOWN_MSMC2_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_GP3_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_MSME2_ID, /* Supported in PM7500 and Panoramix only */
- PM_VREG_PDOWN_GP4_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_GP1_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_TCXO_ID,
- PM_VREG_PDOWN_PA_ID,
- PM_VREG_PDOWN_RFTX_ID,
- PM_VREG_PDOWN_RFRX1_ID,
- PM_VREG_PDOWN_RFRX2_ID,
- PM_VREG_PDOWN_SYNT_ID,
- PM_VREG_PDOWN_WLAN_ID,
- PM_VREG_PDOWN_USB_ID,
- PM_VREG_PDOWN_MMC_ID,
- PM_VREG_PDOWN_RUIM_ID,
- PM_VREG_PDOWN_MSMC0_ID, /* Supported in PM6610 only */
- PM_VREG_PDOWN_GP2_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_GP5_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_GP6_ID, /* Supported in PM7500 only */
- PM_VREG_PDOWN_RF_ID,
- PM_VREG_PDOWN_RF_VCO_ID,
- PM_VREG_PDOWN_MPLL_ID,
- PM_VREG_PDOWN_S2_ID,
- PM_VREG_PDOWN_S3_ID,
- PM_VREG_PDOWN_RFUBM_ID,
+ PCOM_OEM_FIRST_CMD = 0x10000000,
+ PCOM_OEM_TEST_CMD = PCOM_OEM_FIRST_CMD,
- /* new for HAN */
- PM_VREG_PDOWN_RF1_ID,
- PM_VREG_PDOWN_RF2_ID,
- PM_VREG_PDOWN_RFA_ID,
- PM_VREG_PDOWN_CDC2_ID,
- PM_VREG_PDOWN_RFTX2_ID,
- PM_VREG_PDOWN_USIM_ID,
- PM_VREG_PDOWN_USB2P6_ID,
- PM_VREG_PDOWN_USB3P3_ID,
- PM_VREG_PDOWN_INVALID_ID,
+ /* add OEM PROC COMM commands here */
- /* backward compatible enums only */
- PM_VREG_PDOWN_CAM_ID = PM_VREG_PDOWN_GP1_ID,
- PM_VREG_PDOWN_MDDI_ID = PM_VREG_PDOWN_GP2_ID,
- PM_VREG_PDOWN_RUIM2_ID = PM_VREG_PDOWN_GP3_ID,
- PM_VREG_PDOWN_AUX_ID = PM_VREG_PDOWN_GP4_ID,
- PM_VREG_PDOWN_AUX2_ID = PM_VREG_PDOWN_GP5_ID,
- PM_VREG_PDOWN_BT_ID = PM_VREG_PDOWN_GP6_ID,
-
- PM_VREG_PDOWN_MSME_ID = PM_VREG_PDOWN_MSME1_ID,
- PM_VREG_PDOWN_MSMC_ID = PM_VREG_PDOWN_MSMC1_ID,
- PM_VREG_PDOWN_RFA1_ID = PM_VREG_PDOWN_RFRX2_ID,
- PM_VREG_PDOWN_RFA2_ID = PM_VREG_PDOWN_RFTX2_ID,
- PM_VREG_PDOWN_XO_ID = PM_VREG_PDOWN_TCXO_ID
+ PCOM_OEM_LAST = PCOM_OEM_TEST_CMD,
};
-/* gpio info for PCOM_RPC_GPIO_TLMM_CONFIG_EX */
-
-#define GPIO_ENABLE 0
-#define GPIO_DISABLE 1
-
-#define GPIO_INPUT 0
-#define GPIO_OUTPUT 1
-
-#define GPIO_NO_PULL 0
-#define GPIO_PULL_DOWN 1
-#define GPIO_KEEPER 2
-#define GPIO_PULL_UP 3
-
-#define GPIO_2MA 0
-#define GPIO_4MA 1
-#define GPIO_6MA 2
-#define GPIO_8MA 3
-#define GPIO_10MA 4
-#define GPIO_12MA 5
-#define GPIO_14MA 6
-#define GPIO_16MA 7
-
-#define PCOM_GPIO_CFG(gpio, func, dir, pull, drvstr) \
- ((((gpio) & 0x3FF) << 4) | \
- ((func) & 0xf) | \
- (((dir) & 0x1) << 14) | \
- (((pull) & 0x3) << 15) | \
- (((drvstr) & 0xF) << 17))
+enum {
+ PCOM_INVALID_STATUS = 0x0,
+ PCOM_READY,
+ PCOM_CMD_RUNNING,
+ PCOM_CMD_SUCCESS,
+ PCOM_CMD_FAIL,
+ PCOM_CMD_FAIL_FALSE_RETURNED,
+ PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_SERVER,
+ PCOM_CMD_FAIL_CMD_OUT_OF_BOUNDS_CLIENT,
+ PCOM_CMD_FAIL_CMD_UNREGISTERED,
+ PCOM_CMD_FAIL_CMD_LOCKED,
+ PCOM_CMD_FAIL_SERVER_NOT_YET_READY,
+ PCOM_CMD_FAIL_BAD_DESTINATION,
+ PCOM_CMD_FAIL_SERVER_RESET,
+ PCOM_CMD_FAIL_SMSM_NOT_INIT,
+ PCOM_CMD_FAIL_PROC_COMM_BUSY,
+ PCOM_CMD_FAIL_PROC_COMM_NOT_INIT,
+};
+void msm_proc_comm_reset_modem_now(void);
int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2);
#endif
diff --git a/arch/arm/mach-msm/proc_comm_test.c b/arch/arm/mach-msm/proc_comm_test.c
new file mode 100644
index 000000000000..e38b8d651d27
--- /dev/null
+++ b/arch/arm/mach-msm/proc_comm_test.c
@@ -0,0 +1,169 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+/*
+ * PROC COMM TEST Driver source file
+ */
+
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include "proc_comm.h"
+
+static struct dentry *dent;
+static int proc_comm_test_res;
+
+static int proc_comm_reverse_test(void)
+{
+ uint32_t data1, data2;
+ int rc;
+
+ data1 = 10;
+ data2 = 20;
+
+ rc = msm_proc_comm(PCOM_OEM_TEST_CMD, &data1, &data2);
+ if (rc)
+ return rc;
+
+ if ((data1 != 20) || (data2 != 10))
+ return -1;
+
+ return 0;
+}
+
+static ssize_t debug_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char _buf[16];
+
+ snprintf(_buf, sizeof(_buf), "%i\n", proc_comm_test_res);
+
+ return simple_read_from_buffer(buf, count, pos, _buf, strlen(_buf));
+}
+
+static ssize_t debug_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+
+ unsigned char cmd[64];
+ int len;
+
+ if (count < 1)
+ return 0;
+
+ len = count > 63 ? 63 : count;
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "reverse_test", 64))
+ proc_comm_test_res = proc_comm_reverse_test();
+ else
+ proc_comm_test_res = -EINVAL;
+
+ if (proc_comm_test_res)
+ pr_err("proc comm test fail %d\n",
+ proc_comm_test_res);
+ else
+ pr_info("proc comm test passed\n");
+
+ return count;
+}
+
+static int debug_release(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static int debug_open(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .owner = THIS_MODULE,
+ .open = debug_open,
+ .release = debug_release,
+ .read = debug_read,
+ .write = debug_write,
+};
+
+static void __exit proc_comm_test_mod_exit(void)
+{
+ debugfs_remove(dent);
+}
+
+static int __init proc_comm_test_mod_init(void)
+{
+ dent = debugfs_create_file("proc_comm", 0444, 0, NULL, &debug_ops);
+ proc_comm_test_res = -1;
+ return 0;
+}
+
+module_init(proc_comm_test_mod_init);
+module_exit(proc_comm_test_mod_exit);
+
+MODULE_DESCRIPTION("PROC COMM TEST Driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
new file mode 100644
index 000000000000..6e488865930e
--- /dev/null
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -0,0 +1,85 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+
+#include <asm/system.h>
+
+#include <mach/remote_spinlock.h>
+#include "smd_private.h"
+
+#define SMEM_SPINLOCK_COUNT 8
+#define SMEM_SPINLOCK_ARRAY_SIZE (SMEM_SPINLOCK_COUNT * sizeof(uint32_t))
+
+int _remote_spin_lock_init(remote_spin_lock_id_t id, _remote_spinlock_t *lock)
+{
+ _remote_spinlock_t spinlock_start;
+
+ if (id >= SMEM_SPINLOCK_COUNT)
+ return -EINVAL;
+
+ spinlock_start = smem_alloc(SMEM_SPINLOCK_ARRAY,
+ SMEM_SPINLOCK_ARRAY_SIZE);
+ if (spinlock_start == NULL)
+ return -ENXIO;
+
+ *lock = spinlock_start + id;
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-msm/reset_modem.c b/arch/arm/mach-msm/reset_modem.c
new file mode 100644
index 000000000000..5d5b0f9a0620
--- /dev/null
+++ b/arch/arm/mach-msm/reset_modem.c
@@ -0,0 +1,226 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * MSM architecture driver to reset the modem
+ */
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+#include "smd_private.h"
+#include "proc_comm.h"
+
+#define DEBUG
+/* #undef DEBUG */
+#ifdef DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+static ssize_t reset_modem_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return 0;
+}
+
+static ssize_t reset_modem_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ unsigned char cmd[64];
+ int len;
+ int time;
+ int zero = 0;
+ int r;
+
+ if (count < 1)
+ return 0;
+
+ len = count > 63 ? 63 : count;
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ /* lazy */
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "wait", 4)) {
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: WAIT\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ smsm_reset_modem(SMSM_MODEM_WAIT);
+ } else if (!strncmp(cmd, "continue", 8)) {
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: CONTINUE\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ smsm_reset_modem_cont();
+ } else if (!strncmp(cmd, "download", 8)) {
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: DOWNLOAD\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ smsm_reset_modem(SMSM_SYSTEM_DOWNLOAD);
+ } else if (sscanf(cmd, "deferred reset %i", &time) == 1) {
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: DEFERRED RESET %ims\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ time);
+ if (time == 0) {
+ r = 0;
+ msm_proc_comm_reset_modem_now();
+ } else {
+ r = msm_proc_comm(PCOM_RESET_MODEM, &time, &zero);
+ }
+ if (r < 0)
+ return r;
+ } else if (!strncmp(cmd, "deferred reset", 14)) {
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: DEFERRED RESET 0ms\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ r = 0;
+ msm_proc_comm_reset_modem_now();
+ if (r < 0)
+ return r;
+ } else if (!strncmp(cmd, "reset chip now", 14)) {
+ uint param1 = 0x0;
+ uint param2 = 0x0;
+
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: CHIP RESET IMMEDIATE\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+
+ r = msm_proc_comm(PCOM_RESET_CHIP_IMM, &param1, &param2);
+
+ if (r < 0)
+ return r;
+ } else if (!strncmp(cmd, "reset chip", 10)) {
+
+ uint param1 = 0x0;
+ uint param2 = 0x0;
+
+ D(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: CHIP RESET \n",
+ __FILE__,
+ __LINE__,
+ __func__);
+
+ r = msm_proc_comm(PCOM_RESET_CHIP, &param1, &param2);
+
+ if (r < 0)
+ return r;
+ } else { /* if (!strncmp(cmd, "reset", 5)) */
+ printk(KERN_ERR "INFO:%s:%i:%s: "
+ "MODEM RESTART: RESET\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ smsm_reset_modem(SMSM_RESET);
+ }
+
+ return count;
+}
+
+static int reset_modem_open(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static int reset_modem_release(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static const struct file_operations reset_modem_fops = {
+ .owner = THIS_MODULE,
+ .read = reset_modem_read,
+ .write = reset_modem_write,
+ .open = reset_modem_open,
+ .release = reset_modem_release,
+};
+
+static struct miscdevice reset_modem_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "reset_modem",
+ .fops = &reset_modem_fops,
+};
+
+static int __init reset_modem_init(void)
+{
+ return misc_register(&reset_modem_dev);
+}
+
+module_init(reset_modem_init);
+
+MODULE_DESCRIPTION("Reset Modem");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/rpc_hsusb.c b/arch/arm/mach-msm/rpc_hsusb.c
new file mode 100644
index 000000000000..22dee1c3322b
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_hsusb.c
@@ -0,0 +1,574 @@
+/* linux/arch/arm/mach-msm/rpc_hsusb.c
+ *
+ * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * 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, you can find it at http://www.fsf.org
+ */
+
+#include <linux/err.h>
+#include <mach/rpc_hsusb.h>
+#include <asm/mach-types.h>
+
+static struct msm_rpc_endpoint *usb_ep;
+static struct msm_rpc_endpoint *chg_ep;
+
+struct msm_chg_rpc_ids {
+ unsigned long prog;
+ unsigned long vers_comp;
+ unsigned chg_usb_charger_connected_proc;
+ unsigned chg_usb_charger_disconnected_proc;
+ unsigned chg_usb_i_is_available_proc;
+ unsigned chg_usb_i_is_not_available_proc;
+};
+
+struct msm_hsusb_rpc_ids {
+ unsigned long prog;
+ unsigned long vers_comp;
+ unsigned long init_phy;
+ unsigned long vbus_pwr_up;
+ unsigned long vbus_pwr_down;
+ unsigned long update_product_id;
+ unsigned long update_serial_num;
+ unsigned long update_is_serial_num_null;
+ unsigned long reset_rework_installed;
+ unsigned long enable_pmic_ulpi_data0;
+ unsigned long disable_pmic_ulpi_data0;
+};
+
+static struct msm_hsusb_rpc_ids usb_rpc_ids;
+static struct msm_chg_rpc_ids chg_rpc_ids;
+
+static int msm_hsusb_init_rpc_ids(unsigned long vers)
+{
+ if (vers == 0x00010001) {
+ usb_rpc_ids.prog = 0x30000064;
+ usb_rpc_ids.vers_comp = 0x00010001;
+ usb_rpc_ids.init_phy = 2;
+ usb_rpc_ids.vbus_pwr_up = 6;
+ usb_rpc_ids.vbus_pwr_down = 7;
+ usb_rpc_ids.update_product_id = 8;
+ usb_rpc_ids.update_serial_num = 9;
+ usb_rpc_ids.update_is_serial_num_null = 10;
+ usb_rpc_ids.reset_rework_installed = 17;
+ usb_rpc_ids.enable_pmic_ulpi_data0 = 18;
+ usb_rpc_ids.disable_pmic_ulpi_data0 = 19;
+ return 0;
+ } else if (vers == 0x00010002) {
+ usb_rpc_ids.prog = 0x30000064;
+ usb_rpc_ids.vers_comp = 0x00010002;
+ usb_rpc_ids.init_phy = 2;
+ usb_rpc_ids.vbus_pwr_up = 6;
+ usb_rpc_ids.vbus_pwr_down = 7;
+ usb_rpc_ids.update_product_id = 8;
+ usb_rpc_ids.update_serial_num = 9;
+ usb_rpc_ids.update_is_serial_num_null = 10;
+ usb_rpc_ids.reset_rework_installed = 17;
+ usb_rpc_ids.enable_pmic_ulpi_data0 = 18;
+ usb_rpc_ids.disable_pmic_ulpi_data0 = 19;
+ return 0;
+ } else {
+ printk(KERN_INFO "%s: no matches found for version\n",
+ __func__);
+ return -ENODATA;
+ }
+}
+
+static int msm_chg_init_rpc_ids(unsigned long vers)
+{
+ if (vers == 0x00010001) {
+ chg_rpc_ids.prog = 0x3000001a;
+ chg_rpc_ids.vers_comp = 0x00010001;
+ chg_rpc_ids.chg_usb_charger_connected_proc = 7;
+ chg_rpc_ids.chg_usb_charger_disconnected_proc = 8;
+ chg_rpc_ids.chg_usb_i_is_available_proc = 9;
+ chg_rpc_ids.chg_usb_i_is_not_available_proc = 10;
+ return 0;
+ } else {
+ printk(KERN_INFO "%s: no matches found for version\n",
+ __func__);
+ return -ENODATA;
+ }
+}
+EXPORT_SYMBOL(msm_chg_init_rpc_ids);
+
+/* rpc connect for hsusb */
+int msm_hsusb_rpc_connect(void)
+{
+
+ if (usb_ep && !IS_ERR(usb_ep)) {
+ printk(KERN_INFO "%s: usb_ep already connected\n", __func__);
+ return 0;
+ }
+
+ /* Initialize rpc ids */
+ if (msm_hsusb_init_rpc_ids(0x00010001)) {
+ printk(KERN_ERR "%s: rpc ids initialization failed\n"
+ , __func__);
+ return -ENODATA;
+ }
+
+ usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
+ usb_rpc_ids.vers_comp, 0);
+
+ if (IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: connect compatible failed vers = %lx\n",
+ __func__, usb_rpc_ids.vers_comp);
+
+ /* Initialize rpc ids */
+ if (msm_hsusb_init_rpc_ids(0x00010002)) {
+ printk(KERN_ERR "%s: rpc ids initialization failed\n",
+ __func__);
+ return -ENODATA;
+ }
+ usb_ep = msm_rpc_connect_compatible(usb_rpc_ids.prog,
+ usb_rpc_ids.vers_comp, 0);
+ }
+
+ if (IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: connect compatible failed vers = %lx\n",
+ __func__, usb_rpc_ids.vers_comp);
+ return -EAGAIN;
+ } else
+ printk(KERN_INFO "%s: rpc connect success vers = %lx\n",
+ __func__, usb_rpc_ids.vers_comp);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_hsusb_rpc_connect);
+
+/* rpc connect for charging */
+int msm_chg_rpc_connect(void)
+{
+
+ if (machine_is_msm7201a_surf() || machine_is_msm7x27_surf() ||
+ machine_is_qsd8x50_surf())
+ return -ENOTSUPP;
+
+ if (chg_ep && !IS_ERR(chg_ep)) {
+ printk(KERN_INFO "%s: chg_ep already connected\n", __func__);
+ return 0;
+ }
+
+ /* Initialize rpc ids */
+ if (msm_chg_init_rpc_ids(0x00010001)) {
+ printk(KERN_ERR "%s: rpc ids initialization failed\n"
+ , __func__);
+ return -ENODATA;
+ }
+
+ chg_ep = msm_rpc_connect_compatible(chg_rpc_ids.prog,
+ chg_rpc_ids.vers_comp, 0);
+
+ if (IS_ERR(chg_ep)) {
+ printk(KERN_ERR "%s: connect compatible failed vers = %lx\n",
+ __func__, chg_rpc_ids.vers_comp);
+ return -EAGAIN;
+ } else
+ printk(KERN_INFO "%s: rpc connect success vers = %lx\n",
+ __func__, chg_rpc_ids.vers_comp);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_chg_rpc_connect);
+
+/* rpc call for phy_reset */
+int msm_hsusb_phy_reset(void)
+{
+ int rc = 0;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: phy_reset rpc failed before call,"
+ "rc = %ld\n", __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.init_phy,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: phy_reset rpc failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_hsusb_phy_reset\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_phy_reset);
+
+/* rpc call for vbus powerup */
+int msm_hsusb_vbus_powerup(void)
+{
+ int rc = 0;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: vbus_powerup rpc failed before call,"
+ "rc = %ld\n", __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_up,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: vbus_powerup failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_hsusb_vbus_powerup\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_vbus_powerup);
+
+/* rpc call for vbus shutdown */
+int msm_hsusb_vbus_shutdown(void)
+{
+ int rc = 0;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: vbus_shutdown rpc failed before call,"
+ "rc = %ld\n", __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.vbus_pwr_down,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: vbus_shutdown failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_hsusb_vbus_shutdown\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_vbus_shutdown);
+
+int msm_hsusb_send_productID(uint32_t product_id)
+{
+ int rc = 0;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ uint32_t product_id;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ req.product_id = cpu_to_be32(product_id);
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_product_id,
+ &req, sizeof(req),
+ 5 * HZ);
+ if (rc < 0)
+ printk(KERN_ERR "%s: rpc call failed! error: %d\n",
+ __func__, rc);
+ else
+ printk(KERN_ERR "%s: rpc call success\n" ,
+ __func__);
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_send_productID);
+
+int msm_hsusb_send_serial_number(char *serial_number)
+{
+ int rc = 0, serial_len;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ uint32_t length;
+ char serial_num[20];
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ serial_len = strlen(serial_number)+1;
+ strncpy(req.serial_num, serial_number, 20);
+ req.length = cpu_to_be32(serial_len);
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_serial_num,
+ &req, sizeof(req),
+ 5 * HZ);
+ if (rc < 0)
+ printk(KERN_ERR "%s: rpc call failed! error: %d\n",
+ __func__, rc);
+ else
+ printk(KERN_ERR "%s: rpc call success\n" ,
+ __func__);
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_send_serial_number);
+
+int msm_hsusb_is_serial_num_null(uint32_t val)
+{
+ int rc = 0;
+ struct hsusb_phy_start_req {
+ struct rpc_request_hdr hdr;
+ uint32_t value;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: rpc connect failed: rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+ if (!usb_rpc_ids.update_is_serial_num_null) {
+ printk(KERN_ERR "%s: proc id not supported \n", __func__);
+ return -ENODATA;
+ }
+
+ req.value = cpu_to_be32(val);
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.update_is_serial_num_null,
+ &req, sizeof(req),
+ 5 * HZ);
+ if (rc < 0)
+ printk(KERN_ERR "%s: rpc call failed! error: %d\n" ,
+ __func__, rc);
+ else
+ printk(KERN_ERR "%s: rpc call success\n" ,
+ __func__);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_is_serial_num_null);
+
+int msm_chg_usb_charger_connected(uint32_t device)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ uint32_t otg_dev;
+ } req;
+
+ if (!chg_ep || IS_ERR(chg_ep))
+ return -EAGAIN;
+ req.otg_dev = cpu_to_be32(device);
+ rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_connected_proc,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: charger_connected failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_chg_usb_charger_connected\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_charger_connected);
+
+int msm_chg_usb_i_is_available(uint32_t sample)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ uint32_t i_ma;
+ } req;
+
+ if (!chg_ep || IS_ERR(chg_ep))
+ return -EAGAIN;
+ req.i_ma = cpu_to_be32(sample);
+ rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_available_proc,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: charger_i_available failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_chg_usb_i_is_available\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_i_is_available);
+
+int msm_chg_usb_i_is_not_available(void)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!chg_ep || IS_ERR(chg_ep))
+ return -EAGAIN;
+ rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_i_is_not_available_proc,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: charger_i_not_available failed! rc ="
+ "%d \n", __func__, rc);
+ } else
+ printk(KERN_INFO "msm_chg_usb_i_is_not_available\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_i_is_not_available);
+
+int msm_chg_usb_charger_disconnected(void)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!chg_ep || IS_ERR(chg_ep))
+ return -EAGAIN;
+ rc = msm_rpc_call(chg_ep, chg_rpc_ids.chg_usb_charger_disconnected_proc,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: charger_disconnected failed! rc = %d\n",
+ __func__, rc);
+ } else
+ printk(KERN_INFO "msm_chg_usb_charger_disconnected\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_chg_usb_charger_disconnected);
+
+/* rpc call to close connection */
+int msm_hsusb_rpc_close(void)
+{
+ int rc = 0;
+
+ if (IS_ERR(usb_ep)) {
+ printk(KERN_ERR "%s: rpc_close failed before call, rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_close(usb_ep);
+ usb_ep = NULL;
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: close rpc failed! rc = %d\n",
+ __func__, rc);
+ return -EAGAIN;
+ } else
+ printk(KERN_INFO "rpc close success\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_hsusb_rpc_close);
+
+/* rpc call to close charging connection */
+int msm_chg_rpc_close(void)
+{
+ int rc = 0;
+
+ if (IS_ERR(chg_ep)) {
+ printk(KERN_ERR "%s: rpc_close failed before call, rc = %ld\n",
+ __func__, PTR_ERR(chg_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_close(chg_ep);
+ chg_ep = NULL;
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: close rpc failed! rc = %d\n",
+ __func__, rc);
+ return -EAGAIN;
+ } else
+ printk(KERN_INFO "rpc close success\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_chg_rpc_close);
+
+int msm_hsusb_reset_rework_installed(void)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+ struct hsusb_rpc_rep {
+ struct rpc_reply_hdr hdr;
+ uint32_t rework;
+ } rep;
+
+ memset(&rep, 0, sizeof(rep));
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ rc = msm_rpc_call_reply(usb_ep, usb_rpc_ids.reset_rework_installed,
+ &req, sizeof(req),
+ &rep, sizeof(rep), 5 * HZ);
+
+ if (rc < 0) {
+ pr_err("%s: rpc call failed! error: (%d)"
+ "proc id: (%lx)\n",
+ __func__, rc,
+ usb_rpc_ids.reset_rework_installed);
+ return rc;
+ }
+
+ pr_info("%s: rework: (%d)\n", __func__, rep.rework);
+ return be32_to_cpu(rep.rework);
+}
+EXPORT_SYMBOL(msm_hsusb_reset_rework_installed);
+
+static int msm_hsusb_pmic_ulpidata0_config(int enable)
+{
+ int rc = 0;
+ struct hsusb_start_req {
+ struct rpc_request_hdr hdr;
+ } req;
+
+ if (!usb_ep || IS_ERR(usb_ep)) {
+ pr_err("%s: hsusb rpc connection not initialized, rc = %ld\n",
+ __func__, PTR_ERR(usb_ep));
+ return -EAGAIN;
+ }
+
+ if (enable)
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.enable_pmic_ulpi_data0,
+ &req, sizeof(req), 5 * HZ);
+ else
+ rc = msm_rpc_call(usb_ep, usb_rpc_ids.disable_pmic_ulpi_data0,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0)
+ pr_err("%s: rpc call failed! error: %d\n",
+ __func__, rc);
+ return rc;
+}
+
+int msm_hsusb_enable_pmic_ulpidata0(void)
+{
+ return msm_hsusb_pmic_ulpidata0_config(1);
+}
+EXPORT_SYMBOL(msm_hsusb_enable_pmic_ulpidata0);
+
+int msm_hsusb_disable_pmic_ulpidata0(void)
+{
+ return msm_hsusb_pmic_ulpidata0_config(0);
+}
+EXPORT_SYMBOL(msm_hsusb_disable_pmic_ulpidata0);
diff --git a/arch/arm/mach-msm/rpc_server_dog_keepalive.c b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
new file mode 100644
index 000000000000..5e0f46da379d
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_dog_keepalive.c
@@ -0,0 +1,77 @@
+/* arch/arm/mach-msm/rpc_server_dog_keepalive.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <mach/msm_rpcrouter.h>
+
+/* dog_keepalive server definitions */
+
+#define DOG_KEEPALIVE_PROG 0x30000015
+#if CONFIG_MSM_AMSS_VERSION==6210
+#define DOG_KEEPALIVE_VERS 0
+#define RPC_DOG_KEEPALIVE_BEACON 1
+#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
+#define DOG_KEEPALIVE_VERS 0x731fa727
+#define RPC_DOG_KEEPALIVE_BEACON 2
+#else
+#error "Unsupported AMSS version"
+#endif
+#define DOG_KEEPALIVE_VERS_COMP 0x00010001
+#define RPC_DOG_KEEPALIVE_NULL 0
+
+
+/* TODO: Remove server registration with _VERS when modem is upated with _COMP*/
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len)
+{
+ switch (req->procedure) {
+ case RPC_DOG_KEEPALIVE_NULL:
+ return 0;
+ case RPC_DOG_KEEPALIVE_BEACON:
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+static struct msm_rpc_server rpc_server[] = {
+ {
+ .prog = DOG_KEEPALIVE_PROG,
+ .vers = DOG_KEEPALIVE_VERS,
+ .rpc_call = handle_rpc_call,
+ },
+ {
+ .prog = DOG_KEEPALIVE_PROG,
+ .vers = DOG_KEEPALIVE_VERS_COMP,
+ .rpc_call = handle_rpc_call,
+ },
+};
+
+static int __init rpc_server_init(void)
+{
+ /* Dual server registration to support backwards compatibility vers */
+ int ret;
+ ret = msm_rpc_create_server(&rpc_server[1]);
+ if (ret < 0)
+ return ret;
+ return msm_rpc_create_server(&rpc_server[0]);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/rpc_server_handset.c b/arch/arm/mach-msm/rpc_server_handset.c
new file mode 100644
index 000000000000..f2df4aca231b
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_handset.c
@@ -0,0 +1,380 @@
+/* arch/arm/mach-msm/rpc_server_handset.c
+ *
+ * Copyright (c) 2008-2009, 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/msm_handset.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/board.h>
+
+#include "keypad-surf-ffa.h"
+
+#define HS_SERVER_PROG 0x30000062
+#define HS_SERVER_VERS 0x00010001
+
+#define HS_RPC_PROG 0x30000091
+#define HS_RPC_VERS 0x00010001
+
+#define HS_RPC_CB_PROG 0x31000091
+#define HS_RPC_CB_VERS 0x00010001
+
+#define HS_SUBSCRIBE_SRVC_PROC 0x03
+#define HS_EVENT_CB_PROC 1
+
+#define RPC_KEYPAD_NULL_PROC 0
+#define RPC_KEYPAD_PASS_KEY_CODE_PROC 2
+#define RPC_KEYPAD_SET_PWR_KEY_STATE_PROC 3
+
+#define HS_PWR_K 0x6F /* Power key */
+#define HS_END_K 0x51 /* End key or Power key */
+#define HS_STEREO_HEADSET_K 0x82
+#define HS_HEADSET_SWITCH_K 0x84
+#define HS_REL_K 0xFF /* key release */
+
+#define KEY(hs_key, input_key) ((hs_key << 24) | input_key)
+
+struct hs_key_data {
+ uint32_t ver; /* Version number to track sturcture changes */
+ uint32_t code; /* which key? */
+ uint32_t parm; /* key status. Up/down or pressed/released */
+};
+
+enum hs_subs_srvc {
+ HS_SUBS_SEND_CMD = 0, /* Subscribe to send commands to HS */
+ HS_SUBS_RCV_EVNT, /* Subscribe to receive Events from HS */
+ HS_SUBS_SRVC_MAX
+};
+
+enum hs_subs_req {
+ HS_SUBS_REGISTER, /* Subscribe */
+ HS_SUBS_CANCEL, /* Unsubscribe */
+ HS_SUB_STATUS_MAX
+};
+
+enum hs_event_class {
+ HS_EVNT_CLASS_ALL = 0, /* All HS events */
+ HS_EVNT_CLASS_LAST, /* Should always be the last class type */
+ HS_EVNT_CLASS_MAX
+};
+
+enum hs_cmd_class {
+ HS_CMD_CLASS_LCD = 0, /* Send LCD related commands */
+ HS_CMD_CLASS_KPD, /* Send KPD related commands */
+ HS_CMD_CLASS_LAST, /* Should always be the last class type */
+ HS_CMD_CLASS_MAX
+};
+
+/*
+ * Receive events or send command
+ */
+union hs_subs_class {
+ enum hs_event_class evnt;
+ enum hs_cmd_class cmd;
+};
+
+struct hs_subs {
+ uint32_t ver;
+ enum hs_subs_srvc srvc; /* commands or events */
+ enum hs_subs_req req; /* subscribe or unsubscribe */
+ uint32_t host_os;
+ enum hs_subs_req disc; /* discriminator */
+ union hs_subs_class id;
+};
+
+struct hs_event_cb_recv {
+ uint32_t cb_id;
+ uint32_t hs_key_data_ptr;
+ struct hs_key_data key;
+};
+
+static const uint32_t hs_key_map[] = {
+ KEY(HS_PWR_K, KEY_POWER),
+ KEY(HS_END_K, KEY_END),
+ KEY(HS_STEREO_HEADSET_K, SW_HEADPHONE_INSERT),
+ KEY(HS_HEADSET_SWITCH_K, KEY_MEDIA),
+ 0
+};
+
+static struct input_dev *kpdev;
+static struct input_dev *hsdev;
+static struct msm_rpc_client *rpc_client;
+
+static int hs_find_key(uint32_t hscode)
+{
+ int i, key;
+
+ key = KEY(hscode, 0);
+
+ for (i = 0; hs_key_map[i] != 0; i++) {
+ if ((hs_key_map[i] & 0xff000000) == key)
+ return hs_key_map[i] & 0x00ffffff;
+ }
+ return -1;
+}
+
+static void
+report_headset_switch(struct input_dev *dev, int key, int value)
+{
+ struct msm_handset *hs = input_get_drvdata(dev);
+
+ input_report_switch(dev, key, value);
+ input_sync(dev);
+}
+
+/*
+ * tuple format: (key_code, key_param)
+ *
+ * old-architecture:
+ * key-press = (key_code, 0)
+ * key-release = (0xff, key_code)
+ *
+ * new-architecutre:
+ * key-press = (key_code, 0)
+ * key-release = (key_code, 0xff)
+ */
+static void report_hs_key(uint32_t key_code, uint32_t key_parm)
+{
+ int key, temp_key_code;
+
+ if (key_code == HS_REL_K)
+ key = hs_find_key(key_parm);
+ else
+ key = hs_find_key(key_code);
+
+ temp_key_code = key_code;
+
+ if (key_parm == HS_REL_K)
+ key_code = key_parm;
+
+ kpdev = msm_keypad_get_input_dev();
+ hsdev = msm_get_handset_input_dev();
+
+ switch (key) {
+ case KEY_POWER:
+ case KEY_END:
+ if (!kpdev) {
+ printk(KERN_ERR "%s: No input device for reporting "
+ "pwr/end key press\n", __func__);
+ return;
+ }
+ input_report_key(kpdev, key, (key_code != HS_REL_K));
+ input_sync(kpdev);
+ break;
+ case SW_HEADPHONE_INSERT:
+ if (!hsdev) {
+ printk(KERN_ERR "%s: No input device for reporting "
+ "handset events\n", __func__);
+ return;
+ }
+ report_headset_switch(hsdev, key, (key_code != HS_REL_K));
+ break;
+ case KEY_MEDIA:
+ if (!hsdev) {
+ printk(KERN_ERR "%s: No input device for reporting "
+ "handset events\n", __func__);
+ return;
+ }
+ input_report_key(hsdev, key, (key_code != HS_REL_K));
+ input_sync(hsdev);
+ break;
+ case -1:
+ printk(KERN_ERR "%s: No mapping for remote handset event %d\n",
+ __func__, temp_key_code);
+ break;
+ default:
+ printk(KERN_ERR "%s: Unhandled handset key %d\n", __func__,
+ key);
+ }
+}
+
+static int handle_hs_rpc_call(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len)
+{
+ struct rpc_keypad_pass_key_code_args {
+ uint32_t key_code;
+ uint32_t key_parm;
+ };
+
+ switch (req->procedure) {
+ case RPC_KEYPAD_NULL_PROC:
+ return 0;
+
+ case RPC_KEYPAD_PASS_KEY_CODE_PROC: {
+ struct rpc_keypad_pass_key_code_args *args;
+
+ args = (struct rpc_keypad_pass_key_code_args *)(req + 1);
+ args->key_code = be32_to_cpu(args->key_code);
+ args->key_parm = be32_to_cpu(args->key_parm);
+
+ report_hs_key(args->key_code, args->key_parm);
+
+ return 0;
+ }
+
+ case RPC_KEYPAD_SET_PWR_KEY_STATE_PROC:
+ /* This RPC function must be available for the ARM9
+ * to function properly. This function is redundant
+ * when RPC_KEYPAD_PASS_KEY_CODE_PROC is handled. So
+ * input_report_key is not needed.
+ */
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+static struct msm_rpc_server hs_rpc_server = {
+ .prog = HS_SERVER_PROG,
+ .vers = HS_SERVER_VERS,
+ .rpc_call = handle_hs_rpc_call,
+};
+
+static int process_subs_srvc_callback(struct hs_event_cb_recv *recv)
+{
+ if (!recv)
+ return -ENODATA;
+
+ report_hs_key(be32_to_cpu(recv->key.code), be32_to_cpu(recv->key.parm));
+
+ return 0;
+}
+
+static void process_hs_rpc_request(uint32_t proc, void *data)
+{
+ if (proc == HS_EVENT_CB_PROC)
+ process_subs_srvc_callback(data);
+ else
+ pr_err("%s: unknown rpc proc %d\n", __func__, proc);
+}
+
+static int hs_rpc_register_subs_arg(struct msm_rpc_client *client,
+ void *buffer, void *data)
+{
+ struct hs_subs_rpc_req {
+ uint32_t hs_subs_ptr;
+ struct hs_subs hs_subs;
+ uint32_t hs_cb_id;
+ uint32_t hs_handle_ptr;
+ uint32_t hs_handle_data;
+ };
+
+ struct hs_subs_rpc_req *req = buffer;
+
+ req->hs_subs_ptr = cpu_to_be32(0x1);
+ req->hs_subs.ver = cpu_to_be32(0x1);
+ req->hs_subs.srvc = cpu_to_be32(HS_SUBS_RCV_EVNT);
+ req->hs_subs.req = cpu_to_be32(HS_SUBS_REGISTER);
+ req->hs_subs.host_os = cpu_to_be32(0x4); /* linux */
+ req->hs_subs.disc = cpu_to_be32(HS_SUBS_RCV_EVNT);
+ req->hs_subs.id.evnt = cpu_to_be32(HS_EVNT_CLASS_ALL);
+
+ req->hs_cb_id = cpu_to_be32(0x1);
+
+ req->hs_handle_ptr = cpu_to_be32(0x1);
+ req->hs_handle_data = cpu_to_be32(0x0);
+
+ return sizeof(*req);
+}
+
+static int hs_rpc_register_subs_res(struct msm_rpc_client *client,
+ void *buffer, void *data)
+{
+ uint32_t result;
+
+ result = be32_to_cpu(*((uint32_t *)buffer));
+ pr_debug("%s: request completed: 0x%x\n", __func__, result);
+
+ return 0;
+}
+
+static int hs_cb_func(struct msm_rpc_client *client, void *buffer, int in_size)
+{
+ int rc = -1;
+
+ struct rpc_request_hdr *hdr = buffer;
+
+ hdr->type = be32_to_cpu(hdr->type);
+ hdr->xid = be32_to_cpu(hdr->xid);
+ hdr->rpc_vers = be32_to_cpu(hdr->rpc_vers);
+ hdr->prog = be32_to_cpu(hdr->prog);
+ hdr->vers = be32_to_cpu(hdr->vers);
+ hdr->procedure = be32_to_cpu(hdr->procedure);
+
+ if (hdr->type != 0)
+ return rc;
+ if (hdr->rpc_vers != 2)
+ return rc;
+ if (hdr->prog != HS_RPC_CB_PROG)
+ return rc;
+ if (!msm_rpc_is_compatible_version(HS_RPC_CB_VERS,
+ hdr->vers))
+ return rc;
+
+ process_hs_rpc_request(hdr->procedure,
+ (void *) (hdr + 1));
+
+ msm_rpc_start_accepted_reply(client, hdr->xid,
+ RPC_ACCEPTSTAT_SUCCESS);
+ rc = msm_rpc_send_accepted_reply(client, 0);
+ if (rc) {
+ pr_err("%s: sending reply failed: %d\n", __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __init hs_rpc_cb_init(void)
+{
+ int rc = 0;
+
+ rpc_client = msm_rpc_register_client("hs",
+ HS_RPC_PROG, HS_RPC_VERS, 0, hs_cb_func);
+
+ if (IS_ERR(rpc_client)) {
+ pr_err("%s: couldn't open rpc client err %ld\n", __func__,
+ PTR_ERR(rpc_client));
+ return PTR_ERR(rpc_client);
+ }
+
+ rc = msm_rpc_client_req(rpc_client, HS_SUBSCRIBE_SRVC_PROC,
+ hs_rpc_register_subs_arg, NULL,
+ hs_rpc_register_subs_res, NULL, -1);
+ if (rc) {
+ pr_err("%s: couldn't send rpc client request\n", __func__);
+ msm_rpc_unregister_client(rpc_client);
+ }
+
+ return rc;
+}
+
+static int __init hs_rpc_init(void)
+{
+ int rc;
+
+ if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) {
+ rc = hs_rpc_cb_init();
+ if (rc)
+ pr_err("%s: failed to initialize\n", __func__);
+ }
+
+ return msm_rpc_create_server(&hs_rpc_server);
+}
+module_init(hs_rpc_init);
diff --git a/arch/arm/mach-msm/rpc_server_time_remote.c b/arch/arm/mach-msm/rpc_server_time_remote.c
new file mode 100644
index 000000000000..5e9719a085cf
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_time_remote.c
@@ -0,0 +1,90 @@
+/* arch/arm/mach-msm/rpc_server_time_remote.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <mach/msm_rpcrouter.h>
+#include "rpc_server_time_remote.h"
+
+/* time_remote_mtoa server definitions. */
+
+#define TIME_REMOTE_MTOA_PROG 0x3000005d
+#if CONFIG_MSM_AMSS_VERSION==6210
+#define TIME_REMOTE_MTOA_VERS 0
+#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
+#define TIME_REMOTE_MTOA_VERS 0x9202a8e4
+#else
+#error "Unknown AMSS version"
+#endif
+#define TIME_REMOTE_MTOA_VERS_COMP 0x00010001
+#define RPC_TIME_REMOTE_MTOA_NULL 0
+#define RPC_TIME_TOD_SET_APPS_BASES 2
+
+struct rpc_time_tod_set_apps_bases_args {
+ uint32_t tick;
+ uint64_t stamp;
+};
+
+static int handle_rpc_call(struct msm_rpc_server *server,
+ struct rpc_request_hdr *req, unsigned len)
+{
+ switch (req->procedure) {
+ case RPC_TIME_REMOTE_MTOA_NULL:
+ return 0;
+
+ case RPC_TIME_TOD_SET_APPS_BASES: {
+ struct rpc_time_tod_set_apps_bases_args *args;
+ args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1);
+ args->tick = be32_to_cpu(args->tick);
+ args->stamp = be64_to_cpu(args->stamp);
+ printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n"
+ "\ttick = %d\n"
+ "\tstamp = %lld\n",
+ args->tick, args->stamp);
+ rtc_hctosys();
+ return 0;
+ }
+ default:
+ return -ENODEV;
+ }
+}
+
+static struct msm_rpc_server rpc_server[] = {
+ {
+ .prog = TIME_REMOTE_MTOA_PROG,
+ .vers = TIME_REMOTE_MTOA_VERS,
+ .rpc_call = handle_rpc_call,
+ },
+ {
+ .prog = TIME_REMOTE_MTOA_PROG,
+ .vers = TIME_REMOTE_MTOA_VERS_COMP,
+ .rpc_call = handle_rpc_call,
+ },
+};
+
+static int __init rpc_server_init(void)
+{
+ /* Dual server registration to support backwards compatibility vers */
+ int ret;
+ ret = msm_rpc_create_server(&rpc_server[1]);
+ if (ret < 0)
+ return ret;
+ return msm_rpc_create_server(&rpc_server[0]);
+}
+
+
+module_init(rpc_server_init);
diff --git a/arch/arm/mach-msm/rpc_server_time_remote.h b/arch/arm/mach-msm/rpc_server_time_remote.h
new file mode 100644
index 000000000000..056666f50013
--- /dev/null
+++ b/arch/arm/mach-msm/rpc_server_time_remote.h
@@ -0,0 +1,21 @@
+/* arch/arm/mach-msm/rpc_server_time_remote.h
+ *
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H
+#define __ARCH_ARM_MACH_MSM_RPC_SERVER_TIME_REMOTE_H
+
+int rtc_hctosys(void);
+
+#endif
diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c
new file mode 100644
index 000000000000..5a64aa44ddbe
--- /dev/null
+++ b/arch/arm/mach-msm/sirc.c
@@ -0,0 +1,239 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+
+static void sirc_irq_mask(unsigned int irq);
+static void sirc_irq_unmask(unsigned int irq);
+static void sirc_irq_ack(unsigned int irq);
+static int sirc_irq_set_wake(unsigned int irq, unsigned int on);
+static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type);
+static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc);
+
+static unsigned int int_enable;
+static unsigned int wake_enable;
+
+static struct sirc_regs_t sirc_regs = {
+ .int_enable = SPSS_SIRC_INT_ENABLE,
+ .int_enable_clear = SPSS_SIRC_INT_ENABLE_CLEAR,
+ .int_enable_set = SPSS_SIRC_INT_ENABLE_SET,
+ .int_type = SPSS_SIRC_INT_TYPE,
+ .int_polarity = SPSS_SIRC_INT_POLARITY,
+ .int_clear = SPSS_SIRC_INT_CLEAR,
+};
+
+static struct sirc_cascade_regs sirc_reg_table[] = {
+ {
+ .int_status = SPSS_SIRC_IRQ_STATUS,
+ .cascade_irq = INT_SIRC_0,
+ }
+};
+
+static unsigned int save_type;
+static unsigned int save_polarity;
+
+/* Mask off the given interrupt. Keep the int_enable mask in sync with
+ the enable reg, so it can be restored after power collapse. */
+static void sirc_irq_mask(unsigned int irq)
+{
+ unsigned int mask;
+
+
+ mask = 1 << (irq - FIRST_SIRC_IRQ);
+ writel(mask, sirc_regs.int_enable_clear);
+ int_enable &= ~mask;
+ return;
+}
+
+/* Unmask the given interrupt. Keep the int_enable mask in sync with
+ the enable reg, so it can be restored after power collapse. */
+static void sirc_irq_unmask(unsigned int irq)
+{
+ unsigned int mask;
+
+ mask = 1 << (irq - FIRST_SIRC_IRQ);
+ writel(mask, sirc_regs.int_enable_set);
+ int_enable |= mask;
+ return;
+}
+
+static void sirc_irq_ack(unsigned int irq)
+{
+ unsigned int mask;
+
+ mask = 1 << (irq - FIRST_SIRC_IRQ);
+ writel(mask, sirc_regs.int_clear);
+ return;
+}
+
+static int sirc_irq_set_wake(unsigned int irq, unsigned int on)
+{
+ unsigned int mask;
+
+ /* Used to set the interrupt enable mask during power collapse. */
+ mask = 1 << (irq - FIRST_SIRC_IRQ);
+ if (on)
+ wake_enable |= mask;
+ else
+ wake_enable &= ~mask;
+
+ return 0;
+}
+
+static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+ unsigned int mask;
+ unsigned int val;
+
+ mask = 1 << (irq - FIRST_SIRC_IRQ);
+ val = readl(sirc_regs.int_polarity);
+
+ if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
+ val |= mask;
+ else
+ val &= ~mask;
+
+ writel(val, sirc_regs.int_polarity);
+
+ val = readl(sirc_regs.int_type);
+ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ val |= mask;
+ irq_desc[irq].handle_irq = handle_edge_irq;
+ } else {
+ val &= ~mask;
+ irq_desc[irq].handle_irq = handle_level_irq;
+ }
+
+ writel(val, sirc_regs.int_type);
+
+ return 0;
+}
+
+/* Finds the pending interrupt on the passed cascade irq and redrives it */
+static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int reg = 0;
+ unsigned int sirq;
+ unsigned int status;
+
+ while ((reg < ARRAY_SIZE(sirc_reg_table)) &&
+ (sirc_reg_table[reg].cascade_irq != irq))
+ reg++;
+
+ status = readl(sirc_reg_table[reg].int_status);
+ status &= SIRC_MASK;
+ if (status == 0)
+ return;
+
+ for (sirq = 0;
+ (sirq < NR_SIRC_IRQS) && ((status & (1U << sirq)) == 0);
+ sirq++)
+ ;
+ generic_handle_irq(sirq+FIRST_SIRC_IRQ);
+
+ desc->chip->ack(irq);
+}
+
+void msm_sirc_enter_sleep(void)
+{
+ save_type = readl(sirc_regs.int_type);
+ save_polarity = readl(sirc_regs.int_polarity);
+ writel(wake_enable, sirc_regs.int_enable);
+ return;
+}
+
+void msm_sirc_exit_sleep(void)
+{
+ writel(save_type, sirc_regs.int_type);
+ writel(save_polarity, sirc_regs.int_polarity);
+ writel(int_enable, sirc_regs.int_enable);
+ return;
+}
+
+static struct irq_chip sirc_irq_chip = {
+ .name = "sirc",
+ .ack = sirc_irq_ack,
+ .mask = sirc_irq_mask,
+ .unmask = sirc_irq_unmask,
+ .set_wake = sirc_irq_set_wake,
+ .set_type = sirc_irq_set_type,
+};
+
+void __init msm_init_sirc(void)
+{
+ int i;
+
+ int_enable = 0;
+ wake_enable = 0;
+
+ for (i = FIRST_SIRC_IRQ; i < LAST_SIRC_IRQ; i++) {
+ set_irq_chip(i, &sirc_irq_chip);
+ set_irq_handler(i, handle_edge_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sirc_reg_table); i++) {
+ set_irq_chained_handler(sirc_reg_table[i].cascade_irq,
+ sirc_irq_handler);
+ set_irq_wake(sirc_reg_table[i].cascade_irq, 1);
+ }
+ return;
+}
+
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
new file mode 100644
index 000000000000..82596828c7e0
--- /dev/null
+++ b/arch/arm/mach-msm/smd.c
@@ -0,0 +1,1960 @@
+/* arch/arm/mach-msm/smd.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2009, 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/termios.h>
+#include <linux/ctype.h>
+#include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
+#include <mach/system.h>
+#include <linux/io.h>
+
+#include "smd_private.h"
+#include "proc_comm.h"
+#include "modem_notifier.h"
+
+#define MODULE_NAME "msm_smd"
+#define SMEM_VERSION 0x000B
+#define SMD_VERSION 0x00020000
+
+enum {
+ MSM_SMD_DEBUG = 1U << 0,
+ MSM_SMSM_DEBUG = 1U << 1,
+ MSM_SMD_INFO = 1U << 2,
+ MSM_SMSM_INFO = 1U << 3,
+};
+
+enum {
+ SMEM_APPS_Q6_SMSM = 3,
+ SMEM_Q6_APPS_SMSM = 5,
+ SMSM_NUM_INTR_MUX = 8,
+};
+
+/* Internal definitions which are not exported in some targets */
+enum {
+ SMSM_Q6_I = 2,
+};
+
+enum {
+ SMSM_APPS_DEM_I = 3,
+};
+
+enum {
+ SMD_APPS_QDSP_I = 1,
+ SMD_MODEM_QDSP_I = 2
+};
+
+static int msm_smd_debug_mask;
+module_param_named(debug_mask, msm_smd_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+void *smem_find(unsigned id, unsigned size);
+void smd_diag(void);
+
+static unsigned last_heap_free = 0xffffffff;
+
+#if defined(CONFIG_MSM_SMD_DEBUG)
+#define SMD_DBG(x...) do { \
+ if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
+ printk(KERN_DEBUG x); \
+ } while (0)
+
+#define SMSM_DBG(x...) do { \
+ if (msm_smd_debug_mask & MSM_SMSM_DEBUG) \
+ printk(KERN_DEBUG x); \
+ } while (0)
+
+#define SMD_INFO(x...) do { \
+ if (msm_smd_debug_mask & MSM_SMD_INFO) \
+ printk(KERN_INFO x); \
+ } while (0)
+
+#define SMSM_INFO(x...) do { \
+ if (msm_smd_debug_mask & MSM_SMSM_INFO) \
+ printk(KERN_INFO x); \
+ } while (0)
+#else
+#define SMD_DBG(x...) do { } while (0)
+#define SMSM_DBG(x...) do { } while (0)
+#define SMD_INFO(x...) do { } while (0)
+#define SMSM_INFO(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_TRIG_A2M_INT(n) (writel(1 << n, MSM_GCC_BASE + 0x8))
+#else
+#define MSM_TRIG_A2M_INT(n) (writel(1, MSM_CSR_BASE + 0x400 + (n) * 4))
+#endif
+
+static void notify_other_smsm(uint32_t smsm_entry,
+ uint32_t old_val, uint32_t new_val)
+{
+ uint32_t *smsm_intr_mask;
+ uint32_t *smsm_intr_mux;
+
+ smsm_intr_mask = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+ SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS *
+ sizeof(uint32_t));
+
+ /* older protocol don't use smsm_intr_mask,
+ but still communicates with modem */
+ if (!smsm_intr_mask ||
+ (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_MODEM] &
+ (old_val ^ new_val)))
+ MSM_TRIG_A2M_INT(5);
+
+ if (smsm_intr_mask &&
+ (smsm_intr_mask[smsm_entry * SMSM_NUM_HOSTS + SMSM_Q6_I] &
+ (old_val ^ new_val))) {
+ smsm_intr_mux = smem_alloc(SMEM_SMD_SMSM_INTR_MUX,
+ SMSM_NUM_INTR_MUX *
+ sizeof(uint32_t));
+ if (smsm_intr_mux)
+ smsm_intr_mux[SMEM_APPS_Q6_SMSM]++;
+
+ MSM_TRIG_A2M_INT(8);
+ }
+}
+
+static inline void notify_other_smd(uint32_t ch_type)
+{
+ if (ch_type == SMD_APPS_MODEM)
+ MSM_TRIG_A2M_INT(0);
+ else if (ch_type == SMD_APPS_QDSP_I)
+ MSM_TRIG_A2M_INT(8);
+}
+
+void smd_diag(void)
+{
+ char *x;
+ int size;
+
+ x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+ if (x != 0) {
+ x[SZ_DIAG_ERR_MSG - 1] = 0;
+ SMD_INFO("smem: DIAG '%s'\n", x);
+ }
+
+ x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+ if (x != 0) {
+ x[size - 1] = 0;
+ printk(KERN_ERR "smem: CRASH LOG\n'%s'\n", x);
+ }
+}
+
+extern int (*msm_check_for_modem_crash)(void);
+
+static int check_for_modem_crash(void)
+{
+ uint32_t *smsm;
+
+ smsm = smem_find(ID_SHARED_STATE, SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ /* if the modem's not ready yet, we have to hope for the best */
+ if (!smsm)
+ return 0;
+
+ if (smsm[SMSM_MODEM_STATE] & SMSM_RESET) {
+ pr_err("proc_comm: ARM9 has crashed\n");
+ smd_diag();
+ } else {
+ return 0;
+ }
+
+ /* hard reboot if possible FIXME
+ if (msm_reset_hook)
+ msm_reset_hook(0);
+ */
+
+ for (;;)
+ ;
+}
+
+#define SMD_SS_CLOSED 0x00000000
+#define SMD_SS_OPENING 0x00000001
+#define SMD_SS_OPENED 0x00000002
+#define SMD_SS_FLUSHING 0x00000003
+#define SMD_SS_CLOSING 0x00000004
+#define SMD_SS_RESET 0x00000005
+#define SMD_SS_RESET_OPENING 0x00000006
+
+#define SMD_BUF_SIZE 8192
+#define SMD_CHANNELS 64
+
+#define SMD_HEADER_SIZE 20
+
+
+/* the spinlock is used to synchronize between the
+** irq handler and code that mutates the channel
+** list or fiddles with channel state
+*/
+static DEFINE_SPINLOCK(smd_lock);
+static DEFINE_SPINLOCK(smem_lock);
+
+/* the mutex is used during open() and close()
+** operations to avoid races while creating or
+** destroying smd_channel structures
+*/
+static DEFINE_MUTEX(smd_creation_mutex);
+
+static int smd_initialized;
+
+/* 'type' field of smd_alloc_elm structure
+ * has the following breakup
+ * bits 0-7 -> channel type
+ * bits 8-11 -> xfer type
+ * bits 12-31 -> reserved
+ */
+struct smd_alloc_elm {
+ char name[20];
+ uint32_t cid;
+ uint32_t type;
+ uint32_t ref_count;
+};
+
+#define SMD_CHANNEL_TYPE(x) ((x) & 0x000000FF)
+#define SMD_XFER_TYPE(x) (((x) & 0x00000F00) >> 8)
+
+struct smd_half_channel {
+ unsigned state;
+ unsigned char fDSR;
+ unsigned char fCTS;
+ unsigned char fCD;
+ unsigned char fRI;
+ unsigned char fHEAD;
+ unsigned char fTAIL;
+ unsigned char fSTATE;
+ unsigned char fUNUSED;
+ unsigned tail;
+ unsigned head;
+};
+
+struct smd_channel {
+ volatile struct smd_half_channel *send;
+ volatile struct smd_half_channel *recv;
+ unsigned char *send_buf;
+ unsigned char *recv_buf;
+ unsigned buf_size;
+ struct list_head ch_list;
+
+ unsigned current_packet;
+ unsigned n;
+ void *priv;
+ void (*notify)(void *priv, unsigned flags);
+
+ int (*read)(smd_channel_t *ch, void *data, int len);
+ int (*write)(smd_channel_t *ch, const void *data, int len);
+ int (*read_avail)(smd_channel_t *ch);
+ int (*write_avail)(smd_channel_t *ch);
+ int (*read_from_cb)(smd_channel_t *ch, void *data, int len);
+
+ void (*update_state)(smd_channel_t *ch);
+ unsigned last_state;
+
+ char name[20];
+ struct platform_device pdev;
+ unsigned type;
+};
+
+static LIST_HEAD(smd_ch_closed_list);
+static LIST_HEAD(smd_ch_list);
+
+static unsigned char smd_ch_allocated[64];
+static struct work_struct probe_work;
+
+static void smd_alloc_channel(struct smd_alloc_elm *alloc_elm);
+static void *_smem_find(unsigned id, unsigned *size);
+
+static void smd_channel_probe_worker(struct work_struct *work)
+{
+ struct smd_alloc_elm *shared;
+ unsigned n;
+
+ shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
+
+ BUG_ON(!shared);
+
+ for (n = 0; n < 64; n++) {
+ if (smd_ch_allocated[n])
+ continue;
+
+ /* channel should be allocated only if APPS
+ processor is involved */
+ if (SMD_CHANNEL_TYPE(shared[n].type) == SMD_MODEM_QDSP_I)
+ continue;
+ if (!shared[n].ref_count)
+ continue;
+ if (!shared[n].name[0])
+ continue;
+
+ smd_alloc_channel(&shared[n]);
+ smd_ch_allocated[n] = 1;
+ }
+}
+
+static char *chstate(unsigned n)
+{
+ switch (n) {
+ case SMD_SS_CLOSED: return "CLOSED";
+ case SMD_SS_OPENING: return "OPENING";
+ case SMD_SS_OPENED: return "OPENED";
+ case SMD_SS_FLUSHING: return "FLUSHING";
+ case SMD_SS_CLOSING: return "CLOSING";
+ case SMD_SS_RESET: return "RESET";
+ case SMD_SS_RESET_OPENING: return "ROPENING";
+ default: return "UNKNOWN";
+ }
+}
+
+/* how many bytes are available for reading */
+static int smd_stream_read_avail(struct smd_channel *ch)
+{
+ return (ch->recv->head - ch->recv->tail) & (ch->buf_size - 1);
+}
+
+/* how many bytes we are free to write */
+static int smd_stream_write_avail(struct smd_channel *ch)
+{
+ return (ch->buf_size - 1) -
+ ((ch->send->head - ch->send->tail) & (ch->buf_size - 1));
+}
+
+static int smd_packet_read_avail(struct smd_channel *ch)
+{
+ if (ch->current_packet) {
+ int n = smd_stream_read_avail(ch);
+ if (n > ch->current_packet)
+ n = ch->current_packet;
+ return n;
+ } else {
+ return 0;
+ }
+}
+
+static int smd_packet_write_avail(struct smd_channel *ch)
+{
+ int n = smd_stream_write_avail(ch);
+ return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0;
+}
+
+static int ch_is_open(struct smd_channel *ch)
+{
+ return (ch->recv->state == SMD_SS_OPENED ||
+ ch->recv->state == SMD_SS_FLUSHING)
+ && (ch->send->state == SMD_SS_OPENED);
+}
+
+/* provide a pointer and length to readable data in the fifo */
+static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr)
+{
+ unsigned head = ch->recv->head;
+ unsigned tail = ch->recv->tail;
+ *ptr = (void *) (ch->recv_buf + tail);
+
+ if (tail <= head)
+ return head - tail;
+ else
+ return ch->buf_size - tail;
+}
+
+/* advance the fifo read pointer after data from ch_read_buffer is consumed */
+static void ch_read_done(struct smd_channel *ch, unsigned count)
+{
+ BUG_ON(count > smd_stream_read_avail(ch));
+ ch->recv->tail = (ch->recv->tail + count) & (ch->buf_size - 1);
+ ch->send->fTAIL = 1;
+}
+
+/* basic read interface to ch_read_{buffer,done} used
+** by smd_*_read() and update_packet_state()
+** will read-and-discard if the _data pointer is null
+*/
+static int ch_read(struct smd_channel *ch, void *_data, int len)
+{
+ void *ptr;
+ unsigned n;
+ unsigned char *data = _data;
+ int orig_len = len;
+
+ while (len > 0) {
+ n = ch_read_buffer(ch, &ptr);
+ if (n == 0)
+ break;
+
+ if (n > len)
+ n = len;
+ if (_data)
+ memcpy(data, ptr, n);
+
+ data += n;
+ len -= n;
+ ch_read_done(ch, n);
+ }
+
+ return orig_len - len;
+}
+
+static void update_stream_state(struct smd_channel *ch)
+{
+ /* streams have no special state requiring updating */
+}
+
+static void update_packet_state(struct smd_channel *ch)
+{
+ unsigned hdr[5];
+ int r;
+
+ /* can't do anything if we're in the middle of a packet */
+ while (ch->current_packet == 0) {
+ /* discard 0 length packets if any */
+
+ /* don't bother unless we can get the full header */
+ if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE)
+ return;
+
+ r = ch_read(ch, hdr, SMD_HEADER_SIZE);
+ BUG_ON(r != SMD_HEADER_SIZE);
+
+ ch->current_packet = hdr[0];
+ }
+}
+
+/* provide a pointer and length to next free space in the fifo */
+static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr)
+{
+ unsigned head = ch->send->head;
+ unsigned tail = ch->send->tail;
+ *ptr = (void *) (ch->send_buf + head);
+
+ if (head < tail) {
+ return tail - head - 1;
+ } else {
+ if (tail == 0)
+ return ch->buf_size - head - 1;
+ else
+ return ch->buf_size - head;
+ }
+}
+
+/* advace the fifo write pointer after freespace from ch_write_buffer is filled */
+static void ch_write_done(struct smd_channel *ch, unsigned count)
+{
+ BUG_ON(count > smd_stream_write_avail(ch));
+ ch->send->head = (ch->send->head + count) & (ch->buf_size - 1);
+ ch->send->fHEAD = 1;
+}
+
+static void ch_set_state(struct smd_channel *ch, unsigned n)
+{
+ if (n == SMD_SS_OPENED) {
+ ch->send->fDSR = 1;
+ ch->send->fCTS = 1;
+ ch->send->fCD = 1;
+ } else {
+ ch->send->fDSR = 0;
+ ch->send->fCTS = 0;
+ ch->send->fCD = 0;
+ }
+ ch->send->state = n;
+ ch->send->fSTATE = 1;
+ notify_other_smd(ch->type);
+}
+
+static void do_smd_probe(void)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ if (shared->heap_info.free_offset != last_heap_free) {
+ last_heap_free = shared->heap_info.free_offset;
+ schedule_work(&probe_work);
+ }
+}
+
+static void smd_state_change(struct smd_channel *ch,
+ unsigned last, unsigned next)
+{
+ ch->last_state = next;
+
+ SMD_INFO("SMD: ch %d %s -> %s\n", ch->n,
+ chstate(last), chstate(next));
+
+ switch (next) {
+ case SMD_SS_OPENING:
+ if (ch->send->state == SMD_SS_CLOSING ||
+ ch->send->state == SMD_SS_CLOSED) {
+ ch->recv->tail = 0;
+ ch->send->head = 0;
+ ch_set_state(ch, SMD_SS_OPENING);
+ }
+ break;
+ case SMD_SS_OPENED:
+ if (ch->send->state == SMD_SS_OPENING) {
+ ch_set_state(ch, SMD_SS_OPENED);
+ ch->notify(ch->priv, SMD_EVENT_OPEN);
+ }
+ break;
+ case SMD_SS_FLUSHING:
+ case SMD_SS_RESET:
+ /* we should force them to close? */
+ break;
+ case SMD_SS_CLOSED:
+ if (ch->send->state == SMD_SS_OPENED) {
+ ch_set_state(ch, SMD_SS_CLOSING);
+ ch->notify(ch->priv, SMD_EVENT_CLOSE);
+ }
+ break;
+ }
+}
+
+static irqreturn_t smd_irq_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct smd_channel *ch;
+ int do_notify_modem = 0;
+ int do_notify_qdsp = 0;
+ unsigned ch_flags;
+ unsigned tmp;
+
+ spin_lock_irqsave(&smd_lock, flags);
+ list_for_each_entry(ch, &smd_ch_list, ch_list) {
+ ch_flags = 0;
+ if (ch_is_open(ch)) {
+ if (ch->recv->fHEAD) {
+ ch->recv->fHEAD = 0;
+ ch_flags |= 1;
+ if (ch->type == SMD_APPS_MODEM)
+ do_notify_modem |= 1;
+ else if (ch->type == SMD_APPS_QDSP_I)
+ do_notify_qdsp |= 1;
+ }
+ if (ch->recv->fTAIL) {
+ ch->recv->fTAIL = 0;
+ ch_flags |= 2;
+ if (ch->type == SMD_APPS_MODEM)
+ do_notify_modem |= 1;
+ else if (ch->type == SMD_APPS_QDSP_I)
+ do_notify_qdsp |= 1;
+ }
+ if (ch->recv->fSTATE) {
+ ch->recv->fSTATE = 0;
+ ch_flags |= 4;
+ if (ch->type == SMD_APPS_MODEM)
+ do_notify_modem |= 1;
+ else if (ch->type == SMD_APPS_QDSP_I)
+ do_notify_qdsp |= 1;
+ }
+ }
+ tmp = ch->recv->state;
+ if (tmp != ch->last_state)
+ smd_state_change(ch, ch->last_state, tmp);
+ if (ch_flags) {
+ ch->update_state(ch);
+ ch->notify(ch->priv, SMD_EVENT_DATA);
+ }
+ }
+ if (do_notify_modem)
+ notify_other_smd(SMD_APPS_MODEM);
+
+ if (do_notify_qdsp)
+ notify_other_smd(SMD_APPS_QDSP_I);
+
+ spin_unlock_irqrestore(&smd_lock, flags);
+ do_smd_probe();
+ return IRQ_HANDLED;
+}
+
+static void smd_fake_irq_handler(unsigned long arg)
+{
+ smd_irq_handler(0, NULL);
+}
+
+static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0);
+
+void smd_sleep_exit(void)
+{
+ unsigned long flags;
+ struct smd_channel *ch;
+ unsigned tmp;
+ int need_int = 0;
+
+ spin_lock_irqsave(&smd_lock, flags);
+ list_for_each_entry(ch, &smd_ch_list, ch_list) {
+ if (ch_is_open(ch)) {
+ if (ch->recv->fHEAD) {
+ SMD_DBG("smd_sleep_exit ch %d fHEAD "
+ "%x %x %x\n",
+ ch->n,
+ ch->recv->fHEAD,
+ ch->recv->head, ch->recv->tail);
+ need_int = 1;
+ break;
+ }
+ if (ch->recv->fTAIL) {
+ SMD_DBG("smd_sleep_exit ch %d fTAIL "
+ "%x %x %x\n",
+ ch->n,
+ ch->recv->fTAIL,
+ ch->send->head, ch->send->tail);
+ need_int = 1;
+ break;
+ }
+ if (ch->recv->fSTATE) {
+ SMD_DBG("smd_sleep_exit ch %d fSTATE %x"
+ "\n", ch->n,
+ ch->recv->fSTATE);
+ need_int = 1;
+ break;
+ }
+ tmp = ch->recv->state;
+ if (tmp != ch->last_state) {
+ SMD_DBG("smd_sleep_exit ch %d "
+ "state %x != %x\n",
+ ch->n, tmp,
+ ch->last_state);
+ need_int = 1;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&smd_lock, flags);
+ do_smd_probe();
+ if (need_int) {
+ SMD_DBG("smd_sleep_exit need interrupt\n");
+ tasklet_schedule(&smd_fake_irq_tasklet);
+ }
+}
+
+static int smd_is_packet(struct smd_alloc_elm *alloc_elm)
+{
+ if (SMD_XFER_TYPE(alloc_elm->type) == 1)
+ return 0;
+ else if (SMD_XFER_TYPE(alloc_elm->type) == 2)
+ return 1;
+
+ /* for cases where xfer type is 0 */
+ if (!strncmp(alloc_elm->name, "DAL", 3))
+ return 0;
+
+ if (alloc_elm->cid > 4 || alloc_elm->cid == 1)
+ return 1;
+ else
+ return 0;
+}
+
+static int smd_stream_write(smd_channel_t *ch, const void *_data, int len)
+{
+ void *ptr;
+ const unsigned char *buf = _data;
+ unsigned xfer;
+ int orig_len = len;
+
+ SMD_DBG("smd_stream_write() %d -> ch%d\n", len, ch->n);
+ if (len < 0)
+ return -EINVAL;
+ else if (len == 0)
+ return 0;
+
+ while ((xfer = ch_write_buffer(ch, &ptr)) != 0) {
+ if (!ch_is_open(ch))
+ break;
+ if (xfer > len)
+ xfer = len;
+ memcpy(ptr, buf, xfer);
+ ch_write_done(ch, xfer);
+ len -= xfer;
+ buf += xfer;
+ if (len == 0)
+ break;
+ }
+
+ if (orig_len - len)
+ notify_other_smd(ch->type);
+
+ return orig_len - len;
+}
+
+static int smd_packet_write(smd_channel_t *ch, const void *_data, int len)
+{
+ int ret;
+ unsigned hdr[5];
+
+ SMD_DBG("smd_packet_write() %d -> ch%d\n", len, ch->n);
+ if (len < 0)
+ return -EINVAL;
+ else if (len == 0)
+ return 0;
+
+ if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE))
+ return -ENOMEM;
+
+ hdr[0] = len;
+ hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
+
+
+ ret = smd_stream_write(ch, hdr, sizeof(hdr));
+ if (ret < 0 || ret != sizeof(hdr)) {
+ SMD_DBG("%s failed to write pkt header: "
+ "%d returned\n", __func__, ret);
+ return -1;
+ }
+
+
+ ret = smd_stream_write(ch, _data, len);
+ if (ret < 0 || ret != len) {
+ SMD_DBG("%s failed to write pkt data: "
+ "%d returned\n", __func__, ret);
+ return ret;
+ }
+
+ return len;
+}
+
+static int smd_stream_read(smd_channel_t *ch, void *data, int len)
+{
+ int r;
+
+ if (len < 0)
+ return -EINVAL;
+
+ r = ch_read(ch, data, len);
+ if (r > 0)
+ notify_other_smd(ch->type);
+
+ return r;
+}
+
+static int smd_packet_read(smd_channel_t *ch, void *data, int len)
+{
+ unsigned long flags;
+ int r;
+
+ if (len < 0)
+ return -EINVAL;
+
+ if (len > ch->current_packet)
+ len = ch->current_packet;
+
+ r = ch_read(ch, data, len);
+ if (r > 0)
+ notify_other_smd(ch->type);
+
+ spin_lock_irqsave(&smd_lock, flags);
+ ch->current_packet -= r;
+ update_packet_state(ch);
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+ return r;
+}
+
+static int smd_packet_read_from_cb(smd_channel_t *ch, void *data, int len)
+{
+ int r;
+
+ if (len < 0)
+ return -EINVAL;
+
+ if (len > ch->current_packet)
+ len = ch->current_packet;
+
+ r = ch_read(ch, data, len);
+ if (r > 0)
+ notify_other_smd(ch->type);
+
+ ch->current_packet -= r;
+ update_packet_state(ch);
+
+ return r;
+}
+
+static struct smd_channel *_smd_alloc_channel_v1(uint32_t cid)
+{
+ struct smd_channel *ch;
+ void *shared;
+
+ shared = smem_alloc(ID_SMD_CHANNELS + cid,
+ 2 * (sizeof(struct smd_half_channel) +
+ SMD_BUF_SIZE));
+ if (!shared) {
+ pr_err("smd_alloc_channel: cid %d does not exist\n", cid);
+ return NULL;
+ }
+
+ ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);
+ if (ch) {
+ ch->send = shared;
+ ch->send_buf = shared + sizeof(struct smd_half_channel);
+ ch->recv = (struct smd_half_channel *)
+ (ch->send_buf + SMD_BUF_SIZE);
+ ch->recv_buf = (unsigned char *)ch->recv +
+ sizeof(struct smd_half_channel);
+ ch->buf_size = SMD_BUF_SIZE;
+ ch->n = cid;
+ } else
+ pr_err("smd_alloc_channel: out of memory\n");
+
+ return ch;
+}
+
+static struct smd_channel *_smd_alloc_channel_v2(uint32_t cid)
+{
+ struct smd_channel *ch;
+ void *shared, *shared_fifo;
+ unsigned size;
+
+ shared = smem_alloc(ID_SMD_CHANNELS + cid,
+ 2 * sizeof(struct smd_half_channel));
+ if (!shared) {
+ pr_err("smd_alloc_channel: cid %d does not exist\n", cid);
+ return NULL;
+ }
+
+ shared_fifo = _smem_find(SMEM_SMD_FIFO_BASE_ID + cid, &size);
+ if (!shared_fifo) {
+ pr_err("smd_alloc_channel: cid %d fifo do not exist\n", cid);
+ return NULL;
+ }
+ SMD_INFO("smd_alloc_channel: cid %d fifo found; size = %d\n",
+ cid, (size / 2));
+
+ ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);
+ if (ch) {
+ ch->send = shared;
+ ch->recv = shared + sizeof(struct smd_half_channel);
+ ch->send_buf = shared_fifo;
+ ch->recv_buf = shared_fifo + (size / 2);
+ ch->buf_size = size / 2;
+ ch->n = cid;
+ } else
+ pr_err("smd_alloc_channel() out of memory\n");
+
+ return ch;
+}
+
+static void smd_alloc_channel(struct smd_alloc_elm *alloc_elm)
+{
+ struct smd_channel *ch;
+ uint32_t *smd_ver;
+
+ smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
+
+ if (smd_ver && ((smd_ver[VERSION_MODEM] >> 16) >= 1))
+ ch = _smd_alloc_channel_v2(alloc_elm->cid);
+ else
+ ch = _smd_alloc_channel_v1(alloc_elm->cid);
+
+ if (ch == 0)
+ return;
+
+ ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
+ memcpy(ch->name, alloc_elm->name, 20);
+ ch->name[19] = 0;
+
+ if (smd_is_packet(alloc_elm)) {
+ ch->read = smd_packet_read;
+ ch->write = smd_packet_write;
+ ch->read_avail = smd_packet_read_avail;
+ ch->write_avail = smd_packet_write_avail;
+ ch->update_state = update_packet_state;
+ ch->read_from_cb = smd_packet_read_from_cb;
+ } else {
+ ch->read = smd_stream_read;
+ ch->write = smd_stream_write;
+ ch->read_avail = smd_stream_read_avail;
+ ch->write_avail = smd_stream_write_avail;
+ ch->update_state = update_stream_state;
+ ch->read_from_cb = smd_stream_read;
+ }
+
+ ch->pdev.name = ch->name;
+ ch->pdev.id = ch->type;
+
+ SMD_INFO("smd_alloc_channel() '%s' cid=%d\n",
+ ch->name, ch->n);
+
+ mutex_lock(&smd_creation_mutex);
+ list_add(&ch->ch_list, &smd_ch_closed_list);
+ mutex_unlock(&smd_creation_mutex);
+
+ platform_device_register(&ch->pdev);
+}
+
+static void do_nothing_notify(void *priv, unsigned flags)
+{
+}
+
+struct smd_channel *smd_get_channel(const char *name, uint32_t type)
+{
+ struct smd_channel *ch;
+
+ mutex_lock(&smd_creation_mutex);
+ list_for_each_entry(ch, &smd_ch_closed_list, ch_list) {
+ if (!strcmp(name, ch->name) &&
+ (type == ch->type)) {
+ list_del(&ch->ch_list);
+ mutex_unlock(&smd_creation_mutex);
+ return ch;
+ }
+ }
+ mutex_unlock(&smd_creation_mutex);
+
+ return NULL;
+}
+
+int smd_named_open_on_edge(const char *name, uint32_t edge,
+ smd_channel_t **_ch,
+ void *priv, void (*notify)(void *, unsigned))
+{
+ struct smd_channel *ch;
+ unsigned long flags;
+
+ if (smd_initialized == 0) {
+ SMD_INFO("smd_open() before smd_init()\n");
+ return -ENODEV;
+ }
+
+ SMD_DBG("smd_open('%s', %p, %p)\n", name, priv, notify);
+
+ ch = smd_get_channel(name, edge);
+ if (!ch)
+ return -ENODEV;
+
+ if (notify == 0)
+ notify = do_nothing_notify;
+
+ ch->notify = notify;
+ ch->current_packet = 0;
+ ch->last_state = SMD_SS_CLOSED;
+ ch->priv = priv;
+
+ *_ch = ch;
+
+ SMD_DBG("smd_open: opening '%s'\n", ch->name);
+
+ spin_lock_irqsave(&smd_lock, flags);
+ list_add(&ch->ch_list, &smd_ch_list);
+ SMD_DBG("%s: opening ch %d\n", __func__, ch->n);
+
+ smd_state_change(ch, ch->last_state, SMD_SS_OPENING);
+
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(smd_named_open_on_edge);
+
+
+int smd_open(const char *name, smd_channel_t **_ch,
+ void *priv, void (*notify)(void *, unsigned))
+{
+ return smd_named_open_on_edge(name, SMD_APPS_MODEM, _ch, priv,
+ notify);
+}
+EXPORT_SYMBOL(smd_open);
+
+int smd_close(smd_channel_t *ch)
+{
+ unsigned long flags;
+
+ SMD_INFO("smd_close(%p)\n", ch);
+
+ if (ch == 0)
+ return -1;
+
+ spin_lock_irqsave(&smd_lock, flags);
+ ch->notify = do_nothing_notify;
+ list_del(&ch->ch_list);
+ ch_set_state(ch, SMD_SS_CLOSED);
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+ mutex_lock(&smd_creation_mutex);
+ list_add(&ch->ch_list, &smd_ch_closed_list);
+ mutex_unlock(&smd_creation_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(smd_close);
+
+int smd_read(smd_channel_t *ch, void *data, int len)
+{
+ return ch->read(ch, data, len);
+}
+EXPORT_SYMBOL(smd_read);
+
+int smd_read_from_cb(smd_channel_t *ch, void *data, int len)
+{
+ return ch->read_from_cb(ch, data, len);
+}
+EXPORT_SYMBOL(smd_read_from_cb);
+
+int smd_write(smd_channel_t *ch, const void *data, int len)
+{
+ return ch->write(ch, data, len);
+}
+EXPORT_SYMBOL(smd_write);
+
+int smd_read_avail(smd_channel_t *ch)
+{
+ return ch->read_avail(ch);
+}
+EXPORT_SYMBOL(smd_read_avail);
+
+int smd_write_avail(smd_channel_t *ch)
+{
+ return ch->write_avail(ch);
+}
+EXPORT_SYMBOL(smd_write_avail);
+
+int smd_wait_until_readable(smd_channel_t *ch, int bytes)
+{
+ return -1;
+}
+
+int smd_wait_until_writable(smd_channel_t *ch, int bytes)
+{
+ return -1;
+}
+
+int smd_cur_packet_size(smd_channel_t *ch)
+{
+ return ch->current_packet;
+}
+
+int smd_tiocmget(smd_channel_t *ch)
+{
+ return (ch->recv->fDSR ? TIOCM_DSR : 0) |
+ (ch->recv->fCTS ? TIOCM_CTS : 0) |
+ (ch->recv->fCD ? TIOCM_CD : 0) |
+ (ch->recv->fRI ? TIOCM_RI : 0) |
+ (ch->send->fCTS ? TIOCM_RTS : 0) |
+ (ch->send->fDSR ? TIOCM_DTR : 0);
+}
+
+int smd_tiocmset(smd_channel_t *ch, unsigned int set, unsigned int clear)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&smd_lock, flags);
+ if (set & TIOCM_DTR)
+ ch->send->fDSR = 1;
+
+ if (set & TIOCM_RTS)
+ ch->send->fCTS = 1;
+
+ if (clear & TIOCM_DTR)
+ ch->send->fDSR = 0;
+
+ if (clear & TIOCM_RTS)
+ ch->send->fCTS = 0;
+
+ ch->send->fSTATE = 1;
+ barrier();
+ notify_other_smd(ch->type);
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+void *smem_alloc(unsigned id, unsigned size)
+{
+ return smem_find(id, size);
+}
+
+void *smem_get_entry(unsigned id, unsigned *size)
+{
+ return _smem_find(id, size);
+}
+
+static void *_smem_find(unsigned id, unsigned *size)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return 0;
+
+ if (toc[id].allocated) {
+ *size = toc[id].size;
+ return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
+ }
+
+ return 0;
+}
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ unsigned size;
+ void *ptr;
+
+ ptr = _smem_find(id, &size);
+ if (!ptr)
+ return 0;
+
+ size_in = ALIGN(size_in, 8);
+ if (size_in != size) {
+ pr_err("smem_find(%d, %d): wrong size %d\n",
+ id, size_in, size);
+ return 0;
+ }
+
+ return ptr;
+}
+
+static int smem_init(void)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ uint32_t *smsm, i;
+
+ smsm = smem_alloc(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ if (smsm) {
+ smsm[SMSM_APPS_STATE] = 0;
+ if ((shared->version[VERSION_MODEM] >> 16) >= 0xB)
+ smsm[SMSM_APPS_DEM_I] = 0;
+ }
+
+ smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+ SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
+
+ if (smsm)
+ for (i = 0; i < SMSM_NUM_ENTRIES; i++)
+ smsm[i * SMSM_NUM_HOSTS + SMSM_APPS] = 0xffffffff;
+
+ return 0;
+}
+
+void smsm_reset_modem(unsigned mode)
+{
+ if (mode == SMSM_SYSTEM_DOWNLOAD) {
+ mode = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+ } else if (mode == SMSM_MODEM_WAIT) {
+ mode = SMSM_RESET | SMSM_MODEM_WAIT;
+ } else { /* reset_mode is SMSM_RESET or default */
+ mode = SMSM_RESET;
+ }
+
+ smsm_change_state(SMSM_APPS_STATE, mode, mode);
+}
+EXPORT_SYMBOL(smsm_reset_modem);
+
+void smsm_reset_modem_cont(void)
+{
+ unsigned long flags;
+ uint32_t *smsm;
+
+ spin_lock_irqsave(&smem_lock, flags);
+ smsm = smem_alloc(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+ smsm[SMSM_APPS_STATE] &= ~SMSM_MODEM_WAIT;
+ spin_unlock_irqrestore(&smem_lock, flags);
+}
+EXPORT_SYMBOL(smsm_reset_modem_cont);
+
+static irqreturn_t smsm_irq_handler(int irq, void *data)
+{
+ unsigned long flags;
+ uint32_t *smsm;
+ static uint32_t prev_smem_q6_apps_smsm;
+
+ if (irq == INT_ADSP_A11) {
+ smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX,
+ SMSM_NUM_INTR_MUX * sizeof(uint32_t));
+ if (!smsm ||
+ (smsm[SMEM_Q6_APPS_SMSM] == prev_smem_q6_apps_smsm))
+ return IRQ_HANDLED;
+
+ prev_smem_q6_apps_smsm = smsm[SMEM_Q6_APPS_SMSM];
+ }
+
+ spin_lock_irqsave(&smem_lock, flags);
+ smsm = smem_alloc(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ if (smsm == 0) {
+ SMSM_INFO("<SM NO STATE>\n");
+ } else {
+ unsigned old_apps, apps;
+ unsigned modm = smsm[SMSM_MODEM_STATE];
+
+ old_apps = apps = smsm[SMSM_APPS_STATE];
+
+ SMSM_DBG("<SM %08x %08x>\n", apps, modm);
+ if (apps & SMSM_RESET) {
+ /* If we get an interrupt and the apps SMSM_RESET
+ bit is already set, the modem is acking the
+ app's reset ack. */
+ apps &= ~SMSM_RESET;
+
+ /* Issue a fake irq to handle any
+ * smd state changes during reset
+ */
+ smd_fake_irq_handler(0);
+
+ /* queue modem restart notify chain */
+ modem_queue_start_reset_notify();
+
+ } else if (modm & SMSM_RESET) {
+ apps |= SMSM_RESET;
+ } else {
+ apps |= SMSM_INIT;
+ if (modm & SMSM_SMDINIT)
+ apps |= SMSM_SMDINIT;
+ if (modm & SMSM_RPCINIT)
+ apps |= SMSM_RPCINIT;
+ if ((apps & (SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT)) ==
+ (SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT))
+ apps |= SMSM_RUN;
+ }
+
+ if (smsm[SMSM_APPS_STATE] != apps) {
+ SMSM_DBG("<SM %08x NOTIFY>\n", apps);
+ smsm[SMSM_APPS_STATE] = apps;
+ do_smd_probe();
+ notify_other_smsm(SMSM_APPS_STATE, old_apps, apps);
+ }
+ }
+ spin_unlock_irqrestore(&smem_lock, flags);
+ return IRQ_HANDLED;
+}
+
+int smsm_change_state(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask)
+{
+ unsigned long flags;
+ uint32_t *smsm;
+ uint32_t old_state;
+
+ if (smsm_entry >= SMSM_NUM_ENTRIES) {
+ printk(KERN_ERR "smsm_change_state: Invalid entry %d",
+ smsm_entry);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&smem_lock, flags);
+
+ smsm = smem_alloc(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ if (smsm) {
+ old_state = smsm[smsm_entry];
+ smsm[smsm_entry] = (smsm[smsm_entry] & ~clear_mask) | set_mask;
+ SMSM_DBG("smsm_change_state %x\n", smsm[smsm_entry]);
+ notify_other_smsm(SMSM_APPS_STATE, old_state, smsm[smsm_entry]);
+ }
+
+ spin_unlock_irqrestore(&smem_lock, flags);
+
+ if (smsm == NULL) {
+ printk(KERN_ERR "smsm_change_state <SM NO STATE>\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+int smsm_change_intr_mask(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask)
+{
+ uint32_t *smsm;
+
+ if (smsm_entry >= SMSM_NUM_ENTRIES) {
+ printk(KERN_ERR "smsm_change_state: Invalid entry %d\n",
+ smsm_entry);
+ return -EINVAL;
+ }
+
+ smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+ SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
+
+ if (smsm) {
+ smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS] =
+ (smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS] &
+ ~clear_mask) | set_mask;
+ SMSM_INFO("smsm_entry %d, new intr_mask %x\n", smsm_entry,
+ smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS]);
+ } else {
+ printk(KERN_ERR "smsm_change_intr_mask <SM NO INTR_MASK>\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask)
+{
+ uint32_t *smsm;
+
+ if ((smsm_entry >= SMSM_NUM_ENTRIES) || (!intr_mask)) {
+ printk(KERN_ERR "smsm_change_state: Invalid input "
+ "entry %d, mask 0x%x\n",
+ smsm_entry, (unsigned int)intr_mask);
+ return -EINVAL;
+ }
+
+ smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+ SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
+
+ if (smsm) {
+ *intr_mask = smsm[smsm_entry * SMSM_NUM_HOSTS + SMSM_APPS];
+ } else {
+ printk(KERN_ERR "smsm_change_intr_mask <SM NO INTR_MASK>\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+uint32_t smsm_get_state(uint32_t smsm_entry)
+{
+ unsigned long flags;
+ uint32_t *smsm;
+ uint32_t rv;
+
+ if (smsm_entry >= SMSM_NUM_ENTRIES) {
+ printk(KERN_ERR "smsm_change_state: Invalid entry %d",
+ smsm_entry);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&smem_lock, flags);
+
+ smsm = smem_alloc(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ if (smsm)
+ rv = smsm[smsm_entry];
+ else
+ rv = 0;
+
+ spin_unlock_irqrestore(&smem_lock, flags);
+
+ if (smsm == NULL)
+ printk(KERN_ERR "smsm_get_state <SM NO STATE>\n");
+ return rv;
+
+}
+
+#define MAX_NUM_SLEEP_CLIENTS 64
+#define MAX_SLEEP_NAME_LEN 8
+
+#define NUM_GPIO_INT_REGISTERS 6
+#define GPIO_SMEM_NUM_GROUPS 2
+#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
+struct tramp_gpio_save {
+ unsigned int enable;
+ unsigned int detect;
+ unsigned int polarity;
+};
+
+struct tramp_gpio_smem {
+ uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
+ uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
+ uint32_t enabled[NUM_GPIO_INT_REGISTERS];
+ uint32_t detection[NUM_GPIO_INT_REGISTERS];
+ uint32_t polarity[NUM_GPIO_INT_REGISTERS];
+};
+
+/*
+ * Print debug information on shared memory sleep variables
+ */
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+ uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs)
+{
+ unsigned long flags;
+ uint32_t *ptr;
+ struct tramp_gpio_smem *gpio;
+
+ spin_lock_irqsave(&smem_lock, flags);
+
+ printk(KERN_ERR "SMEM_SMSM_SLEEP_DELAY: %x\n", sleep_delay);
+ printk(KERN_ERR "SMEM_SMSM_LIMIT_SLEEP: %x\n", sleep_limit);
+
+ ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr));
+ if (ptr)
+ printk(KERN_ERR "SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr);
+ else
+ printk(KERN_ERR "SMEM_SLEEP_POWER_COLLAPSE_DISABLED: missing\n");
+
+ printk(KERN_ERR "SMEM_SMSM_INT_INFO %x %x %x\n",
+ irq_mask, pending_irqs, wakeup_reason);
+
+ gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio));
+ if (gpio) {
+ int i;
+ for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++) {
+ printk(KERN_ERR "SMEM_GPIO_INT: %d: e %x d %x p %x\n",
+ i, gpio->enabled[i], gpio->detection[i],
+ gpio->polarity[i]);
+ }
+ for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++) {
+ printk(KERN_ERR "SMEM_GPIO_INT: %d: f %d: %d %d...\n",
+ i, gpio->num_fired[i], gpio->fired[i][0],
+ gpio->fired[i][1]);
+ }
+ } else
+ printk(KERN_ERR "SMEM_GPIO_INT: missing\n");
+
+#if 0
+ ptr = smem_alloc(SMEM_SLEEP_STATIC,
+ 2 * MAX_NUM_SLEEP_CLIENTS * (MAX_SLEEP_NAME_LEN + 1));
+ if (ptr)
+ printk(KERN_ERR "SMEM_SLEEP_STATIC: %x %x %x %x\n",
+ ptr[0], ptr[1], ptr[2], ptr[3]);
+ else
+ printk(KERN_ERR "SMEM_SLEEP_STATIC: missing\n");
+#endif
+
+ spin_unlock_irqrestore(&smem_lock, flags);
+}
+
+int smd_core_init(void)
+{
+ int r;
+ SMD_INFO("smd_core_init()\n");
+
+ r = request_irq(INT_A9_M2A_0, smd_irq_handler,
+ IRQF_TRIGGER_RISING, "smd_dev", 0);
+ if (r < 0)
+ return r;
+ r = enable_irq_wake(INT_A9_M2A_0);
+ if (r < 0)
+ printk(KERN_ERR "smd_core_init: "
+ "enable_irq_wake failed for INT_A9_M2A_0\n");
+
+ r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
+ IRQF_TRIGGER_RISING, "smsm_dev", 0);
+ if (r < 0) {
+ free_irq(INT_A9_M2A_0, 0);
+ return r;
+ }
+
+ r = enable_irq_wake(INT_A9_M2A_5);
+ if (r < 0)
+ printk(KERN_ERR "smd_core_init: "
+ "enable_irq_wake failed for INT_A9_M2A_5\n");
+
+ r = request_irq(INT_ADSP_A11, smd_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_SHARED, "smd_dev",
+ smd_irq_handler);
+ if (r < 0)
+ printk(KERN_ERR "smd_core_init: "
+ "request_irq failed for INT_ADSP_A11\n");
+
+ r = request_irq(INT_ADSP_A11, smsm_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_SHARED, "smsm_dev",
+ smsm_irq_handler);
+ if (r < 0)
+ printk(KERN_ERR "smd_core_init: "
+ "request_irq failed for INT_ADSP_A11\n");
+
+ r = enable_irq_wake(INT_ADSP_A11);
+ if (r < 0)
+ printk(KERN_ERR "smd_core_init: "
+ "enable_irq_wake failed for INT_ADSP_A11\n");
+
+ /* we may have missed a signal while booting -- fake
+ * an interrupt to make sure we process any existing
+ * state
+ */
+ smsm_irq_handler(0, 0);
+
+ SMD_INFO("smd_core_init() done\n");
+
+ return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int debug_f3(char *buf, int max)
+{
+ char *x;
+ int size;
+ int i = 0, j = 0;
+ unsigned cols = 0;
+ char str[4*sizeof(unsigned)+1] = {0};
+
+ i += scnprintf(buf + i, max - i,
+ "Printing to log\n");
+
+ x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
+ if (x != 0) {
+ printk(KERN_ERR "smem: F3 TRACE LOG\n");
+ while (size > 0) {
+ if (size >= sizeof(unsigned)) {
+ printk(KERN_ERR "%08x", *((unsigned *) x));
+ for (j = 0; j < sizeof(unsigned); ++j)
+ if (isprint(*(x+j)))
+ str[cols*sizeof(unsigned) + j]
+ = *(x+j);
+ else
+ str[cols*sizeof(unsigned) + j]
+ = '-';
+ x += sizeof(unsigned);
+ size -= sizeof(unsigned);
+ } else {
+ while (size-- > 0)
+ printk(KERN_ERR "%02x",
+ (unsigned) *x++);
+ break;
+ }
+ if (cols == 3) {
+ cols = 0;
+ str[4*sizeof(unsigned)] = 0;
+ printk(KERN_ERR " %s\n", str);
+ str[0] = 0;
+ } else {
+ cols++;
+ printk(KERN_ERR " ");
+ }
+ }
+ printk(KERN_ERR "\n");
+ }
+
+ return max;
+}
+
+static int debug_diag(char *buf, int max)
+{
+ int i = 0;
+
+ i += scnprintf(buf + i, max - i,
+ "Printing to log\n");
+ smd_diag();
+
+ return i;
+}
+
+static int debug_modem_err_f3(char *buf, int max)
+{
+ char *x;
+ int size;
+ int i = 0, j = 0;
+ unsigned cols = 0;
+ char str[4*sizeof(unsigned)+1] = {0};
+
+ x = smem_get_entry(SMEM_ERR_F3_TRACE_LOG, &size);
+ if (x != 0) {
+ printk(KERN_ERR "smem: F3 TRACE LOG\n");
+ while (size > 0 && max - i) {
+ if (size >= sizeof(unsigned)) {
+ i += scnprintf(buf + i, max - i, "%08x",
+ *((unsigned *) x));
+ for (j = 0; j < sizeof(unsigned); ++j)
+ if (isprint(*(x+j)))
+ str[cols*sizeof(unsigned) + j]
+ = *(x+j);
+ else
+ str[cols*sizeof(unsigned) + j]
+ = '-';
+ x += sizeof(unsigned);
+ size -= sizeof(unsigned);
+ } else {
+ while (size-- > 0 && max - i)
+ i += scnprintf(buf + i, max - i,
+ "%02x",
+ (unsigned) *x++);
+ break;
+ }
+ if (cols == 3) {
+ cols = 0;
+ str[4*sizeof(unsigned)] = 0;
+ i += scnprintf(buf + i, max - i, " %s\n",
+ str);
+ str[0] = 0;
+ } else {
+ cols++;
+ i += scnprintf(buf + i, max - i, " ");
+ }
+ }
+ i += scnprintf(buf + i, max - i, "\n");
+ }
+
+ return i;
+}
+
+static int debug_modem_err(char *buf, int max)
+{
+ char *x;
+ int size;
+ int i = 0;
+
+ x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+ if (x != 0) {
+ x[SZ_DIAG_ERR_MSG - 1] = 0;
+ i += scnprintf(buf + i, max - i,
+ "smem: DIAG '%s'\n", x);
+ }
+
+ x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+ if (x != 0) {
+ x[size - 1] = 0;
+ i += scnprintf(buf + i, max - i,
+ "smem: CRASH LOG\n'%s'\n", x);
+ }
+ i += scnprintf(buf + i, max - i, "\n");
+
+ return i;
+}
+
+static int dump_ch(char *buf, int max, int n,
+ struct smd_half_channel *s,
+ struct smd_half_channel *r)
+{
+ return scnprintf(
+ buf, max,
+ "ch%02d:"
+ " %8s(%04d/%04d) %c%c%c%c%c%c%c <->"
+ " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n,
+ chstate(s->state), s->tail, s->head,
+ s->fDSR ? 'D' : 'd',
+ s->fCTS ? 'C' : 'c',
+ s->fCD ? 'C' : 'c',
+ s->fRI ? 'I' : 'i',
+ s->fHEAD ? 'W' : 'w',
+ s->fTAIL ? 'R' : 'r',
+ s->fSTATE ? 'S' : 's',
+ chstate(r->state), r->tail, r->head,
+ r->fDSR ? 'D' : 'd',
+ r->fCTS ? 'R' : 'r',
+ r->fCD ? 'C' : 'c',
+ r->fRI ? 'I' : 'i',
+ r->fHEAD ? 'W' : 'w',
+ r->fTAIL ? 'R' : 'r',
+ r->fSTATE ? 'S' : 's'
+ );
+}
+
+static int debug_read_diag_msg(char *buf, int max)
+{
+ char *msg;
+ int i = 0;
+
+ msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+
+ if (msg) {
+ msg[SZ_DIAG_ERR_MSG - 1] = 0;
+ i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg);
+ }
+ return i;
+}
+
+static int debug_read_mem(char *buf, int max)
+{
+ unsigned n;
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int i = 0;
+
+ i += scnprintf(buf + i, max - i,
+ "heap: init=%d free=%d remain=%d\n",
+ shared->heap_info.initialized,
+ shared->heap_info.free_offset,
+ shared->heap_info.heap_remaining);
+
+ for (n = 0; n < SMD_HEAP_SIZE; n++) {
+ if (toc[n].allocated == 0)
+ continue;
+ i += scnprintf(buf + i, max - i,
+ "%04d: offset %08x size %08x\n",
+ n, toc[n].offset, toc[n].size);
+ }
+ return i;
+}
+
+static int debug_read_ch_v1(char *buf, int max)
+{
+ void *shared;
+ int n, i = 0;
+
+ for (n = 0; n < SMD_CHANNELS; n++) {
+ shared = smem_find(ID_SMD_CHANNELS + n,
+ 2 * (sizeof(struct smd_half_channel) +
+ SMD_BUF_SIZE));
+
+ if (shared == 0)
+ continue;
+ i += dump_ch(buf + i, max - i, n, shared,
+ (shared + sizeof(struct smd_half_channel) +
+ SMD_BUF_SIZE));
+ }
+
+ return i;
+}
+
+static int debug_read_ch_v2(char *buf, int max)
+{
+ void *shared;
+ int n, i = 0;
+
+ for (n = 0; n < SMD_CHANNELS; n++) {
+ shared = smem_find(ID_SMD_CHANNELS + n,
+ 2 * sizeof(struct smd_half_channel));
+
+ if (shared == 0)
+ continue;
+ i += dump_ch(buf + i, max - i, n, shared,
+ (shared + sizeof(struct smd_half_channel)));
+ }
+
+ return i;
+}
+
+static int debug_read_smem_version(char *buf, int max)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ uint32_t n, version, i = 0;
+
+ for (n = 0; n < 32; n++) {
+ version = shared->version[n];
+ i += scnprintf(buf + i, max - i,
+ "entry %d: smem = %d proc_comm = %d\n", n,
+ version >> 16,
+ version & 0xffff);
+ }
+
+ return i;
+}
+
+static int debug_read_smd_version(char *buf, int max)
+{
+ uint32_t *smd_ver;
+ uint32_t n, version, i = 0;
+
+ smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
+
+ if (smd_ver)
+ for (n = 0; n < 32; n++) {
+ version = smd_ver[n];
+ i += scnprintf(buf + i, max - i,
+ "entry %d: %d.%d\n", n,
+ version >> 16,
+ version & 0xffff);
+ }
+
+ return i;
+}
+
+static int debug_read_alloc_tbl(char *buf, int max)
+{
+ struct smd_alloc_elm *shared;
+ int n, i = 0;
+
+ shared = smem_find(ID_CH_ALLOC_TBL, sizeof(struct smd_alloc_elm[64]));
+
+ BUG_ON(!shared);
+
+ for (n = 0; n < 64; n++) {
+ i += scnprintf(buf + i, max - i,
+ "name=%s cid=%d ch type=%d "
+ "xfer type=%d ref_count=%d\n",
+ shared[n].name,
+ shared[n].cid,
+ SMD_CHANNEL_TYPE(shared[n].type),
+ SMD_XFER_TYPE(shared[n].type),
+ shared[n].ref_count);
+ }
+
+ return i;
+}
+
+static int debug_read_smsm_state(char *buf, int max)
+{
+ uint32_t *smsm;
+ int n, i = 0;
+
+ smsm = smem_find(ID_SHARED_STATE,
+ SMSM_NUM_ENTRIES * sizeof(uint32_t));
+
+ if (smsm)
+ for (n = 0; n < SMSM_NUM_ENTRIES; n++)
+ i += scnprintf(buf + i, max - i, "entry %d: 0x%08x\n",
+ n, smsm[n]);
+
+ return i;
+
+}
+
+static int debug_read_intr_mask(char *buf, int max)
+{
+ uint32_t *smsm;
+ int m, n, i = 0;
+
+ smsm = smem_alloc(SMEM_SMSM_CPU_INTR_MASK,
+ SMSM_NUM_ENTRIES * SMSM_NUM_HOSTS * sizeof(uint32_t));
+
+ if (smsm)
+ for (m = 0; m < SMSM_NUM_ENTRIES; m++) {
+ i += scnprintf(buf + i, max - i, "entry %d:", m);
+ for (n = 0; n < SMSM_NUM_HOSTS; n++)
+ i += scnprintf(buf + i, max - i,
+ " host %d: 0x%08x",
+ n, smsm[m * SMSM_NUM_HOSTS + n]);
+ i += scnprintf(buf + i, max - i, "\n");
+ }
+
+ return i;
+}
+
+static int debug_read_intr_mux(char *buf, int max)
+{
+ uint32_t *smsm;
+ int n, i = 0;
+
+ smsm = smem_alloc(SMEM_SMD_SMSM_INTR_MUX,
+ SMSM_NUM_INTR_MUX * sizeof(uint32_t));
+
+ if (smsm)
+ for (n = 0; n < SMSM_NUM_INTR_MUX; n++)
+ i += scnprintf(buf + i, max - i, "entry %d: %d\n",
+ n, smsm[n]);
+
+ return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static void smd_debugfs_init(void)
+{
+ struct dentry *dent;
+ uint32_t *smd_ver;
+
+ dent = debugfs_create_dir("smd", 0);
+ if (IS_ERR(dent))
+ return;
+
+ smd_ver = smem_alloc(SMEM_VERSION_SMD, 32 * sizeof(uint32_t));
+
+ if (smd_ver && ((smd_ver[VERSION_MODEM] >> 16) >= 1))
+ debug_create("ch", 0444, dent, debug_read_ch_v2);
+ else
+ debug_create("ch", 0444, dent, debug_read_ch_v1);
+
+ debug_create("diag", 0444, dent, debug_read_diag_msg);
+ debug_create("mem", 0444, dent, debug_read_mem);
+ debug_create("version", 0444, dent, debug_read_smd_version);
+ debug_create("tbl", 0444, dent, debug_read_alloc_tbl);
+ debug_create("modem_err", 0444, dent, debug_modem_err);
+ debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3);
+ debug_create("print_diag", 0444, dent, debug_diag);
+ debug_create("print_f3", 0444, dent, debug_f3);
+}
+
+static void smsm_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("smsm", 0);
+ if (IS_ERR(dent))
+ return;
+
+ debug_create("state", 0444, dent, debug_read_smsm_state);
+ debug_create("intr_mask", 0444, dent, debug_read_intr_mask);
+ debug_create("intr_mux", 0444, dent, debug_read_intr_mux);
+ debug_create("version", 0444, dent, debug_read_smem_version);
+}
+#else
+static void smd_debugfs_init(void) {}
+static void smsm_debugfs_init(void) {}
+#endif
+
+static int __init msm_smd_probe(struct platform_device *pdev)
+{
+ /* enable smd and smsm info messages */
+ msm_smd_debug_mask = 0xc;
+
+ SMD_INFO("smd probe\n");
+
+ INIT_WORK(&probe_work, smd_channel_probe_worker);
+
+ if (smem_init()) {
+ printk(KERN_ERR "smem_init() failed\n");
+ return -1;
+ }
+
+ if (smd_core_init()) {
+ printk(KERN_ERR "smd_core_init() failed\n");
+ return -1;
+ }
+
+ do_smd_probe();
+
+ msm_check_for_modem_crash = check_for_modem_crash;
+
+ smd_initialized = 1;
+
+ smd_debugfs_init();
+ smsm_debugfs_init();
+
+ return 0;
+}
+
+static struct platform_driver msm_smd_driver = {
+ .probe = msm_smd_probe,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_smd_init(void)
+{
+ return platform_driver_register(&msm_smd_driver);
+}
+
+module_init(msm_smd_init);
+
+MODULE_DESCRIPTION("MSM Shared Memory Core");
+MODULE_AUTHOR("Brian Swetland <swetland@google.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_ctl2.c b/arch/arm/mach-msm/smd_ctl2.c
new file mode 100644
index 000000000000..8348f94dae68
--- /dev/null
+++ b/arch/arm/mach-msm/smd_ctl2.c
@@ -0,0 +1,677 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * SMD Control Driver -- Provides a binary SMD non-muxed control port
+ * interface.
+ */
+
+#include <linux/cdev.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <asm/ioctls.h>
+
+#include <mach/msm_smd.h>
+
+#include "modem_notifier.h"
+
+#define NUM_SMD_CTL_PORTS 3
+#define DEVICE_NAME "smdcntl"
+#define MAX_BUF_SIZE 2048
+
+struct smd_ctl_dev {
+ struct cdev cdev;
+ char name[9];
+ struct device *devicep;
+
+ struct smd_channel *ctl_ch;
+ struct mutex ctl_ch_lock;
+ struct mutex rx_lock;
+ struct mutex is_open_lock;
+ struct workqueue_struct *ctl_wq;
+ struct work_struct ctl_work;
+ wait_queue_head_t ctl_wait_queue;
+ wait_queue_head_t ctl_opened_wait_queue;
+
+ int i;
+
+ unsigned char tx_buf[MAX_BUF_SIZE];
+ unsigned char rx_buf[MAX_BUF_SIZE];
+ int bytes_read;
+ int is_open;
+
+ struct notifier_block nb;
+ int has_reset;
+ struct mutex has_reset_lock;
+
+} *smd_ctl_devp[NUM_SMD_CTL_PORTS];
+
+struct class *smd_ctl_classp;
+static dev_t smd_ctl_number;
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define D_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+ int i; \
+ printk(KERN_ERR "%s", prestr); \
+ for (i = 0; i < cnt; i++) \
+ printk(KERN_ERR "%.2x", buf[i]); \
+ printk(KERN_ERR "\n"); \
+} while (0)
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
+#endif
+
+#ifdef DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+static void clean_and_signal(struct smd_ctl_dev *smd_ctl_devp)
+{
+ flush_workqueue(smd_ctl_devp->ctl_wq);
+
+ mutex_lock(&smd_ctl_devp->has_reset_lock);
+ smd_ctl_devp->has_reset = 1;
+ mutex_unlock(&smd_ctl_devp->has_reset_lock);
+
+ mutex_lock(&smd_ctl_devp->rx_lock);
+ smd_ctl_devp->bytes_read = 0;
+ mutex_unlock(&smd_ctl_devp->rx_lock);
+
+ mutex_lock(&smd_ctl_devp->is_open_lock);
+ smd_ctl_devp->is_open = 0;
+ mutex_unlock(&smd_ctl_devp->is_open_lock);
+
+ wake_up_interruptible(&smd_ctl_devp->ctl_wait_queue);
+ wake_up_interruptible(&smd_ctl_devp->ctl_opened_wait_queue);
+}
+
+static int modem_notifier(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
+{
+ struct smd_ctl_dev *smd_ctl_devp =
+ container_of(this,
+ struct smd_ctl_dev,
+ nb);
+
+ if (!smd_ctl_devp)
+ return NOTIFY_DONE;
+
+ switch (code) {
+ case MODEM_NOTIFIER_START_RESET:
+ printk(KERN_ERR "Notify: start reset ch:%i\n",
+ smd_ctl_devp->i);
+ clean_and_signal(smd_ctl_devp);
+ break;
+ case MODEM_NOTIFIER_END_RESET:
+ printk(KERN_ERR "Notify: end reset\n");
+ break;
+ default:
+ printk(KERN_ERR "Notify: general\n");
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+int smd_ctl_ioctl(struct inode *inode,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct smd_ctl_dev *smd_ctl_devp;
+
+ smd_ctl_devp = file->private_data;
+
+ switch (cmd) {
+ case TIOCMGET:
+ ret = smd_tiocmget(smd_ctl_devp->ctl_ch);
+ break;
+ case TIOCMSET:
+ ret = smd_tiocmset(smd_ctl_devp->ctl_ch, arg, ~arg);
+ break;
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+ssize_t smd_ctl_read(struct file *file,
+ char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int r;
+ int bytes_read;
+ struct smd_ctl_dev *smd_ctl_devp;
+
+ D(KERN_ERR "%s: read %i bytes\n",
+ __func__, count);
+
+ smd_ctl_devp = file->private_data;
+
+ if (!smd_ctl_devp->ctl_ch)
+ return -EINVAL;
+
+ r = wait_event_interruptible(smd_ctl_devp->ctl_wait_queue,
+ smd_ctl_devp->bytes_read |
+ smd_ctl_devp->has_reset);
+
+ if (smd_ctl_devp->has_reset)
+ return -ENETRESET;
+
+ if (r < 0) {
+ /* qualify error message */
+ if (r != -ERESTARTSYS) {
+ /* we get this anytime a signal comes in */
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "wait_event_interruptible ret %i\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r
+ );
+ }
+ return r;
+ }
+
+ /* Here we have a whole packet waiting for us */
+
+ mutex_lock(&smd_ctl_devp->rx_lock);
+ bytes_read = smd_ctl_devp->bytes_read;
+ smd_ctl_devp->bytes_read = 0;
+ mutex_unlock(&smd_ctl_devp->rx_lock);
+
+ D(KERN_ERR "%s: after wait_event_interruptible bytes_read = %i\n",
+ __func__, bytes_read);
+
+ if (bytes_read > count) {
+ printk(KERN_ERR "packet size %i > buffer size %i, "
+ "dropping packet!", bytes_read, count);
+ smd_read(smd_ctl_devp->ctl_ch, 0, bytes_read);
+ return -EINVAL;
+ }
+
+ /* smd_read and copy_to_user need to be merged to only do 1 copy */
+ if (smd_read(smd_ctl_devp->ctl_ch, smd_ctl_devp->rx_buf, bytes_read)
+ != bytes_read) {
+ if (smd_ctl_devp->has_reset)
+ return -ENETRESET;
+
+ printk(KERN_ERR "user read: not enough data?!\n");
+ return -EINVAL;
+ }
+ D_DUMP_BUFFER("read: ", bytes_read, smd_ctl_devp->rx_buf);
+ r = copy_to_user(buf, smd_ctl_devp->rx_buf, bytes_read);
+
+ if (r > 0) {
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "copy_to_user could not copy %i bytes.\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r);
+ return r;
+ }
+
+ D(KERN_ERR "%s: just read %i bytes\n",
+ __func__, bytes_read);
+
+ /* Not all packet events get explictly handled, this doesn't
+ matter if a constant stream of packets is streaming in, but
+ eventually a packet will be received and we'll have missed
+ the event. Queuing one more work item will catch this if
+ its happened, but do nothing if it hasn't.
+ */
+ queue_work(smd_ctl_devp->ctl_wq, &smd_ctl_devp->ctl_work);
+
+ D(KERN_ERR "%s: just queued more work\n", __func__);
+
+ return bytes_read;
+}
+
+ssize_t smd_ctl_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int r;
+ struct smd_ctl_dev *smd_ctl_devp;
+
+ if (count > MAX_BUF_SIZE)
+ return -EINVAL;
+
+ D(KERN_ERR "%s: writting %i bytes\n",
+ __func__, count);
+
+ smd_ctl_devp = file->private_data;
+
+ if (!smd_ctl_devp->ctl_ch)
+ return -EINVAL;
+
+ r = wait_event_interruptible(smd_ctl_devp->ctl_opened_wait_queue,
+ smd_ctl_devp->is_open |
+ smd_ctl_devp->has_reset);
+
+ if (smd_ctl_devp->has_reset)
+ return -ENETRESET;
+
+ if (r < 0) {
+ /* qualify error message */
+ if (r != -ERESTARTSYS) {
+ /* we get this anytime a signal comes in */
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "wait_event_interruptible ret %i\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r
+ );
+ }
+ return r;
+ }
+
+ D_DUMP_BUFFER("write: ", count, buf);
+
+ r = copy_from_user(smd_ctl_devp->tx_buf, buf, count);
+ if (r > 0) {
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "copy_from_user could not copy %i bytes.\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r);
+ return r;
+ }
+
+ D(KERN_ERR "%s: after copy_from_user. count = %i\n",
+ __func__, count);
+
+ r = smd_write(smd_ctl_devp->ctl_ch, smd_ctl_devp->tx_buf, count);
+ if (r != count) {
+ if (smd_ctl_devp->has_reset)
+ return -ENETRESET;
+
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "smd_write(ch,buf,count = %i) ret %i.\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ count,
+ r);
+ return r;
+ }
+
+ D(KERN_ERR "%s: just wrote %i bytes\n",
+ __func__, count);
+
+ return count;
+}
+
+static void ctl_work_func(struct work_struct *work)
+{
+ /* unsigned char buf[MAX_BUF_SIZE]; */
+ int sz;
+ struct smd_ctl_dev *smd_ctl_devp = container_of(work,
+ struct smd_ctl_dev,
+ ctl_work);
+
+ if (!smd_ctl_devp->ctl_ch)
+ return;
+
+ for (;;) {
+ sz = smd_cur_packet_size(smd_ctl_devp->ctl_ch);
+ if (sz == 0) {
+ D(KERN_ERR "%s: packet size is 0\n", __func__);
+ break;
+ }
+ if (sz > smd_read_avail(smd_ctl_devp->ctl_ch)) {
+ D(KERN_ERR "%s: packet size is %i - "
+ "the whole packet isn't here\n",
+ __func__, sz);
+ break;
+ }
+ if (sz > MAX_BUF_SIZE) {
+ smd_read(smd_ctl_devp->ctl_ch, 0, sz);
+ D(KERN_ERR "%s: packet size is %i - "
+ "greater than max %i, dropping\n",
+ __func__, sz, MAX_BUF_SIZE);
+ continue;
+ }
+
+ /* here we have a packet of size sz ready */
+
+ mutex_lock(&smd_ctl_devp->rx_lock);
+ smd_ctl_devp->bytes_read = sz;
+ mutex_unlock(&smd_ctl_devp->rx_lock);
+ wake_up_interruptible(&smd_ctl_devp->ctl_wait_queue);
+ D(KERN_ERR "%s: after wake_up\n", __func__);
+ break;
+ }
+}
+
+static void ctl_notify(void *priv, unsigned event)
+{
+ struct smd_ctl_dev *smd_ctl_devp = priv;
+
+ if (smd_ctl_devp->ctl_ch == 0)
+ return;
+
+ switch (event) {
+ case SMD_EVENT_DATA: {
+ int sz;
+ D(KERN_ERR "%s: data\n",
+ __func__);
+ sz = smd_cur_packet_size(smd_ctl_devp->ctl_ch);
+ D(KERN_ERR "%s: data sz = %i\n",
+ __func__, sz);
+ D(KERN_ERR "%s: smd_read_avail = %i\n",
+ __func__, smd_read_avail(smd_ctl_devp->ctl_ch));
+ if ((sz > 0) && (sz <= smd_read_avail(smd_ctl_devp->ctl_ch))) {
+ queue_work(smd_ctl_devp->ctl_wq,
+ &smd_ctl_devp->ctl_work);
+ D(KERN_ERR "%s: data just queued\n",
+ __func__);
+ }
+ D(KERN_ERR "%s: data after queueing\n",
+ __func__);
+ break;
+ }
+ case SMD_EVENT_OPEN:
+ D(KERN_ERR "%s: smd opened\n",
+ __func__);
+ smd_ctl_devp->is_open = 1;
+ wake_up_interruptible(&smd_ctl_devp->ctl_opened_wait_queue);
+ break;
+ case SMD_EVENT_CLOSE:
+ smd_ctl_devp->is_open = 0;
+ printk(KERN_ERR "%s: smd closed\n",
+ __func__);
+ break;
+ }
+}
+
+static char *smd_ctl_name[] = {
+ "DATA5_CNTL",
+ "DATA6_CNTL",
+ "DATA7_CNTL",
+};
+
+int smd_ctl_open(struct inode *inode, struct file *file)
+{
+ int r = 0;
+ struct smd_ctl_dev *smd_ctl_devp;
+
+ smd_ctl_devp = container_of(inode->i_cdev, struct smd_ctl_dev, cdev);
+
+ if (!smd_ctl_devp)
+ return -EINVAL;
+
+ file->private_data = smd_ctl_devp;
+
+ mutex_lock(&smd_ctl_devp->ctl_ch_lock);
+ if (smd_ctl_devp->ctl_ch == 0)
+ r = smd_open(smd_ctl_name[smd_ctl_devp->i],
+ &smd_ctl_devp->ctl_ch,
+ smd_ctl_devp,
+ ctl_notify);
+ mutex_unlock(&smd_ctl_devp->ctl_ch_lock);
+
+ return r;
+}
+
+int smd_ctl_release(struct inode *inode, struct file *file)
+{
+ int r = 0;
+ struct smd_ctl_dev *smd_ctl_devp = file->private_data;
+
+ if (!smd_ctl_devp)
+ return -EINVAL;
+
+ clean_and_signal(smd_ctl_devp);
+
+ mutex_lock(&smd_ctl_devp->ctl_ch_lock);
+ if (smd_ctl_devp->ctl_ch != 0) {
+ r = smd_close(smd_ctl_devp->ctl_ch);
+ smd_ctl_devp->ctl_ch = 0;
+ }
+ mutex_unlock(&smd_ctl_devp->ctl_ch_lock);
+
+ mutex_lock(&smd_ctl_devp->has_reset_lock);
+ smd_ctl_devp->has_reset = 0;
+ mutex_unlock(&smd_ctl_devp->has_reset_lock);
+
+ return r;
+}
+
+static const struct file_operations smd_ctl_fops = {
+ .owner = THIS_MODULE,
+ .open = smd_ctl_open,
+ .release = smd_ctl_release,
+ .read = smd_ctl_read,
+ .write = smd_ctl_write,
+ .ioctl = smd_ctl_ioctl,
+};
+
+static int __init smd_ctl_init(void)
+{
+ int i;
+ int r;
+ unsigned char buf[32];
+
+ r = alloc_chrdev_region(&smd_ctl_number,
+ 0,
+ NUM_SMD_CTL_PORTS,
+ DEVICE_NAME);
+ if (IS_ERR_VALUE(r)) {
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "alloc_chrdev_region() ret %i.\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r);
+ goto error0;
+ }
+
+ smd_ctl_classp = class_create(THIS_MODULE, DEVICE_NAME);
+ if (IS_ERR(smd_ctl_classp)) {
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "class_create() ENOMEM\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ r = -ENOMEM;
+ goto error1;
+ }
+
+ for (i = 0; i < NUM_SMD_CTL_PORTS; ++i) {
+ smd_ctl_devp[i] = kzalloc(sizeof(struct smd_ctl_dev),
+ GFP_KERNEL);
+ if (IS_ERR(smd_ctl_devp[i])) {
+ printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ r = -ENOMEM;
+ goto error2;
+ }
+
+ smd_ctl_devp[i]->i = i;
+
+ scnprintf(buf, 32, "ctl%i", i);
+ smd_ctl_devp[i]->ctl_wq = create_singlethread_workqueue(buf);
+ if (&smd_ctl_devp[i]->ctl_wq == 0) {
+ printk(KERN_ERR
+ "%s:%i:%s: "
+ "create_singlethread_workqueue() ret 0\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ r = -ENOMEM;
+ goto error2;
+ }
+
+ init_waitqueue_head(&smd_ctl_devp[i]->ctl_wait_queue);
+ smd_ctl_devp[i]->is_open = 0;
+ init_waitqueue_head(&smd_ctl_devp[i]->ctl_opened_wait_queue);
+ INIT_WORK(&smd_ctl_devp[i]->ctl_work,
+ ctl_work_func);
+
+ mutex_init(&smd_ctl_devp[i]->ctl_ch_lock);
+ mutex_init(&smd_ctl_devp[i]->rx_lock);
+ mutex_init(&smd_ctl_devp[i]->is_open_lock);
+
+ cdev_init(&smd_ctl_devp[i]->cdev, &smd_ctl_fops);
+ smd_ctl_devp[i]->cdev.owner = THIS_MODULE;
+
+ r = cdev_add(&smd_ctl_devp[i]->cdev,
+ (smd_ctl_number + i),
+ 1);
+
+ if (IS_ERR_VALUE(r)) {
+ printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r);
+ destroy_workqueue(smd_ctl_devp[i]->ctl_wq);
+ kfree(smd_ctl_devp[i]);
+ goto error2;
+ }
+
+ smd_ctl_devp[i]->devicep =
+ device_create(smd_ctl_classp,
+ NULL,
+ (smd_ctl_number + i),
+ NULL,
+ DEVICE_NAME "%d",
+ i);
+
+ if (IS_ERR(smd_ctl_devp[i]->devicep)) {
+ printk(KERN_ERR "%s:%i:%s: "
+ "device_create() ENOMEM\n",
+ __FILE__,
+ __LINE__,
+ __func__);
+ r = -ENOMEM;
+ cdev_del(&smd_ctl_devp[i]->cdev);
+ destroy_workqueue(smd_ctl_devp[i]->ctl_wq);
+ kfree(smd_ctl_devp[i]);
+ goto error2;
+ }
+
+ smd_ctl_devp[i]->nb.notifier_call = modem_notifier;
+ modem_register_notifier(&smd_ctl_devp[i]->nb);
+ mutex_init(&smd_ctl_devp[i]->has_reset_lock);
+
+ }
+
+ printk(KERN_INFO "SMD Control Port Driver Initialized.\n");
+ return 0;
+
+ error2:
+ if (i > 0) {
+ while (--i >= 0) {
+ cdev_del(&smd_ctl_devp[i]->cdev);
+ destroy_workqueue(smd_ctl_devp[i]->ctl_wq);
+ kfree(smd_ctl_devp[i]);
+ device_destroy(smd_ctl_classp,
+ MKDEV(MAJOR(smd_ctl_number), i));
+ }
+ }
+
+ class_destroy(smd_ctl_classp);
+ error1:
+ unregister_chrdev_region(MAJOR(smd_ctl_number), NUM_SMD_CTL_PORTS);
+ error0:
+ return r;
+}
+
+static void __exit smd_ctl_cleanup(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_SMD_CTL_PORTS; ++i) {
+ modem_unregister_notifier(&smd_ctl_devp[i]->nb);
+ cdev_del(&smd_ctl_devp[i]->cdev);
+ kfree(smd_ctl_devp[i]);
+ device_destroy(smd_ctl_classp,
+ MKDEV(MAJOR(smd_ctl_number), i));
+ }
+
+ class_destroy(smd_ctl_classp);
+
+ unregister_chrdev_region(MAJOR(smd_ctl_number), NUM_SMD_CTL_PORTS);
+}
+
+module_init(smd_ctl_init);
+module_exit(smd_ctl_cleanup);
+
+MODULE_DESCRIPTION("MSM Shared Memory Control Port");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd_nmea.c b/arch/arm/mach-msm/smd_nmea.c
new file mode 100644
index 000000000000..35e1cbdca1e6
--- /dev/null
+++ b/arch/arm/mach-msm/smd_nmea.c
@@ -0,0 +1,249 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * SMD NMEA Driver -- Provides GPS NMEA device to SMD port interface.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+
+#include <mach/msm_smd.h>
+
+#define MAX_BUF_SIZE 200
+
+static DEFINE_MUTEX(nmea_ch_lock);
+static DEFINE_MUTEX(nmea_rx_buf_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(nmea_wait_queue);
+
+struct nmea_device_t {
+ struct miscdevice misc;
+
+ struct smd_channel *ch;
+
+ unsigned char rx_buf[MAX_BUF_SIZE];
+ unsigned int bytes_read;
+};
+
+struct nmea_device_t *nmea_devp;
+
+static void nmea_work_func(struct work_struct *ws)
+{
+ int sz;
+
+ for (;;) {
+ sz = smd_cur_packet_size(nmea_devp->ch);
+ if (sz == 0)
+ break;
+ if (sz > smd_read_avail(nmea_devp->ch))
+ break;
+ if (sz > MAX_BUF_SIZE) {
+ smd_read(nmea_devp->ch, 0, sz);
+ continue;
+ }
+
+ mutex_lock(&nmea_rx_buf_lock);
+ if (smd_read(nmea_devp->ch, nmea_devp->rx_buf, sz) != sz) {
+ mutex_unlock(&nmea_rx_buf_lock);
+ printk(KERN_ERR "nmea: not enough data?!\n");
+ continue;
+ }
+ nmea_devp->bytes_read = sz;
+ mutex_unlock(&nmea_rx_buf_lock);
+ wake_up_interruptible(&nmea_wait_queue);
+ }
+}
+
+struct workqueue_struct *nmea_wq;
+static DECLARE_WORK(nmea_work, nmea_work_func);
+
+static void nmea_notify(void *priv, unsigned event)
+{
+ switch (event) {
+ case SMD_EVENT_DATA: {
+ int sz;
+ sz = smd_cur_packet_size(nmea_devp->ch);
+ if ((sz > 0) && (sz <= smd_read_avail(nmea_devp->ch)))
+ queue_work(nmea_wq, &nmea_work);
+ break;
+ }
+ case SMD_EVENT_OPEN:
+ printk(KERN_INFO "nmea: smd opened\n");
+ break;
+ case SMD_EVENT_CLOSE:
+ printk(KERN_INFO "nmea: smd closed\n");
+ break;
+ }
+}
+
+static ssize_t nmea_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int r;
+ int bytes_read;
+
+ r = wait_event_interruptible(nmea_wait_queue,
+ nmea_devp->bytes_read);
+ if (r < 0) {
+ /* qualify error message */
+ if (r != -ERESTARTSYS) {
+ /* we get this anytime a signal comes in */
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "wait_event_interruptible ret %i\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r
+ );
+ }
+ return r;
+ }
+
+ mutex_lock(&nmea_rx_buf_lock);
+ bytes_read = nmea_devp->bytes_read;
+ nmea_devp->bytes_read = 0;
+ r = copy_to_user(buf, nmea_devp->rx_buf, bytes_read);
+ mutex_unlock(&nmea_rx_buf_lock);
+
+ if (r > 0) {
+ printk(KERN_ERR "ERROR:%s:%i:%s: "
+ "copy_to_user could not copy %i bytes.\n",
+ __FILE__,
+ __LINE__,
+ __func__,
+ r);
+ return r;
+ }
+
+ return bytes_read;
+}
+
+static int nmea_open(struct inode *ip, struct file *fp)
+{
+ int r = 0;
+
+ mutex_lock(&nmea_ch_lock);
+ if (nmea_devp->ch == 0)
+ r = smd_open("GPSNMEA", &nmea_devp->ch, nmea_devp, nmea_notify);
+ mutex_unlock(&nmea_ch_lock);
+
+ return r;
+}
+
+static int nmea_release(struct inode *ip, struct file *fp)
+{
+ int r = 0;
+
+ mutex_lock(&nmea_ch_lock);
+ if (nmea_devp->ch != 0) {
+ r = smd_close(nmea_devp->ch);
+ nmea_devp->ch = 0;
+ }
+ mutex_unlock(&nmea_ch_lock);
+
+ return r;
+}
+
+static const struct file_operations nmea_fops = {
+ .owner = THIS_MODULE,
+ .read = nmea_read,
+ .open = nmea_open,
+ .release = nmea_release,
+};
+
+static struct nmea_device_t nmea_device = {
+ .misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "nmea",
+ .fops = &nmea_fops,
+ }
+};
+
+static void __exit nmea_exit(void)
+{
+ destroy_workqueue(nmea_wq);
+ misc_deregister(&nmea_device.misc);
+}
+
+static int __init nmea_init(void)
+{
+ int ret;
+
+ nmea_device.bytes_read = 0;
+ nmea_devp = &nmea_device;
+
+ nmea_wq = create_singlethread_workqueue("nmea");
+ if (nmea_wq == 0)
+ return -ENOMEM;
+
+ ret = misc_register(&nmea_device.misc);
+ return ret;
+}
+
+module_init(nmea_init);
+module_exit(nmea_exit);
+
+MODULE_DESCRIPTION("MSM Shared Memory NMEA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
new file mode 100644
index 000000000000..3dec5d8ef794
--- /dev/null
+++ b/arch/arm/mach-msm/smd_private.h
@@ -0,0 +1,256 @@
+/* arch/arm/mach-msm/smd_private.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, 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.
+ *
+ */
+#ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
+#define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
+
+struct smem_heap_info
+{
+ unsigned initialized;
+ unsigned free_offset;
+ unsigned heap_remaining;
+ unsigned reserved;
+};
+
+struct smem_heap_entry
+{
+ unsigned allocated;
+ unsigned offset;
+ unsigned size;
+ unsigned reserved;
+};
+
+struct smem_proc_comm
+{
+ unsigned command;
+ unsigned status;
+ unsigned data1;
+ unsigned data2;
+};
+
+#define PC_APPS 0
+#define PC_MODEM 1
+
+#define VERSION_QDSP6 4
+#define VERSION_APPS_SBL 6
+#define VERSION_MODEM_SBL 7
+#define VERSION_APPS 8
+#define VERSION_MODEM 9
+
+#define SMD_HEAP_SIZE 512
+
+struct smem_shared
+{
+ struct smem_proc_comm proc_comm[4];
+ unsigned version[32];
+ struct smem_heap_info heap_info;
+ struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
+};
+
+#if defined(CONFIG_MSM_SMD_PKG4)
+struct smsm_interrupt_info {
+ uint32_t aArm_en_mask;
+ uint32_t aArm_interrupts_pending;
+ uint32_t aArm_wakeup_reason;
+ uint32_t aArm_rpc_prog;
+ uint32_t aArm_rpc_proc;
+ char aArm_smd_port_name[20];
+ uint32_t aArm_gpio_info;
+};
+#elif defined(CONFIG_MSM_SMD_PKG3)
+struct smsm_interrupt_info {
+ uint32_t aArm_en_mask;
+ uint32_t aArm_interrupts_pending;
+ uint32_t aArm_wakeup_reason;
+};
+#else
+#error No SMD Package Specified; aborting
+#endif
+
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+enum {
+ SMSM_APPS_STATE,
+ SMSM_MODEM_STATE,
+ SMSM_Q6_STATE,
+ SMSM_APPS_DEM,
+ SMSM_MODEM_DEM,
+ SMSM_Q6_DEM,
+ SMSM_POWER_MASTER_DEM,
+ SMSM_TIME_MASTER_DEM,
+ SMSM_NUM_ENTRIES,
+};
+#else
+enum {
+ SMSM_APPS_STATE = 1,
+ SMSM_MODEM_STATE = 3,
+ SMSM_NUM_ENTRIES,
+};
+#endif
+
+enum {
+ SMSM_APPS,
+ SMSM_MODEM,
+ SMSM_Q6,
+ SMSM_NUM_HOSTS,
+};
+
+#define SZ_DIAG_ERR_MSG 0xC8
+#define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE
+#define ID_SMD_CHANNELS SMEM_SMD_BASE_ID
+#define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE
+#define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL
+
+#define SMSM_INIT 0x00000001
+#define SMSM_OSENTERED 0x00000002
+#define SMSM_SMDWAIT 0x00000004
+#define SMSM_SMDINIT 0x00000008
+#define SMSM_RPCWAIT 0x00000010
+#define SMSM_RPCINIT 0x00000020
+#define SMSM_RESET 0x00000040
+#define SMSM_RSA 0x00000080
+#define SMSM_RUN 0x00000100
+#define SMSM_PWRC 0x00000200
+#define SMSM_TIMEWAIT 0x00000400
+#define SMSM_TIMEINIT 0x00000800
+#define SMSM_PWRC_EARLY_EXIT 0x00001000
+#define SMSM_WFPI 0x00002000
+#define SMSM_SLEEP 0x00004000
+#define SMSM_SLEEPEXIT 0x00008000
+#define SMSM_OEMSBL_RELEASE 0x00010000
+#define SMSM_APPS_REBOOT 0x00020000
+#define SMSM_SYSTEM_POWER_DOWN 0x00040000
+#define SMSM_SYSTEM_REBOOT 0x00080000
+#define SMSM_SYSTEM_DOWNLOAD 0x00100000
+#define SMSM_PWRC_SUSPEND 0x00200000
+#define SMSM_APPS_SHUTDOWN 0x00400000
+#define SMSM_SMD_LOOPBACK 0x00800000
+#define SMSM_RUN_QUIET 0x01000000
+#define SMSM_MODEM_WAIT 0x02000000
+#define SMSM_MODEM_BREAK 0x04000000
+#define SMSM_MODEM_CONTINUE 0x08000000
+#define SMSM_UNKNOWN 0x80000000
+
+#define SMSM_WKUP_REASON_RPC 0x00000001
+#define SMSM_WKUP_REASON_INT 0x00000002
+#define SMSM_WKUP_REASON_GPIO 0x00000004
+#define SMSM_WKUP_REASON_TIMER 0x00000008
+#define SMSM_WKUP_REASON_ALARM 0x00000010
+#define SMSM_WKUP_REASON_RESET 0x00000020
+
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_get_entry(unsigned id, unsigned *size);
+int smsm_change_state(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask);
+int smsm_change_intr_mask(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask);
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
+uint32_t smsm_get_state(uint32_t smsm_entry);
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+ uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void smsm_reset_modem(unsigned mode);
+void smsm_reset_modem_cont(void);
+void smd_sleep_exit(void);
+
+#define SMEM_NUM_SMD_STREAM_CHANNELS 64
+#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
+
+enum {
+ /* fixed items */
+ SMEM_PROC_COMM = 0,
+ SMEM_HEAP_INFO,
+ SMEM_ALLOCATION_TABLE,
+ SMEM_VERSION_INFO,
+ SMEM_HW_RESET_DETECT,
+ SMEM_AARM_WARM_BOOT,
+ SMEM_DIAG_ERR_MESSAGE,
+ SMEM_SPINLOCK_ARRAY,
+ SMEM_MEMORY_BARRIER_LOCATION,
+
+ /* dynamic items */
+ SMEM_AARM_PARTITION_TABLE,
+ SMEM_AARM_BAD_BLOCK_TABLE,
+ SMEM_RESERVE_BAD_BLOCKS,
+ SMEM_WM_UUID,
+ SMEM_CHANNEL_ALLOC_TBL,
+ SMEM_SMD_BASE_ID,
+ SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_SMEM_LOG_EVENTS,
+ SMEM_SMEM_STATIC_LOG_IDX,
+ SMEM_SMEM_STATIC_LOG_EVENTS,
+ SMEM_SMEM_SLOW_CLOCK_SYNC,
+ SMEM_SMEM_SLOW_CLOCK_VALUE,
+ SMEM_BIO_LED_BUF,
+ SMEM_SMSM_SHARED_STATE,
+ SMEM_SMSM_INT_INFO,
+ SMEM_SMSM_SLEEP_DELAY,
+ SMEM_SMSM_LIMIT_SLEEP,
+ SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
+ SMEM_KEYPAD_KEYS_PRESSED,
+ SMEM_KEYPAD_STATE_UPDATED,
+ SMEM_KEYPAD_STATE_IDX,
+ SMEM_GPIO_INT,
+ SMEM_MDDI_LCD_IDX,
+ SMEM_MDDI_HOST_DRIVER_STATE,
+ SMEM_MDDI_LCD_DISP_STATE,
+ SMEM_LCD_CUR_PANEL,
+ SMEM_MARM_BOOT_SEGMENT_INFO,
+ SMEM_AARM_BOOT_SEGMENT_INFO,
+ SMEM_SLEEP_STATIC,
+ SMEM_SCORPION_FREQUENCY,
+ SMEM_SMD_PROFILES,
+ SMEM_TSSC_BUSY,
+ SMEM_HS_SUSPEND_FILTER_INFO,
+ SMEM_BATT_INFO,
+ SMEM_APPS_BOOT_MODE,
+ SMEM_VERSION_FIRST,
+ SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
+ SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
+ SMEM_OSS_RRCASN1_BUF1,
+ SMEM_OSS_RRCASN1_BUF2,
+ SMEM_ID_VENDOR0,
+ SMEM_ID_VENDOR1,
+ SMEM_ID_VENDOR2,
+ SMEM_HW_SW_BUILD_ID,
+ SMEM_SMD_BLOCK_PORT_BASE_ID,
+ SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SCLK_CONVERSION,
+ SMEM_SMD_SMSM_INTR_MUX,
+ SMEM_SMSM_CPU_INTR_MASK,
+ SMEM_APPS_DEM_SLAVE_DATA,
+ SMEM_QDSP6_DEM_SLAVE_DATA,
+ SMEM_CLKREGIM_BSP,
+ SMEM_CLKREGIM_SOURCES,
+ SMEM_SMD_FIFO_BASE_ID,
+ SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
+ SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_POWER_ON_STATUS_INFO,
+ SMEM_DAL_AREA,
+ SMEM_SMEM_LOG_POWER_IDX,
+ SMEM_SMEM_LOG_POWER_WRAP,
+ SMEM_SMEM_LOG_POWER_EVENTS,
+ SMEM_ERR_CRASH_LOG,
+ SMEM_ERR_F3_TRACE_LOG,
+ SMEM_SMD_BRIDGE_ALLOC_TABLE,
+ SMEM_SMDLITE_TABLE,
+ SMEM_SD_IMG_UPGRADE_STATUS,
+ SMEM_NUM_ITEMS,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/smd_qmi.c b/arch/arm/mach-msm/smd_qmi.c
new file mode 100644
index 000000000000..e6ae979d8df8
--- /dev/null
+++ b/arch/arm/mach-msm/smd_qmi.c
@@ -0,0 +1,844 @@
+/* arch/arm/mach-msm/smd_qmi.c
+ *
+ * QMI Control Driver -- Manages network data connections.
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/workqueue.h>
+
+#include <asm/uaccess.h>
+#include <mach/msm_smd.h>
+
+#define QMI_CTL 0x00
+#define QMI_WDS 0x01
+#define QMI_DMS 0x02
+#define QMI_NAS 0x03
+
+#define QMI_RESULT_SUCCESS 0x0000
+#define QMI_RESULT_FAILURE 0x0001
+
+struct qmi_msg {
+ unsigned char service;
+ unsigned char client_id;
+ unsigned short txn_id;
+ unsigned short type;
+ unsigned short size;
+ unsigned char *tlv;
+};
+
+#define qmi_ctl_client_id 0
+
+#define STATE_OFFLINE 0
+#define STATE_QUERYING 1
+#define STATE_ONLINE 2
+
+struct qmi_ctxt {
+ struct miscdevice misc;
+
+ struct mutex lock;
+
+ unsigned char ctl_txn_id;
+ unsigned char wds_client_id;
+ unsigned short wds_txn_id;
+
+ unsigned wds_busy;
+ unsigned wds_handle;
+ unsigned state_dirty;
+ unsigned state;
+
+ unsigned char addr[4];
+ unsigned char mask[4];
+ unsigned char gateway[4];
+ unsigned char dns1[4];
+ unsigned char dns2[4];
+
+ smd_channel_t *ch;
+ const char *ch_name;
+
+ struct work_struct open_work;
+ struct work_struct read_work;
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n);
+
+static void qmi_read_work(struct work_struct *ws);
+static void qmi_open_work(struct work_struct *work);
+
+void qmi_ctxt_init(struct qmi_ctxt *ctxt, unsigned n)
+{
+ mutex_init(&ctxt->lock);
+ INIT_WORK(&ctxt->read_work, qmi_read_work);
+ INIT_WORK(&ctxt->open_work, qmi_open_work);
+ ctxt->ctl_txn_id = 1;
+ ctxt->wds_txn_id = 1;
+ ctxt->wds_busy = 1;
+ ctxt->state = STATE_OFFLINE;
+
+}
+
+static struct workqueue_struct *qmi_wq;
+
+static int verbose = 0;
+
+/* anyone waiting for a state change waits here */
+static DECLARE_WAIT_QUEUE_HEAD(qmi_wait_queue);
+
+
+static void qmi_dump_msg(struct qmi_msg *msg, const char *prefix)
+{
+ unsigned sz, n;
+ unsigned char *x;
+
+ if (!verbose)
+ return;
+
+ printk(KERN_INFO
+ "qmi: %s: svc=%02x cid=%02x tid=%04x type=%04x size=%04x\n",
+ prefix, msg->service, msg->client_id,
+ msg->txn_id, msg->type, msg->size);
+
+ x = msg->tlv;
+ sz = msg->size;
+
+ while (sz >= 3) {
+ sz -= 3;
+
+ n = x[1] | (x[2] << 8);
+ if (n > sz)
+ break;
+
+ printk(KERN_INFO "qmi: %s: tlv: %02x %04x { ",
+ prefix, x[0], n);
+ x += 3;
+ sz -= n;
+ while (n-- > 0)
+ printk("%02x ", *x++);
+ printk("}\n");
+ }
+}
+
+int qmi_add_tlv(struct qmi_msg *msg,
+ unsigned type, unsigned size, const void *data)
+{
+ unsigned char *x = msg->tlv + msg->size;
+
+ x[0] = type;
+ x[1] = size;
+ x[2] = size >> 8;
+
+ memcpy(x + 3, data, size);
+
+ msg->size += (size + 3);
+
+ return 0;
+}
+
+/* Extract a tagged item from a qmi message buffer,
+** taking care not to overrun the buffer.
+*/
+static int qmi_get_tlv(struct qmi_msg *msg,
+ unsigned type, unsigned size, void *data)
+{
+ unsigned char *x = msg->tlv;
+ unsigned len = msg->size;
+ unsigned n;
+
+ while (len >= 3) {
+ len -= 3;
+
+ /* size of this item */
+ n = x[1] | (x[2] << 8);
+ if (n > len)
+ break;
+
+ if (x[0] == type) {
+ if (n != size)
+ return -1;
+ memcpy(data, x + 3, size);
+ return 0;
+ }
+
+ x += (n + 3);
+ len -= n;
+ }
+
+ return -1;
+}
+
+static unsigned qmi_get_status(struct qmi_msg *msg, unsigned *error)
+{
+ unsigned short status[2];
+ if (qmi_get_tlv(msg, 0x02, sizeof(status), status)) {
+ *error = 0;
+ return QMI_RESULT_FAILURE;
+ } else {
+ *error = status[1];
+ return status[0];
+ }
+}
+
+/* 0x01 <qmux-header> <payload> */
+#define QMUX_HEADER 13
+
+/* should be >= HEADER + FOOTER */
+#define QMUX_OVERHEAD 16
+
+static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+ unsigned char *data;
+ unsigned hlen;
+ unsigned len;
+ int r;
+
+ qmi_dump_msg(msg, "send");
+
+ if (msg->service == QMI_CTL) {
+ hlen = QMUX_HEADER - 1;
+ } else {
+ hlen = QMUX_HEADER;
+ }
+
+ /* QMUX length is total header + total payload - IFC selector */
+ len = hlen + msg->size - 1;
+ if (len > 0xffff)
+ return -1;
+
+ data = msg->tlv - hlen;
+
+ /* prepend encap and qmux header */
+ *data++ = 0x01; /* ifc selector */
+
+ /* qmux header */
+ *data++ = len;
+ *data++ = len >> 8;
+ *data++ = 0x00; /* flags: client */
+ *data++ = msg->service;
+ *data++ = msg->client_id;
+
+ /* qmi header */
+ *data++ = 0x00; /* flags: send */
+ *data++ = msg->txn_id;
+ if (msg->service != QMI_CTL)
+ *data++ = msg->txn_id >> 8;
+
+ *data++ = msg->type;
+ *data++ = msg->type >> 8;
+ *data++ = msg->size;
+ *data++ = msg->size >> 8;
+
+ /* len + 1 takes the interface selector into account */
+ r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);
+
+ if (r != len) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static void qmi_process_ctl_msg(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+ unsigned err;
+ if (msg->type == 0x0022) {
+ unsigned char n[2];
+ if (qmi_get_status(msg, &err))
+ return;
+ if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+ return;
+ if (n[0] == QMI_WDS) {
+ printk(KERN_INFO
+ "qmi: ctl: wds use client_id 0x%02x\n", n[1]);
+ ctxt->wds_client_id = n[1];
+ ctxt->wds_busy = 0;
+ }
+ }
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt);
+
+static void swapaddr(unsigned char *src, unsigned char *dst)
+{
+ dst[0] = src[3];
+ dst[1] = src[2];
+ dst[2] = src[1];
+ dst[3] = src[0];
+}
+
+static unsigned char zero[4];
+static void qmi_read_runtime_profile(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
+{
+ unsigned char tmp[4];
+ unsigned r;
+
+ r = qmi_get_tlv(msg, 0x1e, 4, tmp);
+ swapaddr(r ? zero : tmp, ctxt->addr);
+ r = qmi_get_tlv(msg, 0x21, 4, tmp);
+ swapaddr(r ? zero : tmp, ctxt->mask);
+ r = qmi_get_tlv(msg, 0x20, 4, tmp);
+ swapaddr(r ? zero : tmp, ctxt->gateway);
+ r = qmi_get_tlv(msg, 0x15, 4, tmp);
+ swapaddr(r ? zero : tmp, ctxt->dns1);
+ r = qmi_get_tlv(msg, 0x16, 4, tmp);
+ swapaddr(r ? zero : tmp, ctxt->dns2);
+}
+
+static void qmi_process_unicast_wds_msg(struct qmi_ctxt *ctxt,
+ struct qmi_msg *msg)
+{
+ unsigned err;
+ switch (msg->type) {
+ case 0x0021:
+ if (qmi_get_status(msg, &err)) {
+ printk(KERN_ERR
+ "qmi: wds: network stop failed (%04x)\n", err);
+ } else {
+ printk(KERN_INFO
+ "qmi: wds: network stopped\n");
+ ctxt->state = STATE_OFFLINE;
+ ctxt->state_dirty = 1;
+ }
+ break;
+ case 0x0020:
+ if (qmi_get_status(msg, &err)) {
+ printk(KERN_ERR
+ "qmi: wds: network start failed (%04x)\n", err);
+ } else if (qmi_get_tlv(msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle)) {
+ printk(KERN_INFO
+ "qmi: wds no handle?\n");
+ } else {
+ printk(KERN_INFO
+ "qmi: wds: got handle 0x%08x\n",
+ ctxt->wds_handle);
+ }
+ break;
+ case 0x002D:
+ printk("qmi: got network profile\n");
+ if (ctxt->state == STATE_QUERYING) {
+ qmi_read_runtime_profile(ctxt, msg);
+ ctxt->state = STATE_ONLINE;
+ ctxt->state_dirty = 1;
+ }
+ break;
+ default:
+ printk(KERN_ERR "qmi: unknown msg type 0x%04x\n", msg->type);
+ }
+ ctxt->wds_busy = 0;
+}
+
+static void qmi_process_broadcast_wds_msg(struct qmi_ctxt *ctxt,
+ struct qmi_msg *msg)
+{
+ if (msg->type == 0x0022) {
+ unsigned char n[2];
+ if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
+ return;
+ switch (n[0]) {
+ case 1:
+ printk(KERN_INFO "qmi: wds: DISCONNECTED\n");
+ ctxt->state = STATE_OFFLINE;
+ ctxt->state_dirty = 1;
+ break;
+ case 2:
+ printk(KERN_INFO "qmi: wds: CONNECTED\n");
+ ctxt->state = STATE_QUERYING;
+ ctxt->state_dirty = 1;
+ qmi_network_get_profile(ctxt);
+ break;
+ case 3:
+ printk(KERN_INFO "qmi: wds: SUSPENDED\n");
+ ctxt->state = STATE_OFFLINE;
+ ctxt->state_dirty = 1;
+ }
+ } else {
+ printk(KERN_ERR "qmi: unknown bcast msg type 0x%04x\n", msg->type);
+ }
+}
+
+static void qmi_process_wds_msg(struct qmi_ctxt *ctxt,
+ struct qmi_msg *msg)
+{
+ printk("wds: %04x @ %02x\n", msg->type, msg->client_id);
+ if (msg->client_id == ctxt->wds_client_id) {
+ qmi_process_unicast_wds_msg(ctxt, msg);
+ } else if (msg->client_id == 0xff) {
+ qmi_process_broadcast_wds_msg(ctxt, msg);
+ } else {
+ printk(KERN_ERR
+ "qmi_process_wds_msg client id 0x%02x unknown\n",
+ msg->client_id);
+ }
+}
+
+static void qmi_process_qmux(struct qmi_ctxt *ctxt,
+ unsigned char *buf, unsigned sz)
+{
+ struct qmi_msg msg;
+
+ /* require a full header */
+ if (sz < 5)
+ return;
+
+ /* require a size that matches the buffer size */
+ if (sz != (buf[0] | (buf[1] << 8)))
+ return;
+
+ /* only messages from a service (bit7=1) are allowed */
+ if (buf[2] != 0x80)
+ return;
+
+ msg.service = buf[3];
+ msg.client_id = buf[4];
+
+ /* annoyingly, CTL messages have a shorter TID */
+ if (buf[3] == 0) {
+ if (sz < 7)
+ return;
+ msg.txn_id = buf[6];
+ buf += 7;
+ sz -= 7;
+ } else {
+ if (sz < 8)
+ return;
+ msg.txn_id = buf[6] | (buf[7] << 8);
+ buf += 8;
+ sz -= 8;
+ }
+
+ /* no type and size!? */
+ if (sz < 4)
+ return;
+ sz -= 4;
+
+ msg.type = buf[0] | (buf[1] << 8);
+ msg.size = buf[2] | (buf[3] << 8);
+ msg.tlv = buf + 4;
+
+ if (sz != msg.size)
+ return;
+
+ qmi_dump_msg(&msg, "recv");
+
+ mutex_lock(&ctxt->lock);
+ switch (msg.service) {
+ case QMI_CTL:
+ qmi_process_ctl_msg(ctxt, &msg);
+ break;
+ case QMI_WDS:
+ qmi_process_wds_msg(ctxt, &msg);
+ break;
+ default:
+ printk(KERN_ERR "qmi: msg from unknown svc 0x%02x\n",
+ msg.service);
+ break;
+ }
+ mutex_unlock(&ctxt->lock);
+
+ wake_up(&qmi_wait_queue);
+}
+
+#define QMI_MAX_PACKET (256 + QMUX_OVERHEAD)
+
+static void qmi_read_work(struct work_struct *ws)
+{
+ struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, read_work);
+ struct smd_channel *ch = ctxt->ch;
+ unsigned char buf[QMI_MAX_PACKET];
+ int sz;
+
+ for (;;) {
+ sz = smd_cur_packet_size(ch);
+ if (sz == 0)
+ break;
+ if (sz < smd_read_avail(ch))
+ break;
+ if (sz > QMI_MAX_PACKET) {
+ smd_read(ch, 0, sz);
+ continue;
+ }
+ if (smd_read(ch, buf, sz) != sz) {
+ printk(KERN_ERR "qmi: not enough data?!\n");
+ continue;
+ }
+
+ /* interface selector must be 1 */
+ if (buf[0] != 0x01)
+ continue;
+
+ qmi_process_qmux(ctxt, buf + 1, sz - 1);
+ }
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt);
+
+static void qmi_open_work(struct work_struct *ws)
+{
+ struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, open_work);
+ mutex_lock(&ctxt->lock);
+ qmi_request_wds_cid(ctxt);
+ mutex_unlock(&ctxt->lock);
+}
+
+static void qmi_notify(void *priv, unsigned event)
+{
+ struct qmi_ctxt *ctxt = priv;
+
+ switch (event) {
+ case SMD_EVENT_DATA: {
+ int sz;
+ sz = smd_cur_packet_size(ctxt->ch);
+ if ((sz > 0) && (sz <= smd_read_avail(ctxt->ch))) {
+ queue_work(qmi_wq, &ctxt->read_work);
+ }
+ break;
+ }
+ case SMD_EVENT_OPEN:
+ printk(KERN_INFO "qmi: smd opened\n");
+ queue_work(qmi_wq, &ctxt->open_work);
+ break;
+ case SMD_EVENT_CLOSE:
+ printk(KERN_INFO "qmi: smd closed\n");
+ break;
+ }
+}
+
+static int qmi_request_wds_cid(struct qmi_ctxt *ctxt)
+{
+ unsigned char data[64 + QMUX_OVERHEAD];
+ struct qmi_msg msg;
+ unsigned char n;
+
+ msg.service = QMI_CTL;
+ msg.client_id = qmi_ctl_client_id;
+ msg.txn_id = ctxt->ctl_txn_id;
+ msg.type = 0x0022;
+ msg.size = 0;
+ msg.tlv = data + QMUX_HEADER;
+
+ ctxt->ctl_txn_id += 2;
+
+ n = QMI_WDS;
+ qmi_add_tlv(&msg, 0x01, 0x01, &n);
+
+ return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_get_profile(struct qmi_ctxt *ctxt)
+{
+ unsigned char data[96 + QMUX_OVERHEAD];
+ struct qmi_msg msg;
+
+ msg.service = QMI_WDS;
+ msg.client_id = ctxt->wds_client_id;
+ msg.txn_id = ctxt->wds_txn_id;
+ msg.type = 0x002D;
+ msg.size = 0;
+ msg.tlv = data + QMUX_HEADER;
+
+ ctxt->wds_txn_id += 2;
+
+ return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_up(struct qmi_ctxt *ctxt, char *apn)
+{
+ unsigned char data[96 + QMUX_OVERHEAD];
+ struct qmi_msg msg;
+ char *user;
+ char *pass;
+
+ for (user = apn; *user; user++) {
+ if (*user == ' ') {
+ *user++ = 0;
+ break;
+ }
+ }
+ for (pass = user; *pass; pass++) {
+ if (*pass == ' ') {
+ *pass++ = 0;
+ break;
+ }
+ }
+
+ msg.service = QMI_WDS;
+ msg.client_id = ctxt->wds_client_id;
+ msg.txn_id = ctxt->wds_txn_id;
+ msg.type = 0x0020;
+ msg.size = 0;
+ msg.tlv = data + QMUX_HEADER;
+
+ ctxt->wds_txn_id += 2;
+
+ qmi_add_tlv(&msg, 0x14, strlen(apn), apn);
+ if (*user) {
+ unsigned char x;
+ x = 3;
+ qmi_add_tlv(&msg, 0x16, 1, &x);
+ qmi_add_tlv(&msg, 0x17, strlen(user), user);
+ if (*pass)
+ qmi_add_tlv(&msg, 0x18, strlen(pass), pass);
+ }
+ return qmi_send(ctxt, &msg);
+}
+
+static int qmi_network_down(struct qmi_ctxt *ctxt)
+{
+ unsigned char data[16 + QMUX_OVERHEAD];
+ struct qmi_msg msg;
+
+ msg.service = QMI_WDS;
+ msg.client_id = ctxt->wds_client_id;
+ msg.txn_id = ctxt->wds_txn_id;
+ msg.type = 0x0021;
+ msg.size = 0;
+ msg.tlv = data + QMUX_HEADER;
+
+ ctxt->wds_txn_id += 2;
+
+ qmi_add_tlv(&msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle);
+
+ return qmi_send(ctxt, &msg);
+}
+
+static int qmi_print_state(struct qmi_ctxt *ctxt, char *buf, int max)
+{
+ int i;
+ char *statename;
+
+ if (ctxt->state == STATE_ONLINE) {
+ statename = "up";
+ } else if (ctxt->state == STATE_OFFLINE) {
+ statename = "down";
+ } else {
+ statename = "busy";
+ }
+
+ i = scnprintf(buf, max, "STATE=%s\n", statename);
+ i += scnprintf(buf + i, max - i, "CID=%d\n",ctxt->wds_client_id);
+
+ if (ctxt->state != STATE_ONLINE){
+ return i;
+ }
+
+ i += scnprintf(buf + i, max - i, "ADDR=%d.%d.%d.%d\n",
+ ctxt->addr[0], ctxt->addr[1], ctxt->addr[2], ctxt->addr[3]);
+ i += scnprintf(buf + i, max - i, "MASK=%d.%d.%d.%d\n",
+ ctxt->mask[0], ctxt->mask[1], ctxt->mask[2], ctxt->mask[3]);
+ i += scnprintf(buf + i, max - i, "GATEWAY=%d.%d.%d.%d\n",
+ ctxt->gateway[0], ctxt->gateway[1], ctxt->gateway[2],
+ ctxt->gateway[3]);
+ i += scnprintf(buf + i, max - i, "DNS1=%d.%d.%d.%d\n",
+ ctxt->dns1[0], ctxt->dns1[1], ctxt->dns1[2], ctxt->dns1[3]);
+ i += scnprintf(buf + i, max - i, "DNS2=%d.%d.%d.%d\n",
+ ctxt->dns2[0], ctxt->dns2[1], ctxt->dns2[2], ctxt->dns2[3]);
+
+ return i;
+}
+
+static ssize_t qmi_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct qmi_ctxt *ctxt = fp->private_data;
+ char msg[256];
+ int len;
+ int r;
+
+ mutex_lock(&ctxt->lock);
+ for (;;) {
+ if (ctxt->state_dirty) {
+ ctxt->state_dirty = 0;
+ len = qmi_print_state(ctxt, msg, 256);
+ break;
+ }
+ mutex_unlock(&ctxt->lock);
+ r = wait_event_interruptible(qmi_wait_queue, ctxt->state_dirty);
+ if (r < 0)
+ return r;
+ mutex_lock(&ctxt->lock);
+ }
+ mutex_unlock(&ctxt->lock);
+
+ if (len > count)
+ len = count;
+
+ if (copy_to_user(buf, msg, len))
+ return -EFAULT;
+
+ return len;
+}
+
+
+static ssize_t qmi_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct qmi_ctxt *ctxt = fp->private_data;
+ unsigned char cmd[64];
+ int len;
+ int r;
+
+ if (count < 1)
+ return 0;
+
+ len = count > 63 ? 63 : count;
+
+ if (copy_from_user(cmd, buf, len))
+ return -EFAULT;
+
+ cmd[len] = 0;
+
+ /* lazy */
+ if (cmd[len-1] == '\n') {
+ cmd[len-1] = 0;
+ len--;
+ }
+
+ if (!strncmp(cmd, "verbose", 7)) {
+ verbose = 1;
+ } else if (!strncmp(cmd, "terse", 5)) {
+ verbose = 0;
+ } else if (!strncmp(cmd, "poll", 4)) {
+ ctxt->state_dirty = 1;
+ wake_up(&qmi_wait_queue);
+ } else if (!strncmp(cmd, "down", 4)) {
+retry_down:
+ mutex_lock(&ctxt->lock);
+ if (ctxt->wds_busy) {
+ mutex_unlock(&ctxt->lock);
+ r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+ if (r < 0)
+ return r;
+ goto retry_down;
+ }
+ ctxt->wds_busy = 1;
+ qmi_network_down(ctxt);
+ mutex_unlock(&ctxt->lock);
+ } else if (!strncmp(cmd, "up:", 3)) {
+retry_up:
+ mutex_lock(&ctxt->lock);
+ if (ctxt->wds_busy) {
+ mutex_unlock(&ctxt->lock);
+ r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
+ if (r < 0)
+ return r;
+ goto retry_up;
+ }
+ ctxt->wds_busy = 1;
+ qmi_network_up(ctxt, cmd+3);
+ mutex_unlock(&ctxt->lock);
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static int qmi_open(struct inode *ip, struct file *fp)
+{
+ struct qmi_ctxt *ctxt = qmi_minor_to_ctxt(MINOR(ip->i_rdev));
+ int r = 0;
+
+ if (!ctxt) {
+ printk(KERN_ERR "unknown qmi misc %d\n", MINOR(ip->i_rdev));
+ return -ENODEV;
+ }
+
+ fp->private_data = ctxt;
+
+ mutex_lock(&ctxt->lock);
+ if (ctxt->ch == 0)
+ r = smd_open(ctxt->ch_name, &ctxt->ch, ctxt, qmi_notify);
+ if (r == 0)
+ wake_up(&qmi_wait_queue);
+ mutex_unlock(&ctxt->lock);
+
+ return r;
+}
+
+static int qmi_release(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static struct file_operations qmi_fops = {
+ .owner = THIS_MODULE,
+ .read = qmi_read,
+ .write = qmi_write,
+ .open = qmi_open,
+ .release = qmi_release,
+};
+
+static struct qmi_ctxt qmi_device0 = {
+ .ch_name = "SMD_DATA5_CNTL",
+ .misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "qmi0",
+ .fops = &qmi_fops,
+ }
+};
+static struct qmi_ctxt qmi_device1 = {
+ .ch_name = "SMD_DATA6_CNTL",
+ .misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "qmi1",
+ .fops = &qmi_fops,
+ }
+};
+static struct qmi_ctxt qmi_device2 = {
+ .ch_name = "SMD_DATA7_CNTL",
+ .misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "qmi2",
+ .fops = &qmi_fops,
+ }
+};
+
+static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n)
+{
+ if (n == qmi_device0.misc.minor)
+ return &qmi_device0;
+ if (n == qmi_device1.misc.minor)
+ return &qmi_device1;
+ if (n == qmi_device2.misc.minor)
+ return &qmi_device2;
+ return 0;
+}
+
+static int __init qmi_init(void)
+{
+ int ret;
+
+ qmi_wq = create_singlethread_workqueue("qmi");
+ if (qmi_wq == 0)
+ return -ENOMEM;
+
+ qmi_ctxt_init(&qmi_device0, 0);
+ qmi_ctxt_init(&qmi_device1, 1);
+ qmi_ctxt_init(&qmi_device2, 2);
+
+ ret = misc_register(&qmi_device0.misc);
+ if (ret == 0)
+ ret = misc_register(&qmi_device1.misc);
+ if (ret == 0)
+ ret = misc_register(&qmi_device2.misc);
+ return ret;
+}
+
+module_init(qmi_init);
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
new file mode 100644
index 000000000000..64e0bca35fcf
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -0,0 +1,2199 @@
+/* arch/arm/mach-msm/smd_rpcrouter.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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.
+ *
+ */
+
+/* TODO: handle cases where smd_write() will tempfail due to full fifo */
+/* TODO: thread priority? schedule a work to bump it? */
+/* TODO: maybe make server_list_lock a mutex */
+/* TODO: pool fragments to avoid kmalloc/kfree churn */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/msm_smd.h>
+#include <mach/smem_log.h>
+#include "smd_rpcrouter.h"
+#include "modem_notifier.h"
+
+enum {
+ SMEM_LOG = 1U << 0,
+ RTR_DBG = 1U << 1,
+ R2R_MSG = 1U << 2,
+ R2R_RAW = 1U << 3,
+ RPC_MSG = 1U << 4,
+ NTFY_MSG = 1U << 5,
+ RAW_PMR = 1U << 6,
+ RAW_PMW = 1U << 7,
+ R2R_RAW_HDR = 1U << 8,
+};
+static int smd_rpcrouter_debug_mask;
+module_param_named(debug_mask, smd_rpcrouter_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define DIAG(x...) printk(KERN_ERR "[RR] ERROR " x)
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+#define D(x...) do { \
+if (smd_rpcrouter_debug_mask & RTR_DBG) \
+ printk(KERN_ERR x); \
+} while (0)
+
+#define RR(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_MSG) \
+ printk(KERN_ERR "[RR] "x); \
+} while (0)
+
+#define RAW(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_RAW) \
+ printk(KERN_ERR "[RAW] "x); \
+} while (0)
+
+#define RAW_HDR(x...) do { \
+if (smd_rpcrouter_debug_mask & R2R_RAW_HDR) \
+ printk(KERN_ERR "[HDR] "x); \
+} while (0)
+
+#define RAW_PMR(x...) do { \
+if (smd_rpcrouter_debug_mask & RAW_PMR) \
+ printk(KERN_ERR "[PMR] "x); \
+} while (0)
+
+#define RAW_PMR_NOMASK(x...) do { \
+ printk(KERN_ERR "[PMR] "x); \
+} while (0)
+
+#define RAW_PMW(x...) do { \
+if (smd_rpcrouter_debug_mask & RAW_PMW) \
+ printk(KERN_ERR "[PMW] "x); \
+} while (0)
+
+#define RAW_PMW_NOMASK(x...) do { \
+ printk(KERN_ERR "[PMW] "x); \
+} while (0)
+
+#define IO(x...) do { \
+if (smd_rpcrouter_debug_mask & RPC_MSG) \
+ printk(KERN_ERR "[RPC] "x); \
+} while (0)
+
+#define NTFY(x...) do { \
+if (smd_rpcrouter_debug_mask & NTFY_MSG) \
+ printk(KERN_ERR "[NOTIFY] "x); \
+} while (0)
+#else
+#define D(x...) do { } while (0)
+#define RR(x...) do { } while (0)
+#define RAW(x...) do { } while (0)
+#define RAW_HDR(x...) do { } while (0)
+#define RAW_PMR(x...) do { } while (0)
+#define RAW_PMR_NO_MASK(x...) do { } while (0)
+#define RAW_PMW(x...) do { } while (0)
+#define RAW_PMW_NO_MASK(x...) do { } while (0)
+#define IO(x...) do { } while (0)
+#define NTFY(x...) do { } while (0)
+#endif
+
+
+static LIST_HEAD(local_endpoints);
+static LIST_HEAD(remote_endpoints);
+
+static LIST_HEAD(server_list);
+
+static smd_channel_t *smd_channel;
+static int initialized;
+static wait_queue_head_t newserver_wait;
+static wait_queue_head_t smd_wait;
+
+static DEFINE_SPINLOCK(local_endpoints_lock);
+static DEFINE_SPINLOCK(remote_endpoints_lock);
+static DEFINE_SPINLOCK(server_list_lock);
+static DEFINE_SPINLOCK(smd_lock);
+
+static struct workqueue_struct *rpcrouter_workqueue;
+static int rpcrouter_need_len;
+
+static atomic_t next_xid = ATOMIC_INIT(1);
+static atomic_t pm_mid = ATOMIC_INIT(1);
+
+static void do_read_data(struct work_struct *work);
+static void do_create_pdevs(struct work_struct *work);
+static void do_create_rpcrouter_pdev(struct work_struct *work);
+
+static DECLARE_WORK(work_read_data, do_read_data);
+static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
+static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
+
+#define RR_STATE_IDLE 0
+#define RR_STATE_HEADER 1
+#define RR_STATE_BODY 2
+#define RR_STATE_ERROR 3
+
+/* After restart notification, local ep keep
+ * state for server restart and for ep notify.
+ * Server restart cleared by R-R new svr msg.
+ * NTFY cleared by calling msm_rpc_clear_netreset
+*/
+
+#define RESTART_NORMAL 0
+#define RESTART_PEND_SVR 1
+#define RESTART_PEND_NTFY 2
+#define RESTART_PEND_NTFY_SVR 3
+
+/* State for remote ep following restart */
+#define RESTART_QUOTA_ABORT 1
+
+struct rr_context {
+ struct rr_packet *pkt;
+ uint8_t *ptr;
+ uint32_t state; /* current assembly state */
+ uint32_t count; /* bytes needed in this state */
+};
+
+struct rr_context the_rr_context;
+
+static struct platform_device rpcrouter_pdev = {
+ .name = "oncrpc_router",
+ .id = -1,
+};
+
+
+static int rpcrouter_send_control_msg(union rr_control_msg *msg)
+{
+ struct rr_header hdr;
+ unsigned long flags;
+ int need;
+
+ if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) && !initialized) {
+ printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
+ "router not initialized\n");
+ return -EINVAL;
+ }
+
+ hdr.version = RPCROUTER_VERSION;
+ hdr.type = msg->cmd;
+ hdr.src_pid = RPCROUTER_PID_LOCAL;
+ hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
+ hdr.confirm_rx = 0;
+ hdr.size = sizeof(*msg);
+ hdr.dst_pid = 0;
+ hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
+
+ /* TODO: what if channel is full? */
+
+ need = sizeof(hdr) + hdr.size;
+ spin_lock_irqsave(&smd_lock, flags);
+ while (smd_write_avail(smd_channel) < need) {
+ spin_unlock_irqrestore(&smd_lock, flags);
+ msleep(250);
+ spin_lock_irqsave(&smd_lock, flags);
+ }
+ smd_write(smd_channel, &hdr, sizeof(hdr));
+ smd_write(smd_channel, msg, hdr.size);
+ spin_unlock_irqrestore(&smd_lock, flags);
+ return 0;
+}
+
+static void modem_reset_start_cleanup(void)
+{
+ struct msm_rpc_endpoint *ept;
+ struct rr_remote_endpoint *r_ept;
+ struct rr_packet *pkt, *tmp_pkt;
+ struct rr_fragment *frag, *next;
+ struct msm_rpc_reply *reply, *reply_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ /* remove all partial packets received */
+ list_for_each_entry(ept, &local_endpoints, list) {
+ RR("modem_reset_start_clenup PID %x, remotepid:%d \n",
+ ept->dst_pid, RPCROUTER_PID_REMOTE);
+ /* remove replies */
+ spin_lock(&ept->reply_q_lock);
+ list_for_each_entry_safe(reply, reply_tmp,
+ &ept->reply_pend_q, list) {
+ list_del(&reply->list);
+ kfree(reply);
+ }
+ list_for_each_entry_safe(reply, reply_tmp,
+ &ept->reply_avail_q, list) {
+ list_del(&reply->list);
+ kfree(reply);
+ }
+ spin_unlock(&ept->reply_q_lock);
+ if (ept->dst_pid == RPCROUTER_PID_REMOTE) {
+ spin_lock(&ept->incomplete_lock);
+ list_for_each_entry_safe(pkt, tmp_pkt,
+ &ept->incomplete, list) {
+ list_del(&pkt->list);
+ frag = pkt->first;
+ while (frag != NULL) {
+ next = frag->next;
+ kfree(frag);
+ frag = next;
+ }
+ kfree(pkt);
+ }
+ spin_unlock(&ept->incomplete_lock);
+ /* remove all completed packets waiting to be read*/
+ spin_lock(&ept->read_q_lock);
+ list_for_each_entry_safe(pkt, tmp_pkt, &ept->read_q,
+ list) {
+ list_del(&pkt->list);
+ frag = pkt->first;
+ while (frag != NULL) {
+ next = frag->next;
+ kfree(frag);
+ frag = next;
+ }
+ kfree(pkt);
+ }
+ spin_unlock(&ept->read_q_lock);
+ /* Set restart state for local ep */
+ RR("EPT:0x%p, State %d RESTART_PEND_NTFY_SVR "
+ "PROG:0x%08x VERS:0x%08x \n",
+ ept, ept->restart_state, be32_to_cpu(ept->dst_prog),
+ be32_to_cpu(ept->dst_vers));
+ spin_lock(&ept->restart_lock);
+ ept->restart_state = RESTART_PEND_NTFY_SVR;
+ spin_unlock(&ept->restart_lock);
+ wake_up(&ept->wait_q);
+ }
+ }
+
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+
+ /* Unblock endpoints waiting for quota ack*/
+ spin_lock_irqsave(&remote_endpoints_lock, flags);
+ list_for_each_entry(r_ept, &remote_endpoints, list) {
+ spin_lock(&r_ept->quota_lock);
+ r_ept->quota_restart_state = RESTART_QUOTA_ABORT;
+ RR("Set STATE_PENDING PID:0x%08x CID:0x%08x \n", r_ept->pid,
+ r_ept->cid);
+ spin_unlock(&r_ept->quota_lock);
+ wake_up(&r_ept->quota_wait);
+ }
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+
+}
+
+
+static struct rr_server *rpcrouter_create_server(uint32_t pid,
+ uint32_t cid,
+ uint32_t prog,
+ uint32_t ver)
+{
+ struct rr_server *server;
+ unsigned long flags;
+ int rc;
+
+ server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
+ if (!server)
+ return ERR_PTR(-ENOMEM);
+
+ memset(server, 0, sizeof(struct rr_server));
+ server->pid = pid;
+ server->cid = cid;
+ server->prog = prog;
+ server->vers = ver;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_add_tail(&server->list, &server_list);
+ spin_unlock_irqrestore(&server_list_lock, flags);
+
+ if (pid == RPCROUTER_PID_REMOTE) {
+ rc = msm_rpcrouter_create_server_cdev(server);
+ if (rc < 0)
+ goto out_fail;
+ }
+ return server;
+out_fail:
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_del(&server->list);
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ kfree(server);
+ return ERR_PTR(rc);
+}
+
+static void rpcrouter_destroy_server(struct rr_server *server)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_del(&server->list);
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ device_destroy(msm_rpcrouter_class, server->device_number);
+ kfree(server);
+}
+
+static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
+{
+ struct rr_server *server;
+ unsigned long flags;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(server, &server_list, list) {
+ if (server->prog == prog
+ && server->vers == ver) {
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return server;
+ }
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return NULL;
+}
+
+static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
+{
+ struct rr_server *server;
+ unsigned long flags;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(server, &server_list, list) {
+ if (server->device_number == dev) {
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return server;
+ }
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return NULL;
+}
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
+{
+ struct msm_rpc_endpoint *ept;
+ unsigned long flags;
+
+ ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
+ if (!ept)
+ return NULL;
+ memset(ept, 0, sizeof(struct msm_rpc_endpoint));
+ ept->cid = (uint32_t) ept;
+ ept->pid = RPCROUTER_PID_LOCAL;
+ ept->dev = dev;
+
+ if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
+ struct rr_server *srv;
+ /*
+ * This is a userspace client which opened
+ * a program/ver devicenode. Bind the client
+ * to that destination
+ */
+ srv = rpcrouter_lookup_server_by_dev(dev);
+ /* TODO: bug? really? */
+ BUG_ON(!srv);
+
+ ept->dst_pid = srv->pid;
+ ept->dst_cid = srv->cid;
+ ept->dst_prog = cpu_to_be32(srv->prog);
+ ept->dst_vers = cpu_to_be32(srv->vers);
+ } else {
+ /* mark not connected */
+ ept->dst_pid = 0xffffffff;
+ }
+
+ init_waitqueue_head(&ept->wait_q);
+ INIT_LIST_HEAD(&ept->read_q);
+ spin_lock_init(&ept->read_q_lock);
+ INIT_LIST_HEAD(&ept->reply_avail_q);
+ INIT_LIST_HEAD(&ept->reply_pend_q);
+ spin_lock_init(&ept->reply_q_lock);
+ spin_lock_init(&ept->restart_lock);
+ init_waitqueue_head(&ept->restart_wait);
+ ept->restart_state = RESTART_NORMAL;
+ INIT_LIST_HEAD(&ept->incomplete);
+ spin_lock_init(&ept->incomplete_lock);
+
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ list_add_tail(&ept->list, &local_endpoints);
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+ return ept;
+}
+
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
+{
+ int rc;
+ union rr_control_msg msg;
+ struct msm_rpc_reply *reply, *reply_tmp;
+ unsigned long flags;
+
+ msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
+ msg.cli.pid = ept->pid;
+ msg.cli.cid = ept->cid;
+
+ RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
+ rc = rpcrouter_send_control_msg(&msg);
+ if (rc < 0)
+ return rc;
+
+ /* Free replies */
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ list_for_each_entry_safe(reply, reply_tmp, &ept->reply_pend_q, list) {
+ list_del(&reply->list);
+ kfree(reply);
+ }
+ list_for_each_entry_safe(reply, reply_tmp, &ept->reply_avail_q, list) {
+ list_del(&reply->list);
+ kfree(reply);
+ }
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+
+ list_del(&ept->list);
+ kfree(ept);
+ return 0;
+}
+
+static int rpcrouter_create_remote_endpoint(uint32_t cid)
+{
+ struct rr_remote_endpoint *new_c;
+ unsigned long flags;
+
+ new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
+ if (!new_c)
+ return -ENOMEM;
+ memset(new_c, 0, sizeof(struct rr_remote_endpoint));
+
+ new_c->cid = cid;
+ new_c->pid = RPCROUTER_PID_REMOTE;
+ init_waitqueue_head(&new_c->quota_wait);
+ spin_lock_init(&new_c->quota_lock);
+
+ spin_lock_irqsave(&remote_endpoints_lock, flags);
+ list_add_tail(&new_c->list, &remote_endpoints);
+ new_c->quota_restart_state = RESTART_NORMAL;
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+ return 0;
+}
+
+static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
+{
+ struct msm_rpc_endpoint *ept;
+ unsigned long flags;
+
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ list_for_each_entry(ept, &local_endpoints, list) {
+ if (ept->cid == cid) {
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+ return ept;
+ }
+ }
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+ return NULL;
+}
+
+static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid)
+{
+ struct rr_remote_endpoint *ept;
+ unsigned long flags;
+
+ spin_lock_irqsave(&remote_endpoints_lock, flags);
+ list_for_each_entry(ept, &remote_endpoints, list) {
+ if (ept->cid == cid) {
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+ return ept;
+ }
+ }
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+ return NULL;
+}
+
+static void handle_server_restart(struct rr_server *server, uint32_t cid,
+ uint32_t prog, uint32_t vers)
+{
+ struct rr_remote_endpoint *r_ept;
+ struct msm_rpc_endpoint *ept;
+ unsigned long flags;
+ r_ept = rpcrouter_lookup_remote_endpoint(cid);
+ if (r_ept && (r_ept->quota_restart_state !=
+ RESTART_NORMAL)) {
+ spin_lock_irqsave(&r_ept->quota_lock, flags);
+ r_ept->tx_quota_cntr = 0;
+ r_ept->quota_restart_state =
+ RESTART_NORMAL;
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+ printk(KERN_INFO "rpcrouter: Remote EP %0x Reset\n",
+ (unsigned int)r_ept);
+ wake_up(&r_ept->quota_wait);
+ }
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ list_for_each_entry(ept, &local_endpoints, list) {
+ if ((be32_to_cpu(ept->dst_prog) == prog) &&
+ (be32_to_cpu(ept->dst_vers) == vers) &&
+ (ept->restart_state & RESTART_PEND_SVR)) {
+ spin_lock(&ept->restart_lock);
+ ept->restart_state &= ~RESTART_PEND_SVR;
+ spin_unlock(&ept->restart_lock);
+ D("rpcrouter: Local EPT Reset %08x:%08x \n",
+ prog, vers);
+ wake_up(&ept->restart_wait);
+ wake_up(&ept->wait_q);
+ }
+ }
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+}
+
+static int process_control_msg(union rr_control_msg *msg, int len)
+{
+ union rr_control_msg ctl;
+ struct rr_server *server;
+ struct rr_remote_endpoint *r_ept;
+ int rc = 0;
+ unsigned long flags;
+ static int first = 1;
+
+ if (len != sizeof(*msg)) {
+ printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
+ len, sizeof(*msg));
+ return -EINVAL;
+ }
+
+ switch (msg->cmd) {
+ case RPCROUTER_CTRL_CMD_HELLO:
+ RR("o HELLO\n");
+
+ RR("x HELLO\n");
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
+ rpcrouter_send_control_msg(&ctl);
+
+ initialized = 1;
+
+ /* Send list of servers one at a time */
+ ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+
+ /* TODO: long time to hold a spinlock... */
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(server, &server_list, list) {
+ if (server->pid != RPCROUTER_PID_LOCAL)
+ continue;
+ ctl.srv.pid = server->pid;
+ ctl.srv.cid = server->cid;
+ ctl.srv.prog = server->prog;
+ ctl.srv.vers = server->vers;
+
+ RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+ server->pid, server->cid,
+ server->prog, server->vers);
+
+ rpcrouter_send_control_msg(&ctl);
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+
+ if (first) {
+ first = 0;
+ queue_work(rpcrouter_workqueue,
+ &work_create_rpcrouter_pdev);
+ }
+ break;
+
+ case RPCROUTER_CTRL_CMD_RESUME_TX:
+ RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+
+ r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+ if (!r_ept) {
+ printk(KERN_ERR
+ "rpcrouter: Unable to resume client\n");
+ break;
+ }
+ spin_lock_irqsave(&r_ept->quota_lock, flags);
+ r_ept->tx_quota_cntr = 0;
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+ wake_up(&r_ept->quota_wait);
+ break;
+
+ case RPCROUTER_CTRL_CMD_NEW_SERVER:
+ if (msg->srv.vers == 0) {
+ pr_err(
+ "rpcrouter: Server create rejected, version = 0, "
+ "program = %08x\n", msg->srv.prog);
+ break;
+ }
+
+ RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+ msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
+
+ server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+
+ if (!server) {
+ server = rpcrouter_create_server(
+ msg->srv.pid, msg->srv.cid,
+ msg->srv.prog, msg->srv.vers);
+ if (!server)
+ return -ENOMEM;
+ /*
+ * XXX: Verify that its okay to add the
+ * client to our remote client list
+ * if we get a NEW_SERVER notification
+ */
+ if (!rpcrouter_lookup_remote_endpoint(msg->srv.cid)) {
+ rc = rpcrouter_create_remote_endpoint(
+ msg->srv.cid);
+ if (rc < 0)
+ printk(KERN_ERR
+ "rpcrouter:Client create"
+ "error (%d)\n", rc);
+ }
+ schedule_work(&work_create_pdevs);
+ wake_up(&newserver_wait);
+ } else {
+ if ((server->pid == msg->srv.pid) &&
+ (server->cid == msg->srv.cid)) {
+ handle_server_restart(server, msg->srv.cid,
+ msg->srv.prog,
+ msg->srv.vers);
+ } else {
+ server->pid = msg->srv.pid;
+ server->cid = msg->srv.cid;
+ }
+ }
+ break;
+
+ case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+ RR("o REMOVE_SERVER prog=%08x:%d\n",
+ msg->srv.prog, msg->srv.vers);
+ server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
+ if (server)
+ rpcrouter_destroy_server(server);
+ break;
+
+ case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+ RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
+ if (msg->cli.pid != RPCROUTER_PID_REMOTE) {
+ printk(KERN_ERR
+ "rpcrouter: Denying remote removal of "
+ "local client\n");
+ break;
+ }
+ r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
+ if (r_ept) {
+ spin_lock_irqsave(&remote_endpoints_lock, flags);
+ list_del(&r_ept->list);
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+ kfree(r_ept);
+ }
+
+ /* Notify local clients of this event */
+ printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
+ rc = -ENOSYS;
+
+ break;
+ case RPCROUTER_CTRL_CMD_PING:
+ /* No action needed for ping messages received */
+ RR("o PING\n");
+ break;
+ default:
+ RR("o UNKNOWN(%08x)\n", msg->cmd);
+ rc = -ENOSYS;
+ }
+
+ return rc;
+}
+
+static void do_create_rpcrouter_pdev(struct work_struct *work)
+{
+ platform_device_register(&rpcrouter_pdev);
+}
+
+static void do_create_pdevs(struct work_struct *work)
+{
+ unsigned long flags;
+ struct rr_server *server;
+
+ /* TODO: race if destroyed while being registered */
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(server, &server_list, list) {
+ if (server->pid == RPCROUTER_PID_REMOTE) {
+ if (server->pdev_name[0] == 0) {
+ spin_unlock_irqrestore(&server_list_lock,
+ flags);
+ msm_rpcrouter_create_server_pdev(server);
+ schedule_work(&work_create_pdevs);
+ return;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+}
+
+static void rpcrouter_smdnotify(void *_dev, unsigned event)
+{
+ if (event != SMD_EVENT_DATA)
+ return;
+
+ wake_up(&smd_wait);
+}
+
+static void *rr_malloc(unsigned sz)
+{
+ void *ptr = kmalloc(sz, GFP_KERNEL);
+ if (ptr)
+ return ptr;
+
+ printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
+ do {
+ ptr = kmalloc(sz, GFP_KERNEL);
+ } while (!ptr);
+
+ return ptr;
+}
+
+/* TODO: deal with channel teardown / restore */
+static int rr_read(void *data, int len)
+{
+ int rc;
+ unsigned long flags;
+// printk("rr_read() %d\n", len);
+ for(;;) {
+ spin_lock_irqsave(&smd_lock, flags);
+ if (smd_read_avail(smd_channel) >= len) {
+ rc = smd_read(smd_channel, data, len);
+ spin_unlock_irqrestore(&smd_lock, flags);
+ if (rc == len)
+ return 0;
+ else
+ return -EIO;
+ }
+ rpcrouter_need_len = len;
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+// printk("rr_read: waiting (%d)\n", len);
+ wait_event(smd_wait, smd_read_avail(smd_channel) >= len);
+ }
+ return 0;
+}
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+static char *type_to_str(int i)
+{
+ switch (i) {
+ case RPCROUTER_CTRL_CMD_DATA:
+ return "data ";
+ case RPCROUTER_CTRL_CMD_HELLO:
+ return "hello ";
+ case RPCROUTER_CTRL_CMD_BYE:
+ return "bye ";
+ case RPCROUTER_CTRL_CMD_NEW_SERVER:
+ return "new_srvr";
+ case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
+ return "rmv_srvr";
+ case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
+ return "rmv_clnt";
+ case RPCROUTER_CTRL_CMD_RESUME_TX:
+ return "resum_tx";
+ case RPCROUTER_CTRL_CMD_EXIT:
+ return "cmd_exit";
+ default:
+ return "invalid";
+ }
+}
+#endif
+
+static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX];
+
+static void do_read_data(struct work_struct *work)
+{
+ struct rr_header hdr;
+ struct rr_packet *pkt;
+ struct rr_fragment *frag;
+ struct msm_rpc_endpoint *ept;
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ struct rpc_request_hdr *rq;
+#endif
+ uint32_t pm, mid;
+ unsigned long flags;
+
+ if (rr_read(&hdr, sizeof(hdr)))
+ goto fail_io;
+
+ RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
+ hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
+ hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+ RAW_HDR("[r rr_h] "
+ "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
+ "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+ hdr.version, type_to_str(hdr.type), hdr.src_pid, hdr.src_cid,
+ hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
+
+ if (hdr.version != RPCROUTER_VERSION) {
+ DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
+ goto fail_data;
+ }
+ if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
+ DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
+ goto fail_data;
+ }
+
+ if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
+ if (rr_read(r2r_buf, hdr.size))
+ goto fail_io;
+ process_control_msg((void*) r2r_buf, hdr.size);
+ goto done;
+ }
+
+ if (hdr.size < sizeof(pm)) {
+ DIAG("runt packet (no pacmark)\n");
+ goto fail_data;
+ }
+ if (rr_read(&pm, sizeof(pm)))
+ goto fail_io;
+
+ hdr.size -= sizeof(pm);
+
+ frag = rr_malloc(hdr.size + sizeof(*frag));
+ frag->next = NULL;
+ frag->length = hdr.size;
+ if (rr_read(frag->data, hdr.size))
+ goto fail_io;
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ if ((smd_rpcrouter_debug_mask & RAW_PMR) &&
+ ((pm >> 30 & 0x1) || (pm >> 31 & 0x1))) {
+ uint32_t xid = 0;
+ if (pm >> 30 & 0x1) {
+ rq = (struct rpc_request_hdr *) frag->data;
+ xid = ntohl(rq->xid);
+ }
+ if ((pm >> 31 & 0x1) || (pm >> 30 & 0x1))
+ RAW_PMR_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
+ "len=%3i,dst_cid=%08x\n",
+ xid,
+ pm >> 30 & 0x1,
+ pm >> 31 & 0x1,
+ pm >> 16 & 0xFF,
+ pm & 0xFFFF, hdr.dst_cid);
+ }
+
+ if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+ rq = (struct rpc_request_hdr *) frag->data;
+ if (rq->xid == 0)
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MID_READ,
+ PACMARK_MID(pm),
+ hdr.dst_cid,
+ hdr.src_cid);
+ else
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MSG_READ,
+ ntohl(rq->xid),
+ hdr.dst_cid,
+ hdr.src_cid);
+ }
+#endif
+
+ ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
+ if (!ept) {
+ DIAG("no local ept for cid %08x\n", hdr.dst_cid);
+ kfree(frag);
+ goto done;
+ }
+
+ /* See if there is already a partial packet that matches our mid
+ * and if so, append this fragment to that packet.
+ */
+ mid = PACMARK_MID(pm);
+ spin_lock_irqsave(&ept->incomplete_lock, flags);
+ list_for_each_entry(pkt, &ept->incomplete, list) {
+ if (pkt->mid == mid) {
+ pkt->last->next = frag;
+ pkt->last = frag;
+ pkt->length += frag->length;
+ if (PACMARK_LAST(pm)) {
+ list_del(&pkt->list);
+ spin_unlock_irqrestore(&ept->incomplete_lock,
+ flags);
+ goto packet_complete;
+ }
+ spin_unlock_irqrestore(&ept->incomplete_lock, flags);
+ goto done;
+ }
+ }
+ spin_unlock_irqrestore(&ept->incomplete_lock, flags);
+ /* This mid is new -- create a packet for it, and put it on
+ * the incomplete list if this fragment is not a last fragment,
+ * otherwise put it on the read queue.
+ */
+ pkt = rr_malloc(sizeof(struct rr_packet));
+ pkt->first = frag;
+ pkt->last = frag;
+ memcpy(&pkt->hdr, &hdr, sizeof(hdr));
+ pkt->mid = mid;
+ pkt->length = frag->length;
+ if (!PACMARK_LAST(pm)) {
+ list_add_tail(&pkt->list, &ept->incomplete);
+ goto done;
+ }
+
+packet_complete:
+ spin_lock_irqsave(&ept->read_q_lock, flags);
+ list_add_tail(&pkt->list, &ept->read_q);
+ wake_up(&ept->wait_q);
+ spin_unlock_irqrestore(&ept->read_q_lock, flags);
+done:
+
+ if (hdr.confirm_rx) {
+ union rr_control_msg msg;
+
+ msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
+ msg.cli.pid = hdr.dst_pid;
+ msg.cli.cid = hdr.dst_cid;
+
+ RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
+ rpcrouter_send_control_msg(&msg);
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ if (smd_rpcrouter_debug_mask & SMEM_LOG)
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT,
+ RPCROUTER_PID_LOCAL,
+ hdr.dst_cid,
+ hdr.src_cid);
+#endif
+
+ }
+
+ queue_work(rpcrouter_workqueue, &work_read_data);
+ return;
+
+fail_io:
+fail_data:
+ printk(KERN_ERR "rpc_router has died\n");
+}
+
+void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
+ uint32_t vers, uint32_t proc)
+{
+ memset(hdr, 0, sizeof(struct rpc_request_hdr));
+ hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+ hdr->rpc_vers = cpu_to_be32(2);
+ hdr->prog = cpu_to_be32(prog);
+ hdr->vers = cpu_to_be32(vers);
+ hdr->procedure = cpu_to_be32(proc);
+}
+EXPORT_SYMBOL(msm_rpc_setup_req);
+
+struct msm_rpc_endpoint *msm_rpc_open(void)
+{
+ struct msm_rpc_endpoint *ept;
+
+ ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
+ if (ept == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ return ept;
+}
+
+int msm_rpc_close(struct msm_rpc_endpoint *ept)
+{
+ return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+EXPORT_SYMBOL(msm_rpc_close);
+
+static int msm_rpc_write_pkt(
+ struct rr_header *hdr,
+ struct msm_rpc_endpoint *ept,
+ struct rr_remote_endpoint *r_ept,
+ void *buffer,
+ int count,
+ int first,
+ int last,
+ uint32_t mid
+ )
+{
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ struct rpc_request_hdr *rq = buffer;
+#endif
+ uint32_t pacmark;
+ unsigned long flags;
+ int needed;
+
+ DEFINE_WAIT(__wait);
+
+ /* Create routing header */
+ hdr->type = RPCROUTER_CTRL_CMD_DATA;
+ hdr->version = RPCROUTER_VERSION;
+ hdr->src_pid = ept->pid;
+ hdr->src_cid = ept->cid;
+ hdr->confirm_rx = 0;
+ hdr->size = count + sizeof(uint32_t);
+
+ for (;;) {
+ prepare_to_wait(&ept->restart_wait, &__wait,
+ TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&ept->restart_lock, flags);
+ if (ept->restart_state == RESTART_NORMAL) {
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+ break;
+ }
+ if (signal_pending(current) &&
+ ((!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))) {
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+ schedule();
+ }
+ finish_wait(&ept->restart_wait, &__wait);
+
+ if (signal_pending(current) &&
+ (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
+ return -ERESTARTSYS;
+ }
+
+ for (;;) {
+ prepare_to_wait(&r_ept->quota_wait, &__wait,
+ TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&r_ept->quota_lock, flags);
+ if ((r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA) ||
+ (r_ept->quota_restart_state != RESTART_NORMAL))
+ break;
+ if (signal_pending(current) &&
+ (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
+ break;
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+ schedule();
+ }
+ finish_wait(&r_ept->quota_wait, &__wait);
+
+ if (r_ept->quota_restart_state != RESTART_NORMAL) {
+ spin_lock(&ept->restart_lock);
+ ept->restart_state &= ~RESTART_PEND_NTFY;
+ spin_unlock(&ept->restart_lock);
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+ return -ENETRESET;
+ }
+
+ if (signal_pending(current) &&
+ (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+ return -ERESTARTSYS;
+ }
+ r_ept->tx_quota_cntr++;
+ if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) {
+ hdr->confirm_rx = 1;
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+ if (rq->xid == 0)
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MID_CFM_REQ,
+ hdr->dst_pid,
+ hdr->dst_cid,
+ hdr->src_cid);
+ else
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ,
+ hdr->dst_pid,
+ hdr->dst_cid,
+ hdr->src_cid);
+ }
+#endif
+
+ }
+ pacmark = PACMARK(count, mid, first, last);
+
+ spin_unlock_irqrestore(&r_ept->quota_lock, flags);
+
+ spin_lock_irqsave(&smd_lock, flags);
+ spin_lock(&ept->restart_lock);
+ if (ept->restart_state != RESTART_NORMAL) {
+ ept->restart_state &= ~RESTART_PEND_NTFY;
+ spin_unlock(&ept->restart_lock);
+ spin_unlock_irqrestore(&smd_lock, flags);
+ return -ENETRESET;
+ }
+
+ needed = sizeof(*hdr) + hdr->size;
+ while ((ept->restart_state == RESTART_NORMAL) &&
+ (smd_write_avail(smd_channel) < needed)) {
+ spin_unlock(&ept->restart_lock);
+ spin_unlock_irqrestore(&smd_lock, flags);
+ msleep(250);
+ spin_lock_irqsave(&smd_lock, flags);
+ spin_lock(&ept->restart_lock);
+ }
+ if (ept->restart_state != RESTART_NORMAL) {
+ ept->restart_state &= ~RESTART_PEND_NTFY;
+ spin_unlock(&ept->restart_lock);
+ spin_unlock_irqrestore(&smd_lock, flags);
+ return -ENETRESET;
+ }
+
+ /* TODO: deal with full fifo */
+ smd_write(smd_channel, hdr, sizeof(*hdr));
+ RAW_HDR("[w rr_h] "
+ "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
+ "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
+ hdr->version, type_to_str(hdr->type), hdr->src_pid, hdr->src_cid,
+ hdr->confirm_rx, hdr->size, hdr->dst_pid, hdr->dst_cid);
+ smd_write(smd_channel, &pacmark, sizeof(pacmark));
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ if ((smd_rpcrouter_debug_mask & RAW_PMW) &&
+ ((pacmark >> 30 & 0x1) || (pacmark >> 31 & 0x1))) {
+ uint32_t xid = 0;
+ if (pacmark >> 30 & 0x1)
+ xid = ntohl(rq->xid);
+ if ((pacmark >> 31 & 0x1) || (pacmark >> 30 & 0x1))
+ RAW_PMW_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
+ "len=%3i,src_cid=%x\n",
+ xid,
+ pacmark >> 30 & 0x1,
+ pacmark >> 31 & 0x1,
+ pacmark >> 16 & 0xFF,
+ pacmark & 0xFFFF, hdr->src_cid);
+ }
+#endif
+
+ smd_write(smd_channel, buffer, count);
+ spin_unlock(&ept->restart_lock);
+ spin_unlock_irqrestore(&smd_lock, flags);
+
+#if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
+ if (smd_rpcrouter_debug_mask & SMEM_LOG) {
+ if (rq->xid == 0)
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MID_WRITTEN,
+ PACMARK_MID(pacmark),
+ hdr->dst_cid,
+ hdr->src_cid);
+ else
+ smem_log_event(SMEM_LOG_PROC_ID_APPS |
+ RPC_ROUTER_LOG_EVENT_MSG_WRITTEN,
+ ntohl(rq->xid),
+ hdr->dst_cid,
+ hdr->src_cid);
+ }
+#endif
+
+ return needed;
+}
+
+static struct msm_rpc_reply *get_pend_reply(struct msm_rpc_endpoint *ept,
+ uint32_t xid)
+{
+ unsigned long flags;
+ struct msm_rpc_reply *reply;
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ list_for_each_entry(reply, &ept->reply_pend_q, list) {
+ if (reply->xid == xid) {
+ list_del(&reply->list);
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ return reply;
+ }
+ }
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ return NULL;
+}
+
+void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid,
+ struct msm_rpc_client_info *clnt_info)
+{
+ unsigned long flags;
+ struct msm_rpc_reply *reply;
+
+ if (!clnt_info)
+ return;
+
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ list_for_each_entry(reply, &ept->reply_pend_q, list) {
+ if (reply->xid == xid) {
+ clnt_info->pid = reply->pid;
+ clnt_info->cid = reply->cid;
+ clnt_info->prog = reply->prog;
+ clnt_info->vers = reply->vers;
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ return;
+}
+
+static void set_avail_reply(struct msm_rpc_endpoint *ept,
+ struct msm_rpc_reply *reply)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ list_add_tail(&reply->list, &ept->reply_avail_q);
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+}
+
+static struct msm_rpc_reply *get_avail_reply(struct msm_rpc_endpoint *ept)
+{
+ struct msm_rpc_reply *reply;
+ unsigned long flags;
+ if (list_empty(&ept->reply_avail_q)) {
+ if (ept->reply_cnt >= RPCROUTER_PEND_REPLIES_MAX) {
+ printk(KERN_ERR
+ "exceeding max replies of %d \n",
+ RPCROUTER_PEND_REPLIES_MAX);
+ return 0;
+ }
+ reply = kmalloc(sizeof(struct msm_rpc_reply), GFP_KERNEL);
+ if (!reply)
+ return 0;
+ D("Adding reply 0x%08x \n", (unsigned int)reply);
+ memset(reply, 0, sizeof(struct msm_rpc_reply));
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ ept->reply_cnt++;
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ } else {
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ reply = list_first_entry(&ept->reply_avail_q,
+ struct msm_rpc_reply,
+ list);
+ list_del(&reply->list);
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+ }
+ return reply;
+}
+
+static void set_pend_reply(struct msm_rpc_endpoint *ept,
+ struct msm_rpc_reply *reply)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ept->reply_q_lock, flags);
+ list_add_tail(&reply->list, &ept->reply_pend_q);
+ spin_unlock_irqrestore(&ept->reply_q_lock, flags);
+}
+
+int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
+{
+ struct rr_header hdr;
+ struct rpc_request_hdr *rq = buffer;
+ struct rr_remote_endpoint *r_ept;
+ struct msm_rpc_reply *reply;
+ int max_tx;
+ int tx_cnt;
+ char *tx_buf;
+ int rc;
+ int first_pkt = 1;
+ uint32_t mid;
+
+ /* snoop the RPC packet and enforce permissions */
+
+ /* has to have at least the xid and type fields */
+ if (count < (sizeof(uint32_t) * 2)) {
+ printk(KERN_ERR "rr_write: rejecting runt packet\n");
+ return -EINVAL;
+ }
+
+ if (rq->type == 0) {
+ /* RPC CALL */
+ if (count < (sizeof(uint32_t) * 6)) {
+ printk(KERN_ERR
+ "rr_write: rejecting runt call packet\n");
+ return -EINVAL;
+ }
+ if (ept->dst_pid == 0xffffffff) {
+ printk(KERN_ERR "rr_write: not connected\n");
+ return -ENOTCONN;
+ }
+ if ((ept->dst_prog != rq->prog) ||
+ ((be32_to_cpu(ept->dst_vers) & 0x0fff0000) !=
+ (be32_to_cpu(rq->vers) & 0x0fff0000))) {
+ printk(KERN_ERR
+ "rr_write: cannot write to %08x:%08x "
+ "(bound to %08x:%08x)\n",
+ be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+ be32_to_cpu(ept->dst_prog),
+ be32_to_cpu(ept->dst_vers));
+ return -EINVAL;
+ }
+ hdr.dst_pid = ept->dst_pid;
+ hdr.dst_cid = ept->dst_cid;
+ IO("CALL to %08x:%d @ %d:%08x (%d bytes)\n",
+ be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
+ ept->dst_pid, ept->dst_cid, count);
+ } else {
+ /* RPC REPLY */
+ reply = get_pend_reply(ept, rq->xid);
+ if (!reply) {
+ printk(KERN_ERR
+ "rr_write: rejecting, reply not found \n");
+ return -EINVAL;
+ }
+ hdr.dst_pid = reply->pid;
+ hdr.dst_cid = reply->cid;
+ set_avail_reply(ept, reply);
+ IO("REPLY to xid=%d @ %d:%08x (%d bytes)\n",
+ be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
+ }
+
+ r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_cid);
+
+ if (!r_ept) {
+ printk(KERN_ERR
+ "msm_rpc_write(): No route to ept "
+ "[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
+ return -EHOSTUNREACH;
+ }
+
+ tx_cnt = count;
+ tx_buf = buffer;
+ mid = atomic_add_return(1, &pm_mid) & 0xFF;
+ /* The modem's router can only take 500 bytes of data. The
+ first 8 bytes it uses on the modem side for addressing,
+ the next 4 bytes are for the pacmark header. */
+ max_tx = RPCROUTER_MSGSIZE_MAX - 8 - sizeof(uint32_t);
+ IO("Writing %d bytes, max pkt size is %d\n",
+ tx_cnt, max_tx);
+ while (tx_cnt > 0) {
+ if (tx_cnt > max_tx) {
+ rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
+ tx_buf, max_tx,
+ first_pkt, 0, mid);
+ if (rc < 0)
+ return rc;
+ IO("Wrote %d bytes First %d, Last 0 mid %d\n",
+ rc, first_pkt, mid);
+ tx_cnt -= max_tx;
+ tx_buf += max_tx;
+ } else {
+ rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
+ tx_buf, tx_cnt,
+ first_pkt, 1, mid);
+ if (rc < 0)
+ return rc;
+ IO("Wrote %d bytes First %d Last 1 mid %d\n",
+ rc, first_pkt, mid);
+ break;
+ }
+ first_pkt = 0;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL(msm_rpc_write);
+
+/*
+ * NOTE: It is the responsibility of the caller to kfree buffer
+ */
+int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
+ unsigned user_len, long timeout)
+{
+ struct rr_fragment *frag, *next;
+ char *buf;
+ int rc;
+
+ rc = __msm_rpc_read(ept, &frag, user_len, timeout);
+ if (rc <= 0)
+ return rc;
+
+ /* single-fragment messages conveniently can be
+ * returned as-is (the buffer is at the front)
+ */
+ if (frag->next == 0) {
+ *buffer = (void*) frag;
+ return rc;
+ }
+
+ /* multi-fragment messages, we have to do it the
+ * hard way, which is rather disgusting right now
+ */
+ buf = rr_malloc(rc);
+ *buffer = buf;
+
+ while (frag != NULL) {
+ memcpy(buf, frag->data, frag->length);
+ next = frag->next;
+ buf += frag->length;
+ kfree(frag);
+ frag = next;
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_read);
+
+int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *_request, int request_size,
+ long timeout)
+{
+ return msm_rpc_call_reply(ept, proc,
+ _request, request_size,
+ NULL, 0, timeout);
+}
+EXPORT_SYMBOL(msm_rpc_call);
+
+int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
+ void *_request, int request_size,
+ void *_reply, int reply_size,
+ long timeout)
+{
+ struct rpc_request_hdr *req = _request;
+ struct rpc_reply_hdr *reply;
+ int rc;
+
+ if (request_size < sizeof(*req))
+ return -ETOOSMALL;
+
+ if (ept->dst_pid == 0xffffffff)
+ return -ENOTCONN;
+
+ memset(req, 0, sizeof(*req));
+ req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
+ req->rpc_vers = cpu_to_be32(2);
+ req->prog = ept->dst_prog;
+ req->vers = ept->dst_vers;
+ req->procedure = cpu_to_be32(proc);
+
+ rc = msm_rpc_write(ept, req, request_size);
+ if (rc < 0)
+ return rc;
+
+ for (;;) {
+ rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
+ if (rc < 0)
+ return rc;
+ if (rc < (3 * sizeof(uint32_t))) {
+ rc = -EIO;
+ break;
+ }
+ /* we should not get CALL packets -- ignore them */
+ if (reply->type == 0) {
+ kfree(reply);
+ continue;
+ }
+ /* If an earlier call timed out, we could get the (no
+ * longer wanted) reply for it. Ignore replies that
+ * we don't expect
+ */
+ if (reply->xid != req->xid) {
+ kfree(reply);
+ continue;
+ }
+ if (reply->reply_stat != 0) {
+ rc = -EPERM;
+ break;
+ }
+ if (reply->data.acc_hdr.accept_stat != 0) {
+ rc = -EINVAL;
+ break;
+ }
+ if (_reply == NULL) {
+ rc = 0;
+ break;
+ }
+ if (rc > reply_size) {
+ rc = -ENOMEM;
+ } else {
+ memcpy(_reply, reply, rc);
+ }
+ break;
+ }
+ kfree(reply);
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_call_reply);
+
+
+static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&ept->read_q_lock, flags);
+ ret = !list_empty(&ept->read_q);
+ spin_unlock_irqrestore(&ept->read_q_lock, flags);
+ return ret;
+}
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+ struct rr_fragment **frag_ret,
+ unsigned len, long timeout)
+{
+ struct rr_packet *pkt;
+ struct rpc_request_hdr *rq;
+ struct msm_rpc_reply *reply;
+ DEFINE_WAIT(__wait);
+ unsigned long flags;
+ int rc;
+
+ IO("READ on ept %p\n", ept);
+ spin_lock_irqsave(&ept->restart_lock, flags);
+ if (ept->restart_state != RESTART_NORMAL) {
+ ept->restart_state &= ~RESTART_PEND_NTFY;
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+ return -ENETRESET;
+ }
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+
+ if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
+ if (timeout < 0) {
+ wait_event(ept->wait_q, ept_packet_available(ept));
+ if (!msm_rpc_clear_netreset(ept))
+ return -ENETRESET;
+ } else {
+ rc = wait_event_timeout(
+ ept->wait_q, ept_packet_available(ept),
+ timeout);
+ if (!msm_rpc_clear_netreset(ept))
+ return -ENETRESET;
+ if (rc == 0)
+ return -ETIMEDOUT;
+ }
+ } else {
+ if (timeout < 0) {
+ rc = wait_event_interruptible(
+ ept->wait_q, ept_packet_available(ept));
+ if (!msm_rpc_clear_netreset(ept))
+ return -ENETRESET;
+ if (rc < 0)
+ return rc;
+ } else {
+ rc = wait_event_interruptible_timeout(
+ ept->wait_q, ept_packet_available(ept),
+ timeout);
+ if (!msm_rpc_clear_netreset(ept))
+ return -ENETRESET;
+ if (rc == 0)
+ return -ETIMEDOUT;
+ }
+ }
+
+ spin_lock_irqsave(&ept->read_q_lock, flags);
+ if (list_empty(&ept->read_q)) {
+ spin_unlock_irqrestore(&ept->read_q_lock, flags);
+ return -EAGAIN;
+ }
+ pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
+ if (pkt->length > len) {
+ spin_unlock_irqrestore(&ept->read_q_lock, flags);
+ return -ETOOSMALL;
+ }
+ list_del(&pkt->list);
+ spin_unlock_irqrestore(&ept->read_q_lock, flags);
+
+ rc = pkt->length;
+
+ *frag_ret = pkt->first;
+ rq = (void*) pkt->first->data;
+ if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
+ /* RPC CALL */
+ reply = get_avail_reply(ept);
+ if (!reply)
+ return -ENOMEM;
+ reply->cid = pkt->hdr.src_cid;
+ reply->pid = pkt->hdr.src_pid;
+ reply->xid = rq->xid;
+ reply->prog = rq->prog;
+ reply->vers = rq->vers;
+ set_pend_reply(ept, reply);
+ }
+
+ kfree(pkt);
+
+ IO("READ on ept %p (%d bytes)\n", ept, rc);
+ return rc;
+}
+
+int msm_rpc_is_compatible_version(uint32_t server_version,
+ uint32_t client_version)
+{
+
+ if ((server_version & RPC_VERSION_MODE_MASK) !=
+ (client_version & RPC_VERSION_MODE_MASK))
+ return 0;
+
+ if (server_version & RPC_VERSION_MODE_MASK)
+ return server_version == client_version;
+
+ return ((server_version & RPC_VERSION_MAJOR_MASK) ==
+ (client_version & RPC_VERSION_MAJOR_MASK)) &&
+ ((server_version & RPC_VERSION_MINOR_MASK) >=
+ (client_version & RPC_VERSION_MINOR_MASK));
+}
+EXPORT_SYMBOL(msm_rpc_is_compatible_version);
+
+int msm_rpc_get_compatible_server(uint32_t prog,
+ uint32_t ver,
+ uint32_t *found_vers)
+{
+ struct rr_server *server;
+ unsigned long flags;
+ uint32_t found = -1;
+ if (found_vers == NULL)
+ return 0;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(server, &server_list, list) {
+ if ((server->prog == prog) &&
+ msm_rpc_is_compatible_version(server->vers, ver)) {
+ *found_vers = server->vers;
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return 0;
+ }
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+ return found;
+}
+EXPORT_SYMBOL(msm_rpc_get_compatible_server);
+
+struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
+ uint32_t vers, unsigned flags)
+{
+ uint32_t found_vers;
+ int ret;
+ ret = msm_rpc_get_compatible_server(prog, vers, &found_vers);
+ if (ret < 0)
+ return ERR_PTR(-EHOSTUNREACH);
+ if (found_vers != vers) {
+ D("RPC Using new version 0x%08x(0x%08x) prog 0x%08x",
+ vers, found_vers, prog);
+ D(" ... Continuing\n");
+ }
+ return msm_rpc_connect(prog, found_vers, flags);
+}
+EXPORT_SYMBOL(msm_rpc_connect_compatible);
+
+struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags)
+{
+ struct msm_rpc_endpoint *ept;
+ struct rr_server *server;
+
+ server = rpcrouter_lookup_server(prog, vers);
+ if (!server)
+ return ERR_PTR(-EHOSTUNREACH);
+
+ ept = msm_rpc_open();
+ if (IS_ERR(ept))
+ return ept;
+
+ ept->flags = flags;
+ ept->dst_pid = server->pid;
+ ept->dst_cid = server->cid;
+ ept->dst_prog = cpu_to_be32(prog);
+ ept->dst_vers = cpu_to_be32(vers);
+
+ return ept;
+}
+EXPORT_SYMBOL(msm_rpc_connect);
+
+/* TODO: permission check? */
+int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers)
+{
+ int rc;
+ union rr_control_msg msg;
+ struct rr_server *server;
+
+ server = rpcrouter_create_server(ept->pid, ept->cid,
+ prog, vers);
+ if (!server)
+ return -ENODEV;
+
+ msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
+ msg.srv.pid = ept->pid;
+ msg.srv.cid = ept->cid;
+ msg.srv.prog = prog;
+ msg.srv.vers = vers;
+
+ RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
+ ept->pid, ept->cid, prog, vers);
+
+ rc = rpcrouter_send_control_msg(&msg);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept)
+{
+ unsigned long flags;
+ int rc = 1;
+ RR("RESET RESTART FLAG for EPT:%08x \n", (unsigned int)ept);
+ spin_lock_irqsave(&ept->restart_lock, flags);
+ if (ept->restart_state != RESTART_NORMAL) {
+ ept->restart_state &= ~RESTART_PEND_NTFY;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&ept->restart_lock, flags);
+ return rc;
+}
+
+/* TODO: permission check -- disallow unreg of somebody else's server */
+int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
+ uint32_t prog, uint32_t vers)
+{
+ struct rr_server *server;
+ server = rpcrouter_lookup_server(prog, vers);
+
+ if (!server)
+ return -ENOENT;
+ rpcrouter_destroy_server(server);
+ return 0;
+}
+
+static int msm_rpcrouter_modem_notify(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
+{
+ switch (code) {
+ case MODEM_NOTIFIER_START_RESET:
+ NTFY("%s: MODEM_NOTIFIER_START_RESET", __func__);
+ modem_reset_start_cleanup();
+ break;
+ case MODEM_NOTIFIER_END_RESET:
+ NTFY("%s: MODEM_NOTIFIER_END_RESET", __func__);
+ break;
+ default:
+ NTFY("%s: default", __func__);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block msm_rpcrouter_nb = {
+ .notifier_call = msm_rpcrouter_modem_notify,
+};
+
+static int msm_rpcrouter_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ /* Initialize what we need to start processing */
+ INIT_LIST_HEAD(&local_endpoints);
+ INIT_LIST_HEAD(&remote_endpoints);
+
+ init_waitqueue_head(&newserver_wait);
+ init_waitqueue_head(&smd_wait);
+
+ rpcrouter_workqueue = create_singlethread_workqueue("rpcrouter");
+ if (!rpcrouter_workqueue)
+ return -ENOMEM;
+
+ rc = msm_rpcrouter_init_devices();
+ if (rc < 0)
+ goto fail_destroy_workqueue;
+
+ rc = modem_register_notifier(&msm_rpcrouter_nb);
+ if (rc < 0)
+ goto fail_remove_devices;
+
+ /* Open up SMD channel 2 */
+ initialized = 0;
+ rc = smd_open("RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify);
+ if (rc < 0)
+ goto fail_remove_reset_notifier;
+
+ queue_work(rpcrouter_workqueue, &work_read_data);
+ return 0;
+
+ fail_remove_reset_notifier:
+ modem_unregister_notifier(&msm_rpcrouter_nb);
+ fail_remove_devices:
+ msm_rpcrouter_exit_devices();
+ fail_destroy_workqueue:
+ destroy_workqueue(rpcrouter_workqueue);
+ return rc;
+}
+
+static struct platform_driver msm_smd_channel2_driver = {
+ .probe = msm_rpcrouter_probe,
+ .driver = {
+ .name = "RPCCALL",
+ .owner = THIS_MODULE,
+ },
+};
+
+#if defined(CONFIG_DEBUG_FS)
+#define HSIZE 13
+
+struct sym {
+ uint32_t val;
+ char *str;
+ struct hlist_node node;
+};
+
+static struct sym oncrpc_syms[] = {
+ { 0x30000000, "CM" },
+ { 0x30000001, "DB" },
+ { 0x30000002, "SND" },
+ { 0x30000003, "WMS" },
+ { 0x30000004, "PDSM" },
+ { 0x30000005, "MISC_MODEM_APIS" },
+ { 0x30000006, "MISC_APPS_APIS" },
+ { 0x30000007, "JOYST" },
+ { 0x30000008, "VJOY" },
+ { 0x30000009, "JOYSTC" },
+ { 0x3000000a, "ADSPRTOSATOM" },
+ { 0x3000000b, "ADSPRTOSMTOA" },
+ { 0x3000000c, "I2C" },
+ { 0x3000000d, "TIME_REMOTE" },
+ { 0x3000000e, "NV" },
+ { 0x3000000f, "CLKRGM_SEC" },
+ { 0x30000010, "RDEVMAP" },
+ { 0x30000011, "FS_RAPI" },
+ { 0x30000012, "PBMLIB" },
+ { 0x30000013, "AUDMGR" },
+ { 0x30000014, "MVS" },
+ { 0x30000015, "DOG_KEEPALIVE" },
+ { 0x30000016, "GSDI_EXP" },
+ { 0x30000017, "AUTH" },
+ { 0x30000018, "NVRUIMI" },
+ { 0x30000019, "MMGSDILIB" },
+ { 0x3000001a, "CHARGER" },
+ { 0x3000001b, "UIM" },
+ { 0x3000001C, "ONCRPCTEST" },
+ { 0x3000001d, "PDSM_ATL" },
+ { 0x3000001e, "FS_XMOUNT" },
+ { 0x3000001f, "SECUTIL " },
+ { 0x30000020, "MCCMEID" },
+ { 0x30000021, "PM_STROBE_FLASH" },
+ { 0x30000022, "DS707_EXTIF" },
+ { 0x30000023, "SMD BRIDGE_MODEM" },
+ { 0x30000024, "SMD PORT_MGR" },
+ { 0x30000025, "BUS_PERF" },
+ { 0x30000026, "BUS_MON" },
+ { 0x30000027, "MC" },
+ { 0x30000028, "MCCAP" },
+ { 0x30000029, "MCCDMA" },
+ { 0x3000002a, "MCCDS" },
+ { 0x3000002b, "MCCSCH" },
+ { 0x3000002c, "MCCSRID" },
+ { 0x3000002d, "SNM" },
+ { 0x3000002e, "MCCSYOBJ" },
+ { 0x3000002f, "DS707_APIS" },
+ { 0x30000030, "DS_MP_SHIM_APPS_ASYNC" },
+ { 0x30000031, "DSRLP_APIS" },
+ { 0x30000032, "RLP_APIS" },
+ { 0x30000033, "DS_MP_SHIM_MODEM" },
+ { 0x30000034, "DSHDR_APIS" },
+ { 0x30000035, "DSHDR_MDM_APIS" },
+ { 0x30000036, "DS_MP_SHIM_APPS" },
+ { 0x30000037, "HDRMC_APIS" },
+ { 0x30000038, "SMD_BRIDGE_MTOA" },
+ { 0x30000039, "SMD_BRIDGE_ATOM" },
+ { 0x3000003a, "DPMAPP_OTG" },
+ { 0x3000003b, "DIAG" },
+ { 0x3000003c, "GSTK_EXP" },
+ { 0x3000003d, "DSBC_MDM_APIS" },
+ { 0x3000003e, "HDRMRLP_MDM_APIS" },
+ { 0x3000003f, "HDRMRLP_APPS_APIS" },
+ { 0x30000040, "HDRMC_MRLP_APIS" },
+ { 0x30000041, "PDCOMM_APP_API" },
+ { 0x30000042, "DSAT_APIS" },
+ { 0x30000043, "MISC_RF_APIS" },
+ { 0x30000044, "CMIPAPP" },
+ { 0x30000045, "DSMP_UMTS_MODEM_APIS" },
+ { 0x30000046, "DSMP_UMTS_APPS_APIS" },
+ { 0x30000047, "DSUCSDMPSHIM" },
+ { 0x30000048, "TIME_REMOTE_ATOM" },
+ { 0x3000004a, "SD" },
+ { 0x3000004b, "MMOC" },
+ { 0x3000004c, "WLAN_ADP_FTM" },
+ { 0x3000004d, "WLAN_CP_CM" },
+ { 0x3000004e, "FTM_WLAN" },
+ { 0x3000004f, "SDCC_CPRM" },
+ { 0x30000050, "CPRMINTERFACE" },
+ { 0x30000051, "DATA_ON_MODEM_MTOA_APIS" },
+ { 0x30000052, "DATA_ON_APPS_ATOM_APIS" },
+ { 0x30000053, "MISC_MODEM_APIS_NONWINMOB" },
+ { 0x30000054, "MISC_APPS_APIS_NONWINMOB" },
+ { 0x30000055, "PMEM_REMOTE" },
+ { 0x30000056, "TCXOMGR" },
+ { 0x30000057, "DSUCSDAPPIF_APIS" },
+ { 0x30000058, "BT" },
+ { 0x30000059, "PD_COMMS_API" },
+ { 0x3000005a, "PD_COMMS_CLIENT_API" },
+ { 0x3000005b, "PDAPI" },
+ { 0x3000005c, "LSA_SUPL_DSM" },
+ { 0x3000005d, "TIME_REMOTE_MTOA" },
+ { 0x3000005e, "FTM_BT" },
+ { 0X3000005f, "DSUCSDAPPIF_APIS" },
+ { 0X30000060, "PMAPP_GEN" },
+ { 0X30000061, "PM_LIB" },
+ { 0X30000062, "KEYPAD" },
+ { 0X30000063, "HSU_APP_APIS" },
+ { 0X30000064, "HSU_MDM_APIS" },
+ { 0X30000065, "ADIE_ADC_REMOTE_ATOM " },
+ { 0X30000066, "TLMM_REMOTE_ATOM" },
+ { 0X30000067, "UI_CALLCTRL" },
+ { 0X30000068, "UIUTILS" },
+ { 0X30000069, "PRL" },
+ { 0X3000006a, "HW" },
+ { 0X3000006b, "OEM_RAPI" },
+ { 0X3000006c, "WMSPM" },
+ { 0X3000006d, "BTPF" },
+ { 0X3000006e, "CLKRGM_SYNC_EVENT" },
+ { 0X3000006f, "USB_APPS_RPC" },
+ { 0X30000070, "USB_MODEM_RPC" },
+ { 0X30000071, "ADC" },
+ { 0X30000072, "CAMERAREMOTED" },
+ { 0X30000073, "SECAPIREMOTED" },
+ { 0X30000074, "DSATAPI" },
+ { 0X30000075, "CLKCTL_RPC" },
+ { 0X30000076, "BREWAPPCOORD" },
+ { 0X30000077, "ALTENVSHELL" },
+ { 0X30000078, "WLAN_TRP_UTILS" },
+ { 0X30000079, "GPIO_RPC" },
+ { 0X3000007a, "PING_RPC" },
+ { 0X3000007b, "DSC_DCM_API" },
+ { 0X3000007c, "L1_DS" },
+ { 0X3000007d, "QCHATPK_APIS" },
+ { 0X3000007e, "GPS_API" },
+ { 0X3000007f, "OSS_RRCASN_REMOTE" },
+ { 0X30000080, "PMAPP_OTG_REMOTE" },
+ { 0X30000081, "PING_MDM_RPC" },
+ { 0X30000082, "PING_KERNEL_RPC" },
+ { 0X30000083, "TIMETICK" },
+ { 0X30000084, "WM_BTHCI_FTM " },
+ { 0X30000085, "WM_BT_PF" },
+ { 0X30000086, "IPA_IPC_APIS" },
+ { 0X30000087, "UKCC_IPC_APIS" },
+ { 0X30000088, "CMIPSMS " },
+ { 0X30000089, "VBATT_REMOTE" },
+ { 0X3000008a, "MFPAL" },
+ { 0X3000008b, "DSUMTSPDPREG" },
+ { 0X3000fe00, "RESTART_DAEMON NUMBER 0" },
+ { 0X3000fe01, "RESTART_DAEMON NUMBER 1" },
+ { 0X3000feff, "RESTART_DAEMON NUMBER 255" },
+ { 0X3000fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP" },
+ { 0X3000ffff, "RPC_ROUTER_SERVER_PROGRAM" },
+};
+
+#define ONCRPC_SYM 0
+
+static struct sym_tbl {
+ struct sym *data;
+ int size;
+ struct hlist_head hlist[HSIZE];
+} tbl[] = {
+ { oncrpc_syms, ARRAY_SIZE(oncrpc_syms) },
+};
+
+#define hash(val) (val % HSIZE)
+
+static void init_syms(void)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+ for (j = 0; j < HSIZE; ++j)
+ INIT_HLIST_HEAD(&tbl[i].hlist[j]);
+
+ for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+ for (j = 0; j < tbl[i].size; ++j) {
+ INIT_HLIST_NODE(&tbl[i].data[j].node);
+ hlist_add_head(&tbl[i].data[j].node,
+ &tbl[i].hlist[hash(tbl[i].data[j].val)]);
+ }
+}
+
+static char *find_sym(uint32_t id, uint32_t val)
+{
+ struct hlist_node *n;
+ struct sym *s;
+
+ hlist_for_each(n, &tbl[id].hlist[hash(val)]) {
+ s = hlist_entry(n, struct sym, node);
+ if (s->val == val)
+ return s->str;
+ }
+
+ return 0;
+}
+
+static int dump_servers(char *buf, int max)
+{
+ int i = 0;
+ unsigned long flags;
+ struct rr_server *svr;
+ char *sym;
+
+ spin_lock_irqsave(&server_list_lock, flags);
+ list_for_each_entry(svr, &server_list, list) {
+ i += scnprintf(buf + i, max - i, "pdev_name: %s\n",
+ svr->pdev_name);
+ i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", svr->pid);
+ i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", svr->cid);
+ i += scnprintf(buf + i, max - i, "prog: 0x%08x", svr->prog);
+ sym = find_sym(ONCRPC_SYM, svr->prog);
+ if (sym)
+ i += scnprintf(buf + i, max - i, " (%s)\n", sym);
+ else
+ i += scnprintf(buf + i, max - i, "\n");
+ i += scnprintf(buf + i, max - i, "vers: 0x%08x\n", svr->vers);
+ i += scnprintf(buf + i, max - i, "\n");
+ }
+ spin_unlock_irqrestore(&server_list_lock, flags);
+
+ return i;
+}
+
+static int dump_remote_endpoints(char *buf, int max)
+{
+ int i = 0;
+ unsigned long flags;
+ struct rr_remote_endpoint *ept;
+
+ spin_lock_irqsave(&remote_endpoints_lock, flags);
+ list_for_each_entry(ept, &remote_endpoints, list) {
+ i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
+ i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
+ i += scnprintf(buf + i, max - i, "tx_quota_cntr: %i\n",
+ ept->tx_quota_cntr);
+ i += scnprintf(buf + i, max - i, "quota_restart_state: %i\n",
+ ept->quota_restart_state);
+ i += scnprintf(buf + i, max - i, "\n");
+ }
+ spin_unlock_irqrestore(&remote_endpoints_lock, flags);
+
+ return i;
+}
+
+static int dump_msm_rpc_endpoint(char *buf, int max)
+{
+ int i = 0;
+ unsigned long flags;
+ struct msm_rpc_reply *reply;
+ struct msm_rpc_endpoint *ept;
+ struct rr_packet *pkt;
+ char *sym;
+
+ spin_lock_irqsave(&local_endpoints_lock, flags);
+ list_for_each_entry(ept, &local_endpoints, list) {
+ i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
+ i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
+ i += scnprintf(buf + i, max - i, "dst_pid: 0x%08x\n",
+ ept->dst_pid);
+ i += scnprintf(buf + i, max - i, "dst_cid: 0x%08x\n",
+ ept->dst_cid);
+ i += scnprintf(buf + i, max - i, "dst_prog: 0x%08x",
+ be32_to_cpu(ept->dst_prog));
+ sym = find_sym(ONCRPC_SYM, be32_to_cpu(ept->dst_prog));
+ if (sym)
+ i += scnprintf(buf + i, max - i, " (%s)\n", sym);
+ else
+ i += scnprintf(buf + i, max - i, "\n");
+ i += scnprintf(buf + i, max - i, "dst_vers: 0x%08x\n",
+ be32_to_cpu(ept->dst_vers));
+ i += scnprintf(buf + i, max - i, "reply_cnt: %i\n",
+ ept->reply_cnt);
+ i += scnprintf(buf + i, max - i, "restart_state: %i\n",
+ ept->restart_state);
+
+ i += scnprintf(buf + i, max - i, "outstanding xids:\n");
+ spin_lock(&ept->reply_q_lock);
+ list_for_each_entry(reply, &ept->reply_pend_q, list)
+ i += scnprintf(buf + i, max - i, " xid = %u\n",
+ ntohl(reply->xid));
+ spin_unlock(&ept->reply_q_lock);
+
+ i += scnprintf(buf + i, max - i, "complete unread packets:\n");
+ spin_lock(&ept->read_q_lock);
+ list_for_each_entry(pkt, &ept->read_q, list) {
+ i += scnprintf(buf + i, max - i, " mid = %i\n",
+ pkt->mid);
+ i += scnprintf(buf + i, max - i, " length = %i\n",
+ pkt->length);
+ }
+ spin_unlock(&ept->read_q_lock);
+ i += scnprintf(buf + i, max - i, "\n");
+ }
+ spin_unlock_irqrestore(&local_endpoints_lock, flags);
+
+ return i;
+}
+
+#define DEBUG_BUFMAX 4096
+static char debug_buffer[DEBUG_BUFMAX];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static void debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("smd_rpcrouter", 0);
+ if (IS_ERR(dent))
+ return;
+
+ debug_create("dump_msm_rpc_endpoints", 0444, dent,
+ dump_msm_rpc_endpoint);
+ debug_create("dump_remote_endpoints", 0444, dent,
+ dump_remote_endpoints);
+ debug_create("dump_servers", 0444, dent,
+ dump_servers);
+
+ init_syms();
+}
+
+#else
+static void debugfs_init(void) {}
+#endif
+
+
+static int __init rpcrouter_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&msm_smd_channel2_driver);
+ if (ret)
+ return ret;
+
+ debugfs_init();
+
+ return ret;
+}
+
+module_init(rpcrouter_init);
+MODULE_DESCRIPTION("MSM RPC Router");
+MODULE_AUTHOR("San Mehat <san@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_rpcrouter.h b/arch/arm/mach-msm/smd_rpcrouter.h
new file mode 100644
index 000000000000..fa5bc84267f7
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter.h
@@ -0,0 +1,210 @@
+/** arch/arm/mach-msm/smd_rpcrouter.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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 _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm_smd.h>
+#include <mach/msm_rpcrouter.h>
+
+/* definitions for the R2R wire protcol */
+
+#define RPCROUTER_VERSION 1
+#define RPCROUTER_PROCESSORS_MAX 4
+#define RPCROUTER_MSGSIZE_MAX 512
+#define RPCROUTER_PEND_REPLIES_MAX 32
+
+#define RPCROUTER_CLIENT_BCAST_ID 0xffffffff
+#define RPCROUTER_ROUTER_ADDRESS 0xfffffffe
+
+#define RPCROUTER_PID_LOCAL 1
+#define RPCROUTER_PID_REMOTE 0
+
+#define RPCROUTER_CTRL_CMD_DATA 1
+#define RPCROUTER_CTRL_CMD_HELLO 2
+#define RPCROUTER_CTRL_CMD_BYE 3
+#define RPCROUTER_CTRL_CMD_NEW_SERVER 4
+#define RPCROUTER_CTRL_CMD_REMOVE_SERVER 5
+#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT 6
+#define RPCROUTER_CTRL_CMD_RESUME_TX 7
+#define RPCROUTER_CTRL_CMD_EXIT 8
+#define RPCROUTER_CTRL_CMD_PING 9
+
+#define RPCROUTER_DEFAULT_RX_QUOTA 5
+
+union rr_control_msg {
+ uint32_t cmd;
+ struct {
+ uint32_t cmd;
+ uint32_t prog;
+ uint32_t vers;
+ uint32_t pid;
+ uint32_t cid;
+ } srv;
+ struct {
+ uint32_t cmd;
+ uint32_t pid;
+ uint32_t cid;
+ } cli;
+};
+
+struct rr_header {
+ uint32_t version;
+ uint32_t type;
+ uint32_t src_pid;
+ uint32_t src_cid;
+ uint32_t confirm_rx;
+ uint32_t size;
+ uint32_t dst_pid;
+ uint32_t dst_cid;
+};
+
+/* internals */
+
+#define RPCROUTER_MAX_REMOTE_SERVERS 100
+
+struct rr_fragment {
+ unsigned char data[RPCROUTER_MSGSIZE_MAX];
+ uint32_t length;
+ struct rr_fragment *next;
+};
+
+struct rr_packet {
+ struct list_head list;
+ struct rr_fragment *first;
+ struct rr_fragment *last;
+ struct rr_header hdr;
+ uint32_t mid;
+ uint32_t length;
+};
+
+#define PACMARK_LAST(n) ((n) & 0x80000000)
+#define PACMARK_MID(n) (((n) >> 16) & 0xFF)
+#define PACMARK_LEN(n) ((n) & 0xFFFF)
+
+static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first,
+ uint32_t last)
+{
+ return (len & 0xFFFF) |
+ ((mid & 0xFF) << 16) |
+ ((!!first) << 30) |
+ ((!!last) << 31);
+}
+
+struct rr_server {
+ struct list_head list;
+
+ uint32_t pid;
+ uint32_t cid;
+ uint32_t prog;
+ uint32_t vers;
+
+ dev_t device_number;
+ struct cdev cdev;
+ struct device *device;
+ struct rpcsvr_platform_device p_device;
+ char pdev_name[32];
+};
+
+struct rr_remote_endpoint {
+ uint32_t pid;
+ uint32_t cid;
+
+ int tx_quota_cntr;
+ int quota_restart_state;
+ spinlock_t quota_lock;
+ wait_queue_head_t quota_wait;
+
+ struct list_head list;
+};
+
+struct msm_rpc_reply {
+ struct list_head list;
+ uint32_t pid;
+ uint32_t cid;
+ uint32_t prog; /* be32 */
+ uint32_t vers; /* be32 */
+ uint32_t xid; /* be32 */
+};
+
+struct msm_rpc_endpoint {
+ struct list_head list;
+
+ /* incomplete packets waiting for assembly */
+ struct list_head incomplete;
+ spinlock_t incomplete_lock;
+
+ /* complete packets waiting to be read */
+ struct list_head read_q;
+ spinlock_t read_q_lock;
+ wait_queue_head_t wait_q;
+ unsigned flags;
+
+ /* restart handling */
+ int restart_state;
+ spinlock_t restart_lock;
+ wait_queue_head_t restart_wait;
+
+ /* endpoint address */
+ uint32_t pid;
+ uint32_t cid;
+
+ /* bound remote address
+ * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail
+ * RPC_CALLs must be to the prog/vers below or they will fail
+ */
+ uint32_t dst_pid;
+ uint32_t dst_cid;
+ uint32_t dst_prog; /* be32 */
+ uint32_t dst_vers; /* be32 */
+
+ /* reply queue for inbound messages */
+ struct list_head reply_pend_q;
+ struct list_head reply_avail_q;
+ spinlock_t reply_q_lock;
+ uint32_t reply_cnt;
+
+ /* device node if this endpoint is accessed via userspace */
+ dev_t dev;
+};
+
+/* shared between smd_rpcrouter*.c */
+
+int __msm_rpc_read(struct msm_rpc_endpoint *ept,
+ struct rr_fragment **frag,
+ unsigned len, long timeout);
+
+struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev);
+int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept);
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server);
+int msm_rpcrouter_create_server_pdev(struct rr_server *server);
+
+int msm_rpcrouter_init_devices(void);
+void msm_rpcrouter_exit_devices(void);
+
+void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid,
+ struct msm_rpc_client_info *clnt_info);
+
+extern dev_t msm_rpcrouter_devno;
+extern struct class *msm_rpcrouter_class;
+#endif
diff --git a/arch/arm/mach-msm/smd_rpcrouter_clients.c b/arch/arm/mach-msm/smd_rpcrouter_clients.c
new file mode 100644
index 000000000000..5baf79a7ae4b
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_clients.c
@@ -0,0 +1,607 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+
+/*
+ * SMD RPCROUTER CLIENTS module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+
+#include <mach/msm_rpcrouter.h>
+#include "smd_rpcrouter.h"
+
+struct msm_rpc_client_cb_item {
+ struct list_head list;
+
+ void *buf;
+ int size;
+};
+
+struct msm_rpc_cb_table_item {
+ struct list_head list;
+
+ uint32_t cb_id;
+ void *cb_func;
+};
+
+static int rpc_clients_cb_thread(void *data)
+{
+ struct msm_rpc_client_cb_item *cb_item;
+ struct msm_rpc_client *client;
+ struct rpc_request_hdr *req;
+
+ client = data;
+ for (;;) {
+ wait_event(client->cb_wait, client->cb_avail);
+ if (client->exit_flag)
+ break;
+
+ client->cb_avail = 0;
+ mutex_lock(&client->cb_item_list_lock);
+ while (!list_empty(&client->cb_item_list)) {
+ cb_item = list_first_entry(
+ &client->cb_item_list,
+ struct msm_rpc_client_cb_item,
+ list);
+ list_del(&cb_item->list);
+ mutex_unlock(&client->cb_item_list_lock);
+ req = (struct rpc_request_hdr *)cb_item->buf;
+
+ if (be32_to_cpu(req->type) != 0)
+ goto bad_rpc;
+ if (be32_to_cpu(req->rpc_vers) != 2)
+ goto bad_rpc;
+ if (be32_to_cpu(req->prog) !=
+ (client->prog | 0x01000000))
+ goto bad_rpc;
+
+ client->cb_func(client,
+ cb_item->buf, cb_item->size);
+ bad_rpc:
+ kfree(cb_item->buf);
+ kfree(cb_item);
+ mutex_lock(&client->cb_item_list_lock);
+ }
+ mutex_unlock(&client->cb_item_list_lock);
+ }
+ complete_and_exit(&client->cb_complete, 0);
+}
+
+static int rpc_clients_thread(void *data)
+{
+ void *buffer;
+ uint32_t type;
+ struct msm_rpc_client *client;
+ int rc = 0;
+ struct msm_rpc_client_cb_item *cb_item;
+ struct rpc_request_hdr *req;
+
+ client = data;
+ for (;;) {
+ rc = msm_rpc_read(client->ept, &buffer, -1, HZ);
+ if (client->exit_flag)
+ break;
+ if (rc < ((int)(sizeof(uint32_t) * 2)))
+ continue;
+
+ type = be32_to_cpu(*((uint32_t *)buffer + 1));
+ if (type == 1) {
+ client->buf = buffer;
+ client->read_avail = 1;
+ wake_up(&client->reply_wait);
+ } else if (type == 0) {
+ cb_item = kmalloc(sizeof(*cb_item), GFP_KERNEL);
+ if (!cb_item) {
+ pr_err("%s: no memory for cb item\n",
+ __func__);
+ continue;
+ }
+
+ if (client->cb_thread == NULL) {
+ req = (struct rpc_request_hdr *)buffer;
+
+ if ((be32_to_cpu(req->rpc_vers) == 2) &&
+ (be32_to_cpu(req->prog) ==
+ (client->prog | 0x01000000)))
+ client->cb_func(client, buffer, rc);
+ kfree(buffer);
+ } else {
+ INIT_LIST_HEAD(&cb_item->list);
+ cb_item->buf = buffer;
+ cb_item->size = rc;
+ mutex_lock(&client->cb_item_list_lock);
+ list_add_tail(&cb_item->list,
+ &client->cb_item_list);
+ mutex_unlock(&client->cb_item_list_lock);
+ client->cb_avail = 1;
+ wake_up(&client->cb_wait);
+ }
+ }
+ }
+ complete_and_exit(&client->complete, 0);
+}
+
+static struct msm_rpc_client *msm_rpc_create_client(void)
+{
+ struct msm_rpc_client *client;
+
+ client = kmalloc(sizeof(struct msm_rpc_client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->req = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+ if (!client->req) {
+ kfree(client);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ client->reply = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+ if (!client->reply) {
+ kfree(client->req);
+ kfree(client);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init_waitqueue_head(&client->reply_wait);
+ mutex_init(&client->req_lock);
+ mutex_init(&client->reply_lock);
+ client->buf = NULL;
+ client->read_avail = 0;
+ client->cb_buf = NULL;
+ client->cb_size = 0;
+ client->exit_flag = 0;
+ init_completion(&client->complete);
+ init_completion(&client->cb_complete);
+ INIT_LIST_HEAD(&client->cb_item_list);
+ mutex_init(&client->cb_item_list_lock);
+ client->cb_avail = 0;
+ init_waitqueue_head(&client->cb_wait);
+ INIT_LIST_HEAD(&client->cb_list);
+ mutex_init(&client->cb_list_lock);
+ atomic_set(&client->next_cb_id, 1);
+
+ return client;
+}
+
+void msm_rpc_remove_all_cb_func(struct msm_rpc_client *client)
+{
+ struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
+
+ mutex_lock(&client->cb_list_lock);
+ list_for_each_entry_safe(cb_item, tmp_cb_item,
+ &client->cb_list, list) {
+ list_del(&cb_item->list);
+ kfree(cb_item);
+ }
+ mutex_unlock(&client->cb_list_lock);
+}
+
+/*
+ * Interface to be used to register the client.
+ *
+ * name: string representing the client
+ *
+ * prog: program number of the client
+ *
+ * ver: version number of the client
+ *
+ * create_cb_thread: if set calls the callback function from a seprate thread
+ * which helps the client requests to be processed without
+ * getting loaded by callback handling.
+ *
+ * cb_func: function to be called if callback request is received.
+ * unmarshaling should be handled by the user in callback function
+ *
+ * Return Value:
+ * Pointer to initialized client data sturcture
+ * Or, the error code if registration fails.
+ *
+ */
+struct msm_rpc_client *msm_rpc_register_client(
+ const char *name,
+ uint32_t prog, uint32_t ver,
+ uint32_t create_cb_thread,
+ int (*cb_func)(struct msm_rpc_client *, void *, int))
+{
+ struct msm_rpc_client *client;
+ struct msm_rpc_endpoint *ept;
+ int rc;
+
+ client = msm_rpc_create_client();
+ if (IS_ERR(client))
+ return client;
+
+ ept = msm_rpc_connect_compatible(prog, ver, MSM_RPC_UNINTERRUPTIBLE);
+ if (IS_ERR(ept)) {
+ kfree(client);
+ return (struct msm_rpc_client *)ept;
+ }
+
+ client->prog = prog;
+ client->ver = ver;
+ client->ept = ept;
+ client->cb_func = cb_func;
+
+ /* start the read thread */
+ client->read_thread = kthread_run(rpc_clients_thread, client,
+ "k%sclntd", name);
+ if (IS_ERR(client->read_thread)) {
+ rc = PTR_ERR(client->read_thread);
+ msm_rpc_close(client->ept);
+ kfree(client);
+ return ERR_PTR(rc);
+ }
+
+ if (!create_cb_thread || (cb_func == NULL)) {
+ client->cb_thread = NULL;
+ return client;
+ }
+
+ /* start the callback thread */
+ client->cb_thread = kthread_run(rpc_clients_cb_thread, client,
+ "k%sclntcbd", name);
+ if (IS_ERR(client->cb_thread)) {
+ rc = PTR_ERR(client->cb_thread);
+ client->exit_flag = 1;
+ wait_for_completion(&client->complete);
+ msm_rpc_close(client->ept);
+ kfree(client);
+ return ERR_PTR(rc);
+ }
+
+ return client;
+}
+EXPORT_SYMBOL(msm_rpc_register_client);
+
+/*
+ * Interface to be used to unregister the client
+ * No client operations should be done once the unregister function
+ * is called.
+ *
+ * client: pointer to client data structure.
+ *
+ * Return Value:
+ * Always returns 0 (success).
+ */
+int msm_rpc_unregister_client(struct msm_rpc_client *client)
+{
+ pr_info("%s: stopping client...\n", __func__);
+ client->exit_flag = 1;
+ if (client->cb_thread) {
+ client->cb_avail = 1;
+ wake_up(&client->cb_wait);
+ wait_for_completion(&client->cb_complete);
+ }
+
+ wait_for_completion(&client->complete);
+
+ msm_rpc_close(client->ept);
+ msm_rpc_remove_all_cb_func(client);
+ kfree(client->req);
+ kfree(client->reply);
+ kfree(client);
+ return 0;
+}
+EXPORT_SYMBOL(msm_rpc_unregister_client);
+
+/*
+ * Interface to be used to send a client request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * client: pointer to client data sturcture
+ *
+ * proc: procedure being requested
+ *
+ * arg_func: argument function pointer. 'buf' is where arguments needs to
+ * be filled. 'data' is arg_data.
+ *
+ * ret_func: return function pointer. 'buf' is where returned data should
+ * be read from. 'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies. If negative timeout is
+ * specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ * 0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_client_req(struct msm_rpc_client *client, uint32_t proc,
+ int (*arg_func)(struct msm_rpc_client *client,
+ void *buf, void *data),
+ void *arg_data,
+ int (*ret_func)(struct msm_rpc_client *client,
+ void *buf, void *data),
+ void *ret_data, long timeout)
+{
+ int size = 0;
+ struct rpc_reply_hdr *rpc_rsp;
+ int rc = 0;
+
+ mutex_lock(&client->req_lock);
+
+ msm_rpc_setup_req((struct rpc_request_hdr *)client->req, client->prog,
+ client->ver, proc);
+ size = sizeof(struct rpc_request_hdr);
+
+ if (arg_func) {
+ rc = arg_func(client, (void *)((struct rpc_request_hdr *)
+ client->req + 1), arg_data);
+ if (rc < 0)
+ goto release_locks;
+ else
+ size += rc;
+ }
+
+ rc = msm_rpc_write(client->ept, client->req, size);
+ if (rc < 0) {
+ pr_err("%s: couldn't send RPC request:%d\n", __func__, rc);
+ goto release_locks;
+ } else
+ rc = 0;
+
+ if (timeout < 0)
+ timeout = msecs_to_jiffies(10000);
+
+ rc = wait_event_timeout(client->reply_wait,
+ client->read_avail, timeout);
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ goto release_locks;
+ } else
+ rc = 0;
+
+ client->read_avail = 0;
+
+ rpc_rsp = (struct rpc_reply_hdr *)client->buf;
+ if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+ pr_err("%s: RPC call was denied! %d\n", __func__,
+ be32_to_cpu(rpc_rsp->reply_stat));
+ rc = -EPERM;
+ goto free_and_release;
+ }
+
+ if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
+ RPC_ACCEPTSTAT_SUCCESS) {
+ pr_err("%s: RPC call was not successful (%d)\n", __func__,
+ be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
+ rc = -EINVAL;
+ goto free_and_release;
+ }
+
+ if (ret_func)
+ rc = ret_func(client, (void *)(rpc_rsp + 1), ret_data);
+
+ free_and_release:
+ kfree(client->buf);
+ release_locks:
+ mutex_unlock(&client->req_lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_client_req);
+
+/*
+ * Interface to be used to start accepted reply message required in
+ * callback handling. Returns the buffer pointer to attach any
+ * payload. Should call msm_rpc_send_accepted_reply to complete
+ * sending reply. Marshaling should be handled by user for the payload.
+ *
+ * client: pointer to client data structure
+ *
+ * xid: transaction id. Has to be same as the one in callback request.
+ *
+ * accept_status: acceptance status
+ *
+ * Return Value:
+ * pointer to buffer to attach the payload.
+ */
+void *msm_rpc_start_accepted_reply(struct msm_rpc_client *client,
+ uint32_t xid, uint32_t accept_status)
+{
+ struct rpc_reply_hdr *reply;
+
+ mutex_lock(&client->reply_lock);
+
+ reply = (struct rpc_reply_hdr *)client->reply;
+
+ reply->xid = cpu_to_be32(xid);
+ reply->type = cpu_to_be32(1); /* reply */
+ reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+ reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+ reply->data.acc_hdr.verf_flavor = 0;
+ reply->data.acc_hdr.verf_length = 0;
+
+ return reply + 1;
+}
+EXPORT_SYMBOL(msm_rpc_start_accepted_reply);
+
+/*
+ * Interface to be used to send accepted reply required in callback handling.
+ * msm_rpc_start_accepted_reply should have been called before.
+ * Marshaling should be handled by user for the payload.
+ *
+ * client: pointer to client data structure
+ *
+ * size: additional payload size
+ *
+ * Return Value:
+ * 0 on success, otherwise returns an error code.
+ */
+int msm_rpc_send_accepted_reply(struct msm_rpc_client *client, uint32_t size)
+{
+ int rc = 0;
+
+ size += sizeof(struct rpc_reply_hdr);
+ rc = msm_rpc_write(client->ept, client->reply, size);
+ if (rc > 0)
+ rc = 0;
+
+ mutex_unlock(&client->reply_lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_send_accepted_reply);
+
+/*
+ * Interface to be used to add a callback function.
+ * If the call back function is already in client's 'cb_id - cb_func'
+ * table, then that cb_id is returned. otherwise, new entry
+ * is added to the above table and corresponding cb_id is returned.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_func: callback function
+ *
+ * Return Value:
+ * callback ID on success, otherwise returns an error code.
+ * If cb_func is NULL, the callback Id returned is 0xffffffff.
+ * This tells the other processor that no callback is reqested.
+ */
+int msm_rpc_add_cb_func(struct msm_rpc_client *client, void *cb_func)
+{
+ struct msm_rpc_cb_table_item *cb_item;
+
+ if (cb_func == NULL)
+ return MSM_RPC_CLIENT_NULL_CB_ID;
+
+ mutex_lock(&client->cb_list_lock);
+ list_for_each_entry(cb_item, &client->cb_list, list) {
+ if (cb_item->cb_func == cb_func) {
+ mutex_unlock(&client->cb_list_lock);
+ return cb_item->cb_id;
+ }
+ }
+ mutex_unlock(&client->cb_list_lock);
+
+ cb_item = kmalloc(sizeof(struct msm_rpc_cb_table_item), GFP_KERNEL);
+ if (!cb_item)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&cb_item->list);
+ cb_item->cb_id = atomic_add_return(1, &client->next_cb_id);
+ cb_item->cb_func = cb_func;
+
+ mutex_lock(&client->cb_list_lock);
+ list_add_tail(&cb_item->list, &client->cb_list);
+ mutex_unlock(&client->cb_list_lock);
+
+ return cb_item->cb_id;
+}
+EXPORT_SYMBOL(msm_rpc_add_cb_func);
+
+/*
+ * Interface to be used to get a callback function from a callback ID.
+ * If no entry is found, NULL is returned.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_id: callback ID
+ *
+ * Return Value:
+ * callback function pointer if entry with given cb_id is found,
+ * otherwise returns NULL.
+ */
+void *msm_rpc_get_cb_func(struct msm_rpc_client *client, uint32_t cb_id)
+{
+ struct msm_rpc_cb_table_item *cb_item;
+
+ mutex_lock(&client->cb_list_lock);
+ list_for_each_entry(cb_item, &client->cb_list, list) {
+ if (cb_item->cb_id == cb_id) {
+ mutex_unlock(&client->cb_list_lock);
+ return cb_item->cb_func;
+ }
+ }
+ mutex_unlock(&client->cb_list_lock);
+ return NULL;
+}
+EXPORT_SYMBOL(msm_rpc_get_cb_func);
+
+/*
+ * Interface to be used to remove a callback function.
+ *
+ * client: pointer to client data structure
+ *
+ * cb_func: callback function
+ *
+ */
+void msm_rpc_remove_cb_func(struct msm_rpc_client *client, void *cb_func)
+{
+ struct msm_rpc_cb_table_item *cb_item, *tmp_cb_item;
+
+ if (cb_func == NULL)
+ return;
+
+ mutex_lock(&client->cb_list_lock);
+ list_for_each_entry_safe(cb_item, tmp_cb_item,
+ &client->cb_list, list) {
+ if (cb_item->cb_func == cb_func) {
+ list_del(&cb_item->list);
+ kfree(cb_item);
+ mutex_unlock(&client->cb_list_lock);
+ return;
+ }
+ }
+ mutex_unlock(&client->cb_list_lock);
+}
+EXPORT_SYMBOL(msm_rpc_remove_cb_func);
diff --git a/arch/arm/mach-msm/smd_rpcrouter_device.c b/arch/arm/mach-msm/smd_rpcrouter_device.c
new file mode 100644
index 000000000000..b57746cbf392
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_device.c
@@ -0,0 +1,380 @@
+/* arch/arm/mach-msm/smd_rpcrouter_device.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Author: San Mehat <san@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/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+#include "smd_rpcrouter.h"
+
+#define SAFETY_MEM_SIZE 65536
+
+/* Next minor # available for a remote server */
+static int next_minor = 1;
+
+struct class *msm_rpcrouter_class;
+dev_t msm_rpcrouter_devno;
+
+static struct cdev rpcrouter_cdev;
+static struct device *rpcrouter_device;
+
+static int rpcrouter_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+ struct msm_rpc_endpoint *ept;
+
+ rc = nonseekable_open(inode, filp);
+ if (rc < 0)
+ return rc;
+
+ ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
+ if (!ept)
+ return -ENOMEM;
+
+ filp->private_data = ept;
+ return 0;
+}
+
+static int rpcrouter_release(struct inode *inode, struct file *filp)
+{
+ struct msm_rpc_endpoint *ept;
+ static unsigned int rpcrouter_release_cnt;
+
+ ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+ /* A user program with many files open when ends abruptly,
+ * will cause a flood of REMOVE_CLIENT messages to the
+ * remote processor. This will cause remote processors
+ * internal queue to overflow. Inserting a sleep here
+ * regularly is the effecient option.
+ */
+ if (rpcrouter_release_cnt++ % 2)
+ msleep(1);
+
+ return msm_rpcrouter_destroy_local_endpoint(ept);
+}
+
+static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_rpc_endpoint *ept;
+ struct rr_fragment *frag, *next;
+ int rc;
+
+ ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+ rc = __msm_rpc_read(ept, &frag, count, -1);
+ if (rc < 0)
+ return rc;
+
+ count = rc;
+
+ while (frag != NULL) {
+ if (copy_to_user(buf, frag->data, frag->length)) {
+ printk(KERN_ERR
+ "rpcrouter: could not copy all read data to user!\n");
+ rc = -EFAULT;
+ }
+ buf += frag->length;
+ next = frag->next;
+ kfree(frag);
+ frag = next;
+ }
+
+ return rc;
+}
+
+static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct msm_rpc_endpoint *ept;
+ int rc = 0;
+ void *k_buffer;
+
+ ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+ /* A check for safety, this seems non-standard */
+ if (count > SAFETY_MEM_SIZE)
+ return -EINVAL;
+
+ k_buffer = kmalloc(count, GFP_KERNEL);
+ if (!k_buffer)
+ return -ENOMEM;
+
+ if (copy_from_user(k_buffer, buf, count)) {
+ rc = -EFAULT;
+ goto write_out_free;
+ }
+
+ rc = msm_rpc_write(ept, k_buffer, count);
+ if (rc < 0)
+ goto write_out_free;
+
+ rc = count;
+write_out_free:
+ kfree(k_buffer);
+ return rc;
+}
+
+static unsigned int rpcrouter_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct msm_rpc_endpoint *ept;
+ unsigned mask = 0;
+ ept = (struct msm_rpc_endpoint *) filp->private_data;
+
+ /* If there's data already in the read queue, return POLLIN.
+ * Else, wait for the requested amount of time, and check again.
+ */
+
+ if (!list_empty(&ept->read_q))
+ mask |= POLLIN;
+ if (ept->restart_state != 0)
+ mask |= POLLERR;
+
+ if (!mask) {
+ poll_wait(filp, &ept->wait_q, wait);
+ if (!list_empty(&ept->read_q))
+ mask |= POLLIN;
+ if (ept->restart_state != 0)
+ mask |= POLLERR;
+ }
+
+ return mask;
+}
+
+static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct msm_rpc_endpoint *ept;
+ struct rpcrouter_ioctl_server_args server_args;
+ int rc = 0;
+ uint32_t n;
+
+ ept = (struct msm_rpc_endpoint *) filp->private_data;
+ switch (cmd) {
+
+ case RPC_ROUTER_IOCTL_GET_VERSION:
+ n = RPC_ROUTER_VERSION_V1;
+ rc = put_user(n, (unsigned int *) arg);
+ break;
+
+ case RPC_ROUTER_IOCTL_GET_MTU:
+ /* the pacmark word reduces the actual payload
+ * possible per message
+ */
+ n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
+ rc = put_user(n, (unsigned int *) arg);
+ break;
+
+ case RPC_ROUTER_IOCTL_REGISTER_SERVER:
+ rc = copy_from_user(&server_args, (void *) arg,
+ sizeof(server_args));
+ if (rc < 0)
+ break;
+ msm_rpc_register_server(ept,
+ server_args.prog,
+ server_args.vers);
+ break;
+
+ case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
+ rc = copy_from_user(&server_args, (void *) arg,
+ sizeof(server_args));
+ if (rc < 0)
+ break;
+
+ msm_rpc_unregister_server(ept,
+ server_args.prog,
+ server_args.vers);
+ break;
+
+ case RPC_ROUTER_IOCTL_CLEAR_NETRESET:
+ msm_rpc_clear_netreset(ept);
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static struct file_operations rpcrouter_server_fops = {
+ .owner = THIS_MODULE,
+ .open = rpcrouter_open,
+ .release = rpcrouter_release,
+ .read = rpcrouter_read,
+ .write = rpcrouter_write,
+ .poll = rpcrouter_poll,
+ .unlocked_ioctl = rpcrouter_ioctl,
+};
+
+static struct file_operations rpcrouter_router_fops = {
+ .owner = THIS_MODULE,
+ .open = rpcrouter_open,
+ .release = rpcrouter_release,
+ .read = rpcrouter_read,
+ .write = rpcrouter_write,
+ .poll = rpcrouter_poll,
+ .unlocked_ioctl = rpcrouter_ioctl,
+};
+
+int msm_rpcrouter_create_server_cdev(struct rr_server *server)
+{
+ int rc;
+ uint32_t dev_vers;
+
+ if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
+ printk(KERN_ERR
+ "rpcrouter: Minor numbers exhausted - Increase "
+ "RPCROUTER_MAX_REMOTE_SERVERS\n");
+ return -ENOBUFS;
+ }
+
+ /* Servers with bit 31 set are remote msm servers with hashkey version.
+ * Servers with bit 31 not set are remote msm servers with
+ * backwards compatible version type in which case the minor number
+ * (lower 16 bits) is set to zero.
+ *
+ */
+ if ((server->vers & 0x80000000))
+ dev_vers = server->vers;
+ else
+ dev_vers = server->vers & 0xffff0000;
+
+ server->device_number =
+ MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
+
+ server->device =
+ device_create(msm_rpcrouter_class, rpcrouter_device,
+ server->device_number, NULL, "%.8x:%.8x",
+ server->prog, dev_vers);
+ if (IS_ERR(server->device)) {
+ printk(KERN_ERR
+ "rpcrouter: Unable to create device (%ld)\n",
+ PTR_ERR(server->device));
+ return PTR_ERR(server->device);;
+ }
+
+ cdev_init(&server->cdev, &rpcrouter_server_fops);
+ server->cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&server->cdev, server->device_number, 1);
+ if (rc < 0) {
+ printk(KERN_ERR
+ "rpcrouter: Unable to add chrdev (%d)\n", rc);
+ device_destroy(msm_rpcrouter_class, server->device_number);
+ return rc;
+ }
+ return 0;
+}
+
+/* for backward compatible version type (31st bit cleared)
+ * clearing minor number (lower 16 bits) in device name
+ * is neccessary for driver binding
+ */
+int msm_rpcrouter_create_server_pdev(struct rr_server *server)
+{
+ sprintf(server->pdev_name, "rs%.8x:%.8x",
+ server->prog,
+ (server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
+ (server->vers & RPC_VERSION_MAJOR_MASK));
+
+ server->p_device.base.id = -1;
+ server->p_device.base.name = server->pdev_name;
+
+ server->p_device.prog = server->prog;
+ server->p_device.vers = server->vers;
+
+ platform_device_register(&server->p_device.base);
+ return 0;
+}
+
+int msm_rpcrouter_init_devices(void)
+{
+ int rc;
+ int major;
+
+ /* Create the device nodes */
+ msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
+ if (IS_ERR(msm_rpcrouter_class)) {
+ rc = -ENOMEM;
+ printk(KERN_ERR
+ "rpcrouter: failed to create oncrpc class\n");
+ goto fail;
+ }
+
+ rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
+ RPCROUTER_MAX_REMOTE_SERVERS + 1,
+ "oncrpc");
+ if (rc < 0) {
+ printk(KERN_ERR
+ "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
+ goto fail_destroy_class;
+ }
+
+ major = MAJOR(msm_rpcrouter_devno);
+ rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
+ msm_rpcrouter_devno, NULL, "%.8x:%d",
+ 0, 0);
+ if (IS_ERR(rpcrouter_device)) {
+ rc = -ENOMEM;
+ goto fail_unregister_cdev_region;
+ }
+
+ cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
+ rpcrouter_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
+ if (rc < 0)
+ goto fail_destroy_device;
+
+ return 0;
+
+fail_destroy_device:
+ device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+fail_unregister_cdev_region:
+ unregister_chrdev_region(msm_rpcrouter_devno,
+ RPCROUTER_MAX_REMOTE_SERVERS + 1);
+fail_destroy_class:
+ class_destroy(msm_rpcrouter_class);
+fail:
+ return rc;
+}
+
+void msm_rpcrouter_exit_devices(void)
+{
+ cdev_del(&rpcrouter_cdev);
+ device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
+ unregister_chrdev_region(msm_rpcrouter_devno,
+ RPCROUTER_MAX_REMOTE_SERVERS + 1);
+ class_destroy(msm_rpcrouter_class);
+}
+
diff --git a/arch/arm/mach-msm/smd_rpcrouter_servers.c b/arch/arm/mach-msm/smd_rpcrouter_servers.c
new file mode 100644
index 000000000000..eb74f50c79b4
--- /dev/null
+++ b/arch/arm/mach-msm/smd_rpcrouter_servers.c
@@ -0,0 +1,434 @@
+/* arch/arm/mach-msm/rpc_servers.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Author: Iliyan Malchev <ibm@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/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdev.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/uaccess.h>
+
+#include <mach/msm_rpcrouter.h>
+#include "smd_rpcrouter.h"
+
+static struct msm_rpc_endpoint *endpoint;
+
+#define FLAG_REGISTERED 0x0001
+
+static LIST_HEAD(rpc_server_list);
+static DEFINE_MUTEX(rpc_server_list_lock);
+static int rpc_servers_active;
+static uint32_t current_xid;
+
+static void rpc_server_register(struct msm_rpc_server *server)
+{
+ int rc;
+ rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
+ if (rc < 0)
+ printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
+ server, server->prog, server->vers);
+}
+
+static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
+{
+ struct msm_rpc_server *server;
+
+ mutex_lock(&rpc_server_list_lock);
+ list_for_each_entry(server, &rpc_server_list, list) {
+ if ((server->prog == prog) &&
+ msm_rpc_is_compatible_version(server->vers, vers)) {
+ mutex_unlock(&rpc_server_list_lock);
+ return server;
+ }
+ }
+ mutex_unlock(&rpc_server_list_lock);
+ return NULL;
+}
+
+static void rpc_server_register_all(void)
+{
+ struct msm_rpc_server *server;
+
+ mutex_lock(&rpc_server_list_lock);
+ list_for_each_entry(server, &rpc_server_list, list) {
+ if (!(server->flags & FLAG_REGISTERED)) {
+ rpc_server_register(server);
+ server->flags |= FLAG_REGISTERED;
+ }
+ }
+ mutex_unlock(&rpc_server_list_lock);
+}
+
+int msm_rpc_create_server(struct msm_rpc_server *server)
+{
+ /* make sure we're in a sane state first */
+ server->flags = 0;
+ INIT_LIST_HEAD(&server->list);
+ mutex_init(&server->cb_req_lock);
+ mutex_init(&server->reply_lock);
+
+ server->reply = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+ if (!server->reply)
+ return -ENOMEM;
+
+ server->cb_req = kmalloc(MSM_RPC_MSGSIZE_MAX, GFP_KERNEL);
+ if (!server->cb_req) {
+ kfree(server->reply);
+ return -ENOMEM;
+ }
+
+ server->cb_ept = msm_rpc_open();
+ if (IS_ERR(server->cb_ept)) {
+ kfree(server->reply);
+ kfree(server->cb_req);
+ return PTR_ERR(server->cb_ept);
+ }
+
+ server->cb_ept->flags = MSM_RPC_UNINTERRUPTIBLE;
+ server->cb_ept->dst_prog = cpu_to_be32(server->prog | 0x01000000);
+ server->cb_ept->dst_vers = cpu_to_be32(server->vers);
+
+ mutex_lock(&rpc_server_list_lock);
+ list_add(&server->list, &rpc_server_list);
+ if (rpc_servers_active) {
+ rpc_server_register(server);
+ server->flags |= FLAG_REGISTERED;
+ }
+ mutex_unlock(&rpc_server_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_rpc_create_server);
+
+static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
+ uint32_t xid, uint32_t accept_status)
+{
+ int rc = 0;
+ uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
+ struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
+
+ reply->xid = cpu_to_be32(xid);
+ reply->type = cpu_to_be32(1); /* reply */
+ reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+ reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+ reply->data.acc_hdr.verf_flavor = 0;
+ reply->data.acc_hdr.verf_length = 0;
+
+ rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
+ if (rc == -ENETRESET) {
+ /* Modem restarted, drop reply, clear state */
+ msm_rpc_clear_netreset(client);
+ }
+ if (rc < 0)
+ printk(KERN_ERR
+ "%s: could not write response: %d\n",
+ __FUNCTION__, rc);
+
+ return rc;
+}
+
+/*
+ * Interface to be used to start accepted reply message for a
+ * request. Returns the buffer pointer to attach any payload.
+ * Should call msm_rpc_server_send_accepted_reply to complete sending
+ * reply. Marshaling should be handled by user for the payload.
+ *
+ * server: pointer to server data structure
+ *
+ * xid: transaction id. Has to be same as the one in request.
+ *
+ * accept_status: acceptance status
+ *
+ * Return Value:
+ * pointer to buffer to attach the payload.
+ */
+void *msm_rpc_server_start_accepted_reply(struct msm_rpc_server *server,
+ uint32_t xid, uint32_t accept_status)
+{
+ struct rpc_reply_hdr *reply;
+
+ mutex_lock(&server->reply_lock);
+
+ reply = (struct rpc_reply_hdr *)server->reply;
+
+ reply->xid = cpu_to_be32(xid);
+ reply->type = cpu_to_be32(1); /* reply */
+ reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
+
+ reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
+ reply->data.acc_hdr.verf_flavor = 0;
+ reply->data.acc_hdr.verf_length = 0;
+
+ return reply + 1;
+}
+EXPORT_SYMBOL(msm_rpc_server_start_accepted_reply);
+
+/*
+ * Interface to be used to send accepted reply for a request.
+ * msm_rpc_server_start_accepted_reply should have been called before.
+ * Marshaling should be handled by user for the payload.
+ *
+ * server: pointer to server data structure
+ *
+ * size: additional payload size
+ *
+ * Return Value:
+ * 0 on success, otherwise returns an error code.
+ */
+int msm_rpc_server_send_accepted_reply(struct msm_rpc_server *server,
+ uint32_t size)
+{
+ int rc = 0;
+
+ size += sizeof(struct rpc_reply_hdr);
+ rc = msm_rpc_write(endpoint, server->reply, size);
+ if (rc > 0)
+ rc = 0;
+
+ mutex_unlock(&server->reply_lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_server_send_accepted_reply);
+
+/*
+ * Interface to be used to send a server callback request.
+ * If the request takes any arguments or expects any return, the user
+ * should handle it in 'arg_func' and 'ret_func' respectively.
+ * Marshaling and Unmarshaling should be handled by the user in argument
+ * and return functions.
+ *
+ * server: pointer to server data sturcture
+ *
+ * clnt_info: pointer to client information data structure.
+ * callback will be sent to this client.
+ *
+ * cb_proc: callback procedure being requested
+ *
+ * arg_func: argument function pointer. 'buf' is where arguments needs to
+ * be filled. 'data' is arg_data.
+ *
+ * ret_func: return function pointer. 'buf' is where returned data should
+ * be read from. 'data' is ret_data.
+ *
+ * arg_data: passed as an input parameter to argument function.
+ *
+ * ret_data: passed as an input parameter to return function.
+ *
+ * timeout: timeout for reply wait in jiffies. If negative timeout is
+ * specified a default timeout of 10s is used.
+ *
+ * Return Value:
+ * 0 on success, otherwise an error code is returned.
+ */
+int msm_rpc_server_cb_req(struct msm_rpc_server *server,
+ struct msm_rpc_client_info *clnt_info,
+ uint32_t cb_proc,
+ int (*arg_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *arg_data,
+ int (*ret_func)(struct msm_rpc_server *server,
+ void *buf, void *data),
+ void *ret_data, long timeout)
+{
+ int size = 0;
+ struct rpc_reply_hdr *rpc_rsp;
+ void *buffer;
+ int rc = 0;
+
+ if (!clnt_info)
+ return -EINVAL;
+
+ mutex_lock(&server->cb_req_lock);
+
+ msm_rpc_setup_req((struct rpc_request_hdr *)server->cb_req,
+ (server->prog | 0x01000000),
+ be32_to_cpu(clnt_info->vers), cb_proc);
+ size = sizeof(struct rpc_request_hdr);
+
+ if (arg_func) {
+ rc = arg_func(server, (void *)((struct rpc_request_hdr *)
+ server->cb_req + 1), arg_data);
+ if (rc < 0)
+ goto release_locks;
+ else
+ size += rc;
+ }
+
+ server->cb_ept->dst_pid = clnt_info->pid;
+ server->cb_ept->dst_cid = clnt_info->cid;
+ rc = msm_rpc_write(server->cb_ept, server->cb_req, size);
+ if (rc < 0) {
+ pr_err("%s: couldn't send RPC CB request:%d\n", __func__, rc);
+ goto release_locks;
+ } else
+ rc = 0;
+
+ if (timeout < 0)
+ timeout = msecs_to_jiffies(10000);
+
+ rc = msm_rpc_read(server->cb_ept, &buffer, -1, timeout);
+ if ((rc < ((int)(sizeof(uint32_t) * 2))) ||
+ (be32_to_cpu(*((uint32_t *)buffer + 1)) != 1)) {
+ printk(KERN_ERR "%s: could not read: %d\n", __func__, rc);
+ kfree(buffer);
+ goto free_and_release;
+ } else
+ rc = 0;
+
+ rpc_rsp = (struct rpc_reply_hdr *)buffer;
+
+ if (be32_to_cpu(rpc_rsp->reply_stat) != RPCMSG_REPLYSTAT_ACCEPTED) {
+ pr_err("%s: RPC cb req was denied! %d\n", __func__,
+ be32_to_cpu(rpc_rsp->reply_stat));
+ rc = -EPERM;
+ goto free_and_release;
+ }
+
+ if (be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat) !=
+ RPC_ACCEPTSTAT_SUCCESS) {
+ pr_err("%s: RPC cb req was not successful (%d)\n", __func__,
+ be32_to_cpu(rpc_rsp->data.acc_hdr.accept_stat));
+ rc = -EINVAL;
+ goto free_and_release;
+ }
+
+ if (ret_func)
+ rc = ret_func(server, (void *)(rpc_rsp + 1), ret_data);
+
+free_and_release:
+ kfree(buffer);
+release_locks:
+ mutex_unlock(&server->cb_req_lock);
+ return rc;
+}
+EXPORT_SYMBOL(msm_rpc_server_cb_req);
+
+void msm_rpc_server_get_requesting_client(struct msm_rpc_client_info *clnt_info)
+{
+ if (!clnt_info)
+ return;
+
+ get_requesting_client(endpoint, current_xid, clnt_info);
+}
+
+static int rpc_servers_thread(void *data)
+{
+ void *buffer;
+ struct rpc_request_hdr *req;
+ struct msm_rpc_server *server;
+ int rc;
+
+ for (;;) {
+ rc = wait_event_interruptible(endpoint->wait_q,
+ !list_empty(&endpoint->read_q));
+ rc = msm_rpc_read(endpoint, &buffer, -1, -1);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: could not read: %d\n",
+ __FUNCTION__, rc);
+ break;
+ }
+
+ req = (struct rpc_request_hdr *)buffer;
+
+ current_xid = req->xid;
+
+ req->type = be32_to_cpu(req->type);
+ req->xid = be32_to_cpu(req->xid);
+ req->rpc_vers = be32_to_cpu(req->rpc_vers);
+ req->prog = be32_to_cpu(req->prog);
+ req->vers = be32_to_cpu(req->vers);
+ req->procedure = be32_to_cpu(req->procedure);
+
+ server = rpc_server_find(req->prog, req->vers);
+
+ if (req->rpc_vers != 2)
+ continue;
+ if (req->type != 0)
+ continue;
+ if (!server) {
+ rpc_send_accepted_void_reply(
+ endpoint, req->xid,
+ RPC_ACCEPTSTAT_PROG_UNAVAIL);
+ continue;
+ }
+
+ rc = server->rpc_call(server, req, rc);
+
+ if (rc == 0) {
+ msm_rpc_server_start_accepted_reply(
+ server, req->xid,
+ RPC_ACCEPTSTAT_SUCCESS);
+ msm_rpc_server_send_accepted_reply(server, 0);
+ } else if (rc < 0) {
+ msm_rpc_server_start_accepted_reply(
+ server, req->xid,
+ RPC_ACCEPTSTAT_PROC_UNAVAIL);
+ msm_rpc_server_send_accepted_reply(server, 0);
+ }
+ kfree(buffer);
+ }
+ do_exit(0);
+}
+
+static int rpcservers_probe(struct platform_device *pdev)
+{
+ struct task_struct *server_thread;
+
+ endpoint = msm_rpc_open();
+ if (IS_ERR(endpoint))
+ return PTR_ERR(endpoint);
+
+ /* we're online -- register any servers installed beforehand */
+ rpc_servers_active = 1;
+ current_xid = 0;
+ rpc_server_register_all();
+
+ /* start the kernel thread */
+ server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
+ if (IS_ERR(server_thread))
+ return PTR_ERR(server_thread);
+
+ return 0;
+}
+
+static struct platform_driver rpcservers_driver = {
+ .probe = rpcservers_probe,
+ .driver = {
+ .name = "oncrpc_router",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init rpc_servers_init(void)
+{
+ return platform_driver_register(&rpcservers_driver);
+}
+
+module_init(rpc_servers_init);
+
+MODULE_DESCRIPTION("MSM RPC Servers");
+MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
new file mode 100644
index 000000000000..d4272faff974
--- /dev/null
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -0,0 +1,284 @@
+/* arch/arm/mach-msm/smd_tty.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <mach/msm_smd.h>
+#include "smd_private.h"
+
+#define MAX_SMD_TTYS 37
+
+static DEFINE_MUTEX(smd_tty_lock);
+
+struct smd_tty_info {
+ smd_channel_t *ch;
+ struct tty_struct *tty;
+ int open_count;
+ struct work_struct tty_work;
+};
+
+static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
+static struct workqueue_struct *smd_tty_wq;
+
+static void smd_tty_work_func(struct work_struct *work)
+{
+ unsigned char *ptr;
+ int avail;
+ struct smd_tty_info *info = container_of(work,
+ struct smd_tty_info,
+ tty_work);
+ struct tty_struct *tty = info->tty;
+
+ if (!tty)
+ return;
+
+ for (;;) {
+ if (test_bit(TTY_THROTTLED, &tty->flags)) break;
+
+ mutex_lock(&smd_tty_lock);
+ if (info->ch == 0) {
+ mutex_unlock(&smd_tty_lock);
+ break;
+ }
+
+ avail = smd_read_avail(info->ch);
+ if (avail == 0) {
+ mutex_unlock(&smd_tty_lock);
+ break;
+ }
+
+ avail = tty_prepare_flip_string(tty, &ptr, avail);
+
+ if (smd_read(info->ch, ptr, avail) != avail) {
+ /* shouldn't be possible since we're in interrupt
+ ** context here and nobody else could 'steal' our
+ ** characters.
+ */
+ printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
+ }
+ mutex_unlock(&smd_tty_lock);
+
+ tty_flip_buffer_push(tty);
+ }
+
+ /* XXX only when writable and necessary */
+ tty_wakeup(tty);
+}
+
+static void smd_tty_notify(void *priv, unsigned event)
+{
+ struct smd_tty_info *info = priv;
+
+ if (event != SMD_EVENT_DATA)
+ return;
+
+ queue_work(smd_tty_wq, &info->tty_work);
+}
+
+static int smd_tty_open(struct tty_struct *tty, struct file *f)
+{
+ int res = 0;
+ int n = tty->index;
+ struct smd_tty_info *info;
+ const char *name;
+
+ if (n == 0)
+ name = "DS";
+ else if (n == 7)
+ name = "DATA1";
+ else if (n == 21)
+ name = "DATA21";
+ else if (n == 27)
+ name = "GPSNMEA";
+ else if (n == 36)
+ name = "LOOPBACK";
+ else
+ return -ENODEV;
+
+ info = smd_tty + n;
+
+ mutex_lock(&smd_tty_lock);
+ tty->driver_data = info;
+
+ if (info->open_count++ == 0) {
+ info->tty = tty;
+ if (!info->ch) {
+ if (n == 36) {
+ /* set smsm state to SMSM_SMD_LOOPBACK state
+ ** and wait allowing enough time for Modem side
+ ** to open the loopback port (Currently, this is
+ ** this is effecient than polling).
+ */
+ smsm_change_state(SMSM_APPS_STATE,
+ 0, SMSM_SMD_LOOPBACK);
+ msleep(100);
+ } else if ((n == 0) || (n == 7))
+ tty->low_latency = 1;
+
+ res = smd_open(name, &info->ch, info,
+ smd_tty_notify);
+ }
+ }
+ mutex_unlock(&smd_tty_lock);
+
+ return res;
+}
+
+static void smd_tty_close(struct tty_struct *tty, struct file *f)
+{
+ struct smd_tty_info *info = tty->driver_data;
+
+ if (info == 0)
+ return;
+
+ mutex_lock(&smd_tty_lock);
+ if (--info->open_count == 0) {
+ info->tty = 0;
+ tty->driver_data = 0;
+ if (info->ch) {
+ smd_close(info->ch);
+ info->ch = 0;
+ }
+ }
+ mutex_unlock(&smd_tty_lock);
+}
+
+static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
+{
+ struct smd_tty_info *info = tty->driver_data;
+ int avail;
+
+ /* if we're writing to a packet channel we will
+ ** never be able to write more data than there
+ ** is currently space for
+ */
+ avail = smd_write_avail(info->ch);
+ if (len > avail)
+ len = avail;
+
+ return smd_write(info->ch, buf, len);
+}
+
+static int smd_tty_write_room(struct tty_struct *tty)
+{
+ struct smd_tty_info *info = tty->driver_data;
+ return smd_write_avail(info->ch);
+}
+
+static int smd_tty_chars_in_buffer(struct tty_struct *tty)
+{
+ struct smd_tty_info *info = tty->driver_data;
+ return smd_read_avail(info->ch);
+}
+
+static void smd_tty_unthrottle(struct tty_struct *tty)
+{
+ struct smd_tty_info *info = tty->driver_data;
+ queue_work(smd_tty_wq, &info->tty_work);
+ return;
+}
+
+static int smd_tty_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct smd_tty_info *info = tty->driver_data;
+
+ return smd_tiocmget(info->ch);
+}
+
+static int smd_tty_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct smd_tty_info *info = tty->driver_data;
+
+ return smd_tiocmset(info->ch, set, clear);
+}
+
+static struct tty_operations smd_tty_ops = {
+ .open = smd_tty_open,
+ .close = smd_tty_close,
+ .write = smd_tty_write,
+ .write_room = smd_tty_write_room,
+ .chars_in_buffer = smd_tty_chars_in_buffer,
+ .unthrottle = smd_tty_unthrottle,
+ .tiocmget = smd_tty_tiocmget,
+ .tiocmset = smd_tty_tiocmset,
+};
+
+static struct tty_driver *smd_tty_driver;
+
+static int __init smd_tty_init(void)
+{
+ int ret;
+
+ smd_tty_wq = create_singlethread_workqueue("smd_tty");
+ if (smd_tty_wq == 0)
+ return -ENOMEM;
+
+ smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
+ if (smd_tty_driver == 0) {
+ destroy_workqueue(smd_tty_wq);
+ return -ENOMEM;
+ }
+
+ smd_tty_driver->owner = THIS_MODULE;
+ smd_tty_driver->driver_name = "smd_tty_driver";
+ smd_tty_driver->name = "smd";
+ smd_tty_driver->major = 0;
+ smd_tty_driver->minor_start = 0;
+ smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+ smd_tty_driver->init_termios = tty_std_termios;
+ smd_tty_driver->init_termios.c_iflag = 0;
+ smd_tty_driver->init_termios.c_oflag = 0;
+ smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+ smd_tty_driver->init_termios.c_lflag = 0;
+ smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+ TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(smd_tty_driver, &smd_tty_ops);
+
+ ret = tty_register_driver(smd_tty_driver);
+ if (ret) return ret;
+
+ /* this should be dynamic */
+ tty_register_device(smd_tty_driver, 0, 0);
+ INIT_WORK(&smd_tty[0].tty_work, smd_tty_work_func);
+
+ tty_register_device(smd_tty_driver, 7, 0);
+ INIT_WORK(&smd_tty[7].tty_work, smd_tty_work_func);
+
+ tty_register_device(smd_tty_driver, 27, 0);
+ INIT_WORK(&smd_tty[27].tty_work, smd_tty_work_func);
+
+ tty_register_device(smd_tty_driver, 36, 0);
+ INIT_WORK(&smd_tty[36].tty_work, smd_tty_work_func);
+
+ tty_register_device(smd_tty_driver, 21, 0);
+ INIT_WORK(&smd_tty[21].tty_work, smd_tty_work_func);
+
+ return 0;
+}
+
+module_init(smd_tty_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
new file mode 100644
index 000000000000..c2809109fc62
--- /dev/null
+++ b/arch/arm/mach-msm/smem_log.c
@@ -0,0 +1,2024 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * Shared memory logging implementation.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/remote_spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/string.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/smem_log.h>
+
+#include "smd_private.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define D_DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+ int i; \
+ printk(KERN_ERR "%s", prestr); \
+ for (i = 0; i < cnt; i++) \
+ printk(KERN_ERR "%.2x", buf[i]); \
+ printk(KERN_ERR "\n"); \
+} while (0)
+#else
+#define D_DUMP_BUFFER(prestr, cnt, buf)
+#endif
+
+#ifdef DEBUG
+#define D(x...) printk(x)
+#else
+#define D(x...) do {} while (0)
+#endif
+
+#define TIMESTAMP_ADDR (MSM_CSR_BASE + 0x04)
+
+struct smem_log_item {
+ uint32_t identifier;
+ uint32_t timetick;
+ uint32_t data1;
+ uint32_t data2;
+ uint32_t data3;
+};
+
+#define SMEM_LOG_NUM_ENTRIES 2000
+#define SMEM_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+ SMEM_LOG_NUM_ENTRIES)
+
+#define SMEM_LOG_NUM_STATIC_ENTRIES 150
+#define SMEM_STATIC_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+ SMEM_LOG_NUM_STATIC_ENTRIES)
+
+#define SMEM_LOG_NUM_POWER_ENTRIES 2000
+#define SMEM_POWER_LOG_EVENTS_SIZE (sizeof(struct smem_log_item) * \
+ SMEM_LOG_NUM_POWER_ENTRIES)
+
+#define SMEM_SPINLOCK_SMEM_LOG 2
+#define SMEM_SPINLOCK_STATIC_LOG 5
+/* POWER shares with SMEM_SPINLOCK_SMEM_LOG */
+
+static remote_spinlock_t remote_spinlock;
+static remote_spinlock_t remote_spinlock_static;
+
+struct smem_log_inst {
+ int which_log;
+ struct smem_log_item __iomem *events;
+ uint32_t __iomem *idx;
+ int num;
+ remote_spinlock_t *remote_spinlock;
+};
+
+enum smem_logs {
+ GEN = 0,
+ STA,
+ POW,
+ NUM
+};
+
+static struct smem_log_inst inst[NUM];
+
+#if defined(CONFIG_DEBUG_FS)
+
+#define HSIZE 13
+
+struct sym {
+ uint32_t val;
+ char *str;
+ struct hlist_node node;
+};
+
+struct sym id_syms[] = {
+ { SMEM_LOG_PROC_ID_MODEM, "MODM" },
+ { SMEM_LOG_PROC_ID_Q6, "QDSP" },
+ { SMEM_LOG_PROC_ID_APPS, "APPS" },
+};
+
+struct sym base_syms[] = {
+ { SMEM_LOG_ONCRPC_EVENT_BASE, "ONCRPC" },
+ { SMEM_LOG_SMEM_EVENT_BASE, "SMEM" },
+ { SMEM_LOG_TMC_EVENT_BASE, "TMC" },
+ { SMEM_LOG_TIMETICK_EVENT_BASE, "TIMETICK" },
+ { SMEM_LOG_DEM_EVENT_BASE, "DEM" },
+ { SMEM_LOG_ERROR_EVENT_BASE, "ERROR" },
+ { SMEM_LOG_DCVS_EVENT_BASE, "DCVS" },
+ { SMEM_LOG_SLEEP_EVENT_BASE, "SLEEP" },
+ { SMEM_LOG_RPC_ROUTER_EVENT_BASE, "ROUTER" },
+};
+
+struct sym event_syms[] = {
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+ { DEM_SMSM_ISR, "SMSM_ISR" },
+ { DEM_STATE_CHANGE, "STATE_CHANGE" },
+ { DEM_STATE_MACHINE_ENTER, "STATE_MACHINE_ENTER" },
+ { DEM_ENTER_SLEEP, "ENTER_SLEEP" },
+ { DEM_END_SLEEP, "END_SLEEP" },
+ { DEM_SETUP_SLEEP, "SETUP_SLEEP" },
+ { DEM_SETUP_POWER_COLLAPSE, "SETUP_POWER_COLLAPSE" },
+ { DEM_SETUP_SUSPEND, "SETUP_SUSPEND" },
+ { DEM_EARLY_EXIT, "EARLY_EXIT" },
+ { DEM_WAKEUP_REASON, "WAKEUP_REASON" },
+ { DEM_DETECT_WAKEUP, "DETECT_WAKEUP" },
+ { DEM_DETECT_RESET, "DETECT_RESET" },
+ { DEM_DETECT_SLEEPEXIT, "DETECT_SLEEPEXIT" },
+ { DEM_DETECT_RUN, "DETECT_RUN" },
+ { DEM_APPS_SWFI, "APPS_SWFI" },
+ { DEM_SEND_WAKEUP, "SEND_WAKEUP" },
+ { DEM_ASSERT_OKTS, "ASSERT_OKTS" },
+ { DEM_NEGATE_OKTS, "NEGATE_OKTS" },
+ { DEM_PROC_COMM_CMD, "PROC_COMM_CMD" },
+ { DEM_REMOVE_PROC_PWR, "REMOVE_PROC_PWR" },
+ { DEM_RESTORE_PROC_PWR, "RESTORE_PROC_PWR" },
+ { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
+ { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
+ { DEM_MAO_INTS, "MAO_INTS" },
+ { DEM_APPS_WAKEUP_INT, "APPS_WAKEUP_INT" },
+ { DEM_PROC_WAKEUP, "PROC_WAKEUP" },
+ { DEM_PROC_POWERUP, "PROC_POWERUP" },
+ { DEM_TIMER_EXPIRED, "TIMER_EXPIRED" },
+ { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
+ { DEM_REMOTE_PWR_CB, "REMOTE_PWR_CB" },
+ { DEM_TIME_SYNC_START, "TIME_SYNC_START" },
+ { DEM_TIME_SYNC_SEND_VALUE, "TIME_SYNC_SEND_VALUE" },
+ { DEM_TIME_SYNC_DONE, "TIME_SYNC_DONE" },
+ { DEM_TIME_SYNC_REQUEST, "TIME_SYNC_REQUEST" },
+ { DEM_TIME_SYNC_POLL, "TIME_SYNC_POLL" },
+ { DEM_TIME_SYNC_INIT, "TIME_SYNC_INIT" },
+ { DEM_INIT, "INIT" },
+#else
+
+ { DEM_NO_SLEEP, "NO_SLEEP" },
+ { DEM_INSUF_TIME, "INSUF_TIME" },
+ { DEMAPPS_ENTER_SLEEP, "APPS_ENTER_SLEEP" },
+ { DEMAPPS_DETECT_WAKEUP, "APPS_DETECT_WAKEUP" },
+ { DEMAPPS_END_APPS_TCXO, "APPS_END_APPS_TCXO" },
+ { DEMAPPS_ENTER_SLEEPEXIT, "APPS_ENTER_SLEEPEXIT" },
+ { DEMAPPS_END_APPS_SLEEP, "APPS_END_APPS_SLEEP" },
+ { DEMAPPS_SETUP_APPS_PWRCLPS, "APPS_SETUP_APPS_PWRCLPS" },
+ { DEMAPPS_PWRCLPS_EARLY_EXIT, "APPS_PWRCLPS_EARLY_EXIT" },
+ { DEMMOD_SEND_WAKEUP, "MOD_SEND_WAKEUP" },
+ { DEMMOD_NO_APPS_VOTE, "MOD_NO_APPS_VOTE" },
+ { DEMMOD_NO_TCXO_SLEEP, "MOD_NO_TCXO_SLEEP" },
+ { DEMMOD_BT_CLOCK, "MOD_BT_CLOCK" },
+ { DEMMOD_UART_CLOCK, "MOD_UART_CLOCK" },
+ { DEMMOD_OKTS, "MOD_OKTS" },
+ { DEM_SLEEP_INFO, "SLEEP_INFO" },
+ { DEMMOD_TCXO_END, "MOD_TCXO_END" },
+ { DEMMOD_END_SLEEP_SIG, "MOD_END_SLEEP_SIG" },
+ { DEMMOD_SETUP_APPSSLEEP, "MOD_SETUP_APPSSLEEP" },
+ { DEMMOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
+ { DEMMOD_WAKE_APPS, "MOD_WAKE_APPS" },
+ { DEMMOD_POWER_COLLAPSE_APPS, "MOD_POWER_COLLAPSE_APPS" },
+ { DEMMOD_RESTORE_APPS_PWR, "MOD_RESTORE_APPS_PWR" },
+ { DEMAPPS_ASSERT_OKTS, "APPS_ASSERT_OKTS" },
+ { DEMAPPS_RESTART_START_TIMER, "APPS_RESTART_START_TIMER" },
+ { DEMAPPS_ENTER_RUN, "APPS_ENTER_RUN" },
+ { DEMMOD_MAO_INTS, "MOD_MAO_INTS" },
+ { DEMMOD_POWERUP_APPS_CALLED, "MOD_POWERUP_APPS_CALLED" },
+ { DEMMOD_PC_TIMER_EXPIRED, "MOD_PC_TIMER_EXPIRED" },
+ { DEM_DETECT_SLEEPEXIT, "_DETECT_SLEEPEXIT" },
+ { DEM_DETECT_RUN, "DETECT_RUN" },
+ { DEM_SET_APPS_TIMER, "SET_APPS_TIMER" },
+ { DEM_NEGATE_OKTS, "NEGATE_OKTS" },
+ { DEMMOD_APPS_WAKEUP_INT, "MOD_APPS_WAKEUP_INT" },
+ { DEMMOD_APPS_SWFI, "MOD_APPS_SWFI" },
+ { DEM_SEND_BATTERY_INFO, "SEND_BATTERY_INFO" },
+ { DEM_SMI_CLK_DISABLED, "SMI_CLK_DISABLED" },
+ { DEM_SMI_CLK_ENABLED, "SMI_CLK_ENABLED" },
+ { DEMAPPS_SETUP_APPS_SUSPEND, "APPS_SETUP_APPS_SUSPEND" },
+ { DEM_RPC_EARLY_EXIT, "RPC_EARLY_EXIT" },
+ { DEMAPPS_WAKEUP_REASON, "APPS_WAKEUP_REASON" },
+ { DEM_INIT, "INIT" },
+#endif
+ { DEMMOD_UMTS_BASE, "MOD_UMTS_BASE" },
+ { DEMMOD_GL1_GO_TO_SLEEP, "GL1_GO_TO_SLEEP" },
+ { DEMMOD_GL1_SLEEP_START, "GL1_SLEEP_START" },
+ { DEMMOD_GL1_AFTER_GSM_CLK_ON, "GL1_AFTER_GSM_CLK_ON" },
+ { DEMMOD_GL1_BEFORE_RF_ON, "GL1_BEFORE_RF_ON" },
+ { DEMMOD_GL1_AFTER_RF_ON, "GL1_AFTER_RF_ON" },
+ { DEMMOD_GL1_FRAME_TICK, "GL1_FRAME_TICK" },
+ { DEMMOD_GL1_WCDMA_START, "GL1_WCDMA_START" },
+ { DEMMOD_GL1_WCDMA_ENDING, "GL1_WCDMA_ENDING" },
+ { DEMMOD_UMTS_NOT_OKTS, "UMTS_NOT_OKTS" },
+ { DEMMOD_UMTS_START_TCXO_SHUTDOWN, "UMTS_START_TCXO_SHUTDOWN" },
+ { DEMMOD_UMTS_END_TCXO_SHUTDOWN, "UMTS_END_TCXO_SHUTDOWN" },
+ { DEMMOD_UMTS_START_ARM_HALT, "UMTS_START_ARM_HALT" },
+ { DEMMOD_UMTS_END_ARM_HALT, "UMTS_END_ARM_HALT" },
+ { DEMMOD_UMTS_NEXT_WAKEUP_SCLK, "UMTS_NEXT_WAKEUP_SCLK" },
+ { TIME_REMOTE_LOG_EVENT_START, "START" },
+ { TIME_REMOTE_LOG_EVENT_GOTO_WAIT,
+ "GOTO_WAIT" },
+ { TIME_REMOTE_LOG_EVENT_GOTO_INIT,
+ "GOTO_INIT" },
+ { ERR_ERROR_FATAL, "ERR_ERROR_FATAL" },
+ { ERR_ERROR_FATAL_TASK, "ERR_ERROR_FATAL_TASK" },
+ { DCVSAPPS_LOG_IDLE, "DCVSAPPS_LOG_IDLE" },
+ { DCVSAPPS_LOG_ERR, "DCVSAPPS_LOG_ERR" },
+ { DCVSAPPS_LOG_CHG, "DCVSAPPS_LOG_CHG" },
+ { DCVSAPPS_LOG_REG, "DCVSAPPS_LOG_REG" },
+ { DCVSAPPS_LOG_DEREG, "DCVSAPPS_LOG_DEREG" },
+ { SMEM_LOG_EVENT_CB, "CB" },
+ { SMEM_LOG_EVENT_START, "START" },
+ { SMEM_LOG_EVENT_INIT, "INIT" },
+ { SMEM_LOG_EVENT_RUNNING, "RUNNING" },
+ { SMEM_LOG_EVENT_STOP, "STOP" },
+ { SMEM_LOG_EVENT_RESTART, "RESTART" },
+ { SMEM_LOG_EVENT_SS, "SS" },
+ { SMEM_LOG_EVENT_READ, "READ" },
+ { SMEM_LOG_EVENT_WRITE, "WRITE" },
+ { SMEM_LOG_EVENT_SIGS1, "SIGS1" },
+ { SMEM_LOG_EVENT_SIGS2, "SIGS2" },
+ { SMEM_LOG_EVENT_WRITE_DM, "WRITE_DM" },
+ { SMEM_LOG_EVENT_READ_DM, "READ_DM" },
+ { SMEM_LOG_EVENT_SKIP_DM, "SKIP_DM" },
+ { SMEM_LOG_EVENT_STOP_DM, "STOP_DM" },
+ { SMEM_LOG_EVENT_ISR, "ISR" },
+ { SMEM_LOG_EVENT_TASK, "TASK" },
+ { SMEM_LOG_EVENT_RS, "RS" },
+ { ONCRPC_LOG_EVENT_SMD_WAIT, "SMD_WAIT" },
+ { ONCRPC_LOG_EVENT_RPC_WAIT, "RPC_WAIT" },
+ { ONCRPC_LOG_EVENT_RPC_BOTH_WAIT, "RPC_BOTH_WAIT" },
+ { ONCRPC_LOG_EVENT_RPC_INIT, "RPC_INIT" },
+ { ONCRPC_LOG_EVENT_RUNNING, "RUNNING" },
+ { ONCRPC_LOG_EVENT_APIS_INITED, "APIS_INITED" },
+ { ONCRPC_LOG_EVENT_AMSS_RESET, "AMSS_RESET" },
+ { ONCRPC_LOG_EVENT_SMD_RESET, "SMD_RESET" },
+ { ONCRPC_LOG_EVENT_ONCRPC_RESET, "ONCRPC_RESET" },
+ { ONCRPC_LOG_EVENT_CB, "CB" },
+ { ONCRPC_LOG_EVENT_STD_CALL, "STD_CALL" },
+ { ONCRPC_LOG_EVENT_STD_REPLY, "STD_REPLY" },
+ { ONCRPC_LOG_EVENT_STD_CALL_ASYNC, "STD_CALL_ASYNC" },
+ { NO_SLEEP_OLD, "NO_SLEEP_OLD" },
+ { INSUF_TIME, "INSUF_TIME" },
+ { MOD_UART_CLOCK, "MOD_UART_CLOCK" },
+ { SLEEP_INFO, "SLEEP_INFO" },
+ { MOD_TCXO_END, "MOD_TCXO_END" },
+ { MOD_ENTER_TCXO, "MOD_ENTER_TCXO" },
+ { NO_SLEEP_NEW, "NO_SLEEP_NEW" },
+ { RPC_ROUTER_LOG_EVENT_UNKNOWN, "UNKNOWN" },
+ { RPC_ROUTER_LOG_EVENT_MSG_READ, "MSG_READ" },
+ { RPC_ROUTER_LOG_EVENT_MSG_WRITTEN, "MSG_WRITTEN" },
+ { RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ, "MSG_CFM_REQ" },
+ { RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT, "MSG_CFM_SNT" },
+ { RPC_ROUTER_LOG_EVENT_MID_READ, "MID_READ" },
+ { RPC_ROUTER_LOG_EVENT_MID_WRITTEN, "MID_WRITTEN" },
+ { RPC_ROUTER_LOG_EVENT_MID_CFM_REQ, "MID_CFM_REQ" },
+
+};
+
+struct sym oncrpc_syms[] = {
+ { 0x30000000, "CM" },
+ { 0x30000001, "DB" },
+ { 0x30000002, "SND" },
+ { 0x30000003, "WMS" },
+ { 0x30000004, "PDSM" },
+ { 0x30000005, "MISC_MODEM_APIS" },
+ { 0x30000006, "MISC_APPS_APIS" },
+ { 0x30000007, "JOYST" },
+ { 0x30000008, "VJOY" },
+ { 0x30000009, "JOYSTC" },
+ { 0x3000000a, "ADSPRTOSATOM" },
+ { 0x3000000b, "ADSPRTOSMTOA" },
+ { 0x3000000c, "I2C" },
+ { 0x3000000d, "TIME_REMOTE" },
+ { 0x3000000e, "NV" },
+ { 0x3000000f, "CLKRGM_SEC" },
+ { 0x30000010, "RDEVMAP" },
+ { 0x30000011, "FS_RAPI" },
+ { 0x30000012, "PBMLIB" },
+ { 0x30000013, "AUDMGR" },
+ { 0x30000014, "MVS" },
+ { 0x30000015, "DOG_KEEPALIVE" },
+ { 0x30000016, "GSDI_EXP" },
+ { 0x30000017, "AUTH" },
+ { 0x30000018, "NVRUIMI" },
+ { 0x30000019, "MMGSDILIB" },
+ { 0x3000001a, "CHARGER" },
+ { 0x3000001b, "UIM" },
+ { 0x3000001C, "ONCRPCTEST" },
+ { 0x3000001d, "PDSM_ATL" },
+ { 0x3000001e, "FS_XMOUNT" },
+ { 0x3000001f, "SECUTIL " },
+ { 0x30000020, "MCCMEID" },
+ { 0x30000021, "PM_STROBE_FLASH" },
+ { 0x30000022, "DS707_EXTIF" },
+ { 0x30000023, "SMD BRIDGE_MODEM" },
+ { 0x30000024, "SMD PORT_MGR" },
+ { 0x30000025, "BUS_PERF" },
+ { 0x30000026, "BUS_MON" },
+ { 0x30000027, "MC" },
+ { 0x30000028, "MCCAP" },
+ { 0x30000029, "MCCDMA" },
+ { 0x3000002a, "MCCDS" },
+ { 0x3000002b, "MCCSCH" },
+ { 0x3000002c, "MCCSRID" },
+ { 0x3000002d, "SNM" },
+ { 0x3000002e, "MCCSYOBJ" },
+ { 0x3000002f, "DS707_APIS" },
+ { 0x30000030, "DS_MP_SHIM_APPS_ASYNC" },
+ { 0x30000031, "DSRLP_APIS" },
+ { 0x30000032, "RLP_APIS" },
+ { 0x30000033, "DS_MP_SHIM_MODEM" },
+ { 0x30000034, "DSHDR_APIS" },
+ { 0x30000035, "DSHDR_MDM_APIS" },
+ { 0x30000036, "DS_MP_SHIM_APPS" },
+ { 0x30000037, "HDRMC_APIS" },
+ { 0x30000038, "SMD_BRIDGE_MTOA" },
+ { 0x30000039, "SMD_BRIDGE_ATOM" },
+ { 0x3000003a, "DPMAPP_OTG" },
+ { 0x3000003b, "DIAG" },
+ { 0x3000003c, "GSTK_EXP" },
+ { 0x3000003d, "DSBC_MDM_APIS" },
+ { 0x3000003e, "HDRMRLP_MDM_APIS" },
+ { 0x3000003f, "HDRMRLP_APPS_APIS" },
+ { 0x30000040, "HDRMC_MRLP_APIS" },
+ { 0x30000041, "PDCOMM_APP_API" },
+ { 0x30000042, "DSAT_APIS" },
+ { 0x30000043, "MISC_RF_APIS" },
+ { 0x30000044, "CMIPAPP" },
+ { 0x30000045, "DSMP_UMTS_MODEM_APIS" },
+ { 0x30000046, "DSMP_UMTS_APPS_APIS" },
+ { 0x30000047, "DSUCSDMPSHIM" },
+ { 0x30000048, "TIME_REMOTE_ATOM" },
+ { 0x3000004a, "SD" },
+ { 0x3000004b, "MMOC" },
+ { 0x3000004c, "WLAN_ADP_FTM" },
+ { 0x3000004d, "WLAN_CP_CM" },
+ { 0x3000004e, "FTM_WLAN" },
+ { 0x3000004f, "SDCC_CPRM" },
+ { 0x30000050, "CPRMINTERFACE" },
+ { 0x30000051, "DATA_ON_MODEM_MTOA_APIS" },
+ { 0x30000052, "DATA_ON_APPS_ATOM_APIS" },
+ { 0x30000053, "MISC_MODEM_APIS_NONWINMOB" },
+ { 0x30000054, "MISC_APPS_APIS_NONWINMOB" },
+ { 0x30000055, "PMEM_REMOTE" },
+ { 0x30000056, "TCXOMGR" },
+ { 0x30000057, "DSUCSDAPPIF_APIS" },
+ { 0x30000058, "BT" },
+ { 0x30000059, "PD_COMMS_API" },
+ { 0x3000005a, "PD_COMMS_CLIENT_API" },
+ { 0x3000005b, "PDAPI" },
+ { 0x3000005c, "LSA_SUPL_DSM" },
+ { 0x3000005d, "TIME_REMOTE_MTOA" },
+ { 0x3000005e, "FTM_BT" },
+ { 0X3000005f, "DSUCSDAPPIF_APIS" },
+ { 0X30000060, "PMAPP_GEN" },
+ { 0X30000061, "PM_LIB" },
+ { 0X30000062, "KEYPAD" },
+ { 0X30000063, "HSU_APP_APIS" },
+ { 0X30000064, "HSU_MDM_APIS" },
+ { 0X30000065, "ADIE_ADC_REMOTE_ATOM " },
+ { 0X30000066, "TLMM_REMOTE_ATOM" },
+ { 0X30000067, "UI_CALLCTRL" },
+ { 0X30000068, "UIUTILS" },
+ { 0X30000069, "PRL" },
+ { 0X3000006a, "HW" },
+ { 0X3000006b, "OEM_RAPI" },
+ { 0X3000006c, "WMSPM" },
+ { 0X3000006d, "BTPF" },
+ { 0X3000006e, "CLKRGM_SYNC_EVENT" },
+ { 0X3000006f, "USB_APPS_RPC" },
+ { 0X30000070, "USB_MODEM_RPC" },
+ { 0X30000071, "ADC" },
+ { 0X30000072, "CAMERAREMOTED" },
+ { 0X30000073, "SECAPIREMOTED" },
+ { 0X30000074, "DSATAPI" },
+ { 0X30000075, "CLKCTL_RPC" },
+ { 0X30000076, "BREWAPPCOORD" },
+ { 0X30000077, "ALTENVSHELL" },
+ { 0X30000078, "WLAN_TRP_UTILS" },
+ { 0X30000079, "GPIO_RPC" },
+ { 0X3000007a, "PING_RPC" },
+ { 0X3000007b, "DSC_DCM_API" },
+ { 0X3000007c, "L1_DS" },
+ { 0X3000007d, "QCHATPK_APIS" },
+ { 0X3000007e, "GPS_API" },
+ { 0X3000007f, "OSS_RRCASN_REMOTE" },
+ { 0X30000080, "PMAPP_OTG_REMOTE" },
+ { 0X30000081, "PING_MDM_RPC" },
+ { 0X30000082, "PING_KERNEL_RPC" },
+ { 0X30000083, "TIMETICK" },
+ { 0X30000084, "WM_BTHCI_FTM " },
+ { 0X30000085, "WM_BT_PF" },
+ { 0X30000086, "IPA_IPC_APIS" },
+ { 0X30000087, "UKCC_IPC_APIS" },
+ { 0X30000088, "CMIPSMS " },
+ { 0X30000089, "VBATT_REMOTE" },
+ { 0X3000008a, "MFPAL" },
+ { 0X3000008b, "DSUMTSPDPREG" },
+ { 0X3000fe00, "RESTART_DAEMON NUMBER 0" },
+ { 0X3000fe01, "RESTART_DAEMON NUMBER 1" },
+ { 0X3000feff, "RESTART_DAEMON NUMBER 255" },
+ { 0X3000fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP" },
+ { 0X3000ffff, "RPC_ROUTER_SERVER_PROGRAM" },
+ { 0x31000000, "CM CB" },
+ { 0x31000001, "DB CB" },
+ { 0x31000002, "SND CB" },
+ { 0x31000003, "WMS CB" },
+ { 0x31000004, "PDSM CB" },
+ { 0x31000005, "MISC_MODEM_APIS CB" },
+ { 0x31000006, "MISC_APPS_APIS CB" },
+ { 0x31000007, "JOYST CB" },
+ { 0x31000008, "VJOY CB" },
+ { 0x31000009, "JOYSTC CB" },
+ { 0x3100000a, "ADSPRTOSATOM CB" },
+ { 0x3100000b, "ADSPRTOSMTOA CB" },
+ { 0x3100000c, "I2C CB" },
+ { 0x3100000d, "TIME_REMOTE CB" },
+ { 0x3100000e, "NV CB" },
+ { 0x3100000f, "CLKRGM_SEC CB" },
+ { 0x31000010, "RDEVMAP CB" },
+ { 0x31000011, "FS_RAPI CB" },
+ { 0x31000012, "PBMLIB CB" },
+ { 0x31000013, "AUDMGR CB" },
+ { 0x31000014, "MVS CB" },
+ { 0x31000015, "DOG_KEEPALIVE CB" },
+ { 0x31000016, "GSDI_EXP CB" },
+ { 0x31000017, "AUTH CB" },
+ { 0x31000018, "NVRUIMI CB" },
+ { 0x31000019, "MMGSDILIB CB" },
+ { 0x3100001a, "CHARGER CB" },
+ { 0x3100001b, "UIM CB" },
+ { 0x3100001C, "ONCRPCTEST CB" },
+ { 0x3100001d, "PDSM_ATL CB" },
+ { 0x3100001e, "FS_XMOUNT CB" },
+ { 0x3100001f, "SECUTIL CB" },
+ { 0x31000020, "MCCMEID" },
+ { 0x31000021, "PM_STROBE_FLASH CB" },
+ { 0x31000022, "DS707_EXTIF CB" },
+ { 0x31000023, "SMD BRIDGE_MODEM CB" },
+ { 0x31000024, "SMD PORT_MGR CB" },
+ { 0x31000025, "BUS_PERF CB" },
+ { 0x31000026, "BUS_MON CB" },
+ { 0x31000027, "MC CB" },
+ { 0x31000028, "MCCAP CB" },
+ { 0x31000029, "MCCDMA CB" },
+ { 0x3100002a, "MCCDS CB" },
+ { 0x3100002b, "MCCSCH CB" },
+ { 0x3100002c, "MCCSRID CB" },
+ { 0x3100002d, "SNM CB" },
+ { 0x3100002e, "MCCSYOBJ CB" },
+ { 0x3100002f, "DS707_APIS CB" },
+ { 0x31000030, "DS_MP_SHIM_APPS_ASYNC CB" },
+ { 0x31000031, "DSRLP_APIS CB" },
+ { 0x31000032, "RLP_APIS CB" },
+ { 0x31000033, "DS_MP_SHIM_MODEM CB" },
+ { 0x31000034, "DSHDR_APIS CB" },
+ { 0x31000035, "DSHDR_MDM_APIS CB" },
+ { 0x31000036, "DS_MP_SHIM_APPS CB" },
+ { 0x31000037, "HDRMC_APIS CB" },
+ { 0x31000038, "SMD_BRIDGE_MTOA CB" },
+ { 0x31000039, "SMD_BRIDGE_ATOM CB" },
+ { 0x3100003a, "DPMAPP_OTG CB" },
+ { 0x3100003b, "DIAG CB" },
+ { 0x3100003c, "GSTK_EXP CB" },
+ { 0x3100003d, "DSBC_MDM_APIS CB" },
+ { 0x3100003e, "HDRMRLP_MDM_APIS CB" },
+ { 0x3100003f, "HDRMRLP_APPS_APIS CB" },
+ { 0x31000040, "HDRMC_MRLP_APIS CB" },
+ { 0x31000041, "PDCOMM_APP_API CB" },
+ { 0x31000042, "DSAT_APIS CB" },
+ { 0x31000043, "MISC_RF_APIS CB" },
+ { 0x31000044, "CMIPAPP CB" },
+ { 0x31000045, "DSMP_UMTS_MODEM_APIS CB" },
+ { 0x31000046, "DSMP_UMTS_APPS_APIS CB" },
+ { 0x31000047, "DSUCSDMPSHIM CB" },
+ { 0x31000048, "TIME_REMOTE_ATOM CB" },
+ { 0x3100004a, "SD CB" },
+ { 0x3100004b, "MMOC CB" },
+ { 0x3100004c, "WLAN_ADP_FTM CB" },
+ { 0x3100004d, "WLAN_CP_CM CB" },
+ { 0x3100004e, "FTM_WLAN CB" },
+ { 0x3100004f, "SDCC_CPRM CB" },
+ { 0x31000050, "CPRMINTERFACE CB" },
+ { 0x31000051, "DATA_ON_MODEM_MTOA_APIS CB" },
+ { 0x31000052, "DATA_ON_APPS_ATOM_APIS CB" },
+ { 0x31000053, "MISC_APIS_NONWINMOB CB" },
+ { 0x31000054, "MISC_APPS_APIS_NONWINMOB CB" },
+ { 0x31000055, "PMEM_REMOTE CB" },
+ { 0x31000056, "TCXOMGR CB" },
+ { 0x31000057, "DSUCSDAPPIF_APIS CB" },
+ { 0x31000058, "BT CB" },
+ { 0x31000059, "PD_COMMS_API CB" },
+ { 0x3100005a, "PD_COMMS_CLIENT_API CB" },
+ { 0x3100005b, "PDAPI CB" },
+ { 0x3100005c, "LSA_SUPL_DSM CB" },
+ { 0x3100005d, "TIME_REMOTE_MTOA CB" },
+ { 0x3100005e, "FTM_BT CB" },
+ { 0X3100005f, "DSUCSDAPPIF_APIS CB" },
+ { 0X31000060, "PMAPP_GEN CB" },
+ { 0X31000061, "PM_LIB CB" },
+ { 0X31000062, "KEYPAD CB" },
+ { 0X31000063, "HSU_APP_APIS CB" },
+ { 0X31000064, "HSU_MDM_APIS CB" },
+ { 0X31000065, "ADIE_ADC_REMOTE_ATOM CB" },
+ { 0X31000066, "TLMM_REMOTE_ATOM CB" },
+ { 0X31000067, "UI_CALLCTRL CB" },
+ { 0X31000068, "UIUTILS CB" },
+ { 0X31000069, "PRL CB" },
+ { 0X3100006a, "HW CB" },
+ { 0X3100006b, "OEM_RAPI CB" },
+ { 0X3100006c, "WMSPM CB" },
+ { 0X3100006d, "BTPF CB" },
+ { 0X3100006e, "CLKRGM_SYNC_EVENT CB" },
+ { 0X3100006f, "USB_APPS_RPC CB" },
+ { 0X31000070, "USB_MODEM_RPC CB" },
+ { 0X31000071, "ADC CB" },
+ { 0X31000072, "CAMERAREMOTED CB" },
+ { 0X31000073, "SECAPIREMOTED CB" },
+ { 0X31000074, "DSATAPI CB" },
+ { 0X31000075, "CLKCTL_RPC CB" },
+ { 0X31000076, "BREWAPPCOORD CB" },
+ { 0X31000077, "ALTENVSHELL CB" },
+ { 0X31000078, "WLAN_TRP_UTILS CB" },
+ { 0X31000079, "GPIO_RPC CB" },
+ { 0X3100007a, "PING_RPC CB" },
+ { 0X3100007b, "DSC_DCM_API CB" },
+ { 0X3100007c, "L1_DS CB" },
+ { 0X3100007d, "QCHATPK_APIS CB" },
+ { 0X3100007e, "GPS_API CB" },
+ { 0X3100007f, "OSS_RRCASN_REMOTE CB" },
+ { 0X31000080, "PMAPP_OTG_REMOTE CB" },
+ { 0X31000081, "PING_MDM_RPC CB" },
+ { 0X31000082, "PING_KERNEL_RPC CB" },
+ { 0X31000083, "TIMETICK CB" },
+ { 0X31000084, "WM_BTHCI_FTM CB" },
+ { 0X31000085, "WM_BT_PF CB" },
+ { 0X31000086, "IPA_IPC_APIS CB" },
+ { 0X31000087, "UKCC_IPC_APIS CB" },
+ { 0X31000088, "CMIPSMS CB" },
+ { 0X31000089, "VBATT_REMOTE CB" },
+ { 0X3100008a, "MFPAL CB" },
+ { 0X3100008b, "DSUMTSPDPREG CB" },
+ { 0X3100fe00, "RESTART_DAEMON NUMBER 0 CB" },
+ { 0X3100fe01, "RESTART_DAEMON NUMBER 1 CB" },
+ { 0X3100feff, "RESTART_DAEMON NUMBER 255 CB" },
+ { 0X3100fffe, "BACKWARDS_COMPATIBILITY_IN_RPC_CLNT_LOOKUP CB" },
+ { 0X3100ffff, "RPC_ROUTER_SERVER_PROGRAM CB" },
+};
+
+struct sym wakeup_syms[] = {
+ { 0x00000040, "OTHER" },
+ { 0x00000020, "RESET" },
+ { 0x00000010, "ALARM" },
+ { 0x00000008, "TIMER" },
+ { 0x00000004, "GPIO" },
+ { 0x00000002, "INT" },
+ { 0x00000001, "RPC" },
+ { 0x00000000, "NONE" },
+};
+
+struct sym wakeup_int_syms[] = {
+ { 0, "MDDI_EXT" },
+ { 1, "MDDI_PRI" },
+ { 2, "MDDI_CLIENT"},
+ { 3, "USB_OTG" },
+ { 4, "I2CC" },
+ { 5, "SDC1_0" },
+ { 6, "SDC1_1" },
+ { 7, "SDC2_0" },
+ { 8, "SDC2_1" },
+ { 9, "ADSP_A9A11" },
+ { 10, "UART1" },
+ { 11, "UART2" },
+ { 12, "UART3" },
+ { 13, "DP_RX_DATA" },
+ { 14, "DP_RX_DATA2" },
+ { 15, "DP_RX_DATA3" },
+ { 16, "DM_UART" },
+ { 17, "DM_DP_RX_DATA" },
+ { 18, "KEYSENSE" },
+ { 19, "HSSD" },
+ { 20, "NAND_WR_ER_DONE" },
+ { 21, "NAND_OP_DONE" },
+ { 22, "TCHSCRN1" },
+ { 23, "TCHSCRN2" },
+ { 24, "TCHSCRN_SSBI" },
+ { 25, "USB_HS" },
+ { 26, "UART2_DM_RX" },
+ { 27, "UART2_DM" },
+ { 28, "SDC4_1" },
+ { 29, "SDC4_0" },
+ { 30, "SDC3_1" },
+ { 31, "SDC3_0" },
+};
+
+struct sym smsm_syms[] = {
+ { 0x80000000, "UN" },
+ { 0x7F000000, "ERR" },
+ { 0x00800000, "SMLP" },
+ { 0x00400000, "ADWN" },
+ { 0x00200000, "PWRS" },
+ { 0x00100000, "DWLD" },
+ { 0x00080000, "SRBT" },
+ { 0x00040000, "SDWN" },
+ { 0x00020000, "ARBT" },
+ { 0x00010000, "REL" },
+ { 0x00008000, "SLE" },
+ { 0x00004000, "SLP" },
+ { 0x00002000, "WFPI" },
+ { 0x00001000, "EEX" },
+ { 0x00000800, "TIN" },
+ { 0x00000400, "TWT" },
+ { 0x00000200, "PWRC" },
+ { 0x00000100, "RUN" },
+ { 0x00000080, "SA" },
+ { 0x00000040, "RES" },
+ { 0x00000020, "RIN" },
+ { 0x00000010, "RWT" },
+ { 0x00000008, "SIN" },
+ { 0x00000004, "SWT" },
+ { 0x00000002, "OE" },
+ { 0x00000001, "I" },
+};
+
+/* never reorder */
+struct sym voter_d2_syms[] = {
+ { 0x00000001, NULL },
+ { 0x00000002, NULL },
+ { 0x00000004, NULL },
+ { 0x00000008, NULL },
+ { 0x00000010, NULL },
+ { 0x00000020, NULL },
+ { 0x00000040, NULL },
+ { 0x00000080, NULL },
+ { 0x00000100, NULL },
+ { 0x00000200, NULL },
+ { 0x00000400, NULL },
+ { 0x00000800, NULL },
+ { 0x00001000, NULL },
+ { 0x00002000, NULL },
+ { 0x00004000, NULL },
+ { 0x00008000, NULL },
+ { 0x00010000, NULL },
+ { 0x00020000, NULL },
+ { 0x00040000, NULL },
+ { 0x00080000, NULL },
+ { 0x00100000, NULL },
+ { 0x00200000, NULL },
+ { 0x00400000, NULL },
+ { 0x00800000, NULL },
+ { 0x01000000, NULL },
+ { 0x02000000, NULL },
+ { 0x04000000, NULL },
+ { 0x08000000, NULL },
+ { 0x10000000, NULL },
+ { 0x20000000, NULL },
+ { 0x40000000, NULL },
+ { 0x80000000, NULL },
+};
+
+/* never reorder */
+struct sym voter_d3_syms[] = {
+ { 0x00000001, NULL },
+ { 0x00000002, NULL },
+ { 0x00000004, NULL },
+ { 0x00000008, NULL },
+ { 0x00000010, NULL },
+ { 0x00000020, NULL },
+ { 0x00000040, NULL },
+ { 0x00000080, NULL },
+ { 0x00000100, NULL },
+ { 0x00000200, NULL },
+ { 0x00000400, NULL },
+ { 0x00000800, NULL },
+ { 0x00001000, NULL },
+ { 0x00002000, NULL },
+ { 0x00004000, NULL },
+ { 0x00008000, NULL },
+ { 0x00010000, NULL },
+ { 0x00020000, NULL },
+ { 0x00040000, NULL },
+ { 0x00080000, NULL },
+ { 0x00100000, NULL },
+ { 0x00200000, NULL },
+ { 0x00400000, NULL },
+ { 0x00800000, NULL },
+ { 0x01000000, NULL },
+ { 0x02000000, NULL },
+ { 0x04000000, NULL },
+ { 0x08000000, NULL },
+ { 0x10000000, NULL },
+ { 0x20000000, NULL },
+ { 0x40000000, NULL },
+ { 0x80000000, NULL },
+};
+
+struct sym dem_state_master_syms[] = {
+ { 0, "INIT" },
+ { 1, "RUN" },
+ { 2, "SLEEP_WAIT" },
+ { 3, "SLEEP_CONFIRMED" },
+ { 4, "SLEEP_EXIT" },
+ { 5, "RSA" },
+ { 6, "EARLY_EXIT" },
+ { 7, "RSA_DELAYED" },
+ { 8, "RSA_CHECK_INTS" },
+ { 9, "RSA_CONFIRMED" },
+ { 10, "RSA_WAKING" },
+ { 11, "RSA_RESTORE" },
+ { 12, "RESET" },
+};
+
+struct sym dem_state_slave_syms[] = {
+ { 0, "INIT" },
+ { 1, "RUN" },
+ { 2, "SLEEP_WAIT" },
+ { 3, "SLEEP_EXIT" },
+ { 4, "SLEEP_RUN_PENDING" },
+ { 5, "POWER_COLLAPSE" },
+ { 6, "CHECK_INTERRUPTS" },
+ { 7, "SWFI" },
+ { 8, "WFPI" },
+ { 9, "EARLY_EXIT" },
+ { 10, "RESET_RECOVER" },
+ { 11, "RESET_ACKNOWLEDGE" },
+ { 12, "ERROR" },
+};
+
+struct sym smsm_entry_type_syms[] = {
+ { 0, "SMSM_APPS_STATE" },
+ { 1, "SMSM_MODEM_STATE" },
+ { 2, "SMSM_Q6_STATE" },
+ { 3, "SMSM_APPS_DEM" },
+ { 4, "SMSM_MODEM_DEM" },
+ { 5, "SMSM_Q6_DEM" },
+ { 6, "SMSM_POWER_MASTER_DEM" },
+ { 7, "SMSM_TIME_MASTER_DEM" },
+};
+
+struct sym smsm_state_syms[] = {
+ { 0x00000001, "INIT" },
+ { 0x00000002, "OSENTERED" },
+ { 0x00000004, "SMDWAIT" },
+ { 0x00000008, "SMDINIT" },
+ { 0x00000010, "RPCWAIT" },
+ { 0x00000020, "RPCINIT" },
+ { 0x00000040, "RESET" },
+ { 0x00000080, "RSA" },
+ { 0x00000100, "RUN" },
+ { 0x00000200, "PWRC" },
+ { 0x00000400, "TIMEWAIT" },
+ { 0x00000800, "TIMEINIT" },
+ { 0x00001000, "PWRC_EARLY_EXIT" },
+ { 0x00002000, "WFPI" },
+ { 0x00004000, "SLEEP" },
+ { 0x00008000, "SLEEPEXIT" },
+ { 0x00010000, "OEMSBL_RELEASE" },
+ { 0x00020000, "APPS_REBOOT" },
+ { 0x00040000, "SYSTEM_POWER_DOWN" },
+ { 0x00080000, "SYSTEM_REBOOT" },
+ { 0x00100000, "SYSTEM_DOWNLOAD" },
+ { 0x00200000, "PWRC_SUSPEND" },
+ { 0x00400000, "APPS_SHUTDOWN" },
+ { 0x00800000, "SMD_LOOPBACK" },
+ { 0x01000000, "RUN_QUIET" },
+ { 0x02000000, "MODEM_WAIT" },
+ { 0x04000000, "MODEM_BREAK" },
+ { 0x08000000, "MODEM_CONTINUE" },
+ { 0x80000000, "UNKNOWN" },
+};
+
+#define ID_SYM 0
+#define BASE_SYM 1
+#define EVENT_SYM 2
+#define ONCRPC_SYM 3
+#define WAKEUP_SYM 4
+#define WAKEUP_INT_SYM 5
+#define SMSM_SYM 6
+#define VOTER_D2_SYM 7
+#define VOTER_D3_SYM 8
+#define DEM_STATE_MASTER_SYM 9
+#define DEM_STATE_SLAVE_SYM 10
+#define SMSM_ENTRY_TYPE_SYM 11
+#define SMSM_STATE_SYM 12
+
+static struct sym_tbl {
+ struct sym *data;
+ int size;
+ struct hlist_head hlist[HSIZE];
+} tbl[] = {
+ { id_syms, ARRAY_SIZE(id_syms) },
+ { base_syms, ARRAY_SIZE(base_syms) },
+ { event_syms, ARRAY_SIZE(event_syms) },
+ { oncrpc_syms, ARRAY_SIZE(oncrpc_syms) },
+ { wakeup_syms, ARRAY_SIZE(wakeup_syms) },
+ { wakeup_int_syms, ARRAY_SIZE(wakeup_int_syms) },
+ { smsm_syms, ARRAY_SIZE(smsm_syms) },
+ { voter_d2_syms, ARRAY_SIZE(voter_d2_syms) },
+ { voter_d3_syms, ARRAY_SIZE(voter_d3_syms) },
+ { dem_state_master_syms, ARRAY_SIZE(dem_state_master_syms) },
+ { dem_state_slave_syms, ARRAY_SIZE(dem_state_slave_syms) },
+ { smsm_entry_type_syms, ARRAY_SIZE(smsm_entry_type_syms) },
+ { smsm_state_syms, ARRAY_SIZE(smsm_state_syms) },
+};
+
+static void find_voters(void)
+{
+ void *x, *next;
+ unsigned size;
+ int i = 0, j = 0;
+
+ x = smem_get_entry(SMEM_SLEEP_STATIC, &size);
+ next = x;
+ while (next && (next < (x + size)) &&
+ ((i + j) < (ARRAY_SIZE(voter_d3_syms) +
+ ARRAY_SIZE(voter_d2_syms)))) {
+
+ if (i < ARRAY_SIZE(voter_d3_syms)) {
+ voter_d3_syms[i].str = (char *) next;
+ i++;
+ } else if (i >= ARRAY_SIZE(voter_d3_syms) &&
+ j < ARRAY_SIZE(voter_d2_syms)) {
+ voter_d2_syms[j].str = (char *) next;
+ j++;
+ }
+
+ next += 9;
+ }
+}
+
+#define hash(val) (val % HSIZE)
+
+static void init_syms(void)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+ for (j = 0; j < HSIZE; ++j)
+ INIT_HLIST_HEAD(&tbl[i].hlist[j]);
+
+ for (i = 0; i < ARRAY_SIZE(tbl); ++i)
+ for (j = 0; j < tbl[i].size; ++j) {
+ INIT_HLIST_NODE(&tbl[i].data[j].node);
+ hlist_add_head(&tbl[i].data[j].node,
+ &tbl[i].hlist[hash(tbl[i].data[j].val)]);
+ }
+}
+
+static char *find_sym(uint32_t id, uint32_t val)
+{
+ struct hlist_node *n;
+ struct sym *s;
+
+ hlist_for_each(n, &tbl[id].hlist[hash(val)]) {
+ s = hlist_entry(n, struct sym, node);
+ if (s->val == val)
+ return s->str;
+ }
+
+ return 0;
+}
+
+#else
+static void init_syms(void) {}
+#endif
+
+static inline unsigned int read_timestamp(void)
+{
+ unsigned int tick;
+
+ do {
+ tick = readl(TIMESTAMP_ADDR);
+ } while (tick != (tick = readl(TIMESTAMP_ADDR)));
+
+ return tick;
+}
+
+static void smem_log_event_from_user(struct smem_log_inst *inst,
+ const char __user *buf, int size, int num)
+{
+ uint32_t idx;
+ uint32_t next_idx;
+ unsigned long flags;
+ uint32_t identifier = 0;
+ uint32_t timetick = 0;
+ int first = 1;
+ int ret;
+
+ remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+
+ while (num--) {
+ idx = *inst->idx;
+
+ if (idx < inst->num) {
+ ret = copy_from_user(&inst->events[idx],
+ buf, size);
+ if (ret) {
+ printk("ERROR %s:%i tried to write "
+ "%i got ret %i",
+ __func__, __LINE__,
+ size, size - ret);
+ goto out;
+ }
+
+ if (first) {
+ identifier =
+ inst->events[idx].
+ identifier;
+ timetick = read_timestamp();
+ first = 0;
+ } else {
+ identifier |= SMEM_LOG_CONT;
+ }
+ inst->events[idx].identifier =
+ identifier;
+ inst->events[idx].timetick =
+ timetick;
+ }
+
+ next_idx = idx + 1;
+ if (next_idx >= inst->num)
+ next_idx = 0;
+ *inst->idx = next_idx;
+
+ buf += sizeof(struct smem_log_item);
+ }
+
+ out:
+ remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+}
+
+static void _smem_log_event(
+ struct smem_log_item __iomem *events,
+ uint32_t __iomem *_idx,
+ remote_spinlock_t *lock,
+ int num,
+ uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3)
+{
+ struct smem_log_item item;
+ uint32_t idx;
+ uint32_t next_idx;
+ unsigned long flags;
+
+ item.timetick = read_timestamp();
+ item.identifier = id;
+ item.data1 = data1;
+ item.data2 = data2;
+ item.data3 = data3;
+
+ remote_spin_lock_irqsave(lock, flags);
+
+ idx = *_idx;
+
+ if (idx < num) {
+ memcpy(&events[idx],
+ &item, sizeof(item));
+ }
+
+ next_idx = idx + 1;
+ if (next_idx >= num)
+ next_idx = 0;
+ *_idx = next_idx;
+
+ remote_spin_unlock_irqrestore(lock, flags);
+}
+
+static void _smem_log_event6(
+ struct smem_log_item __iomem *events,
+ uint32_t __iomem *_idx,
+ remote_spinlock_t *lock,
+ int num,
+ uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6)
+{
+ struct smem_log_item item[2];
+ uint32_t idx;
+ uint32_t next_idx;
+ unsigned long flags;
+
+ item[0].timetick = read_timestamp();
+ item[0].identifier = id;
+ item[0].data1 = data1;
+ item[0].data2 = data2;
+ item[0].data3 = data3;
+ item[1].identifier = item[0].identifier;
+ item[1].timetick = item[0].timetick;
+ item[1].data1 = data4;
+ item[1].data2 = data5;
+ item[1].data3 = data6;
+
+ remote_spin_lock_irqsave(lock, flags);
+
+ idx = *_idx;
+
+ if (idx < (num-1)) {
+ memcpy(&events[idx],
+ &item, sizeof(item));
+ }
+
+ next_idx = idx + 2;
+ if (next_idx >= num)
+ next_idx = 0;
+ *_idx = next_idx;
+
+ remote_spin_unlock_irqrestore(lock, flags);
+}
+
+void smem_log_event(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3)
+{
+ _smem_log_event(inst[GEN].events, inst[GEN].idx,
+ inst[GEN].remote_spinlock, SMEM_LOG_NUM_ENTRIES,
+ id, data1, data2, data3);
+}
+
+void smem_log_event6(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6)
+{
+ _smem_log_event6(inst[GEN].events, inst[GEN].idx,
+ inst[GEN].remote_spinlock, SMEM_LOG_NUM_ENTRIES,
+ id, data1, data2, data3, data4, data5, data6);
+}
+
+void smem_log_event_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3)
+{
+ _smem_log_event(inst[STA].events, inst[STA].idx,
+ inst[STA].remote_spinlock, SMEM_LOG_NUM_STATIC_ENTRIES,
+ id, data1, data2, data3);
+}
+
+void smem_log_event6_to_static(uint32_t id, uint32_t data1, uint32_t data2,
+ uint32_t data3, uint32_t data4, uint32_t data5,
+ uint32_t data6)
+{
+ _smem_log_event6(inst[STA].events, inst[STA].idx,
+ inst[STA].remote_spinlock, SMEM_LOG_NUM_STATIC_ENTRIES,
+ id, data1, data2, data3, data4, data5, data6);
+}
+
+static int _smem_log_init(void)
+{
+ inst[GEN].which_log = GEN;
+ inst[GEN].events =
+ (struct smem_log_item *)smem_alloc(SMEM_SMEM_LOG_EVENTS,
+ SMEM_LOG_EVENTS_SIZE);
+ inst[GEN].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_IDX,
+ sizeof(uint32_t));
+ if (!inst[GEN].events || !inst[GEN].idx) {
+ pr_err("%s: no log or log_idx allocated, "
+ "smem_log disabled\n", __func__);
+ }
+ inst[GEN].num = SMEM_LOG_NUM_ENTRIES;
+ inst[GEN].remote_spinlock = &remote_spinlock;
+
+ inst[STA].which_log = STA;
+ inst[STA].events =
+ (struct smem_log_item *)
+ smem_alloc(SMEM_SMEM_STATIC_LOG_EVENTS,
+ SMEM_STATIC_LOG_EVENTS_SIZE);
+ inst[STA].idx = (uint32_t *)smem_alloc(SMEM_SMEM_STATIC_LOG_IDX,
+ sizeof(uint32_t));
+ if (!inst[STA].events || !inst[STA].idx) {
+ pr_err("%s: no static log or log_idx "
+ "allocated, smem_log disabled\n", __func__);
+ }
+ inst[STA].num = SMEM_LOG_NUM_STATIC_ENTRIES;
+ inst[STA].remote_spinlock = &remote_spinlock_static;
+
+ inst[POW].which_log = POW;
+ inst[POW].events =
+ (struct smem_log_item *)
+ smem_alloc(SMEM_SMEM_LOG_POWER_EVENTS,
+ SMEM_POWER_LOG_EVENTS_SIZE);
+ inst[POW].idx = (uint32_t *)smem_alloc(SMEM_SMEM_LOG_POWER_IDX,
+ sizeof(uint32_t));
+ if (!inst[POW].events || !inst[POW].idx) {
+ pr_err("%s: no power log or log_idx "
+ "allocated, smem_log disabled\n", __func__);
+ }
+ inst[POW].num = SMEM_LOG_NUM_POWER_ENTRIES;
+ inst[POW].remote_spinlock = &remote_spinlock;
+
+ remote_spin_lock_init(&remote_spinlock,
+ SMEM_SPINLOCK_SMEM_LOG);
+ remote_spin_lock_init(&remote_spinlock_static,
+ SMEM_SPINLOCK_STATIC_LOG);
+
+ init_syms();
+
+ return 0;
+}
+
+static ssize_t smem_log_read_bin(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int idx;
+ int orig_idx;
+ unsigned long flags;
+ int ret;
+ int tot_bytes = 0;
+ struct smem_log_inst *inst;
+
+ inst = fp->private_data;
+
+ remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+
+ orig_idx = *inst->idx;
+ idx = orig_idx;
+
+ while (1) {
+ idx--;
+ if (idx < 0)
+ idx = inst->num - 1;
+ if (idx == orig_idx) {
+ ret = tot_bytes;
+ break;
+ }
+
+ if ((tot_bytes + sizeof(struct smem_log_item)) > count) {
+ ret = tot_bytes;
+ break;
+ }
+
+ ret = copy_to_user(buf, &inst[GEN].events[idx],
+ sizeof(struct smem_log_item));
+ if (ret) {
+ ret = -EIO;
+ break;
+ }
+
+ tot_bytes += sizeof(struct smem_log_item);
+
+ buf += sizeof(struct smem_log_item);
+ }
+
+ remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+
+ return ret;
+}
+
+static ssize_t smem_log_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ char loc_buf[128];
+ int i;
+ int idx;
+ int orig_idx;
+ unsigned long flags;
+ int ret;
+ int tot_bytes = 0;
+ struct smem_log_inst *inst;
+
+ inst = fp->private_data;
+
+ remote_spin_lock_irqsave(inst->remote_spinlock, flags);
+
+ orig_idx = *inst->idx;
+ idx = orig_idx;
+
+ while (1) {
+ idx--;
+ if (idx < 0)
+ idx = inst->num - 1;
+ if (idx == orig_idx) {
+ ret = tot_bytes;
+ break;
+ }
+
+ i = scnprintf(loc_buf, 128,
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ inst->events[idx].identifier,
+ inst->events[idx].timetick,
+ inst->events[idx].data1,
+ inst->events[idx].data2,
+ inst->events[idx].data3);
+ if (i == 0) {
+ ret = -EIO;
+ break;
+ }
+
+ if ((tot_bytes + i) > count) {
+ ret = tot_bytes;
+ break;
+ }
+
+ tot_bytes += i;
+
+ ret = copy_to_user(buf, loc_buf, i);
+ if (ret) {
+ ret = -EIO;
+ break;
+ }
+
+ buf += i;
+ }
+
+ remote_spin_unlock_irqrestore(inst->remote_spinlock, flags);
+
+ return ret;
+}
+
+static ssize_t smem_log_write_bin(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ if (count < sizeof(struct smem_log_item))
+ return -EINVAL;
+
+ smem_log_event_from_user(fp->private_data, buf,
+ sizeof(struct smem_log_item),
+ count / sizeof(struct smem_log_item));
+
+ return count;
+}
+
+static ssize_t smem_log_write(struct file *fp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int ret;
+ const char delimiters[] = " ,;";
+ char locbuf[256] = {0};
+ uint32_t val[10];
+ int vals = 0;
+ char *token;
+ char *running;
+ struct smem_log_inst *inst;
+ unsigned long res;
+
+ inst = fp->private_data;
+
+ if (count < 0) {
+ printk(KERN_ERR "ERROR: %s passed neg count = %i\n",
+ __func__, count);
+ return -EINVAL;
+ }
+
+ count = count > 255 ? 255 : count;
+
+ locbuf[count] = '\0';
+
+ ret = copy_from_user(locbuf, buf, count);
+ if (ret != 0) {
+ printk(KERN_ERR "ERROR: %s could not copy %i bytes\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ D(KERN_ERR "%s: ", __func__);
+ D_DUMP_BUFFER("We got", len, locbuf);
+
+ running = locbuf;
+
+ token = strsep(&running, delimiters);
+ while (token && vals < ARRAY_SIZE(val)) {
+ if (*token != '\0') {
+ D(KERN_ERR "%s: ", __func__);
+ D_DUMP_BUFFER("", strlen(token), token);
+ ret = strict_strtoul(token, 0, &res);
+ if (ret) {
+ printk(KERN_ERR "ERROR: %s:%i got bad char "
+ "at strict_strtoul\n",
+ __func__, __LINE__-4);
+ return -EINVAL;
+ }
+ val[vals++] = res;
+ }
+ token = strsep(&running, delimiters);
+ }
+
+ if (vals > 5) {
+ if (inst->which_log == GEN)
+ smem_log_event6(val[0], val[2], val[3], val[4],
+ val[7], val[8], val[9]);
+ else if (inst->which_log == STA)
+ smem_log_event6_to_static(val[0],
+ val[2], val[3], val[4],
+ val[7], val[8], val[9]);
+ else
+ return -1;
+ } else {
+ if (inst->which_log == GEN)
+ smem_log_event(val[0], val[2], val[3], val[4]);
+ else if (inst->which_log == STA)
+ smem_log_event_to_static(val[0],
+ val[2], val[3], val[4]);
+ else
+ return -1;
+ }
+
+ return count;
+}
+
+static int smem_log_open(struct inode *ip, struct file *fp)
+{
+ fp->private_data = &inst[GEN];
+
+ return 0;
+}
+
+
+static int smem_log_release(struct inode *ip, struct file *fp)
+{
+ return 0;
+}
+
+static int smem_log_ioctl(struct inode *ip, struct file *fp,
+ unsigned int cmd, unsigned long arg);
+
+static const struct file_operations smem_log_fops = {
+ .owner = THIS_MODULE,
+ .read = smem_log_read,
+ .write = smem_log_write,
+ .open = smem_log_open,
+ .release = smem_log_release,
+ .ioctl = smem_log_ioctl,
+};
+
+static const struct file_operations smem_log_bin_fops = {
+ .owner = THIS_MODULE,
+ .read = smem_log_read_bin,
+ .write = smem_log_write_bin,
+ .open = smem_log_open,
+ .release = smem_log_release,
+ .ioctl = smem_log_ioctl,
+};
+
+static int smem_log_ioctl(struct inode *ip, struct file *fp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct smem_log_inst *inst;
+
+ inst = fp->private_data;
+
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+
+ case SMIOC_SETMODE:
+ if (arg == SMIOC_TEXT) {
+ D("%s set text mode\n", __func__);
+ fp->f_op = &smem_log_fops;
+ } else if (arg == SMIOC_BINARY) {
+ D("%s set bin mode\n", __func__);
+ fp->f_op = &smem_log_bin_fops;
+ } else {
+ return -EINVAL;
+ }
+ break;
+ case SMIOC_SETLOG:
+ if (arg == SMIOC_LOG)
+ fp->private_data = &inst[GEN];
+ else if (arg == SMIOC_STATIC_LOG)
+ fp->private_data = &inst[STA];
+ else
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static struct miscdevice smem_log_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "smem_log",
+ .fops = &smem_log_fops,
+};
+
+#if defined(CONFIG_DEBUG_FS)
+
+static int _debug_dump(int log, char *buf, int max)
+{
+ unsigned int idx;
+ int orig_idx;
+ unsigned long flags;
+ int i = 0;
+
+ if (!inst[log].events)
+ return 0;
+
+ remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
+
+ orig_idx = *inst[log].idx;
+ idx = orig_idx;
+
+ while (1) {
+ idx++;
+ if (idx > inst[log].num - 1)
+ idx = 0;
+ if (idx == orig_idx)
+ break;
+
+ if (idx < inst[log].num) {
+ if (!inst[log].events[idx].identifier)
+ continue;
+
+ i += scnprintf(buf + i, max - i,
+ "%08x %08x %08x %08x %08x\n",
+ inst[log].events[idx].identifier,
+ inst[log].events[idx].timetick,
+ inst[log].events[idx].data1,
+ inst[log].events[idx].data2,
+ inst[log].events[idx].data3);
+ }
+ }
+
+ remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
+
+ return i;
+}
+
+static int _debug_dump_sym(int log, char *buf, int max)
+{
+ unsigned int idx;
+ int orig_idx;
+ unsigned long flags;
+ int i = 0;
+
+ char *proc;
+ char *sub;
+ char *id;
+ char *sym = NULL;
+
+ uint32_t data[3];
+
+ uint32_t proc_val = 0;
+ uint32_t sub_val = 0;
+ uint32_t id_val = 0;
+ uint32_t id_only_val = 0;
+ uint32_t data1 = 0;
+ uint32_t data2 = 0;
+ uint32_t data3 = 0;
+
+ int k;
+
+ if (!inst[log].events)
+ return 0;
+
+ find_voters(); /* need to call each time in case voters come and go */
+
+ i += scnprintf(buf + i, max - i, "Voters:\n");
+ for (k = 0; k < ARRAY_SIZE(voter_d3_syms); ++k)
+ if (voter_d3_syms[k].str)
+ i += scnprintf(buf + i, max - i, "%s ",
+ voter_d3_syms[k].str);
+ for (k = 0; k < ARRAY_SIZE(voter_d2_syms); ++k)
+ if (voter_d2_syms[k].str)
+ i += scnprintf(buf + i, max - i, "%s ",
+ voter_d2_syms[k].str);
+ i += scnprintf(buf + i, max - i, "\n");
+
+ remote_spin_lock_irqsave(inst[log].remote_spinlock, flags);
+
+ orig_idx = *inst[log].idx;
+ idx = orig_idx;
+
+ while (1) {
+ idx++;
+ if (idx > inst[log].num - 1)
+ idx = 0;
+ if (idx == orig_idx) {
+ i += scnprintf(buf + i, max - i, "\n");
+ break;
+ }
+ if (idx < inst[log].num) {
+ if (!inst[log].events[idx].identifier)
+ continue;
+
+ proc_val = PROC & inst[log].events[idx].identifier;
+ sub_val = SUB & inst[log].events[idx].identifier;
+ id_val = (SUB | ID) & inst[log].events[idx].identifier;
+ id_only_val = ID & inst[log].events[idx].identifier;
+ data1 = inst[log].events[idx].data1;
+ data2 = inst[log].events[idx].data2;
+ data3 = inst[log].events[idx].data3;
+
+ if (!(proc_val & SMEM_LOG_CONT)) {
+ i += scnprintf(buf + i, max - i, "\n");
+
+ proc = find_sym(ID_SYM, proc_val);
+
+ if (proc)
+ i += scnprintf(buf + i, max - i,
+ "%4s: ",
+ proc);
+ else
+ i += scnprintf(buf + i, max - i,
+ "%04x: ",
+ PROC &
+ inst[log].events[idx].
+ identifier);
+
+ i += scnprintf(buf + i, max - i,
+ "%10u ",
+ inst[log].events[idx].timetick);
+
+ sub = find_sym(BASE_SYM, sub_val);
+
+ if (sub)
+ i += scnprintf(buf + i, max - i,
+ "%9s: ",
+ sub);
+ else
+ i += scnprintf(buf + i, max - i,
+ "%08x: ",
+ sub_val);
+
+ id = find_sym(EVENT_SYM, id_val);
+
+ if (id)
+ i += scnprintf(buf + i, max - i,
+ "%11s: ",
+ id);
+ else
+ i += scnprintf(buf + i, max - i,
+ "%08x: ",
+ id_only_val);
+ }
+
+ if ((proc_val & SMEM_LOG_CONT) &&
+ (id_val == ONCRPC_LOG_EVENT_STD_CALL ||
+ id_val == ONCRPC_LOG_EVENT_STD_REPLY)) {
+ data[0] = data1;
+ data[1] = data2;
+ data[2] = data3;
+ i += scnprintf(buf + i, max - i,
+ " %.16s",
+ (char *) data);
+ } else if (proc_val & SMEM_LOG_CONT) {
+ i += scnprintf(buf + i, max - i,
+ " %08x %08x %08x",
+ data1,
+ data2,
+ data3);
+ } else if (id_val == ONCRPC_LOG_EVENT_STD_CALL) {
+ sym = find_sym(ONCRPC_SYM, data2);
+
+ if (sym)
+ i += scnprintf(buf + i, max - i,
+ "xid:%4i %8s proc:%3i",
+ data1,
+ sym,
+ data3);
+ else
+ i += scnprintf(buf + i, max - i,
+ "xid:%4i %08x proc:%3i",
+ data1,
+ data2,
+ data3);
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+ } else if (id_val == DEM_STATE_CHANGE) {
+ if (data1 == 1) {
+ i += scnprintf(buf + i,
+ max - i,
+ "MASTER: ");
+ sym = find_sym(DEM_STATE_MASTER_SYM,
+ data2);
+ } else if (data1 == 0) {
+ i += scnprintf(buf + i,
+ max - i,
+ " SLAVE: ");
+ sym = find_sym(DEM_STATE_SLAVE_SYM,
+ data2);
+ } else {
+ i += scnprintf(buf + i,
+ max - i,
+ "%x: ",
+ data1);
+ sym = NULL;
+ }
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "from:%s ",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "from:0x%x ",
+ data2);
+
+ if (data1 == 1)
+ sym = find_sym(DEM_STATE_MASTER_SYM,
+ data3);
+ else if (data1 == 0)
+ sym = find_sym(DEM_STATE_SLAVE_SYM,
+ data3);
+ else
+ sym = NULL;
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "to:%s ",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "to:0x%x ",
+ data3);
+
+ } else if (id_val == DEM_STATE_MACHINE_ENTER) {
+ i += scnprintf(buf + i,
+ max - i,
+ "swfi:%i timer:%i manexit:%i",
+ data1, data2, data3);
+
+ } else if (id_val == DEM_TIME_SYNC_REQUEST ||
+ id_val == DEM_TIME_SYNC_POLL ||
+ id_val == DEM_TIME_SYNC_INIT) {
+ sym = find_sym(SMSM_ENTRY_TYPE_SYM,
+ data1);
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "hostid:%s",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "hostid:%x",
+ data1);
+
+ } else if (id_val == DEM_TIME_SYNC_START ||
+ id_val == DEM_TIME_SYNC_SEND_VALUE) {
+ unsigned mask = 0x1;
+ unsigned tmp = 0;
+ if (id_val == DEM_TIME_SYNC_START)
+ i += scnprintf(buf + i,
+ max - i,
+ "req:");
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "pol:");
+ while (mask) {
+ if (mask & data1) {
+ sym = find_sym(
+ SMSM_ENTRY_TYPE_SYM,
+ tmp);
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s ",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "%i ",
+ tmp);
+ }
+ mask <<= 1;
+ tmp++;
+ }
+ if (id_val == DEM_TIME_SYNC_SEND_VALUE)
+ i += scnprintf(buf + i,
+ max - i,
+ "tick:%x",
+ data2);
+ } else if (id_val == DEM_SMSM_ISR) {
+ unsigned vals[] = {data2, data3};
+ unsigned j;
+ unsigned mask;
+ unsigned tmp;
+ unsigned once;
+ sym = find_sym(SMSM_ENTRY_TYPE_SYM,
+ data1);
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s ",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "%x ",
+ data1);
+
+ for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+ i += scnprintf(buf + i, max - i, "[");
+ mask = 0x80000000;
+ once = 0;
+ while (mask) {
+ tmp = vals[j] & mask;
+ mask >>= 1;
+ if (!tmp)
+ continue;
+ sym = find_sym(SMSM_STATE_SYM,
+ tmp);
+
+ if (once)
+ i += scnprintf(buf + i,
+ max - i,
+ " ");
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "0x%x",
+ tmp);
+ once = 1;
+ }
+ i += scnprintf(buf + i, max - i, "] ");
+ }
+#else
+ } else if (id_val == DEMAPPS_WAKEUP_REASON) {
+ unsigned mask = 0x80000000;
+ unsigned tmp = 0;
+ while (mask) {
+ tmp = data1 & mask;
+ mask >>= 1;
+ if (!tmp)
+ continue;
+ sym = find_sym(WAKEUP_SYM, tmp);
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s ",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "%08x ",
+ tmp);
+ }
+ i += scnprintf(buf + i, max - i,
+ "%08x %08x",
+ data2,
+ data3);
+ } else if (id_val == DEMMOD_APPS_WAKEUP_INT) {
+ sym = find_sym(WAKEUP_INT_SYM, data1);
+
+ if (sym)
+ i += scnprintf(buf + i, max - i,
+ "%s %08x %08x",
+ sym,
+ data2,
+ data3);
+ else
+ i += scnprintf(buf + i, max - i,
+ "%08x %08x %08x",
+ data1,
+ data2,
+ data3);
+ } else if (id_val == DEM_NO_SLEEP ||
+ id_val == NO_SLEEP_NEW) {
+ unsigned vals[] = {data3, data2};
+ unsigned j;
+ unsigned mask;
+ unsigned tmp;
+ unsigned once;
+ i += scnprintf(buf + i, max - i, "%08x ",
+ data1);
+ i += scnprintf(buf + i, max - i, "[");
+ once = 0;
+ for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+ mask = 0x00000001;
+ while (mask) {
+ tmp = vals[j] & mask;
+ mask <<= 1;
+ if (!tmp)
+ continue;
+ if (j == 0)
+ sym = find_sym(
+ VOTER_D3_SYM,
+ tmp);
+ else
+ sym = find_sym(
+ VOTER_D2_SYM,
+ tmp);
+
+ if (once)
+ i += scnprintf(buf + i,
+ max - i,
+ " ");
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "%08x",
+ tmp);
+ once = 1;
+ }
+ }
+ i += scnprintf(buf + i, max - i, "] ");
+#endif
+ } else if (id_val == SMEM_LOG_EVENT_CB) {
+ unsigned vals[] = {data2, data3};
+ unsigned j;
+ unsigned mask;
+ unsigned tmp;
+ unsigned once;
+ i += scnprintf(buf + i, max - i, "%08x ",
+ data1);
+ for (j = 0; j < ARRAY_SIZE(vals); ++j) {
+ i += scnprintf(buf + i, max - i, "[");
+ mask = 0x80000000;
+ once = 0;
+ while (mask) {
+ tmp = vals[j] & mask;
+ mask >>= 1;
+ if (!tmp)
+ continue;
+ sym = find_sym(SMSM_SYM, tmp);
+
+ if (once)
+ i += scnprintf(buf + i,
+ max - i,
+ " ");
+ if (sym)
+ i += scnprintf(buf + i,
+ max - i,
+ "%s",
+ sym);
+ else
+ i += scnprintf(buf + i,
+ max - i,
+ "%08x",
+ tmp);
+ once = 1;
+ }
+ i += scnprintf(buf + i, max - i, "] ");
+ }
+ } else {
+ i += scnprintf(buf + i, max - i,
+ "%08x %08x %08x",
+ data1,
+ data2,
+ data3);
+ }
+ }
+ }
+
+ remote_spin_unlock_irqrestore(inst[log].remote_spinlock, flags);
+
+ return i;
+}
+
+static int debug_dump(char *buf, int max)
+{
+ return _debug_dump(GEN, buf, max);
+}
+
+static int debug_dump_sym(char *buf, int max)
+{
+ return _debug_dump_sym(GEN, buf, max);
+}
+
+static int debug_dump_static(char *buf, int max)
+{
+ return _debug_dump(STA, buf, max);
+}
+
+static int debug_dump_static_sym(char *buf, int max)
+{
+ return _debug_dump_sym(STA, buf, max);
+}
+
+static int debug_dump_power(char *buf, int max)
+{
+ return _debug_dump(POW, buf, max);
+}
+
+static int debug_dump_power_sym(char *buf, int max)
+{
+ return _debug_dump_sym(POW, buf, max);
+}
+
+#define SMEM_LOG_ITEM_PRINT_SIZE 160
+
+#define EVENTS_PRINT_SIZE \
+(SMEM_LOG_ITEM_PRINT_SIZE * SMEM_LOG_NUM_ENTRIES)
+
+static char debug_buffer[EVENTS_PRINT_SIZE];
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int (*fill)(char *buf, int max) = file->private_data;
+ int bsize = fill(debug_buffer, EVENTS_PRINT_SIZE);
+ return simple_read_from_buffer(buf, count, ppos, debug_buffer,
+ bsize);
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+};
+
+static void debug_create(const char *name, mode_t mode,
+ struct dentry *dent,
+ int (*fill)(char *buf, int max))
+{
+ debugfs_create_file(name, mode, dent, fill, &debug_ops);
+}
+
+static void smem_log_debugfs_init(void)
+{
+ struct dentry *dent;
+
+ dent = debugfs_create_dir("smem_log", 0);
+ if (IS_ERR(dent))
+ return;
+
+ debug_create("dump", 0444, dent, debug_dump);
+ debug_create("dump_sym", 0444, dent, debug_dump_sym);
+ debug_create("dump_static", 0444, dent, debug_dump_static);
+ debug_create("dump_static_sym", 0444, dent, debug_dump_static_sym);
+ debug_create("dump_power", 0444, dent, debug_dump_power);
+ debug_create("dump_power_sym", 0444, dent, debug_dump_power_sym);
+}
+#else
+static void smem_log_debugfs_init(void) {}
+#endif
+
+static int __init smem_log_init(void)
+{
+ int ret;
+
+ ret = _smem_log_init();
+ if (ret < 0)
+ return ret;
+
+ smem_log_debugfs_init();
+
+ return misc_register(&smem_log_dev);
+}
+
+
+module_init(smem_log_init);
+
+MODULE_DESCRIPTION("smem log");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
new file mode 100644
index 000000000000..0c65e25c9c66
--- /dev/null
+++ b/arch/arm/mach-msm/socinfo.c
@@ -0,0 +1,430 @@
+/* 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 nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this software
+ * may be relicensed by the recipient under the terms of the GNU General Public
+ * License version 2 ("GPL") and only version 2, in which case the provisions of
+ * the GPL apply INSTEAD OF those given above. If the recipient relicenses the
+ * software under the GPL, then the identification text in the MODULE_LICENSE
+ * macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
+ * recipient changes the license terms to the GPL, subsequent recipients shall
+ * not relicense under alternate licensing terms, including the BSD or dual
+ * BSD/GPL terms. In addition, the following license statement immediately
+ * below and between the words START and END shall also then apply when this
+ * software is relicensed under the GPL:
+ *
+ * START
+ *
+ * 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.
+ *
+ * END
+ *
+ * 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 AND FITNESS FOR A PARTICULAR PURPOSE
+ * 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.
+ *
+ */
+/*
+ * SOC Info Routines
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/sysdev.h>
+#include "socinfo.h"
+#include "smd_private.h"
+
+enum {
+ HW_PLATFORM_UNKNOWN = 0,
+ HW_PLATFORM_SURF = 1,
+ HW_PLATFORM_FFA = 2,
+ HW_PLATFORM_FLUID = 3,
+ HW_PLATFORM_INVALID
+};
+
+char *hw_platform[] = {
+ "Unknown",
+ "Surf",
+ "FFA",
+ "Fluid"
+};
+
+/* Used to parse shared memory. Must match the modem. */
+struct socinfo_v1 {
+ uint32_t format;
+ uint32_t id;
+ uint32_t version;
+ char build_id[32];
+};
+
+struct socinfo_v2 {
+ struct socinfo_v1 v1;
+
+ /* only valid when format==2 */
+ uint32_t raw_id;
+ uint32_t raw_version;
+};
+
+struct socinfo_v3 {
+ struct socinfo_v2 v2;
+
+ /* only valid when format==3 */
+ uint32_t hw_platform;
+};
+
+static union {
+ struct socinfo_v1 v1;
+ struct socinfo_v2 v2;
+ struct socinfo_v3 v3;
+} *socinfo;
+
+static enum msm_cpu cpu_of_id[] = {
+
+ /* 7x01 IDs */
+ [1] = MSM_CPU_7X01,
+ [16] = MSM_CPU_7X01,
+ [17] = MSM_CPU_7X01,
+ [18] = MSM_CPU_7X01,
+ [19] = MSM_CPU_7X01,
+ [23] = MSM_CPU_7X01,
+ [25] = MSM_CPU_7X01,
+ [26] = MSM_CPU_7X01,
+ [32] = MSM_CPU_7X01,
+ [33] = MSM_CPU_7X01,
+ [34] = MSM_CPU_7X01,
+ [35] = MSM_CPU_7X01,
+
+ /* 7x25 IDs */
+ [20] = MSM_CPU_7X25,
+ [21] = MSM_CPU_7X25,
+ [24] = MSM_CPU_7X25,
+ [27] = MSM_CPU_7X25,
+ [39] = MSM_CPU_7X25,
+ [40] = MSM_CPU_7X25,
+ [41] = MSM_CPU_7X25,
+ [42] = MSM_CPU_7X25,
+
+ /* 7x27 IDs */
+ [43] = MSM_CPU_7X27,
+ [44] = MSM_CPU_7X27,
+ [61] = MSM_CPU_7X27,
+
+ /* 8x50 IDs */
+ [30] = MSM_CPU_8X50,
+ [36] = MSM_CPU_8X50,
+ [37] = MSM_CPU_8X50,
+ [38] = MSM_CPU_8X50,
+
+ /* 7x30 IDs */
+ [59] = MSM_CPU_7X30,
+ [60] = MSM_CPU_7X30,
+
+ /* Uninitialized IDs are not known to run Linux.
+ MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
+ considered as unknown CPU. Any ID > 60 is invalid. */
+};
+
+static enum msm_cpu cur_cpu;
+
+uint32_t socinfo_get_id(void)
+{
+ return (socinfo) ? socinfo->v1.id : 0;
+}
+
+uint32_t socinfo_get_version(void)
+{
+ return (socinfo) ? socinfo->v1.version : 0;
+}
+
+char *socinfo_get_build_id(void)
+{
+ return (socinfo) ? socinfo->v1.build_id : NULL;
+}
+
+uint32_t socinfo_get_raw_id(void)
+{
+ return socinfo ?
+ (socinfo->v1.format == 2 ? socinfo->v2.raw_id : 0)
+ : 0;
+}
+
+uint32_t socinfo_get_raw_version(void)
+{
+ return socinfo ?
+ (socinfo->v1.format == 2 ? socinfo->v2.raw_version : 0)
+ : 0;
+}
+
+uint32_t socinfo_get_platform_type(void)
+{
+ return socinfo ?
+ (socinfo->v1.format == 3 ? socinfo->v3.hw_platform : 0)
+ : 0;
+}
+
+enum msm_cpu socinfo_get_msm_cpu(void)
+{
+ return cur_cpu;
+}
+
+static ssize_t
+socinfo_show_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_id());
+}
+
+static ssize_t
+socinfo_show_version(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ uint32_t version;
+
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+
+ version = socinfo_get_version();
+ return snprintf(buf, PAGE_SIZE, "%u.%u\n",
+ SOCINFO_VERSION_MAJOR(version),
+ SOCINFO_VERSION_MINOR(version));
+}
+
+static ssize_t
+socinfo_show_build_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n", socinfo_get_build_id());
+}
+
+static ssize_t
+socinfo_show_raw_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+ if (socinfo->v1.format != 2) {
+ pr_err("%s: Raw ID not available!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_id());
+}
+
+static ssize_t
+socinfo_show_raw_version(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+ if (socinfo->v1.format != 2) {
+ pr_err("%s: Raw version not available!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_version());
+}
+
+static ssize_t
+socinfo_show_platform_type(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_type;
+
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+ if (socinfo->v1.format != 3) {
+ pr_err("%s: platform type not available!\n", __func__);
+ return 0;
+ }
+
+ hw_type = socinfo_get_platform_type();
+ if (hw_type >= HW_PLATFORM_INVALID) {
+ pr_err("%s: Invalid hardware platform type found\n",
+ __func__);
+ hw_type = HW_PLATFORM_UNKNOWN;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%-.32s\n", hw_platform[hw_type]);
+}
+
+static struct sysdev_attribute socinfo_v1_files[] = {
+ _SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
+ _SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
+ _SYSDEV_ATTR(build_id, 0444, socinfo_show_build_id, NULL),
+};
+
+static struct sysdev_attribute socinfo_v2_files[] = {
+ _SYSDEV_ATTR(raw_id, 0444, socinfo_show_raw_id, NULL),
+ _SYSDEV_ATTR(raw_version, 0444, socinfo_show_raw_version, NULL),
+};
+
+static struct sysdev_attribute socinfo_v3_files[] = {
+ _SYSDEV_ATTR(hw_platform, 0444, socinfo_show_platform_type, NULL),
+};
+
+static struct sysdev_class soc_sysdev_class = {
+ .name = "soc",
+};
+
+static struct sys_device soc_sys_device = {
+ .id = 0,
+ .cls = &soc_sysdev_class,
+};
+
+static void __init socinfo_create_files(struct sys_device *dev,
+ struct sysdev_attribute files[],
+ int size)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ int err = sysdev_create_file(dev, &files[i]);
+ if (err) {
+ pr_err("%s: sysdev_create_file(%s)=%d\n",
+ __func__, files[i].attr.name, err);
+ return;
+ }
+ }
+}
+
+static void __init socinfo_init_sysdev(void)
+{
+ int err;
+
+ err = sysdev_class_register(&soc_sysdev_class);
+ if (err) {
+ pr_err("%s: sysdev_class_register fail (%d)\n",
+ __func__, err);
+ return;
+ }
+ err = sysdev_register(&soc_sys_device);
+ if (err) {
+ pr_err("%s: sysdev_register fail (%d)\n",
+ __func__, err);
+ return;
+ }
+ socinfo_create_files(&soc_sys_device, socinfo_v1_files,
+ ARRAY_SIZE(socinfo_v1_files));
+ if (socinfo->v1.format < 2)
+ return;
+ socinfo_create_files(&soc_sys_device, socinfo_v2_files,
+ ARRAY_SIZE(socinfo_v2_files));
+
+ if (socinfo->v1.format < 3)
+ return;
+
+ socinfo_create_files(&soc_sys_device, socinfo_v3_files,
+ ARRAY_SIZE(socinfo_v3_files));
+
+}
+
+int __init socinfo_init(void)
+{
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v3));
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v2));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v1));
+
+ if (!socinfo) {
+ pr_err("%s: Can't find SMEM_HW_SW_BUILD_ID\n",
+ __func__);
+ return -EIO;
+ }
+
+ WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
+ WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
+ "New IDs added! ID => CPU mapping might need an update.\n");
+
+ if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
+ cur_cpu = cpu_of_id[socinfo->v1.id];
+
+ socinfo_init_sysdev();
+
+ switch (socinfo->v1.format) {
+ case 1:
+ pr_info("%s: v%u, id=%u, ver=%u.%u\n",
+ __func__, socinfo->v1.format, socinfo->v1.id,
+ SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+ SOCINFO_VERSION_MINOR(socinfo->v1.version));
+ break;
+ case 2:
+ pr_info("%s: v%u, id=%u, ver=%u.%u, "
+ "raw_id=%u, raw_ver=%u\n",
+ __func__, socinfo->v1.format, socinfo->v1.id,
+ SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+ SOCINFO_VERSION_MINOR(socinfo->v1.version),
+ socinfo->v2.raw_id, socinfo->v2.raw_version);
+ break;
+ case 3:
+ pr_info("%s: v%u, id=%u, ver=%u.%u, "
+ "raw_id=%u, raw_ver=%u, hw_plat=%u\n",
+ __func__, socinfo->v1.format, socinfo->v1.id,
+ SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+ SOCINFO_VERSION_MINOR(socinfo->v1.version),
+ socinfo->v2.raw_id, socinfo->v2.raw_version,
+ socinfo->v3.hw_platform);
+ break;
+ default:
+ pr_err("%s: Unknown format found\n", __func__);
+ break;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/socinfo.h b/arch/arm/mach-msm/socinfo.h
new file mode 100644
index 000000000000..a3c04b19f4ba
--- /dev/null
+++ b/arch/arm/mach-msm/socinfo.h
@@ -0,0 +1,97 @@
+/* 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 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SOCINFO_H_
+#define _ARCH_ARM_MACH_MSM_SOCINFO_H_
+
+/*
+ * SOC version type with major number in the upper 16 bits and minor
+ * number in the lower 16 bits. For example:
+ * 1.0 -> 0x00010000
+ * 2.3 -> 0x00020003
+ */
+#define SOCINFO_VERSION_MAJOR(ver) ((ver & 0xffff0000) >> 16)
+#define SOCINFO_VERSION_MINOR(ver) (ver & 0x0000ffff)
+
+enum msm_cpu {
+ MSM_CPU_UNKNOWN = 0,
+ MSM_CPU_7X01,
+ MSM_CPU_7X25,
+ MSM_CPU_7X27,
+ MSM_CPU_8X50,
+ MSM_CPU_7X30,
+};
+
+enum msm_cpu socinfo_get_msm_cpu(void);
+uint32_t socinfo_get_id(void);
+uint32_t socinfo_get_version(void);
+char *socinfo_get_build_id(void);
+uint32_t socinfo_get_platform_type(void);
+int __init socinfo_init(void) __must_check;
+
+static inline int cpu_is_msm7x01(void)
+{
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_7X01;
+}
+
+static inline int cpu_is_msm7x25(void)
+{
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_7X25;
+}
+
+static inline int cpu_is_msm7x27(void)
+{
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_7X27;
+}
+
+static inline int cpu_is_qsd8x50(void)
+{
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8X50;
+}
+
+static inline int cpu_is_msm7x30(void)
+{
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_7X30;
+}
+
+#endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 4855b8ca5101..02fbdca60525 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,7 @@
/* linux/arch/arm/mach-msm/timer.c
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, 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
@@ -25,21 +26,62 @@
#include <asm/mach/time.h>
#include <mach/msm_iomap.h>
-#define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
+#include "smd_private.h"
+#include "timer.h"
+
+enum {
+ MSM_TIMER_DEBUG_SYNC = 1U << 0,
+};
+static int msm_timer_debug_mask;
+module_param_named(debug_mask, msm_timer_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GPT_BASE (MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24)
+#else
+#define MSM_GPT_BASE MSM_TMR_BASE
+#define MSM_DGT_BASE (MSM_TMR_BASE + 0x10)
+#endif
+
+#if defined(CONFIG_ARCH_MSM_ARM11)
#define MSM_DGT_SHIFT (5)
+#else
+#define MSM_DGT_SHIFT (0)
+#endif
#define TIMER_MATCH_VAL 0x0000
#define TIMER_COUNT_VAL 0x0004
#define TIMER_ENABLE 0x0008
-#define TIMER_ENABLE_CLR_ON_MATCH_EN 2
-#define TIMER_ENABLE_EN 1
-#define TIMER_CLEAR 0x000C
+#define TIMER_ENABLE_EN 1
-#define CSR_PROTECTION 0x0020
-#define CSR_PROTECTION_EN 1
+#if defined(CONFIG_ARCH_QSD8X50)
+#define DGT_HZ 4800000 /* Uses TCXO/4 (19.2 MHz / 4) */
+#elif defined(CONFIG_ARCH_MSM7X30)
+#define DGT_HZ 6144000 /* Uses LPXO/4 (24.576 MHz / 4) */
+#else
+#define DGT_HZ 19200000 /* Uses TCXO (19.2 MHz) */
+#endif
#define GPT_HZ 32768
-#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+#define SCLK_HZ 32768
+
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+/* Time Master State Bits */
+#define MASTER_BITS_PER_CPU 1
+#define MASTER_TIME_PENDING \
+ (0x01UL << (MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
+
+/* Time Slave State Bits */
+#define SLAVE_TIME_REQUEST 0x0400
+#define SLAVE_TIME_POLL 0x0800
+#define SLAVE_TIME_INIT 0x1000
+#endif
+
+enum {
+ MSM_CLOCK_FLAGS_UNSTABLE_COUNT = 1U << 0,
+ MSM_CLOCK_FLAGS_ODD_MATCH_WRITE = 1U << 1,
+ MSM_CLOCK_FLAGS_DELAYED_WRITE_POST = 1U << 2,
+};
struct msm_clock {
struct clock_event_device clockevent;
@@ -48,6 +90,30 @@ struct msm_clock {
void __iomem *regbase;
uint32_t freq;
uint32_t shift;
+ uint32_t flags;
+ uint32_t write_delay;
+ uint32_t last_set;
+ uint32_t sleep_offset;
+ uint32_t alarm_vtime;
+ uint32_t non_sleep_offset;
+ uint32_t in_sync;
+ cycle_t stopped_tick;
+ int stopped;
+ uint32_t rollover_offset;
+ uint32_t last_sync_gpt;
+ u64 last_sync_jiffies;
+};
+enum {
+ MSM_CLOCK_GPT,
+ MSM_CLOCK_DGT,
+};
+static struct msm_clock msm_clocks[];
+static struct msm_clock *msm_active_clock;
+
+struct msm_timer_sync_data_t {
+ struct msm_clock *clock;
+ uint32_t timeout;
+ int exit_sleep;
};
static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
@@ -57,31 +123,82 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static uint32_t msm_read_timer_count(struct msm_clock *clock)
+{
+ uint32_t t1, t2;
+ int loop_count = 0;
+
+ t1 = readl(clock->regbase + TIMER_COUNT_VAL);
+ if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
+ return t1;
+ while (1) {
+ t2 = readl(clock->regbase + TIMER_COUNT_VAL);
+ if (t1 == t2)
+ return t1;
+ if (loop_count++ > 10) {
+ printk(KERN_ERR "msm_read_timer_count timer %s did not"
+ "stabilize %u != %u\n", clock->clockevent.name,
+ t2, t1);
+ return t2;
+ }
+ t1 = t2;
+ }
+}
+
static cycle_t msm_gpt_read(struct clocksource *cs)
{
- return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
+ struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
+ if (clock->stopped)
+ return clock->stopped_tick;
+ else
+ return msm_read_timer_count(clock) + clock->sleep_offset;
}
static cycle_t msm_dgt_read(struct clocksource *cs)
{
- return readl(MSM_DGT_BASE + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT;
+ struct msm_clock *clock = &msm_clocks[MSM_CLOCK_DGT];
+ if (clock->stopped)
+ return clock->stopped_tick >> MSM_DGT_SHIFT;
+ return (msm_read_timer_count(clock) + clock->sleep_offset)
+ >> MSM_DGT_SHIFT;
}
static int msm_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
- uint32_t now = readl(clock->regbase + TIMER_COUNT_VAL);
- uint32_t alarm = now + (cycles << clock->shift);
+ int i;
+ struct msm_clock *clock;
+ uint32_t now;
+ uint32_t alarm;
int late;
+ clock = container_of(evt, struct msm_clock, clockevent);
+ now = msm_read_timer_count(clock);
+ alarm = now + (cycles << clock->shift);
+ if (clock->flags & MSM_CLOCK_FLAGS_ODD_MATCH_WRITE)
+ while (now == clock->last_set)
+ now = msm_read_timer_count(clock);
writel(alarm, clock->regbase + TIMER_MATCH_VAL);
- now = readl(clock->regbase + TIMER_COUNT_VAL);
+ if (clock->flags & MSM_CLOCK_FLAGS_DELAYED_WRITE_POST) {
+ /* read the counter four extra times to make sure write posts
+ before reading the time */
+ for (i = 0; i < 4; i++)
+ readl(clock->regbase + TIMER_COUNT_VAL);
+ }
+ now = msm_read_timer_count(clock);
+ clock->last_set = now;
+ clock->alarm_vtime = alarm + clock->sleep_offset;
late = now - alarm;
- if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
- printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
- "alarm already expired, now %x, alarm %x, late %d\n",
- cycles, clock->clockevent.name, now, alarm, late);
+ if (late >= (int)(-clock->write_delay << clock->shift) && late < DGT_HZ*5) {
+ static int print_limit = 10;
+ if (print_limit > 0) {
+ print_limit--;
+ printk(KERN_NOTICE "msm_timer_set_next_event(%lu) "
+ "clock %s, alarm already expired, now %x, "
+ "alarm %x, late %d%s\n",
+ cycles, clock->clockevent.name, now, alarm, late,
+ print_limit ? "" : " stop printing");
+ }
return -ETIME;
}
return 0;
@@ -90,23 +207,538 @@ static int msm_timer_set_next_event(unsigned long cycles,
static void msm_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
+ struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+ struct msm_clock *clock;
+ unsigned long irq_flags;
+
+ clock = container_of(evt, struct msm_clock, clockevent);
+ local_irq_save(irq_flags);
+
switch (mode) {
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
break;
case CLOCK_EVT_MODE_ONESHOT:
+ clock->stopped = 0;
+ clock->sleep_offset = -msm_read_timer_count(clock) +
+ clock->stopped_tick;
+ msm_active_clock = clock;
writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+ if (clock != gpt_clk)
+ writel(TIMER_ENABLE_EN,
+ gpt_clk->regbase + TIMER_ENABLE);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
+ msm_active_clock = NULL;
+ clock->in_sync = 0;
+ clock->stopped = 1;
+ clock->stopped_tick = msm_read_timer_count(clock) +
+ clock->sleep_offset;
writel(0, clock->regbase + TIMER_ENABLE);
+ if (clock != gpt_clk) {
+ gpt_clk->in_sync = 0;
+ writel(0, gpt_clk->regbase + TIMER_ENABLE);
+ }
break;
}
+ local_irq_restore(irq_flags);
}
+/*
+ * Retrieve the cycle count from sclk and optionally synchronize local clock
+ * with the sclk value.
+ *
+ * time_start and time_expired are callbacks that must be specified. The
+ * protocol uses them to detect timeout. The update callback is optional.
+ * If not NULL, update will be called so that it can update local clock.
+ *
+ * The function does not use the argument data directly; it passes data to
+ * the callbacks.
+ *
+ * Return value:
+ * 0: the operation failed
+ * >0: the slow clock value after time-sync
+ */
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+static uint32_t msm_timer_do_sync_to_sclk(
+ void (*time_start)(struct msm_timer_sync_data_t *data),
+ bool (*time_expired)(struct msm_timer_sync_data_t *data),
+ void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+ struct msm_timer_sync_data_t *data)
+{
+ uint32_t *smem_clock;
+ uint32_t smem_clock_val;
+ uint32_t state;
+
+ smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE, sizeof(uint32_t));
+ if (smem_clock == NULL) {
+ printk(KERN_ERR "no smem clock\n");
+ return 0;
+ }
+
+ state = smsm_get_state(SMSM_MODEM_STATE);
+ if ((state & SMSM_INIT) == 0) {
+ printk(KERN_ERR "smsm not initialized\n");
+ return 0;
+ }
+
+ time_start(data);
+ while ((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) &
+ MASTER_TIME_PENDING) {
+ if (time_expired(data)) {
+ printk(KERN_INFO "get_smem_clock: timeout 1 still "
+ "invalid state %x\n", state);
+ return 0;
+ }
+ }
+
+ smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_POLL | SLAVE_TIME_INIT,
+ SLAVE_TIME_REQUEST);
+
+ time_start(data);
+ while (!((state = smsm_get_state(SMSM_TIME_MASTER_DEM)) &
+ MASTER_TIME_PENDING)) {
+ if (time_expired(data)) {
+ printk(KERN_INFO "get_smem_clock: timeout 2 still "
+ "invalid state %x\n", state);
+ smem_clock_val = 0;
+ goto sync_sclk_exit;
+ }
+ }
+
+ smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST, SLAVE_TIME_POLL);
+
+ time_start(data);
+ do {
+ smem_clock_val = *smem_clock;
+ } while (smem_clock_val == 0 && !time_expired(data));
+
+ state = smsm_get_state(SMSM_TIME_MASTER_DEM);
+
+ if (smem_clock_val) {
+ if (update != NULL)
+ update(data, smem_clock_val, SCLK_HZ);
+
+ if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+ printk(KERN_INFO
+ "get_smem_clock: state %x clock %u\n",
+ state, smem_clock_val);
+ } else {
+ printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n",
+ state, smem_clock_val);
+ }
+
+sync_sclk_exit:
+ smsm_change_state(SMSM_APPS_DEM, SLAVE_TIME_REQUEST | SLAVE_TIME_POLL,
+ SLAVE_TIME_INIT);
+ return smem_clock_val;
+}
+#else /* CONFIG_MSM_N_WAY_SMSM */
+static uint32_t msm_timer_do_sync_to_sclk(
+ void (*time_start)(struct msm_timer_sync_data_t *data),
+ bool (*time_expired)(struct msm_timer_sync_data_t *data),
+ void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+ struct msm_timer_sync_data_t *data)
+{
+ uint32_t *smem_clock;
+ uint32_t smem_clock_val;
+ uint32_t last_state;
+ uint32_t state;
+
+ smem_clock = smem_alloc(SMEM_SMEM_SLOW_CLOCK_VALUE,
+ sizeof(uint32_t));
+
+ if (smem_clock == NULL) {
+ printk(KERN_ERR "no smem clock\n");
+ return 0;
+ }
+
+ last_state = state = smsm_get_state(SMSM_MODEM_STATE);
+ smem_clock_val = *smem_clock;
+ if (smem_clock_val) {
+ printk(KERN_INFO "get_smem_clock: invalid start state %x "
+ "clock %u\n", state, smem_clock_val);
+ smsm_change_state(SMSM_APPS_STATE,
+ SMSM_TIMEWAIT, SMSM_TIMEINIT);
+
+ time_start(data);
+ while (*smem_clock != 0 && !time_expired(data))
+ ;
+
+ smem_clock_val = *smem_clock;
+ if (smem_clock_val) {
+ printk(KERN_INFO "get_smem_clock: timeout still "
+ "invalid state %x clock %u\n",
+ state, smem_clock_val);
+ return 0;
+ }
+ }
+
+ time_start(data);
+ smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEINIT, SMSM_TIMEWAIT);
+ do {
+ smem_clock_val = *smem_clock;
+ state = smsm_get_state(SMSM_MODEM_STATE);
+ if (state != last_state) {
+ last_state = state;
+ if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+ printk(KERN_INFO
+ "get_smem_clock: state %x clock %u\n",
+ state, smem_clock_val);
+ }
+ } while (smem_clock_val == 0 && !time_expired(data));
+
+ if (smem_clock_val) {
+ if (update != NULL)
+ update(data, smem_clock_val, SCLK_HZ);
+ } else {
+ printk(KERN_INFO "get_smem_clock: timeout state %x clock %u\n",
+ state, smem_clock_val);
+ }
+
+ smsm_change_state(SMSM_APPS_STATE, SMSM_TIMEWAIT, SMSM_TIMEINIT);
+ time_start(data);
+ while (*smem_clock != 0 && !time_expired(data))
+ ;
+
+ if (*smem_clock)
+ printk(KERN_INFO "get_smem_clock: exit timeout state %x "
+ "clock %u\n", state, *smem_clock);
+ return smem_clock_val;
+}
+#endif /* CONFIG_MSM_N_WAY_SMSM */
+
+/*
+ * Callback function that initializes the timeout value.
+ */
+static void msm_timer_sync_to_sclk_time_start(
+ struct msm_timer_sync_data_t *data)
+{
+ /* approx 1/128th of a second */
+ uint32_t delta = data->clock->freq >> 7 << data->clock->shift;
+ data->timeout = msm_read_timer_count(data->clock) + delta;
+}
+
+/*
+ * Callback function that checks the timeout.
+ */
+static bool msm_timer_sync_to_sclk_time_expired(
+ struct msm_timer_sync_data_t *data)
+{
+ uint32_t delta = msm_read_timer_count(data->clock) - data->timeout;
+ return ((int32_t) delta) > 0;
+}
+
+/*
+ * Callback function that updates local clock from the specified source clock
+ * value and frequency.
+ */
+static void msm_timer_sync_update(struct msm_timer_sync_data_t *data,
+ uint32_t src_clk_val, uint32_t src_clk_freq)
+{
+ struct msm_clock *dst_clk = data->clock;
+ uint32_t dst_clk_val = msm_read_timer_count(dst_clk);
+ uint32_t new_offset;
+
+ if ((dst_clk->freq << dst_clk->shift) == src_clk_freq) {
+ new_offset = src_clk_val - dst_clk_val;
+ } else {
+ uint64_t temp;
+
+ /* separate multiplication and division steps to reduce
+ rounding error */
+ temp = src_clk_val;
+ temp *= dst_clk->freq << dst_clk->shift;
+ do_div(temp, src_clk_freq);
+
+ new_offset = (uint32_t)(temp) - dst_clk_val;
+ }
+
+ if (dst_clk->sleep_offset + dst_clk->non_sleep_offset != new_offset) {
+ if (data->exit_sleep)
+ dst_clk->sleep_offset =
+ new_offset - dst_clk->non_sleep_offset;
+ else
+ dst_clk->non_sleep_offset =
+ new_offset - dst_clk->sleep_offset;
+
+ if (msm_timer_debug_mask & MSM_TIMER_DEBUG_SYNC)
+ printk(KERN_INFO "sync clock %s: "
+ "src %u, new offset %u + %u\n",
+ dst_clk->clocksource.name, src_clk_val,
+ dst_clk->sleep_offset,
+ dst_clk->non_sleep_offset);
+ }
+}
+
+/*
+ * Synchronize GPT clock with sclk.
+ */
+static void msm_timer_sync_gpt_to_sclk(int exit_sleep)
+{
+ struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+ struct msm_timer_sync_data_t data;
+ uint32_t ret;
+
+ if (gpt_clk->in_sync)
+ return;
+
+ data.clock = gpt_clk;
+ data.timeout = 0;
+ data.exit_sleep = exit_sleep;
+
+ ret = msm_timer_do_sync_to_sclk(
+ msm_timer_sync_to_sclk_time_start,
+ msm_timer_sync_to_sclk_time_expired,
+ msm_timer_sync_update,
+ &data);
+
+ if (ret)
+ gpt_clk->in_sync = 1;
+}
+
+/*
+ * Synchronize clock with GPT clock.
+ */
+static void msm_timer_sync_to_gpt(struct msm_clock *clock, int exit_sleep)
+{
+ struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+ struct msm_timer_sync_data_t data;
+ uint32_t gpt_clk_val;
+ u64 gpt_period = (1ULL << 32) * HZ / GPT_HZ;
+ u64 now = get_jiffies_64();
+
+ BUG_ON(clock == gpt_clk);
+
+ if (clock->in_sync &&
+ (now - clock->last_sync_jiffies < (gpt_period >> 1)))
+ return;
+
+ gpt_clk_val = msm_read_timer_count(gpt_clk)
+ + gpt_clk->sleep_offset + gpt_clk->non_sleep_offset;
+
+ if (exit_sleep && gpt_clk_val < clock->last_sync_gpt)
+ clock->non_sleep_offset -= clock->rollover_offset;
+
+ data.clock = clock;
+ data.timeout = 0;
+ data.exit_sleep = exit_sleep;
+
+ msm_timer_sync_update(&data, gpt_clk_val, GPT_HZ);
+
+ clock->in_sync = 1;
+ clock->last_sync_gpt = gpt_clk_val;
+ clock->last_sync_jiffies = now;
+}
+
+static void msm_timer_reactivate_alarm(struct msm_clock *clock)
+{
+ long alarm_delta = clock->alarm_vtime - clock->sleep_offset -
+ msm_read_timer_count(clock);
+ alarm_delta >>= clock->shift;
+ if (alarm_delta < (long)clock->write_delay + 4)
+ alarm_delta = clock->write_delay + 4;
+ while (msm_timer_set_next_event(alarm_delta, &clock->clockevent))
+ ;
+}
+
+int64_t msm_timer_enter_idle(void)
+{
+ struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+ struct msm_clock *clock = msm_active_clock;
+ uint32_t alarm;
+ uint32_t count;
+ int32_t delta;
+
+ BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] &&
+ clock != &msm_clocks[MSM_CLOCK_DGT]);
+
+ msm_timer_sync_gpt_to_sclk(0);
+ if (clock != gpt_clk)
+ msm_timer_sync_to_gpt(clock, 0);
+
+ count = msm_read_timer_count(clock);
+ if (clock->stopped++ == 0)
+ clock->stopped_tick = count + clock->sleep_offset;
+ alarm = readl(clock->regbase + TIMER_MATCH_VAL);
+ delta = alarm - count;
+ if (delta <= -(int32_t)((clock->freq << clock->shift) >> 10)) {
+ /* timer should have triggered 1ms ago */
+ printk(KERN_ERR "msm_timer_enter_idle: timer late %d, "
+ "reprogram it\n", delta);
+ msm_timer_reactivate_alarm(clock);
+ }
+ if (delta <= 0)
+ return 0;
+ return clocksource_cyc2ns((alarm - count) >> clock->shift , clock->clocksource.mult, clock->clocksource.shift);
+}
+
+void msm_timer_exit_idle(int low_power)
+{
+ struct msm_clock *gpt_clk = &msm_clocks[MSM_CLOCK_GPT];
+ struct msm_clock *clock = msm_active_clock;
+ uint32_t enabled;
+
+ BUG_ON(clock != &msm_clocks[MSM_CLOCK_GPT] &&
+ clock != &msm_clocks[MSM_CLOCK_DGT]);
+
+ if (!low_power)
+ goto exit_idle_exit;
+
+ enabled = readl(gpt_clk->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN;
+ if (!enabled)
+ writel(TIMER_ENABLE_EN, gpt_clk->regbase + TIMER_ENABLE);
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+ gpt_clk->in_sync = 0;
+#else
+ gpt_clk->in_sync = gpt_clk->in_sync && enabled;
+#endif
+ msm_timer_sync_gpt_to_sclk(1);
+
+ if (clock == gpt_clk)
+ goto exit_idle_alarm;
+
+ enabled = readl(clock->regbase + TIMER_ENABLE) & TIMER_ENABLE_EN;
+ if (!enabled)
+ writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
+
+#if defined(CONFIG_ARCH_MSM_SCORPION)
+ clock->in_sync = 0;
+#else
+ clock->in_sync = clock->in_sync && enabled;
+#endif
+ msm_timer_sync_to_gpt(clock, 1);
+
+exit_idle_alarm:
+ msm_timer_reactivate_alarm(clock);
+
+exit_idle_exit:
+ clock->stopped--;
+}
+
+/*
+ * Callback function that initializes the timeout value.
+ */
+static void msm_timer_get_sclk_time_start(
+ struct msm_timer_sync_data_t *data)
+{
+ data->timeout = 10000;
+}
+
+/*
+ * Callback function that checks the timeout.
+ */
+static bool msm_timer_get_sclk_time_expired(
+ struct msm_timer_sync_data_t *data)
+{
+ return --data->timeout <= 0;
+}
+
+/*
+ * Retrieve the cycle count from the sclk and convert it into
+ * nanoseconds.
+ *
+ * On exit, if period is not NULL, it contains the period of the
+ * sclk in nanoseconds, i.e. how long the cycle count wraps around.
+ *
+ * Return value:
+ * 0: the operation failed; period is not set either
+ * >0: time in nanoseconds
+ */
+int64_t msm_timer_get_sclk_time(int64_t *period)
+{
+ struct msm_timer_sync_data_t data;
+ uint32_t clock_value;
+ int64_t tmp;
+
+ memset(&data, 0, sizeof(data));
+
+ clock_value = msm_timer_do_sync_to_sclk(
+ msm_timer_get_sclk_time_start,
+ msm_timer_get_sclk_time_expired,
+ NULL,
+ &data);
+
+ if (!clock_value)
+ return 0;
+
+ if (period) {
+ tmp = 1LL << 32;
+ tmp = tmp * NSEC_PER_SEC / SCLK_HZ;
+ *period = tmp;
+ }
+
+ tmp = (int64_t)clock_value;
+ tmp = tmp * NSEC_PER_SEC / SCLK_HZ;
+ return tmp;
+}
+
+int __init msm_timer_init_time_sync(void)
+{
+#if defined(CONFIG_MSM_N_WAY_SMSM)
+ int ret = smsm_change_intr_mask(SMSM_TIME_MASTER_DEM, 0xFFFFFFFF, 0);
+
+ if (ret) {
+ printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ smsm_change_state(SMSM_APPS_DEM,
+ SLAVE_TIME_REQUEST | SLAVE_TIME_POLL, SLAVE_TIME_INIT);
+#endif
+
+ return 0;
+}
+
+unsigned long long sched_clock(void)
+{
+ static cycle_t saved_ticks;
+ static int saved_ticks_valid;
+ static unsigned long long base;
+ static unsigned long long last_result;
+
+ unsigned long irq_flags;
+ static cycle_t last_ticks;
+ cycle_t ticks;
+ static unsigned long long result;
+ struct clocksource *cs;
+ struct msm_clock *clock = msm_active_clock;
+
+ local_irq_save(irq_flags);
+ if (clock) {
+ cs = &clock->clocksource;
+
+ last_ticks = saved_ticks;
+ saved_ticks = ticks = cs->read(cs);
+ if (!saved_ticks_valid) {
+ saved_ticks_valid = 1;
+ last_ticks = ticks;
+ base -= clocksource_cyc2ns(ticks, cs->mult, cs->shift);
+ }
+ if (ticks < last_ticks) {
+ base += clocksource_cyc2ns(cs->mask, cs->mult, cs->shift);
+ base += clocksource_cyc2ns(1, cs->mult, cs->shift);
+ }
+ last_result = result = clocksource_cyc2ns(ticks, cs->mult, cs->shift) + base;
+ } else {
+ base = result = last_result;
+ saved_ticks_valid = 0;
+ }
+ local_irq_restore(irq_flags);
+ return result;
+}
+
+#ifdef CONFIG_MSM7X00A_USE_GP_TIMER
+ #define DG_TIMER_RATING 100
+#else
+ #define DG_TIMER_RATING 300
+#endif
+
static struct msm_clock msm_clocks[] = {
- {
+ [MSM_CLOCK_GPT] = {
.clockevent = {
.name = "gp_timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
@@ -120,46 +752,54 @@ static struct msm_clock msm_clocks[] = {
.rating = 200,
.read = msm_gpt_read,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 24,
+ .shift = 17,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
.irq = {
.name = "gp_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+ .flags = IRQF_DISABLED | IRQF_TIMER |
+ IRQF_TRIGGER_RISING,
.handler = msm_timer_interrupt,
.dev_id = &msm_clocks[0].clockevent,
.irq = INT_GP_TIMER_EXP
},
.regbase = MSM_GPT_BASE,
- .freq = GPT_HZ
+ .freq = GPT_HZ,
+ .flags =
+ MSM_CLOCK_FLAGS_UNSTABLE_COUNT |
+ MSM_CLOCK_FLAGS_ODD_MATCH_WRITE |
+ MSM_CLOCK_FLAGS_DELAYED_WRITE_POST,
+ .write_delay = 9,
},
- {
+ [MSM_CLOCK_DGT] = {
.clockevent = {
.name = "dg_timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32 + MSM_DGT_SHIFT,
- .rating = 300,
+ .rating = DG_TIMER_RATING,
.set_next_event = msm_timer_set_next_event,
.set_mode = msm_timer_set_mode,
},
.clocksource = {
.name = "dg_timer",
- .rating = 300,
+ .rating = DG_TIMER_RATING,
.read = msm_dgt_read,
- .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
+ .mask = CLOCKSOURCE_MASK((32-MSM_DGT_SHIFT)),
.shift = 24 - MSM_DGT_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
},
.irq = {
.name = "dg_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING,
+ .flags = IRQF_DISABLED | IRQF_TIMER |
+ IRQF_TRIGGER_RISING,
.handler = msm_timer_interrupt,
.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
+ .shift = MSM_DGT_SHIFT,
+ .write_delay = 2,
}
};
@@ -173,15 +813,27 @@ static void __init msm_timer_init(void)
struct clock_event_device *ce = &clock->clockevent;
struct clocksource *cs = &clock->clocksource;
writel(0, clock->regbase + TIMER_ENABLE);
- writel(0, clock->regbase + TIMER_CLEAR);
writel(~0, clock->regbase + TIMER_MATCH_VAL);
+ if ((clock->freq << clock->shift) == GPT_HZ) {
+ clock->rollover_offset = 0;
+ } else {
+ uint64_t temp;
+
+ temp = clock->freq << clock->shift;
+ temp <<= 32;
+ temp /= GPT_HZ;
+
+ clock->rollover_offset = (uint32_t) temp;
+ }
+
ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
/* allow at least 10 seconds to notice that the timer wrapped */
ce->max_delta_ns =
clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
- /* 4 gets rounded down to 3 */
- ce->min_delta_ns = clockevent_delta2ns(4, ce);
+ /* ticks gets rounded down by one */
+ ce->min_delta_ns =
+ clockevent_delta2ns(clock->write_delay + 4, ce);
ce->cpumask = cpumask_of(0);
cs->mult = clocksource_hz2mult(clock->freq, cs->shift);
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
new file mode 100644
index 000000000000..161751e99c36
--- /dev/null
+++ b/arch/arm/mach-msm/timer.h
@@ -0,0 +1,38 @@
+/* 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 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.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_TIMER_H_
+#define _ARCH_ARM_MACH_MSM_TIMER_H_
+
+extern struct sys_timer msm_timer;
+
+int64_t msm_timer_enter_idle(void);
+void msm_timer_exit_idle(int low_power);
+int64_t msm_timer_get_sclk_time(int64_t *period);
+int msm_timer_init_time_sync(void);
+#endif
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index fcb0b9f25684..cb7a71b55f43 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/vreg.c
*
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -18,49 +19,78 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/debugfs.h>
+#include <linux/string.h>
#include <mach/vreg.h>
#include "proc_comm.h"
+#if defined(CONFIG_MSM_VREG_SWITCH_INVERTED)
+#define VREG_SWITCH_ENABLE 0
+#define VREG_SWITCH_DISABLE 1
+#else
+#define VREG_SWITCH_ENABLE 1
+#define VREG_SWITCH_DISABLE 0
+#endif
+
struct vreg {
const char *name;
unsigned id;
+ int status;
+ unsigned refcnt;
};
-#define VREG(_name, _id) { .name = _name, .id = _id, }
+#define VREG(_name, _id, _status, _refcnt) \
+ { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
static struct vreg vregs[] = {
- VREG("msma", 0),
- VREG("msmp", 1),
- VREG("msme1", 2),
- VREG("msmc1", 3),
- VREG("msmc2", 4),
- VREG("gp3", 5),
- VREG("msme2", 6),
- VREG("gp4", 7),
- VREG("gp1", 8),
- VREG("tcxo", 9),
- VREG("pa", 10),
- VREG("rftx", 11),
- VREG("rfrx1", 12),
- VREG("rfrx2", 13),
- VREG("synt", 14),
- VREG("wlan", 15),
- VREG("usb", 16),
- VREG("boost", 17),
- VREG("mmc", 18),
- VREG("ruim", 19),
- VREG("msmc0", 20),
- VREG("gp2", 21),
- VREG("gp5", 22),
- VREG("gp6", 23),
- VREG("rf", 24),
- VREG("rf_vco", 26),
- VREG("mpll", 27),
- VREG("s2", 28),
- VREG("s3", 29),
- VREG("rfubm", 30),
- VREG("ncp", 31),
+ VREG("msma", 0, 0, 0),
+ VREG("msmp", 1, 0, 0),
+ VREG("msme1", 2, 0, 0),
+ VREG("msmc1", 3, 0, 0),
+ VREG("msmc2", 4, 0, 0),
+ VREG("gp3", 5, 0, 0),
+ VREG("msme2", 6, 0, 0),
+ VREG("gp4", 7, 0, 0),
+ VREG("gp1", 8, 0, 0),
+ VREG("tcxo", 9, 0, 0),
+ VREG("pa", 10, 0, 0),
+ VREG("rftx", 11, 0, 0),
+ VREG("rfrx1", 12, 0, 0),
+ VREG("rfrx2", 13, 0, 0),
+ VREG("synt", 14, 0, 0),
+ VREG("wlan", 15, 0, 0),
+ VREG("usb", 16, 0, 0),
+ VREG("boost", 17, 0, 0),
+ VREG("mmc", 18, 0, 0),
+ VREG("ruim", 19, 0, 0),
+ VREG("msmc0", 20, 0, 0),
+ VREG("gp2", 21, 0, 0),
+ VREG("gp5", 22, 0, 0),
+ VREG("gp6", 23, 0, 0),
+ VREG("rf", 24, 0, 0),
+ VREG("rf_vco", 26, 0, 0),
+ VREG("mpll", 27, 0, 0),
+ VREG("s2", 28, 0, 0),
+ VREG("s3", 29, 0, 0),
+ VREG("rfubm", 30, 0, 0),
+ VREG("ncp", 31, 0, 0),
+ VREG("gp7", 32, 0, 0),
+ VREG("gp8", 33, 0, 0),
+ VREG("gp9", 34, 0, 0),
+ VREG("gp10", 35, 0, 0),
+ VREG("gp11", 36, 0, 0),
+ VREG("gp12", 37, 0, 0),
+ VREG("gp13", 38, 0, 0),
+ VREG("gp14", 39, 0, 0),
+ VREG("gp15", 40, 0, 0),
+ VREG("gp16", 41, 0, 0),
+ VREG("gp17", 42, 0, 0),
+ VREG("s4", 43, 0, 0),
+ VREG("usb2", 44, 0, 0),
+ VREG("wlan2", 45, 0, 0),
+ VREG("xo_out", 46, 0, 0),
+ VREG("lvsw0", 47, 0, 0),
+ VREG("lvsw1", 48, 0, 0),
};
struct vreg *vreg_get(struct device *dev, const char *id)
@@ -70,8 +100,9 @@ struct vreg *vreg_get(struct device *dev, const char *id)
if (!strcmp(vregs[n].name, id))
return vregs + n;
}
- return 0;
+ return ERR_PTR(-ENOENT);
}
+EXPORT_SYMBOL(vreg_get);
void vreg_put(struct vreg *vreg)
{
@@ -80,22 +111,44 @@ void vreg_put(struct vreg *vreg)
int vreg_enable(struct vreg *vreg)
{
unsigned id = vreg->id;
- unsigned enable = 1;
- return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+ int enable = VREG_SWITCH_ENABLE;
+
+ if (vreg->refcnt == 0)
+ vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+
+ if ((vreg->refcnt < UINT_MAX) && (!vreg->status))
+ vreg->refcnt++;
+
+ return vreg->status;
}
+EXPORT_SYMBOL(vreg_enable);
-void vreg_disable(struct vreg *vreg)
+int vreg_disable(struct vreg *vreg)
{
unsigned id = vreg->id;
- unsigned enable = 0;
- msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+ int disable = VREG_SWITCH_DISABLE;
+
+ if (!vreg->refcnt)
+ return 0;
+
+ if (vreg->refcnt == 1)
+ vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &disable);
+
+ if (!vreg->status)
+ vreg->refcnt--;
+
+ return vreg->status;
}
+EXPORT_SYMBOL(vreg_disable);
int vreg_set_level(struct vreg *vreg, unsigned mv)
{
unsigned id = vreg->id;
- return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
+
+ vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
+ return vreg->status;
}
+EXPORT_SYMBOL(vreg_set_level);
#if defined(CONFIG_DEBUG_FS)
@@ -118,24 +171,59 @@ static int vreg_debug_set(void *data, u64 val)
static int vreg_debug_get(void *data, u64 *val)
{
- return -ENOSYS;
+ struct vreg *vreg = data;
+
+ if (!vreg->status)
+ *val = 0;
+ else
+ *val = 1;
+
+ return 0;
+}
+
+static int vreg_debug_count_set(void *data, u64 val)
+{
+ struct vreg *vreg = data;
+ if (val > UINT_MAX)
+ val = UINT_MAX;
+ vreg->refcnt = val;
+ return 0;
+}
+
+static int vreg_debug_count_get(void *data, u64 *val)
+{
+ struct vreg *vreg = data;
+
+ *val = vreg->refcnt;
+
+ return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get,
+ vreg_debug_count_set, "%llu\n");
static int __init vreg_debug_init(void)
{
struct dentry *dent;
int n;
+ char name[32];
+ const char *refcnt_name = "_refcnt";
dent = debugfs_create_dir("vreg", 0);
if (IS_ERR(dent))
return 0;
- for (n = 0; n < ARRAY_SIZE(vregs); n++)
+ for (n = 0; n < ARRAY_SIZE(vregs); n++) {
(void) debugfs_create_file(vregs[n].name, 0644,
dent, vregs + n, &vreg_fops);
+ strlcpy(name, vregs[n].name, sizeof(name));
+ strlcat(name, refcnt_name, sizeof(name));
+ (void) debugfs_create_file(name, 0644,
+ dent, vregs + n, &vreg_count_fops);
+ }
+
return 0;
}
diff --git a/arch/arm/mach-mx1/clock.c b/arch/arm/mach-mx1/clock.c
index d1b588519ad2..6cf2d4a7511d 100644
--- a/arch/arm/mach-mx1/clock.c
+++ b/arch/arm/mach-mx1/clock.c
@@ -570,7 +570,6 @@ static struct clk_lookup lookups[] __initdata = {
int __init mx1_clocks_init(unsigned long fref)
{
unsigned int reg;
- int i;
/* disable clocks we are able to */
__raw_writel(0, SCM_GCCR);
@@ -592,8 +591,7 @@ int __init mx1_clocks_init(unsigned long fref)
reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
clko_clk.parent = (struct clk *)clko_clocks[reg];
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
clk_enable(&hclk);
clk_enable(&fclk);
diff --git a/arch/arm/mach-mx2/clock_imx21.c b/arch/arm/mach-mx2/clock_imx21.c
index 91901b5d56c2..e82b489d1215 100644
--- a/arch/arm/mach-mx2/clock_imx21.c
+++ b/arch/arm/mach-mx2/clock_imx21.c
@@ -968,7 +968,6 @@ static struct clk_lookup lookups[] = {
*/
int __init mx21_clocks_init(unsigned long lref, unsigned long href)
{
- int i;
u32 cscr;
external_low_reference = lref;
@@ -986,8 +985,7 @@ int __init mx21_clocks_init(unsigned long lref, unsigned long href)
else
spll_clk.parent = &fpm_clk;
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
/* Turn off all clock gates */
__raw_writel(0, CCM_PCCR0);
diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
index b010bf9ceaab..18c53a6487fa 100644
--- a/arch/arm/mach-mx2/clock_imx27.c
+++ b/arch/arm/mach-mx2/clock_imx27.c
@@ -719,7 +719,6 @@ static void __init to2_adjust_clocks(void)
int __init mx27_clocks_init(unsigned long fref)
{
u32 cscr = __raw_readl(CCM_CSCR);
- int i;
external_high_reference = fref;
@@ -736,8 +735,7 @@ int __init mx27_clocks_init(unsigned long fref)
to2_adjust_clocks();
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
/* Turn off all clocks we do not need */
__raw_writel(0, CCM_PCCR0);
diff --git a/arch/arm/mach-mx2/mxt_td60.c b/arch/arm/mach-mx2/mxt_td60.c
index 03dbbdc98955..8bcc1a5b8829 100644
--- a/arch/arm/mach-mx2/mxt_td60.c
+++ b/arch/arm/mach-mx2/mxt_td60.c
@@ -58,21 +58,6 @@ static unsigned int mxt_td60_pins[] __initdata = {
PE9_PF_UART3_RXD,
PE10_PF_UART3_CTS,
PE11_PF_UART3_RTS,
- /* UART3 */
- PB26_AF_UART4_RTS,
- PB28_AF_UART4_TXD,
- PB29_AF_UART4_CTS,
- PB31_AF_UART4_RXD,
- /* UART4 */
- PB18_AF_UART5_TXD,
- PB19_AF_UART5_RXD,
- PB20_AF_UART5_CTS,
- PB21_AF_UART5_RTS,
- /* UART5 */
- PB10_AF_UART6_TXD,
- PB12_AF_UART6_CTS,
- PB11_AF_UART6_RXD,
- PB13_AF_UART6_RTS,
/* FEC */
PD0_AIN_FEC_TXD0,
PD1_AIN_FEC_TXD1,
@@ -261,12 +246,6 @@ static struct imxuart_platform_data uart_pdata[] = {
.flags = IMXUART_HAVE_RTSCTS,
}, {
.flags = IMXUART_HAVE_RTSCTS,
- }, {
- .flags = IMXUART_HAVE_RTSCTS,
- }, {
- .flags = IMXUART_HAVE_RTSCTS,
- }, {
- .flags = IMXUART_HAVE_RTSCTS,
},
};
@@ -278,9 +257,6 @@ static void __init mxt_td60_board_init(void)
mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
- mxc_register_device(&mxc_uart_device3, &uart_pdata[3]);
- mxc_register_device(&mxc_uart_device4, &uart_pdata[4]);
- mxc_register_device(&mxc_uart_device5, &uart_pdata[5]);
mxc_register_device(&mxc_nand_device, &mxt_td60_nand_board_info);
i2c_register_board_info(0, mxt_td60_i2c_devices,
diff --git a/arch/arm/mach-mx25/clock.c b/arch/arm/mach-mx25/clock.c
index ef26951a5275..66916f104812 100644
--- a/arch/arm/mach-mx25/clock.c
+++ b/arch/arm/mach-mx25/clock.c
@@ -173,6 +173,7 @@ DEFINE_CLOCK(pwm4_clk, 0, CCM_CGCR2, 2, get_rate_ipg, NULL);
DEFINE_CLOCK(kpp_clk, 0, CCM_CGCR1, 28, get_rate_ipg, NULL);
DEFINE_CLOCK(tsc_clk, 0, CCM_CGCR2, 13, get_rate_ipg, NULL);
DEFINE_CLOCK(i2c_clk, 0, CCM_CGCR0, 6, get_rate_i2c, NULL);
+DEFINE_CLOCK(fec_clk, 0, CCM_CGCR0, 23, get_rate_ipg, NULL);
#define _REGISTER_CLOCK(d, n, c) \
{ \
@@ -204,15 +205,12 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
_REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
_REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk)
+ _REGISTER_CLOCK("fec.0", NULL, fec_clk)
};
int __init mx25_clocks_init(unsigned long fref)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
-
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
return 0;
diff --git a/arch/arm/mach-mx25/devices.c b/arch/arm/mach-mx25/devices.c
index 63511de3a559..9fdeea1c083b 100644
--- a/arch/arm/mach-mx25/devices.c
+++ b/arch/arm/mach-mx25/devices.c
@@ -419,3 +419,22 @@ int __init mxc_register_gpios(void)
return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
}
+static struct resource mx25_fec_resources[] = {
+ {
+ .start = MX25_FEC_BASE_ADDR,
+ .end = MX25_FEC_BASE_ADDR + 0xfff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MX25_INT_FEC,
+ .end = MX25_INT_FEC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mx25_fec_device = {
+ .name = "fec",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mx25_fec_resources),
+ .resource = mx25_fec_resources,
+};
diff --git a/arch/arm/mach-mx25/devices.h b/arch/arm/mach-mx25/devices.h
index fe6bf88ad1dd..fe5420fcd11f 100644
--- a/arch/arm/mach-mx25/devices.h
+++ b/arch/arm/mach-mx25/devices.h
@@ -17,3 +17,4 @@ extern struct platform_device mxc_keypad_device;
extern struct platform_device mxc_i2c_device0;
extern struct platform_device mxc_i2c_device1;
extern struct platform_device mxc_i2c_device2;
+extern struct platform_device mx25_fec_device;
diff --git a/arch/arm/mach-mx25/mx25pdk.c b/arch/arm/mach-mx25/mx25pdk.c
index d23ae571c03f..921bc99ea231 100644
--- a/arch/arm/mach-mx25/mx25pdk.c
+++ b/arch/arm/mach-mx25/mx25pdk.c
@@ -18,10 +18,11 @@
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/gpio.h>
-#include <linux/smsc911x.h>
+#include <linux/fec.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
@@ -35,16 +36,57 @@
#include <mach/mx25.h>
#include <mach/mxc_nand.h>
#include "devices.h"
-#include <mach/iomux-v3.h>
+#include <mach/iomux.h>
static struct imxuart_platform_data uart_pdata = {
.flags = IMXUART_HAVE_RTSCTS,
};
+static struct pad_desc mx25pdk_pads[] = {
+ MX25_PAD_FEC_MDC__FEC_MDC,
+ MX25_PAD_FEC_MDIO__FEC_MDIO,
+ MX25_PAD_FEC_TDATA0__FEC_TDATA0,
+ MX25_PAD_FEC_TDATA1__FEC_TDATA1,
+ MX25_PAD_FEC_TX_EN__FEC_TX_EN,
+ MX25_PAD_FEC_RDATA0__FEC_RDATA0,
+ MX25_PAD_FEC_RDATA1__FEC_RDATA1,
+ MX25_PAD_FEC_RX_DV__FEC_RX_DV,
+ MX25_PAD_FEC_TX_CLK__FEC_TX_CLK,
+ MX25_PAD_A17__GPIO_2_3, /* FEC_EN, GPIO 35 */
+ MX25_PAD_D12__GPIO_4_8, /* FEC_RESET_B, GPIO 104 */
+};
+
+static struct fec_platform_data mx25_fec_pdata = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+#define FEC_ENABLE_GPIO 35
+#define FEC_RESET_B_GPIO 104
+
+static void __init mx25pdk_fec_reset(void)
+{
+ gpio_request(FEC_ENABLE_GPIO, "FEC PHY enable");
+ gpio_request(FEC_RESET_B_GPIO, "FEC PHY reset");
+
+ gpio_direction_output(FEC_ENABLE_GPIO, 0); /* drop PHY power */
+ gpio_direction_output(FEC_RESET_B_GPIO, 0); /* assert reset */
+ udelay(2);
+
+ /* turn on PHY power and lift reset */
+ gpio_set_value(FEC_ENABLE_GPIO, 1);
+ gpio_set_value(FEC_RESET_B_GPIO, 1);
+}
+
static void __init mx25pdk_init(void)
{
+ mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
+ ARRAY_SIZE(mx25pdk_pads));
+
mxc_register_device(&mxc_uart_device0, &uart_pdata);
mxc_register_device(&mxc_usbh2, NULL);
+
+ mx25pdk_fec_reset();
+ mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
}
static void __init mx25pdk_timer_init(void)
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
index ea8ed109a7c2..28294416b0af 100644
--- a/arch/arm/mach-mx3/Kconfig
+++ b/arch/arm/mach-mx3/Kconfig
@@ -49,6 +49,7 @@ config MACH_PCM037_EET
config MACH_MX31LITE
bool "Support MX31 LITEKIT (LogicPD)"
select ARCH_MX31
+ select MXC_ULPI if USB_ULPI
help
Include support for MX31 LITEKIT platform. This includes specific
configurations for the board and its peripherals.
@@ -63,7 +64,7 @@ config MACH_MX31_3DS
config MACH_MX31MOBOARD
bool "Support mx31moboard platforms (EPFL Mobots group)"
select ARCH_MX31
- select MXC_ULPI
+ select MXC_ULPI if USB_ULPI
help
Include support for mx31moboard platform. This includes specific
configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c
index 7584b4c6c556..f3f41fa4f21b 100644
--- a/arch/arm/mach-mx3/clock-imx35.c
+++ b/arch/arm/mach-mx3/clock-imx35.c
@@ -485,15 +485,13 @@ static struct clk_lookup lookups[] = {
int __init mx35_clocks_init()
{
- int i;
unsigned int ll = 0;
#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
ll = (3 << 16);
#endif
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
/* Turn off all clocks except the ones we need to survive, namely:
* EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart
diff --git a/arch/arm/mach-mx3/clock.c b/arch/arm/mach-mx3/clock.c
index 27a318af0d20..b5c39a016db7 100644
--- a/arch/arm/mach-mx3/clock.c
+++ b/arch/arm/mach-mx3/clock.c
@@ -578,12 +578,10 @@ static struct clk_lookup lookups[] = {
int __init mx31_clocks_init(unsigned long fref)
{
u32 reg;
- int i;
ckih_rate = fref;
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
/* change the csi_clk parent if necessary */
reg = __raw_readl(MXC_CCM_CCMR);
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
index bedf5b8d976a..6858a4f9806c 100644
--- a/arch/arm/mach-mx3/mm.c
+++ b/arch/arm/mach-mx3/mm.c
@@ -65,6 +65,11 @@ static struct map_desc mxc_io_desc[] __initdata = {
.pfn = __phys_to_pfn(AIPS2_BASE_ADDR),
.length = AIPS2_SIZE,
.type = MT_DEVICE_NONSHARED
+ }, {
+ .virtual = SPBA0_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
+ .length = SPBA0_SIZE,
+ .type = MT_DEVICE_NONSHARED
},
};
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
index 0497c152be18..3e7bafa2ddbb 100644
--- a/arch/arm/mach-mx3/mx31ads.c
+++ b/arch/arm/mach-mx3/mx31ads.c
@@ -494,11 +494,6 @@ static void mxc_init_i2c(void)
*/
static struct map_desc mx31ads_io_desc[] __initdata = {
{
- .virtual = SPBA0_BASE_ADDR_VIRT,
- .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
- .length = SPBA0_SIZE,
- .type = MT_DEVICE_NONSHARED
- }, {
.virtual = CS4_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(CS4_BASE_ADDR),
.length = CS4_SIZE / 2,
diff --git a/arch/arm/mach-mx3/mx31lite.c b/arch/arm/mach-mx3/mx31lite.c
index def6b6736594..789b20d1730f 100644
--- a/arch/arm/mach-mx3/mx31lite.c
+++ b/arch/arm/mach-mx3/mx31lite.c
@@ -135,6 +135,7 @@ 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)
@@ -180,6 +181,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
.portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
.flags = MXC_EHCI_POWER_PINS_ENABLED,
};
+#endif
/*
* NOR flash
@@ -212,11 +214,6 @@ static struct platform_device physmap_flash_device = {
*/
static struct map_desc mx31lite_io_desc[] __initdata = {
{
- .virtual = SPBA0_BASE_ADDR_VIRT,
- .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
- .length = SPBA0_SIZE,
- .type = MT_DEVICE_NONSHARED
- }, {
.virtual = CS4_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(CS4_BASE_ADDR),
.length = CS4_SIZE,
@@ -261,11 +258,13 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_spi_device1, &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,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+#endif
/* SMSC9117 IRQ pin */
ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq");
diff --git a/arch/arm/mach-mx3/mx31moboard-devboard.c b/arch/arm/mach-mx3/mx31moboard-devboard.c
index 8fc624f141cb..438428eaf769 100644
--- a/arch/arm/mach-mx3/mx31moboard-devboard.c
+++ b/arch/arm/mach-mx3/mx31moboard-devboard.c
@@ -179,7 +179,7 @@ static int __init devboard_usbh1_init(void)
usbh1_pdata.otg = otg;
- return mxc_register_device(&mx31_usbh1, &usbh1_pdata);
+ return mxc_register_device(&mxc_usbh1, &usbh1_pdata);
}
/*
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c
index 85184a35e674..1f44b9ccbb0f 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c
@@ -294,7 +294,7 @@ static int __init marxbot_usbh1_init(void)
usbh1_pdata.otg = otg;
- return mxc_register_device(&mx31_usbh1, &usbh1_pdata);
+ return mxc_register_device(&mxc_usbh1, &usbh1_pdata);
}
/*
diff --git a/arch/arm/mach-mx3/mx31moboard.c b/arch/arm/mach-mx3/mx31moboard.c
index b70529145936..cfd605d078ec 100644
--- a/arch/arm/mach-mx3/mx31moboard.c
+++ b/arch/arm/mach-mx3/mx31moboard.c
@@ -346,6 +346,8 @@ static struct fsl_usb2_platform_data usb_pdata = {
.phy_mode = FSL_USB2_PHY_ULPI,
};
+#if defined(CONFIG_USB_ULPI)
+
#define USBH2_EN_B IOMUX_TO_GPIO(MX31_PIN_SCK6)
static int moboard_usbh2_hw_init(struct platform_device *pdev)
@@ -392,8 +394,11 @@ static int __init moboard_usbh2_init(void)
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
- return mxc_register_device(&mx31_usbh2, &usbh2_pdata);
+ return mxc_register_device(&mxc_usbh2, &usbh2_pdata);
}
+#else
+static inline int moboard_usbh2_init(void) { return 0; }
+#endif
static struct gpio_led mx31moboard_leds[] = {
diff --git a/arch/arm/mach-mx3/mx31pdk.c b/arch/arm/mach-mx3/mx31pdk.c
index 0f7a2f06bc2d..18715f1aa7eb 100644
--- a/arch/arm/mach-mx3/mx31pdk.c
+++ b/arch/arm/mach-mx3/mx31pdk.c
@@ -211,11 +211,6 @@ static int __init mx31pdk_init_expio(void)
*/
static struct map_desc mx31pdk_io_desc[] __initdata = {
{
- .virtual = SPBA0_BASE_ADDR_VIRT,
- .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
- .length = SPBA0_SIZE,
- .type = MT_DEVICE_NONSHARED,
- }, {
.virtual = CS5_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(CS5_BASE_ADDR),
.length = CS5_SIZE,
diff --git a/arch/arm/mach-mx3/pcm037.c b/arch/arm/mach-mx3/pcm037.c
index 6cbaabedf386..5be396917c99 100644
--- a/arch/arm/mach-mx3/pcm037.c
+++ b/arch/arm/mach-mx3/pcm037.c
@@ -322,16 +322,25 @@ static int pcm037_camera_power(struct device *dev, int on)
return 0;
}
-static struct i2c_board_info pcm037_i2c_2_devices[] = {
+static struct i2c_board_info pcm037_i2c_camera[] = {
{
I2C_BOARD_INFO("mt9t031", 0x5d),
+ }, {
+ I2C_BOARD_INFO("mt9v022", 0x48),
},
};
-static struct soc_camera_link iclink = {
+static struct soc_camera_link iclink_mt9v022 = {
+ .bus_id = 0, /* Must match with the camera ID */
+ .board_info = &pcm037_i2c_camera[1],
+ .i2c_adapter_id = 2,
+ .module_name = "mt9v022",
+};
+
+static struct soc_camera_link iclink_mt9t031 = {
.bus_id = 0, /* Must match with the camera ID */
.power = pcm037_camera_power,
- .board_info = &pcm037_i2c_2_devices[0],
+ .board_info = &pcm037_i2c_camera[0],
.i2c_adapter_id = 2,
.module_name = "mt9t031",
};
@@ -345,11 +354,19 @@ static struct i2c_board_info pcm037_i2c_devices[] = {
}
};
-static struct platform_device pcm037_camera = {
+static struct platform_device pcm037_mt9t031 = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
- .platform_data = &iclink,
+ .platform_data = &iclink_mt9t031,
+ },
+};
+
+static struct platform_device pcm037_mt9v022 = {
+ .name = "soc-camera-pdrv",
+ .id = 1,
+ .dev = {
+ .platform_data = &iclink_mt9v022,
},
};
@@ -449,7 +466,8 @@ static int __init pcm037_camera_alloc_dma(const size_t buf_size)
static struct platform_device *devices[] __initdata = {
&pcm037_flash,
&pcm037_sram_device,
- &pcm037_camera,
+ &pcm037_mt9t031,
+ &pcm037_mt9v022,
};
static struct ipu_platform_data mx3_ipu_data = {
@@ -599,7 +617,7 @@ static void __init mxc_board_init(void)
if (!ret)
gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), 1);
else
- iclink.power = NULL;
+ iclink_mt9t031.power = NULL;
if (!pcm037_camera_alloc_dma(4 * 1024 * 1024))
mxc_register_device(&mx3_camera, &camera_pdata);
diff --git a/arch/arm/mach-mxc91231/clock.c b/arch/arm/mach-mxc91231/clock.c
index ecfa37fef8ad..5c85075d8a56 100644
--- a/arch/arm/mach-mxc91231/clock.c
+++ b/arch/arm/mach-mxc91231/clock.c
@@ -624,7 +624,6 @@ static struct clk_lookup lookups[] = {
int __init mxc91231_clocks_init(unsigned long fref)
{
void __iomem *gpt_base;
- int i;
ckih_rate = fref;
@@ -632,8 +631,7 @@ int __init mxc91231_clocks_init(unsigned long fref)
sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]);
sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]);
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR);
mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT);
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index f93c59634191..9bf33b30a025 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -86,11 +86,19 @@ static struct amba_device cpu8815_amba_gpio[] = {
},
};
+static struct amba_device cpu8815_amba_rng = {
+ .dev = {
+ .init_name = "rng",
+ },
+ __MEM_4K_RESOURCE(NOMADIK_RNG_BASE),
+};
+
static struct amba_device *amba_devs[] __initdata = {
cpu8815_amba_gpio + 0,
cpu8815_amba_gpio + 1,
cpu8815_amba_gpio + 2,
cpu8815_amba_gpio + 3,
+ &cpu8815_amba_rng
};
static int __init cpu8815_init(void)
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 9ce17f13d3f1..b6a537c875b8 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,7 +3,7 @@
#
# Common support
-obj-y := io.o id.o sram.o irq.o mux.o serial.o devices.o
+obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o
obj-y += clock.o clock_data.o opp_data.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 7e70c3c08da6..096f2ed102cb 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -18,18 +18,19 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/smc91x.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <plat/tc.h>
#include <mach/gpio.h>
#include <plat/mux.h>
+#include <plat/flash.h>
#include <plat/fpga.h>
#include <plat/keypad.h>
#include <plat/common.h>
@@ -150,9 +151,9 @@ static struct mtd_partition nor_partitions[] = {
},
};
-static struct flash_platform_data nor_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data nor_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = nor_partitions,
.nr_parts = ARRAY_SIZE(nor_partitions),
};
@@ -164,7 +165,7 @@ static struct resource nor_resource = {
};
static struct platform_device nor_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &nor_data,
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index fa7cecea19f9..d1100e4f65ac 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -26,6 +26,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/i2c/tps65010.h>
#include <linux/smc91x.h>
@@ -35,7 +36,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <plat/mux.h>
@@ -45,6 +45,7 @@
#include <plat/usb.h>
#include <plat/keypad.h>
#include <plat/common.h>
+#include <plat/flash.h>
#include "board-h2.h"
@@ -121,9 +122,9 @@ static struct mtd_partition h2_nor_partitions[] = {
}
};
-static struct flash_platform_data h2_nor_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data h2_nor_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = h2_nor_partitions,
.nr_parts = ARRAY_SIZE(h2_nor_partitions),
};
@@ -134,7 +135,7 @@ static struct resource h2_nor_resource = {
};
static struct platform_device h2_nor_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &h2_nor_data,
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 6a7f9c391cf1..a53ab8297d25 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -25,6 +25,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#include <linux/i2c/tps65010.h>
@@ -37,7 +38,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/irqs.h>
@@ -47,6 +47,7 @@
#include <plat/keypad.h>
#include <plat/dma.h>
#include <plat/common.h>
+#include <plat/flash.h>
#include "board-h3.h"
@@ -126,9 +127,9 @@ static struct mtd_partition nor_partitions[] = {
}
};
-static struct flash_platform_data nor_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data nor_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = nor_partitions,
.nr_parts = ARRAY_SIZE(nor_partitions),
};
@@ -139,7 +140,7 @@ static struct resource nor_resource = {
};
static struct platform_device nor_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &nor_data,
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 2133b006f6a3..5d12fd35681b 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -22,16 +22,17 @@
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/smc91x.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <plat/mux.h>
+#include <plat/flash.h>
#include <plat/fpga.h>
#include <mach/gpio.h>
#include <plat/tc.h>
@@ -94,9 +95,9 @@ static struct mtd_partition innovator_partitions[] = {
}
};
-static struct flash_platform_data innovator_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data innovator_flash_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = innovator_partitions,
.nr_parts = ARRAY_SIZE(innovator_partitions),
};
@@ -108,7 +109,7 @@ static struct resource innovator_flash_resource = {
};
static struct platform_device innovator_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &innovator_flash_data,
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index ccea4f448e9a..80d862001def 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -37,6 +37,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/i2c/tps65010.h>
@@ -46,8 +47,8 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
+#include <plat/flash.h>
#include <plat/usb.h>
#include <plat/mux.h>
#include <plat/tc.h>
@@ -94,9 +95,9 @@ static struct mtd_partition osk_partitions[] = {
}
};
-static struct flash_platform_data osk_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data osk_flash_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = osk_partitions,
.nr_parts = ARRAY_SIZE(osk_partitions),
};
@@ -107,7 +108,7 @@ static struct resource osk_flash_resource = {
};
static struct platform_device osk5912_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &osk_flash_data,
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 9fe887262bdf..569b4c9085cd 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/apm-emulation.h>
@@ -31,9 +32,9 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/gpio.h>
+#include <plat/flash.h>
#include <plat/mux.h>
#include <plat/usb.h>
#include <plat/tc.h>
@@ -126,9 +127,9 @@ static struct mtd_partition palmte_rom_partitions[] = {
},
};
-static struct flash_platform_data palmte_rom_data = {
- .map_name = "map_rom",
+static struct physmap_flash_data palmte_rom_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = palmte_rom_partitions,
.nr_parts = ARRAY_SIZE(palmte_rom_partitions),
};
@@ -140,7 +141,7 @@ static struct resource palmte_rom_resource = {
};
static struct platform_device palmte_rom_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = -1,
.dev = {
.platform_data = &palmte_rom_data,
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index af068e3e0fe7..6ad49a2cc1a0 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -21,16 +21,17 @@
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/leds.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <plat/led.h>
#include <mach/gpio.h>
+#include <plat/flash.h>
#include <plat/mux.h>
#include <plat/usb.h>
#include <plat/dma.h>
@@ -104,9 +105,9 @@ static struct mtd_partition palmtt_partitions[] = {
}
};
-static struct flash_platform_data palmtt_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data palmtt_flash_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = palmtt_partitions,
.nr_parts = ARRAY_SIZE(palmtt_partitions),
};
@@ -118,7 +119,7 @@ static struct resource palmtt_flash_resource = {
};
static struct platform_device palmtt_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &palmtt_flash_data,
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index c7a3b6f36500..6641de9257ef 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -25,14 +25,15 @@
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/gpio.h>
+#include <plat/flash.h>
#include <plat/mux.h>
#include <plat/usb.h>
#include <plat/dma.h>
@@ -126,10 +127,9 @@ static struct mtd_partition palmz71_rom_partitions[] = {
},
};
-static struct flash_platform_data palmz71_rom_data = {
- .map_name = "map_rom",
- .name = "onboardrom",
+static struct physmap_flash_data palmz71_rom_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = palmz71_rom_partitions,
.nr_parts = ARRAY_SIZE(palmz71_rom_partitions),
};
@@ -141,7 +141,7 @@ static struct resource palmz71_rom_resource = {
};
static struct platform_device palmz71_rom_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = -1,
.dev = {
.platform_data = &palmz71_rom_data,
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 1387a4f15da9..e854d5741c88 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -18,19 +18,20 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/smc91x.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <plat/tc.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include <plat/fpga.h>
+#include <plat/flash.h>
#include <plat/keypad.h>
#include <plat/common.h>
#include <plat/board.h>
@@ -117,9 +118,9 @@ static struct mtd_partition nor_partitions[] = {
},
};
-static struct flash_platform_data nor_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data nor_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = nor_partitions,
.nr_parts = ARRAY_SIZE(nor_partitions),
};
@@ -131,7 +132,7 @@ static struct resource nor_resource = {
};
static struct platform_device nor_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &nor_data,
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
index 7a97fac83d8d..2fb1e5f8e2ec 100644
--- a/arch/arm/mach-omap1/board-sx1.c
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -22,6 +22,7 @@
#include <linux/notifier.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/errno.h>
@@ -29,10 +30,10 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/gpio.h>
+#include <plat/flash.h>
#include <plat/mux.h>
#include <plat/dma.h>
#include <plat/irda.h>
@@ -287,9 +288,9 @@ static struct mtd_partition sx1_partitions[] = {
}
};
-static struct flash_platform_data sx1_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data sx1_flash_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
.parts = sx1_partitions,
.nr_parts = ARRAY_SIZE(sx1_partitions),
};
@@ -310,7 +311,7 @@ static struct resource sx1_old_flash_resource[] = {
};
static struct platform_device sx1_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &sx1_flash_data,
@@ -327,7 +328,7 @@ static struct resource sx1_new_flash_resource = {
};
static struct platform_device sx1_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &sx1_flash_data,
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 169183537997..87b9436fe7c0 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/mtd/physmap.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/serial_8250.h>
@@ -27,11 +28,11 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <plat/common.h>
#include <mach/gpio.h>
+#include <plat/flash.h>
#include <plat/mux.h>
#include <plat/tc.h>
#include <plat/usb.h>
@@ -86,9 +87,9 @@ static int __init ext_uart_init(void)
}
arch_initcall(ext_uart_init);
-static struct flash_platform_data voiceblue_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data voiceblue_flash_data = {
.width = 2,
+ .set_vpp = omap1_set_vpp,
};
static struct resource voiceblue_flash_resource = {
@@ -98,7 +99,7 @@ static struct resource voiceblue_flash_resource = {
};
static struct platform_device voiceblue_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &voiceblue_flash_data,
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
index ab995a9c606c..65e7b5b85d83 100644
--- a/arch/arm/mach-omap1/clock_data.c
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -599,7 +599,7 @@ static struct clk i2c_ick = {
static struct omap_clk omap_clks[] = {
/* non-ULPD clocks */
CLK(NULL, "ck_ref", &ck_ref, CK_16XX | CK_1510 | CK_310 | CK_7XX),
- CLK(NULL, "ck_dpll1", &ck_dpll1, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "ck_dpll1", &ck_dpll1, CK_16XX | CK_1510 | CK_310 | CK_7XX),
/* CK_GEN1 clocks */
CLK(NULL, "ck_dpll1out", &ck_dpll1out.clk, CK_16XX),
CLK(NULL, "ck_sossi", &sossi_ck, CK_16XX),
@@ -627,7 +627,7 @@ static struct omap_clk omap_clks[] = {
CLK(NULL, "tc2_ck", &tc2_ck, CK_16XX),
CLK(NULL, "dma_ck", &dma_ck, CK_16XX | CK_1510 | CK_310),
CLK(NULL, "dma_lcdfree_ck", &dma_lcdfree_ck, CK_16XX),
- CLK(NULL, "api_ck", &api_ck.clk, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "api_ck", &api_ck.clk, CK_16XX | CK_1510 | CK_310 | CK_7XX),
CLK(NULL, "lb_ck", &lb_ck.clk, CK_1510 | CK_310),
CLK(NULL, "rhea1_ck", &rhea1_ck, CK_16XX),
CLK(NULL, "rhea2_ck", &rhea2_ck, CK_16XX),
@@ -658,6 +658,10 @@ static struct omap_clk omap_clks[] = {
CLK("i2c_omap.1", "fck", &i2c_fck, CK_16XX | CK_1510 | CK_310 | CK_7XX),
CLK("i2c_omap.1", "ick", &i2c_ick, CK_16XX),
CLK("i2c_omap.1", "ick", &dummy_ck, CK_1510 | CK_310 | CK_7XX),
+ CLK("omap1_spi100k.1", "fck", &dummy_ck, CK_7XX),
+ CLK("omap1_spi100k.1", "ick", &dummy_ck, CK_7XX),
+ CLK("omap1_spi100k.2", "fck", &dummy_ck, CK_7XX),
+ CLK("omap1_spi100k.2", "ick", &dummy_ck, CK_7XX),
CLK("omap_uwire", "fck", &armxor_ck.clk, CK_16XX | CK_1510 | CK_310),
CLK("omap-mcbsp.1", "ick", &dspper_ck, CK_16XX),
CLK("omap-mcbsp.1", "ick", &dummy_ck, CK_1510 | CK_310),
@@ -674,7 +678,7 @@ static struct omap_clk omap_clks[] = {
* init
*/
-static struct clk_functions omap1_clk_functions __initdata = {
+static struct clk_functions omap1_clk_functions = {
.clk_enable = omap1_clk_enable,
.clk_disable = omap1_clk_disable,
.clk_round_rate = omap1_clk_round_rate,
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 23ded2d49600..a2d07aa75c9e 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/spi/spi.h>
#include <mach/hardware.h>
#include <asm/mach/map.h>
@@ -23,6 +24,7 @@
#include <plat/mux.h>
#include <mach/gpio.h>
#include <plat/mmc.h>
+#include <plat/omap7xx.h>
/*-------------------------------------------------------------------------*/
@@ -196,6 +198,38 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
/*-------------------------------------------------------------------------*/
+/* OMAP7xx SPI support */
+#if defined(CONFIG_SPI_OMAP_100K) || defined(CONFIG_SPI_OMAP_100K_MODULE)
+
+struct platform_device omap_spi1 = {
+ .name = "omap1_spi100k",
+ .id = 1,
+};
+
+struct platform_device omap_spi2 = {
+ .name = "omap1_spi100k",
+ .id = 2,
+};
+
+static void omap_init_spi100k(void)
+{
+ omap_spi1.dev.platform_data = ioremap(OMAP7XX_SPI1_BASE, 0x7ff);
+ if (omap_spi1.dev.platform_data)
+ platform_device_register(&omap_spi1);
+
+ omap_spi2.dev.platform_data = ioremap(OMAP7XX_SPI2_BASE, 0x7ff);
+ if (omap_spi2.dev.platform_data)
+ platform_device_register(&omap_spi2);
+}
+
+#else
+static inline void omap_init_spi100k(void)
+{
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#if defined(CONFIG_OMAP_STI)
#define OMAP1_STI_BASE 0xfffea000
@@ -263,6 +297,7 @@ static int __init omap1_init_devices(void)
omap_init_mbox();
omap_init_rtc();
+ omap_init_spi100k();
omap_init_sti();
return 0;
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
new file mode 100644
index 000000000000..0b07a78eeaa7
--- /dev/null
+++ b/arch/arm/mach-omap1/flash.c
@@ -0,0 +1,33 @@
+/*
+ * Flash support for OMAP1
+ *
+ * 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/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+#include <plat/io.h>
+#include <plat/tc.h>
+
+void omap1_set_vpp(struct map_info *map, int enable)
+{
+ static int count;
+ u32 l;
+
+ if (enable) {
+ if (count++ == 0) {
+ l = omap_readl(EMIFS_CONFIG);
+ l |= OMAP_EMIFS_CONFIG_WP;
+ omap_writel(l, EMIFS_CONFIG);
+ }
+ } else {
+ if (count && (--count == 0)) {
+ l = omap_readl(EMIFS_CONFIG);
+ l &= ~OMAP_EMIFS_CONFIG_WP;
+ omap_writel(l, EMIFS_CONFIG);
+ }
+ }
+}
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index 07212cc621ae..84341377232d 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -62,6 +62,14 @@ MUX_CFG_7XX("MMC_7XX_DAT0", 2, 17, 0, 16, 1, 0)
/* I2C interface */
MUX_CFG_7XX("I2C_7XX_SCL", 5, 1, 0, 0, 1, 0)
MUX_CFG_7XX("I2C_7XX_SDA", 5, 5, 0, 0, 1, 0)
+
+/* SPI pins */
+MUX_CFG_7XX("SPI_7XX_1", 6, 5, 4, 4, 1, 0)
+MUX_CFG_7XX("SPI_7XX_2", 6, 9, 4, 8, 1, 0)
+MUX_CFG_7XX("SPI_7XX_3", 6, 13, 4, 12, 1, 0)
+MUX_CFG_7XX("SPI_7XX_4", 6, 17, 4, 16, 1, 0)
+MUX_CFG_7XX("SPI_7XX_5", 8, 25, 0, 24, 0, 0)
+MUX_CFG_7XX("SPI_7XX_6", 9, 5, 0, 4, 0, 0)
};
#define OMAP7XX_PINS_SZ ARRAY_SIZE(omap7xx_pins)
#else
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 10eafa70a909..606bf04f51b6 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -80,6 +80,7 @@ config MACH_OVERO
config MACH_OMAP3EVM
bool "OMAP 3530 EVM board"
depends on ARCH_OMAP3 && ARCH_OMAP34XX
+ select OMAP_PACKAGE_CBB
config MACH_OMAP3517EVM
bool "OMAP3517/ AM3517 EVM board"
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index e508904fb67e..31042ee7e772 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/delay.h>
#include <linux/i2c/twl.h>
#include <linux/err.h>
@@ -28,7 +29,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <mach/gpio.h>
#include <plat/mux.h>
@@ -74,8 +74,7 @@ static struct mtd_partition sdp2430_partitions[] = {
}
};
-static struct flash_platform_data sdp2430_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data sdp2430_flash_data = {
.width = 2,
.parts = sdp2430_partitions,
.nr_parts = ARRAY_SIZE(sdp2430_partitions),
@@ -88,7 +87,7 @@ static struct resource sdp2430_flash_resource = {
};
static struct platform_device sdp2430_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &sdp2430_flash_data,
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index 739059632811..739059632811 100755..100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index cfb7f1257d20..ffb005101fa8 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
@@ -29,7 +30,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/mach/flash.h>
#include <plat/control.h>
#include <mach/gpio.h>
@@ -115,8 +115,7 @@ static struct mtd_partition h4_partitions[] = {
}
};
-static struct flash_platform_data h4_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data h4_flash_data = {
.width = 2,
.parts = h4_partitions,
.nr_parts = ARRAY_SIZE(h4_partitions),
@@ -127,7 +126,7 @@ static struct resource h4_flash_resource = {
};
static struct platform_device h4_flash_device = {
- .name = "omapflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &h4_flash_data,
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 8dd277c36661..5c8474c75a34 100755..100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -24,6 +24,7 @@
#include <plat/common.h>
#include <plat/usb.h>
+#include "mux.h"
#include "mmc-twl4030.h"
/* Zoom2 has Qwerty keyboard*/
@@ -63,21 +64,21 @@ static int board_keymap[] = {
KEY(5, 1, KEY_H),
KEY(5, 2, KEY_J),
KEY(5, 3, KEY_F3),
+ KEY(5, 4, KEY_UNKNOWN),
KEY(5, 5, KEY_VOLUMEDOWN),
KEY(5, 6, KEY_M),
- KEY(5, 7, KEY_ENTER),
+ KEY(5, 7, KEY_RIGHT),
KEY(6, 0, KEY_Q),
KEY(6, 1, KEY_A),
KEY(6, 2, KEY_N),
KEY(6, 3, KEY_BACKSPACE),
KEY(6, 6, KEY_P),
- KEY(6, 7, KEY_SELECT),
+ KEY(6, 7, KEY_UP),
KEY(7, 0, KEY_PROG1), /*MACRO 1 <User defined> */
KEY(7, 1, KEY_PROG2), /*MACRO 2 <User defined> */
KEY(7, 2, KEY_PROG3), /*MACRO 3 <User defined> */
KEY(7, 3, KEY_PROG4), /*MACRO 4 <User defined> */
- KEY(7, 5, KEY_RIGHT),
- KEY(7, 6, KEY_UP),
+ KEY(7, 6, KEY_SELECT),
KEY(7, 7, KEY_DOWN)
};
@@ -263,9 +264,17 @@ static int __init omap_i2c_init(void)
return 0;
}
+static void enable_board_wakeup_source(void)
+{
+ /* T2 interrupt line (keypad) */
+ omap_mux_init_signal("sys_nirq",
+ OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
+}
+
void __init zoom_peripherals_init(void)
{
omap_i2c_init();
omap_serial_init();
usb_musb_init();
+ enable_board_wakeup_source();
}
diff --git a/arch/arm/mach-omap2/board-zoom3.c b/arch/arm/mach-omap2/board-zoom3.c
index a9fe9181b010..6512b2143f32 100644
--- a/arch/arm/mach-omap2/board-zoom3.c
+++ b/arch/arm/mach-omap2/board-zoom3.c
@@ -20,6 +20,7 @@
#include <plat/common.h>
#include <plat/board.h>
+#include <plat/usb.h>
#include "mux.h"
#include "sdram-hynix-h8mbx00u0mer-0em.h"
@@ -51,11 +52,24 @@ static struct omap_board_mux board_mux[] __initdata = {
#define board_mux NULL
#endif
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+ .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+ .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+ .phy_reset = true,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = 64,
+ .reset_gpio_port[2] = -EINVAL,
+};
+
static void __init omap_zoom_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
zoom_peripherals_init();
zoom_debugboard_init();
+
+ omap_mux_init_gpio(64, OMAP_PIN_OUTPUT);
+ usb_ehci_init(&ehci_pdata);
}
MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
diff --git a/arch/arm/mach-omap2/clock2xxx.c b/arch/arm/mach-omap2/clock2xxx.c
index d0e3fb7f9298..5420356eb407 100644
--- a/arch/arm/mach-omap2/clock2xxx.c
+++ b/arch/arm/mach-omap2/clock2xxx.c
@@ -449,40 +449,78 @@ int omap2_select_table_rate(struct clk *clk, unsigned long rate)
#ifdef CONFIG_CPU_FREQ
/*
* Walk PRCM rate table and fillout cpufreq freq_table
+ * XXX This should be replaced by an OPP layer in the near future
*/
-static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(rate_table)];
+static struct cpufreq_frequency_table *freq_table;
void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
{
- struct prcm_config *prcm;
+ const struct prcm_config *prcm;
+ long sys_ck_rate;
int i = 0;
+ int tbl_sz = 0;
+
+ sys_ck_rate = clk_get_rate(sclk);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
- if (prcm->xtal_speed != sys_ck.rate)
+ if (prcm->xtal_speed != sys_ck_rate)
continue;
/* don't put bypass rates in table */
if (prcm->dpll_speed == prcm->xtal_speed)
continue;
- freq_table[i].index = i;
- freq_table[i].frequency = prcm->mpu_speed / 1000;
- i++;
+ tbl_sz++;
}
- if (i == 0) {
- printk(KERN_WARNING "%s: failed to initialize frequency "
- "table\n", __func__);
+ /*
+ * XXX Ensure that we're doing what CPUFreq expects for this error
+ * case and the following one
+ */
+ if (tbl_sz == 0) {
+ pr_warning("%s: no matching entries in rate_table\n",
+ __func__);
+ return;
+ }
+
+ /* Include the CPUFREQ_TABLE_END terminator entry */
+ tbl_sz++;
+
+ freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * tbl_sz,
+ GFP_ATOMIC);
+ if (!freq_table) {
+ pr_err("%s: could not kzalloc frequency table\n", __func__);
return;
}
+ for (prcm = rate_table; prcm->mpu_speed; prcm++) {
+ if (!(prcm->flags & cpu_mask))
+ continue;
+ if (prcm->xtal_speed != sys_ck_rate)
+ continue;
+
+ /* don't put bypass rates in table */
+ if (prcm->dpll_speed == prcm->xtal_speed)
+ continue;
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = prcm->mpu_speed / 1000;
+ i++;
+ }
+
freq_table[i].index = i;
freq_table[i].frequency = CPUFREQ_TABLE_END;
*table = &freq_table[0];
}
+
+void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+ kfree(freq_table);
+}
+
#endif
struct clk_functions omap2_clk_functions = {
@@ -494,6 +532,7 @@ struct clk_functions omap2_clk_functions = {
.clk_disable_unused = omap2_clk_disable_unused,
#ifdef CONFIG_CPU_FREQ
.clk_init_cpufreq_table = omap2_clk_init_cpufreq_table,
+ .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table,
#endif
};
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index ded32364f32b..d4217b93e10b 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -34,7 +34,6 @@
#include <asm/div64.h>
#include <asm/clkdev.h>
-#include <plat/sdrc.h>
#include "clock.h"
#include "clock34xx.h"
#include "sdrc.h"
diff --git a/arch/arm/mach-omap2/clock34xx_data.c b/arch/arm/mach-omap2/clock34xx_data.c
index 8bdcc9cc7f9a..c6031d74d6f6 100644
--- a/arch/arm/mach-omap2/clock34xx_data.c
+++ b/arch/arm/mach-omap2/clock34xx_data.c
@@ -776,6 +776,8 @@ static struct clk dpll4_m5_ck = {
.clksel_mask = OMAP3430_CLKSEL_CAM_MASK,
.clksel = div16_dpll4_clksel,
.clkdm_name = "dpll4_clkdm",
+ .set_rate = &omap2_clksel_set_rate,
+ .round_rate = &omap2_clksel_round_rate,
.recalc = &omap2_clksel_recalc,
};
@@ -1500,6 +1502,7 @@ static struct clk uart2_fck = {
.parent = &core_48m_fck,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_UART2_SHIFT,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
@@ -1509,6 +1512,7 @@ static struct clk uart1_fck = {
.parent = &core_48m_fck,
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_UART1_SHIFT,
+ .clkdm_name = "core_l4_clkdm",
.recalc = &followparent_recalc,
};
@@ -2745,7 +2749,7 @@ static struct clk mcbsp4_ick = {
};
static const struct clksel mcbsp_234_clksel[] = {
- { .parent = &core_96m_fck, .rates = common_mcbsp_96m_rates },
+ { .parent = &per_96m_fck, .rates = common_mcbsp_96m_rates },
{ .parent = &mcbsp_clks, .rates = common_mcbsp_mcbsp_rates },
{ .parent = NULL }
};
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 1a45ed1e8ba1..dd285f001467 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -559,7 +559,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
* downstream clocks for debugging purposes?
*/
- if (!clkdm || !clk)
+ if (!clkdm || !clk || !clkdm->clktrctrl_mask)
return -EINVAL;
if (atomic_inc_return(&clkdm->usecount) > 1)
@@ -610,7 +610,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
* downstream clocks for debugging purposes?
*/
- if (!clkdm || !clk)
+ if (!clkdm || !clk || !clkdm->clktrctrl_mask)
return -EINVAL;
#ifdef DEBUG
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index a8749e8017b9..5a7996402c53 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -33,7 +33,6 @@
#include <plat/sdrc.h>
#include <plat/gpmc.h>
#include <plat/serial.h>
-#include <plat/mux.h>
#include <plat/vram.h>
#include "clock.h"
@@ -73,21 +72,21 @@ static struct map_desc omap24xx_io_desc[] __initdata = {
#ifdef CONFIG_ARCH_OMAP2420
static struct map_desc omap242x_io_desc[] __initdata = {
{
- .virtual = DSP_MEM_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_MEM_24XX_PHYS),
- .length = DSP_MEM_24XX_SIZE,
+ .virtual = DSP_MEM_2420_VIRT,
+ .pfn = __phys_to_pfn(DSP_MEM_2420_PHYS),
+ .length = DSP_MEM_2420_SIZE,
.type = MT_DEVICE
},
{
- .virtual = DSP_IPI_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_IPI_24XX_PHYS),
- .length = DSP_IPI_24XX_SIZE,
+ .virtual = DSP_IPI_2420_VIRT,
+ .pfn = __phys_to_pfn(DSP_IPI_2420_PHYS),
+ .length = DSP_IPI_2420_SIZE,
.type = MT_DEVICE
},
{
- .virtual = DSP_MMU_24XX_VIRT,
- .pfn = __phys_to_pfn(DSP_MMU_24XX_PHYS),
- .length = DSP_MMU_24XX_SIZE,
+ .virtual = DSP_MMU_2420_VIRT,
+ .pfn = __phys_to_pfn(DSP_MMU_2420_PHYS),
+ .length = DSP_MMU_2420_SIZE,
.type = MT_DEVICE
},
};
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index e071b3fd1878..a8febd3cea17 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -977,6 +977,38 @@ static void __init omap_mux_init_list(struct omap_mux *superset)
}
}
+#ifdef CONFIG_OMAP_MUX
+
+static void omap_mux_init_package(struct omap_mux *superset,
+ struct omap_mux *package_subset,
+ struct omap_ball *package_balls)
+{
+ if (package_subset)
+ omap_mux_package_fixup(package_subset, superset);
+ if (package_balls)
+ omap_mux_package_init_balls(package_balls, superset);
+}
+
+static void omap_mux_init_signals(struct omap_board_mux *board_mux)
+{
+ omap_mux_set_cmdline_signals();
+ omap_mux_set_board_signals(board_mux);
+}
+
+#else
+
+static void omap_mux_init_package(struct omap_mux *superset,
+ struct omap_mux *package_subset,
+ struct omap_ball *package_balls)
+{
+}
+
+static void omap_mux_init_signals(struct omap_board_mux *board_mux)
+{
+}
+
+#endif
+
int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
struct omap_mux *superset,
struct omap_mux *package_subset,
@@ -993,14 +1025,9 @@ int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
return -ENODEV;
}
-#ifdef CONFIG_OMAP_MUX
- omap_mux_package_fixup(package_subset, superset);
- omap_mux_package_init_balls(package_balls, superset);
- omap_mux_set_cmdline_signals();
- omap_mux_set_board_signals(board_mux);
-#endif
-
+ omap_mux_init_package(superset, package_subset, package_balls);
omap_mux_init_list(superset);
+ omap_mux_init_signals(board_mux);
return 0;
}
diff --git a/arch/arm/mach-omap2/opp2420_data.c b/arch/arm/mach-omap2/opp2420_data.c
index 126a9396b3a8..e6dda694fd5c 100644
--- a/arch/arm/mach-omap2/opp2420_data.c
+++ b/arch/arm/mach-omap2/opp2420_data.c
@@ -9,45 +9,47 @@
* The OMAP2 processor can be run at several discrete 'PRCM configurations'.
* These configurations are characterized by voltage and speed for clocks.
* The device is only validated for certain combinations. One way to express
- * these combinations is via the 'ratio's' which the clocks operate with
+ * these combinations is via the 'ratios' which the clocks operate with
* respect to each other. These ratio sets are for a given voltage/DPLL
- * setting. All configurations can be described by a DPLL setting and a ratio
- * There are 3 ratio sets for the 2430 and X ratio sets for 2420.
- *
- * 2430 differs from 2420 in that there are no more phase synchronizers used.
- * They both have a slightly different clock domain setup. 2420(iva1,dsp) vs
- * 2430 (iva2.1, NOdsp, mdm)
+ * setting. All configurations can be described by a DPLL setting and a ratio.
*
* XXX Missing voltage data.
+ * XXX Missing 19.2MHz sys_clk rate sets (needed for N800/N810)
*
* THe format described in this file is deprecated. Once a reasonable
* OPP API exists, the data in this file should be converted to use it.
*
* This is technically part of the OMAP2xxx clock code.
+ *
+ * Considerable work is still needed to fully support dynamic frequency
+ * changes on OMAP2xxx-series chips. Readers interested in such a
+ * project are encouraged to review the Maemo Diablo RX-34 and RX-44
+ * kernel source at:
+ * http://repository.maemo.org/pool/diablo/free/k/kernel-source-diablo/
*/
#include "opp2xxx.h"
#include "sdrc.h"
#include "clock.h"
-/*-------------------------------------------------------------------------
- * Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
+/*
+ * Key dividers which make up a PRCM set. Ratios for a PRCM are mandated.
* xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,
* CM_CLKSEL_DSP, CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL,
* CM_CLKSEL2_PLL, CM_CLKSEL_MDM
*
- * Filling in table based on H4 boards and 2430-SDPs variants available.
- * There are quite a few more rates combinations which could be defined.
+ * Filling in table based on H4 boards available. There are quite a
+ * few more rate combinations which could be defined.
*
- * When multiple values are defined the start up will try and choose the
- * fastest one. If a 'fast' value is defined, then automatically, the /2
- * one should be included as it can be used. Generally having more that
- * one fast set does not make sense, as static timings need to be changed
- * to change the set. The exception is the bypass setting which is
- * availble for low power bypass.
+ * When multiple values are defined the start up will try and choose
+ * the fastest one. If a 'fast' value is defined, then automatically,
+ * the /2 one should be included as it can be used. Generally having
+ * more than one fast set does not make sense, as static timings need
+ * to be changed to change the set. The exception is the bypass
+ * setting which is available for low power bypass.
*
* Note: This table needs to be sorted, fastest to slowest.
- *-------------------------------------------------------------------------*/
+ **/
const struct prcm_config omap2420_rate_table[] = {
/* PRCM I - FAST */
{S12M, S660M, S330M, RI_CM_CLKSEL_MPU_VAL, /* 330MHz ARM */
diff --git a/arch/arm/mach-omap2/opp2430_data.c b/arch/arm/mach-omap2/opp2430_data.c
index edb81672c844..1b9596ae201e 100644
--- a/arch/arm/mach-omap2/opp2430_data.c
+++ b/arch/arm/mach-omap2/opp2430_data.c
@@ -1,5 +1,5 @@
/*
- * opp2420_data.c - old-style "OPP" table for OMAP2420
+ * opp2430_data.c - old-style "OPP" table for OMAP2430
*
* Copyright (C) 2005-2009 Texas Instruments, Inc.
* Copyright (C) 2004-2009 Nokia Corporation
@@ -9,16 +9,16 @@
* The OMAP2 processor can be run at several discrete 'PRCM configurations'.
* These configurations are characterized by voltage and speed for clocks.
* The device is only validated for certain combinations. One way to express
- * these combinations is via the 'ratio's' which the clocks operate with
+ * these combinations is via the 'ratios' which the clocks operate with
* respect to each other. These ratio sets are for a given voltage/DPLL
- * setting. All configurations can be described by a DPLL setting and a ratio
- * There are 3 ratio sets for the 2430 and X ratio sets for 2420.
+ * setting. All configurations can be described by a DPLL setting and a ratio.
*
* 2430 differs from 2420 in that there are no more phase synchronizers used.
* They both have a slightly different clock domain setup. 2420(iva1,dsp) vs
* 2430 (iva2.1, NOdsp, mdm)
*
* XXX Missing voltage data.
+ * XXX Missing 19.2MHz sys_clk rate sets.
*
* THe format described in this file is deprecated. Once a reasonable
* OPP API exists, the data in this file should be converted to use it.
@@ -30,24 +30,24 @@
#include "sdrc.h"
#include "clock.h"
-/*-------------------------------------------------------------------------
- * Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated.
+/*
+ * Key dividers which make up a PRCM set. Ratios for a PRCM are mandated.
* xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,
* CM_CLKSEL_DSP, CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL,
* CM_CLKSEL2_PLL, CM_CLKSEL_MDM
*
- * Filling in table based on H4 boards and 2430-SDPs variants available.
- * There are quite a few more rates combinations which could be defined.
+ * Filling in table based on 2430-SDPs variants available. There are
+ * quite a few more rate combinations which could be defined.
*
- * When multiple values are defined the start up will try and choose the
- * fastest one. If a 'fast' value is defined, then automatically, the /2
- * one should be included as it can be used. Generally having more that
- * one fast set does not make sense, as static timings need to be changed
- * to change the set. The exception is the bypass setting which is
- * availble for low power bypass.
+ * When multiple values are defined the start up will try and choose
+ * the fastest one. If a 'fast' value is defined, then automatically,
+ * the /2 one should be included as it can be used. Generally having
+ * more than one fast set does not make sense, as static timings need
+ * to be changed to change the set. The exception is the bypass
+ * setting which is available for low power bypass.
*
* Note: This table needs to be sorted, fastest to slowest.
- *-------------------------------------------------------------------------*/
+ */
const struct prcm_config omap2430_rate_table[] = {
/* PRCM #4 - ratio2 (ES2.1) - FAST */
{S13M, S798M, S399M, R2_CM_CLKSEL_MPU_VAL, /* 399MHz ARM */
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 81ed252a0f8a..c6cc809afb79 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -124,8 +124,8 @@ static void omap3_core_save_context(void)
control_padconf_off |= START_PADCONF_SAVE;
omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
/* wait for the save to complete */
- while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
- & PADCONF_SAVE_DONE)
+ while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
+ & PADCONF_SAVE_DONE))
;
/* Save the Interrupt controller context */
omap_intc_save_context();
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 19805a7de06c..837b34757ffc 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -125,6 +125,13 @@ static struct plat_serial8250_port serial_platform_data3[] = {
}
};
#endif
+static inline unsigned int __serial_read_reg(struct uart_port *up,
+ int offset)
+{
+ offset <<= up->regshift;
+ return (unsigned int)__raw_readb(up->membase + offset);
+}
+
static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
int offset)
{
@@ -583,11 +590,12 @@ static unsigned int serial_in_override(struct uart_port *up, int offset)
{
if (UART_RX == offset) {
unsigned int lsr;
- lsr = serial_read_reg(omap_uart[up->line].p, UART_LSR);
+ lsr = __serial_read_reg(up, UART_LSR);
if (!(lsr & UART_LSR_DR))
return -EPERM;
}
- return serial_read_reg(omap_uart[up->line].p, offset);
+
+ return __serial_read_reg(up, offset);
}
void __init omap_serial_early_init(void)
@@ -686,15 +694,16 @@ void __init omap_serial_init_port(int port)
DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
}
- /* omap44xx: Never read empty UART fifo
- * omap3xxx: Never read empty UART fifo on UARTs
- * with IP rev >=0x52
- */
- if (cpu_is_omap44xx())
- uart->p->serial_in = serial_in_override;
- else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
- >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
- uart->p->serial_in = serial_in_override;
+ /*
+ * omap44xx: Never read empty UART fifo
+ * omap3xxx: Never read empty UART fifo on UARTs
+ * with IP rev >=0x52
+ */
+ if (cpu_is_omap44xx())
+ uart->p->serial_in = serial_in_override;
+ else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
+ >= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
+ uart->p->serial_in = serial_in_override;
}
/**
diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
index 898c0e88acbc..9d1975fa4d9f 100644
--- a/arch/arm/mach-pnx4008/clock.c
+++ b/arch/arm/mach-pnx4008/clock.c
@@ -22,8 +22,9 @@
#include <linux/delay.h>
#include <linux/io.h>
-#include <mach/hardware.h>
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
#include <mach/clock.h>
#include "clock.h"
@@ -56,18 +57,19 @@ static void propagate_rate(struct clk *clk)
}
}
-static inline void clk_reg_disable(struct clk *clk)
+static void clk_reg_disable(struct clk *clk)
{
if (clk->enable_reg)
__raw_writel(__raw_readl(clk->enable_reg) &
~(1 << clk->enable_shift), clk->enable_reg);
}
-static inline void clk_reg_enable(struct clk *clk)
+static int clk_reg_enable(struct clk *clk)
{
if (clk->enable_reg)
__raw_writel(__raw_readl(clk->enable_reg) |
(1 << clk->enable_shift), clk->enable_reg);
+ return 0;
}
static inline void clk_reg_disable1(struct clk *clk)
@@ -636,31 +638,34 @@ static struct clk flash_ck = {
static struct clk i2c0_ck = {
.name = "i2c0_ck",
.parent = &per_ck,
- .flags = NEEDS_INITIALIZATION,
- .round_rate = &on_off_round_rate,
- .set_rate = &on_off_set_rate,
+ .flags = NEEDS_INITIALIZATION | FIXED_RATE,
.enable_shift = 0,
.enable_reg = I2CCLKCTRL_REG,
+ .rate = 13000000,
+ .enable = clk_reg_enable,
+ .disable = clk_reg_disable,
};
static struct clk i2c1_ck = {
.name = "i2c1_ck",
.parent = &per_ck,
- .flags = NEEDS_INITIALIZATION,
- .round_rate = &on_off_round_rate,
- .set_rate = &on_off_set_rate,
+ .flags = NEEDS_INITIALIZATION | FIXED_RATE,
.enable_shift = 1,
.enable_reg = I2CCLKCTRL_REG,
+ .rate = 13000000,
+ .enable = clk_reg_enable,
+ .disable = clk_reg_disable,
};
static struct clk i2c2_ck = {
.name = "i2c2_ck",
.parent = &per_ck,
- .flags = NEEDS_INITIALIZATION,
- .round_rate = &on_off_round_rate,
- .set_rate = &on_off_set_rate,
+ .flags = NEEDS_INITIALIZATION | FIXED_RATE,
.enable_shift = 2,
.enable_reg = USB_OTG_CLKCTRL_REG,
+ .rate = 13000000,
+ .enable = clk_reg_enable,
+ .disable = clk_reg_disable,
};
static struct clk spi0_ck = {
@@ -738,16 +743,16 @@ static struct clk wdt_ck = {
.name = "wdt_ck",
.parent = &per_ck,
.flags = NEEDS_INITIALIZATION,
- .round_rate = &on_off_round_rate,
- .set_rate = &on_off_set_rate,
.enable_shift = 0,
.enable_reg = TIMCLKCTRL_REG,
+ .enable = clk_reg_enable,
+ .disable = clk_reg_disable,
};
/* These clocks are visible outside this module
* and can be initialized
*/
-static struct clk *onchip_clks[] = {
+static struct clk *onchip_clks[] __initdata = {
&ck_13MHz,
&ck_pll1,
&ck_pll4,
@@ -777,49 +782,74 @@ static struct clk *onchip_clks[] = {
&wdt_ck,
};
-static int local_clk_enable(struct clk *clk)
-{
- int ret = 0;
-
- if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
- && clk->user_rate)
- ret = clk->set_rate(clk, clk->user_rate);
- return ret;
-}
+static struct clk_lookup onchip_clkreg[] = {
+ { .clk = &ck_13MHz, .con_id = "ck_13MHz" },
+ { .clk = &ck_pll1, .con_id = "ck_pll1" },
+ { .clk = &ck_pll4, .con_id = "ck_pll4" },
+ { .clk = &ck_pll5, .con_id = "ck_pll5" },
+ { .clk = &ck_pll3, .con_id = "ck_pll3" },
+ { .clk = &vfp9_ck, .con_id = "vfp9_ck" },
+ { .clk = &m2hclk_ck, .con_id = "m2hclk_ck" },
+ { .clk = &hclk_ck, .con_id = "hclk_ck" },
+ { .clk = &dma_ck, .con_id = "dma_ck" },
+ { .clk = &flash_ck, .con_id = "flash_ck" },
+ { .clk = &dum_ck, .con_id = "dum_ck" },
+ { .clk = &keyscan_ck, .con_id = "keyscan_ck" },
+ { .clk = &pwm1_ck, .con_id = "pwm1_ck" },
+ { .clk = &pwm2_ck, .con_id = "pwm2_ck" },
+ { .clk = &jpeg_ck, .con_id = "jpeg_ck" },
+ { .clk = &ms_ck, .con_id = "ms_ck" },
+ { .clk = &touch_ck, .con_id = "touch_ck" },
+ { .clk = &i2c0_ck, .dev_id = "pnx-i2c.0" },
+ { .clk = &i2c1_ck, .dev_id = "pnx-i2c.1" },
+ { .clk = &i2c2_ck, .dev_id = "pnx-i2c.2" },
+ { .clk = &spi0_ck, .con_id = "spi0_ck" },
+ { .clk = &spi1_ck, .con_id = "spi1_ck" },
+ { .clk = &uart3_ck, .con_id = "uart3_ck" },
+ { .clk = &uart4_ck, .con_id = "uart4_ck" },
+ { .clk = &uart5_ck, .con_id = "uart5_ck" },
+ { .clk = &uart6_ck, .con_id = "uart6_ck" },
+ { .clk = &wdt_ck, .dev_id = "pnx4008-watchdog" },
+};
static void local_clk_disable(struct clk *clk)
{
- if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
- clk->set_rate(clk, 0);
-}
+ if (WARN_ON(clk->usecount == 0))
+ return;
-static void local_clk_unuse(struct clk *clk)
-{
- if (clk->usecount > 0 && !(--clk->usecount)) {
- local_clk_disable(clk);
+ if (!(--clk->usecount)) {
+ if (clk->disable)
+ clk->disable(clk);
+ else if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
+ clk->set_rate(clk, 0);
if (clk->parent)
- local_clk_unuse(clk->parent);
+ local_clk_disable(clk->parent);
}
}
-static int local_clk_use(struct clk *clk)
+static int local_clk_enable(struct clk *clk)
{
int ret = 0;
- if (clk->usecount++ == 0) {
- if (clk->parent)
- ret = local_clk_use(clk->parent);
- if (ret != 0) {
- clk->usecount--;
- goto out;
+ if (clk->usecount == 0) {
+ if (clk->parent) {
+ ret = local_clk_enable(clk->parent);
+ if (ret != 0)
+ goto out;
}
- ret = local_clk_enable(clk);
+ if (clk->enable)
+ ret = clk->enable(clk);
+ else if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
+ && clk->user_rate)
+ ret = clk->set_rate(clk, clk->user_rate);
if (ret != 0 && clk->parent) {
- local_clk_unuse(clk->parent);
- clk->usecount--;
+ local_clk_disable(clk->parent);
+ goto out;
}
+
+ clk->usecount++;
}
out:
return ret;
@@ -866,35 +896,6 @@ out:
EXPORT_SYMBOL(clk_set_rate);
-struct clk *clk_get(struct device *dev, const char *id)
-{
- struct clk *clk = ERR_PTR(-ENOENT);
- struct clk **clkp;
-
- clock_lock();
- for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
- clkp++) {
- if (strcmp(id, (*clkp)->name) == 0
- && try_module_get((*clkp)->owner)) {
- clk = (*clkp);
- break;
- }
- }
- clock_unlock();
-
- return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
- clock_lock();
- if (clk && !IS_ERR(clk))
- module_put(clk->owner);
- clock_unlock();
-}
-EXPORT_SYMBOL(clk_put);
-
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long ret;
@@ -907,10 +908,10 @@ EXPORT_SYMBOL(clk_get_rate);
int clk_enable(struct clk *clk)
{
- int ret = 0;
+ int ret;
clock_lock();
- ret = local_clk_use(clk);
+ ret = local_clk_enable(clk);
clock_unlock();
return ret;
}
@@ -920,7 +921,7 @@ EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
clock_lock();
- local_clk_unuse(clk);
+ local_clk_disable(clk);
clock_unlock();
}
@@ -967,18 +968,24 @@ static int __init clk_init(void)
for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
clkp++) {
- if (((*clkp)->flags & NEEDS_INITIALIZATION)
- && ((*clkp)->set_rate)) {
- (*clkp)->user_rate = (*clkp)->rate;
- local_set_rate((*clkp), (*clkp)->user_rate);
- if ((*clkp)->set_parent)
- (*clkp)->set_parent((*clkp), (*clkp)->parent);
+ struct clk *clk = *clkp;
+ if (clk->flags & NEEDS_INITIALIZATION) {
+ if (clk->set_rate) {
+ clk->user_rate = clk->rate;
+ local_set_rate(clk, clk->user_rate);
+ if (clk->set_parent)
+ clk->set_parent(clk, clk->parent);
+ }
+ if (clk->enable && clk->usecount)
+ clk->enable(clk);
+ if (clk->disable && !clk->usecount)
+ clk->disable(clk);
}
pr_debug("%s: clock %s, rate %ld\n",
- __func__, (*clkp)->name, (*clkp)->rate);
+ __func__, clk->name, clk->rate);
}
- local_clk_use(&ck_pll4);
+ local_clk_enable(&ck_pll4);
/* if ck_13MHz is not used, disable it. */
if (ck_13MHz.usecount == 0)
@@ -987,6 +994,8 @@ static int __init clk_init(void)
/* Disable autoclocking */
__raw_writeb(0xff, AUTOCLK_CTRL);
+ clkdev_add_table(onchip_clkreg, ARRAY_SIZE(onchip_clkreg));
+
return 0;
}
diff --git a/arch/arm/mach-pnx4008/clock.h b/arch/arm/mach-pnx4008/clock.h
index cd58f372cfd0..39720d6c0d01 100644
--- a/arch/arm/mach-pnx4008/clock.h
+++ b/arch/arm/mach-pnx4008/clock.h
@@ -14,8 +14,6 @@
#define __ARCH_ARM_PNX4008_CLOCK_H__
struct clk {
- struct list_head node;
- struct module *owner;
const char *name;
struct clk *parent;
struct clk *propagate_next;
@@ -29,9 +27,11 @@ struct clk {
u8 enable_shift1;
u32 enable_reg1;
u32 parent_switch_reg;
- u32(*round_rate) (struct clk *, u32);
+ u32(*round_rate) (struct clk *, u32);
int (*set_rate) (struct clk *, u32);
int (*set_parent) (struct clk * clk, struct clk * parent);
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
};
/* Flags */
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c
index f3fea29c00d3..8103f9644e2d 100644
--- a/arch/arm/mach-pnx4008/i2c.c
+++ b/arch/arm/mach-pnx4008/i2c.c
@@ -18,120 +18,24 @@
#include <mach/irqs.h>
#include <mach/i2c.h>
-static int set_clock_run(struct platform_device *pdev)
-{
- struct clk *clk;
- char name[10];
- int retval = 0;
-
- snprintf(name, 10, "i2c%d_ck", pdev->id);
- clk = clk_get(&pdev->dev, name);
- if (!IS_ERR(clk)) {
- clk_set_rate(clk, 1);
- clk_put(clk);
- } else
- retval = -ENOENT;
-
- return retval;
-}
-
-static int set_clock_stop(struct platform_device *pdev)
-{
- struct clk *clk;
- char name[10];
- int retval = 0;
-
- snprintf(name, 10, "i2c%d_ck", pdev->id);
- clk = clk_get(&pdev->dev, name);
- if (!IS_ERR(clk)) {
- clk_set_rate(clk, 0);
- clk_put(clk);
- } else
- retval = -ENOENT;
-
- return retval;
-}
-
-static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int retval = 0;
-#ifdef CONFIG_PM
- retval = set_clock_run(pdev);
-#endif
- return retval;
-}
-
-static int i2c_pnx_resume(struct platform_device *pdev)
-{
- int retval = 0;
-#ifdef CONFIG_PM
- retval = set_clock_run(pdev);
-#endif
- return retval;
-}
-
-static u32 calculate_input_freq(struct platform_device *pdev)
-{
- return HCLK_MHZ;
-}
-
-
-static struct i2c_pnx_algo_data pnx_algo_data0 = {
+static struct i2c_pnx_data i2c0_data = {
+ .name = I2C_CHIP_NAME "0",
.base = PNX4008_I2C1_BASE,
.irq = I2C_1_INT,
};
-static struct i2c_pnx_algo_data pnx_algo_data1 = {
+static struct i2c_pnx_data i2c1_data = {
+ .name = I2C_CHIP_NAME "1",
.base = PNX4008_I2C2_BASE,
.irq = I2C_2_INT,
};
-static struct i2c_pnx_algo_data pnx_algo_data2 = {
+static struct i2c_pnx_data i2c2_data = {
+ .name = "USB-I2C",
.base = (PNX4008_USB_CONFIG_BASE + 0x300),
.irq = USB_I2C_INT,
};
-static struct i2c_adapter pnx_adapter0 = {
- .name = I2C_CHIP_NAME "0",
- .algo_data = &pnx_algo_data0,
-};
-static struct i2c_adapter pnx_adapter1 = {
- .name = I2C_CHIP_NAME "1",
- .algo_data = &pnx_algo_data1,
-};
-
-static struct i2c_adapter pnx_adapter2 = {
- .name = "USB-I2C",
- .algo_data = &pnx_algo_data2,
-};
-
-static struct i2c_pnx_data i2c0_data = {
- .suspend = i2c_pnx_suspend,
- .resume = i2c_pnx_resume,
- .calculate_input_freq = calculate_input_freq,
- .set_clock_run = set_clock_run,
- .set_clock_stop = set_clock_stop,
- .adapter = &pnx_adapter0,
-};
-
-static struct i2c_pnx_data i2c1_data = {
- .suspend = i2c_pnx_suspend,
- .resume = i2c_pnx_resume,
- .calculate_input_freq = calculate_input_freq,
- .set_clock_run = set_clock_run,
- .set_clock_stop = set_clock_stop,
- .adapter = &pnx_adapter1,
-};
-
-static struct i2c_pnx_data i2c2_data = {
- .suspend = i2c_pnx_suspend,
- .resume = i2c_pnx_resume,
- .calculate_input_freq = calculate_input_freq,
- .set_clock_run = set_clock_run,
- .set_clock_stop = set_clock_stop,
- .adapter = &pnx_adapter2,
-};
-
static struct platform_device i2c0_device = {
.name = "pnx-i2c",
.id = 0,
diff --git a/arch/arm/mach-pnx4008/include/mach/clkdev.h b/arch/arm/mach-pnx4008/include/mach/clkdev.h
new file mode 100644
index 000000000000..04b37a89801c
--- /dev/null
+++ b/arch/arm/mach-pnx4008/include/mach/clkdev.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-pnx4008/include/mach/timex.h b/arch/arm/mach-pnx4008/include/mach/timex.h
index 5ff0196c0f16..b383c7de7ab4 100644
--- a/arch/arm/mach-pnx4008/include/mach/timex.h
+++ b/arch/arm/mach-pnx4008/include/mach/timex.h
@@ -14,60 +14,6 @@
#ifndef __PNX4008_TIMEX_H
#define __PNX4008_TIMEX_H
-#include <linux/io.h>
-#include <mach/hardware.h>
-
#define CLOCK_TICK_RATE 1000000
-#define TICKS2USECS(x) (x)
-
-/* MilliSecond Timer - Chapter 21 Page 202 */
-
-#define MSTIM_INT IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0))
-#define MSTIM_CTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4))
-#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8))
-#define MSTIM_MCTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14))
-#define MSTIM_MATCH0 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18))
-#define MSTIM_MATCH1 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c))
-
-/* High Speed Timer - Chpater 22, Page 205 */
-
-#define HSTIM_INT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0))
-#define HSTIM_CTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4))
-#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8))
-#define HSTIM_PMATCH IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC))
-#define HSTIM_PCOUNT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10))
-#define HSTIM_MCTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14))
-#define HSTIM_MATCH0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18))
-#define HSTIM_MATCH1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c))
-#define HSTIM_MATCH2 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20))
-#define HSTIM_CCR IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28))
-#define HSTIM_CR0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C))
-#define HSTIM_CR1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30))
-
-/* IMPORTANT: both timers are UPCOUNTING */
-
-/* xSTIM_MCTRL bit definitions */
-#define MR0_INT 1
-#define RESET_COUNT0 (1<<1)
-#define STOP_COUNT0 (1<<2)
-#define MR1_INT (1<<3)
-#define RESET_COUNT1 (1<<4)
-#define STOP_COUNT1 (1<<5)
-#define MR2_INT (1<<6)
-#define RESET_COUNT2 (1<<7)
-#define STOP_COUNT2 (1<<8)
-
-/* xSTIM_CTRL bit definitions */
-#define COUNT_ENAB 1
-#define RESET_COUNT (1<<1)
-#define DEBUG_EN (1<<2)
-
-/* xSTIM_INT bit definitions */
-#define MATCH0_INT 1
-#define MATCH1_INT (1<<1)
-#define MATCH2_INT (1<<2)
-#define RTC_TICK0 (1<<4)
-#define RTC_TICK1 (1<<5)
-
#endif
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
index b3d8d53e32ef..1f0585329be4 100644
--- a/arch/arm/mach-pnx4008/pm.c
+++ b/arch/arm/mach-pnx4008/pm.c
@@ -21,6 +21,8 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
#include <mach/pm.h>
#include <mach/clock.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index fc0ba183fe12..0c8aad4bb0dc 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -30,6 +30,8 @@
#include <asm/mach/time.h>
#include <asm/errno.h>
+#include "time.h"
+
/*! Note: all timers are UPCOUNTING */
/*!
diff --git a/arch/arm/mach-pnx4008/time.h b/arch/arm/mach-pnx4008/time.h
new file mode 100644
index 000000000000..75e88c570aa7
--- /dev/null
+++ b/arch/arm/mach-pnx4008/time.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-pnx4008/include/mach/timex.h
+ *
+ * PNX4008 timers header file
+ *
+ * Author: Dmitry Chigirev <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+#ifndef PNX_TIME_H
+#define PNX_TIME_H
+
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+#define TICKS2USECS(x) (x)
+
+/* MilliSecond Timer - Chapter 21 Page 202 */
+
+#define MSTIM_INT IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x0))
+#define MSTIM_CTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x4))
+#define MSTIM_COUNTER IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x8))
+#define MSTIM_MCTRL IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x14))
+#define MSTIM_MATCH0 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x18))
+#define MSTIM_MATCH1 IO_ADDRESS((PNX4008_MSTIMER_BASE + 0x1c))
+
+/* High Speed Timer - Chpater 22, Page 205 */
+
+#define HSTIM_INT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x0))
+#define HSTIM_CTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x4))
+#define HSTIM_COUNTER IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x8))
+#define HSTIM_PMATCH IO_ADDRESS((PNX4008_HSTIMER_BASE + 0xC))
+#define HSTIM_PCOUNT IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x10))
+#define HSTIM_MCTRL IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x14))
+#define HSTIM_MATCH0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x18))
+#define HSTIM_MATCH1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x1c))
+#define HSTIM_MATCH2 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x20))
+#define HSTIM_CCR IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x28))
+#define HSTIM_CR0 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x2C))
+#define HSTIM_CR1 IO_ADDRESS((PNX4008_HSTIMER_BASE + 0x30))
+
+/* IMPORTANT: both timers are UPCOUNTING */
+
+/* xSTIM_MCTRL bit definitions */
+#define MR0_INT 1
+#define RESET_COUNT0 (1<<1)
+#define STOP_COUNT0 (1<<2)
+#define MR1_INT (1<<3)
+#define RESET_COUNT1 (1<<4)
+#define STOP_COUNT1 (1<<5)
+#define MR2_INT (1<<6)
+#define RESET_COUNT2 (1<<7)
+#define STOP_COUNT2 (1<<8)
+
+/* xSTIM_CTRL bit definitions */
+#define COUNT_ENAB 1
+#define RESET_COUNT (1<<1)
+#define DEBUG_EN (1<<2)
+
+/* xSTIM_INT bit definitions */
+#define MATCH0_INT 1
+#define MATCH1_INT (1<<1)
+#define MATCH2_INT (1<<2)
+#define RTC_TICK0 (1<<4)
+#define RTC_TICK1 (1<<5)
+
+#endif
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 8a0837ea0294..385c30ee3f23 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -37,6 +37,8 @@ config MACH_ZYLONITE320
config MACH_LITTLETON
bool "PXA3xx Form Factor Platform (aka Littleton)"
select PXA3xx
+ select CPU_PXA300
+ select CPU_PXA310
select PXA_SSP
config MACH_TAVOREVB
@@ -415,6 +417,24 @@ config MACH_TREO680
Say Y here if you intend to run this kernel on Palm Treo 680
smartphone.
+config MACH_RAUMFELD_RC
+ bool "Raumfeld Controller"
+ select PXA3xx
+ select CPU_PXA300
+ select HAVE_PWM
+
+config MACH_RAUMFELD_CONNECTOR
+ bool "Raumfeld Connector"
+ select PXA3xx
+ select CPU_PXA300
+ select PXA_SSP
+
+config MACH_RAUMFELD_SPEAKER
+ bool "Raumfeld Speaker"
+ select PXA3xx
+ select CPU_PXA300
+ select PXA_SSP
+
config PXA_SHARPSL
bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
select SHARP_SCOOP
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index f64afda7e6f6..9d831939b3c5 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -89,6 +89,9 @@ obj-$(CONFIG_MACH_E740) += e740.o
obj-$(CONFIG_MACH_E750) += e750.o
obj-$(CONFIG_MACH_E400) += e400.o
obj-$(CONFIG_MACH_E800) += e800.o
+obj-$(CONFIG_MACH_RAUMFELD_RC) += raumfeld.o
+obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o
+obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o
# Support for blinky lights
led-y := leds.o
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
index 49ae38292310..abba0089a2ae 100644
--- a/arch/arm/mach-pxa/clock.c
+++ b/arch/arm/mach-pxa/clock.c
@@ -78,11 +78,3 @@ const struct clkops clk_cken_ops = {
.enable = clk_cken_enable,
.disable = clk_cken_disable,
};
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
- int i;
-
- for (i = 0; i < num; i++)
- clkdev_add(&clks[i]);
-}
diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h
index 978a3667e90d..d8488742b807 100644
--- a/arch/arm/mach-pxa/clock.h
+++ b/arch/arm/mach-pxa/clock.h
@@ -67,7 +67,3 @@ extern void clk_pxa3xx_cken_enable(struct clk *);
extern void clk_pxa3xx_cken_disable(struct clk *);
#endif
-void clks_register(struct clk_lookup *clks, size_t num);
-int clk_add_alias(const char *alias, const char *alias_name, char *id,
- struct device *dev);
-
diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
index 91417f035069..96ed13081639 100644
--- a/arch/arm/mach-pxa/eseries.c
+++ b/arch/arm/mach-pxa/eseries.c
@@ -128,6 +128,6 @@ static struct clk_lookup eseries_clkregs[] = {
void eseries_register_clks(void)
{
- clks_register(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
+ clkdev_add_table(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
}
diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h
index 50f1297bf5ac..e741bf1bfb2d 100644
--- a/arch/arm/mach-pxa/include/mach/hardware.h
+++ b/arch/arm/mach-pxa/include/mach/hardware.h
@@ -250,20 +250,17 @@
#define cpu_is_pxa930() \
({ \
- unsigned int id = read_cpuid(CPUID_ID); \
- __cpu_is_pxa930(id); \
+ __cpu_is_pxa930(read_cpuid_id()); \
})
#define cpu_is_pxa935() \
({ \
- unsigned int id = read_cpuid(CPUID_ID); \
- __cpu_is_pxa935(id); \
+ __cpu_is_pxa935(read_cpuid_id()); \
})
#define cpu_is_pxa950() \
({ \
- unsigned int id = read_cpuid(CPUID_ID); \
- __cpu_is_pxa950(id); \
+ __cpu_is_pxa950(read_cpuid_id()); \
})
diff --git a/arch/arm/mach-pxa/include/mach/zylonite.h b/arch/arm/mach-pxa/include/mach/zylonite.h
index bf6785adccf4..9edf645368d6 100644
--- a/arch/arm/mach-pxa/include/mach/zylonite.h
+++ b/arch/arm/mach-pxa/include/mach/zylonite.h
@@ -8,13 +8,6 @@
/* the following variables are processor specific and initialized
* by the corresponding zylonite_pxa3xx_init()
*/
-struct platform_mmc_slot {
- int gpio_cd;
- int gpio_wp;
-};
-
-extern struct platform_mmc_slot zylonite_mmc_slot[];
-
extern int gpio_eth_irq;
extern int gpio_debug_led1;
extern int gpio_debug_led2;
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index f28c1715b910..fa527b258d61 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -110,6 +110,12 @@ static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
GPIO7_MMC1_CLK,
GPIO8_MMC1_CMD,
GPIO15_GPIO, /* card detect */
+
+ /* UART3 */
+ GPIO107_UART3_CTS,
+ GPIO108_UART3_RTS,
+ GPIO109_UART3_TXD,
+ GPIO110_UART3_RXD,
};
static struct resource smc91x_resources[] = {
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 8a38d604dc77..189f330719a2 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -381,7 +381,7 @@ err:
return ret;
}
-static int magician_backlight_notify(int brightness)
+static int magician_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(EGPIO_MAGICIAN_BL_POWER, brightness);
if (brightness >= 200) {
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index 59140217890a..e100af78b166 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -270,7 +270,7 @@ err:
return ret;
}
-static int palmld_backlight_notify(int brightness)
+static int palmld_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_PALMLD_BL_POWER, brightness);
gpio_set_value(GPIO_NR_PALMLD_LCD_POWER, brightness);
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 7f89ca20f13a..8fe3ec27568f 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -209,7 +209,7 @@ err:
return ret;
}
-static int palmt5_backlight_notify(int brightness)
+static int palmt5_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_PALMT5_BL_POWER, brightness);
gpio_set_value(GPIO_NR_PALMT5_LCD_POWER, brightness);
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index 308417592007..b992f07ece21 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -185,7 +185,7 @@ err:
return ret;
}
-static int palmtc_backlight_notify(int brightness)
+static int palmtc_backlight_notify(struct device *dev, int brightness)
{
/* backlight is on when GPIO16 AF0 is high */
gpio_set_value(GPIO_NR_PALMTC_BL_POWER, brightness);
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 265d62bae7de..dc728d6ab94e 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -181,7 +181,7 @@ err:
return ret;
}
-static int palmte2_backlight_notify(int brightness)
+static int palmte2_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_PALMTE2_BL_POWER, brightness);
gpio_set_value(GPIO_NR_PALMTE2_LCD_POWER, brightness);
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index 606eb7e8a17e..b433bb496711 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -375,7 +375,7 @@ err:
return ret;
}
-static int treo_backlight_notify(int brightness)
+static int treo_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_TREO_BL_POWER, brightness);
return TREO_MAX_INTENSITY - brightness;
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 7bf18c2f002f..b37a025c0b7b 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -269,7 +269,7 @@ err:
return ret;
}
-static int palmtx_backlight_notify(int brightness)
+static int palmtx_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_PALMTX_BL_POWER, brightness);
gpio_set_value(GPIO_NR_PALMTX_LCD_POWER, brightness);
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index d787ac7cfdd8..1c5d68a94511 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -196,7 +196,7 @@ err:
return ret;
}
-static int palmz72_backlight_notify(int brightness)
+static int palmz72_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(GPIO_NR_PALMZ72_BL_POWER, brightness);
gpio_set_value(GPIO_NR_PALMZ72_LCD_POWER, brightness);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index e5eeb3a62d01..c2b938a4d5c9 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -293,7 +293,7 @@ static struct pxamci_platform_data poodle_mci_platform_data = {
.init = poodle_mci_init,
.setpower = poodle_mci_setpower,
.exit = poodle_mci_exit,
- .gpio_card_detect = POODLE_IRQ_GPIO_nSD_DETECT,
+ .gpio_card_detect = POODLE_GPIO_nSD_DETECT,
.gpio_card_ro = POODLE_GPIO_nSD_WP,
.gpio_power = -1,
};
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 2c1b0b70d01d..0b9ad30bfd51 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -349,7 +349,7 @@ static int __init pxa25x_init(void)
reset_status = RCSR;
- clks_register(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
+ clkdev_add_table(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
if ((ret = pxa_init_dma(IRQ_DMA, 16)))
return ret;
@@ -370,7 +370,7 @@ static int __init pxa25x_init(void)
/* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
if (cpu_is_pxa255())
- clks_register(&pxa25x_hwuart_clkreg, 1);
+ clkdev_add(&pxa25x_hwuart_clkreg);
return ret;
}
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 6a0b73167e03..d783123e2d48 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -392,7 +392,7 @@ static int __init pxa27x_init(void)
reset_status = RCSR;
- clks_register(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
+ clkdev_add_table(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c
index f4af6e2bef89..40bb16501d86 100644
--- a/arch/arm/mach-pxa/pxa300.c
+++ b/arch/arm/mach-pxa/pxa300.c
@@ -102,12 +102,12 @@ static int __init pxa300_init(void)
if (cpu_is_pxa300() || cpu_is_pxa310()) {
mfp_init_base(io_p2v(MFPR_BASE));
mfp_init_addr(pxa300_mfp_addr_map);
- clks_register(ARRAY_AND_SIZE(common_clkregs));
+ clkdev_add_table(ARRAY_AND_SIZE(common_clkregs));
}
if (cpu_is_pxa310()) {
mfp_init_addr(pxa310_mfp_addr_map);
- clks_register(ARRAY_AND_SIZE(pxa310_clkregs));
+ clkdev_add_table(ARRAY_AND_SIZE(pxa310_clkregs));
}
return 0;
diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c
index c7373e74a109..8d614ecd8e99 100644
--- a/arch/arm/mach-pxa/pxa320.c
+++ b/arch/arm/mach-pxa/pxa320.c
@@ -90,7 +90,7 @@ static int __init pxa320_init(void)
if (cpu_is_pxa320()) {
mfp_init_base(io_p2v(MFPR_BASE));
mfp_init_addr(pxa320_mfp_addr_map);
- clks_register(ARRAY_AND_SIZE(pxa320_clkregs));
+ clkdev_add_table(ARRAY_AND_SIZE(pxa320_clkregs));
}
return 0;
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fcb0721f4669..4d7c03e72504 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -634,7 +634,7 @@ static int __init pxa3xx_init(void)
*/
ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
- clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
+ clkdev_add_table(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
new file mode 100644
index 000000000000..06717d7995cb
--- /dev/null
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -0,0 +1,1100 @@
+/*
+ * arch/arm/mach-pxa/raumfeld.c
+ *
+ * Support for the following Raumfeld devices:
+ *
+ * * Controller
+ * * Connector
+ * * Speaker S/M
+ *
+ * See http://www.raumfeld.com for details.
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.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/init.h>
+#include <linux/kernel.h>
+#include <linux/sysdev.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/smsc911x.h>
+#include <linux/input.h>
+#include <linux/rotary_encoder.h>
+#include <linux/gpio_keys.h>
+#include <linux/input/eeti_ts.h>
+#include <linux/leds.h>
+#include <linux/w1-gpio.h>
+#include <linux/sched.h>
+#include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/lis3lv02d.h>
+#include <linux/pda_power.h>
+#include <linux/power_supply.h>
+#include <linux/pda_power.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/max8660.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa3xx-regs.h>
+#include <mach/mfp-pxa3xx.h>
+#include <mach/mfp-pxa300.h>
+#include <mach/ohci.h>
+#include <mach/pxafb.h>
+#include <mach/mmc.h>
+#include <plat/i2c.h>
+#include <plat/pxa3xx_nand.h>
+
+#include "generic.h"
+#include "devices.h"
+#include "clock.h"
+
+/* common GPIO definitions */
+
+/* inputs */
+#define GPIO_ON_OFF (14)
+#define GPIO_VOLENC_A (19)
+#define GPIO_VOLENC_B (20)
+#define GPIO_CHARGE_DONE (23)
+#define GPIO_CHARGE_IND (27)
+#define GPIO_TOUCH_IRQ (32)
+#define GPIO_ETH_IRQ (40)
+#define GPIO_SPI_MISO (98)
+#define GPIO_ACCEL_IRQ (104)
+#define GPIO_RESCUE_BOOT (115)
+#define GPIO_DOCK_DETECT (116)
+#define GPIO_KEY1 (117)
+#define GPIO_KEY2 (118)
+#define GPIO_KEY3 (119)
+#define GPIO_CHARGE_USB_OK (112)
+#define GPIO_CHARGE_DC_OK (101)
+#define GPIO_CHARGE_USB_SUSP (102)
+
+/* outputs */
+#define GPIO_SHUTDOWN_SUPPLY (16)
+#define GPIO_SHUTDOWN_BATT (18)
+#define GPIO_CHRG_PEN2 (31)
+#define GPIO_TFT_VA_EN (33)
+#define GPIO_SPDIF_CS (34)
+#define GPIO_LED2 (35)
+#define GPIO_LED1 (36)
+#define GPIO_SPDIF_RESET (38)
+#define GPIO_SPI_CLK (95)
+#define GPIO_MCLK_DAC_CS (96)
+#define GPIO_SPI_MOSI (97)
+#define GPIO_W1_PULLUP_ENABLE (105)
+#define GPIO_DISPLAY_ENABLE (106)
+#define GPIO_MCLK_RESET (111)
+#define GPIO_W2W_RESET (113)
+#define GPIO_W2W_PDN (114)
+#define GPIO_CODEC_RESET (120)
+#define GPIO_AUDIO_VA_ENABLE (124)
+#define GPIO_ACCEL_CS (125)
+#define GPIO_ONE_WIRE (126)
+
+/*
+ * GPIO configurations
+ */
+static mfp_cfg_t raumfeld_controller_pin_config[] __initdata = {
+ /* UART1 */
+ GPIO77_UART1_RXD,
+ GPIO78_UART1_TXD,
+ GPIO79_UART1_CTS,
+ GPIO81_UART1_DSR,
+ GPIO83_UART1_DTR,
+ GPIO84_UART1_RTS,
+
+ /* UART3 */
+ GPIO110_UART3_RXD,
+
+ /* USB Host */
+ GPIO0_2_USBH_PEN,
+ GPIO1_2_USBH_PWR,
+
+ /* I2C */
+ GPIO21_I2C_SCL | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+ GPIO22_I2C_SDA | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+
+ /* SPI */
+ GPIO34_GPIO, /* SPDIF_CS */
+ GPIO96_GPIO, /* MCLK_CS */
+ GPIO125_GPIO, /* ACCEL_CS */
+
+ /* MMC */
+ GPIO3_MMC1_DAT0,
+ GPIO4_MMC1_DAT1,
+ GPIO5_MMC1_DAT2,
+ GPIO6_MMC1_DAT3,
+ GPIO7_MMC1_CLK,
+ GPIO8_MMC1_CMD,
+
+ /* One-wire */
+ GPIO126_GPIO | MFP_LPM_FLOAT,
+ GPIO105_GPIO | MFP_PULL_LOW | MFP_LPM_PULL_LOW,
+
+ /* CHRG_USB_OK */
+ GPIO101_GPIO | MFP_PULL_HIGH,
+ /* CHRG_USB_OK */
+ GPIO112_GPIO | MFP_PULL_HIGH,
+ /* CHRG_USB_SUSP */
+ GPIO102_GPIO,
+ /* DISPLAY_ENABLE */
+ GPIO106_GPIO,
+ /* DOCK_DETECT */
+ GPIO116_GPIO | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+
+ /* LCD */
+ GPIO54_LCD_LDD_0,
+ GPIO55_LCD_LDD_1,
+ GPIO56_LCD_LDD_2,
+ GPIO57_LCD_LDD_3,
+ GPIO58_LCD_LDD_4,
+ GPIO59_LCD_LDD_5,
+ GPIO60_LCD_LDD_6,
+ GPIO61_LCD_LDD_7,
+ GPIO62_LCD_LDD_8,
+ GPIO63_LCD_LDD_9,
+ GPIO64_LCD_LDD_10,
+ GPIO65_LCD_LDD_11,
+ GPIO66_LCD_LDD_12,
+ GPIO67_LCD_LDD_13,
+ GPIO68_LCD_LDD_14,
+ GPIO69_LCD_LDD_15,
+ GPIO70_LCD_LDD_16,
+ GPIO71_LCD_LDD_17,
+ GPIO72_LCD_FCLK,
+ GPIO73_LCD_LCLK,
+ GPIO74_LCD_PCLK,
+ GPIO75_LCD_BIAS,
+};
+
+static mfp_cfg_t raumfeld_connector_pin_config[] __initdata = {
+ /* UART1 */
+ GPIO77_UART1_RXD,
+ GPIO78_UART1_TXD,
+ GPIO79_UART1_CTS,
+ GPIO81_UART1_DSR,
+ GPIO83_UART1_DTR,
+ GPIO84_UART1_RTS,
+
+ /* UART3 */
+ GPIO110_UART3_RXD,
+
+ /* USB Host */
+ GPIO0_2_USBH_PEN,
+ GPIO1_2_USBH_PWR,
+
+ /* I2C */
+ GPIO21_I2C_SCL | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+ GPIO22_I2C_SDA | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+
+ /* SPI */
+ GPIO34_GPIO, /* SPDIF_CS */
+ GPIO96_GPIO, /* MCLK_CS */
+ GPIO125_GPIO, /* ACCEL_CS */
+
+ /* MMC */
+ GPIO3_MMC1_DAT0,
+ GPIO4_MMC1_DAT1,
+ GPIO5_MMC1_DAT2,
+ GPIO6_MMC1_DAT3,
+ GPIO7_MMC1_CLK,
+ GPIO8_MMC1_CMD,
+
+ /* Ethernet */
+ GPIO1_nCS2, /* CS */
+ GPIO40_GPIO | MFP_PULL_HIGH, /* IRQ */
+
+ /* SSP for I2S */
+ GPIO85_SSP1_SCLK,
+ GPIO89_SSP1_EXTCLK,
+ GPIO86_SSP1_FRM,
+ GPIO87_SSP1_TXD,
+ GPIO88_SSP1_RXD,
+ GPIO90_SSP1_SYSCLK,
+
+ /* SSP2 for S/PDIF */
+ GPIO25_SSP2_SCLK,
+ GPIO26_SSP2_FRM,
+ GPIO27_SSP2_TXD,
+ GPIO29_SSP2_EXTCLK,
+};
+
+static mfp_cfg_t raumfeld_speaker_pin_config[] __initdata = {
+ /* UART1 */
+ GPIO77_UART1_RXD,
+ GPIO78_UART1_TXD,
+ GPIO79_UART1_CTS,
+ GPIO81_UART1_DSR,
+ GPIO83_UART1_DTR,
+ GPIO84_UART1_RTS,
+
+ /* UART3 */
+ GPIO110_UART3_RXD,
+
+ /* USB Host */
+ GPIO0_2_USBH_PEN,
+ GPIO1_2_USBH_PWR,
+
+ /* I2C */
+ GPIO21_I2C_SCL | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+ GPIO22_I2C_SDA | MFP_LPM_FLOAT | MFP_PULL_FLOAT,
+
+ /* SPI */
+ GPIO34_GPIO, /* SPDIF_CS */
+ GPIO96_GPIO, /* MCLK_CS */
+ GPIO125_GPIO, /* ACCEL_CS */
+
+ /* MMC */
+ GPIO3_MMC1_DAT0,
+ GPIO4_MMC1_DAT1,
+ GPIO5_MMC1_DAT2,
+ GPIO6_MMC1_DAT3,
+ GPIO7_MMC1_CLK,
+ GPIO8_MMC1_CMD,
+
+ /* Ethernet */
+ GPIO1_nCS2, /* CS */
+ GPIO40_GPIO | MFP_PULL_HIGH, /* IRQ */
+
+ /* SSP for I2S */
+ GPIO85_SSP1_SCLK,
+ GPIO89_SSP1_EXTCLK,
+ GPIO86_SSP1_FRM,
+ GPIO87_SSP1_TXD,
+ GPIO88_SSP1_RXD,
+ GPIO90_SSP1_SYSCLK,
+};
+
+/*
+ * SMSC LAN9220 Ethernet
+ */
+
+static struct resource smc91x_resources[] = {
+ {
+ .start = PXA3xx_CS2_PHYS,
+ .end = PXA3xx_CS2_PHYS + 0xfffff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = gpio_to_irq(GPIO_ETH_IRQ),
+ .end = gpio_to_irq(GPIO_ETH_IRQ),
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING,
+ }
+};
+
+static struct smsc911x_platform_config raumfeld_smsc911x_config = {
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+ .dev = {
+ .platform_data = &raumfeld_smsc911x_config,
+ }
+};
+
+/**
+ * NAND
+ */
+
+static struct mtd_partition raumfeld_nand_partitions[] = {
+ {
+ .name = "Bootloader",
+ .offset = 0,
+ .size = 0xa0000,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "BootloaderEnvironment",
+ .offset = 0xa0000,
+ .size = 0x20000,
+ },
+ {
+ .name = "BootloaderSplashScreen",
+ .offset = 0xc0000,
+ .size = 0x60000,
+ },
+ {
+ .name = "UBI",
+ .offset = 0x120000,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct pxa3xx_nand_platform_data raumfeld_nand_info = {
+ .enable_arbiter = 1,
+ .keep_config = 1,
+ .parts = raumfeld_nand_partitions,
+ .nr_parts = ARRAY_SIZE(raumfeld_nand_partitions),
+};
+
+/**
+ * USB (OHCI) support
+ */
+
+static struct pxaohci_platform_data raumfeld_ohci_info = {
+ .port_mode = PMM_GLOBAL_MODE,
+ .flags = ENABLE_PORT1,
+};
+
+/**
+ * Rotary encoder input device
+ */
+
+static struct rotary_encoder_platform_data raumfeld_rotary_encoder_info = {
+ .steps = 24,
+ .axis = REL_X,
+ .relative_axis = 1,
+ .gpio_a = GPIO_VOLENC_A,
+ .gpio_b = GPIO_VOLENC_B,
+ .inverted_a = 1,
+ .inverted_b = 0,
+};
+
+static struct platform_device rotary_encoder_device = {
+ .name = "rotary-encoder",
+ .id = 0,
+ .dev = {
+ .platform_data = &raumfeld_rotary_encoder_info,
+ }
+};
+
+/**
+ * GPIO buttons
+ */
+
+static struct gpio_keys_button gpio_keys_button[] = {
+ {
+ .code = KEY_F1,
+ .type = EV_KEY,
+ .gpio = GPIO_KEY1,
+ .active_low = 1,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "Button 1",
+ },
+ {
+ .code = KEY_F2,
+ .type = EV_KEY,
+ .gpio = GPIO_KEY2,
+ .active_low = 1,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "Button 2",
+ },
+ {
+ .code = KEY_F3,
+ .type = EV_KEY,
+ .gpio = GPIO_KEY3,
+ .active_low = 1,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "Button 3",
+ },
+ {
+ .code = KEY_F4,
+ .type = EV_KEY,
+ .gpio = GPIO_RESCUE_BOOT,
+ .active_low = 0,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "rescue boot button",
+ },
+ {
+ .code = KEY_F5,
+ .type = EV_KEY,
+ .gpio = GPIO_DOCK_DETECT,
+ .active_low = 1,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "dock detect",
+ },
+ {
+ .code = KEY_F6,
+ .type = EV_KEY,
+ .gpio = GPIO_ON_OFF,
+ .active_low = 0,
+ .wakeup = 0,
+ .debounce_interval = 5, /* ms */
+ .desc = "on/off button",
+ },
+};
+
+static struct gpio_keys_platform_data gpio_keys_platform_data = {
+ .buttons = gpio_keys_button,
+ .nbuttons = ARRAY_SIZE(gpio_keys_button),
+ .rep = 0,
+};
+
+static struct platform_device raumfeld_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_keys_platform_data,
+ }
+};
+
+/**
+ * GPIO LEDs
+ */
+
+static struct gpio_led raumfeld_leds[] = {
+ {
+ .name = "raumfeld:1",
+ .gpio = GPIO_LED1,
+ .active_low = 1,
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ },
+ {
+ .name = "raumfeld:2",
+ .gpio = GPIO_LED2,
+ .active_low = 0,
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ }
+};
+
+static struct gpio_led_platform_data raumfeld_led_platform_data = {
+ .leds = raumfeld_leds,
+ .num_leds = ARRAY_SIZE(raumfeld_leds),
+};
+
+static struct platform_device raumfeld_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &raumfeld_led_platform_data,
+ },
+};
+
+/**
+ * One-wire (W1 bus) support
+ */
+
+static void w1_enable_external_pullup(int enable)
+{
+ gpio_set_value(GPIO_W1_PULLUP_ENABLE, enable);
+ msleep(100);
+}
+
+static struct w1_gpio_platform_data w1_gpio_platform_data = {
+ .pin = GPIO_ONE_WIRE,
+ .is_open_drain = 0,
+ .enable_external_pullup = w1_enable_external_pullup,
+};
+
+struct platform_device raumfeld_w1_gpio_device = {
+ .name = "w1-gpio",
+ .dev = {
+ .platform_data = &w1_gpio_platform_data
+ }
+};
+
+static void __init raumfeld_w1_init(void)
+{
+ int ret = gpio_request(GPIO_W1_PULLUP_ENABLE,
+ "W1 external pullup enable");
+
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n");
+ else
+ gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0);
+
+ platform_device_register(&raumfeld_w1_gpio_device);
+}
+
+/**
+ * Framebuffer device
+ */
+
+/* PWM controlled backlight */
+static struct platform_pwm_backlight_data raumfeld_pwm_backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 100,
+ .dft_brightness = 100,
+ /* 10000 ns = 10 ms ^= 100 kHz */
+ .pwm_period_ns = 10000,
+};
+
+static struct platform_device raumfeld_pwm_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .parent = &pxa27x_device_pwm0.dev,
+ .platform_data = &raumfeld_pwm_backlight_data,
+ }
+};
+
+/* LT3593 controlled backlight */
+static struct gpio_led raumfeld_lt3593_led = {
+ .name = "backlight",
+ .gpio = mfp_to_gpio(MFP_PIN_GPIO17),
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+};
+
+static struct gpio_led_platform_data raumfeld_lt3593_platform_data = {
+ .leds = &raumfeld_lt3593_led,
+ .num_leds = 1,
+};
+
+static struct platform_device raumfeld_lt3593_device = {
+ .name = "leds-lt3593",
+ .id = -1,
+ .dev = {
+ .platform_data = &raumfeld_lt3593_platform_data,
+ },
+};
+
+static struct pxafb_mode_info sharp_lq043t3dx02_mode = {
+ .pixclock = 111000,
+ .xres = 480,
+ .yres = 272,
+ .bpp = 16,
+ .hsync_len = 4,
+ .left_margin = 2,
+ .right_margin = 1,
+ .vsync_len = 1,
+ .upper_margin = 3,
+ .lower_margin = 1,
+ .sync = 0,
+};
+
+static struct pxafb_mach_info raumfeld_sharp_lcd_info = {
+ .modes = &sharp_lq043t3dx02_mode,
+ .num_modes = 1,
+ .video_mem_size = 0x400000,
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
+};
+
+static void __init raumfeld_lcd_init(void)
+{
+ int ret;
+
+ set_pxa_fb_info(&raumfeld_sharp_lcd_info);
+
+ /* Earlier devices had the backlight regulator controlled
+ * via PWM, later versions use another controller for that */
+ if ((system_rev & 0xff) < 2) {
+ mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT;
+ pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1);
+ platform_device_register(&raumfeld_pwm_backlight_device);
+ } else
+ platform_device_register(&raumfeld_lt3593_device);
+
+ ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_TFT_VA_EN\n");
+ else
+ gpio_direction_output(GPIO_TFT_VA_EN, 1);
+
+ ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n");
+ else
+ gpio_direction_output(GPIO_DISPLAY_ENABLE, 1);
+}
+
+/**
+ * SPI devices
+ */
+
+struct spi_gpio_platform_data raumfeld_spi_platform_data = {
+ .sck = GPIO_SPI_CLK,
+ .mosi = GPIO_SPI_MOSI,
+ .miso = GPIO_SPI_MISO,
+ .num_chipselect = 3,
+};
+
+static struct platform_device raumfeld_spi_device = {
+ .name = "spi_gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &raumfeld_spi_platform_data,
+ }
+};
+
+static struct lis3lv02d_platform_data lis3_pdata = {
+ .click_flags = LIS3_CLICK_SINGLE_X |
+ LIS3_CLICK_SINGLE_Y |
+ LIS3_CLICK_SINGLE_Z,
+ .irq_cfg = LIS3_IRQ1_CLICK | LIS3_IRQ2_CLICK,
+ .wakeup_flags = LIS3_WAKEUP_X_LO | LIS3_WAKEUP_X_HI |
+ LIS3_WAKEUP_Y_LO | LIS3_WAKEUP_Y_HI |
+ LIS3_WAKEUP_Z_LO | LIS3_WAKEUP_Z_HI,
+ .wakeup_thresh = 10,
+ .click_thresh_x = 10,
+ .click_thresh_y = 10,
+ .click_thresh_z = 10,
+};
+
+#define SPI_AK4104 \
+{ \
+ .modalias = "ak4104", \
+ .max_speed_hz = 10000, \
+ .bus_num = 0, \
+ .chip_select = 0, \
+ .controller_data = (void *) GPIO_SPDIF_CS, \
+}
+
+#define SPI_LIS3 \
+{ \
+ .modalias = "lis3lv02d_spi", \
+ .max_speed_hz = 1000000, \
+ .bus_num = 0, \
+ .chip_select = 1, \
+ .controller_data = (void *) GPIO_ACCEL_CS, \
+ .platform_data = &lis3_pdata, \
+ .irq = gpio_to_irq(GPIO_ACCEL_IRQ), \
+}
+
+#define SPI_DAC7512 \
+{ \
+ .modalias = "dac7512", \
+ .max_speed_hz = 1000000, \
+ .bus_num = 0, \
+ .chip_select = 2, \
+ .controller_data = (void *) GPIO_MCLK_DAC_CS, \
+}
+
+static struct spi_board_info connector_spi_devices[] __initdata = {
+ SPI_AK4104,
+ SPI_DAC7512,
+};
+
+static struct spi_board_info speaker_spi_devices[] __initdata = {
+ SPI_DAC7512,
+};
+
+static struct spi_board_info controller_spi_devices[] __initdata = {
+ SPI_LIS3,
+};
+
+/**
+ * MMC for Marvell Libertas 8688 via SDIO
+ */
+
+static int raumfeld_mci_init(struct device *dev, irq_handler_t isr, void *data)
+{
+ gpio_set_value(GPIO_W2W_RESET, 1);
+ gpio_set_value(GPIO_W2W_PDN, 1);
+
+ return 0;
+}
+
+static void raumfeld_mci_exit(struct device *dev, void *data)
+{
+ gpio_set_value(GPIO_W2W_RESET, 0);
+ gpio_set_value(GPIO_W2W_PDN, 0);
+}
+
+static struct pxamci_platform_data raumfeld_mci_platform_data = {
+ .init = raumfeld_mci_init,
+ .exit = raumfeld_mci_exit,
+ .detect_delay = 20,
+ .gpio_card_detect = -1,
+ .gpio_card_ro = -1,
+ .gpio_power = -1,
+};
+
+/*
+ * External power / charge logic
+ */
+
+static int power_supply_init(struct device *dev)
+{
+ return 0;
+}
+
+static void power_supply_exit(struct device *dev)
+{
+}
+
+static int raumfeld_is_ac_online(void)
+{
+ return !gpio_get_value(GPIO_CHARGE_DC_OK);
+}
+
+static int raumfeld_is_usb_online(void)
+{
+ return 0;
+}
+
+static char *raumfeld_power_supplicants[] = { "ds2760-battery.0" };
+
+static struct pda_power_pdata power_supply_info = {
+ .init = power_supply_init,
+ .is_ac_online = raumfeld_is_ac_online,
+ .is_usb_online = raumfeld_is_usb_online,
+ .exit = power_supply_exit,
+ .supplied_to = raumfeld_power_supplicants,
+ .num_supplicants = ARRAY_SIZE(raumfeld_power_supplicants)
+};
+
+static struct resource power_supply_resources[] = {
+ {
+ .name = "ac",
+ .flags = IORESOURCE_IRQ |
+ IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+ .start = GPIO_CHARGE_DC_OK,
+ .end = GPIO_CHARGE_DC_OK,
+ },
+};
+
+static irqreturn_t charge_done_irq(int irq, void *dev_id)
+{
+ struct power_supply *psy;
+
+ psy = power_supply_get_by_name("ds2760-battery.0");
+
+ if (psy)
+ power_supply_set_battery_charged(psy);
+
+ return IRQ_HANDLED;
+}
+
+static struct platform_device raumfeld_power_supply = {
+ .name = "pda-power",
+ .id = -1,
+ .dev = {
+ .platform_data = &power_supply_info,
+ },
+ .resource = power_supply_resources,
+ .num_resources = ARRAY_SIZE(power_supply_resources),
+};
+
+static void __init raumfeld_power_init(void)
+{
+ int ret;
+
+ /* Set PEN2 high to enable maximum charge current */
+ ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_CHRG_PEN2\n");
+ else
+ gpio_direction_output(GPIO_CHRG_PEN2, 1);
+
+ ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_CHARGE_DC_OK\n");
+
+ ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n");
+ else
+ gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0);
+
+ power_supply_resources[0].start = gpio_to_irq(GPIO_CHARGE_DC_OK);
+ power_supply_resources[0].end = gpio_to_irq(GPIO_CHARGE_DC_OK);
+
+ ret = request_irq(gpio_to_irq(GPIO_CHARGE_DONE),
+ &charge_done_irq, IORESOURCE_IRQ_LOWEDGE,
+ "charge_done", NULL);
+
+ if (ret < 0)
+ printk(KERN_ERR "%s: unable to register irq %d\n", __func__,
+ GPIO_CHARGE_DONE);
+ else
+ platform_device_register(&raumfeld_power_supply);
+}
+
+/* Fixed regulator for AUDIO_VA, 0-0048 maps to the cs4270 codec device */
+
+static struct regulator_consumer_supply audio_va_consumer_supply =
+ REGULATOR_SUPPLY("va", "0-0048");
+
+struct regulator_init_data audio_va_initdata = {
+ .consumer_supplies = &audio_va_consumer_supply,
+ .num_consumer_supplies = 1,
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct fixed_voltage_config audio_va_config = {
+ .supply_name = "audio_va",
+ .microvolts = 5000000,
+ .gpio = GPIO_AUDIO_VA_ENABLE,
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &audio_va_initdata,
+};
+
+static struct platform_device audio_va_device = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &audio_va_config,
+ },
+};
+
+/* Dummy supplies for Codec's VD/VLC */
+
+static struct regulator_consumer_supply audio_dummy_supplies[] = {
+ REGULATOR_SUPPLY("vd", "0-0048"),
+ REGULATOR_SUPPLY("vlc", "0-0048"),
+};
+
+struct regulator_init_data audio_dummy_initdata = {
+ .consumer_supplies = audio_dummy_supplies,
+ .num_consumer_supplies = ARRAY_SIZE(audio_dummy_supplies),
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct fixed_voltage_config audio_dummy_config = {
+ .supply_name = "audio_vd",
+ .microvolts = 3300000,
+ .gpio = -1,
+ .init_data = &audio_dummy_initdata,
+};
+
+static struct platform_device audio_supply_dummy_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &audio_dummy_config,
+ },
+};
+
+static struct platform_device *audio_regulator_devices[] = {
+ &audio_va_device,
+ &audio_supply_dummy_device,
+};
+
+/**
+ * Regulator support via MAX8660
+ */
+
+static struct regulator_consumer_supply vcc_mmc_supply =
+ REGULATOR_SUPPLY("vmmc", "pxa2xx-mci.0");
+
+static struct regulator_init_data vcc_mmc_init_data = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE,
+ },
+ .consumer_supplies = &vcc_mmc_supply,
+ .num_consumer_supplies = 1,
+};
+
+struct max8660_subdev_data max8660_v6_subdev_data = {
+ .id = MAX8660_V6,
+ .name = "vmmc",
+ .platform_data = &vcc_mmc_init_data,
+};
+
+static struct max8660_platform_data max8660_pdata = {
+ .subdevs = &max8660_v6_subdev_data,
+ .num_subdevs = 1,
+};
+
+/**
+ * I2C devices
+ */
+
+static struct i2c_board_info raumfeld_pwri2c_board_info = {
+ .type = "max8660",
+ .addr = 0x34,
+ .platform_data = &max8660_pdata,
+};
+
+static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = {
+ .type = "cs4270",
+ .addr = 0x48,
+};
+
+static struct eeti_ts_platform_data eeti_ts_pdata = {
+ .irq_active_high = 1,
+};
+
+static struct i2c_board_info raumfeld_controller_i2c_board_info __initdata = {
+ .type = "eeti_ts",
+ .addr = 0x0a,
+ .irq = gpio_to_irq(GPIO_TOUCH_IRQ),
+ .platform_data = &eeti_ts_pdata,
+};
+
+static struct platform_device *raumfeld_common_devices[] = {
+ &raumfeld_gpio_keys_device,
+ &raumfeld_led_device,
+ &raumfeld_spi_device,
+};
+
+static void __init raumfeld_audio_init(void)
+{
+ int ret;
+
+ ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset");
+ if (ret < 0)
+ pr_warning("unable to request GPIO_CODEC_RESET\n");
+ else
+ gpio_direction_output(GPIO_CODEC_RESET, 1);
+
+ ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset");
+ if (ret < 0)
+ pr_warning("unable to request GPIO_SPDIF_RESET\n");
+ else
+ gpio_direction_output(GPIO_SPDIF_RESET, 1);
+
+ ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset");
+ if (ret < 0)
+ pr_warning("unable to request GPIO_MCLK_RESET\n");
+ else
+ gpio_direction_output(GPIO_MCLK_RESET, 1);
+
+ platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices));
+}
+
+static void __init raumfeld_common_init(void)
+{
+ int ret;
+
+ /* The on/off button polarity has changed after revision 1 */
+ if ((system_rev & 0xff) > 1) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_keys_button); i++)
+ if (!strcmp(gpio_keys_button[i].desc, "on/off button"))
+ gpio_keys_button[i].active_low = 1;
+ }
+
+ enable_irq_wake(IRQ_WAKEUP0);
+
+ pxa3xx_set_nand_info(&raumfeld_nand_info);
+ pxa3xx_set_i2c_power_info(NULL);
+ pxa_set_ohci_info(&raumfeld_ohci_info);
+ pxa_set_mci_info(&raumfeld_mci_platform_data);
+ pxa_set_i2c_info(NULL);
+ pxa_set_ffuart_info(NULL);
+
+ ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_W2W_RESET\n");
+ else
+ gpio_direction_output(GPIO_W2W_RESET, 0);
+
+ ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_W2W_PDN\n");
+ else
+ gpio_direction_output(GPIO_W2W_PDN, 0);
+
+ /* this can be used to switch off the device */
+ ret = gpio_request(GPIO_SHUTDOWN_SUPPLY,
+ "supply shutdown");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n");
+ else
+ gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
+
+ platform_add_devices(ARRAY_AND_SIZE(raumfeld_common_devices));
+ i2c_register_board_info(1, &raumfeld_pwri2c_board_info, 1);
+}
+
+static void __init raumfeld_controller_init(void)
+{
+ int ret;
+
+ pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_controller_pin_config));
+ platform_device_register(&rotary_encoder_device);
+ spi_register_board_info(ARRAY_AND_SIZE(controller_spi_devices));
+ i2c_register_board_info(0, &raumfeld_controller_i2c_board_info, 1);
+
+ ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown");
+ if (ret < 0)
+ pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n");
+ else
+ gpio_direction_output(GPIO_SHUTDOWN_BATT, 0);
+
+ raumfeld_common_init();
+ raumfeld_power_init();
+ raumfeld_lcd_init();
+ raumfeld_w1_init();
+}
+
+static void __init raumfeld_connector_init(void)
+{
+ pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_connector_pin_config));
+ spi_register_board_info(ARRAY_AND_SIZE(connector_spi_devices));
+ i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+ platform_device_register(&smc91x_device);
+
+ raumfeld_audio_init();
+ raumfeld_common_init();
+}
+
+static void __init raumfeld_speaker_init(void)
+{
+ pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_speaker_pin_config));
+ spi_register_board_info(ARRAY_AND_SIZE(speaker_spi_devices));
+ i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
+
+ platform_device_register(&smc91x_device);
+ platform_device_register(&rotary_encoder_device);
+
+ raumfeld_audio_init();
+ raumfeld_common_init();
+}
+
+/* physical memory regions */
+#define RAUMFELD_SDRAM_BASE 0xa0000000 /* SDRAM region */
+
+#ifdef CONFIG_MACH_RAUMFELD_RC
+MACHINE_START(RAUMFELD_RC, "Raumfeld Controller")
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .boot_params = RAUMFELD_SDRAM_BASE + 0x100,
+ .init_machine = raumfeld_controller_init,
+ .map_io = pxa_map_io,
+ .init_irq = pxa3xx_init_irq,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_RAUMFELD_CONNECTOR
+MACHINE_START(RAUMFELD_CONNECTOR, "Raumfeld Connector")
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .boot_params = RAUMFELD_SDRAM_BASE + 0x100,
+ .init_machine = raumfeld_connector_init,
+ .map_io = pxa_map_io,
+ .init_irq = pxa3xx_init_irq,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_RAUMFELD_SPEAKER
+MACHINE_START(RAUMFELD_SPEAKER, "Raumfeld Speaker")
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .boot_params = RAUMFELD_SDRAM_BASE + 0x100,
+ .init_machine = raumfeld_speaker_init,
+ .map_io = pxa_map_io,
+ .init_irq = pxa3xx_init_irq,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 4b50f144fa48..28352c0b8c34 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -389,13 +389,13 @@ static struct gpio_keys_button spitz_gpio_keys[] = {
.type = EV_SW,
.code = 0,
.gpio = SPITZ_GPIO_SWA,
- .desc = "Display Down",
+ .desc = "Display Down",
},
{
.type = EV_SW,
.code = 1,
.gpio = SPITZ_GPIO_SWB,
- .desc = "Lid Closed",
+ .desc = "Lid Closed",
},
};
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 5352b4e5a7dd..89f258c9e126 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -379,7 +379,7 @@ err_request_bckl:
return ret;
}
-static int viper_backlight_notify(int brightness)
+static int viper_backlight_notify(struct device *dev, int brightness)
{
gpio_set_value(VIPER_LCD_EN_GPIO, !!brightness);
gpio_set_value(VIPER_BCKLIGHT_EN_GPIO, !!brightness);
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index 5b986a8bd9e6..75f2a37f945d 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -25,6 +25,7 @@
#include <linux/mtd/physmap.h>
#include <linux/i2c.h>
#include <linux/i2c/pca953x.h>
+#include <linux/apm-emulation.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -626,8 +627,27 @@ static void zeus_power_off(void)
pxa27x_cpu_suspend(PWRMODE_DEEPSLEEP);
}
-int zeus_get_pcb_info(struct i2c_client *client, unsigned gpio,
- unsigned ngpio, void *context)
+#ifdef CONFIG_APM_EMULATION
+static void zeus_get_power_status(struct apm_power_info *info)
+{
+ /* Power supply is always present */
+ info->ac_line_status = APM_AC_ONLINE;
+ info->battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
+ info->battery_flag = APM_BATTERY_FLAG_NOT_PRESENT;
+}
+
+static inline void zeus_setup_apm(void)
+{
+ apm_get_power_status = zeus_get_power_status;
+}
+#else
+static inline void zeus_setup_apm(void)
+{
+}
+#endif
+
+static int zeus_get_pcb_info(struct i2c_client *client, unsigned gpio,
+ unsigned ngpio, void *context)
{
int i;
u8 pcb_info = 0;
@@ -726,9 +746,18 @@ static mfp_cfg_t zeus_pin_config[] __initdata = {
GPIO99_GPIO, /* CF RDY */
};
+/*
+ * DM9k MSCx settings: SRAM, 16 bits
+ * 17 cycles delay first access
+ * 5 cycles delay next access
+ * 13 cycles recovery time
+ * faster device
+ */
+#define DM9K_MSC_VALUE 0xe4c9
+
static void __init zeus_init(void)
{
- u16 dm9000_msc = 0xe279;
+ u16 dm9000_msc = DM9K_MSC_VALUE;
system_rev = __raw_readw(ZEUS_CPLD_VERSION);
pr_info("Zeus CPLD V%dI%d\n", (system_rev & 0xf0) >> 4, (system_rev & 0x0f));
@@ -738,6 +767,7 @@ static void __init zeus_init(void)
MSC1 = (MSC1 & 0xffff0000) | dm9000_msc;
pm_power_off = zeus_power_off;
+ zeus_setup_apm();
pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config));
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index b66e9e2d06e7..2b4043c04d0c 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -36,9 +36,6 @@
#include "devices.h"
#include "generic.h"
-#define MAX_SLOTS 3
-struct platform_mmc_slot zylonite_mmc_slot[MAX_SLOTS];
-
int gpio_eth_irq;
int gpio_debug_led1;
int gpio_debug_led2;
@@ -220,84 +217,28 @@ static inline void zylonite_init_lcd(void) {}
#endif
#if defined(CONFIG_MMC)
-static int zylonite_mci_ro(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- return gpio_get_value(zylonite_mmc_slot[pdev->id].gpio_wp);
-}
-
-static int zylonite_mci_init(struct device *dev,
- irq_handler_t zylonite_detect_int,
- void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int err, cd_irq, gpio_cd, gpio_wp;
-
- cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd);
- gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd;
- gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp;
-
- /*
- * setup GPIO for Zylonite MMC controller
- */
- err = gpio_request(gpio_cd, "mmc card detect");
- if (err)
- goto err_request_cd;
- gpio_direction_input(gpio_cd);
-
- err = gpio_request(gpio_wp, "mmc write protect");
- if (err)
- goto err_request_wp;
- gpio_direction_input(gpio_wp);
-
- err = request_irq(cd_irq, zylonite_detect_int,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "MMC card detect", data);
- if (err) {
- printk(KERN_ERR "%s: MMC/SD/SDIO: "
- "can't request card detect IRQ\n", __func__);
- goto err_request_irq;
- }
-
- return 0;
-
-err_request_irq:
- gpio_free(gpio_wp);
-err_request_wp:
- gpio_free(gpio_cd);
-err_request_cd:
- return err;
-}
-
-static void zylonite_mci_exit(struct device *dev, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int cd_irq, gpio_cd, gpio_wp;
-
- cd_irq = gpio_to_irq(zylonite_mmc_slot[pdev->id].gpio_cd);
- gpio_cd = zylonite_mmc_slot[pdev->id].gpio_cd;
- gpio_wp = zylonite_mmc_slot[pdev->id].gpio_wp;
-
- free_irq(cd_irq, data);
- gpio_free(gpio_cd);
- gpio_free(gpio_wp);
-}
-
static struct pxamci_platform_data zylonite_mci_platform_data = {
.detect_delay = 20,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = zylonite_mci_init,
- .exit = zylonite_mci_exit,
- .get_ro = zylonite_mci_ro,
- .gpio_card_detect = -1,
- .gpio_card_ro = -1,
+ .gpio_card_detect = EXT_GPIO(0),
+ .gpio_card_ro = EXT_GPIO(2),
.gpio_power = -1,
};
static struct pxamci_platform_data zylonite_mci2_platform_data = {
.detect_delay = 20,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = EXT_GPIO(1),
+ .gpio_card_ro = EXT_GPIO(3),
+ .gpio_power = -1,
+};
+
+static struct pxamci_platform_data zylonite_mci3_platform_data = {
+ .detect_delay = 20,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .gpio_card_detect = EXT_GPIO(30),
+ .gpio_card_ro = EXT_GPIO(31),
+ .gpio_power = -1,
};
static void __init zylonite_init_mmc(void)
@@ -305,7 +246,7 @@ static void __init zylonite_init_mmc(void)
pxa_set_mci_info(&zylonite_mci_platform_data);
pxa3xx_set_mci2_info(&zylonite_mci2_platform_data);
if (cpu_is_pxa310())
- pxa3xx_set_mci3_info(&zylonite_mci_platform_data);
+ pxa3xx_set_mci3_info(&zylonite_mci3_platform_data);
}
#else
static inline void zylonite_init_mmc(void) {}
diff --git a/arch/arm/mach-pxa/zylonite_pxa300.c b/arch/arm/mach-pxa/zylonite_pxa300.c
index 84095440a878..3aa73b3e33f2 100644
--- a/arch/arm/mach-pxa/zylonite_pxa300.c
+++ b/arch/arm/mach-pxa/zylonite_pxa300.c
@@ -129,8 +129,8 @@ static mfp_cfg_t common_mfp_cfg[] __initdata = {
GPIO22_I2C_SDA,
/* GPIO */
- GPIO18_GPIO, /* GPIO Expander #0 INT_N */
- GPIO19_GPIO, /* GPIO Expander #1 INT_N */
+ GPIO18_GPIO | MFP_PULL_HIGH, /* GPIO Expander #0 INT_N */
+ GPIO19_GPIO | MFP_PULL_HIGH, /* GPIO Expander #1 INT_N */
};
static mfp_cfg_t pxa300_mfp_cfg[] __initdata = {
@@ -258,10 +258,6 @@ void __init zylonite_pxa300_init(void)
/* detect LCD panel */
zylonite_detect_lcd_panel();
- /* MMC card detect & write protect for controller 0 */
- zylonite_mmc_slot[0].gpio_cd = EXT_GPIO(0);
- zylonite_mmc_slot[0].gpio_wp = EXT_GPIO(2);
-
/* WM9713 IRQ */
wm9713_irq = mfp_to_gpio(MFP_PIN_GPIO26);
@@ -276,10 +272,6 @@ void __init zylonite_pxa300_init(void)
if (cpu_is_pxa310()) {
pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa310_mfp_cfg));
gpio_eth_irq = mfp_to_gpio(MFP_PIN_GPIO102);
-
- /* MMC card detect & write protect for controller 2 */
- zylonite_mmc_slot[2].gpio_cd = EXT_GPIO(30);
- zylonite_mmc_slot[2].gpio_wp = EXT_GPIO(31);
}
/* GPIOs for Debug LEDs */
diff --git a/arch/arm/mach-pxa/zylonite_pxa320.c b/arch/arm/mach-pxa/zylonite_pxa320.c
index 60d08f23f5e4..9942bac4cf7d 100644
--- a/arch/arm/mach-pxa/zylonite_pxa320.c
+++ b/arch/arm/mach-pxa/zylonite_pxa320.c
@@ -209,10 +209,6 @@ void __init zylonite_pxa320_init(void)
gpio_debug_led1 = mfp_to_gpio(MFP_PIN_GPIO1_2);
gpio_debug_led2 = mfp_to_gpio(MFP_PIN_GPIO4_2);
- /* MMC card detect & write protect for controller 0 */
- zylonite_mmc_slot[0].gpio_cd = mfp_to_gpio(MFP_PIN_GPIO1);
- zylonite_mmc_slot[0].gpio_wp = mfp_to_gpio(MFP_PIN_GPIO5);
-
/* WM9713 IRQ */
wm9713_irq = mfp_to_gpio(MFP_PIN_GPIO15);
}
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 9f293438e020..90bd4ef71b2c 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -346,10 +346,7 @@ static struct clk_lookup lookups[] = {
static int __init clk_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return 0;
}
arch_initcall(clk_init);
diff --git a/arch/arm/mach-realview/include/mach/board-pb1176.h b/arch/arm/mach-realview/include/mach/board-pb1176.h
index 34b80b7d40b8..2f5ccb298858 100644
--- a/arch/arm/mach-realview/include/mach/board-pb1176.h
+++ b/arch/arm/mach-realview/include/mach/board-pb1176.h
@@ -74,8 +74,8 @@
#define REALVIEW_PB1176_L220_BASE 0x10110000 /* L220 registers */
/*
- * Control register SYS_RESETCTL is set to 1 to force a soft reset
+ * Control register SYS_RESETCTL Bit 8 is set to 1 to force a soft reset
*/
-#define REALVIEW_PB1176_SYS_LOCKVAL_RSTCTL 0x0100
+#define REALVIEW_PB1176_SYS_SOFT_RESET 0x0100
#endif /* __ASM_ARCH_BOARD_PB1176_H */
diff --git a/arch/arm/mach-realview/include/mach/platform.h b/arch/arm/mach-realview/include/mach/platform.h
index 4f46bf71e752..86c0c4435a46 100644
--- a/arch/arm/mach-realview/include/mach/platform.h
+++ b/arch/arm/mach-realview/include/mach/platform.h
@@ -140,7 +140,7 @@
* SYS_CLD, SYS_BOOTCS
*/
#define REALVIEW_SYS_LOCK_LOCKED (1 << 16)
-#define REALVIEW_SYS_LOCKVAL_MASK 0xA05F /* Enable write access */
+#define REALVIEW_SYS_LOCK_VAL 0xA05F /* Enable write access */
/*
* REALVIEW_SYS_FLASH
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 917f8ca3abff..7d857d300558 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -381,6 +381,20 @@ static struct sys_timer realview_eb_timer = {
.init = realview_eb_timer_init,
};
+static void realview_eb_reset(char mode)
+{
+ void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
+ void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
+
+ /*
+ * To reset, we hit the on-board reset register
+ * in the system FPGA
+ */
+ __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
+ if (core_tile_eb11mp())
+ __raw_writel(0x0008, reset_ctrl);
+}
+
static void __init realview_eb_init(void)
{
int i;
@@ -408,6 +422,7 @@ static void __init realview_eb_init(void)
#ifdef CONFIG_LEDS
leds_event = realview_leds_event;
#endif
+ realview_reset = realview_eb_reset;
}
MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index 7fb726d5f8b9..44392e51dd50 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -292,12 +292,10 @@ static struct sys_timer realview_pb1176_timer = {
static void realview_pb1176_reset(char mode)
{
- void __iomem *hdr_ctrl = __io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_RESETCTL_OFFSET;
- void __iomem *rst_hdr_ctrl = __io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_LOCK_OFFSET;
- __raw_writel(REALVIEW_SYS_LOCKVAL_MASK, rst_hdr_ctrl);
- __raw_writel(REALVIEW_PB1176_SYS_LOCKVAL_RSTCTL, hdr_ctrl);
+ void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
+ void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
+ __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
+ __raw_writel(REALVIEW_PB1176_SYS_SOFT_RESET, reset_ctrl);
}
static void realview_pb1176_fixup(struct machine_desc *mdesc,
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index 9bbbfc05f225..3e02731af959 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -301,17 +301,16 @@ static struct sys_timer realview_pb11mp_timer = {
static void realview_pb11mp_reset(char mode)
{
- void __iomem *hdr_ctrl = __io_address(REALVIEW_SYS_BASE) +
- REALVIEW_SYS_RESETCTL_OFFSET;
- unsigned int val;
+ void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
+ void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
/*
* To reset, we hit the on-board reset register
* in the system FPGA
*/
- val = __raw_readl(hdr_ctrl);
- val |= REALVIEW_PB11MP_SYS_CTRL_RESET_CONFIGCLR;
- __raw_writel(val, hdr_ctrl);
+ __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
+ __raw_writel(0x0000, reset_ctrl);
+ __raw_writel(0x0004, reset_ctrl);
}
static void __init realview_pb11mp_init(void)
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index fe861e96c566..fe4e25c4201a 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -272,6 +272,20 @@ static struct sys_timer realview_pba8_timer = {
.init = realview_pba8_timer_init,
};
+static void realview_pba8_reset(char mode)
+{
+ void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
+ void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
+
+ /*
+ * To reset, we hit the on-board reset register
+ * in the system FPGA
+ */
+ __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
+ __raw_writel(0x0000, reset_ctrl);
+ __raw_writel(0x0004, reset_ctrl);
+}
+
static void __init realview_pba8_init(void)
{
int i;
@@ -291,6 +305,7 @@ static void __init realview_pba8_init(void)
#ifdef CONFIG_LEDS
leds_event = realview_leds_event;
#endif
+ realview_reset = realview_pba8_reset;
}
MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index ec39488e2b42..a21a4b395f73 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -324,6 +324,20 @@ static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
#endif
}
+static void realview_pbx_reset(char mode)
+{
+ void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
+ void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
+
+ /*
+ * To reset, we hit the on-board reset register
+ * in the system FPGA
+ */
+ __raw_writel(REALVIEW_SYS_LOCK_VAL, lock_ctrl);
+ __raw_writel(0x0000, reset_ctrl);
+ __raw_writel(0x0004, reset_ctrl);
+}
+
static void __init realview_pbx_init(void)
{
int i;
@@ -358,6 +372,7 @@ static void __init realview_pbx_init(void)
#ifdef CONFIG_LEDS
leds_event = realview_leds_event;
#endif
+ realview_reset = realview_pbx_reset;
}
MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
diff --git a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
index 980a099e209c..dcef2287cb38 100644
--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
@@ -3,7 +3,7 @@
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C2410 - SPI Controller platfrom_device info
+ * S3C2410 - SPI Controller platform_device info
*
* 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-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
index a037df5e1c2d..0c0505b025cb 100644
--- a/arch/arm/mach-s3c2412/clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -124,7 +124,9 @@ static struct clk clk_usysclk = {
.name = "usysclk",
.id = -1,
.parent = &clk_xtal,
- .set_parent = s3c2412_setparent_usysclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2412_setparent_usysclk,
+ },
};
static struct clk clk_mrefclk = {
@@ -199,10 +201,12 @@ static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
static struct clk clk_usbsrc = {
.name = "usbsrc",
.id = -1,
- .get_rate = s3c2412_getrate_usbsrc,
- .set_rate = s3c2412_setrate_usbsrc,
- .round_rate = s3c2412_roundrate_usbsrc,
- .set_parent = s3c2412_setparent_usbsrc,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2412_getrate_usbsrc,
+ .set_rate = s3c2412_setrate_usbsrc,
+ .round_rate = s3c2412_roundrate_usbsrc,
+ .set_parent = s3c2412_setparent_usbsrc,
+ },
};
static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
@@ -225,7 +229,9 @@ static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
static struct clk clk_msysclk = {
.name = "msysclk",
.id = -1,
- .set_parent = s3c2412_setparent_msysclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2412_setparent_msysclk,
+ },
};
static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
@@ -264,7 +270,9 @@ static struct clk clk_armclk = {
.name = "armclk",
.id = -1,
.parent = &clk_msysclk,
- .set_parent = s3c2412_setparent_armclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2412_setparent_armclk,
+ },
};
/* these next clocks have an divider immediately after them,
@@ -337,10 +345,12 @@ static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
static struct clk clk_uart = {
.name = "uartclk",
.id = -1,
- .get_rate = s3c2412_getrate_uart,
- .set_rate = s3c2412_setrate_uart,
- .set_parent = s3c2412_setparent_uart,
- .round_rate = s3c2412_roundrate_clksrc,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2412_getrate_uart,
+ .set_rate = s3c2412_setrate_uart,
+ .set_parent = s3c2412_setparent_uart,
+ .round_rate = s3c2412_roundrate_clksrc,
+ },
};
static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
@@ -388,10 +398,12 @@ static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
static struct clk clk_i2s = {
.name = "i2sclk",
.id = -1,
- .get_rate = s3c2412_getrate_i2s,
- .set_rate = s3c2412_setrate_i2s,
- .set_parent = s3c2412_setparent_i2s,
- .round_rate = s3c2412_roundrate_clksrc,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2412_getrate_i2s,
+ .set_rate = s3c2412_setrate_i2s,
+ .set_parent = s3c2412_setparent_i2s,
+ .round_rate = s3c2412_roundrate_clksrc,
+ },
};
static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
@@ -438,10 +450,12 @@ static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
static struct clk clk_cam = {
.name = "camif-upll", /* same as 2440 name */
.id = -1,
- .get_rate = s3c2412_getrate_cam,
- .set_rate = s3c2412_setrate_cam,
- .set_parent = s3c2412_setparent_cam,
- .round_rate = s3c2412_roundrate_clksrc,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2412_getrate_cam,
+ .set_rate = s3c2412_setrate_cam,
+ .set_parent = s3c2412_setparent_cam,
+ .round_rate = s3c2412_roundrate_clksrc,
+ },
};
/* standard clock definitions */
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
index d1c29b2537cd..3dc2426e2345 100644
--- a/arch/arm/mach-s3c2440/clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -98,8 +98,10 @@ static struct clk s3c2440_clk_cam = {
static struct clk s3c2440_clk_cam_upll = {
.name = "camif-upll",
.id = -1,
- .set_rate = s3c2440_camif_upll_setrate,
- .round_rate = s3c2440_camif_upll_round,
+ .ops = &(struct clk_ops) {
+ .set_rate = s3c2440_camif_upll_setrate,
+ .round_rate = s3c2440_camif_upll_round,
+ },
};
static struct clk s3c2440_clk_ac97 = {
diff --git a/arch/arm/mach-s3c2442/clock.c b/arch/arm/mach-s3c2442/clock.c
index ea1aa1f5157a..d9b692a12480 100644
--- a/arch/arm/mach-s3c2442/clock.c
+++ b/arch/arm/mach-s3c2442/clock.c
@@ -109,8 +109,10 @@ static struct clk s3c2442_clk_cam = {
static struct clk s3c2442_clk_cam_upll = {
.name = "camif-upll",
.id = -1,
- .set_rate = s3c2442_camif_upll_setrate,
- .round_rate = s3c2442_camif_upll_round,
+ .ops = &(struct clk_ops) {
+ .set_rate = s3c2442_camif_upll_setrate,
+ .round_rate = s3c2442_camif_upll_round,
+ },
};
static int s3c2442_clk_add(struct sys_device *sysdev)
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 2785d69c95b0..3eb8b935d64c 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -187,7 +187,9 @@ static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent)
static struct clk clk_epllref = {
.name = "epllref",
.id = -1,
- .set_parent = s3c2443_setparent_epllref,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_epllref,
+ },
};
static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
@@ -205,7 +207,9 @@ static struct clk clk_mdivclk = {
.name = "mdivclk",
.parent = &clk_mpllref,
.id = -1,
- .get_rate = s3c2443_getrate_mdivclk,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_mdivclk,
+ },
};
static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
@@ -232,7 +236,9 @@ static struct clk clk_msysclk = {
.name = "msysclk",
.parent = &clk_xtal,
.id = -1,
- .set_parent = s3c2443_setparent_msysclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_msysclk,
+ },
};
/* armdiv
@@ -273,7 +279,9 @@ static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent)
static struct clk clk_arm = {
.name = "armclk",
.id = -1,
- .set_parent = s3c2443_setparent_armclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_armclk,
+ },
};
/* esysclk
@@ -302,7 +310,9 @@ static struct clk clk_esysclk = {
.name = "esysclk",
.parent = &clk_epll,
.id = -1,
- .set_parent = s3c2443_setparent_esysclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_esysclk,
+ },
};
/* uartclk
@@ -341,9 +351,11 @@ static struct clk clk_uart = {
.name = "uartclk",
.id = -1,
.parent = &clk_esysclk,
- .get_rate = s3c2443_getrate_uart,
- .set_rate = s3c2443_setrate_uart,
- .round_rate = s3c2443_roundrate_clksrc16,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_uart,
+ .set_rate = s3c2443_setrate_uart,
+ .round_rate = s3c2443_roundrate_clksrc16,
+ },
};
/* hsspi
@@ -384,9 +396,11 @@ static struct clk clk_hsspi = {
.parent = &clk_esysclk,
.ctrlbit = S3C2443_SCLKCON_HSSPICLK,
.enable = s3c2443_clkcon_enable_s,
- .get_rate = s3c2443_getrate_hsspi,
- .set_rate = s3c2443_setrate_hsspi,
- .round_rate = s3c2443_roundrate_clksrc4,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_hsspi,
+ .set_rate = s3c2443_setrate_hsspi,
+ .round_rate = s3c2443_roundrate_clksrc4,
+ },
};
/* usbhost
@@ -426,9 +440,11 @@ static struct clk clk_usb_bus_host = {
.parent = &clk_esysclk,
.ctrlbit = S3C2443_SCLKCON_USBHOST,
.enable = s3c2443_clkcon_enable_s,
- .get_rate = s3c2443_getrate_usbhost,
- .set_rate = s3c2443_setrate_usbhost,
- .round_rate = s3c2443_roundrate_clksrc4,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_usbhost,
+ .set_rate = s3c2443_setrate_usbhost,
+ .round_rate = s3c2443_roundrate_clksrc4,
+ },
};
/* clk_hsmcc_div
@@ -468,9 +484,11 @@ static struct clk clk_hsmmc_div = {
.name = "hsmmc-div",
.id = -1,
.parent = &clk_esysclk,
- .get_rate = s3c2443_getrate_hsmmc_div,
- .set_rate = s3c2443_setrate_hsmmc_div,
- .round_rate = s3c2443_roundrate_clksrc4,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_hsmmc_div,
+ .set_rate = s3c2443_setrate_hsmmc_div,
+ .round_rate = s3c2443_roundrate_clksrc4,
+ },
};
static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
@@ -505,7 +523,9 @@ static struct clk clk_hsmmc = {
.id = -1,
.parent = &clk_hsmmc_div,
.enable = s3c2443_enable_hsmmc,
- .set_parent = s3c2443_setparent_hsmmc,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_hsmmc,
+ },
};
/* i2s_eplldiv
@@ -543,9 +563,11 @@ static struct clk clk_i2s_eplldiv = {
.name = "i2s-eplldiv",
.id = -1,
.parent = &clk_esysclk,
- .get_rate = s3c2443_getrate_i2s_eplldiv,
- .set_rate = s3c2443_setrate_i2s_eplldiv,
- .round_rate = s3c2443_roundrate_clksrc16,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_i2s_eplldiv,
+ .set_rate = s3c2443_setrate_i2s_eplldiv,
+ .round_rate = s3c2443_roundrate_clksrc16,
+ },
};
/* i2s-ref
@@ -578,7 +600,9 @@ static struct clk clk_i2s = {
.parent = &clk_i2s_eplldiv,
.ctrlbit = S3C2443_SCLKCON_I2SCLK,
.enable = s3c2443_clkcon_enable_s,
- .set_parent = s3c2443_setparent_i2s,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2443_setparent_i2s,
+ },
};
/* cam-if
@@ -618,9 +642,11 @@ static struct clk clk_cam = {
.parent = &clk_esysclk,
.ctrlbit = S3C2443_SCLKCON_CAMCLK,
.enable = s3c2443_clkcon_enable_s,
- .get_rate = s3c2443_getrate_cam,
- .set_rate = s3c2443_setrate_cam,
- .round_rate = s3c2443_roundrate_clksrc16,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_cam,
+ .set_rate = s3c2443_setrate_cam,
+ .round_rate = s3c2443_roundrate_clksrc16,
+ },
};
/* display-if
@@ -660,9 +686,11 @@ static struct clk clk_display = {
.parent = &clk_esysclk,
.ctrlbit = S3C2443_SCLKCON_DISPCLK,
.enable = s3c2443_clkcon_enable_s,
- .get_rate = s3c2443_getrate_display,
- .set_rate = s3c2443_setrate_display,
- .round_rate = s3c2443_roundrate_clksrc256,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_getrate_display,
+ .set_rate = s3c2443_setrate_display,
+ .round_rate = s3c2443_roundrate_clksrc256,
+ },
};
/* prediv
@@ -685,7 +713,9 @@ static struct clk clk_prediv = {
.name = "prediv",
.id = -1,
.parent = &clk_msysclk,
- .get_rate = s3c2443_prediv_getrate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c2443_prediv_getrate,
+ },
};
/* standard clock definitions */
@@ -1074,14 +1104,7 @@ void __init s3c2443_init_clocks(int xtal)
/* register clocks from clock array */
- clkp = init_clocks;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- }
+ s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
/* We must be careful disabling the clocks we are not intending to
* be using at boot time, as subsystems such as the LCD which do
diff --git a/arch/arm/mach-s3c6400/include/mach/entry-macro.S b/arch/arm/mach-s3c6400/include/mach/entry-macro.S
index fbd90d2cf355..33a8fe240882 100644
--- a/arch/arm/mach-s3c6400/include/mach/entry-macro.S
+++ b/arch/arm/mach-s3c6400/include/mach/entry-macro.S
@@ -12,33 +12,7 @@
* warranty of any kind, whether express or implied.
*/
-#include <asm/hardware/vic.h>
#include <mach/map.h>
#include <plat/irqs.h>
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =S3C_VA_VIC0
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- @ check the vic0
- mov \irqnr, # S3C_IRQ_OFFSET + 31
- ldr \irqstat, [ \base, # VIC_IRQ_STATUS ]
- teq \irqstat, #0
-
- @ otherwise try vic1
- addeq \tmp, \base, #(S3C_VA_VIC1 - S3C_VA_VIC0)
- addeq \irqnr, \irqnr, #32
- ldreq \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
- teqeq \irqstat, #0
-
- clzne \irqstat, \irqstat
- subne \irqnr, \irqnr, \irqstat
- .endm
+#include <asm/entry-macro-vic2.S>
diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h
index 106ee13581e2..d4cd3abe3cba 100644
--- a/arch/arm/mach-s3c6400/include/mach/map.h
+++ b/arch/arm/mach-s3c6400/include/mach/map.h
@@ -70,8 +70,8 @@
#define S3C64XX_VA_USB_HSPHY S3C_ADDR_CPU(0x00200000)
/* place VICs close together */
-#define S3C_VA_VIC0 (S3C_VA_IRQ + 0x00)
-#define S3C_VA_VIC1 (S3C_VA_IRQ + 0x10000)
+#define VA_VIC0 (S3C_VA_IRQ + 0x00)
+#define VA_VIC1 (S3C_VA_IRQ + 0x10000)
/* compatibiltiy defines. */
#define S3C_PA_TIMER S3C64XX_PA_TIMER
diff --git a/arch/arm/mach-s3c6400/include/mach/tick.h b/arch/arm/mach-s3c6400/include/mach/tick.h
index d9c0dc7014ec..ebe18a9469b8 100644
--- a/arch/arm/mach-s3c6400/include/mach/tick.h
+++ b/arch/arm/mach-s3c6400/include/mach/tick.h
@@ -20,7 +20,7 @@
*/
static inline u32 s3c24xx_ostimer_pending(void)
{
- u32 pend = __raw_readl(S3C_VA_VIC0 + VIC_RAW_STATUS);
+ u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
return pend & 1 << (IRQ_TIMER4_VIC - S3C64XX_IRQ_VIC0(0));
}
diff --git a/arch/arm/mach-s5pc100/setup-sdhci.c b/arch/arm/mach-s5pc100/setup-sdhci.c
index 4385986a3da0..ea7ff19adb95 100644
--- a/arch/arm/mach-s5pc100/setup-sdhci.c
+++ b/arch/arm/mach-s5pc100/setup-sdhci.c
@@ -28,8 +28,8 @@
char *s5pc100_hsmmc_clksrcs[4] = {
[0] = "hsmmc",
[1] = "hsmmc",
- /* [2] = "mmc_bus", not yet succesfuuly used yet */
- /* [3] = "48m", - note not succesfully used yet */
+ /* [2] = "mmc_bus", not yet successfully used yet */
+ /* [3] = "48m", - note not successfully used yet */
};
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c
index 111f7ea32b38..c174ed1f3691 100644
--- a/arch/arm/mach-u300/clock.c
+++ b/arch/arm/mach-u300/clock.c
@@ -1276,11 +1276,8 @@ static struct clk_lookup lookups[] = {
static void __init clk_register(void)
{
- int i;
-
/* Register the lookups */
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
}
/*
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 20b6ebb6783a..8359a73d0041 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -85,11 +85,8 @@ static struct clk_lookup lookups[] = {
static int __init clk_init(void)
{
- int i;
-
/* register the clock lookups */
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return 0;
}
arch_initcall(clk_init);
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index e13be7c444ca..9ddb49b1cb71 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -851,8 +851,7 @@ void __init versatile_init(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(lookups); i++)
- clkdev_add(&lookups[i]);
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
platform_device_register(&versatile_flash_device);
platform_device_register(&versatile_i2c_device);
diff --git a/arch/arm/mach-w90x900/clock.c b/arch/arm/mach-w90x900/clock.c
index b785994bab0a..2c371ff22e51 100644
--- a/arch/arm/mach-w90x900/clock.c
+++ b/arch/arm/mach-w90x900/clock.c
@@ -90,12 +90,3 @@ void nuc900_subclk_enable(struct clk *clk, int enable)
__raw_writel(clken, W90X900_VA_CLKPWR + SUBCLK);
}
-
-
-void clks_register(struct clk_lookup *clks, size_t num)
-{
- int i;
-
- for (i = 0; i < num; i++)
- clkdev_add(&clks[i]);
-}
diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h
index f5816a06eed6..c56ddab3d912 100644
--- a/arch/arm/mach-w90x900/clock.h
+++ b/arch/arm/mach-w90x900/clock.h
@@ -14,7 +14,6 @@
void nuc900_clk_enable(struct clk *clk, int enable);
void nuc900_subclk_enable(struct clk *clk, int enable);
-void clks_register(struct clk_lookup *clks, size_t num);
struct clk {
unsigned long cken;
diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c
index 20dc0c96214d..6f5ca532883f 100644
--- a/arch/arm/mach-w90x900/cpu.c
+++ b/arch/arm/mach-w90x900/cpu.c
@@ -208,6 +208,6 @@ void __init nuc900_map_io(struct map_desc *mach_desc, int mach_size)
void __init nuc900_init_clocks(void)
{
- clks_register(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs));
+ clkdev_add_table(nuc900_clkregs, ARRAY_SIZE(nuc900_clkregs));
}
diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h
index 940640066857..ce228bdc66dd 100644
--- a/arch/arm/mach-w90x900/include/mach/system.h
+++ b/arch/arm/mach-w90x900/include/mach/system.h
@@ -15,7 +15,15 @@
*
*/
+#include <linux/io.h>
#include <asm/proc-fns.h>
+#include <mach/map.h>
+#include <mach/regs-timer.h>
+
+#define WTCR (TMR_BA + 0x1C)
+#define WTCLK (1 << 10)
+#define WTE (1 << 7)
+#define WTRE (1 << 1)
static void arch_idle(void)
{
@@ -23,6 +31,11 @@ static void arch_idle(void)
static void arch_reset(char mode, const char *cmd)
{
- cpu_reset(0);
+ if (mode == 's') {
+ /* Jump into ROM at address 0 */
+ cpu_reset(0);
+ } else {
+ __raw_writel(WTE | WTRE | WTCLK, WTCR);
+ }
}
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
index 4128af870b41..b80f769bc135 100644
--- a/arch/arm/mach-w90x900/time.c
+++ b/arch/arm/mach-w90x900/time.c
@@ -42,7 +42,10 @@
#define TICKS_PER_SEC 100
#define PRESCALE 0x63 /* Divider = prescale + 1 */
-unsigned int timer0_load;
+#define TDR_SHIFT 24
+#define TDR_MASK ((1 << TDR_SHIFT) - 1)
+
+static unsigned int timer0_load;
static void nuc900_clockevent_setmode(enum clock_event_mode mode,
struct clock_event_device *clk)
@@ -88,7 +91,7 @@ static int nuc900_clockevent_setnextevent(unsigned long evt,
static struct clock_event_device nuc900_clockevent_device = {
.name = "nuc900-timer0",
.shift = 32,
- .features = CLOCK_EVT_MODE_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = nuc900_clockevent_setmode,
.set_next_event = nuc900_clockevent_setnextevent,
.rating = 300,
@@ -112,8 +115,23 @@ static struct irqaction nuc900_timer0_irq = {
.handler = nuc900_timer0_interrupt,
};
-static void __init nuc900_clockevents_init(unsigned int rate)
+static void __init nuc900_clockevents_init(void)
{
+ unsigned int rate;
+ struct clk *clk = clk_get(NULL, "timer0");
+
+ BUG_ON(IS_ERR(clk));
+
+ __raw_writel(0x00, REG_TCSR0);
+
+ clk_enable(clk);
+ rate = clk_get_rate(clk) / (PRESCALE + 1);
+
+ timer0_load = (rate / TICKS_PER_SEC);
+
+ __raw_writel(RESETINT, REG_TISR);
+ setup_irq(IRQ_TIMER0, &nuc900_timer0_irq);
+
nuc900_clockevent_device.mult = div_sc(rate, NSEC_PER_SEC,
nuc900_clockevent_device.shift);
nuc900_clockevent_device.max_delta_ns = clockevent_delta2ns(0xffffffff,
@@ -127,26 +145,35 @@ static void __init nuc900_clockevents_init(unsigned int rate)
static cycle_t nuc900_get_cycles(struct clocksource *cs)
{
- return ~__raw_readl(REG_TDR1);
+ return (~__raw_readl(REG_TDR1)) & TDR_MASK;
}
static struct clocksource clocksource_nuc900 = {
.name = "nuc900-timer1",
.rating = 200,
.read = nuc900_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .shift = 20,
+ .mask = CLOCKSOURCE_MASK(TDR_SHIFT),
+ .shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-static void __init nuc900_clocksource_init(unsigned int rate)
+static void __init nuc900_clocksource_init(void)
{
unsigned int val;
+ unsigned int rate;
+ struct clk *clk = clk_get(NULL, "timer1");
+
+ BUG_ON(IS_ERR(clk));
+
+ __raw_writel(0x00, REG_TCSR1);
+
+ clk_enable(clk);
+ rate = clk_get_rate(clk) / (PRESCALE + 1);
__raw_writel(0xffffffff, REG_TICR1);
val = __raw_readl(REG_TCSR1);
- val |= (COUNTEN | PERIOD);
+ val |= (COUNTEN | PERIOD | PRESCALE);
__raw_writel(val, REG_TCSR1);
clocksource_nuc900.mult =
@@ -156,25 +183,8 @@ static void __init nuc900_clocksource_init(unsigned int rate)
static void __init nuc900_timer_init(void)
{
- struct clk *ck_ext = clk_get(NULL, "ext");
- unsigned int rate;
-
- BUG_ON(IS_ERR(ck_ext));
-
- rate = clk_get_rate(ck_ext);
- clk_put(ck_ext);
- rate = rate / (PRESCALE + 0x01);
-
- /* set a known state */
- __raw_writel(0x00, REG_TCSR0);
- __raw_writel(0x00, REG_TCSR1);
- __raw_writel(RESETINT, REG_TISR);
- timer0_load = (rate / TICKS_PER_SEC);
-
- setup_irq(IRQ_TIMER0, &nuc900_timer0_irq);
-
- nuc900_clocksource_init(rate);
- nuc900_clockevents_init(rate);
+ nuc900_clocksource_init();
+ nuc900_clockevents_init();
}
struct sys_timer nuc900_timer = {
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 827e238e5d4a..e8d34a80851c 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -27,6 +27,9 @@ obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o
obj-$(CONFIG_CPU_ABRT_EV6) += abort-ev6.o
obj-$(CONFIG_CPU_ABRT_EV7) += abort-ev7.o
+AFLAGS_abort-ev6.o :=-Wa,-march=armv6k
+AFLAGS_abort-ev7.o :=-Wa,-march=armv7-a
+
obj-$(CONFIG_CPU_PABRT_LEGACY) += pabort-legacy.o
obj-$(CONFIG_CPU_PABRT_V6) += pabort-v6.o
obj-$(CONFIG_CPU_PABRT_V7) += pabort-v7.o
@@ -39,6 +42,9 @@ obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o
obj-$(CONFIG_CPU_CACHE_FA) += cache-fa.o
+AFLAGS_cache-v6.o :=-Wa,-march=armv6
+AFLAGS_cache-v7.o :=-Wa,-march=armv7-a
+
obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
@@ -58,6 +64,9 @@ obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o
obj-$(CONFIG_CPU_TLB_FA) += tlb-fa.o
+AFLAGS_tlb-v6.o :=-Wa,-march=armv6
+AFLAGS_tlb-v7.o :=-Wa,-march=armv7-a
+
obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
obj-$(CONFIG_CPU_ARM7TDMI) += proc-arm7tdmi.o
@@ -84,6 +93,9 @@ obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
obj-$(CONFIG_CPU_V7) += proc-v7.o
+AFLAGS_proc-v6.o :=-Wa,-march=armv6
+AFLAGS_proc-v7.o :=-Wa,-march=armv7-a
+
obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index b270d6228fe2..0c5eb6983cef 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -898,11 +898,7 @@ static int __init alignment_init(void)
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *res;
- res = proc_mkdir("cpu", NULL);
- if (!res)
- return -ENOMEM;
-
- res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
+ res = create_proc_entry("cpu/alignment", S_IWUSR | S_IRUGO, NULL);
if (!res)
return -ENOMEM;
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
index a89444a3c016..7148e53e6078 100644
--- a/arch/arm/mm/cache-fa.S
+++ b/arch/arm/mm/cache-fa.S
@@ -157,7 +157,7 @@ ENTRY(fa_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(fa_dma_inv_range)
+fa_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D entry
@@ -180,7 +180,7 @@ ENTRY(fa_dma_inv_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(fa_dma_clean_range)
+fa_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -205,6 +205,30 @@ ENTRY(fa_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(fa_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq fa_dma_clean_range
+ bcs fa_dma_inv_range
+ b fa_dma_flush_range
+ENDPROC(fa_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(fa_dma_unmap_area)
+ mov pc, lr
+ENDPROC(fa_dma_unmap_area)
+
__INITDATA
.type fa_cache_fns, #object
@@ -215,7 +239,7 @@ ENTRY(fa_cache_fns)
.long fa_coherent_kern_range
.long fa_coherent_user_range
.long fa_flush_kern_dcache_area
- .long fa_dma_inv_range
- .long fa_dma_clean_range
+ .long fa_dma_map_area
+ .long fa_dma_unmap_area
.long fa_dma_flush_range
.size fa_cache_fns, . - fa_cache_fns
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
index 2a482731ea36..c2ff3c599fee 100644
--- a/arch/arm/mm/cache-v3.S
+++ b/arch/arm/mm/cache-v3.S
@@ -84,20 +84,6 @@ ENTRY(v3_flush_kern_dcache_area)
/* FALLTHROUGH */
/*
- * dma_inv_range(start, end)
- *
- * Invalidate (discard) the specified virtual address range.
- * May not write back any entries. If 'start' or 'end'
- * are not cache line aligned, those lines must be written
- * back.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v3_dma_inv_range)
- /* FALLTHROUGH */
-
-/*
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -108,18 +94,29 @@ ENTRY(v3_dma_inv_range)
ENTRY(v3_dma_flush_range)
mov r0, #0
mcr p15, 0, r0, c7, c0, 0 @ flush ID cache
+ mov pc, lr
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v3_dma_unmap_area)
+ teq r2, #DMA_TO_DEVICE
+ bne v3_dma_flush_range
/* FALLTHROUGH */
/*
- * dma_clean_range(start, end)
- *
- * Clean (write back) the specified virtual address range.
- *
- * - start - virtual start address
- * - end - virtual end address
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
*/
-ENTRY(v3_dma_clean_range)
+ENTRY(v3_dma_map_area)
mov pc, lr
+ENDPROC(v3_dma_unmap_area)
+ENDPROC(v3_dma_map_area)
__INITDATA
@@ -131,7 +128,7 @@ ENTRY(v3_cache_fns)
.long v3_coherent_kern_range
.long v3_coherent_user_range
.long v3_flush_kern_dcache_area
- .long v3_dma_inv_range
- .long v3_dma_clean_range
+ .long v3_dma_map_area
+ .long v3_dma_unmap_area
.long v3_dma_flush_range
.size v3_cache_fns, . - v3_cache_fns
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index 5c7da3e372e9..4810f7e3e813 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -94,20 +94,6 @@ ENTRY(v4_flush_kern_dcache_area)
/* FALLTHROUGH */
/*
- * dma_inv_range(start, end)
- *
- * Invalidate (discard) the specified virtual address range.
- * May not write back any entries. If 'start' or 'end'
- * are not cache line aligned, those lines must be written
- * back.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v4_dma_inv_range)
- /* FALLTHROUGH */
-
-/*
* dma_flush_range(start, end)
*
* Clean and invalidate the specified virtual address range.
@@ -120,18 +106,29 @@ ENTRY(v4_dma_flush_range)
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
#endif
+ mov pc, lr
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v4_dma_unmap_area)
+ teq r2, #DMA_TO_DEVICE
+ bne v4_dma_flush_range
/* FALLTHROUGH */
/*
- * dma_clean_range(start, end)
- *
- * Clean (write back) the specified virtual address range.
- *
- * - start - virtual start address
- * - end - virtual end address
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
*/
-ENTRY(v4_dma_clean_range)
+ENTRY(v4_dma_map_area)
mov pc, lr
+ENDPROC(v4_dma_unmap_area)
+ENDPROC(v4_dma_map_area)
__INITDATA
@@ -143,7 +140,7 @@ ENTRY(v4_cache_fns)
.long v4_coherent_kern_range
.long v4_coherent_user_range
.long v4_flush_kern_dcache_area
- .long v4_dma_inv_range
- .long v4_dma_clean_range
+ .long v4_dma_map_area
+ .long v4_dma_unmap_area
.long v4_dma_flush_range
.size v4_cache_fns, . - v4_cache_fns
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
index 3dbedf1ec0e7..df8368afa102 100644
--- a/arch/arm/mm/cache-v4wb.S
+++ b/arch/arm/mm/cache-v4wb.S
@@ -173,7 +173,7 @@ ENTRY(v4wb_coherent_user_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(v4wb_dma_inv_range)
+v4wb_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -194,7 +194,7 @@ ENTRY(v4wb_dma_inv_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(v4wb_dma_clean_range)
+v4wb_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -216,6 +216,30 @@ ENTRY(v4wb_dma_clean_range)
.globl v4wb_dma_flush_range
.set v4wb_dma_flush_range, v4wb_coherent_kern_range
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v4wb_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq v4wb_dma_clean_range
+ bcs v4wb_dma_inv_range
+ b v4wb_dma_flush_range
+ENDPROC(v4wb_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v4wb_dma_unmap_area)
+ mov pc, lr
+ENDPROC(v4wb_dma_unmap_area)
+
__INITDATA
.type v4wb_cache_fns, #object
@@ -226,7 +250,7 @@ ENTRY(v4wb_cache_fns)
.long v4wb_coherent_kern_range
.long v4wb_coherent_user_range
.long v4wb_flush_kern_dcache_area
- .long v4wb_dma_inv_range
- .long v4wb_dma_clean_range
+ .long v4wb_dma_map_area
+ .long v4wb_dma_unmap_area
.long v4wb_dma_flush_range
.size v4wb_cache_fns, . - v4wb_cache_fns
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
index b3b7410270b4..45c70312f43b 100644
--- a/arch/arm/mm/cache-v4wt.S
+++ b/arch/arm/mm/cache-v4wt.S
@@ -142,23 +142,12 @@ ENTRY(v4wt_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(v4wt_dma_inv_range)
+v4wt_dma_inv_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
- /* FALLTHROUGH */
-
-/*
- * dma_clean_range(start, end)
- *
- * Clean the specified virtual address range.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v4wt_dma_clean_range)
mov pc, lr
/*
@@ -172,6 +161,29 @@ ENTRY(v4wt_dma_clean_range)
.globl v4wt_dma_flush_range
.equ v4wt_dma_flush_range, v4wt_dma_inv_range
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v4wt_dma_unmap_area)
+ add r1, r1, r0
+ teq r2, #DMA_TO_DEVICE
+ bne v4wt_dma_inv_range
+ /* FALLTHROUGH */
+
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v4wt_dma_map_area)
+ mov pc, lr
+ENDPROC(v4wt_dma_unmap_area)
+ENDPROC(v4wt_dma_map_area)
+
__INITDATA
.type v4wt_cache_fns, #object
@@ -182,7 +194,7 @@ ENTRY(v4wt_cache_fns)
.long v4wt_coherent_kern_range
.long v4wt_coherent_user_range
.long v4wt_flush_kern_dcache_area
- .long v4wt_dma_inv_range
- .long v4wt_dma_clean_range
+ .long v4wt_dma_map_area
+ .long v4wt_dma_unmap_area
.long v4wt_dma_flush_range
.size v4wt_cache_fns, . - v4wt_cache_fns
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 4ba0a24ce6f5..9d89c67a1cc3 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -195,7 +195,7 @@ ENTRY(v6_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v6_dma_inv_range)
+v6_dma_inv_range:
tst r0, #D_CACHE_LINE_SIZE - 1
bic r0, r0, #D_CACHE_LINE_SIZE - 1
#ifdef HARVARD_CACHE
@@ -228,7 +228,7 @@ ENTRY(v6_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v6_dma_clean_range)
+v6_dma_clean_range:
bic r0, r0, #D_CACHE_LINE_SIZE - 1
1:
#ifdef HARVARD_CACHE
@@ -263,6 +263,32 @@ ENTRY(v6_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v6_dma_map_area)
+ add r1, r1, r0
+ teq r2, #DMA_FROM_DEVICE
+ beq v6_dma_inv_range
+ b v6_dma_clean_range
+ENDPROC(v6_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v6_dma_unmap_area)
+ add r1, r1, r0
+ teq r2, #DMA_TO_DEVICE
+ bne v6_dma_inv_range
+ mov pc, lr
+ENDPROC(v6_dma_unmap_area)
+
__INITDATA
.type v6_cache_fns, #object
@@ -273,7 +299,7 @@ ENTRY(v6_cache_fns)
.long v6_coherent_kern_range
.long v6_coherent_user_range
.long v6_flush_kern_dcache_area
- .long v6_dma_inv_range
- .long v6_dma_clean_range
+ .long v6_dma_map_area
+ .long v6_dma_unmap_area
.long v6_dma_flush_range
.size v6_cache_fns, . - v6_cache_fns
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 9073db849fb4..bcd64f265870 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -216,7 +216,7 @@ ENDPROC(v7_flush_kern_dcache_area)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v7_dma_inv_range)
+v7_dma_inv_range:
dcache_line_size r2, r3
sub r3, r2, #1
tst r0, r3
@@ -240,7 +240,7 @@ ENDPROC(v7_dma_inv_range)
* - start - virtual start address of region
* - end - virtual end address of region
*/
-ENTRY(v7_dma_clean_range)
+v7_dma_clean_range:
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
@@ -271,6 +271,32 @@ ENTRY(v7_dma_flush_range)
mov pc, lr
ENDPROC(v7_dma_flush_range)
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v7_dma_map_area)
+ add r1, r1, r0
+ teq r2, #DMA_FROM_DEVICE
+ beq v7_dma_inv_range
+ b v7_dma_clean_range
+ENDPROC(v7_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(v7_dma_unmap_area)
+ add r1, r1, r0
+ teq r2, #DMA_TO_DEVICE
+ bne v7_dma_inv_range
+ mov pc, lr
+ENDPROC(v7_dma_unmap_area)
+
__INITDATA
.type v7_cache_fns, #object
@@ -281,7 +307,7 @@ ENTRY(v7_cache_fns)
.long v7_coherent_kern_range
.long v7_coherent_user_range
.long v7_flush_kern_dcache_area
- .long v7_dma_inv_range
- .long v7_dma_clean_range
+ .long v7_dma_map_area
+ .long v7_dma_unmap_area
.long v7_dma_flush_range
.size v7_cache_fns, . - v7_cache_fns
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index 5d180cb0bd94..c3154928bccd 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -221,15 +221,14 @@ static int __init xsc3_l2_init(void)
if (!cpu_is_xsc3() || !xsc3_l2_present())
return 0;
- if (!(get_cr() & CR_L2)) {
+ if (get_cr() & CR_L2) {
pr_info("XScale3 L2 cache enabled.\n");
- adjust_cr(CR_L2, CR_L2);
xsc3_l2_inv_all();
- }
- outer_cache.inv_range = xsc3_l2_inv_range;
- outer_cache.clean_range = xsc3_l2_clean_range;
- outer_cache.flush_range = xsc3_l2_flush_range;
+ outer_cache.inv_range = xsc3_l2_inv_range;
+ outer_cache.clean_range = xsc3_l2_clean_range;
+ outer_cache.flush_range = xsc3_l2_flush_range;
+ }
return 0;
}
diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c
index 70997d5bee2d..5eb4fd93893d 100644
--- a/arch/arm/mm/copypage-feroceon.c
+++ b/arch/arm/mm/copypage-feroceon.c
@@ -68,12 +68,13 @@ feroceon_copy_user_page(void *kto, const void *kfrom)
}
void feroceon_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
kto = kmap_atomic(to, KM_USER0);
kfrom = kmap_atomic(from, KM_USER1);
+ flush_cache_page(vma, vaddr, page_to_pfn(from));
feroceon_copy_user_page(kto, kfrom);
kunmap_atomic(kfrom, KM_USER1);
kunmap_atomic(kto, KM_USER0);
diff --git a/arch/arm/mm/copypage-v3.c b/arch/arm/mm/copypage-v3.c
index de9c06854ad7..f72303e1d804 100644
--- a/arch/arm/mm/copypage-v3.c
+++ b/arch/arm/mm/copypage-v3.c
@@ -38,7 +38,7 @@ v3_copy_user_page(void *kto, const void *kfrom)
}
void v3_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index 7370a7142b04..598c51ad5071 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -69,7 +69,7 @@ mc_copy_user_page(void *from, void *to)
}
void v4_mc_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto = kmap_atomic(to, KM_USER1);
diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c
index 9ab098414227..7c2eb55cd4a9 100644
--- a/arch/arm/mm/copypage-v4wb.c
+++ b/arch/arm/mm/copypage-v4wb.c
@@ -48,12 +48,13 @@ v4wb_copy_user_page(void *kto, const void *kfrom)
}
void v4wb_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
kto = kmap_atomic(to, KM_USER0);
kfrom = kmap_atomic(from, KM_USER1);
+ flush_cache_page(vma, vaddr, page_to_pfn(from));
v4wb_copy_user_page(kto, kfrom);
kunmap_atomic(kfrom, KM_USER1);
kunmap_atomic(kto, KM_USER0);
diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c
index 300efafd6643..172e6a55458e 100644
--- a/arch/arm/mm/copypage-v4wt.c
+++ b/arch/arm/mm/copypage-v4wt.c
@@ -44,7 +44,7 @@ v4wt_copy_user_page(void *kto, const void *kfrom)
}
void v4wt_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 0fa1319273de..8bca4dea6dfa 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -34,7 +34,7 @@ static DEFINE_SPINLOCK(v6_lock);
* attack the kernel's existing mapping of these pages.
*/
static void v6_copy_user_highpage_nonaliasing(struct page *to,
- struct page *from, unsigned long vaddr)
+ struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
@@ -81,7 +81,7 @@ static void discard_old_kernel_data(void *kto)
* Copy the page, taking account of the cache colour.
*/
static void v6_copy_user_highpage_aliasing(struct page *to,
- struct page *from, unsigned long vaddr)
+ struct page *from, unsigned long vaddr, struct vm_area_struct *vma)
{
unsigned int offset = CACHE_COLOUR(vaddr);
unsigned long kfrom, kto;
diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c
index bc4525f5ab23..747ad4140fc7 100644
--- a/arch/arm/mm/copypage-xsc3.c
+++ b/arch/arm/mm/copypage-xsc3.c
@@ -71,12 +71,13 @@ xsc3_mc_copy_user_page(void *kto, const void *kfrom)
}
void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto, *kfrom;
kto = kmap_atomic(to, KM_USER0);
kfrom = kmap_atomic(from, KM_USER1);
+ flush_cache_page(vma, vaddr, page_to_pfn(from));
xsc3_mc_copy_user_page(kto, kfrom);
kunmap_atomic(kfrom, KM_USER1);
kunmap_atomic(kto, KM_USER0);
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 76824d3e966a..9920c0ae2096 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -91,7 +91,7 @@ mc_copy_user_page(void *from, void *to)
}
void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
- unsigned long vaddr)
+ unsigned long vaddr, struct vm_area_struct *vma)
{
void *kto = kmap_atomic(to, KM_USER1);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 26325cb5d368..64daef2173bd 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -404,78 +404,44 @@ EXPORT_SYMBOL(dma_free_coherent);
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
-void dma_cache_maint(const void *start, size_t size, int direction)
+void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
+ enum dma_data_direction dir)
{
- void (*inner_op)(const void *, const void *);
- void (*outer_op)(unsigned long, unsigned long);
-
- BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1));
-
- switch (direction) {
- case DMA_FROM_DEVICE: /* invalidate only */
- inner_op = dmac_inv_range;
- outer_op = outer_inv_range;
- break;
- case DMA_TO_DEVICE: /* writeback only */
- inner_op = dmac_clean_range;
- outer_op = outer_clean_range;
- break;
- case DMA_BIDIRECTIONAL: /* writeback and invalidate */
- inner_op = dmac_flush_range;
- outer_op = outer_flush_range;
- break;
- default:
- BUG();
- }
+ unsigned long paddr;
+
+ BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
+
+ dmac_map_area(kaddr, size, dir);
- inner_op(start, start + size);
- outer_op(__pa(start), __pa(start) + size);
+ paddr = __pa(kaddr);
+ if (dir == DMA_FROM_DEVICE) {
+ outer_inv_range(paddr, paddr + size);
+ } else {
+ outer_clean_range(paddr, paddr + size);
+ }
+ /* FIXME: non-speculating: flush on bidirectional mappings? */
}
-EXPORT_SYMBOL(dma_cache_maint);
+EXPORT_SYMBOL(___dma_single_cpu_to_dev);
-static void dma_cache_maint_contiguous(struct page *page, unsigned long offset,
- size_t size, int direction)
+void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
+ enum dma_data_direction dir)
{
- void *vaddr;
- unsigned long paddr;
- void (*inner_op)(const void *, const void *);
- void (*outer_op)(unsigned long, unsigned long);
-
- switch (direction) {
- case DMA_FROM_DEVICE: /* invalidate only */
- inner_op = dmac_inv_range;
- outer_op = outer_inv_range;
- break;
- case DMA_TO_DEVICE: /* writeback only */
- inner_op = dmac_clean_range;
- outer_op = outer_clean_range;
- break;
- case DMA_BIDIRECTIONAL: /* writeback and invalidate */
- inner_op = dmac_flush_range;
- outer_op = outer_flush_range;
- break;
- default:
- BUG();
- }
+ BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
- if (!PageHighMem(page)) {
- vaddr = page_address(page) + offset;
- inner_op(vaddr, vaddr + size);
- } else {
- vaddr = kmap_high_get(page);
- if (vaddr) {
- vaddr += offset;
- inner_op(vaddr, vaddr + size);
- kunmap_high(page);
- }
+ /* FIXME: non-speculating: not required */
+ /* don't bother invalidating if DMA to device */
+ if (dir != DMA_TO_DEVICE) {
+ unsigned long paddr = __pa(kaddr);
+ outer_inv_range(paddr, paddr + size);
}
- paddr = page_to_phys(page) + offset;
- outer_op(paddr, paddr + size);
+ dmac_unmap_area(kaddr, size, dir);
}
+EXPORT_SYMBOL(___dma_single_dev_to_cpu);
-void dma_cache_maint_page(struct page *page, unsigned long offset,
- size_t size, int dir)
+static void dma_cache_maint_page(struct page *page, unsigned long offset,
+ size_t size, enum dma_data_direction dir,
+ void (*op)(const void *, size_t, int))
{
/*
* A single sg entry may refer to multiple physically contiguous
@@ -486,20 +452,62 @@ void dma_cache_maint_page(struct page *page, unsigned long offset,
size_t left = size;
do {
size_t len = left;
- if (PageHighMem(page) && len + offset > PAGE_SIZE) {
- if (offset >= PAGE_SIZE) {
- page += offset / PAGE_SIZE;
- offset %= PAGE_SIZE;
+ void *vaddr;
+
+ if (PageHighMem(page)) {
+ if (len + offset > PAGE_SIZE) {
+ if (offset >= PAGE_SIZE) {
+ page += offset / PAGE_SIZE;
+ offset %= PAGE_SIZE;
+ }
+ len = PAGE_SIZE - offset;
}
- len = PAGE_SIZE - offset;
+ vaddr = kmap_high_get(page);
+ if (vaddr) {
+ vaddr += offset;
+ op(vaddr, len, dir);
+ kunmap_high(page);
+ }
+ } else {
+ vaddr = page_address(page) + offset;
+ op(vaddr, len, dir);
}
- dma_cache_maint_contiguous(page, offset, len, dir);
offset = 0;
page++;
left -= len;
} while (left);
}
-EXPORT_SYMBOL(dma_cache_maint_page);
+
+void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long paddr;
+
+ dma_cache_maint_page(page, off, size, dir, dmac_map_area);
+
+ paddr = page_to_phys(page) + off;
+ if (dir == DMA_FROM_DEVICE) {
+ outer_inv_range(paddr, paddr + size);
+ } else {
+ outer_clean_range(paddr, paddr + size);
+ }
+ /* FIXME: non-speculating: flush on bidirectional mappings? */
+}
+EXPORT_SYMBOL(___dma_page_cpu_to_dev);
+
+void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+ size_t size, enum dma_data_direction dir)
+{
+ unsigned long paddr = page_to_phys(page) + off;
+
+ /* FIXME: non-speculating: not required */
+ /* don't bother invalidating if DMA to device */
+ if (dir != DMA_TO_DEVICE)
+ outer_inv_range(paddr, paddr + size);
+
+ dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+}
+EXPORT_SYMBOL(___dma_page_dev_to_cpu);
/**
* dma_map_sg - map a set of SG buffers for streaming mode DMA
@@ -573,8 +581,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int i;
for_each_sg(sg, s, nents, i) {
- dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
- sg_dma_len(s), dir);
+ if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
+ sg_dma_len(s), dir))
+ continue;
+
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
}
}
EXPORT_SYMBOL(dma_sync_sg_for_cpu);
@@ -597,9 +609,8 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
sg_dma_len(s), dir))
continue;
- if (!arch_is_coherent())
- dma_cache_maint_page(sg_page(s), s->offset,
- s->length, dir);
+ __dma_page_cpu_to_dev(sg_page(s), s->offset,
+ s->length, dir);
}
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 6f3a4b7a3b82..e34f095e2090 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -13,6 +13,7 @@
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
+#include <asm/smp_plat.h>
#include <asm/system.h>
#include <asm/tlbflush.h>
@@ -87,13 +88,26 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
__flush_icache_all();
}
+#else
+#define flush_pfn_alias(pfn,vaddr) do { } while (0)
+#endif
+#ifdef CONFIG_SMP
+static void flush_ptrace_access_other(void *args)
+{
+ __flush_icache_all();
+}
+#endif
+
+static
void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
- unsigned long uaddr, void *kaddr,
- unsigned long len, int write)
+ unsigned long uaddr, void *kaddr, unsigned long len)
{
if (cache_is_vivt()) {
- vivt_flush_ptrace_access(vma, page, uaddr, kaddr, len, write);
+ if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
+ unsigned long addr = (unsigned long)kaddr;
+ __cpuc_coherent_kern_range(addr, addr + len);
+ }
return;
}
@@ -104,16 +118,37 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
}
/* VIPT non-aliasing cache */
- if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm)) &&
- vma->vm_flags & VM_EXEC) {
+ if (vma->vm_flags & VM_EXEC) {
unsigned long addr = (unsigned long)kaddr;
- /* only flushing the kernel mapping on non-aliasing VIPT */
__cpuc_coherent_kern_range(addr, addr + len);
+#ifdef CONFIG_SMP
+ if (cache_ops_need_broadcast())
+ smp_call_function(flush_ptrace_access_other,
+ NULL, 1);
+#endif
}
}
-#else
-#define flush_pfn_alias(pfn,vaddr) do { } while (0)
+
+/*
+ * Copy user data from/to a page which is mapped into a different
+ * processes address space. Really, we want to allow our "user
+ * space" model to handle this.
+ *
+ * Note that this code needs to run on the current CPU.
+ */
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long uaddr, void *dst, const void *src,
+ unsigned long len)
+{
+#ifdef CONFIG_SMP
+ preempt_disable();
#endif
+ memcpy(dst, src, len);
+ flush_ptrace_access(vma, page, uaddr, dst, len);
+#ifdef CONFIG_SMP
+ preempt_enable();
+#endif
+}
void __flush_dcache_page(struct address_space *mapping, struct page *page)
{
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 52c40d155672..a340569b991e 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -32,19 +32,21 @@
static unsigned long phys_initrd_start __initdata = 0;
static unsigned long phys_initrd_size __initdata = 0;
-static void __init early_initrd(char **p)
+static int __init early_initrd(char *p)
{
unsigned long start, size;
+ char *endp;
- start = memparse(*p, p);
- if (**p == ',') {
- size = memparse((*p) + 1, p);
+ start = memparse(p, &endp);
+ if (*endp == ',') {
+ size = memparse(endp + 1, NULL);
phys_initrd_start = start;
phys_initrd_size = size;
}
+ return 0;
}
-__early_param("initrd=", early_initrd);
+early_param("initrd", early_initrd);
static int __init parse_tag_initrd(const struct tag *tag)
{
@@ -616,7 +618,7 @@ void __init mem_init(void)
"%dK data, %dK init, %luK highmem)\n",
nr_free_pages() << (PAGE_SHIFT-10), codesize >> 10,
datasize >> 10, initsize >> 10,
- (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+ totalhigh_pages << (PAGE_SHIFT-10));
if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
extern int sysctl_overcommit_memory;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 0ab75c60f7cf..28c8b950ef04 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -139,8 +139,8 @@ void __check_kvm_seq(struct mm_struct *mm)
* which requires the new ioremap'd region to be referenced, the CPU will
* reference the _old_ region.
*
- * Note that get_vm_area() allocates a guard 4K page, so we need to mask
- * the size back to 1MB aligned or we will overflow in the loop below.
+ * Note that get_vm_area_caller() allocates a guard 4K page, so we need to
+ * mask the size back to 1MB aligned or we will overflow in the loop below.
*/
static void unmap_area_sections(unsigned long virt, unsigned long size)
{
@@ -254,22 +254,8 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
}
#endif
-
-/*
- * Remap an arbitrary physical address space into the kernel virtual
- * address space. Needed when the kernel wants to access high addresses
- * directly.
- *
- * NOTE! We need to allow non-page-aligned mappings too: we will obviously
- * have to convert them into an offset in a page-aligned mapping, but the
- * caller shouldn't need to know that small detail.
- *
- * 'flags' are the extra L_PTE_ flags that you want to specify for this
- * mapping. See <asm/pgtable.h> for more information.
- */
-void __iomem *
-__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
- unsigned int mtype)
+void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
+ unsigned long offset, size_t size, unsigned int mtype, void *caller)
{
const struct mem_type *type;
int err;
@@ -291,7 +277,7 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
*/
size = PAGE_ALIGN(offset + size);
- area = get_vm_area(size, VM_IOREMAP);
+ area = get_vm_area_caller(size, VM_IOREMAP, caller);
if (!area)
return NULL;
addr = (unsigned long)area->addr;
@@ -318,10 +304,9 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
flush_cache_vmap(addr, addr + size);
return (void __iomem *) (offset + addr);
}
-EXPORT_SYMBOL(__arm_ioremap_pfn);
-void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+ unsigned int mtype, void *caller)
{
unsigned long last_addr;
unsigned long offset = phys_addr & ~PAGE_MASK;
@@ -334,7 +319,33 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
if (!size || last_addr < phys_addr)
return NULL;
- return __arm_ioremap_pfn(pfn, offset, size, mtype);
+ return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
+ caller);
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ */
+void __iomem *
+__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
+ unsigned int mtype)
+{
+ return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
+ __builtin_return_address(0));
+}
+EXPORT_SYMBOL(__arm_ioremap_pfn);
+
+void __iomem *
+__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+{
+ return __arm_ioremap_caller(phys_addr, size, mtype,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(__arm_ioremap);
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 1708da82da96..88f5d71248d9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -100,18 +100,17 @@ static struct cachepolicy cache_policies[] __initdata = {
* writebuffer to be turned off. (Note: the write
* buffer should not be on and the cache off).
*/
-static void __init early_cachepolicy(char **p)
+static int __init early_cachepolicy(char *p)
{
int i;
for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
int len = strlen(cache_policies[i].policy);
- if (memcmp(*p, cache_policies[i].policy, len) == 0) {
+ if (memcmp(p, cache_policies[i].policy, len) == 0) {
cachepolicy = i;
cr_alignment &= ~cache_policies[i].cr_mask;
cr_no_alignment &= ~cache_policies[i].cr_mask;
- *p += len;
break;
}
}
@@ -130,36 +129,37 @@ static void __init early_cachepolicy(char **p)
}
flush_cache_all();
set_cr(cr_alignment);
+ return 0;
}
-__early_param("cachepolicy=", early_cachepolicy);
+early_param("cachepolicy", early_cachepolicy);
-static void __init early_nocache(char **__unused)
+static int __init early_nocache(char *__unused)
{
char *p = "buffered";
printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
- early_cachepolicy(&p);
+ early_cachepolicy(p);
+ return 0;
}
-__early_param("nocache", early_nocache);
+early_param("nocache", early_nocache);
-static void __init early_nowrite(char **__unused)
+static int __init early_nowrite(char *__unused)
{
char *p = "uncached";
printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
- early_cachepolicy(&p);
+ early_cachepolicy(p);
+ return 0;
}
-__early_param("nowb", early_nowrite);
+early_param("nowb", early_nowrite);
-static void __init early_ecc(char **p)
+static int __init early_ecc(char *p)
{
- if (memcmp(*p, "on", 2) == 0) {
+ if (memcmp(p, "on", 2) == 0)
ecc_mask = PMD_PROTECTION;
- *p += 2;
- } else if (memcmp(*p, "off", 3) == 0) {
+ else if (memcmp(p, "off", 3) == 0)
ecc_mask = 0;
- *p += 3;
- }
+ return 0;
}
-__early_param("ecc=", early_ecc);
+early_param("ecc", early_ecc);
static int __init noalign_setup(char *__unused)
{
@@ -670,9 +670,9 @@ static unsigned long __initdata vmalloc_reserve = SZ_128M;
* bytes. This can be used to increase (or decrease) the vmalloc
* area - the default is 128m.
*/
-static void __init early_vmalloc(char **arg)
+static int __init early_vmalloc(char *arg)
{
- vmalloc_reserve = memparse(*arg, arg);
+ vmalloc_reserve = memparse(arg, NULL);
if (vmalloc_reserve < SZ_16M) {
vmalloc_reserve = SZ_16M;
@@ -687,8 +687,9 @@ static void __init early_vmalloc(char **arg)
"vmalloc area is too big, limiting to %luMB\n",
vmalloc_reserve >> 20);
}
+ return 0;
}
-__early_param("vmalloc=", early_vmalloc);
+early_param("vmalloc", early_vmalloc);
#define VMALLOC_MIN (void *)(VMALLOC_END - vmalloc_reserve)
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 374a8311bc84..9bfeb6b9509a 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -74,6 +74,12 @@ void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
}
EXPORT_SYMBOL(__arm_ioremap_pfn);
+void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
+ size_t size, unsigned int mtype, void *caller)
+{
+ return __arm_ioremap_pfn(pfn, offset, size, mtype);
+}
+
void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
unsigned int mtype)
{
@@ -81,6 +87,12 @@ void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
}
EXPORT_SYMBOL(__arm_ioremap);
+void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+ unsigned int mtype, void *caller)
+{
+ return __arm_ioremap(phys_addr, size, mtype);
+}
+
void __iounmap(volatile void __iomem *addr)
{
}
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 8012e24282b2..72507c630ceb 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -265,7 +265,7 @@ ENTRY(arm1020_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm1020_dma_inv_range)
+arm1020_dma_inv_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -295,7 +295,7 @@ ENTRY(arm1020_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm1020_dma_clean_range)
+arm1020_dma_clean_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -330,6 +330,30 @@ ENTRY(arm1020_dma_flush_range)
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1020_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm1020_dma_clean_range
+ bcs arm1020_dma_inv_range
+ b arm1020_dma_flush_range
+ENDPROC(arm1020_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1020_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm1020_dma_unmap_area)
+
ENTRY(arm1020_cache_fns)
.long arm1020_flush_kern_cache_all
.long arm1020_flush_user_cache_all
@@ -337,8 +361,8 @@ ENTRY(arm1020_cache_fns)
.long arm1020_coherent_kern_range
.long arm1020_coherent_user_range
.long arm1020_flush_kern_dcache_area
- .long arm1020_dma_inv_range
- .long arm1020_dma_clean_range
+ .long arm1020_dma_map_area
+ .long arm1020_dma_unmap_area
.long arm1020_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 41fe25d234f5..d27829805609 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -258,7 +258,7 @@ ENTRY(arm1020e_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm1020e_dma_inv_range)
+arm1020e_dma_inv_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -284,7 +284,7 @@ ENTRY(arm1020e_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm1020e_dma_clean_range)
+arm1020e_dma_clean_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -316,6 +316,30 @@ ENTRY(arm1020e_dma_flush_range)
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1020e_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm1020e_dma_clean_range
+ bcs arm1020e_dma_inv_range
+ b arm1020e_dma_flush_range
+ENDPROC(arm1020e_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1020e_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm1020e_dma_unmap_area)
+
ENTRY(arm1020e_cache_fns)
.long arm1020e_flush_kern_cache_all
.long arm1020e_flush_user_cache_all
@@ -323,8 +347,8 @@ ENTRY(arm1020e_cache_fns)
.long arm1020e_coherent_kern_range
.long arm1020e_coherent_user_range
.long arm1020e_flush_kern_dcache_area
- .long arm1020e_dma_inv_range
- .long arm1020e_dma_clean_range
+ .long arm1020e_dma_map_area
+ .long arm1020e_dma_unmap_area
.long arm1020e_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 20a5b1b31a70..ce13e4a827de 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -247,7 +247,7 @@ ENTRY(arm1022_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm1022_dma_inv_range)
+arm1022_dma_inv_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -273,7 +273,7 @@ ENTRY(arm1022_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm1022_dma_clean_range)
+arm1022_dma_clean_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -305,6 +305,30 @@ ENTRY(arm1022_dma_flush_range)
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1022_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm1022_dma_clean_range
+ bcs arm1022_dma_inv_range
+ b arm1022_dma_flush_range
+ENDPROC(arm1022_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1022_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm1022_dma_unmap_area)
+
ENTRY(arm1022_cache_fns)
.long arm1022_flush_kern_cache_all
.long arm1022_flush_user_cache_all
@@ -312,8 +336,8 @@ ENTRY(arm1022_cache_fns)
.long arm1022_coherent_kern_range
.long arm1022_coherent_user_range
.long arm1022_flush_kern_dcache_area
- .long arm1022_dma_inv_range
- .long arm1022_dma_clean_range
+ .long arm1022_dma_map_area
+ .long arm1022_dma_unmap_area
.long arm1022_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 96aedb10fcc4..636672a29c6d 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -241,7 +241,7 @@ ENTRY(arm1026_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm1026_dma_inv_range)
+arm1026_dma_inv_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
tst r0, #CACHE_DLINESIZE - 1
@@ -267,7 +267,7 @@ ENTRY(arm1026_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm1026_dma_clean_range)
+arm1026_dma_clean_range:
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_DISABLE
bic r0, r0, #CACHE_DLINESIZE - 1
@@ -299,6 +299,30 @@ ENTRY(arm1026_dma_flush_range)
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1026_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm1026_dma_clean_range
+ bcs arm1026_dma_inv_range
+ b arm1026_dma_flush_range
+ENDPROC(arm1026_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm1026_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm1026_dma_unmap_area)
+
ENTRY(arm1026_cache_fns)
.long arm1026_flush_kern_cache_all
.long arm1026_flush_user_cache_all
@@ -306,8 +330,8 @@ ENTRY(arm1026_cache_fns)
.long arm1026_coherent_kern_range
.long arm1026_coherent_user_range
.long arm1026_flush_kern_dcache_area
- .long arm1026_dma_inv_range
- .long arm1026_dma_clean_range
+ .long arm1026_dma_map_area
+ .long arm1026_dma_unmap_area
.long arm1026_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 471669e2d7cb..8be81992645d 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -239,7 +239,7 @@ ENTRY(arm920_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm920_dma_inv_range)
+arm920_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -262,7 +262,7 @@ ENTRY(arm920_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm920_dma_clean_range)
+arm920_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -288,6 +288,30 @@ ENTRY(arm920_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm920_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm920_dma_clean_range
+ bcs arm920_dma_inv_range
+ b arm920_dma_flush_range
+ENDPROC(arm920_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm920_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm920_dma_unmap_area)
+
ENTRY(arm920_cache_fns)
.long arm920_flush_kern_cache_all
.long arm920_flush_user_cache_all
@@ -295,8 +319,8 @@ ENTRY(arm920_cache_fns)
.long arm920_coherent_kern_range
.long arm920_coherent_user_range
.long arm920_flush_kern_dcache_area
- .long arm920_dma_inv_range
- .long arm920_dma_clean_range
+ .long arm920_dma_map_area
+ .long arm920_dma_unmap_area
.long arm920_dma_flush_range
#endif
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index ee111b00fa41..c0ff8e4b1074 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -241,7 +241,7 @@ ENTRY(arm922_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm922_dma_inv_range)
+arm922_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -264,7 +264,7 @@ ENTRY(arm922_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm922_dma_clean_range)
+arm922_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -290,6 +290,30 @@ ENTRY(arm922_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm922_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm922_dma_clean_range
+ bcs arm922_dma_inv_range
+ b arm922_dma_flush_range
+ENDPROC(arm922_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm922_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm922_dma_unmap_area)
+
ENTRY(arm922_cache_fns)
.long arm922_flush_kern_cache_all
.long arm922_flush_user_cache_all
@@ -297,8 +321,8 @@ ENTRY(arm922_cache_fns)
.long arm922_coherent_kern_range
.long arm922_coherent_user_range
.long arm922_flush_kern_dcache_area
- .long arm922_dma_inv_range
- .long arm922_dma_clean_range
+ .long arm922_dma_map_area
+ .long arm922_dma_unmap_area
.long arm922_dma_flush_range
#endif
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 8deb5bde58e4..3c6cffe400f6 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -283,7 +283,7 @@ ENTRY(arm925_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm925_dma_inv_range)
+arm925_dma_inv_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -308,7 +308,7 @@ ENTRY(arm925_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm925_dma_clean_range)
+arm925_dma_clean_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -341,6 +341,30 @@ ENTRY(arm925_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm925_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm925_dma_clean_range
+ bcs arm925_dma_inv_range
+ b arm925_dma_flush_range
+ENDPROC(arm925_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm925_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm925_dma_unmap_area)
+
ENTRY(arm925_cache_fns)
.long arm925_flush_kern_cache_all
.long arm925_flush_user_cache_all
@@ -348,8 +372,8 @@ ENTRY(arm925_cache_fns)
.long arm925_coherent_kern_range
.long arm925_coherent_user_range
.long arm925_flush_kern_dcache_area
- .long arm925_dma_inv_range
- .long arm925_dma_clean_range
+ .long arm925_dma_map_area
+ .long arm925_dma_unmap_area
.long arm925_dma_flush_range
ENTRY(cpu_arm925_dcache_clean_area)
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 64db6e275a44..75b707c9cce1 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -246,7 +246,7 @@ ENTRY(arm926_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(arm926_dma_inv_range)
+arm926_dma_inv_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -271,7 +271,7 @@ ENTRY(arm926_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(arm926_dma_clean_range)
+arm926_dma_clean_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -304,6 +304,30 @@ ENTRY(arm926_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm926_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm926_dma_clean_range
+ bcs arm926_dma_inv_range
+ b arm926_dma_flush_range
+ENDPROC(arm926_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm926_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm926_dma_unmap_area)
+
ENTRY(arm926_cache_fns)
.long arm926_flush_kern_cache_all
.long arm926_flush_user_cache_all
@@ -311,8 +335,8 @@ ENTRY(arm926_cache_fns)
.long arm926_coherent_kern_range
.long arm926_coherent_user_range
.long arm926_flush_kern_dcache_area
- .long arm926_dma_inv_range
- .long arm926_dma_clean_range
+ .long arm926_dma_map_area
+ .long arm926_dma_unmap_area
.long arm926_dma_flush_range
ENTRY(cpu_arm926_dcache_clean_area)
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 8196b9f401fb..1af1657819eb 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -171,7 +171,7 @@ ENTRY(arm940_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(arm940_dma_inv_range)
+arm940_dma_inv_range:
mov ip, #0
mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
@@ -192,7 +192,7 @@ ENTRY(arm940_dma_inv_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(arm940_dma_clean_range)
+arm940_dma_clean_range:
ENTRY(cpu_arm940_dcache_clean_area)
mov ip, #0
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
@@ -233,6 +233,30 @@ ENTRY(arm940_dma_flush_range)
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm940_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm940_dma_clean_range
+ bcs arm940_dma_inv_range
+ b arm940_dma_flush_range
+ENDPROC(arm940_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm940_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm940_dma_unmap_area)
+
ENTRY(arm940_cache_fns)
.long arm940_flush_kern_cache_all
.long arm940_flush_user_cache_all
@@ -240,8 +264,8 @@ ENTRY(arm940_cache_fns)
.long arm940_coherent_kern_range
.long arm940_coherent_user_range
.long arm940_flush_kern_dcache_area
- .long arm940_dma_inv_range
- .long arm940_dma_clean_range
+ .long arm940_dma_map_area
+ .long arm940_dma_unmap_area
.long arm940_dma_flush_range
__INIT
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index 9a951239c86c..1664b6aaff79 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -215,7 +215,7 @@ ENTRY(arm946_flush_kern_dcache_area)
* - end - virtual end address
* (same as arm926)
*/
-ENTRY(arm946_dma_inv_range)
+arm946_dma_inv_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -240,7 +240,7 @@ ENTRY(arm946_dma_inv_range)
*
* (same as arm926)
*/
-ENTRY(arm946_dma_clean_range)
+arm946_dma_clean_range:
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -275,6 +275,30 @@ ENTRY(arm946_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm946_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq arm946_dma_clean_range
+ bcs arm946_dma_inv_range
+ b arm946_dma_flush_range
+ENDPROC(arm946_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(arm946_dma_unmap_area)
+ mov pc, lr
+ENDPROC(arm946_dma_unmap_area)
+
ENTRY(arm946_cache_fns)
.long arm946_flush_kern_cache_all
.long arm946_flush_user_cache_all
@@ -282,8 +306,8 @@ ENTRY(arm946_cache_fns)
.long arm946_coherent_kern_range
.long arm946_coherent_user_range
.long arm946_flush_kern_dcache_area
- .long arm946_dma_inv_range
- .long arm946_dma_clean_range
+ .long arm946_dma_map_area
+ .long arm946_dma_unmap_area
.long arm946_dma_flush_range
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index dbc39383e66a..53e632343849 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -274,7 +274,7 @@ ENTRY(feroceon_range_flush_kern_dcache_area)
* (same as v4wb)
*/
.align 5
-ENTRY(feroceon_dma_inv_range)
+feroceon_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
bic r0, r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -288,7 +288,7 @@ ENTRY(feroceon_dma_inv_range)
mov pc, lr
.align 5
-ENTRY(feroceon_range_dma_inv_range)
+feroceon_range_dma_inv_range:
mrs r2, cpsr
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -314,7 +314,7 @@ ENTRY(feroceon_range_dma_inv_range)
* (same as v4wb)
*/
.align 5
-ENTRY(feroceon_dma_clean_range)
+feroceon_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -324,7 +324,7 @@ ENTRY(feroceon_dma_clean_range)
mov pc, lr
.align 5
-ENTRY(feroceon_range_dma_clean_range)
+feroceon_range_dma_clean_range:
mrs r2, cpsr
cmp r1, r0
subne r1, r1, #1 @ top address is inclusive
@@ -367,6 +367,44 @@ ENTRY(feroceon_range_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(feroceon_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq feroceon_dma_clean_range
+ bcs feroceon_dma_inv_range
+ b feroceon_dma_flush_range
+ENDPROC(feroceon_dma_map_area)
+
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(feroceon_range_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq feroceon_range_dma_clean_range
+ bcs feroceon_range_dma_inv_range
+ b feroceon_range_dma_flush_range
+ENDPROC(feroceon_range_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(feroceon_dma_unmap_area)
+ mov pc, lr
+ENDPROC(feroceon_dma_unmap_area)
+
ENTRY(feroceon_cache_fns)
.long feroceon_flush_kern_cache_all
.long feroceon_flush_user_cache_all
@@ -374,8 +412,8 @@ ENTRY(feroceon_cache_fns)
.long feroceon_coherent_kern_range
.long feroceon_coherent_user_range
.long feroceon_flush_kern_dcache_area
- .long feroceon_dma_inv_range
- .long feroceon_dma_clean_range
+ .long feroceon_dma_map_area
+ .long feroceon_dma_unmap_area
.long feroceon_dma_flush_range
ENTRY(feroceon_range_cache_fns)
@@ -385,8 +423,8 @@ ENTRY(feroceon_range_cache_fns)
.long feroceon_coherent_kern_range
.long feroceon_coherent_user_range
.long feroceon_range_flush_kern_dcache_area
- .long feroceon_range_dma_inv_range
- .long feroceon_range_dma_clean_range
+ .long feroceon_range_dma_map_area
+ .long feroceon_dma_unmap_area
.long feroceon_range_dma_flush_range
.align 5
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index 9674d36cc97d..caa31154e7db 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -218,7 +218,7 @@ ENTRY(mohawk_flush_kern_dcache_area)
*
* (same as v4wb)
*/
-ENTRY(mohawk_dma_inv_range)
+mohawk_dma_inv_range:
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
tst r1, #CACHE_DLINESIZE - 1
@@ -241,7 +241,7 @@ ENTRY(mohawk_dma_inv_range)
*
* (same as v4wb)
*/
-ENTRY(mohawk_dma_clean_range)
+mohawk_dma_clean_range:
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
@@ -268,6 +268,30 @@ ENTRY(mohawk_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(mohawk_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq mohawk_dma_clean_range
+ bcs mohawk_dma_inv_range
+ b mohawk_dma_flush_range
+ENDPROC(mohawk_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(mohawk_dma_unmap_area)
+ mov pc, lr
+ENDPROC(mohawk_dma_unmap_area)
+
ENTRY(mohawk_cache_fns)
.long mohawk_flush_kern_cache_all
.long mohawk_flush_user_cache_all
@@ -275,8 +299,8 @@ ENTRY(mohawk_cache_fns)
.long mohawk_coherent_kern_range
.long mohawk_coherent_user_range
.long mohawk_flush_kern_dcache_area
- .long mohawk_dma_inv_range
- .long mohawk_dma_clean_range
+ .long mohawk_dma_map_area
+ .long mohawk_dma_unmap_area
.long mohawk_dma_flush_range
ENTRY(cpu_mohawk_dcache_clean_area)
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 96456f548798..e5797f1c1db7 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -257,7 +257,7 @@ ENTRY(xsc3_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(xsc3_dma_inv_range)
+xsc3_dma_inv_range:
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line
@@ -278,7 +278,7 @@ ENTRY(xsc3_dma_inv_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(xsc3_dma_clean_range)
+xsc3_dma_clean_range:
bic r0, r0, #CACHELINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
add r0, r0, #CACHELINESIZE
@@ -304,6 +304,30 @@ ENTRY(xsc3_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ data write barrier
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(xsc3_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq xsc3_dma_clean_range
+ bcs xsc3_dma_inv_range
+ b xsc3_dma_flush_range
+ENDPROC(xsc3_dma_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(xsc3_dma_unmap_area)
+ mov pc, lr
+ENDPROC(xsc3_dma_unmap_area)
+
ENTRY(xsc3_cache_fns)
.long xsc3_flush_kern_cache_all
.long xsc3_flush_user_cache_all
@@ -311,8 +335,8 @@ ENTRY(xsc3_cache_fns)
.long xsc3_coherent_kern_range
.long xsc3_coherent_user_range
.long xsc3_flush_kern_dcache_area
- .long xsc3_dma_inv_range
- .long xsc3_dma_clean_range
+ .long xsc3_dma_map_area
+ .long xsc3_dma_unmap_area
.long xsc3_dma_flush_range
ENTRY(cpu_xsc3_dcache_clean_area)
@@ -407,6 +431,13 @@ __xsc3_setup:
adr r5, xsc3_crval
ldmia r5, {r5, r6}
+
+#ifdef CONFIG_CACHE_XSC3L2
+ mrc p15, 1, r0, c0, c0, 1 @ get L2 present information
+ ands r0, r0, #0xf8
+ orrne r6, r6, #(1 << 26) @ enable L2 if present
+#endif
+
mrc p15, 0, r0, c1, c0, 0 @ get control register
bic r0, r0, r5 @ ..V. ..R. .... ..A.
orr r0, r0, r6 @ ..VI Z..S .... .C.M (mmu)
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 93df47265f2d..63037e2162f2 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -315,7 +315,7 @@ ENTRY(xscale_flush_kern_dcache_area)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(xscale_dma_inv_range)
+xscale_dma_inv_range:
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -336,7 +336,7 @@ ENTRY(xscale_dma_inv_range)
* - start - virtual start address
* - end - virtual end address
*/
-ENTRY(xscale_dma_clean_range)
+xscale_dma_clean_range:
bic r0, r0, #CACHELINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHELINESIZE
@@ -363,6 +363,43 @@ ENTRY(xscale_dma_flush_range)
mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
mov pc, lr
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(xscale_dma_map_area)
+ add r1, r1, r0
+ cmp r2, #DMA_TO_DEVICE
+ beq xscale_dma_clean_range
+ bcs xscale_dma_inv_range
+ b xscale_dma_flush_range
+ENDPROC(xscale_dma_map_area)
+
+/*
+ * dma_map_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(xscale_dma_a0_map_area)
+ add r1, r1, r0
+ teq r2, #DMA_TO_DEVICE
+ beq xscale_dma_clean_range
+ b xscale_dma_flush_range
+ENDPROC(xscsale_dma_a0_map_area)
+
+/*
+ * dma_unmap_area(start, size, dir)
+ * - start - kernel virtual start address
+ * - size - size of region
+ * - dir - DMA direction
+ */
+ENTRY(xscale_dma_unmap_area)
+ mov pc, lr
+ENDPROC(xscale_dma_unmap_area)
+
ENTRY(xscale_cache_fns)
.long xscale_flush_kern_cache_all
.long xscale_flush_user_cache_all
@@ -370,8 +407,8 @@ ENTRY(xscale_cache_fns)
.long xscale_coherent_kern_range
.long xscale_coherent_user_range
.long xscale_flush_kern_dcache_area
- .long xscale_dma_inv_range
- .long xscale_dma_clean_range
+ .long xscale_dma_map_area
+ .long xscale_dma_unmap_area
.long xscale_dma_flush_range
/*
@@ -394,8 +431,8 @@ ENTRY(xscale_80200_A0_A1_cache_fns)
.long xscale_coherent_kern_range
.long xscale_coherent_user_range
.long xscale_flush_kern_dcache_area
- .long xscale_dma_flush_range
- .long xscale_dma_clean_range
+ .long xscale_dma_a0_map_area
+ .long xscale_dma_unmap_area
.long xscale_dma_flush_range
ENTRY(cpu_xscale_dcache_clean_area)
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index a26a605b73bd..0cb1848bd876 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -40,7 +40,6 @@ ENTRY(v7wbi_flush_user_tlb_range)
asid r3, r3 @ mask ASID
orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
mov r1, r1, lsl #PAGE_SHIFT
- vma_vm_flags r2, r2 @ get vma->vm_flags
1:
#ifdef CONFIG_SMP
mcr p15, 0, r0, c8, c3, 1 @ TLB invalidate U MVA (shareable)
diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c
index ed0bbece0d61..e15bc17db90b 100644
--- a/arch/arm/plat-iop/io.c
+++ b/arch/arm/plat-iop/io.c
@@ -34,7 +34,8 @@ void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie);
break;
default:
- retval = __arm_ioremap(cookie, size, mtype);
+ retval = __arm_ioremap_caller(cookie, size, mtype,
+ __builtin_return_address(0));
}
return retval;
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx25.h b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
index 810c47f56e77..9af494f0ab3d 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx25.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
@@ -58,19 +58,19 @@
#define MX25_PAD_A18__A18 IOMUX_PAD(0x23c, 0x020, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A18__GPIO_2_4 IOMUX_PAD(0x23c, 0x020, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A18__FEC_COL IOMUX_PAD(0x23c, 0x020, 0x17, 0x504, 0, NO_PAD_CTL)
+#define MX25_PAD_A18__FEC_COL IOMUX_PAD(0x23c, 0x020, 0x17, 0x504, 0, NO_PAD_CTRL)
#define MX25_PAD_A19__A19 IOMUX_PAD(0x240, 0x024, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A19__FEC_RX_ER IOMUX_PAD(0x240, 0x024, 0x17, 0x518, 0, NO_PAD_CTL)
+#define MX25_PAD_A19__FEC_RX_ER IOMUX_PAD(0x240, 0x024, 0x17, 0x518, 0, NO_PAD_CTRL)
#define MX25_PAD_A19__GPIO_2_5 IOMUX_PAD(0x240, 0x024, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A20__A20 IOMUX_PAD(0x244, 0x028, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A20__GPIO_2_6 IOMUX_PAD(0x244, 0x028, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A20__FEC_RDATA2 IOMUX_PAD(0x244, 0x028, 0x17, 0x50c, 0, NO_PAD_CTL)
+#define MX25_PAD_A20__FEC_RDATA2 IOMUX_PAD(0x244, 0x028, 0x17, 0x50c, 0, NO_PAD_CTRL)
#define MX25_PAD_A21__A21 IOMUX_PAD(0x248, 0x02c, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A21__GPIO_2_7 IOMUX_PAD(0x248, 0x02c, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A21__FEC_RDATA3 IOMUX_PAD(0x248, 0x02c, 0x17, 0x510, 0, NO_PAD_CTL)
+#define MX25_PAD_A21__FEC_RDATA3 IOMUX_PAD(0x248, 0x02c, 0x17, 0x510, 0, NO_PAD_CTRL)
#define MX25_PAD_A22__A22 IOMUX_PAD(0x000, 0x030, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A22__GPIO_2_8 IOMUX_PAD(0x000, 0x030, 0x15, 0, 0, NO_PAD_CTRL)
@@ -80,11 +80,11 @@
#define MX25_PAD_A24__A24 IOMUX_PAD(0x250, 0x038, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A24__GPIO_2_10 IOMUX_PAD(0x250, 0x038, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A24__FEC_RX_CLK IOMUX_PAD(0x250, 0x038, 0x17, 0x514, 0, NO_PAD_CTL)
+#define MX25_PAD_A24__FEC_RX_CLK IOMUX_PAD(0x250, 0x038, 0x17, 0x514, 0, NO_PAD_CTRL)
#define MX25_PAD_A25__A25 IOMUX_PAD(0x254, 0x03c, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_A25__GPIO_2_11 IOMUX_PAD(0x254, 0x03c, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_A25__FEC_CRS IOMUX_PAD(0x254, 0x03c, 0x17, 0x508, 0, NO_PAD_CTL)
+#define MX25_PAD_A25__FEC_CRS IOMUX_PAD(0x254, 0x03c, 0x17, 0x508, 0, NO_PAD_CTRL)
#define MX25_PAD_EB0__EB0 IOMUX_PAD(0x258, 0x040, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_EB0__AUD4_TXD IOMUX_PAD(0x258, 0x040, 0x14, 0x464, 0, NO_PAD_CTRL)
@@ -112,7 +112,7 @@
#define MX25_PAD_CS5__UART5_RTS IOMUX_PAD(0x268, 0x058, 0x13, 0x574, 0, NO_PAD_CTRL)
#define MX25_PAD_CS5__GPIO_3_21 IOMUX_PAD(0x268, 0x058, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_NF_CE0__NF_CE0 IOMUX_PAD(0x26c, 0x05c, 0x10, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_NF_CE0__NF_CE0 IOMUX_PAD(0x26c, 0x05c, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_NF_CE0__GPIO_3_22 IOMUX_PAD(0x26c, 0x05c, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_ECB__ECB IOMUX_PAD(0x270, 0x060, 0x10, 0, 0, NO_PAD_CTRL)
@@ -229,28 +229,28 @@
#define MX25_PAD_LD7__GPIO_1_21 IOMUX_PAD(0x2dc, 0x0e4, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_LD8__LD8 IOMUX_PAD(0x2e0, 0x0e8, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD8__FEC_TX_ERR IOMUX_PAD(0x2e0, 0x0e8, 0x15, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_LD8__FEC_TX_ERR IOMUX_PAD(0x2e0, 0x0e8, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_LD9__LD9 IOMUX_PAD(0x2e4, 0x0ec, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD9__FEC_COL IOMUX_PAD(0x2e4, 0x0ec, 0x15, 0x504, 1, NO_PAD_CTL)
+#define MX25_PAD_LD9__FEC_COL IOMUX_PAD(0x2e4, 0x0ec, 0x15, 0x504, 1, NO_PAD_CTRL)
#define MX25_PAD_LD10__LD10 IOMUX_PAD(0x2e8, 0x0f0, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD10__FEC_RX_ER IOMUX_PAD(0x2e8, 0x0f0, 0x15, 0x518, 1, NO_PAD_CTL)
+#define MX25_PAD_LD10__FEC_RX_ER IOMUX_PAD(0x2e8, 0x0f0, 0x15, 0x518, 1, NO_PAD_CTRL)
#define MX25_PAD_LD11__LD11 IOMUX_PAD(0x2ec, 0x0f4, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD11__FEC_RDATA2 IOMUX_PAD(0x2ec, 0x0f4, 0x15, 0x50c, 1, NO_PAD_CTL)
+#define MX25_PAD_LD11__FEC_RDATA2 IOMUX_PAD(0x2ec, 0x0f4, 0x15, 0x50c, 1, NO_PAD_CTRL)
#define MX25_PAD_LD12__LD12 IOMUX_PAD(0x2f0, 0x0f8, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD12__FEC_RDATA3 IOMUX_PAD(0x2f0, 0x0f8, 0x15, 0x510, 1, NO_PAD_CTL)
+#define MX25_PAD_LD12__FEC_RDATA3 IOMUX_PAD(0x2f0, 0x0f8, 0x15, 0x510, 1, NO_PAD_CTRL)
#define MX25_PAD_LD13__LD13 IOMUX_PAD(0x2f4, 0x0fc, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD13__FEC_TDATA2 IOMUX_PAD(0x2f4, 0x0fc, 0x15, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_LD13__FEC_TDATA2 IOMUX_PAD(0x2f4, 0x0fc, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_LD14__LD14 IOMUX_PAD(0x2f8, 0x100, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD14__FEC_TDATA3 IOMUX_PAD(0x2f8, 0x100, 0x15, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_LD14__FEC_TDATA3 IOMUX_PAD(0x2f8, 0x100, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_LD15__LD15 IOMUX_PAD(0x2fc, 0x104, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_LD15__FEC_RX_CLK IOMUX_PAD(0x2fc, 0x104, 0x15, 0x514, 1, NO_PAD_CTL)
+#define MX25_PAD_LD15__FEC_RX_CLK IOMUX_PAD(0x2fc, 0x104, 0x15, 0x514, 1, NO_PAD_CTRL)
#define MX25_PAD_HSYNC__HSYNC IOMUX_PAD(0x300, 0x108, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_HSYNC__GPIO_1_22 IOMUX_PAD(0x300, 0x108, 0x15, 0, 0, NO_PAD_CTRL)
@@ -265,7 +265,7 @@
#define MX25_PAD_OE_ACD__GPIO_1_25 IOMUX_PAD(0x30c, 0x114, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CONTRAST__CONTRAST IOMUX_PAD(0x310, 0x118, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_CONTRAST__FEC_CRS IOMUX_PAD(0x310, 0x118, 0x15, 0x508, 1, NO_PAD_CTL)
+#define MX25_PAD_CONTRAST__FEC_CRS IOMUX_PAD(0x310, 0x118, 0x15, 0x508, 1, NO_PAD_CTRL)
#define MX25_PAD_PWM__PWM IOMUX_PAD(0x314, 0x11c, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_PWM__GPIO_1_26 IOMUX_PAD(0x314, 0x11c, 0x15, 0, 0, NO_PAD_CTRL)
@@ -354,19 +354,19 @@
#define MX25_PAD_UART2_TXD__GPIO_4_27 IOMUX_PAD(0x37c, 0x184, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_UART2_RTS__UART2_RTS IOMUX_PAD(0x380, 0x188, 0x10, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_UART2_RTS__FEC_COL IOMUX_PAD(0x380, 0x188, 0x12, 0x504, 2, NO_PAD_CTL)
+#define MX25_PAD_UART2_RTS__FEC_COL IOMUX_PAD(0x380, 0x188, 0x12, 0x504, 2, NO_PAD_CTRL)
#define MX25_PAD_UART2_RTS__GPIO_4_28 IOMUX_PAD(0x380, 0x188, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_UART2_CTS__FEC_RX_ER IOMUX_PAD(0x384, 0x18c, 0x12, 0x518, 2, NO_PAD_CTL)
+#define MX25_PAD_UART2_CTS__FEC_RX_ER IOMUX_PAD(0x384, 0x18c, 0x12, 0x518, 2, NO_PAD_CTRL)
#define MX25_PAD_UART2_CTS__UART2_CTS IOMUX_PAD(0x384, 0x18c, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_UART2_CTS__GPIO_4_29 IOMUX_PAD(0x384, 0x18c, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x388, 0x190, 0x10, 0, 0, PAD_CTL_PUS_47K_UP)
-#define MX25_PAD_SD1_CMD__FEC_RDATA2 IOMUX_PAD(0x388, 0x190, 0x12, 0x50c, 2, NO_PAD_CTL)
+#define MX25_PAD_SD1_CMD__FEC_RDATA2 IOMUX_PAD(0x388, 0x190, 0x12, 0x50c, 2, NO_PAD_CTRL)
#define MX25_PAD_SD1_CMD__GPIO_2_23 IOMUX_PAD(0x388, 0x190, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x38c, 0x194, 0x10, 0, 0, PAD_CTL_PUS_47K_UP)
-#define MX25_PAD_SD1_CLK__FEC_RDATA3 IOMUX_PAD(0x38c, 0x194, 0x12, 0x510, 2, NO_PAD_CTL)
+#define MX25_PAD_SD1_CLK__FEC_RDATA3 IOMUX_PAD(0x38c, 0x194, 0x12, 0x510, 2, NO_PAD_CTRL)
#define MX25_PAD_SD1_CLK__GPIO_2_24 IOMUX_PAD(0x38c, 0x194, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(0x390, 0x198, 0x10, 0, 0, PAD_CTL_PUS_47K_UP)
@@ -377,11 +377,11 @@
#define MX25_PAD_SD1_DATA1__GPIO_2_26 IOMUX_PAD(0x394, 0x19c, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(0x398, 0x1a0, 0x10, 0, 0, PAD_CTL_PUS_47K_UP)
-#define MX25_PAD_SD1_DATA2__FEC_RX_CLK IOMUX_PAD(0x398, 0x1a0, 0x15, 0x514, 2, NO_PAD_CTL)
+#define MX25_PAD_SD1_DATA2__FEC_RX_CLK IOMUX_PAD(0x398, 0x1a0, 0x15, 0x514, 2, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA2__GPIO_2_27 IOMUX_PAD(0x398, 0x1a0, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x39c, 0x1a4, 0x10, 0, 0, PAD_CTL_PUS_47K_UP)
-#define MX25_PAD_SD1_DATA3__FEC_CRS IOMUX_PAD(0x39c, 0x1a4, 0x10, 0x508, 2, NO_PAD_CTL)
+#define MX25_PAD_SD1_DATA3__FEC_CRS IOMUX_PAD(0x39c, 0x1a4, 0x10, 0x508, 2, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA3__GPIO_2_28 IOMUX_PAD(0x39c, 0x1a4, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, PAD_CTL_PKE)
@@ -410,7 +410,7 @@
#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
#define MX25_PAD_KPP_COL3__GPIO_3_4 IOMUX_PAD(0x3bc, 0x1c4, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(0x3c0, 0x1c8, 0x10, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(0x3c0, 0x1c8, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_FEC_MDC__AUD4_TXD IOMUX_PAD(0x3c0, 0x1c8, 0x12, 0x464, 1, NO_PAD_CTRL)
#define MX25_PAD_FEC_MDC__GPIO_3_5 IOMUX_PAD(0x3c0, 0x1c8, 0x15, 0, 0, NO_PAD_CTRL)
@@ -418,23 +418,23 @@
#define MX25_PAD_FEC_MDIO__AUD4_RXD IOMUX_PAD(0x3c4, 0x1cc, 0x12, 0x460, 1, NO_PAD_CTRL)
#define MX25_PAD_FEC_MDIO__GPIO_3_6 IOMUX_PAD(0x3c4, 0x1cc, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_TDATA0__FEC_TDATA0 IOMUX_PAD(0x3c8, 0x1d0, 0x10, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_FEC_TDATA0__FEC_TDATA0 IOMUX_PAD(0x3c8, 0x1d0, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_FEC_TDATA0__GPIO_3_7 IOMUX_PAD(0x3c8, 0x1d0, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_TDATA1__FEC_TDATA1 IOMUX_PAD(0x3cc, 0x1d4, 0x10, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_FEC_TDATA1__FEC_TDATA1 IOMUX_PAD(0x3cc, 0x1d4, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_FEC_TDATA1__AUD4_TXFS IOMUX_PAD(0x3cc, 0x1d4, 0x12, 0x474, 1, NO_PAD_CTRL)
#define MX25_PAD_FEC_TDATA1__GPIO_3_8 IOMUX_PAD(0x3cc, 0x1d4, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_TX_EN__FEC_TX_EN IOMUX_PAD(0x3d0, 0x1d8, 0x10, 0, 0, NO_PAD_CTL)
+#define MX25_PAD_FEC_TX_EN__FEC_TX_EN IOMUX_PAD(0x3d0, 0x1d8, 0x10, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_FEC_TX_EN__GPIO_3_9 IOMUX_PAD(0x3d0, 0x1d8, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_RDATA0__FEC_RDATA0 IOMUX_PAD(0x3d4, 0x1dc, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTL)
+#define MX25_PAD_FEC_RDATA0__FEC_RDATA0 IOMUX_PAD(0x3d4, 0x1dc, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTRL)
#define MX25_PAD_FEC_RDATA0__GPIO_3_10 IOMUX_PAD(0x3d4, 0x1dc, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_RDATA1__FEC_RDATA1 IOMUX_PAD(0x3d8, 0x1e0, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTL)
+#define MX25_PAD_FEC_RDATA1__FEC_RDATA1 IOMUX_PAD(0x3d8, 0x1e0, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTRL)
#define MX25_PAD_FEC_RDATA1__GPIO_3_11 IOMUX_PAD(0x3d8, 0x1e0, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_FEC_RX_DV__FEC_RX_DV IOMUX_PAD(0x3dc, 0x1e4, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTL)
+#define MX25_PAD_FEC_RX_DV__FEC_RX_DV IOMUX_PAD(0x3dc, 0x1e4, 0x10, 0, 0, PAD_CTL_PUS_100K_DOWN | NO_PAD_CTRL)
#define MX25_PAD_FEC_RX_DV__CAN2_RX IOMUX_PAD(0x3dc, 0x1e4, 0x14, 0x484, 0, PAD_CTL_PUS_22K_UP)
#define MX25_PAD_FEC_RX_DV__GPIO_3_12 IOMUX_PAD(0x3dc, 0x1e4, 0x15, 0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/mx25.h b/arch/arm/plat-mxc/include/mach/mx25.h
index 91e738144804..854e2dc58481 100644
--- a/arch/arm/plat-mxc/include/mach/mx25.h
+++ b/arch/arm/plat-mxc/include/mach/mx25.h
@@ -41,4 +41,8 @@
#define UART1_BASE_ADDR 0x43f90000
#define UART2_BASE_ADDR 0x43f94000
+#define MX25_FEC_BASE_ADDR 0x50038000
+
+#define MX25_INT_FEC 57
+
#endif /* __MACH_MX25_H__ */
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 89cafc937249..d9f8c844c385 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -36,10 +36,6 @@ static struct clk_functions *arch_clock;
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
-/* This functions is moved to arch/arm/common/clkdev.c. For OMAP4 since
- * clock framework is not up , it is defined here to avoid rework in
- * every driver. Also dummy prcm reset function is added */
-
int clk_enable(struct clk *clk)
{
unsigned long flags;
@@ -305,7 +301,6 @@ void clk_enable_init_clocks(void)
clk_enable(clkp);
}
}
-EXPORT_SYMBOL(clk_enable_init_clocks);
/*
* Low level helpers
@@ -334,7 +329,16 @@ void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
arch_clock->clk_init_cpufreq_table(table);
spin_unlock_irqrestore(&clockfw_lock, flags);
}
-EXPORT_SYMBOL(clk_init_cpufreq_table);
+
+void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (arch_clock->clk_exit_cpufreq_table)
+ arch_clock->clk_exit_cpufreq_table(table);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+}
#endif
/*-------------------------------------------------------------------------*/
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index f8ddbdd8b076..6d3d33360056 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -134,6 +134,7 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
+ clk_exit_cpufreq_table(&freq_table);
clk_put(mpu_clk);
return 0;
}
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 09d82b3c66ce..728c64204184 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1183,7 +1183,7 @@ void omap_dma_unlink_lch(int lch_head, int lch_queue)
}
if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) ||
- (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) {
+ (dma_chan[lch_queue].flags & OMAP_DMA_ACTIVE)) {
printk(KERN_ERR "omap_dma: You need to stop the DMA channels "
"before unlinking\n");
dump_stack();
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 04846811d0aa..d17620c50c28 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -192,6 +192,7 @@ struct gpio_bank {
u32 saved_risingdetect;
#endif
u32 level_mask;
+ u32 toggle_mask;
spinlock_t lock;
struct gpio_chip chip;
struct clk *dbck;
@@ -749,6 +750,44 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
}
#endif
+/*
+ * This only applies to chips that can't do both rising and falling edge
+ * detection at once. For all other chips, this function is a noop.
+ */
+static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
+{
+ void __iomem *reg = bank->base;
+ u32 l = 0;
+
+ switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
+ case METHOD_MPUIO:
+ reg += OMAP_MPUIO_GPIO_INT_EDGE;
+ break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
+ case METHOD_GPIO_1510:
+ reg += OMAP1510_GPIO_INT_CONTROL;
+ break;
+#endif
+#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
+ case METHOD_GPIO_7XX:
+ reg += OMAP7XX_GPIO_INT_CONTROL;
+ break;
+#endif
+ default:
+ return;
+ }
+
+ l = __raw_readl(reg);
+ if ((l >> gpio) & 1)
+ l &= ~(1 << gpio);
+ else
+ l |= 1 << gpio;
+
+ __raw_writel(l, reg);
+}
+
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
{
void __iomem *reg = bank->base;
@@ -759,6 +798,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_INT_EDGE;
l = __raw_readl(reg);
+ if (trigger & IRQ_TYPE_EDGE_BOTH)
+ bank->toggle_mask |= 1 << gpio;
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 1 << gpio;
else if (trigger & IRQ_TYPE_EDGE_FALLING)
@@ -771,6 +812,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_CONTROL;
l = __raw_readl(reg);
+ if (trigger & IRQ_TYPE_EDGE_BOTH)
+ bank->toggle_mask |= 1 << gpio;
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 1 << gpio;
else if (trigger & IRQ_TYPE_EDGE_FALLING)
@@ -803,6 +846,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_GPIO_7XX:
reg += OMAP7XX_GPIO_INT_CONTROL;
l = __raw_readl(reg);
+ if (trigger & IRQ_TYPE_EDGE_BOTH)
+ bank->toggle_mask |= 1 << gpio;
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 1 << gpio;
else if (trigger & IRQ_TYPE_EDGE_FALLING)
@@ -1072,7 +1117,7 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
*/
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
{
- unsigned long flags;
+ unsigned long uninitialized_var(flags);
switch (bank->method) {
#ifdef CONFIG_ARCH_OMAP16XX
@@ -1217,7 +1262,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
void __iomem *isr_reg = NULL;
u32 isr;
- unsigned int gpio_irq;
+ unsigned int gpio_irq, gpio_index;
struct gpio_bank *bank;
u32 retrigger = 0;
int unmasked = 0;
@@ -1284,9 +1329,23 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
gpio_irq = bank->virtual_irq_start;
for (; isr != 0; isr >>= 1, gpio_irq++) {
+ gpio_index = get_gpio_index(irq_to_gpio(gpio_irq));
+
if (!(isr & 1))
continue;
+#ifdef CONFIG_ARCH_OMAP1
+ /*
+ * Some chips can't respond to both rising and falling
+ * at the same time. If this irq was requested with
+ * both flags, we need to flip the ICR data for the IRQ
+ * to respond to the IRQ for the opposite direction.
+ * This will be indicated in the bank toggle_mask.
+ */
+ if (bank->toggle_mask & (1 << gpio_index))
+ _toggle_gpio_edge_triggering(bank, gpio_index);
+#endif
+
generic_handle_irq(gpio_irq);
}
}
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index 376ce18216ff..5cd622039da0 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -99,7 +99,6 @@ struct fb_info;
struct omap_backlight_config {
int default_intensity;
int (*set_power)(struct device *dev, int state);
- int (*check_fb)(struct fb_info *fb);
};
struct omap_fbmem_config {
diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h
index 309b6d1dccdb..94fe2a0ce40a 100644
--- a/arch/arm/plat-omap/include/plat/clock.h
+++ b/arch/arm/plat-omap/include/plat/clock.h
@@ -119,6 +119,7 @@ struct clk_functions {
void (*clk_disable_unused)(struct clk *clk);
#ifdef CONFIG_CPU_FREQ
void (*clk_init_cpufreq_table)(struct cpufreq_frequency_table **);
+ void (*clk_exit_cpufreq_table)(struct cpufreq_frequency_table **);
#endif
};
@@ -135,6 +136,7 @@ extern unsigned long followparent_recalc(struct clk *clk);
extern void clk_enable_init_clocks(void);
#ifdef CONFIG_CPU_FREQ
extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
+extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
#endif
extern const struct clkops clkops_null;
diff --git a/arch/arm/plat-omap/include/plat/control.h b/arch/arm/plat-omap/include/plat/control.h
index 2ae884378638..a745d62fad0d 100644
--- a/arch/arm/plat-omap/include/plat/control.h
+++ b/arch/arm/plat-omap/include/plat/control.h
@@ -147,7 +147,7 @@
#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194)
#define OMAP343X_CONTROL_DEBOBS(i) (OMAP2_CONTROL_GENERAL + 0x01B0 \
- + ((i) >> 1) * 4 + (!(i) & 1) * 2)
+ + ((i) >> 1) * 4 + (!((i) & 1)) * 2)
#define OMAP343X_CONTROL_PROG_IO0 (OMAP2_CONTROL_GENERAL + 0x01D4)
#define OMAP343X_CONTROL_PROG_IO1 (OMAP2_CONTROL_GENERAL + 0x01D8)
#define OMAP343X_CONTROL_DSS_DPLL_SPREADING (OMAP2_CONTROL_GENERAL + 0x01E0)
diff --git a/arch/arm/plat-omap/include/plat/flash.h b/arch/arm/plat-omap/include/plat/flash.h
new file mode 100644
index 000000000000..3e6327016b40
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/flash.h
@@ -0,0 +1,16 @@
+/*
+ * Flash support for OMAP1
+ *
+ * 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 __OMAP_FLASH_H
+#define __OMAP_FLASH_H
+
+#include <linux/mtd/map.h>
+
+extern void omap1_set_vpp(struct map_info *map, int enable);
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/io.h b/arch/arm/plat-omap/include/plat/io.h
index 7e5319f907d1..a3e7b471bcba 100644
--- a/arch/arm/plat-omap/include/plat/io.h
+++ b/arch/arm/plat-omap/include/plat/io.h
@@ -122,16 +122,21 @@
#define OMAP243X_SMS_VIRT (OMAP243X_SMS_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP243X_SMS_SIZE SZ_1M
-/* DSP */
-#define DSP_MEM_24XX_PHYS OMAP2420_DSP_MEM_BASE /* 0x58000000 */
-#define DSP_MEM_24XX_VIRT 0xe0000000
-#define DSP_MEM_24XX_SIZE 0x28000
-#define DSP_IPI_24XX_PHYS OMAP2420_DSP_IPI_BASE /* 0x59000000 */
-#define DSP_IPI_24XX_VIRT 0xe1000000
-#define DSP_IPI_24XX_SIZE SZ_4K
-#define DSP_MMU_24XX_PHYS OMAP2420_DSP_MMU_BASE /* 0x5a000000 */
-#define DSP_MMU_24XX_VIRT 0xe2000000
-#define DSP_MMU_24XX_SIZE SZ_4K
+/* 2420 IVA */
+#define DSP_MEM_2420_PHYS OMAP2420_DSP_MEM_BASE
+ /* 0x58000000 --> 0xfc100000 */
+#define DSP_MEM_2420_VIRT 0xfc100000
+#define DSP_MEM_2420_SIZE 0x28000
+#define DSP_IPI_2420_PHYS OMAP2420_DSP_IPI_BASE
+ /* 0x59000000 --> 0xfc128000 */
+#define DSP_IPI_2420_VIRT 0xfc128000
+#define DSP_IPI_2420_SIZE SZ_4K
+#define DSP_MMU_2420_PHYS OMAP2420_DSP_MMU_BASE
+ /* 0x5a000000 --> 0xfc129000 */
+#define DSP_MMU_2420_VIRT 0xfc129000
+#define DSP_MMU_2420_SIZE SZ_4K
+
+/* 2430 IVA2.1 - currently unmapped */
/*
* ----------------------------------------------------------------------------
@@ -182,16 +187,7 @@
#define OMAP343X_SDRC_VIRT (OMAP343X_SDRC_PHYS + OMAP2_L3_IO_OFFSET)
#define OMAP343X_SDRC_SIZE SZ_1M
-/* DSP */
-#define DSP_MEM_34XX_PHYS OMAP34XX_DSP_MEM_BASE /* 0x58000000 */
-#define DSP_MEM_34XX_VIRT 0xe0000000
-#define DSP_MEM_34XX_SIZE 0x28000
-#define DSP_IPI_34XX_PHYS OMAP34XX_DSP_IPI_BASE /* 0x59000000 */
-#define DSP_IPI_34XX_VIRT 0xe1000000
-#define DSP_IPI_34XX_SIZE SZ_4K
-#define DSP_MMU_34XX_PHYS OMAP34XX_DSP_MMU_BASE /* 0x5a000000 */
-#define DSP_MMU_34XX_VIRT 0xe2000000
-#define DSP_MMU_34XX_SIZE SZ_4K
+/* 3430 IVA - currently unmapped */
/*
* ----------------------------------------------------------------------------
diff --git a/arch/arm/plat-omap/include/plat/mux.h b/arch/arm/plat-omap/include/plat/mux.h
index 8f069cc80350..692c90e89ac3 100644
--- a/arch/arm/plat-omap/include/plat/mux.h
+++ b/arch/arm/plat-omap/include/plat/mux.h
@@ -183,6 +183,14 @@ enum omap7xx_index {
/* I2C */
I2C_7XX_SCL,
I2C_7XX_SDA,
+
+ /* SPI */
+ SPI_7XX_1,
+ SPI_7XX_2,
+ SPI_7XX_3,
+ SPI_7XX_4,
+ SPI_7XX_5,
+ SPI_7XX_6,
};
enum omap1xxx_index {
diff --git a/arch/arm/plat-omap/include/plat/omap7xx.h b/arch/arm/plat-omap/include/plat/omap7xx.h
index 53f52414b0e9..48e4757e1e30 100644
--- a/arch/arm/plat-omap/include/plat/omap7xx.h
+++ b/arch/arm/plat-omap/include/plat/omap7xx.h
@@ -46,6 +46,9 @@
#define OMAP7XX_DSPREG_SIZE SZ_128K
#define OMAP7XX_DSPREG_START 0xE1000000
+#define OMAP7XX_SPI1_BASE 0xfffc0800
+#define OMAP7XX_SPI2_BASE 0xfffc1000
+
/*
* ----------------------------------------------------------------------------
* OMAP7XX specific configuration registers
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
index 11f5d7961c73..4cbd4fb3232c 100644
--- a/arch/arm/plat-omap/io.c
+++ b/arch/arm/plat-omap/io.c
@@ -66,12 +66,12 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
return XLATE(p, L4_24XX_PHYS, L4_24XX_VIRT);
}
if (cpu_is_omap2420()) {
- if (BETWEEN(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_SIZE))
- return XLATE(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_VIRT);
- if (BETWEEN(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE))
- return XLATE(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE);
- if (BETWEEN(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_SIZE))
- return XLATE(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_VIRT);
+ if (BETWEEN(p, DSP_MEM_2420_PHYS, DSP_MEM_2420_SIZE))
+ return XLATE(p, DSP_MEM_2420_PHYS, DSP_MEM_2420_VIRT);
+ if (BETWEEN(p, DSP_IPI_2420_PHYS, DSP_IPI_2420_SIZE))
+ return XLATE(p, DSP_IPI_2420_PHYS, DSP_IPI_2420_SIZE);
+ if (BETWEEN(p, DSP_MMU_2420_PHYS, DSP_MMU_2420_SIZE))
+ return XLATE(p, DSP_MMU_2420_PHYS, DSP_MMU_2420_VIRT);
}
if (cpu_is_omap2430()) {
if (BETWEEN(p, L4_WK_243X_PHYS, L4_WK_243X_SIZE))
@@ -128,7 +128,7 @@ void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
return XLATE(p, L4_EMU_44XX_PHYS, L4_EMU_44XX_VIRT);
}
#endif
- return __arm_ioremap(p, size, type);
+ return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
}
EXPORT_SYMBOL(omap_ioremap);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index c0ff1e39d893..463d6386aff2 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -827,7 +827,7 @@ EXPORT_SYMBOL_GPL(iommu_get);
**/
void iommu_put(struct iommu *obj)
{
- if (!obj && IS_ERR(obj))
+ if (!obj || IS_ERR(obj))
return;
mutex_lock(&obj->iommu_lock);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 2cc1cc328bac..f75767278fc3 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -436,7 +436,7 @@ int omap_mcbsp_request(unsigned int id)
dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
"for McBSP%d\n", mcbsp->tx_irq,
mcbsp->id);
- return err;
+ goto error;
}
init_completion(&mcbsp->rx_irq_completion);
@@ -446,12 +446,26 @@ int omap_mcbsp_request(unsigned int id)
dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
"for McBSP%d\n", mcbsp->rx_irq,
mcbsp->id);
- free_irq(mcbsp->tx_irq, (void *)mcbsp);
- return err;
+ goto tx_irq;
}
}
return 0;
+tx_irq:
+ free_irq(mcbsp->tx_irq, (void *)mcbsp);
+error:
+ if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+ mcbsp->pdata->ops->free(id);
+
+ /* Do procedure specific to omap34xx arch, if applicable */
+ omap34xx_mcbsp_free(mcbsp);
+
+ clk_disable(mcbsp->fclk);
+ clk_disable(mcbsp->iclk);
+
+ mcbsp->free = 1;
+
+ return err;
}
EXPORT_SYMBOL(omap_mcbsp_request);
diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c
index a9eabdcfa163..51dc5c8106c0 100644
--- a/arch/arm/plat-pxa/pwm.c
+++ b/arch/arm/plat-pxa/pwm.c
@@ -204,14 +204,14 @@ static int __devinit pwm_probe(struct platform_device *pdev)
goto err_free_clk;
}
- r = request_mem_region(r->start, r->end - r->start + 1, pdev->name);
+ r = request_mem_region(r->start, resource_size(r), pdev->name);
if (r == NULL) {
dev_err(&pdev->dev, "failed to request memory resource\n");
ret = -EBUSY;
goto err_free_clk;
}
- pwm->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ pwm->mmio_base = ioremap(r->start, resource_size(r));
if (pwm->mmio_base == NULL) {
dev_err(&pdev->dev, "failed to ioremap() registers\n");
ret = -ENODEV;
@@ -241,7 +241,7 @@ static int __devinit pwm_probe(struct platform_device *pdev)
return 0;
err_free_mem:
- release_mem_region(r->start, r->end - r->start + 1);
+ release_mem_region(r->start, resource_size(r));
err_free_clk:
clk_put(pwm->clk);
err_free:
@@ -271,7 +271,7 @@ static int __devexit pwm_remove(struct platform_device *pdev)
iounmap(pwm->mmio_base);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, r->end - r->start + 1);
+ release_mem_region(r->start, resource_size(r));
clk_put(pwm->clk);
kfree(pwm);
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index 9e9d0286e48f..454cc39b7adc 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -130,39 +130,6 @@ config S3C_GPIO_TRACK
Internal configuration option to enable the s3c specific gpio
chip tracking if the platform requires it.
-config S3C_GPIO_PULL_UPDOWN
- bool
- help
- Internal configuration to enable the correct GPIO pull helper
-
-config S3C_GPIO_PULL_DOWN
- bool
- help
- Internal configuration to enable the correct GPIO pull helper
-
-config S3C_GPIO_PULL_UP
- bool
- help
- Internal configuration to enable the correct GPIO pull helper
-
-config S3C_GPIO_CFG_S3C24XX
- bool
- help
- Internal configuration to enable S3C24XX style GPIO configuration
- functions.
-
-config S3C_GPIO_CFG_S3C64XX
- bool
- help
- Internal configuration to enable S3C64XX style GPIO configuration
- functions.
-
-config S5P_GPIO_CFG_S5PC1XX
- bool
- help
- Internal configuration to enable S5PC1XX style GPIO configuration
- functions.
-
# DMA
config S3C_DMA
@@ -170,46 +137,4 @@ config S3C_DMA
help
Internal configuration for S3C DMA core
-# device definitions to compile in
-
-config S3C_DEV_HSMMC
- bool
- help
- Compile in platform device definitions for HSMMC code
-
-config S3C_DEV_HSMMC1
- bool
- help
- Compile in platform device definitions for HSMMC channel 1
-
-config S3C_DEV_HSMMC2
- bool
- help
- Compile in platform device definitions for HSMMC channel 2
-
-config S3C_DEV_I2C1
- bool
- help
- Compile in platform device definitions for I2C channel 1
-
-config S3C_DEV_FB
- bool
- help
- Compile in platform device definition for framebuffer
-
-config S3C_DEV_USB_HOST
- bool
- help
- Compile in platform device definition for USB host.
-
-config S3C_DEV_USB_HSOTG
- bool
- help
- Compile in platform device definition for USB high-speed OtG
-
-config S3C_DEV_NAND
- bool
- help
- Compile in platform device definition for NAND controller
-
endif
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index 50444da98425..ea4a001f6793 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -11,12 +11,9 @@ obj- :=
# Core support for all Samsung SoCs
-obj-y += init.o
+obj-y += init.o
obj-y += time.o
-obj-y += clock.o
-obj-y += pwm-clock.o
obj-y += gpio.o
-obj-y += gpio-config.o
# DMA support
@@ -31,15 +28,3 @@ obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o
# PWM support
obj-$(CONFIG_HAVE_PWM) += pwm.o
-
-# devices
-
-obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o
-obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o
-obj-$(CONFIG_S3C_DEV_HSMMC2) += dev-hsmmc2.o
-obj-y += dev-i2c0.o
-obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
-obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
-obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
-obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o
-obj-$(CONFIG_S3C_DEV_NAND) += dev-nand.o
diff --git a/arch/arm/plat-s3c/include/plat/nand.h b/arch/arm/plat-s3c/include/plat/nand.h
index 226147b7e026..b64115fa93a4 100644
--- a/arch/arm/plat-s3c/include/plat/nand.h
+++ b/arch/arm/plat-s3c/include/plat/nand.h
@@ -3,7 +3,7 @@
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C2410 - NAND device controller platfrom_device info
+ * S3C2410 - NAND device controller platform_device info
*
* 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/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c
index ac061a1bcb37..cf97caafe56b 100644
--- a/arch/arm/plat-s3c24xx/clock-dclk.c
+++ b/arch/arm/plat-s3c24xx/clock-dclk.c
@@ -161,14 +161,18 @@ static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
/* external clock definitions */
+static struct clk_ops dclk_ops = {
+ .set_parent = s3c24xx_dclk_setparent,
+ .set_rate = s3c24xx_set_dclk_rate,
+ .round_rate = s3c24xx_round_dclk_rate,
+};
+
struct clk s3c24xx_dclk0 = {
.name = "dclk0",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
- .set_parent = s3c24xx_dclk_setparent,
- .set_rate = s3c24xx_set_dclk_rate,
- .round_rate = s3c24xx_round_dclk_rate,
+ .ops = &dclk_ops,
};
struct clk s3c24xx_dclk1 = {
@@ -176,19 +180,21 @@ struct clk s3c24xx_dclk1 = {
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK1EN,
.enable = s3c24xx_dclk_enable,
- .set_parent = s3c24xx_dclk_setparent,
- .set_rate = s3c24xx_set_dclk_rate,
- .round_rate = s3c24xx_round_dclk_rate,
+ .ops = &dclk_ops,
+};
+
+static struct clk_ops clkout_ops = {
+ .set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_clkout0 = {
.name = "clkout0",
.id = -1,
- .set_parent = s3c24xx_clkout_setparent,
+ .ops = &clkout_ops,
};
struct clk s3c24xx_clkout1 = {
.name = "clkout1",
.id = -1,
- .set_parent = s3c24xx_clkout_setparent,
+ .ops = &clkout_ops,
};
diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
index 79371091aa38..f8d96130d1d1 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
@@ -68,7 +68,9 @@ static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
static struct clk clk_arm = {
.name = "armclk",
.id = -1,
- .set_parent = s3c2440_setparent_armclk,
+ .ops = &(struct clk_ops) {
+ .set_parent = s3c2440_setparent_armclk,
+ },
};
static int s3c244x_clk_add(struct sys_device *sysdev)
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
index e6da87a5885c..0fba1f956b8a 100644
--- a/arch/arm/plat-s3c64xx/Kconfig
+++ b/arch/arm/plat-s3c64xx/Kconfig
@@ -13,6 +13,9 @@ config PLAT_S3C64XX
select ARM_VIC
select NO_IOPORT
select ARCH_REQUIRE_GPIOLIB
+ select SAMSUNG_CLKSRC
+ select SAMSUNG_IRQ_VIC_TIMER
+ select SAMSUNG_IRQ_UART
select S3C_GPIO_TRACK
select S3C_GPIO_PULL_UPDOWN
select S3C_GPIO_CFG_S3C24XX
diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c
index 7a36e899360d..ae5883c00e7a 100644
--- a/arch/arm/plat-s3c64xx/clock.c
+++ b/arch/arm/plat-s3c64xx/clock.c
@@ -274,15 +274,7 @@ void __init s3c64xx_register_clocks(void)
int ptr;
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-
- clkp = init_clocks;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- }
+ s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
clkp = init_clocks_disable;
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
diff --git a/arch/arm/plat-s3c64xx/cpu.c b/arch/arm/plat-s3c64xx/cpu.c
index 49796d2db86d..c0e6f2a45154 100644
--- a/arch/arm/plat-s3c64xx/cpu.c
+++ b/arch/arm/plat-s3c64xx/cpu.c
@@ -78,12 +78,12 @@ static struct map_desc s3c_iodesc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S3C_VA_VIC0,
+ .virtual = (unsigned long)VA_VIC0,
.pfn = __phys_to_pfn(S3C64XX_PA_VIC0),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S3C_VA_VIC1,
+ .virtual = (unsigned long)VA_VIC1,
.pfn = __phys_to_pfn(S3C64XX_PA_VIC1),
.length = SZ_16K,
.type = MT_DEVICE,
diff --git a/arch/arm/plat-s3c64xx/include/plat/irqs.h b/arch/arm/plat-s3c64xx/include/plat/irqs.h
index 7956fd3bb194..176fe15a61d6 100644
--- a/arch/arm/plat-s3c64xx/include/plat/irqs.h
+++ b/arch/arm/plat-s3c64xx/include/plat/irqs.h
@@ -24,8 +24,8 @@
#define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET)
-#define S3C_VIC0_BASE S3C_IRQ(0)
-#define S3C_VIC1_BASE S3C_IRQ(32)
+#define IRQ_VIC0_BASE S3C_IRQ(0)
+#define IRQ_VIC1_BASE S3C_IRQ(32)
/* UART interrupts, each UART has 4 intterupts per channel so
* use the space between the ISA and S3C main interrupts. Note, these
@@ -59,8 +59,8 @@
/* VIC based IRQs */
-#define S3C64XX_IRQ_VIC0(x) (S3C_VIC0_BASE + (x))
-#define S3C64XX_IRQ_VIC1(x) (S3C_VIC1_BASE + (x))
+#define S3C64XX_IRQ_VIC0(x) (IRQ_VIC0_BASE + (x))
+#define S3C64XX_IRQ_VIC1(x) (IRQ_VIC1_BASE + (x))
/* VIC0 */
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
index ff46e7fa957a..3ef62741e5d1 100644
--- a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
@@ -35,14 +35,6 @@
#define S3C_MEM0_GATE S3C_CLKREG(0x3C)
/* CLKDIV0 */
-#define S3C6400_CLKDIV0_MFC_MASK (0xf << 28)
-#define S3C6400_CLKDIV0_MFC_SHIFT (28)
-#define S3C6400_CLKDIV0_JPEG_MASK (0xf << 24)
-#define S3C6400_CLKDIV0_JPEG_SHIFT (24)
-#define S3C6400_CLKDIV0_CAM_MASK (0xf << 20)
-#define S3C6400_CLKDIV0_CAM_SHIFT (20)
-#define S3C6400_CLKDIV0_SECURITY_MASK (0x3 << 18)
-#define S3C6400_CLKDIV0_SECURITY_SHIFT (18)
#define S3C6400_CLKDIV0_PCLK_MASK (0xf << 12)
#define S3C6400_CLKDIV0_PCLK_SHIFT (12)
#define S3C6400_CLKDIV0_HCLK2_MASK (0x7 << 9)
@@ -51,42 +43,11 @@
#define S3C6400_CLKDIV0_HCLK_SHIFT (8)
#define S3C6400_CLKDIV0_MPLL_MASK (0x1 << 4)
#define S3C6400_CLKDIV0_MPLL_SHIFT (4)
+
#define S3C6400_CLKDIV0_ARM_MASK (0x7 << 0)
#define S3C6410_CLKDIV0_ARM_MASK (0xf << 0)
#define S3C6400_CLKDIV0_ARM_SHIFT (0)
-/* CLKDIV1 */
-#define S3C6410_CLKDIV1_FIMC_MASK (0xf << 24)
-#define S3C6410_CLKDIV1_FIMC_SHIFT (24)
-#define S3C6400_CLKDIV1_UHOST_MASK (0xf << 20)
-#define S3C6400_CLKDIV1_UHOST_SHIFT (20)
-#define S3C6400_CLKDIV1_SCALER_MASK (0xf << 16)
-#define S3C6400_CLKDIV1_SCALER_SHIFT (16)
-#define S3C6400_CLKDIV1_LCD_MASK (0xf << 12)
-#define S3C6400_CLKDIV1_LCD_SHIFT (12)
-#define S3C6400_CLKDIV1_MMC2_MASK (0xf << 8)
-#define S3C6400_CLKDIV1_MMC2_SHIFT (8)
-#define S3C6400_CLKDIV1_MMC1_MASK (0xf << 4)
-#define S3C6400_CLKDIV1_MMC1_SHIFT (4)
-#define S3C6400_CLKDIV1_MMC0_MASK (0xf << 0)
-#define S3C6400_CLKDIV1_MMC0_SHIFT (0)
-
-/* CLKDIV2 */
-#define S3C6410_CLKDIV2_AUDIO2_MASK (0xf << 24)
-#define S3C6410_CLKDIV2_AUDIO2_SHIFT (24)
-#define S3C6400_CLKDIV2_IRDA_MASK (0xf << 20)
-#define S3C6400_CLKDIV2_IRDA_SHIFT (20)
-#define S3C6400_CLKDIV2_UART_MASK (0xf << 16)
-#define S3C6400_CLKDIV2_UART_SHIFT (16)
-#define S3C6400_CLKDIV2_AUDIO1_MASK (0xf << 12)
-#define S3C6400_CLKDIV2_AUDIO1_SHIFT (12)
-#define S3C6400_CLKDIV2_AUDIO0_MASK (0xf << 8)
-#define S3C6400_CLKDIV2_AUDIO0_SHIFT (8)
-#define S3C6400_CLKDIV2_SPI1_MASK (0xf << 4)
-#define S3C6400_CLKDIV2_SPI1_SHIFT (4)
-#define S3C6400_CLKDIV2_SPI0_MASK (0xf << 0)
-#define S3C6400_CLKDIV2_SPI0_SHIFT (0)
-
/* HCLK GATE Registers */
#define S3C_CLKCON_HCLK_3DSE (1<<31)
#define S3C_CLKCON_HCLK_UHOST (1<<29)
@@ -192,34 +153,4 @@
#define S3C6400_CLKSRC_EPLL_MOUT_SHIFT (2)
#define S3C6400_CLKSRC_MFC (1 << 4)
-#define S3C6410_CLKSRC_TV27_MASK (0x1 << 31)
-#define S3C6410_CLKSRC_TV27_SHIFT (31)
-#define S3C6410_CLKSRC_DAC27_MASK (0x1 << 30)
-#define S3C6410_CLKSRC_DAC27_SHIFT (30)
-#define S3C6400_CLKSRC_SCALER_MASK (0x3 << 28)
-#define S3C6400_CLKSRC_SCALER_SHIFT (28)
-#define S3C6400_CLKSRC_LCD_MASK (0x3 << 26)
-#define S3C6400_CLKSRC_LCD_SHIFT (26)
-#define S3C6400_CLKSRC_IRDA_MASK (0x3 << 24)
-#define S3C6400_CLKSRC_IRDA_SHIFT (24)
-#define S3C6400_CLKSRC_MMC2_MASK (0x3 << 22)
-#define S3C6400_CLKSRC_MMC2_SHIFT (22)
-#define S3C6400_CLKSRC_MMC1_MASK (0x3 << 20)
-#define S3C6400_CLKSRC_MMC1_SHIFT (20)
-#define S3C6400_CLKSRC_MMC0_MASK (0x3 << 18)
-#define S3C6400_CLKSRC_MMC0_SHIFT (18)
-#define S3C6400_CLKSRC_SPI1_MASK (0x3 << 16)
-#define S3C6400_CLKSRC_SPI1_SHIFT (16)
-#define S3C6400_CLKSRC_SPI0_MASK (0x3 << 14)
-#define S3C6400_CLKSRC_SPI0_SHIFT (14)
-#define S3C6400_CLKSRC_UART_MASK (0x1 << 13)
-#define S3C6400_CLKSRC_UART_SHIFT (13)
-#define S3C6400_CLKSRC_AUDIO1_MASK (0x7 << 10)
-#define S3C6400_CLKSRC_AUDIO1_SHIFT (10)
-#define S3C6400_CLKSRC_AUDIO0_MASK (0x7 << 7)
-#define S3C6400_CLKSRC_AUDIO0_SHIFT (7)
-#define S3C6400_CLKSRC_UHOST_MASK (0x3 << 5)
-#define S3C6400_CLKSRC_UHOST_SHIFT (5)
-
-
#endif /* _PLAT_REGS_CLOCK_H */
diff --git a/arch/arm/plat-s3c64xx/irq.c b/arch/arm/plat-s3c64xx/irq.c
index 8dc5b6da9789..67a145d440f3 100644
--- a/arch/arm/plat-s3c64xx/irq.c
+++ b/arch/arm/plat-s3c64xx/irq.c
@@ -21,88 +21,11 @@
#include <asm/hardware/vic.h>
#include <mach/map.h>
-#include <plat/regs-serial.h>
-#include <plat/regs-timer.h>
+#include <plat/irq-vic-timer.h>
+#include <plat/irq-uart.h>
#include <plat/cpu.h>
-/* Timer interrupt handling */
-
-static void s3c_irq_demux_timer(unsigned int base_irq, unsigned int sub_irq)
-{
- generic_handle_irq(sub_irq);
-}
-
-static void s3c_irq_demux_timer0(unsigned int irq, struct irq_desc *desc)
-{
- s3c_irq_demux_timer(irq, IRQ_TIMER0);
-}
-
-static void s3c_irq_demux_timer1(unsigned int irq, struct irq_desc *desc)
-{
- s3c_irq_demux_timer(irq, IRQ_TIMER1);
-}
-
-static void s3c_irq_demux_timer2(unsigned int irq, struct irq_desc *desc)
-{
- s3c_irq_demux_timer(irq, IRQ_TIMER2);
-}
-
-static void s3c_irq_demux_timer3(unsigned int irq, struct irq_desc *desc)
-{
- s3c_irq_demux_timer(irq, IRQ_TIMER3);
-}
-
-static void s3c_irq_demux_timer4(unsigned int irq, struct irq_desc *desc)
-{
- s3c_irq_demux_timer(irq, IRQ_TIMER4);
-}
-
-/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
-
-static void s3c_irq_timer_mask(unsigned int irq)
-{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
-
- reg &= 0x1f; /* mask out pending interrupts */
- reg &= ~(1 << (irq - IRQ_TIMER0));
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
-}
-
-static void s3c_irq_timer_unmask(unsigned int irq)
-{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
-
- reg &= 0x1f; /* mask out pending interrupts */
- reg |= 1 << (irq - IRQ_TIMER0);
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
-}
-
-static void s3c_irq_timer_ack(unsigned int irq)
-{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
-
- reg &= 0x1f;
- reg |= (1 << 5) << (irq - IRQ_TIMER0);
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
-}
-
-static struct irq_chip s3c_irq_timer = {
- .name = "s3c-timer",
- .mask = s3c_irq_timer_mask,
- .unmask = s3c_irq_timer_unmask,
- .ack = s3c_irq_timer_ack,
-};
-
-struct uart_irq {
- void __iomem *regs;
- unsigned int base_irq;
- unsigned int parent_irq;
-};
-
-/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
- * are consecutive when looking up the interrupt in the demux routines.
- */
-static struct uart_irq uart_irqs[] = {
+static struct s3c_uart_irq uart_irqs[] = {
[0] = {
.regs = S3C_VA_UART0,
.base_irq = IRQ_S3CUART_BASE0,
@@ -125,132 +48,22 @@ static struct uart_irq uart_irqs[] = {
},
};
-static inline void __iomem *s3c_irq_uart_base(unsigned int irq)
-{
- struct uart_irq *uirq = get_irq_chip_data(irq);
- return uirq->regs;
-}
-
-static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
-{
- return irq & 3;
-}
-
-/* UART interrupt registers, not worth adding to seperate include header */
-
-static void s3c_irq_uart_mask(unsigned int irq)
-{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg |= (1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
-}
-
-static void s3c_irq_uart_maskack(unsigned int irq)
-{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg |= (1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
- __raw_writel(1 << bit, regs + S3C64XX_UINTP);
-}
-
-static void s3c_irq_uart_unmask(unsigned int irq)
-{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg &= ~(1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
-}
-
-static void s3c_irq_uart_ack(unsigned int irq)
-{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
-
- __raw_writel(1 << bit, regs + S3C64XX_UINTP);
-}
-
-static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
-{
- struct uart_irq *uirq = &uart_irqs[irq - IRQ_UART0];
- u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
- int base = uirq->base_irq;
-
- if (pend & (1 << 0))
- generic_handle_irq(base);
- if (pend & (1 << 1))
- generic_handle_irq(base + 1);
- if (pend & (1 << 2))
- generic_handle_irq(base + 2);
- if (pend & (1 << 3))
- generic_handle_irq(base + 3);
-}
-
-static struct irq_chip s3c_irq_uart = {
- .name = "s3c-uart",
- .mask = s3c_irq_uart_mask,
- .unmask = s3c_irq_uart_unmask,
- .mask_ack = s3c_irq_uart_maskack,
- .ack = s3c_irq_uart_ack,
-};
-
-static void __init s3c64xx_uart_irq(struct uart_irq *uirq)
-{
- void __iomem *reg_base = uirq->regs;
- unsigned int irq;
- int offs;
-
- /* mask all interrupts at the start. */
- __raw_writel(0xf, reg_base + S3C64XX_UINTM);
-
- for (offs = 0; offs < 3; offs++) {
- irq = uirq->base_irq + offs;
-
- set_irq_chip(irq, &s3c_irq_uart);
- set_irq_chip_data(irq, uirq);
- set_irq_handler(irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
- set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
-}
void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
{
- int uart, irq;
-
printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
/* initialise the pair of VICs */
- vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid, 0);
- vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid, 0);
+ vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0);
+ vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);
/* add the timer sub-irqs */
- set_irq_chained_handler(IRQ_TIMER0_VIC, s3c_irq_demux_timer0);
- set_irq_chained_handler(IRQ_TIMER1_VIC, s3c_irq_demux_timer1);
- set_irq_chained_handler(IRQ_TIMER2_VIC, s3c_irq_demux_timer2);
- set_irq_chained_handler(IRQ_TIMER3_VIC, s3c_irq_demux_timer3);
- set_irq_chained_handler(IRQ_TIMER4_VIC, s3c_irq_demux_timer4);
-
- for (irq = IRQ_TIMER0; irq <= IRQ_TIMER4; irq++) {
- set_irq_chip(irq, &s3c_irq_timer);
- set_irq_handler(irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
+ s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
+ s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
+ s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
+ s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
+ s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
- for (uart = 0; uart < ARRAY_SIZE(uart_irqs); uart++)
- s3c64xx_uart_irq(&uart_irqs[uart]);
+ s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
}
-
-
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
index 6ffa21eb1b91..cb2bf4bff051 100644
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c
@@ -29,6 +29,7 @@
#include <plat/regs-clock.h>
#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
#include <plat/cpu.h>
#include <plat/pll.h>
@@ -46,22 +47,7 @@ static struct clk clk_ext_xtal_mux = {
#define clk_fin_epll clk_ext_xtal_mux
#define clk_fout_mpll clk_mpll
-
-struct clk_sources {
- unsigned int nr_sources;
- struct clk **sources;
-};
-
-struct clksrc_clk {
- struct clk clk;
- unsigned int mask;
- unsigned int shift;
-
- struct clk_sources *sources;
-
- unsigned int divider_shift;
- void __iomem *reg_divider;
-};
+#define clk_fout_epll clk_epll
static struct clk clk_fout_apll = {
.name = "fout_apll",
@@ -73,7 +59,7 @@ static struct clk *clk_src_apll_list[] = {
[1] = &clk_fout_apll,
};
-static struct clk_sources clk_src_apll = {
+static struct clksrc_sources clk_src_apll = {
.sources = clk_src_apll_list,
.nr_sources = ARRAY_SIZE(clk_src_apll_list),
};
@@ -83,22 +69,16 @@ static struct clksrc_clk clk_mout_apll = {
.name = "mout_apll",
.id = -1,
},
- .shift = S3C6400_CLKSRC_APLL_MOUT_SHIFT,
- .mask = S3C6400_CLKSRC_APLL_MOUT,
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 0, .size = 1 },
.sources = &clk_src_apll,
};
-static struct clk clk_fout_epll = {
- .name = "fout_epll",
- .id = -1,
-};
-
static struct clk *clk_src_epll_list[] = {
[0] = &clk_fin_epll,
[1] = &clk_fout_epll,
};
-static struct clk_sources clk_src_epll = {
+static struct clksrc_sources clk_src_epll = {
.sources = clk_src_epll_list,
.nr_sources = ARRAY_SIZE(clk_src_epll_list),
};
@@ -108,8 +88,7 @@ static struct clksrc_clk clk_mout_epll = {
.name = "mout_epll",
.id = -1,
},
- .shift = S3C6400_CLKSRC_EPLL_MOUT_SHIFT,
- .mask = S3C6400_CLKSRC_EPLL_MOUT,
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 2, .size = 1 },
.sources = &clk_src_epll,
};
@@ -118,7 +97,7 @@ static struct clk *clk_src_mpll_list[] = {
[1] = &clk_fout_mpll,
};
-static struct clk_sources clk_src_mpll = {
+static struct clksrc_sources clk_src_mpll = {
.sources = clk_src_mpll_list,
.nr_sources = ARRAY_SIZE(clk_src_mpll_list),
};
@@ -128,8 +107,7 @@ static struct clksrc_clk clk_mout_mpll = {
.name = "mout_mpll",
.id = -1,
},
- .shift = S3C6400_CLKSRC_MPLL_MOUT_SHIFT,
- .mask = S3C6400_CLKSRC_MPLL_MOUT,
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 1, .size = 1 },
.sources = &clk_src_mpll,
};
@@ -187,9 +165,11 @@ static struct clk clk_arm = {
.name = "armclk",
.id = -1,
.parent = &clk_mout_apll.clk,
- .get_rate = s3c64xx_clk_arm_get_rate,
- .set_rate = s3c64xx_clk_arm_set_rate,
- .round_rate = s3c64xx_clk_arm_round_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s3c64xx_clk_arm_get_rate,
+ .set_rate = s3c64xx_clk_arm_set_rate,
+ .round_rate = s3c64xx_clk_arm_round_rate,
+ },
};
static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
@@ -204,11 +184,15 @@ static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
return rate;
}
+static struct clk_ops clk_dout_ops = {
+ .get_rate = s3c64xx_clk_doutmpll_get_rate,
+};
+
static struct clk clk_dout_mpll = {
.name = "dout_mpll",
.id = -1,
.parent = &clk_mout_mpll.clk,
- .get_rate = s3c64xx_clk_doutmpll_get_rate,
+ .ops = &clk_dout_ops,
};
static struct clk *clkset_spi_mmc_list[] = {
@@ -218,7 +202,7 @@ static struct clk *clkset_spi_mmc_list[] = {
&clk_27m,
};
-static struct clk_sources clkset_spi_mmc = {
+static struct clksrc_sources clkset_spi_mmc = {
.sources = clkset_spi_mmc_list,
.nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
};
@@ -230,7 +214,7 @@ static struct clk *clkset_irda_list[] = {
&clk_27m,
};
-static struct clk_sources clkset_irda = {
+static struct clksrc_sources clkset_irda = {
.sources = clkset_irda_list,
.nr_sources = ARRAY_SIZE(clkset_irda_list),
};
@@ -242,7 +226,7 @@ static struct clk *clkset_uart_list[] = {
NULL
};
-static struct clk_sources clkset_uart = {
+static struct clksrc_sources clkset_uart = {
.sources = clkset_uart_list,
.nr_sources = ARRAY_SIZE(clkset_uart_list),
};
@@ -254,12 +238,11 @@ static struct clk *clkset_uhost_list[] = {
&clk_fin_epll,
};
-static struct clk_sources clkset_uhost = {
+static struct clksrc_sources clkset_uhost = {
.sources = clkset_uhost_list,
.nr_sources = ARRAY_SIZE(clkset_uhost_list),
};
-
/* The peripheral clocks are all controlled via clocksource followed
* by an optional divider and gate stage. We currently roll this into
* one clock which hides the intermediate clock from the mux.
@@ -270,221 +253,7 @@ static struct clk_sources clkset_uhost = {
* have a common parent divisor so are not included here.
*/
-static inline struct clksrc_clk *to_clksrc(struct clk *clk)
-{
- return container_of(clk, struct clksrc_clk, clk);
-}
-
-static unsigned long s3c64xx_getrate_clksrc(struct clk *clk)
-{
- struct clksrc_clk *sclk = to_clksrc(clk);
- unsigned long rate = clk_get_rate(clk->parent);
- u32 clkdiv = __raw_readl(sclk->reg_divider);
-
- clkdiv >>= sclk->divider_shift;
- clkdiv &= 0xf;
- clkdiv++;
-
- rate /= clkdiv;
- return rate;
-}
-
-static int s3c64xx_setrate_clksrc(struct clk *clk, unsigned long rate)
-{
- struct clksrc_clk *sclk = to_clksrc(clk);
- void __iomem *reg = sclk->reg_divider;
- unsigned int div;
- u32 val;
-
- rate = clk_round_rate(clk, rate);
- div = clk_get_rate(clk->parent) / rate;
- if (div > 16)
- return -EINVAL;
-
- val = __raw_readl(reg);
- val &= ~(0xf << sclk->divider_shift);
- val |= (div - 1) << sclk->divider_shift;
- __raw_writel(val, reg);
-
- return 0;
-}
-
-static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent)
-{
- struct clksrc_clk *sclk = to_clksrc(clk);
- struct clk_sources *srcs = sclk->sources;
- u32 clksrc = __raw_readl(S3C_CLK_SRC);
- int src_nr = -1;
- int ptr;
-
- for (ptr = 0; ptr < srcs->nr_sources; ptr++)
- if (srcs->sources[ptr] == parent) {
- src_nr = ptr;
- break;
- }
-
- if (src_nr >= 0) {
- clksrc &= ~sclk->mask;
- clksrc |= src_nr << sclk->shift;
-
- __raw_writel(clksrc, S3C_CLK_SRC);
-
- clk->parent = parent;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk,
- unsigned long rate)
-{
- unsigned long parent_rate = clk_get_rate(clk->parent);
- int div;
-
- if (rate > parent_rate)
- rate = parent_rate;
- else {
- div = parent_rate / rate;
-
- if (div == 0)
- div = 1;
- if (div > 16)
- div = 16;
-
- rate = parent_rate / div;
- }
-
- return rate;
-}
-
-static struct clksrc_clk clk_mmc0 = {
- .clk = {
- .name = "mmc_bus",
- .id = 0,
- .ctrlbit = S3C_CLKCON_SCLK_MMC0,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_MMC0_SHIFT,
- .mask = S3C6400_CLKSRC_MMC0_MASK,
- .sources = &clkset_spi_mmc,
- .divider_shift = S3C6400_CLKDIV1_MMC0_SHIFT,
- .reg_divider = S3C_CLK_DIV1,
-};
-
-static struct clksrc_clk clk_mmc1 = {
- .clk = {
- .name = "mmc_bus",
- .id = 1,
- .ctrlbit = S3C_CLKCON_SCLK_MMC1,
- .enable = s3c64xx_sclk_ctrl,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .set_parent = s3c64xx_setparent_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_MMC1_SHIFT,
- .mask = S3C6400_CLKSRC_MMC1_MASK,
- .sources = &clkset_spi_mmc,
- .divider_shift = S3C6400_CLKDIV1_MMC1_SHIFT,
- .reg_divider = S3C_CLK_DIV1,
-};
-
-static struct clksrc_clk clk_mmc2 = {
- .clk = {
- .name = "mmc_bus",
- .id = 2,
- .ctrlbit = S3C_CLKCON_SCLK_MMC2,
- .enable = s3c64xx_sclk_ctrl,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .set_parent = s3c64xx_setparent_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_MMC2_SHIFT,
- .mask = S3C6400_CLKSRC_MMC2_MASK,
- .sources = &clkset_spi_mmc,
- .divider_shift = S3C6400_CLKDIV1_MMC2_SHIFT,
- .reg_divider = S3C_CLK_DIV1,
-};
-
-static struct clksrc_clk clk_usbhost = {
- .clk = {
- .name = "usb-bus-host",
- .id = -1,
- .ctrlbit = S3C_CLKCON_SCLK_UHOST,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_UHOST_SHIFT,
- .mask = S3C6400_CLKSRC_UHOST_MASK,
- .sources = &clkset_uhost,
- .divider_shift = S3C6400_CLKDIV1_UHOST_SHIFT,
- .reg_divider = S3C_CLK_DIV1,
-};
-
-static struct clksrc_clk clk_uart_uclk1 = {
- .clk = {
- .name = "uclk1",
- .id = -1,
- .ctrlbit = S3C_CLKCON_SCLK_UART,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_UART_SHIFT,
- .mask = S3C6400_CLKSRC_UART_MASK,
- .sources = &clkset_uart,
- .divider_shift = S3C6400_CLKDIV2_UART_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
-
-/* Where does UCLK0 come from? */
-
-static struct clksrc_clk clk_spi0 = {
- .clk = {
- .name = "spi-bus",
- .id = 0,
- .ctrlbit = S3C_CLKCON_SCLK_SPI0,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_SPI0_SHIFT,
- .mask = S3C6400_CLKSRC_SPI0_MASK,
- .sources = &clkset_spi_mmc,
- .divider_shift = S3C6400_CLKDIV2_SPI0_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
-
-static struct clksrc_clk clk_spi1 = {
- .clk = {
- .name = "spi-bus",
- .id = 1,
- .ctrlbit = S3C_CLKCON_SCLK_SPI1,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_SPI1_SHIFT,
- .mask = S3C6400_CLKSRC_SPI1_MASK,
- .sources = &clkset_spi_mmc,
- .divider_shift = S3C6400_CLKDIV2_SPI1_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
+/* clocks that feed other parts of the clock source tree */
static struct clk clk_iis_cd0 = {
.name = "iis_cdclk0",
@@ -509,29 +278,11 @@ static struct clk *clkset_audio0_list[] = {
[4] = &clk_pcm_cd,
};
-static struct clk_sources clkset_audio0 = {
+static struct clksrc_sources clkset_audio0 = {
.sources = clkset_audio0_list,
.nr_sources = ARRAY_SIZE(clkset_audio0_list),
};
-static struct clksrc_clk clk_audio0 = {
- .clk = {
- .name = "audio-bus",
- .id = 0,
- .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_AUDIO0_SHIFT,
- .mask = S3C6400_CLKSRC_AUDIO0_MASK,
- .sources = &clkset_audio0,
- .divider_shift = S3C6400_CLKDIV2_AUDIO0_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
-
static struct clk *clkset_audio1_list[] = {
[0] = &clk_mout_epll.clk,
[1] = &clk_dout_mpll,
@@ -540,72 +291,133 @@ static struct clk *clkset_audio1_list[] = {
[4] = &clk_pcm_cd,
};
-static struct clk_sources clkset_audio1 = {
+static struct clksrc_sources clkset_audio1 = {
.sources = clkset_audio1_list,
.nr_sources = ARRAY_SIZE(clkset_audio1_list),
};
-static struct clksrc_clk clk_audio1 = {
- .clk = {
- .name = "audio-bus",
- .id = 1,
- .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_AUDIO1_SHIFT,
- .mask = S3C6400_CLKSRC_AUDIO1_MASK,
- .sources = &clkset_audio1,
- .divider_shift = S3C6400_CLKDIV2_AUDIO1_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
-
-static struct clksrc_clk clk_irda = {
- .clk = {
- .name = "irda-bus",
- .id = 0,
- .ctrlbit = S3C_CLKCON_SCLK_IRDA,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
- },
- .shift = S3C6400_CLKSRC_IRDA_SHIFT,
- .mask = S3C6400_CLKSRC_IRDA_MASK,
- .sources = &clkset_irda,
- .divider_shift = S3C6400_CLKDIV2_IRDA_SHIFT,
- .reg_divider = S3C_CLK_DIV2,
-};
-
static struct clk *clkset_camif_list[] = {
&clk_h2,
};
-static struct clk_sources clkset_camif = {
+static struct clksrc_sources clkset_camif = {
.sources = clkset_camif_list,
.nr_sources = ARRAY_SIZE(clkset_camif_list),
};
-static struct clksrc_clk clk_camif = {
- .clk = {
- .name = "camera",
- .id = -1,
- .ctrlbit = S3C_CLKCON_SCLK_CAM,
- .enable = s3c64xx_sclk_ctrl,
- .set_parent = s3c64xx_setparent_clksrc,
- .get_rate = s3c64xx_getrate_clksrc,
- .set_rate = s3c64xx_setrate_clksrc,
- .round_rate = s3c64xx_roundrate_clksrc,
+static struct clksrc_clk clksrcs[] = {
+ {
+ .clk = {
+ .name = "mmc_bus",
+ .id = 0,
+ .ctrlbit = S3C_CLKCON_SCLK_MMC0,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 },
+ .sources = &clkset_spi_mmc,
+ }, {
+ .clk = {
+ .name = "mmc_bus",
+ .id = 1,
+ .ctrlbit = S3C_CLKCON_SCLK_MMC1,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 },
+ .sources = &clkset_spi_mmc,
+ }, {
+ .clk = {
+ .name = "mmc_bus",
+ .id = 2,
+ .ctrlbit = S3C_CLKCON_SCLK_MMC2,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 },
+ .sources = &clkset_spi_mmc,
+ }, {
+ .clk = {
+ .name = "usb-bus-host",
+ .id = -1,
+ .ctrlbit = S3C_CLKCON_SCLK_UHOST,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 5, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV1, .shift = 20, .size = 4 },
+ .sources = &clkset_uhost,
+ }, {
+ .clk = {
+ .name = "uclk1",
+ .id = -1,
+ .ctrlbit = S3C_CLKCON_SCLK_UART,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 13, .size = 1 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 16, .size = 4 },
+ .sources = &clkset_uart,
+ }, {
+/* Where does UCLK0 come from? */
+ .clk = {
+ .name = "spi-bus",
+ .id = 0,
+ .ctrlbit = S3C_CLKCON_SCLK_SPI0,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 14, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 0, .size = 4 },
+ .sources = &clkset_spi_mmc,
+ }, {
+ .clk = {
+ .name = "spi-bus",
+ .id = 1,
+ .ctrlbit = S3C_CLKCON_SCLK_SPI1,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 16, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 4, .size = 4 },
+ .sources = &clkset_spi_mmc,
+ }, {
+ .clk = {
+ .name = "audio-bus",
+ .id = 0,
+ .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4 },
+ .sources = &clkset_audio0,
+ }, {
+ .clk = {
+ .name = "audio-bus",
+ .id = 1,
+ .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4 },
+ .sources = &clkset_audio1,
+ }, {
+ .clk = {
+ .name = "irda-bus",
+ .id = 0,
+ .ctrlbit = S3C_CLKCON_SCLK_IRDA,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_src = { .reg = S3C_CLK_SRC, .shift = 24, .size = 2 },
+ .reg_div = { .reg = S3C_CLK_DIV2, .shift = 20, .size = 4 },
+ .sources = &clkset_irda,
+ }, {
+ .clk = {
+ .name = "camera",
+ .id = -1,
+ .ctrlbit = S3C_CLKCON_SCLK_CAM,
+ .enable = s3c64xx_sclk_ctrl,
+ },
+ .reg_div = { .reg = S3C_CLK_DIV0, .shift = 20, .size = 4 },
+ .reg_src = { .reg = NULL, .shift = 0, .size = 0 },
+ .sources = &clkset_camif,
},
- .shift = 0,
- .mask = 0,
- .sources = &clkset_camif,
- .divider_shift = S3C6400_CLKDIV0_CAM_SHIFT,
- .reg_divider = S3C_CLK_DIV0,
};
/* Clock initialisation code */
@@ -614,39 +426,7 @@ static struct clksrc_clk *init_parents[] = {
&clk_mout_apll,
&clk_mout_epll,
&clk_mout_mpll,
- &clk_mmc0,
- &clk_mmc1,
- &clk_mmc2,
- &clk_usbhost,
- &clk_uart_uclk1,
- &clk_spi0,
- &clk_spi1,
- &clk_audio0,
- &clk_audio1,
- &clk_irda,
- &clk_camif,
-};
-
-static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
-{
- struct clk_sources *srcs = clk->sources;
- u32 clksrc = __raw_readl(S3C_CLK_SRC);
-
- clksrc &= clk->mask;
- clksrc >>= clk->shift;
-
- if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
- printk(KERN_ERR "%s: bad source %d\n",
- clk->clk.name, clksrc);
- return;
- }
-
- clk->clk.parent = srcs->sources[clksrc];
-
- printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
- clk->clk.name, clk->clk.parent->name, clksrc,
- clk_get_rate(&clk->clk));
-}
+};
#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
@@ -706,7 +486,10 @@ void __init_or_cpufreq s3c6400_setup_clocks(void)
clk_f.rate = fclk;
for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
- s3c6400_set_clksrc(init_parents[ptr]);
+ s3c_set_clksrc(init_parents[ptr], true);
+
+ for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+ s3c_set_clksrc(&clksrcs[ptr], true);
}
static struct clk *clks[] __initdata = {
@@ -715,20 +498,8 @@ static struct clk *clks[] __initdata = {
&clk_iis_cd1,
&clk_pcm_cd,
&clk_mout_epll.clk,
- &clk_fout_epll,
&clk_mout_mpll.clk,
&clk_dout_mpll,
- &clk_mmc0.clk,
- &clk_mmc1.clk,
- &clk_mmc2.clk,
- &clk_usbhost.clk,
- &clk_uart_uclk1.clk,
- &clk_spi0.clk,
- &clk_spi1.clk,
- &clk_audio0.clk,
- &clk_audio1.clk,
- &clk_irda.clk,
- &clk_camif.clk,
&clk_arm,
};
@@ -761,6 +532,5 @@ void __init s3c6400_register_clocks(unsigned armclk_divlimit)
}
}
- clk_mpll.parent = &clk_mout_mpll.clk;
- clk_epll.parent = &clk_mout_epll.clk;
+ s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
}
diff --git a/arch/arm/plat-s5pc1xx/clock.c b/arch/arm/plat-s5pc1xx/clock.c
index 26c21d849790..cc21a8bc884e 100644
--- a/arch/arm/plat-s5pc1xx/clock.c
+++ b/arch/arm/plat-s5pc1xx/clock.c
@@ -70,6 +70,10 @@ static int clk_default_setrate(struct clk *clk, unsigned long rate)
return 0;
}
+static struct clk_ops clk_ops_default_setrate = {
+ .set_rate = clk_default_setrate,
+};
+
static int clk_dummy_enable(struct clk *clk, int enable)
{
return 0;
@@ -81,8 +85,8 @@ struct clk clk_hd0 = {
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
- .set_rate = clk_default_setrate,
.enable = clk_dummy_enable,
+ .ops = &clk_ops_default_setrate,
};
struct clk clk_pd0 = {
@@ -91,7 +95,7 @@ struct clk clk_pd0 = {
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
- .set_rate = clk_default_setrate,
+ .ops = &clk_ops_default_setrate,
.enable = clk_dummy_enable,
};
@@ -700,16 +704,8 @@ void __init s5pc1xx_register_clocks(void)
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
- clkp = s5pc100_init_clocks;
- size = ARRAY_SIZE(s5pc100_init_clocks);
-
- for (ptr = 0; ptr < size; ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- }
+ s3c_register_clocks(s5pc100_init_clocks,
+ ARRAY_SIZE(s5pc100_init_clocks);
clkp = s5pc100_init_clocks_disable;
size = ARRAY_SIZE(s5pc100_init_clocks_disable);
diff --git a/arch/arm/plat-s5pc1xx/s5pc100-clock.c b/arch/arm/plat-s5pc1xx/s5pc100-clock.c
index b436d44510c8..16f0b9077390 100644
--- a/arch/arm/plat-s5pc1xx/s5pc100-clock.c
+++ b/arch/arm/plat-s5pc1xx/s5pc100-clock.c
@@ -111,7 +111,9 @@ static struct clk clk_dout_apll = {
.name = "dout_apll",
.id = -1,
.parent = &clk_mout_apll.clk,
- .get_rate = s5pc100_clk_dout_apll_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_apll_get_rate,
+ },
};
static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
@@ -165,9 +167,11 @@ static struct clk clk_arm = {
.name = "armclk",
.id = -1,
.parent = &clk_dout_apll,
- .get_rate = s5pc100_clk_arm_get_rate,
- .set_rate = s5pc100_clk_arm_set_rate,
- .round_rate = s5pc100_clk_arm_round_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_arm_get_rate,
+ .set_rate = s5pc100_clk_arm_set_rate,
+ .round_rate = s5pc100_clk_arm_round_rate,
+ },
};
static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
@@ -185,7 +189,9 @@ static struct clk clk_dout_d0_bus = {
.name = "dout_d0_bus",
.id = -1,
.parent = &clk_arm,
- .get_rate = s5pc100_clk_dout_d0_bus_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_d0_bus_get_rate,
+ },
};
static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
@@ -203,7 +209,9 @@ static struct clk clk_dout_pclkd0 = {
.name = "dout_pclkd0",
.id = -1,
.parent = &clk_dout_d0_bus,
- .get_rate = s5pc100_clk_dout_pclkd0_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_pclkd0_get_rate,
+ },
};
static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
@@ -221,7 +229,9 @@ static struct clk clk_dout_apll2 = {
.name = "dout_apll2",
.id = -1,
.parent = &clk_mout_apll.clk,
- .get_rate = s5pc100_clk_dout_apll2_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_apll2_get_rate,
+ },
};
/* MPLL */
@@ -284,7 +294,9 @@ static struct clk clk_dout_d1_bus = {
.name = "dout_d1_bus",
.id = -1,
.parent = &clk_mout_am.clk,
- .get_rate = s5pc100_clk_dout_d1_bus_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_d1_bus_get_rate,
+ },
};
static struct clk *clkset_onenand_list[] = {
@@ -325,7 +337,9 @@ static struct clk clk_dout_pclkd1 = {
.name = "dout_pclkd1",
.id = -1,
.parent = &clk_dout_d1_bus,
- .get_rate = s5pc100_clk_dout_pclkd1_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_pclkd1_get_rate,
+ },
};
static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
@@ -345,7 +359,9 @@ static struct clk clk_dout_mpll2 = {
.name = "dout_mpll2",
.id = -1,
.parent = &clk_mout_am.clk,
- .get_rate = s5pc100_clk_dout_mpll2_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_mpll2_get_rate,
+ },
};
static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
@@ -365,7 +381,9 @@ static struct clk clk_dout_cam = {
.name = "dout_cam",
.id = -1,
.parent = &clk_dout_mpll2,
- .get_rate = s5pc100_clk_dout_cam_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_cam_get_rate,
+ },
};
static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
@@ -385,7 +403,9 @@ static struct clk clk_dout_mpll = {
.name = "dout_mpll",
.id = -1,
.parent = &clk_mout_am.clk,
- .get_rate = s5pc100_clk_dout_mpll_get_rate,
+ .ops = &(struct clk_ops) {
+ .get_rate = s5pc100_clk_dout_mpll_get_rate,
+ },
};
/* EPLL */
@@ -540,6 +560,13 @@ static unsigned long s5pc100_roundrate_clksrc(struct clk *clk,
return rate;
}
+static struct clk_ops s5pc100_clksrc_ops = {
+ .set_parent = s5pc100_setparent_clksrc,
+ .get_rate = s5pc100_getrate_clksrc,
+ .set_rate = s5pc100_setrate_clksrc,
+ .round_rate = s5pc100_roundrate_clksrc,
+};
+
static struct clk *clkset_spi_list[] = {
&clk_mout_epll.clk,
&clk_dout_mpll2,
@@ -558,10 +585,7 @@ static struct clksrc_clk clk_spi0 = {
.id = 0,
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+
},
.shift = S5PC100_CLKSRC1_SPI0_SHIFT,
.mask = S5PC100_CLKSRC1_SPI0_MASK,
@@ -577,10 +601,7 @@ static struct clksrc_clk clk_spi1 = {
.id = 1,
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC1_SPI1_SHIFT,
.mask = S5PC100_CLKSRC1_SPI1_MASK,
@@ -596,10 +617,7 @@ static struct clksrc_clk clk_spi2 = {
.id = 2,
.ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC1_SPI2_SHIFT,
.mask = S5PC100_CLKSRC1_SPI2_MASK,
@@ -625,10 +643,7 @@ static struct clksrc_clk clk_uart_uclk1 = {
.id = -1,
.ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC1_UART_SHIFT,
.mask = S5PC100_CLKSRC1_UART_MASK,
@@ -683,10 +698,7 @@ static struct clksrc_clk clk_audio0 = {
.id = 0,
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC3_AUDIO0_SHIFT,
.mask = S5PC100_CLKSRC3_AUDIO0_MASK,
@@ -716,10 +728,7 @@ static struct clksrc_clk clk_audio1 = {
.id = 1,
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC3_AUDIO1_SHIFT,
.mask = S5PC100_CLKSRC3_AUDIO1_MASK,
@@ -748,10 +757,7 @@ static struct clksrc_clk clk_audio2 = {
.id = 2,
.ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC3_AUDIO2_SHIFT,
.mask = S5PC100_CLKSRC3_AUDIO2_MASK,
@@ -801,10 +807,7 @@ static struct clksrc_clk clk_lcd = {
.id = -1,
.ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_LCD_SHIFT,
.mask = S5PC100_CLKSRC2_LCD_MASK,
@@ -820,10 +823,7 @@ static struct clksrc_clk clk_fimc0 = {
.id = 0,
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_FIMC0_SHIFT,
.mask = S5PC100_CLKSRC2_FIMC0_MASK,
@@ -839,10 +839,7 @@ static struct clksrc_clk clk_fimc1 = {
.id = 1,
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_FIMC1_SHIFT,
.mask = S5PC100_CLKSRC2_FIMC1_MASK,
@@ -858,10 +855,7 @@ static struct clksrc_clk clk_fimc2 = {
.id = 2,
.ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
.enable = s5pc100_sclk1_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_FIMC2_SHIFT,
.mask = S5PC100_CLKSRC2_FIMC2_MASK,
@@ -889,10 +883,7 @@ static struct clksrc_clk clk_mmc0 = {
.id = 0,
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_MMC0_SHIFT,
.mask = S5PC100_CLKSRC2_MMC0_MASK,
@@ -908,10 +899,7 @@ static struct clksrc_clk clk_mmc1 = {
.id = 1,
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_MMC1_SHIFT,
.mask = S5PC100_CLKSRC2_MMC1_MASK,
@@ -927,10 +915,7 @@ static struct clksrc_clk clk_mmc2 = {
.id = 2,
.ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC2_MMC2_SHIFT,
.mask = S5PC100_CLKSRC2_MMC2_MASK,
@@ -959,10 +944,7 @@ static struct clksrc_clk clk_usbhost = {
.id = -1,
.ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
.enable = s5pc100_sclk0_ctrl,
- .set_parent = s5pc100_setparent_clksrc,
- .get_rate = s5pc100_getrate_clksrc,
- .set_rate = s5pc100_setrate_clksrc,
- .round_rate = s5pc100_roundrate_clksrc,
+ .ops = &s5pc100_clksrc_ops,
},
.shift = S5PC100_CLKSRC1_UHOST_SHIFT,
.mask = S5PC100_CLKSRC1_UHOST_MASK,
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index 486a0d6301e7..faec4b8c626c 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -13,5 +13,107 @@ config PLAT_SAMSUNG
if PLAT_SAMSUNG
+config SAMSUNG_CLKSRC
+ bool
+ help
+ Select the clock code for the clksrc implementation
+ used by newer systems such as the S3C64XX.
+
+# options for IRQ support
+
+config SAMSUNG_IRQ_VIC_TIMER
+ bool
+ help
+ Internal configuration to build the VIC timer interrupt code.
+
+config SAMSUNG_IRQ_UART
+ bool
+ help
+ Internal configuration to build the IRQ UART demux code.
+
+# options for gpio configuration support
+
+config S3C_GPIO_CFG_S3C24XX
+ bool
+ help
+ Internal configuration to enable S3C24XX style GPIO configuration
+ functions.
+
+config S3C_GPIO_CFG_S3C64XX
+ bool
+ help
+ Internal configuration to enable S3C64XX style GPIO configuration
+ functions.
+
+config S5P_GPIO_CFG_S5PC1XX
+ bool
+ help
+ Internal configuration to enable S5PC1XX style GPIO configuration
+ functions.
+
+config S3C_GPIO_PULL_UPDOWN
+ bool
+ help
+ Internal configuration to enable the correct GPIO pull helper
+
+config S3C_GPIO_PULL_DOWN
+ bool
+ help
+ Internal configuration to enable the correct GPIO pull helper
+
+config S3C_GPIO_PULL_UP
+ bool
+ help
+ Internal configuration to enable the correct GPIO pull helper
+
+config SAMSUNG_GPIO_EXTRA
+ int "Number of additional GPIO pins"
+ default 0
+ help
+ Use additional GPIO space in addition to the GPIO's the SOC
+ provides. This allows expanding the GPIO space for use with
+ GPIO expanders.
+
+# device definitions to compile in
+
+config S3C_DEV_HSMMC
+ bool
+ help
+ Compile in platform device definitions for HSMMC code
+
+config S3C_DEV_HSMMC1
+ bool
+ help
+ Compile in platform device definitions for HSMMC channel 1
+
+config S3C_DEV_HSMMC2
+ bool
+ help
+ Compile in platform device definitions for HSMMC channel 2
+
+config S3C_DEV_I2C1
+ bool
+ help
+ Compile in platform device definitions for I2C channel 1
+
+config S3C_DEV_FB
+ bool
+ help
+ Compile in platform device definition for framebuffer
+
+config S3C_DEV_USB_HOST
+ bool
+ help
+ Compile in platform device definition for USB host.
+
+config S3C_DEV_USB_HSOTG
+ bool
+ help
+ Compile in platform device definition for USB high-speed OtG
+
+config S3C_DEV_NAND
+ bool
+ help
+ Compile in platform device definition for NAND controller
endif
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 4478b9f7dc34..aeb7e12d1f63 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -9,3 +9,25 @@ obj-m :=
obj-n := dummy.o
obj- :=
+# Objects we always build independent of SoC choice
+
+obj-y += clock.o
+obj-y += pwm-clock.o
+obj-y += gpio-config.o
+
+obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
+
+obj-$(CONFIG_SAMSUNG_IRQ_UART) += irq-uart.o
+obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
+
+# devices
+
+obj-$(CONFIG_S3C_DEV_HSMMC) += dev-hsmmc.o
+obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o
+obj-$(CONFIG_S3C_DEV_HSMMC2) += dev-hsmmc2.o
+obj-y += dev-i2c0.o
+obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
+obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
+obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
+obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o
+obj-$(CONFIG_S3C_DEV_NAND) += dev-nand.o
diff --git a/arch/arm/plat-samsung/clock-clksrc.c b/arch/arm/plat-samsung/clock-clksrc.c
new file mode 100644
index 000000000000..33c633a8be8d
--- /dev/null
+++ b/arch/arm/plat-samsung/clock-clksrc.c
@@ -0,0 +1,203 @@
+/* linux/arch/arm/plat-samsung/clock-clksrc.c
+ *
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.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/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <plat/clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/cpu-freq.h>
+
+static inline struct clksrc_clk *to_clksrc(struct clk *clk)
+{
+ return container_of(clk, struct clksrc_clk, clk);
+}
+
+static inline u32 bit_mask(u32 shift, u32 nr_bits)
+{
+ u32 mask = 0xffffffff >> (32 - nr_bits);
+
+ return mask << shift;
+}
+
+static unsigned long s3c_getrate_clksrc(struct clk *clk)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ unsigned long rate = clk_get_rate(clk->parent);
+ u32 clkdiv = __raw_readl(sclk->reg_div.reg);
+ u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
+
+ clkdiv &= mask;
+ clkdiv >>= sclk->reg_div.shift;
+ clkdiv++;
+
+ rate /= clkdiv;
+ return rate;
+}
+
+static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ void __iomem *reg = sclk->reg_div.reg;
+ unsigned int div;
+ u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
+ u32 val;
+
+ rate = clk_round_rate(clk, rate);
+ div = clk_get_rate(clk->parent) / rate;
+ if (div > 16)
+ return -EINVAL;
+
+ val = __raw_readl(reg);
+ val &= ~mask;
+ val |= (div - 1) << sclk->reg_div.shift;
+ __raw_writel(val, reg);
+
+ return 0;
+}
+
+static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ struct clksrc_sources *srcs = sclk->sources;
+ u32 clksrc = __raw_readl(sclk->reg_src.reg);
+ u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
+ int src_nr = -1;
+ int ptr;
+
+ for (ptr = 0; ptr < srcs->nr_sources; ptr++)
+ if (srcs->sources[ptr] == parent) {
+ src_nr = ptr;
+ break;
+ }
+
+ if (src_nr >= 0) {
+ clk->parent = parent;
+
+ clksrc &= ~mask;
+ clksrc |= src_nr << sclk->reg_src.shift;
+
+ __raw_writel(clksrc, sclk->reg_src.reg);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static unsigned long s3c_roundrate_clksrc(struct clk *clk,
+ unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ int div;
+
+ if (rate >= parent_rate)
+ rate = parent_rate;
+ else {
+ div = parent_rate / rate;
+ if (parent_rate % rate)
+ div++;
+
+ if (div == 0)
+ div = 1;
+ if (div > 16)
+ div = 16;
+
+ rate = parent_rate / div;
+ }
+
+ return rate;
+}
+
+/* Clock initialisation code */
+
+void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce)
+{
+ struct clksrc_sources *srcs = clk->sources;
+ u32 mask = bit_mask(clk->reg_src.shift, clk->reg_src.size);
+ u32 clksrc = 0;
+
+ if (clk->reg_src.reg)
+ clksrc = __raw_readl(clk->reg_src.reg);
+
+ clksrc &= mask;
+ clksrc >>= clk->reg_src.shift;
+
+ if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
+ printk(KERN_ERR "%s: bad source %d\n",
+ clk->clk.name, clksrc);
+ return;
+ }
+
+ clk->clk.parent = srcs->sources[clksrc];
+
+ if (announce)
+ printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
+ clk->clk.name, clk->clk.parent->name, clksrc,
+ clk_get_rate(&clk->clk));
+}
+
+static struct clk_ops clksrc_ops = {
+ .set_parent = s3c_setparent_clksrc,
+ .get_rate = s3c_getrate_clksrc,
+ .set_rate = s3c_setrate_clksrc,
+ .round_rate = s3c_roundrate_clksrc,
+};
+
+static struct clk_ops clksrc_ops_nodiv = {
+ .set_parent = s3c_setparent_clksrc,
+};
+
+static struct clk_ops clksrc_ops_nosrc = {
+ .get_rate = s3c_getrate_clksrc,
+ .set_rate = s3c_setrate_clksrc,
+ .round_rate = s3c_roundrate_clksrc,
+};
+
+void __init s3c_register_clksrc(struct clksrc_clk *clksrc, int size)
+{
+ int ret;
+
+ WARN_ON(!clksrc->reg_div.reg && !clksrc->reg_src.reg);
+
+ for (; size > 0; size--, clksrc++) {
+ /* fill in the default functions */
+
+ if (!clksrc->clk.ops) {
+ if (!clksrc->reg_div.reg)
+ clksrc->clk.ops = &clksrc_ops_nodiv;
+ else if (!clksrc->reg_src.reg)
+ clksrc->clk.ops = &clksrc_ops_nosrc;
+ else
+ clksrc->clk.ops = &clksrc_ops;
+ }
+
+ /* setup the clocksource, but do not announce it
+ * as it may be re-set by the setup routines
+ * called after the rest of the clocks have been
+ * registered
+ */
+ s3c_set_clksrc(clksrc, false);
+
+ ret = s3c24xx_register_clock(&clksrc->clk);
+
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to register %s (%d)\n",
+ __func__, clksrc->clk.name, ret);
+ }
+ }
+}
diff --git a/arch/arm/plat-s3c/clock.c b/arch/arm/plat-samsung/clock.c
index 619cfa82dcab..0c746ae7b2a6 100644
--- a/arch/arm/plat-s3c/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -150,8 +150,8 @@ unsigned long clk_get_rate(struct clk *clk)
if (clk->rate != 0)
return clk->rate;
- if (clk->get_rate != NULL)
- return (clk->get_rate)(clk);
+ if (clk->ops != NULL && clk->ops->get_rate != NULL)
+ return (clk->ops->get_rate)(clk);
if (clk->parent != NULL)
return clk_get_rate(clk->parent);
@@ -161,8 +161,8 @@ unsigned long clk_get_rate(struct clk *clk)
long clk_round_rate(struct clk *clk, unsigned long rate)
{
- if (!IS_ERR(clk) && clk->round_rate)
- return (clk->round_rate)(clk, rate);
+ if (!IS_ERR(clk) && clk->ops && clk->ops->round_rate)
+ return (clk->ops->round_rate)(clk, rate);
return rate;
}
@@ -178,13 +178,14 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
* the clock may have been made this way by choice.
*/
- WARN_ON(clk->set_rate == NULL);
+ WARN_ON(clk->ops == NULL);
+ WARN_ON(clk->ops && clk->ops->set_rate == NULL);
- if (clk->set_rate == NULL)
+ if (clk->ops == NULL || clk->ops->set_rate == NULL)
return -EINVAL;
spin_lock(&clocks_lock);
- ret = (clk->set_rate)(clk, rate);
+ ret = (clk->ops->set_rate)(clk, rate);
spin_unlock(&clocks_lock);
return ret;
@@ -204,8 +205,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
spin_lock(&clocks_lock);
- if (clk->set_parent)
- ret = (clk->set_parent)(clk, parent);
+ if (clk->ops && clk->ops->set_parent)
+ ret = (clk->ops->set_parent)(clk, parent);
spin_unlock(&clocks_lock);
@@ -224,12 +225,16 @@ EXPORT_SYMBOL(clk_set_parent);
/* base clocks */
-static int clk_default_setrate(struct clk *clk, unsigned long rate)
+int clk_default_setrate(struct clk *clk, unsigned long rate)
{
clk->rate = rate;
return 0;
}
+struct clk_ops clk_ops_def_setrate = {
+ .set_rate = clk_default_setrate,
+};
+
struct clk clk_xtal = {
.name = "xtal",
.id = -1,
@@ -251,7 +256,7 @@ struct clk clk_epll = {
struct clk clk_mpll = {
.name = "mpll",
.id = -1,
- .set_rate = clk_default_setrate,
+ .ops = &clk_ops_def_setrate,
};
struct clk clk_upll = {
@@ -267,7 +272,6 @@ struct clk clk_f = {
.rate = 0,
.parent = &clk_mpll,
.ctrlbit = 0,
- .set_rate = clk_default_setrate,
};
struct clk clk_h = {
@@ -276,7 +280,7 @@ struct clk clk_h = {
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
- .set_rate = clk_default_setrate,
+ .ops = &clk_ops_def_setrate,
};
struct clk clk_p = {
@@ -285,7 +289,7 @@ struct clk clk_p = {
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
- .set_rate = clk_default_setrate,
+ .ops = &clk_ops_def_setrate,
};
struct clk clk_usb_bus = {
@@ -296,7 +300,6 @@ struct clk clk_usb_bus = {
};
-
struct clk s3c24xx_uclk = {
.name = "uclk",
.id = -1,
@@ -333,6 +336,28 @@ int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
return fails;
}
+/**
+ * s3c_register_clocks() - register an array of clocks
+ * @clkp: Pointer to the first clock in the array.
+ * @nr_clks: Number of clocks to register.
+ *
+ * Call s3c24xx_register_clock() on the @clkp array given, printing an
+ * error if it fails to register the clock (unlikely).
+ */
+void __initdata s3c_register_clocks(struct clk *clkp, int nr_clks)
+{
+ int ret;
+
+ for (; nr_clks > 0; nr_clks--, clkp++) {
+ ret = s3c24xx_register_clock(clkp);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+}
+
/* initalise all the clocks */
int __init s3c24xx_register_baseclocks(unsigned long xtal)
diff --git a/arch/arm/plat-s3c/dev-fb.c b/arch/arm/plat-samsung/dev-fb.c
index a90198fc4b0f..a90198fc4b0f 100644
--- a/arch/arm/plat-s3c/dev-fb.c
+++ b/arch/arm/plat-samsung/dev-fb.c
diff --git a/arch/arm/plat-s3c/dev-hsmmc.c b/arch/arm/plat-samsung/dev-hsmmc.c
index 4c05b39810e2..4c05b39810e2 100644
--- a/arch/arm/plat-s3c/dev-hsmmc.c
+++ b/arch/arm/plat-samsung/dev-hsmmc.c
diff --git a/arch/arm/plat-s3c/dev-hsmmc1.c b/arch/arm/plat-samsung/dev-hsmmc1.c
index e49bc4cd0ee6..e49bc4cd0ee6 100644
--- a/arch/arm/plat-s3c/dev-hsmmc1.c
+++ b/arch/arm/plat-samsung/dev-hsmmc1.c
diff --git a/arch/arm/plat-s3c/dev-hsmmc2.c b/arch/arm/plat-samsung/dev-hsmmc2.c
index 824580bc0e06..824580bc0e06 100644
--- a/arch/arm/plat-s3c/dev-hsmmc2.c
+++ b/arch/arm/plat-samsung/dev-hsmmc2.c
diff --git a/arch/arm/plat-s3c/dev-i2c0.c b/arch/arm/plat-samsung/dev-i2c0.c
index 4c761529b949..4c761529b949 100644
--- a/arch/arm/plat-s3c/dev-i2c0.c
+++ b/arch/arm/plat-samsung/dev-i2c0.c
diff --git a/arch/arm/plat-s3c/dev-i2c1.c b/arch/arm/plat-samsung/dev-i2c1.c
index d44f79110506..d44f79110506 100644
--- a/arch/arm/plat-s3c/dev-i2c1.c
+++ b/arch/arm/plat-samsung/dev-i2c1.c
diff --git a/arch/arm/plat-s3c/dev-nand.c b/arch/arm/plat-samsung/dev-nand.c
index 84808ccda70e..84808ccda70e 100644
--- a/arch/arm/plat-s3c/dev-nand.c
+++ b/arch/arm/plat-samsung/dev-nand.c
diff --git a/arch/arm/plat-s3c/dev-usb-hsotg.c b/arch/arm/plat-samsung/dev-usb-hsotg.c
index e2f604b51c86..e2f604b51c86 100644
--- a/arch/arm/plat-s3c/dev-usb-hsotg.c
+++ b/arch/arm/plat-samsung/dev-usb-hsotg.c
diff --git a/arch/arm/plat-s3c/dev-usb.c b/arch/arm/plat-samsung/dev-usb.c
index 2ee85abed6d9..2ee85abed6d9 100644
--- a/arch/arm/plat-s3c/dev-usb.c
+++ b/arch/arm/plat-samsung/dev-usb.c
diff --git a/arch/arm/plat-s3c/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c
index 456969b6fa0d..456969b6fa0d 100644
--- a/arch/arm/plat-s3c/gpio-config.c
+++ b/arch/arm/plat-samsung/gpio-config.c
diff --git a/arch/arm/plat-samsung/include/plat/clock-clksrc.h b/arch/arm/plat-samsung/include/plat/clock-clksrc.h
new file mode 100644
index 000000000000..50a8ca7c3760
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/clock-clksrc.h
@@ -0,0 +1,83 @@
+/* linux/arch/arm/plat-samsung/include/plat/clock-clksrc.h
+ *
+ * Parts taken from arch/arm/plat-s3c64xx/clock.c
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * Copyright 2009 Ben Dooks <ben-linux@fluff.org>
+ * Copyright 2009 Harald Welte
+ *
+ * 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.
+*/
+
+/**
+ * struct clksrc_sources - list of sources for a given clock
+ * @sources: array of pointers to clocks
+ * @nr_sources: The size of @sources
+ */
+struct clksrc_sources {
+ unsigned int nr_sources;
+ struct clk **sources;
+};
+
+/**
+ * struct clksrc_reg - register definition for clock control bits
+ * @reg: pointer to the register in virtual memory.
+ * @shift: the shift in bits to where the bitfield is.
+ * @size: the size in bits of the bitfield.
+ *
+ * This specifies the size and position of the bits we are interested
+ * in within the register specified by @reg.
+ */
+struct clksrc_reg {
+ void __iomem *reg;
+ unsigned short shift;
+ unsigned short size;
+};
+
+/**
+ * struct clksrc_clk - class of clock for newer style samsung devices.
+ * @clk: the standard clock representation
+ * @sources: the sources for this clock
+ * @reg_src: the register definition for selecting the clock's source
+ * @reg_div: the register definition for the clock's output divisor
+ *
+ * This clock implements the features required by the newer SoCs where
+ * the standard clock block provides an input mux and a post-mux divisor
+ * to provide the periperhal's clock.
+ *
+ * The array of @sources provides the mapping of mux position to the
+ * clock, and @reg_src shows the code where to modify to change the mux
+ * position. The @reg_div defines how to change the divider settings on
+ * the output.
+ */
+struct clksrc_clk {
+ struct clk clk;
+ struct clksrc_sources *sources;
+
+ struct clksrc_reg reg_src;
+ struct clksrc_reg reg_div;
+};
+
+/**
+ * s3c_set_clksrc() - setup the clock from the register settings
+ * @clk: The clock to setup.
+ * @announce: true to announce the setting to printk().
+ *
+ * Setup the clock from the current register settings, for when the
+ * kernel boots or if it is resuming from a possibly unknown state.
+ */
+extern void s3c_set_clksrc(struct clksrc_clk *clk, bool announce);
+
+/**
+ * s3c_register_clksrc() register clocks from an array of clksrc clocks
+ * @srcs: The array of clocks to register
+ * @size: The size of the @srcs array.
+ *
+ * Initialise and register the array of clocks described by @srcs.
+ */
+extern void s3c_register_clksrc(struct clksrc_clk *srcs, int size);
diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index d86af84b5b8c..22e011497502 100644
--- a/arch/arm/plat-s3c/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -11,6 +11,30 @@
#include <linux/spinlock.h>
+struct clk;
+
+/**
+ * struct clk_ops - standard clock operations
+ * @set_rate: set the clock rate, see clk_set_rate().
+ * @get_rate: get the clock rate, see clk_get_rate().
+ * @round_rate: round a given clock rate, see clk_round_rate().
+ * @set_parent: set the clock's parent, see clk_set_parent().
+ *
+ * Group the common clock implementations together so that we
+ * don't have to keep setting the same fiels again. We leave
+ * enable in struct clk.
+ *
+ * Adding an extra layer of indirection into the process should
+ * not be a problem as it is unlikely these operations are going
+ * to need to be called quickly.
+ */
+struct clk_ops {
+ int (*set_rate)(struct clk *c, unsigned long rate);
+ unsigned long (*get_rate)(struct clk *c);
+ unsigned long (*round_rate)(struct clk *c, unsigned long rate);
+ int (*set_parent)(struct clk *c, struct clk *parent);
+};
+
struct clk {
struct list_head list;
struct module *owner;
@@ -21,11 +45,8 @@ struct clk {
unsigned long rate;
unsigned long ctrlbit;
+ struct clk_ops *ops;
int (*enable)(struct clk *, int enable);
- int (*set_rate)(struct clk *c, unsigned long rate);
- unsigned long (*get_rate)(struct clk *c);
- unsigned long (*round_rate)(struct clk *c, unsigned long rate);
- int (*set_parent)(struct clk *c, struct clk *parent);
};
/* other clocks which may be registered by board support */
@@ -54,6 +75,9 @@ extern struct clk clk_h2;
extern struct clk clk_27m;
extern struct clk clk_48m;
+extern int clk_default_setrate(struct clk *clk, unsigned long rate);
+extern struct clk_ops clk_ops_def_setrate;
+
/* exports for arch/arm/mach-s3c2410
*
* Please DO NOT use these outside of arch/arm/mach-s3c2410
@@ -66,6 +90,8 @@ extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
extern int s3c24xx_register_clock(struct clk *clk);
extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
+extern void s3c_register_clocks(struct clk *clk, int nr_clks);
+
extern int s3c24xx_register_baseclocks(unsigned long xtal);
extern void s3c64xx_register_clocks(void);
diff --git a/arch/arm/plat-samsung/include/plat/irq-uart.h b/arch/arm/plat-samsung/include/plat/irq-uart.h
new file mode 100644
index 000000000000..a9331e49bea3
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/irq-uart.h
@@ -0,0 +1,20 @@
+/* arch/arm/plat-samsung/include/plat/irq-uart.h
+ *
+ * Copyright (c) 2010 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for Samsung SoC UART IRQ demux for S3C64XX and later
+ *
+ * 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.
+*/
+
+struct s3c_uart_irq {
+ void __iomem *regs;
+ unsigned int base_irq;
+ unsigned int parent_irq;
+};
+
+extern void s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs);
+
diff --git a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
new file mode 100644
index 000000000000..a90b53431b5b
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
@@ -0,0 +1,13 @@
+/* arch/arm/plat-samsung/include/plat/irq-vic-timer.h
+ *
+ * Copyright (c) 2010 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for Samsung SoC IRQ VIC 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.
+*/
+
+extern void s3c_init_vic_timer_irq(unsigned int vic, unsigned int timer);
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
new file mode 100644
index 000000000000..4f8c102674ae
--- /dev/null
+++ b/arch/arm/plat-samsung/irq-uart.c
@@ -0,0 +1,143 @@
+/* arch/arm/plat-samsung/irq-uart.c
+ * originally part of arch/arm/plat-s3c64xx/irq.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * Samsung- UART Interrupt handling
+ *
+ * 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/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <plat/irq-uart.h>
+#include <plat/regs-serial.h>
+#include <plat/cpu.h>
+
+/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
+ * are consecutive when looking up the interrupt in the demux routines.
+ */
+
+static inline void __iomem *s3c_irq_uart_base(unsigned int irq)
+{
+ struct s3c_uart_irq *uirq = get_irq_chip_data(irq);
+ return uirq->regs;
+}
+
+static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
+{
+ return irq & 3;
+}
+
+static void s3c_irq_uart_mask(unsigned int irq)
+{
+ void __iomem *regs = s3c_irq_uart_base(irq);
+ unsigned int bit = s3c_irq_uart_bit(irq);
+ u32 reg;
+
+ reg = __raw_readl(regs + S3C64XX_UINTM);
+ reg |= (1 << bit);
+ __raw_writel(reg, regs + S3C64XX_UINTM);
+}
+
+static void s3c_irq_uart_maskack(unsigned int irq)
+{
+ void __iomem *regs = s3c_irq_uart_base(irq);
+ unsigned int bit = s3c_irq_uart_bit(irq);
+ u32 reg;
+
+ reg = __raw_readl(regs + S3C64XX_UINTM);
+ reg |= (1 << bit);
+ __raw_writel(reg, regs + S3C64XX_UINTM);
+ __raw_writel(1 << bit, regs + S3C64XX_UINTP);
+}
+
+static void s3c_irq_uart_unmask(unsigned int irq)
+{
+ void __iomem *regs = s3c_irq_uart_base(irq);
+ unsigned int bit = s3c_irq_uart_bit(irq);
+ u32 reg;
+
+ reg = __raw_readl(regs + S3C64XX_UINTM);
+ reg &= ~(1 << bit);
+ __raw_writel(reg, regs + S3C64XX_UINTM);
+}
+
+static void s3c_irq_uart_ack(unsigned int irq)
+{
+ void __iomem *regs = s3c_irq_uart_base(irq);
+ unsigned int bit = s3c_irq_uart_bit(irq);
+
+ __raw_writel(1 << bit, regs + S3C64XX_UINTP);
+}
+
+static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
+{
+ struct s3c_uart_irq *uirq = desc->handler_data;
+ u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
+ int base = uirq->base_irq;
+
+ if (pend & (1 << 0))
+ generic_handle_irq(base);
+ if (pend & (1 << 1))
+ generic_handle_irq(base + 1);
+ if (pend & (1 << 2))
+ generic_handle_irq(base + 2);
+ if (pend & (1 << 3))
+ generic_handle_irq(base + 3);
+}
+
+static struct irq_chip s3c_irq_uart = {
+ .name = "s3c-uart",
+ .mask = s3c_irq_uart_mask,
+ .unmask = s3c_irq_uart_unmask,
+ .mask_ack = s3c_irq_uart_maskack,
+ .ack = s3c_irq_uart_ack,
+};
+
+static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
+{
+ struct irq_desc *desc = irq_to_desc(uirq->parent_irq);
+ void __iomem *reg_base = uirq->regs;
+ unsigned int irq;
+ int offs;
+
+ /* mask all interrupts at the start. */
+ __raw_writel(0xf, reg_base + S3C64XX_UINTM);
+
+ for (offs = 0; offs < 3; offs++) {
+ irq = uirq->base_irq + offs;
+
+ set_irq_chip(irq, &s3c_irq_uart);
+ set_irq_chip_data(irq, uirq);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+ desc->handler_data = uirq;
+ set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
+}
+
+/**
+ * s3c_init_uart_irqs() - initialise UART IRQs and the necessary demuxing
+ * @irq: The interrupt data for registering
+ * @nr_irqs: The number of interrupt descriptions in @irq.
+ *
+ * Register the UART interrupts specified by @irq including the demuxing
+ * routines. This supports the S3C6400 and newer style of devices.
+ */
+void __init s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs)
+{
+ for (; nr_irqs > 0; nr_irqs--, irq++)
+ s3c_init_uart_irq(irq);
+}
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
new file mode 100644
index 000000000000..0270519fcabc
--- /dev/null
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -0,0 +1,86 @@
+/* arch/arm/plat-samsung/irq-vic-timer.c
+ * originally part of arch/arm/plat-s3c64xx/irq.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <plat/irq-vic-timer.h>
+#include <plat/regs-timer.h>
+
+static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
+{
+ generic_handle_irq((int)desc->handler_data);
+}
+
+/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
+
+static void s3c_irq_timer_mask(unsigned int irq)
+{
+ u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+ reg &= 0x1f; /* mask out pending interrupts */
+ reg &= ~(1 << (irq - IRQ_TIMER0));
+ __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static void s3c_irq_timer_unmask(unsigned int irq)
+{
+ u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+ reg &= 0x1f; /* mask out pending interrupts */
+ reg |= 1 << (irq - IRQ_TIMER0);
+ __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static void s3c_irq_timer_ack(unsigned int irq)
+{
+ u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+ reg &= 0x1f;
+ reg |= (1 << 5) << (irq - IRQ_TIMER0);
+ __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static struct irq_chip s3c_irq_timer = {
+ .name = "s3c-timer",
+ .mask = s3c_irq_timer_mask,
+ .unmask = s3c_irq_timer_unmask,
+ .ack = s3c_irq_timer_ack,
+};
+
+/**
+ * s3c_init_vic_timer_irq() - initialise timer irq chanined off VIC.\
+ * @parent_irq: The parent IRQ on the VIC for the timer.
+ * @timer_irq: The IRQ to be used for the timer.
+ *
+ * Register the necessary IRQ chaining and support for the timer IRQs
+ * chained of the VIC.
+ */
+void __init s3c_init_vic_timer_irq(unsigned int parent_irq,
+ unsigned int timer_irq)
+{
+ struct irq_desc *desc = irq_to_desc(parent_irq);
+
+ set_irq_chained_handler(parent_irq, s3c_irq_demux_vic_timer);
+
+ set_irq_chip(timer_irq, &s3c_irq_timer);
+ set_irq_handler(timer_irq, handle_level_irq);
+ set_irq_flags(timer_irq, IRQF_VALID);
+
+ desc->handler_data = (void *)timer_irq;
+}
diff --git a/arch/arm/plat-s3c/pwm-clock.c b/arch/arm/plat-samsung/pwm-clock.c
index a318215ab535..46c9381e083b 100644
--- a/arch/arm/plat-s3c/pwm-clock.c
+++ b/arch/arm/plat-samsung/pwm-clock.c
@@ -130,20 +130,22 @@ static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
return 0;
}
+static struct clk_ops clk_pwm_scaler_ops = {
+ .get_rate = clk_pwm_scaler_get_rate,
+ .set_rate = clk_pwm_scaler_set_rate,
+ .round_rate = clk_pwm_scaler_round_rate,
+};
+
static struct clk clk_timer_scaler[] = {
[0] = {
.name = "pwm-scaler0",
.id = -1,
- .get_rate = clk_pwm_scaler_get_rate,
- .set_rate = clk_pwm_scaler_set_rate,
- .round_rate = clk_pwm_scaler_round_rate,
+ .ops = &clk_pwm_scaler_ops,
},
[1] = {
.name = "pwm-scaler1",
.id = -1,
- .get_rate = clk_pwm_scaler_get_rate,
- .set_rate = clk_pwm_scaler_set_rate,
- .round_rate = clk_pwm_scaler_round_rate,
+ .ops = &clk_pwm_scaler_ops,
},
};
@@ -256,50 +258,46 @@ static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
return 0;
}
+static struct clk_ops clk_tdiv_ops = {
+ .get_rate = clk_pwm_tdiv_get_rate,
+ .set_rate = clk_pwm_tdiv_set_rate,
+ .round_rate = clk_pwm_tdiv_round_rate,
+};
+
static struct pwm_tdiv_clk clk_timer_tdiv[] = {
[0] = {
.clk = {
- .name = "pwm-tdiv",
- .parent = &clk_timer_scaler[0],
- .get_rate = clk_pwm_tdiv_get_rate,
- .set_rate = clk_pwm_tdiv_set_rate,
- .round_rate = clk_pwm_tdiv_round_rate,
+ .name = "pwm-tdiv",
+ .ops = &clk_tdiv_ops,
+ .parent = &clk_timer_scaler[0],
},
},
[1] = {
.clk = {
- .name = "pwm-tdiv",
- .parent = &clk_timer_scaler[0],
- .get_rate = clk_pwm_tdiv_get_rate,
- .set_rate = clk_pwm_tdiv_set_rate,
- .round_rate = clk_pwm_tdiv_round_rate,
+ .name = "pwm-tdiv",
+ .ops = &clk_tdiv_ops,
+ .parent = &clk_timer_scaler[0],
}
},
[2] = {
.clk = {
- .name = "pwm-tdiv",
- .parent = &clk_timer_scaler[1],
- .get_rate = clk_pwm_tdiv_get_rate,
- .set_rate = clk_pwm_tdiv_set_rate,
- .round_rate = clk_pwm_tdiv_round_rate,
+ .name = "pwm-tdiv",
+ .ops = &clk_tdiv_ops,
+ .parent = &clk_timer_scaler[1],
},
},
[3] = {
.clk = {
- .name = "pwm-tdiv",
- .parent = &clk_timer_scaler[1],
- .get_rate = clk_pwm_tdiv_get_rate,
- .set_rate = clk_pwm_tdiv_set_rate,
- .round_rate = clk_pwm_tdiv_round_rate,
+ .name = "pwm-tdiv",
+ .ops = &clk_tdiv_ops,
+ .parent = &clk_timer_scaler[1],
},
},
[4] = {
.clk = {
- .name = "pwm-tdiv",
- .parent = &clk_timer_scaler[1],
- .get_rate = clk_pwm_tdiv_get_rate,
- .set_rate = clk_pwm_tdiv_set_rate,
- .round_rate = clk_pwm_tdiv_round_rate,
+ .name = "pwm-tdiv",
+ .ops = &clk_tdiv_ops,
+ .parent = &clk_timer_scaler[1],
},
},
};
@@ -356,31 +354,35 @@ static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
+static struct clk_ops clk_tin_ops = {
+ .set_parent = clk_pwm_tin_set_parent,
+};
+
static struct clk clk_tin[] = {
[0] = {
- .name = "pwm-tin",
- .id = 0,
- .set_parent = clk_pwm_tin_set_parent,
+ .name = "pwm-tin",
+ .id = 0,
+ .ops = &clk_tin_ops,
},
[1] = {
- .name = "pwm-tin",
- .id = 1,
- .set_parent = clk_pwm_tin_set_parent,
+ .name = "pwm-tin",
+ .id = 1,
+ .ops = &clk_tin_ops,
},
[2] = {
- .name = "pwm-tin",
- .id = 2,
- .set_parent = clk_pwm_tin_set_parent,
+ .name = "pwm-tin",
+ .id = 2,
+ .ops = &clk_tin_ops,
},
[3] = {
- .name = "pwm-tin",
- .id = 3,
- .set_parent = clk_pwm_tin_set_parent,
+ .name = "pwm-tin",
+ .id = 3,
+ .ops = &clk_tin_ops,
},
[4] = {
- .name = "pwm-tin",
- .id = 4,
- .set_parent = clk_pwm_tin_set_parent,
+ .name = "pwm-tin",
+ .id = 4,
+ .ops = &clk_tin_ops,
},
};
@@ -428,25 +430,15 @@ __init void s3c_pwmclk_init(void)
return;
}
- for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
+ for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++)
clk_timer_scaler[clk].parent = clk_timers;
- ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
- if (ret < 0) {
- printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
- return;
- }
- }
- for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
- ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
- if (ret < 0) {
- printk(KERN_ERR "error adding pww tclk%d\n", clk);
- return;
- }
- }
+ s3c_register_clocks(clk_timer_scaler, ARRAY_SIZE(clk_timer_scaler));
+ s3c_register_clocks(clk_timer_tclk, ARRAY_SIZE(clk_timer_tclk));
for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
ret = clk_pwm_tdiv_register(clk);
+
if (ret < 0) {
printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
return;
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
index 5d2f19a09e44..e593a2a801c6 100644
--- a/arch/arm/plat-stmp3xxx/clock.c
+++ b/arch/arm/plat-stmp3xxx/clock.c
@@ -1126,9 +1126,8 @@ static int __init clk_init(void)
if (ops && ops->set_parent)
ops->set_parent(cl->clk, cl->clk->parent);
}
-
- clkdev_add(cl);
}
+ clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
return 0;
}